react-digraph icon indicating copy to clipboard operation
react-digraph copied to clipboard

Style edges and marker arrow head

Open volotovskyy opened this issue 6 years ago • 1 comments

extend doc or feature request

I'm wondering if it's possible to style edges? I found one helpful tip in #128 Currently I'm using afterRenderEdge for this purpose. So far I can conditionally handle edge styles by adding new class Like this: edgeContainer.querySelector('.edge').classList.add('default'); Unfortunately It seems like we have to handle edge's arrow separately. I'd been looking through source code and found workaround which i'm using inside afterRenderEdge. E.g: wrapperRef.querySelector('defs>marker>.arrow').classList.add('defaultConnection'); where wrapperRef is html element <div class='view-wrapper><svg class='graph'>... But this hack let us only change some styles for all arrowhead-markers among graph.

  1. How can I style edges and arrow by some condition?
  2. Are you going to implement edge styling by some props in near future?

Would you be so kind to share some approaches to achieve my final goal - have different styles/colors for edges including arrowhead markers. Thank for you attention.

volotovskyy avatar Jul 02 '19 10:07 volotovskyy

@volotovskyy, we are aware of the limitations with modifying edge colors, particularly with the markerEnds. This is a limitation with SVGs. In order to style markers you need to render each marker end color your app will use in the defs.

In the code below we've rendered several types of "traveled state" markers. One might be red, or blue, or green, and the normal marker color is called "end-arrow". Each marker style is given a custom ID.

The code below that modifies the edge fill color to match the preferred color for the particular feature. This color corresponds to the traveledState in this example.

  // only need to modify the edge when the traveledState changes.
  if (edge.traveledState != null) {
    edgeElem.style.markerEnd = `url(#end-arrow-${edge.traveledState})`;
  } else {
    edgeElem.style.markerEnd = `url(#end-arrow)`;
  }

  // color might be null
  if (color && edgeElem && edgeText) {
    edgeElem.style.stroke = color;
    edgeText.style.fill = isEdgeSelected ? '#ffffff' : color;
    edgeText.style.color = isEdgeSelected ? '#ffffff' : color;
    edgeText.style.stroke = isEdgeSelected ? '#ffffff' : color;
  }

To render the marker defs of various colors, this is the function we use (some code has been removed):

// renderWorkflowDefs is an override of GraphView.renderDefs that allows inserting additional defs
export function renderWorkflowDefs() {
  let defIndex = 0;
  const graphConfigDefs = [];

  // code removed to fill in graphConfigDefs with other defs.

  return (
    <React.Fragment>
      {graphConfigDefs}
      {Object.keys(travelStateToColor).map(state => {
        const color: string = travelStateToColor[state];

        return (
          <marker
            id={`end-arrow-${state}`}
            key={`end-arrow-${state}`}
            markerHeight={String(this.edgeArrowSize)}
            markerWidth={String(this.edgeArrowSize)}
            orient="auto"
            refX={String(this.edgeArrowSize / 2)}
            viewBox={`0 -${this.edgeArrowSize / 2} ${this.edgeArrowSize} ${
              this.edgeArrowSize
            }`}
          >
            <path
              d={`M0,-${this.edgeArrowSize / 2}L${this.edgeArrowSize},0L0,${this
                .edgeArrowSize / 2}`}
              style={{ fill: color }}
            />
          </marker>
        );
      })}
    </React.Fragment>
  );

ajbogh avatar Jul 16 '19 23:07 ajbogh