how to make SVG LinearGradient invariant

64 Views Asked by At

I am complete beginer in SVG and React, I am working on a reactflow app to design a low-code tool to produce DAGs.

I have nodes with different colors for source and target handles and I used this medium article to produce custom edges with a linear gradient

Correct edge color gradient:

correct edge color gradient

My problem is that when the source is moved below the target the linear gradient changes orientation and I get the following

Incorrect edge color gradient:

incorrect edge color gradient

I'd like the linear gradient to be invariant with respect to the source and target position.

Any suggestion?

EDIT: the medium article provides a codesandbox example which illustrates my problem: moving node 5 above node 4 inverts the gradient

1

There are 1 best solutions below

0
sylvain471 On

Question solved

I defined a function that checks the relative position of the nodes and adjust the gradient style correspondingly.

function adjustStyle(sourceY,targetY) {
    // Check if source is below target
    let style;
    if (sourceY < targetY) {
      style = {stroke: 'url(#edgegradient1)'};
      }
    else {
      style = {stroke: 'url(#edgegradient2)'};
    }
    return style;
  } 

I added a call to this function into the CustomEdge.js script

import React from 'react';
import { getBezierPath } from 'reactflow';

export default function CustomEdge({id,sourceX,sourceY,targetX,targetY,
                                    sourcePosition,targetPosition,
                                    style = {},data,markerEnd,}) {

const newstyle=adjustStyle(sourceY,targetY);
const [edgePath] = getBezierPath({sourceX,sourceY,sourcePosition,
                                  targetX,targetY,targetPosition,});
return (
  <>
    <path
      id={id}
      style={newstyle}
      className="react-flow__edge-path"
      d={edgePath}
      markerEnd={markerEnd}
    />
    <text>
      <textPath
        href={`#${id}`}
        style={{ fontSize: '12px' }}
        startOffset="50%"
        textAnchor="middle"
      >
        {data.text}
      </textPath>
    </text>
  </>
);
}

edgegradient1 and edgegradient2 being defined by

export default function GradientEdge1() {
    return (
      <svg viewBox="0 0 10 10" style={{ height: 0, width: 0 }}>
        <defs>
          <linearGradient id="edgegradient1" gradientTransform="rotate(90)">
            <stop offset="5%" stopColor="gold" />
            <stop offset="95%" stopColor="red" />
          </linearGradient>
        </defs>
        <circle cx="5" cy="5" r="4" fill="url('#myGradient')" />
      </svg>
    );
  }

and

export default function GradientEdge2() {
    return (
      <svg viewBox="0 0 10 10" style={{ height: 0, width: 0 }}>
        <defs>
          <linearGradient id="edgegradient2" gradientTransform="rotate(90)">
            <stop offset="5%" stopColor="red" />
            <stop offset="95%" stopColor="gold" />
          </linearGradient>
        </defs>
        <circle cx="5" cy="5" r="4" fill="url('#myGradient')" />
      </svg>
    );
  }