一个常见的使用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