神刀安全网

Making Arrows in SVG

Given that one of the common purposes ofSVG is to make diagrams and illustrations, it makes sense that terminating lines and paths with arrowheads is a very common request. While it is possible to decorate a line with its own, individual hand-coded arrow shape, it is much more efficient to use a arrowhead pattern via a <marker> definition.

You can add an arrowhead to line , polyline , polygon and path elements. The arrow shape is defined in a marker element, which is placed inside <defs> at the start of your SVG:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 100">   <defs>     <marker id="arrowhead" markerWidth="10" markerHeight="7"      refX="0" refY="3.5" orient="auto">       <polygon points="0 0, 10 3.5, 0 7" />     </marker>   </defs>   <line x1="0" y1="50" x2="250" y2="50" stroke="#000"    stroke-width="8" marker-end="url(#arrowhead)" /> </svg>

Which produces:

It’s easiest to think of the <marker> as being like a <symbol> or <pattern> : an element drawn within its own unique SVG space. In the example above, the space for the arrowhead is 10 units wide and 7 units high. In principle, any shape, line, or collection of elements could be drawn inside this space as an arrowhead. In this case, the shape is a triangle that touches the upper left and lower left corners of the marker area, with a point that touches the extreme right side. The <line> of the bottom of the SVG references this marker via its <id> .

The refX and refY attributes position the marker relative to the end of the path . Setting these values to 0 (the default) would place the top left corner of the <marker> at the termination of the line. In the case of a solid arrowhead, the values for an end arrow will be set to 0 for X position, and half the height of the marker for the Y position.

Setting orient to auto aligns the arrowhead to the path. We can see the affect of this if we alter the start or end point of the line:

<line x1="0" y1="0" x2="250" y2="50"   stroke="#000" stroke-width="8"   marker-end="url(#arrowhead)" />

In most cases, orient should be left with an auto value, but if it needs a little tweaking, the attribute can take a numerical value that defines the exact rotation of the arrowhead.

Double-Headed Arrows

Once the marker is defined, it can be reused as many times as you wish. An obvious application is to create paths or lines with double-headed arrows by using marker-start and marker-end . However , if you apply the same <marker> element to both ends, they’ll both point in the same direction:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 100">   <defs>     <marker id="arrowhead" markerWidth="10" markerHeight="7"   refX="0" refY="3.5" orient="auto">       <polygon points="0 0, 10 3.5, 0 7" />     </marker>   </defs>   <line x1="0" y1="50" x2="250" y2="50" stroke="#000" stroke-width="8"   marker-end="url(#arrowhead)" marker-start="url(#arrowhead)" /> </svg>

Which produces:

A better approach is to make two separate arrowheads, referencing them induvidually:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 350 100">   <defs>     <marker id="startarrow" markerWidth="10" markerHeight="7"      refX="10" refY="3.5" orient="auto">       <polygon points="10 0, 10 7, 0 3.5" fill="red" />     </marker>     <marker id="endarrow" markerWidth="10" markerHeight="7"      refX="0" refY="3.5" orient="auto" markerUnits="strokeWidth">         <polygon points="0 0, 10 3.5, 0 7" fill="red" />     </marker>   </defs>   <line x1="100" y1="50" x2="250" y2="50" stroke="#000" stroke-width="8"    marker-end="url(#endarrow)" marker-start="url(#startarrow)" /> </svg>

Which creates:

Note that the line is shorter to fit the arrowhead at the start, and that the refX value for the startarrow has changed.

In principle it should be possible to create a single <symbol> that is transformed into the appropriately-oriented arrowhead for either end of the line. That’s a little more challenging than it might first appear, so I’ll leave that technique for a future article.

Hairline & Scaled Arrows

All of the examples so far have been responsive, which means that both the arrowhead(s) and the line thickness will be altered with the width of the viewport. In some cases, you’ll want the line and arrows to change in dimension , but not thickness , typically to remain as hairlines.

This example is created from the following code:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 200">   <defs>     <style>         path, polyline {             fill: none;             stroke: #231F20;             vector-effect: non-scaling-stroke;             stroke-width: 2;        }         path {             stroke-dasharray: 11, 5;          }     </style>     <marker id="pointer" markerWidth="10" markerHeight="8"   refX="9.5" refY="5.1" orient="-45" markerUnits="userSpaceOnUse">         <polyline points="1 1, 9 5, 1 7" />     </marker>   </defs>   <path d="M16.7,178 c87.6-46.9,162.9-185.4,227-136.4C307.2,90.1,195,158.5,111,108.9C71,85.2,92.2,30.7,126,7"      marker-end="url(#pointer)"/> </svg>

In this case the arrow is a <polyline> element. Markers cannot inherit the stroke or fill of the element that they are attached to, but it’s easy to provide them with the same appearance using agrouped combinator in a style sheet, as shown above.

The default value for the markerUnits attribute is strokeWidth (which is the reason it’s not applied in the examples above). It defines the coordinate system for the marker: essentially the scale of the arrowhead as it relates to the path. strokeWidth relates the size of the marker to the stroke of the path; userSpaceOnUse uses the current co-ordinate system.

Using this in combination with vector-effect: non-scaling-stroke effectively makes the path and arrow hairline at any browser size; in this case, I’ve also manipulated the values of refX , refY and orient to “back up” the polyline arrowhead onto the path and provide it with a more aesthetically pleasing direction.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Making Arrows in SVG

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮