如何创建SVG箭头和polymarker——`marker`元素
一个常见的使用SVG绘制的图形是箭头。一行代码就可以创建一个,但是这样代码重复度很大。你也可以在<defs>和<symbol>中定义好再去重用,但是你每次应用的时候都需要对其移动或旋转。直接用一个<marker>元素的话会方便很多。
前面几周的时候我讲过如何组织SVG代码,以及如何定义一个可重用的图形对象。可以翻一下w3cplus上SVG系列文章进行学习~
今天我想要讨论一个特殊的元素,可以在一个地方定义,然后在另一个地方引用的——marker,通常用来创建箭头和一些polymarker。
<marker>元素
marker是一种可以连结一个或多个path、line、polyline、或polygon的顶点的标志类型。最常见的用例是绘制箭头或在输出结果的线上的标记一个(polymarker)图形。
使用<marker>元素创建一个marker,以及其相关属性。通常我们把marker放在<defs>元素中,然后在其它地方对其进行引用。下面我们通过一个简单的实例来学习。
<svg width="600px" height="100px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<line x1="50" y1="50" x2="250" y2="50" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>
这个SVG包含了一个marker,以及一条引用marker的基础图形line。我们先来看看marker标签中的内容。它是包含在<defs>标签中的,所以它暂时不会被渲染出来。还赋了一个id为arrow。
在marker标签内是path,创建了一个红色的小三角形。前面我们介绍过line路径命令,这条path绘制的就是从(0,0)点开始,绘制一条直线到点(0,6),然后再画一条线到(9,3),然后z命令关闭路径,也就是画一条线回到点(0,0)。路径使用了#f00即红色填充。
我们先忽略marker中的内容(除了id="arrow")的属性,看看line元素。这是一条黑色(#000)的水平线,宽度为5px,从点(50,50)连到点(250,50)。
在line元素的结尾,有一个属性叫marker-end,通过"url(#arrow)"引用了前面定义的marker。结果如下。
我们先不管marker,改变line的内容,换一个相反的方向,并和水平方向成一个小角度。
<svg width="600px" height="100px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<line x1="295" y1="50" x2="95" y2="75" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>
第二条线从点(295,50)开始,连到点(95,75)。我只改变了线条的x和y的值。没有改动marker本身的任何东西。
marker的特殊之处就在于它们可以根据应用的对象指向的方向来调整方向。没有对<marker>中的内容做任何调整,箭头就自动调整为和line同一方向了。
marker的属性
现在我们来看看marker元素都有哪些属性吧。这是第一个实例的代码。
<svg width="600px" height="100px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<line x1="50" y1="50" x2="250" y2="50" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>
除了arrow这个id,marker还有六个属性在这里写出来了。
markerWidth和markerHeight属性定义了marker视窗的宽度和高度。marker在自己的视窗中展示,所以这个尺寸必须至少大于marker标签内定义的图形(除非你是要隐藏图形的某部分)。
上面的实例中我把markerWidth和markerHeight都设置为10px。path中绘制出的三角形需要适应9px x 6px的面积,所以我也可以把markerWidth设置为9,然互markerHeight设置为6。这是marker可以接受的最小尺寸,任何小于这个的尺寸都会导致图形被裁剪。
接下来的两个属性,refX和refY,指的是图形元素和marker连接的位置坐标。我们还给背后的场景应用了一个变换,来移动marker,与之对齐。
在实例中,我把三角形向上移动,通过把refY的值设置为3。将点(0,3)作为和图形元素连接的点。
下一个属性,orient,这个属性是我为什么在转换line的方向时,不需要调整marker的原因。它接受一个auto值,或者一个角度值,这个值决定了marker是否要旋转,在与其它内容连接的时候。
auto这个值表示marker会随着应用的元素一起旋转。45deg这个值则表示marker的方向一直保持45deg,不会随着连接的元素一起旋转。大多数时候这个值都是设置为auto的。
为了作对比,我们这里第二个示例设置了orient等于45deg。注意两个实例中的箭头都旋转了相同的角度。在第二个实例中它甚至被SVG视窗裁剪了,也就是它超出边框了。
最后一个属性是markerUNits,用于确定marker是否进行缩放。它定义了markerWidth和markerHeight,以及marker的内容本身的坐标系统。
它接受两个值,strokeWidth和userSpaceOnUse。默认值是strokeWidth,这也是大家大多数情况下会设置的值,因为它允许你的marker随着它连接的line进行缩放。
strokeWidth:坐标系统中的marker值和当前描边宽度的单位是相同的尺寸。也就是说strokeWidth这个值允许你的marker缩放。
userSpaceOnUse: marker的值是当前用户坐标系统的值。也就是说如果你的marker是一个半径为10px的圆,它就一直都是10px的半径,不受连接的元素的影响。
在这篇文章前面的那个实例中,我使用的是strokeWidth。创建了一个水平9px、垂直6px的三角形,然后把它和一个stroke-width为5px的line连接起来。如果你量了结果SVG中的三角形的尺寸,你会发现它的尺寸是45px乘30px。
下面这个是同一个SVG实例,只是把markerUnits的值修改成userSpaceOnUse。它的矩形就是9px乘6px。
有时候你可能会希望marker一直保持相同的尺寸,不过大家一般还是用strokeWidth这个值,来让marker随着连接的元素进行缩放。
上周我提到了你可以给symbol元素添加一个viewBox。同样的你也可以给marker元素添加一个viewBox,作额外的缩放。例如,这里我把markerUnits的值改回成strokeWidth,然后给marker元素添加一个viewBox。(关于viewBox,欢迎戳这里学习~)
<svg width="600px" height="100px">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth" viewBox="0 0 20 20">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<line x1="50" y1="50" x2="250" y2="50" stroke="#000" stroke-width="5" marker-end="url(#arrow)" />
</svg>
viewBox的值设为(0 0 20 20),是当前marker视窗(宽度为10,高度为10)两倍的大小,所以它会把三角形变成原来的一半大(注意,是一半!因为视窗变大啦)。结果如下。
给<symbol>元素添加viewBox也是同样的道理,symbol中的所有内容都会继承这个效果。
Marker特性——在元素中引用marker
这里我所有引用marker的实例都是用的同一种方法,设置id然后赋给marker-end属性。marker-end属性是marker的一个属性,表示在哪里连接marker。
marker-end="url(#arrow)"
给line、path、polyline、polygon这些基础图形应用marker一共有四种方法:
marker-start=”url(#marker-id)”marker-mid=”url(#marker-id)”marker-end=”url(#marker-id)”marker=”url(#marker-id)”
注意:你还可以在你的CSS中这样设置marker-end: url("#arrow");~
你应该可以理解marker-end和marker-start都是啥叻。这是使用marker-start的例子:
注意,箭头和之前一样都是指向一个方向。它不会改变方向,因为它指向的是line的终点。
你可能会想marker-mid是表示把marker放置在line的中间,但是不是哒。实际上如果我们把marker连接到一个line元素的marker-mid属性,是没有任何效果的。marker完全没有出现。
marker-mid属性设置在当polyline、path和polygon转换方向的位置点。这里我创建了另一个marker,里面放个圆形。我把三角形marker放到了polyline、line和path的尾部,然后把圆形marker放到了markerStart和markerMid。
<svg width="600px" height="400px" class="example">
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refx="0" refy="3" orient="auto" markerUnits="strokeWidth" viewBox="0 0 20 20">
<path d="M0,0 L0,6 L9,3 z" fill="#f00" />
</marker>
</defs>
<marker id="circle" markerWidth="4" markerHeight="4" refx="2" refy="2">
<circle cx="2" cy="2" r="2" stroke="none" fill="#f00"/>
</marker>
<polyline points="50,100 250,100 250,200 350,200" fill="none" stroke="#000" stroke-width="10" marker-end="url(#arrow)" marker-start="url(#circle)" marker-mid="url(#circle)" />
<path d="M50,100 l0,200 l50,0" stroke="#000" fill="none" stroke-width="10" marker-end="url(#arrow)" marker-start="url(#circle)" marker-mid="url(#circle)" />
<line x1="50" y1="100" x2="220" y2="270" stroke="#000" stroke-width="10" marker-end="url(#arrow)" marker-start="url(#circle)" marker-mid="url(#circle)"/>
</svg>
结果如下。有三个圆重叠出现在了line、polyline和path的起点位置。你只能看到最顶上的那个圆。
还有line(向右下45deg)并没有一个mid圆。而polyline和line在改变方向的地方都有一个圆,就是marker-mid。
marker属性(没有-start、-mid、-end)是其它三个简写,不过我没有发现它在哪里可以工作。
总结
marker是给图形元素(如line、path、polyline和polygon)添加内容的好方法,通常用来做箭头和连接点(如最后一个实例中的圆)。
你可以使用少量的属性来控制你的marker的尺寸和位置。还可以控制它是随着连接的内容一起缩放,或保持绝对尺寸。另外,四个marker(-start,-mid,-end)属性允许你将marker连接到line、polyline、polygon和path的不同位置。
下次我们要讨论另一个元素了,用来定义图形元素的。pattern元素,以及如何创建图案,填充到不同的元素上。
给大家找了几个codepen上关于marker的实例,巩固学习~
本文根据@Steven Bradley的《How To Create SVG Arrowheads and Polymarkers — The marker Element》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://vanseodesign.com/web-design/svg-markers/。
如需转载,烦请注明出处:http://www.w3cplus.com/svg/svg-markers.html




