Svg defs encapsulation

2020-04-26 04:51发布

问题:

I'm trying to encapsulate an SVG line with an arrowhead at the end without any global ids in a React component, (but the question itself has nothing to do with React).

Example fiddle https://jsfiddle.net/wzyzqhgh/1/

const LinkComponent = ({ x1, y1, x2, y2, color }) => {
  const coordinates = calculateCoordinates(x1, y1, x2, y2)
  const linkStyle = calculateStyles(x1, y1, x2, y2)
  return (<svg style={linkStyle} shapeRendering="geometricPrecision">
    <defs>
      <marker 
        id="arrow" 
        markerWidth={10} 
        markerHeight={10} 
        refX={9} 
        refY={3} 
        orient="auto" 
        markerUnits="strokeWidth"
      >
        <path d="M0,0 L0,6 L9,3 z" fill={color} />
      </marker>
    </defs>
    <line
      x1={coordinates.x1}
      y1={coordinates.y1}
      x2={coordinates.x2}
      y2={coordinates.y2}
      strokeWidth={1}
      stroke={color}
      markerEnd="url(#arrow)"
    />
  </svg>)
}

This component defines a marker locally each time it's rendered, but seems like the id of the marker is global. So when I do this:

ReactDom.render(
  (<div>
    <LinkComponent x1={10} y1={20} x2={100} y2={200} color="red" />
    <LinkComponent x1={10} y1={200} x2={200} y2={10} color="blue" />
  </div>),
  document.getElementById('test')
)

The first color is used in both components marker-end.

Question: How do I encapsulate markers in a single svg element so they don't leak out? Is there any other way to reference them in marker-* properties than id? If it's not possible, how can I achieve similar effects without using defs/markers

回答1:

You have a few choices:

  1. Pull the marker definition(s) out into a static SVG that is referenced by all LinkComponents, or

  2. Generate a random, unique id each time.

  3. Add the colour to the id, so even if you have duplicate marker definitions, it doesn't matter which one is referenced:

    id="arrow-{color}"
    
  4. Don't use markers. Draw the arrowhead yourself.



标签: html reactjs svg