第13章:绘图:填充、描边和标记符号

13.1. 介绍

13.1.1. 定义

填充
绘画形状内部或文本字符串中字符字形内部的操作。
描边
绘画形状轮廓或文本字符串中字符字形轮廓的操作。

定义形状的图形元素——路径元素、基本形状文本内容元素——通过填充(绘画对象内部)和描边(沿对象轮廓绘画)进行渲染。填充和描边都是绘画操作。SVG 2支持多种不同的填充和描边涂料,包括:

用于填充和描边元素的涂料通过填充描边属性指定。以下部分描述了这些属性的不同值。

其他属性,如填充不透明度描边宽度,也会影响填充和描边涂料应用于画布的方式。以下的填充属性描边属性部分描述了这些属性。

某些图形元素——路径元素和基本形状——也可以在其顶点或沿其描述的路径的其他位置绘制标记符号。以下的标记部分描述了如何定义和使用标记。

SVG 2在形状上增加了标记。解决于东京 F2F

13.2. 指定绘制

SVG 2 要求: 添加新绘制值以引用当前填充绘制、轮廓绘制等。
解决方案: 我们将为 SVG 2 添加新的绘制值 currentFillPaint、currentStrokePaint 等
目的: 其中之一是提供一种简单的方法将标记颜色与轮廓颜色匹配。
负责人: Chris (ACTION-3094)
SVG 2 增加: 允许在填充和轮廓中使用多个绘制。
解决方案: 我们将在 SVG 2 中允许在填充和轮廓属性中使用多个绘制。
目的: 用于创建交叉线、在实心填充上放置部分透明的图案等。
负责人: Tav (ACTION-3500)
延迟: 这已被取消,但将与 CSS 填充和轮廓第 3 级同步添加

填充轮廓 属性用于指定用于渲染形状和文本的内部及周围的 绘制。绘制规范描述了一种将 颜色值放置到画布上的方法,并由一个或多个绘制层组成。 这四种绘制类型在这些绘制层中得到支持: 实色渐变图案

<paint> 值定义如下:

<paint> = none | <color> | <url> [none | <color>]? | context-fill | context-stroke

可能值如下:

none
该层未应用任何绘制。
<url> [none | <color>]?
指向一个 绘制服务器元素 的 URL 参考, 这是一个定义 绘制服务器 的元素: linearGradientpatternradialGradient, 可选地跟随一个后备值,用于在无法解析绘制服务器引用时使用。
<color>
实色绘制。
context-fill
使用来自 填充 的绘制值 从 上下文元素
context-stroke
使用来自 轮廓 的绘制值 从 上下文元素

<paint> 允许绘制服务器引用,后面可选地跟随 <color> 或关键字 none。 当给出这个可选值时,<color> 值或 none 是一个后备值,用于在该层中的绘制服务器引用无效时使用 (由于指向的元素不存在或不是有效的绘制服务器)。

注意,这与 CSS 背景语法略有不同,在该语法中,最终层的 背景 值中指定的背景图像和颜色将会同时渲染。

如果 <paint> 中的绘制服务器引用无效,并且没有给出后备值,则该层不渲染任何绘制。

这与 SVG 1.1 的行为不同,后者在绘制服务器引用无效且未指定后备颜色时会导致文档错误。

<rect width="100" height="100" fill="url(#MyHatch) powderblue">
  
带有后备实色填充的示例

左侧的矩形显示了如果定义了 MyHatch,则预期的填充。 右侧的矩形显示了如果缺少 MyHatch,则预期的填充。

对于任何 <color> 值,必须支持在 CSS 颜色模块第 3 级 中定义的所有颜色语法,包括 rgb()rgba()hsl()hsla()扩展颜色关键字currentColor 值。

context-fillcontext-stroke 是对被绘制元素的 填充轮廓 属性生成的绘制层的引用。被绘制元素的上下文元素定义如下:

如果没有上下文元素并且使用了这些关键字,则不应用任何绘制。

当上下文绘制层包含绘制服务器引用时,用于缩放绘制服务器元素和内容的坐标空间和边界框是 上下文元素 的坐标空间。换句话说,通过这些关键字引用的任何渐变和图案应该在主形状与标记之间,或者在一个 使用元素阴影树 中的一个元素与另一个元素之间是连续的。

如果 填充轮廓 的引用值为 context-fillcontext-stroke,则这些上下文引用是递归的。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <style>
    path {
      fill: none;
      stroke-width: 4px;
      marker: url(#diamond);
    }
  </style>
  <path d="M 10,50 v -20 h 40 v -20" stroke="red">
  <path d="M 30,70 v -20 h 40 v -20" stroke="green">
  <path d="M 50,90 v -20 h 40 v -20" stroke="blue">
  <marker id="diamond" markerWidth="12" markerHeight="12" refX="6" refY="6"
          markerUnits="userSpaceOnUse">
    <circle cx="6" cy="6" r="3"
            fill="white" stroke="context-stroke" stroke-width="2">
  </marker>
</svg>
使用 marker 中的 context-stroke 关键字的示例

该标记使用一个形状定义,其 轮廓 设置为 context-stroke。这导致标记采用使用该标记的每个 path 元素的颜色。

13.3. ‘color’ 属性的效果

有关 color 的定义,请参见 CSS 颜色模块第 3 级规范。 [css-color-3]

color 属性用于提供可能的间接值, currentColor,用于 fillstrokestop-colorflood-colorlighting-color 属性。该属性对 SVG 元素没有其他影响。

以下示例演示了如何使用来自 HTML 文档的继承值 color 属性来设置内联 SVG 片段中 SVG 文本的颜色。

<!DOCTYPE html>
<style>
body { color: #468; font: 16px sans-serif }
svg { border: 1px solid #888; background-color: #eee }
</style>
<p>请参见下方图示:</p>
<svg width="200" height="100">
  <g fill="currentColor">
    <text x="70" y="55" text-anchor="end">START</text>
    <text x="130" y="55">STOP</text>
    <path d="M 85,45 h 25 v -5 l 10,10 -10,10 v -5 h -25 z">
  </g>
</svg>

请参见下方图示:

START STOP

SVG 片段中的文本和箭头使用与继承的 color 属性相同的颜色填充。

13.4. 填充属性

13.4.1. 指定填充绘画:‘fill’ 属性

名称: fill
值: <paint>
初始值: 黑色
适用对象: 形状文本内容元素
继承:
百分比: 不适用
媒体: 视觉
计算值: 如指定,但 <color> 值计算 并且 <url> 值变为绝对值
可动画化

fill 属性用于填充给定图形元素的内部。要填充的区域包括形状轮廓内的任何区域。为了确定形状的内部,所有子路径都会被考虑,并且内部根据当前值的 fill-rule 属性相关规则进行确定。形状的零宽几何轮廓包括在要填充的区域内。

填充操作通过执行填充操作来填充 开放子路径,就像向路径中添加一个额外的“closepath”命令以连接子路径的最后一点和第一点。因此,填充操作适用于 开放子路径 内的 path 元素(即没有 closepath 命令的子路径)和 polyline 元素。

13.4.2. 轮廓规则:‘fill-rule’ 属性

名称: fill-rule
值: nonzero | evenodd
初始值: nonzero
适用对象: 形状文本内容元素
继承:
百分比: 不适用
媒体: 视觉
计算值: 如指定
可动画化

fill-rule 属性指示用于确定画布上哪些部分包含在形状内部的算法(或 轮廓规则)。对于简单的、不相交的路径,"内部" 区域是直观清晰的;然而,对于更复杂的路径,例如自相交的路径或一个子路径包含另一个子路径的情况,"内部" 的解释并不那么明显。

fill-rule 属性提供了两种确定形状内部的选项:

nonzero

此规则通过从该点向任意方向绘制一条光线到无穷远来确定画布上某点的 "内部"。然后检查形状的哪个段与光线相交。从零开始计数,每当路径段从左到右穿过光线时加一,每当路径段从右到左穿过光线时减一。计数完成后,如果结果为零,则该点位于路径 外部;否则,位于 内部。以下图示说明了 nonzero 规则:

Image showing nonzero fill rule

非零填充规则对自交和封闭子路径的影响。

evenodd

此规则通过从该点向任意方向绘制一条光线到无穷远并计算光线穿过给定形状的路径段的数量来确定画布上某点的 "内部"。如果这个数字是奇数,则该点在内部;如果是偶数,则该点在外部。以下图示说明了 evenodd 规则:

Image showing evenodd fill rule

偶数填充规则对自交和封闭子路径的影响。

上述描述没有说明如果路径段与光线重合或相切该如何处理。由于任何光线都可以使用,因此可以简单选择另一条没有此类问题交点的光线。

13.4.3. 填充绘画不透明度:‘fill-opacity’ 属性

名称: fill-opacity
值: <alpha-value>
初始值: 1
适用对象: 形状文本内容元素
继承:
百分比: 不适用
媒体: 视觉
计算值: 指定值转换为数字,限制在范围 [0,1] 内
可动画化

fill-opacity 指定用于绘制当前对象填充的不透明度。(参见 绘制形状和文本)。

<number>
填充的不透明度。任何超出范围 0(完全透明)到 1(完全不透明)的值必须限制在此范围内。
<percentage>
填充的不透明度以 0 到 1 范围的百分比表示。

另请参见 不透明度 属性,它指定组的不透明度。

13.5. 描边属性

SVG 2 要求: 支持非缩放描边。
解决方案: SVG 2 将包括非缩放描边。
SVG 2 将拥有 ‘vector-effect’ 属性。
目的: 支持在缩放页面时宽度不变的描边,例如地图中常见的描边。
负责人: Chris 或 Erik(无行动)
备注: 请注意,这可能是更通用的非缩放特性的组成部分。

在本节中,我们定义了一些属性,使作者能够控制描边的不同方面,包括其绘画、厚度、虚线的使用以及路径段的连接和端点。

在所有情况下,所有受方向性影响的描边属性,例如与虚线模式有关的属性,必须以图形元素开始的同一点开始渲染描边操作。特别是,对于 path 元素,路径的起点是初始 "moveto" 命令的第一个点。

对于计算依赖于图形元素轮廓进度的描边属性,例如虚线模式,需要使用 SVG 用户代理的标准 沿路径的距离 算法进行距离计算。

当使用复杂的绘画服务器(例如渐变或图案)进行描边时,描边操作必须与如果将当前图形元素及其相关描边属性定义的几何形状转换为等效的 path 元素并使用给定的绘画服务器填充时的结果相同。

13.5.1. 指定描边绘画:‘stroke’ 属性

名称: stroke
值: <paint>
初始值:
适用对象: 形状文本内容元素
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定,但 <color> 值计算后,<url> 值变为绝对值
可动画化

stroke 属性沿给定图形元素的轮廓进行绘制。

请注意,当描边 path 元素时,任何仅由 moveto 组成的子路径但没有后续的线条绘制命令将不会被描边。任何其他类型的零长度子路径,例如 'M 10,10 L 10,10''M 30,30 Z' 也不会被描边,如果 stroke-linecap 属性的值为 butt。有关计算路径描边的详细信息,请参见下面的 描边形状 定义。

SVG 2 要求: 包含指定描边位置的方法。
解决方案: SVG 2 将包括指定描边位置的方法。
目的: 允许描边位于路径内部或外部。
负责人: Cameron (ACTION-3162)
备注: 请参见 提案页面

13.5.2. 描边绘画的不透明度:‘stroke-opacity’ 属性

名称: stroke-opacity
值: <alpha-value>
初始值: 1
适用对象: 形状文本内容元素
继承:
百分比: N/A
媒体: 视觉
计算值: 指定的值转换为数字,限制在 [0,1] 范围内
可动画化

stroke-opacity 属性指定用于描边当前对象的绘制操作的不透明度。(参见 绘制形状和文本。)与 fill-opacity 相同。

<number>
描边的不透明度。任何超出 0(完全透明)到 1(完全不透明)范围的值必须限制在此范围内。
<percentage>
描边的不透明度以 0 到 1 的百分比表示。

另请参见 不透明度 属性,该属性指定组的不透明度。

13.5.3. 描边宽度:‘stroke-width’ 属性

名称: stroke-width
值: <length-percentage>
初始值: 1
适用对象: 形状文本内容元素
继承:
百分比: 参照当前 SVG 视口的大小(见 单位
媒体: 视觉
计算值: 绝对长度或百分比
可动画化

该属性指定当前对象的描边宽度。零值将导致不绘制描边。负值是 无效 的。

13.5.4. 描边末端的绘制帽形:‘stroke-linecap’ 属性

名称: stroke-linecap
值: butt | round | square
初始值: butt
适用对象: 形状文本内容元素
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定
可动画化

stroke-linecap 属性指定在描边时使用的形状 以及零长度子路径的绘制形状,无论它们是开放还是闭合的。可能的值有:

butt
此值表示每个子路径的描边不超过其两个端点。因此,零长度子路径将没有任何描边。
round

此值表示在每个子路径的末端,表示描边的形状将通过直径等于描边宽度的半圆扩展。如果子路径(无论是开放还是闭合)长度为零,那么最终效果是该子路径的描边仅由一个位于子路径点的完整圆构成。

square

此值表示在每个子路径的末端,表示描边的形状将通过与描边宽度相同的矩形扩展,其长度为描边宽度的一半。如果子路径(无论是开放还是闭合)长度为零,那么最终效果是该子路径的描边仅由一个边长等于描边宽度的正方形构成,正方形居于子路径的点,并且有两个边与该子路径点的有效切线平行。有关如何确定零长度子路径的切线的详细信息,请参见‘path’ 元素实施说明

显示三条路径,每条路径具有不同的线帽。

三种线帽的类型。

有关线帽形状的更精确描述,请参见下面的帽形定义。

13.5.5. 控制线段连接:‘stroke-linejoin’ 和‘stroke-miterlimit’属性

名称: stroke-linejoin
值: miter | miter-clip | round | bevel | arcs
初始值: miter
适用对象: 形状文本内容元素
继承:
百分比: N/A
媒体: 视觉
计算值: 如所指定
可动画

stroke-linejoin 指定在描边时用于路径或基本形状角落的形状。有关更多详细信息,请参见路径实现说明

miter
该值指示使用尖锐的角来连接路径段。角是通过在路径段的切线处扩展描边的外缘,直到它们相交而形成的。如果超出了stroke-miterlimit,则线连接回落到bevel(见下文)。
miter-clip
该值与miter相同,但如果超出了stroke-miterlimit,则在距离路径段交点的描边宽度乘以一半的stroke-miterlimit值处裁剪斜角。
round
该值指示使用圆形角来连接路径段。角是以连接点为中心的圆形扇形。
bevel
该值指示使用斜面角来连接路径段。斜面形状是填充两个描边段之间区域的三角形。
arcs
该值指示使用弧角来连接路径段。弧形是通过在连接点处扩展描边的外缘,并以相同的曲率形成的弧线。

miter-cliparcs值在SVG 2中是新的。 miter-clip值为具有多个连接的路径提供了更一致的展示,以及在路径动画时的更好行为。 arcs值在路径段在连接处是曲线时提供了更美观的连接。

添加 'arcs' 线连接是在Rigi Kaltbad小组会议上解决的。

添加 'miter-clip' 线连接是在悉尼(2015)小组会议上解决的。

显示四条路径,每条路径具有不同线连接的图像。

四种类型的线连接。

名称: stroke-miterlimit
值: <number>
初始值: 4
适用对象: 形状文本内容元素
继承:
百分比: N/A
媒体: 视觉
计算值: 如所指定
可动画

当两条线段在锐角相遇,并且为stroke-linejoin指定了mitermiter-cliparcs值时,连接可能会远远超过描边路径的线的厚度。 stroke-miterlimit对线连接的范围施加了限制。

<number>
mitermiter-cliparcs线连接的范围限制,以描边宽度值的倍数表示。 stroke-miterlimit的负值必须视为非法值

以前版本的SVG规范也指出0到1之间的值是错误的,但这在用户代理的CSS解析器中实现得不够好。 实际上,任何斜接连接都将超出0到1之间的斜接限制。

对于mitermiter-clip值,给定用户坐标系中段之间的角度θ, 斜接长度的计算公式为:

斜接长度 = ‘描边宽度’ sin θ 2
斜接长度 = 描边宽度 / sin(theta / 2)

历史上,斜接长度定义为相交路径段内部描边边缘到斜接顶端的距离。在实践中,仅对直线路径段遵循此定义。基于角度的斜接长度定义仅依赖于路径段在连接处的切线,从而提供一致的结果,而不受路径段曲率的影响。为了与此定义一致,miter-cliparcs线连接的裁剪点位于两个路径段连接点处,距离为描边宽度乘以一半的stroke-miterlimit

显示描边斜接长度定义和不同形状路径段之间裁剪一致性的图像。

左:斜接长度的历史定义。 右:两条路径在路径段连接处具有相同的切线。斜接连接的行为(回落到斜面或裁剪位置)对两条路径是相同的。它不依赖于内部描边边缘相交的位置。

如果斜接长度除以描边宽度超过stroke-miterlimit,则对于值:

miter
连接将转换为斜面;
miter-clip
斜接通过一条垂直于夹角二分线的线裁剪,裁剪距离为斜接长度的一半,从两个路径段交点开始。
显示当描边斜接限制被超过时的结果描边图像。

stroke-miterlimit被超过时,线连接的效果。橄榄绿色虚线显示描边斜接限制的位置,当stroke-miterlimit值为3时。灰色区域显示没有斜接限制时连接的样子。

对于arcs值,斜接长度是在连接的两段之间切线的角二分线上的圆弧上计算的,该圆弧经过连接的端点。如果需要,线连接将通过与此弧线垂直的线裁剪,裁剪距离为两个路径段交点的距离,等于stroke-miterlimit值的一半乘以描边宽度。

'stroke-miterlimit' 对'arcs'线连接的影响是在悉尼(2015)小组会议上解决的。

有关线连接形状的更精确描述,请参见线连接形状的定义。

13.5.6. 线段虚线:‘stroke-dasharray’ 和 ‘stroke-dashoffset’ 属性

名称: stroke-dasharray
值: none | <dasharray>
初始值: none
适用对象: 形状文本内容元素
继承:
百分比: 参照当前SVG视口的大小(见 单位
媒体: 视觉
计算值: 绝对长度或百分比,或关键词指定
可动画化 是 (非加法)

其中:

<dasharray> = [ <length-percentage> | <number> ]#*

stroke-dasharray 属性控制 用于形成路径线条形状的虚线和间隙模式。

none
表示不使用虚线。
<dasharray>

指定要使用的虚线模式。<dasharray> 是 一个以逗号和/或空格分隔的长度或百分比的列表。 每个值指定沿路径的线条要绘制的长度(虚线)和不绘制的长度(间隙)。 列表中的第一个值及其后每隔一个值指定虚线的长度,而每个其他值指定虚线之间的间隙长度。 如果列表有奇数个值,则重复该列表以产生偶数个值。(因此,stroke-dasharray: 5,3,2 的渲染行为等同于 stroke-dasharray: 5,3,2,5,3,2。)

结果的偶数长度虚线模式在每个子路径上重复。 虚线模式在每个子路径的起始处重置并重新开始。

如果列表中的任何值为负,则<dasharray> 值 是无效。如果列表中的所有值均为零, 则线条将作为一条实线呈现,而没有任何虚线。

显示粗虚线的图像。

一条虚线。虚线模式是 20,10。 红线显示实际绘制的路径。

pathLength 属性在path 元素上 影响stroke-dasharray:每个虚线和间隙长度 相对于作者指定的路径长度进行解释 pathLength

名称: stroke-dashoffset
值: <length-percentage>
初始值: 0
适用对象: 形状文本内容元素
继承:
百分比: 参照当前SVG视口的大小(见 单位
媒体: 视觉
计算值: 绝对长度或百分比
可动画化

stroke-dashoffset 属性指定 在路径开始处开始绘制虚线模式的距离。如果值为负,则效果与虚线偏移 d 相同:

d = s - ‘stroke-dashoffset’ mod s
d = s - (abs(stroke-dashoffset) mod s)

其中 s 是虚线数组值的总和。

显示具有非零虚线偏移的粗虚线的图像。

一条虚线,具有非零的虚线偏移。虚线模式是 20,10,虚线偏移为 15。红线显示实际绘制的路径。

stroke-dasharray 类似,stroke-dashoffset 是相对于作者在pathLength 元素上指定的路径长度进行解释的 path 元素。

下面的例子展示了如何使用一个与实际路径长度大相径庭的pathLength 来更轻松地控制笔画虚线。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     width="300" height="150">
  <defs>
    <path id="p" d="M -50,0 A 50,50 0 0 0 50,0 A 50,50 0 0 0 -50,0 z"
          pathLength="80">
    <g id="chip" stroke-width="10">
      <circle cy="5" r="55" fill="#000" fill-opacity="0.15" stroke="none">
      <use xlink:href="#p">
      <use xlink:href="#p" fill="none" stroke="#eee" stroke-width="10"
           stroke-dasharray="10 10" stroke-dashoffset="5">
      <g fill="none" stroke-width="5" stroke-dasharray="0 20" stroke-linecap="round">
        <use xlink:href="#p" stroke="#eee" stroke-dashoffset="10">
        <use xlink:href="#p" stroke-dashoffset="0">
      </g>
      <circle r="40" fill="#000" fill-opacity="0.15"
              stroke-width="2" stroke="white">
    </g>
  </defs>
  <rect width="100%" height="100%" fill="#063">
  <use xlink:href="#chip" x="140" y="75" fill="#00c" stroke="#00c">
  <use xlink:href="#chip" x="160" y="85" fill="#000" stroke="#000">
  <use xlink:href="#chip" x="170" y="65" fill="#c00" stroke="#c00">
</svg>
三枚赌场筹码的图像,每个筹码都有一个使用笔画虚线产生的图案边框。

四个宽白色虚线和每个筹码周围的八个小圆形虚线相对于作者指定的pathLength'80',使得所需的stroke-dasharraystroke-dashoffset 值易于计算。

请参见下面的虚线位置定义,以获取有关路径上虚线放置位置的更精确描述。

13.5.7. 计算描边的形状

SVG 2 要求: 更精确地指定笔划虚线。
解决方案: SVG 2 应更精确地指定笔划虚线。
目的: 定义基本形状和路径段上的虚线起点。
所有者: Cameron(无行动)

笔划形状是元素由笔划属性填充的形状。由于文本元素可以分块呈现,每块都有自己的笔划形状。以下算法描述了路径基本形状或单个文本块的理想笔划形状,考虑到上述笔划属性。描述的理想笔划形状定义了最佳情况实现,但实现可以在性能原因上有一定的偏差。

作者应注意,在某些情况下,例如在极紧的曲线处,笔划的形状可能在不同平台上有所不同。
图像显示了如何在不同平台上笔划形状的差异。一个示例是本规范中算法描述的,而另一个则不同,整体看起来不太正确。它的不同之处在于,由于曲线末端与高曲率段的接近,描述笔划左右两侧的几何图形被扭曲。

笔划形状在不同平台上的绘制示例。

以上示例显示了以下两个SVG路径的可能渲染结果:
<svg viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
<path d="M 1,3 C 8,2 8,6 7,6" stroke-width="4" fill="none" stroke="skyblue">
<path d="M 1,3 C 8,2 8,6 7,6" stroke-width="0.075" fill="none" stroke="black">
</svg>
理想的笔划形状的确定如下:
  1. shape为空形状。
  2. 如果笔划宽度 > 0,则:
    1. scale成为虚线模式的缩放因子。如果我们正在计算文本块的笔划形状,或如果元素上没有pathLength属性,则scale为1。否则,它的确定如下:
      1. length为用户代理计算的路径等效路径的长度。
      2. authorlength形状pathLength属性的值。
      3. scaleauthorlength / length
    2. path为元素的等效路径(或单个文本元素的块)。
    3. 对于path的每个子路径:
      1. positions为子路径的虚线位置
      2. 对于positions中的每对<start, end>:
        1. scale缩放startend
        2. dash成为包括子路径上startend之间所有距离的形状,所有位于该距离的子路径上的点都在距该位置stroke-width范围内的垂直线上的点。
        3. dash设为dash与子路径在位置start的起始端部形状的并集。
        4. dash设为dash与子路径在位置end的结束端部形状的并集。
        5. indexlast成为子路径中在距离startend的路径段的索引。

          选择indexlast时是否包含任何零长度段并不重要。

        6. index < last时:
          1. dash设为dash与子路径在段索引index线连接形状的并集。
          2. index加1。
        7. shape设为shapestroke的并集。
  3. 返回shape

给定等效路径路径基本形状的子路径的虚线位置是一系列成对的值,表示构成子路径笔划的每个虚线的起始和结束距离。其确定如下:

  1. pathlength为子路径的长度。
  2. dashes为元素上stroke-dasharray属性的值,转换为用户单位,必要时重复以使其具有偶数个元素;如果属性的值为none,则列表仅包含一个值0。
  3. countdashes中的值的数量。
  4. sumdashes中值的总和。
  5. 如果sum = 0,则返回序列<0, pathlength>。
  6. positions为空序列。
  7. offset为元素上stroke-dashoffset属性的值。
  8. 如果offset为负,则将offset设为sum − abs(offset)。
  9. offset设为offset mod sum
  10. index为最小的整数,使得sum(dashesi, 0 ≤ iindex) ≥ offset
  11. dashlength为min(sum(dashesi, 0 ≤ iindex) − offset, pathlength)。
  12. 如果index mod 2 = 0,则将对positions追加对<0, dashlength>。
  13. positiondashlength
  14. position < pathlength时:
    1. index设为(index + 1)mod count
    2. dashlength为min(dashesindex, pathlengthposition)。
    3. 如果index mod 2 = 0,则将对positions追加对<position, position + dashlength>。
    4. position设为position + dashlength
  15. 返回positions

给定子路径上某一位置的起始和结束端点形状的确定方法如下:

  1. 如果stroke-linecapbutt,则返回一个空形状。
  2. 否则,如果stroke-linecapround,则:
    1. 如果这是一个起始端点,则返回一个直径为stroke-width的半圆,其位置如下:
      • 半圆相对于的子路径是从距离position开始的子路径。
      • 其直边与子路径在距离position处的垂直线平行。
      • 其直边的中点位于沿子路径在距离position处的点。
      • 从弧的中点到直边中点的方向与子路径在距离position处的方向相同。
    2. 否则,这是一个结束端点。返回一个直径为stroke-width的半圆,其位置如下:
      • 半圆相对于的子路径是到距离position结束的子路径。
      • 其直边与子路径在距离position处的垂直线平行。
      • 其直边的中点位于沿子路径在距离position处的点。
      • 从直边的中点到弧的中点的方向与子路径的方向相同。
  3. 否则,stroke-linecapsquare
    1. 如果这是一个起始端点,则返回一个边长为stroke-widthstroke-width / 2的矩形,其位置如下:
      • 其长边AB与子路径在距离position处的垂直线平行。
      • A的中点位于start
      • B的中点到A的中点的方向与子路径在距离position处的方向相同。
    2. 否则,这是一个结束端点。返回一个边长为stroke-widthstroke-width / 2的矩形,其位置如下:
      • 其长边AB与子路径在距离position处的垂直线平行。
      • A的中点位于end
      • A的中点到B的中点的方向与子路径在距离position处的方向相同。
展示如何构造三种类型线条端点的图像

在具有单个非零长度子路径的路径上使用的三种不同stroke-linecap值。白线是路径本身,厚灰色区域是笔划。在顶部行中,绿色线条表示路径端点的切线的垂直线,粉色区域是端点形状。底行展示了没有突出垂直线和端点形状的笔划。

给定子路径的一段的线连接形状的确定如下:

  1. P为段末端的点。
  2. 如果段末端的单位切向量与后续段的单位切向量相等,则返回一个空形状。

    这意味着例如'M 100,100 h 100 h 100'不会在两个直线段之间产生线连接形状,但'M 100,100 h 100 h -100'会。

  3. A为与段末端切线平行的线。
  4. B为与后续段切线平行的线。
  5. AleftAright为与A平行的线,距离为线宽 / 2,分别位于相对于子路径方向的左侧和右侧。
  6. BleftBright为与B平行的线,距离为线宽 / 2,分别位于相对于子路径方向的左侧和右侧。
  7. P1P2P3为如下所述的点:
    1. 如果AB之间的较小角度位于这些线的右侧,考虑子路径的方向,则P1P2为位于AleftBleft上距离P最近的点,而P3AleftBleft的交点。
    2. 否则,P1P2为位于ArightBright上距离P最近的点,而P3ArightBright的交点。
  8. bevel为由三点PP1P2形成的三角形。
  9. 如果线连接样式圆角,则返回bevel和以P为中心、直径为线宽的圆弧的并集,圆弧的两个端点为P1P2
  10. 如果线连接样式arcs,则找到在P1P2处与边缘切的圆,且在这些点处的曲率与边缘相同(见下文)。如果两个曲率均为零,则转到斜接剪裁。如果任一曲率大于2/(线宽),则回退到圆角。 扩展使用这些圆(或在曲率为零的情况下的线)来延伸边缘。 如果两个圆(或圆与线)不相交,则调整两个圆的半径,使它们相交(见下文)。 线连接区域由连接PP1P2的线以及由圆(或弧与线)定义的弧段组成,弧段从离P最近的交点延伸至P1P2。 接下来计算斜接限制,如斜接限制部分所定义。剪裁任何超出斜接限制的线连接区域。返回结果区域。 请注意,曲率在用户空间中计算,在应用任何变换之前。
  11. 如果线连接样式斜接斜接剪裁,则线连接区域为bevel与由三点P1P2P3形成的三角形的并集。
  12. θAB之间的角度。如果1 / sin(θ / 2) ≤ 斜接限制,则返回线连接区域。
  13. 如果线连接样式斜接剪裁,则剪裁任何超出斜接限制的线连接区域并返回此区域。
  14. 返回bevel
显示构造圆角线连接的线条和点的图像。

圆角线连接形状的构造,显示为粉红色。白线为原始路径,包含两个汇聚到一点的段,灰色区域为笔画。

显示构造弧线连接的线条和点的图像。

弧线连接形状的构造,显示为粉红色。白线为原始路径,包含两个汇聚到一点的段,深灰色区域为笔画。虚线表示在连接处与段切的圆。橄榄绿色圆圈(与虚线圆圈同心)定义连接形状。

13.5.8. 计算arcs的 'stroke-linejoin'

arcs stroke-linejoin 需要找到与路径段末端的外部笔划边缘相切且具有相同曲率的圆。要找到其中一个圆,首先计算路径段末端的曲率 κ(见下文)。接下来,找到与该曲率对应的圆的半径:r = 1/κ。增加或减少半个笔划宽度以考虑笔划:rc = r ± ½ 笔划宽度。圆心将位于路径末端法线方向上,距离外部笔划边缘 rc 的位置。

对于直线:曲率为零。通过一条直线延伸外部笔划边缘。

对于椭圆弧:

κ ( t ) = r x r y ( r x 2 sin 2 t + r y 2 cos 2 t ) 3 / 2
$$\kappa(t) = {{r_x r_y}\over{(r_x^2 \sin^2 t + r_y^2 \cos^2 t)^{3/2}}}$$

其中:

t = arctan ( r y r x tan θ )
$$t = \arctan \left( {r_y \over r_x} \tan \theta \right)$$

在弧段的开始或结束处,参数 θ 可以通过使用 椭圆弧实现说明 中的公式找到。(注意,一些渲染器在渲染之前将椭圆弧转换为三次 Bézier 曲线,因此这里的方程可能不需要。)

对于二次 Bézier:

κ ( 0 ) = 1 2 ( P 1 P 0 ) × ( P 2 P 1 ) | P 1 P 0 | 3
$$\kappa(0) = {2\over3}{(P_1-P_0)\times((P_0-P_1)+(P_2-P_1))\over|P_1-P_0|^3}$$
κ ( 1 ) = 1 2 ( P 2 P 1 ) × ( P 0 P 1 ) | P 2 P 1 | 3
$$\kappa(0) = {2\over3}{(P_1-P_0)\times((P_0-P_1)+(P_2-P_1))\over|P_1-P_0|^3}$$

其中 κ(0)κ(1) 分别是路径段开始和结束处的带符号曲率,P 是定义二次 Bézier 的三个点。

对于三次 Bézier:

κ ( 0 ) = 2 3 ( P 1 P 0 ) × ( P 2 P 1 ) | P 1 P 0 | 3
$$\kappa(0) = {2\over3}{(P_1-P_0)\times((P_0-P_1)+(P_2-P_1))\over|P_1-P_0|^3}$$
κ ( 1 ) = 2 3 ( P 3 P 2 ) × ( P 1 P 2 ) | P 3 P 2 | 3
$$\kappa(1) = {2\over3}{(P_3-P_2)\times((P_1-P_2)+(P_3-P_2))\over|P_3-P_2|^3}$$

其中 κ(0)κ(1) 分别是路径段开始和结束处的带符号曲率,P 是定义三次 Bézier 的四个点。注意,如果 P0P1,或 P2P3 是退化的,则曲率将是无限的,应使用直线构建连接。

13.5.9. 调整 arcs 的 'stroke-linejoin' 圆形,当初始圆形不相交时

回退行为在 2016 年悉尼 F2F 上解决。它提供了回退与非回退状态之间的平滑过渡。

当为 arcs 的初始圆形 stroke-linejoin 计算的圆形不相交时,需要通过相同幅度调整两个半径(移动圆心以保持圆形与偏移路径相切),直到圆形恰好接触。需要考虑两种情况。第一种情况是一个圆包围另一个圆。在这种情况下,较大的圆减小尺寸,而较小的圆增大尺寸:

展示当原始偏移圆形不相交时计算的弧线连接的图像。

构建的弧线连接形状,显示为粉色。白线是原始路径,深灰区域是笔画。虚线显示与连接段相切并具有段的曲率的圆。注意,圆形不相交。通过相同幅度调整原始圆的半径构造两个新圆,较大的圆变小,较小的圆变大,直到新圆刚好接触,如橄榄绿色圆所示。这些新圆定义了连接形状。

第二种情况是圆之间没有重叠。在这种情况下,两个圆的半径都增加相同的量:

展示当原始偏移圆形不相交时计算的弧线连接的图像。

构建的弧线连接形状,显示为粉色。白线是原始路径,深灰区域是笔画。虚线显示与连接段相切并具有段的曲率的圆。注意,它们不相交。通过增加原始圆的半径相同的量构造两个新圆,直到新圆刚好接触,如橄榄绿色圆所示。这些新圆定义了连接形状。

如果在这种情况下,连接处偏移路径的切线平行,则圆形无法调整以使其接触。连接应构造为一个矩形,宽度为笔画宽度,长度为笔画宽度乘以 stroke-miterlimit 的一半:

展示当原始偏移圆形不相交时计算的弧线连接的图像。

构建的弧线连接形状,显示为粉色。白线是原始路径,有两个段形成一个点,深灰区域是笔画。虚线显示与连接段相切并具有段的曲率的圆。注意,它们不相交。即使圆的半径增加到无穷大,圆也不会相交。连接则是一个矩形,长度由斜接限制决定(以垂直虚线表示)。

实现回退算法有几种方法。第一种方法是通过对半径变化幅度的递归试错。第二种是通过利用 接触圆条件 的精确计算以及圆心必须保持在连接处路径段法线上的约束。这导致一个二次方程,其中一个解是所需的半径变化。

13.6. 向量效果

本章解释与绘制相关的 vector-effect。有关 vector-effect 的视角,请参考 此处

non-scaling-stroke
修改对象的描边方式。通常,描边涉及在当前 用户坐标系 中计算形状路径的描边轮廓并用描边油漆(颜色或渐变)填充该轮廓。使用 non-scaling-stroke 向量效果时,描边轮廓应在“主机”坐标空间中计算,而不是在 用户坐标系 中。更准确地说:用户代理建立了一个主机坐标空间,在 SVG Tiny 1.2 中,它始终与“屏幕坐标空间”相同。描边轮廓的计算方法如下:首先,将形状的路径转换到主机坐标空间。描边轮廓在主机坐标空间中计算。然后,结果轮廓被转换回 用户坐标系。(描边轮廓始终在当前用户坐标系中用描边油漆填充。)这种修改的结果是,描边宽度不依赖于元素的变换(包括非均匀缩放和剪切变换)和缩放级别。

13.7. 标记

SVG 2 要求: 改善标记。
决议: 我们将改善 SVG 2 的标记。
目的: 解决作者在 SVG 标记中遇到的常见问题。
负责人: Cameron (ACTION-3286)

标记是沿着任何 形状 元素特定位置绘制的图形对象。

marker-startmarker-end 属性可用于在 形状 的第一个和最后一个顶点放置标记,而 marker-mid 属性可用于在所有其他顶点(除了第一个和最后一个)放置标记。marker-startmarker-end 例如可以用来在路径上添加箭头。使用这些属性放置的标记称为 顶点标记

在 SVG 2 中,顶点标记是唯一可用的标记类型。其他规范将添加新类型的标记。

标记的图形由 marker 元素定义。marker-startmarker-endmarker-mid 属性统称为 标记属性,引用 marker 元素。

标记可以被动画,并且与 use 元素一样,动画效果将在文档中标记的所有当前使用中显示。

给定元素上的标记按以下顺序绘制,从底部到顶部:

13.7.1. ‘marker’ 元素

marker
类别:
容器元素从不渲染的元素
内容模型:
任何数量的以下元素,顺序不限:aaudiocanvasclipPathfilterforeignObjectiframeimagemarkermaskscriptstyleswitchtextvideoview
属性:
DOM 接口:

marker’ 元素定义了用于在 形状 上绘制标记的图形。

属性定义:

名称 初始值 可动画
markerUnits strokeWidth | userSpaceOnUse strokeWidth

markerUnits’ 属性定义了属性 markerWidthmarkerHeightmarker 内容的坐标系统。值的含义如下:

strokeWidth
markerWidthmarkerHeightmarker 的内容在坐标系统中具有一个单位,等于引用该标记的元素的绘制笔划宽度的用户单位。
userSpaceOnUse
markerWidthmarkerHeightmarker 的内容在引用该标记的元素的当前用户坐标系统中具有值。

当 ‘markerUnits’ 的值为 strokeWidth 时,标记的大小相对于在 stroke-width 上应用的任何变换后的宽度。这意味着,例如,具有值 non-scaling-strokevector-effect 属性将导致标记也不缩放。

名称 初始值 可动画
markerWidthmarkerHeight <length-percentage> | <number> 3

markerWidth’ 和 ‘markerHeight’ 属性表示 SVG 视口的大小,标记根据 viewBoxpreserveAspectRatio 属性被适配。任何一个属性的值为零将导致标记不被渲染。任何一个属性的负值是错误的(见 错误处理)。

名称 初始值 可动画
refX <length-percentage> | <number> | left | center | right 0
refY <length-percentage> | <number> | top | center | bottom 0

新增于 SVG 2: 几何关键字(与 symbol 的用法匹配)。

我们将为 refX/refY 在标记/符号上添加 top/center/bottom、left/center/right 关键字。解决于 伦敦 F2F。值受 'background-position' 启发。

refXrefY 属性定义了标记的参考点,标记将被精确放置在 形状 上。 长度和数字必须被解释为在应用 viewBoxpreserveAspectRatio 属性后的标记内容的坐标系统中。 百分比值必须被解释为在 viewBox 宽度的百分比对于 refX 或者 refY 的高度百分比。

关键字值必须评估为以下百分比:

refX 和 refY 关键字到百分比的映射。
关键字 百分比等价
left 0%
center 50%
right 100%
top 0%
bottom 100%
名称 初始值 可动画
orient auto | auto-start-reverse | <angle> | <number> 0 是(非累加)

orient 属性指示标记在其位置上放置时如何旋转,位于 形状 上。 值的含义如下:

'auto'

标记的正 x 轴指向标记放置位置相对于路径的方向(见 渲染标记)。

'auto-start-reverse'

如果通过 marker-start 放置,则标记的 方向与 'auto' 指定的方向相差 180°。对于 所有其他标记,'auto-start-reverse' 的意思与 'auto' 相同。

这允许定义一个单一的箭头标记,可以用于路径的起始和结束,即指向两个末端的外部。

<angle>
<number>

标记的方向是指定角度与 形状 的正 x 轴和标记的正 x 轴之间的角度。 <number> 值指定以度为单位的角度。

例如,如果给定值为 '45',则标记的正 x 轴将在 形状 的坐标系统中指向下方和右方。

13.7.2. 顶点标记:‘marker-start’, ‘marker-mid’ 和 ‘marker-end’ 属性

名称: marker-startmarker-midmarker-end
值: none | <marker-ref>
初始: none
适用对象: 形状
继承:
百分比: N/A
媒体: 视觉
计算值: 按指定值,但包含的<url>值(属于 <marker-ref>)变为绝对值
可动画

其中:

<marker-ref> = <url>

marker-startmarker-end 属性用于 指定在给定的形状的第一个和最后一个顶点 处绘制的标记。marker-mid 用于指定在所有其他顶点绘制的标记(即,除了第一个和最后一个顶点)。 marker-startmarker-midmarker-end 的可能值为:

none
表示在给定的顶点或顶点处不会绘制任何标记符号。
<marker-ref>
表示将绘制由<marker-ref>值引用的 marker 元素在给定的顶点或顶点处。 如果引用无效,则在给定的顶点或顶点处不会绘制任何标记。

对于所有形状,计算标记位置时必须使用的路径是等效路径

对于所有形状元素,除了polylinepath, 最后一个顶点与第一个 顶点相同。在这种情况下,如果marker-startmarker-end 的值都不是none,那么将在该最终顶点上渲染两个标记。 对于path元素, 每个封闭子路径,最后一个顶点与第一个顶点相同。 marker-start只能在 路径数据的第一个顶点上渲染。marker-end必须仅在 路径数据的最后一个顶点上渲染。 marker-mid必须在路径数据的每个顶点上渲染,但不包括路径数据的第一个顶点和最后一个顶点。

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 30">
  <defs>
    <marker id="m1" viewBox="0 0 10 10" refX="5" refY="5"
     markerWidth="8" markerHeight="8">
      <circle cx="5" cy="5" r="5" fill="green">
    </marker>
    <marker id="m2" viewBox="0 0 10 10" refX="5" refY="5"
     markerWidth="6.5" markerHeight="6.5">
      <circle cx="5" cy="5" r="5" fill="skyblue" opacity="0.9">
    </marker>
    <marker id="m3" viewBox="0 0 10 10" refX="5" refY="5"
     markerWidth="5" markerHeight="5">
      <circle cx="5" cy="5" r="5" fill="maroon" opacity="0.85">
    </marker>    
  </defs>
  
  <path d="M10,10 h10 v10 z m20,0 h10 v10 z m20,0 h10 v10 z"
  fill="none" stroke="black"
  marker-start="url(#m1)"  
  marker-mid="url(#m2)"
  marker-end="url(#m3)"  
  />
</svg>
图像显示,对于封闭子路径,在每个子路径的起始点绘制了两个标记。

对于包含封闭子路径路径数据, 在每个封闭子路径的第一个/最后一个顶点绘制两个标记。 对于最左边的封闭子路径,在marker-mid上绘制了一个marker-start。对于中间的封闭子路径, 在最后一个顶点上绘制了一个marker-end

注意,marker-startmarker-end 指的是整个路径的第一个和最后一个顶点,而不是每个子路径。

以下示例显示了一个三角形标记符号,用作顶点标记, 以在两个路径的末端形成箭头。

<svg xmlns="http://www.w3.org/2000/svg"
     width="275" height="200" viewBox="0 0 275 200">
  <defs>
    <marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5" 
            markerUnits="strokeWidth" markerWidth="4" markerHeight="3"
            orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" fill="context-stroke">
    </marker>
  </defs>

  <g fill="none" stroke-width="10" marker-end="url(#Triangle)">
    <path stroke="crimson" d="M 100,75 C 125,50 150,50 175,75">
    <path stroke="olivedrab" d="M 175,125 C 150,150 125,150 100,125">
  </g>
</svg>
图像显示自动定向的标记的使用。

三角形位于路径的末端,并自动定向,以便指向正确的方向。 使用context-stroke确保三角形的填充与每个path的描边匹配。

13.7.3. 标记简写:‘marker’ 属性

名称: marker
值: none | <marker-ref>
初始值: 未定义于简写属性
适用于: 形状
继承:
百分比: N/A
媒体: 视觉
计算值: 见各个属性
可动画

marker 属性设置 marker-startmarker-midmarker-end 属性的值。marker 的值直接用于这三个对应的长属性。

13.7.4. 渲染标记

当自动定向标记时,由于将orient 指定为'auto',将使用以下规则:

对于绘制的每个标记,建立一个临时新的用户坐标系,以便标记能够正确定位和大小,如下所示:

请注意,用户代理样式表marker元素的overflow属性设置为hidden,这会导致默认情况下在标记的SVG视口边界创建一个矩形裁剪路径。

属性不会从引用marker的元素继承到标记的内容中。但是,通过在其定义中的元素上使用context-stroke值作为fillstroke,可以设计出一个单一的标记与引用标记的元素样式相匹配。

标记不能被交互。比如,点击或鼠标悬停等事件不会在鼠标点击或移动到渲染的标记上时分派到marker或其子元素。

标记不会直接渲染,必须通过标记属性之一进行引用才能被渲染。marker元素的display值必须始终由用户代理样式表设置为none,并且此声明必须优先于任何其他CSS规则或呈现属性。 marker元素即使在其或任何祖先的display属性设置为none时仍可供引用。

标记的渲染效果就好像引用的marker元素的内容在每个标记实例中都被深度克隆到一个单独的非暴露DOM树中。由于克隆的DOM树是非暴露的,SVG DOM不会显示标记的克隆实例。

引用的marker元素的概念深度克隆到非暴露DOM树中还会复制由于CSS级联([CSS2], 第6章)和引用元素及其内容上的属性继承而产生的任何属性值。CSS选择器可以应用于原始(即引用的)元素,因为它们是正式文档结构的一部分。CSS选择器不能应用于(概念上)克隆的DOM树,因为其内容不是正式文档结构的一部分。

为了说明目的,我们将重复前面展示的标记示例:

<?xml version="1.0" standalone="no"?>
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000"
     xmlns="http://www.w3.org/2000/svg">
  <defs>
    <marker id="Triangle"
      viewBox="0 0 10 10" refX="0" refY="5"
      markerUnits="strokeWidth"
      markerWidth="4" markerHeight="3"
      orient="auto">
      <path d="M 0 0 L 10 5 L 0 10 z" />
    </marker>
  </defs>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <desc>在路径的末尾放置一个箭头。
  </desc>
  <path d="M 1000 750 L 2000 750 L 2500 1250"
        fill="none" stroke="black" stroke-width="100"
        marker-end="url(#Triangle)"  />
</svg>

上述文件的渲染效果将与以下文件在视觉上完全相同:

<?xml version="1.0" standalone="no"?>
<svg width="4in" height="2in"
     viewBox="0 0 4000 2000"
     xmlns="http://www.w3.org/2000/svg">
  <desc>生成与标记示例文件相同效果的文件,但不使用标记。
  </desc>
  <rect x="10" y="10" width="3980" height="1980"
       fill="none" stroke="blue" stroke-width="10" />
  <!-- 路径的绘制与之前相同,但不使用标记属性 -->
  <path d="M 1000 750 L 2000 750 L 2500 1250"
        fill="none" stroke="black" stroke-width="100"  />
  <!-- 以下逻辑模拟在路径的最终顶点绘制标记。 -->
  <!-- 首先,移动用户坐标系统的原点,使其与路径的终点对齐。 -->
  <g transform="translate(2500,1250)" >
    <!-- 因为标记指定了orient="auto",路径的最终段
         朝向45度,因此将坐标系统旋转45度。 -->
    <g transform="rotate(45)" >
      <!-- 将坐标系统缩放以匹配由'markerUnits'属性指示的坐标系统,
           在此情况下的值为'strokeWidth'。因此,将坐标系统缩放为
           'stroke-width'属性的当前值,即100。 -->
      <g transform="scale(100)" >
        <!-- 通过
             (-refX*viewBoxToMarkerUnitsScaleX, -refY*viewBoxToMarkerUnitsScaleY)
             平移坐标系统,以便标记内的(refX,refY)与顶点对齐。
             在这种情况下,我们使用preserveAspectRatio的默认值
             ('xMidYMid meet'),这意味着寻找一个统一的缩放因子
             (即viewBoxToMarkerUnitsScaleX=viewBoxToMarkerUnitsScaleY)
             使得viewBox完全适合SVG视口('meet')并且
             居中对齐('xMidYMid')。在这种情况下,统一缩放因子
             为markerHeight/viewBoxHeight=3/10=.3。因此,平移为
             (-refX*.3,-refY*.3)=(0*.3,-5*.3)=(0,-1.5)。 -->
        <g transform="translate(0,-1.5)" >
          <!-- 因为用户代理样式表指示标记的'overflow'属性值为'hidden',
               所以存在一个隐式裁剪路径。为此,在SVG视口的边界创建裁剪路径。
               请注意,在这种情况下,由于统一缩放因子、markerWidth/viewBoxWidth和
               markerHeight/viewBoxHeight的不同比例,以及'xMidYMid'对齐,
               SVG视口向左和右延伸了0.5个单位。 -->
          <clipPath id="cp1" >
            <rect x="-0.5" y="0" width="4" height="3" />
          </clipPath>
          <g clip-path="url(#cp1)" >
            <!-- 将坐标系统缩放为统一缩放因子
                 markerHeight/viewBoxHeight=3/10=.3,以设置坐标
                 系统为viewBox单位。 -->
            <g transform="scale(.3)" >
              <!-- 此'g'元素承载来自原始'marker'元素属性的
                   级联和继承的所有属性值。在此示例中,既未在'marker'元素上
                   指定fill也未指定stroke,因此使用初始值
                   "black"和"none"。 -->
             <g fill="black" stroke="none" >
                <!-- 展开'marker'元素的内容。 -->
                <path d="M 0 0 L 10 5 L 0 10 z" />
              </g>
            </g>
          </g>
        </g>
      </g>
    </g>
  </g>
</svg>

将此示例视为SVG(仅支持SVG的浏览器)

13.8. 控制绘制操作顺序:‘paint-order’ 属性

SVG 2 要求: 支持控制填充、描边和形状上标记的绘制顺序。
解决方案: SVG 2 将采纳‘paint-order’属性提案,尽管可能使用不同的名称。 属性名称现在已确定,请参阅2013年11月15日会议记录
目的: 解决常见需求,即在不需要复制元素的情况下,将描边绘制在填充下方。
负责人: Cameron (ACTION-3285)
名称: paint-order
值: normal | [ fill || stroke || markers ]
初始值: normal
适用对象: 形状文本内容元素
继承:
百分比: 不适用
媒体: 视觉
计算值: 如指定
可动画化

SVG 2 新增。主要是为了允许在不需要复制text元素的情况下, 将文本的描边绘制在其填充下方。

paint-order属性控制绘制 形状和文本的三种绘制操作的顺序: 填充、描边以及它们可能拥有的任何标记。

当此属性的值为normal时, 元素按照标准的绘制操作顺序绘制: 首先绘制填充,然后是描边,最后是标记。

当使用其他任何关键字时,绘制元素的操作顺序将按从左到右的顺序进行。如果省略 任何三个关键字,则它们最后绘制,按照paint-order: normal时的顺序。

这意味着,例如, paint-order: stroke 的渲染行为与 paint-order: stroke fill markers相同。

以下示例展示了如何使用paint-order 属性以更美观的方式渲染描边文本。

<svg xmlns="http://www.w3.org/2000/svg"
     width="600" height="150" viewBox="0 0 600 150">

  <style>
    text {
      font: 80px bold sans-serif; stroke-linejoin: round;
      text-anchor: middle; fill: peachpuff; stroke: crimson;
    }
  </style>

  <text x="150" y="100" style="stroke-width: 6px;">pizazz</text>
  <text x="450" y="100" style="stroke-width: 12px; paint-order: stroke;">pizazz</text>
</svg>
显示paint-order效果的图像。

文本的描边绘制在填充下方。

13.9. 插值的颜色空间:‘color-interpolation’ 属性

名称: color-interpolation
值: auto | sRGB | linearRGB
初始: sRGB
适用对象: 容器元素图形元素渐变元素useanimate
继承:
百分比: N/A
媒体: 视觉
计算值: 按指定的
可动画

SVG 用户代理在处理 SVG 内容时会在多个点执行颜色插值和合成。color-interpolation 属性控制以下图形操作所使用的颜色空间:

对于 滤镜效果color-interpolation-filters 属性控制所使用的颜色空间。 [filter-effects-1]

color-interpolation 属性在 sRGB 颜色空间或线性 RGB 颜色空间(光能线性化)之间选择颜色操作。选择合适的颜色空间后,使用逐分量线性插值。color-interpolation 的值具有以下含义:

auto
表示用户代理可以选择 sRGBlinearRGB 颜色空间进行插值。此选项表示作者不要求在特定颜色空间中进行插值。
sRGB
表示插值发生在 sRGB 颜色空间中。
linearRGB
表示插值发生在下述线性化 RGB 颜色空间中。

sRGB 颜色空间(即,非线性的 2.2 gamma 曲线)和线性化 RGB 颜色空间(即,颜色值以 sRGB 三刺激值表示,不带 gamma 曲线)之间的转换公式可以在 sRGB 规范 [SRGB] 中找到。 为了说明,以下公式显示从 sRGB 转换为线性化 RGB,其中 Csrgb 是三个 sRGB 颜色分量之一,Clinear 是对应的线性化 RGB 颜色分量,所有颜色值均在 0 到 1 之间:

C linear = { C srgb 12.92 如果 C srgb 0.04045 C srgb + 0.055 1.055 2.4 if  C srgb > 0.04045
if C_srgb <= 0.04045
  C_linear = C_srgb / 12.92
else if c_srgb > 0.04045
  C_linear = ((C_srgb + 0.055) / 1.055) ^ 2.4

如果用户代理支持,超出范围的颜色值也将使用上述公式进行转换。

当子元素混合到背景中时,子元素的 color-interpolation 属性的值决定了混合的类型,而不是父元素的 color-interpolation 属性的值。 对于使用 ‘href’ 属性引用另一个渐变的 渐变,该渐变使用由 fillstroke 属性直接引用的渐变元素的 color-interpolation 属性值。当动画颜色时,颜色插值根据被动画元素的 color-interpolation 属性的值进行。

13.10. 渲染提示

13.10.1. ‘color-rendering’ 属性

名称: color-rendering
值: auto | optimizeSpeed | optimizeQuality
初始: auto
适用对象: 容器元素图形元素渐变元素useanimate
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定
可动画

color-rendering 属性为 SVG 用户代理提供了关于如何优化其颜色插值和合成操作的提示。值的含义如下:

auto
表示用户代理应做出适当的权衡,以平衡速度和质量,但质量应优先于速度。
optimizeSpeed
表示用户代理应强调渲染速度而不是质量。对于 RGB 显示设备,此选项有时会导致用户代理在设备 RGB 颜色空间中执行颜色插值和合成。
optimizeQuality
表示用户代理应强调质量而不是渲染速度。

color-rendering 优先于 color-interpolation-filters。例如,假设 color-rendering: optimizeSpeedcolor-interpolation-filters: linearRGB。 在这种情况下,SVG 用户代理应以优化性能的方式执行颜色操作,这可能意味着牺牲由 color-interpolation-filters: linearRGB 指定的颜色插值精度。

13.10.2. ‘shape-rendering’ 属性

名称: shape-rendering
值: auto | optimizeSpeed | crispEdges | geometricPrecision
初始: auto
适用对象: 形状
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定
可动画

shape-rendering 属性为实现提供了关于在渲染矢量图形元素时应做出何种权衡的提示,例如 path 元素和 基本形状,如圆形和矩形。值的含义如下:

auto
表示用户代理应做出适当的权衡,以平衡速度、清晰边缘和几何精度,但应优先考虑几何精度而不是速度和清晰边缘。
optimizeSpeed
表示用户代理应强调渲染速度,而不是几何精度和清晰边缘。此选项有时会导致用户代理关闭形状抗锯齿。
crispEdges
表示用户代理应尝试强调艺术作品干净边缘之间的对比,而不是渲染速度和几何精度。为了实现清晰的边缘,用户代理可能会关闭所有线条和曲线的抗锯齿,或者可能仅对接近垂直或水平的直线关闭抗锯齿。此外,用户代理可能会调整线条位置和线宽,以使边缘与设备像素对齐。
geometricPrecision
表示用户代理应强调几何精度,而不是速度和清晰边缘。

13.10.3. ‘text-rendering’ 属性

名称: text-rendering
值: auto | optimizeSpeed | optimizeLegibility | geometricPrecision
初始: auto
适用对象: text
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定
可动画

text-rendering 属性为实现提供了关于在渲染文本时应做出何种权衡的提示。值的含义如下:

auto
表示用户代理应做出适当的权衡,以平衡速度、可读性和几何精度,但应优先考虑可读性而不是速度和几何精度。
optimizeSpeed
表示用户代理应强调渲染速度,而不是可读性和几何精度。此选项有时会导致用户代理关闭文本抗锯齿。
optimizeLegibility
表示用户代理应强调可读性,而不是渲染速度和几何精度。用户代理通常会选择是否应用抗锯齿技术、内置字体提示或两者结合,以产生最具可读性的文本。
geometricPrecision
表示用户代理应强调几何精度,而不是可读性和渲染速度。此选项通常会导致用户代理暂停使用提示,以便字形轮廓以与路径数据相当的几何精度进行绘制。

13.10.4. ‘image-rendering’ 属性

名称: image-rendering
值: auto | optimizeQuality | optimizeSpeed
初始: auto
适用对象: 图像
继承:
百分比: N/A
媒体: 视觉
计算值: 如指定
可动画

CSS 图像值和替代内容模块第 4 级可能在未来重新定义此属性。特别是,它应该允许在放大时选择平滑处理和保持像素化外观之间的选择。

image-rendering 属性为实现提供了关于在进行图像处理时如何进行速度与质量之间的权衡的提示。值的含义如下:

auto
表示用户代理应做出适当的权衡,以平衡速度和质量,但质量应优先于速度。用户代理应使用至少与最近邻重采样一样好的重采样算法,但双线性重采样是强烈推荐的。对于 符合标准的高质量 SVG 查看器,用户代理应使用至少与双线性重采样一样好的重采样算法。
optimizeQuality
表示用户代理应强调质量,而不是渲染速度。用户代理应使用至少与双线性重采样一样好的重采样算法。
optimizeSpeed
表示用户代理应强调渲染速度,而不是质量。用户代理应使用能够实现快速渲染的重采样算法,要求重采样算法至少与最近邻重采样一样好。如果可以通过更高质量的算法实现性能目标,则用户代理应使用更高质量的算法,而不是最近邻重采样。

在所有情况下,重采样必须在真实色彩(例如,24 位)颜色空间中进行,即使原始数据和/或目标设备是索引颜色。高质量的 SVG 查看器应使用线性色彩空间进行图像重采样。

13.11. ‘will-change’属性的效果

有关 will-change 的定义,请参见 CSS Will Change 模块第 1 级规范。

will-change 属性用于向用户代理提供即将对内容进行的更改类型的提示,从而使用户代理更好地进行渲染优化。

will-change 属性适用于所有 SVG 图形元素,但由于 SVG 元素不支持滚动,因此 scroll-position 值对它们没有影响。

以下示例演示了如何使用 will-change 来预警用户代理某个元素的 transform 属性将被更改,可能导致用户代理将该元素渲染到自己的 GPU 层中,从而使脚本的 transform 更改看起来更加平滑。

<svg xmlns="http://www.w3.org/2000/svg">
  <style>
    #background { fill: lemonchiffon; }
    #star {
      fill: cornflowerblue;
      stroke: navy; stroke-width: 5px; stroke-linejoin: round;
      paint-order: stroke fill;
      will-change: transform;
    }
    text { font: 24px sans-serif; user-select: none; }
  </style>
  <g onmousemove="drag(evt.clientX, evt.clientY);"
     onmouseup="dragging = false;">
    <rect id="background" width="100%" height="100%">
    <text x="10" y="30">拖动星星!</text>
    <path id="star" transform="translate(200,150)"
          d="M 0.00,-40.00 -11.76,-16.18 -38.04,-12.36 -19.02,6.18 -23.51,32.36
               0.00,20.00 23.51,32.36 19.02,6.18 38.04,-12.36 11.76,-16.18 z"
          onmousedown="dragging = true;">
  </g>
  <script>
    var dragging = false;
    var star = document.getElementById("star");
    function drag(x, y) {
      if (dragging) {
        star.setAttribute("transform", "translate(" + x + "," + y + ")");
      }
    }
  </script>
</svg>
一颗蓝色的星星,上方有文本“拖动星星!”。

在支持 will-change 的 SVG 元素的用户代理中,星星可能被渲染到一个层中,以便在其被拖动时可以快速合成。 查看交互式 SVG 文档。

will-change 属性替代了在 SVG Tiny 1.2 中定义的 ‘buffered-rendering’ 属性。

13.12. DOM 接口

13.12.1. 接口 SVGMarkerElement

一个 SVGMarkerElement 对象代表 DOM 中的 marker 元素。

[Exposed=Window]
interface SVGMarkerElement : SVGElement {

  // 标记单位类型
  const unsigned short SVG_MARKERUNITS_UNKNOWN = 0;
  const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1;
  const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2;

  // 标记方向类型
  const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
  const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
  const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;

  [SameObject] readonly attribute SVGAnimatedLength refX;
  [SameObject] readonly attribute SVGAnimatedLength refY;
  [SameObject] readonly attribute SVGAnimatedEnumeration markerUnits;
  [SameObject] readonly attribute SVGAnimatedLength markerWidth;
  [SameObject] readonly attribute SVGAnimatedLength markerHeight;
  [SameObject] readonly attribute SVGAnimatedEnumeration orientType;
  [SameObject] readonly attribute SVGAnimatedAngle orientAngle;
  attribute DOMString orient;

  void setOrientToAuto();
  void setOrientToAngle(SVGAngle angle);
};

SVGMarkerElement includes SVGFitToViewBox;

SVGMarkerElement 上定义的数字标记单位类型常量用于表示 markerUnits 属性可以取的关键字值。其含义如下:

常量 含义
SVG_MARKERUNITS_USERSPACEONUSE userSpaceOnUse 关键字。
SVG_MARKERUNITS_STROKEWIDTH strokeWidth 关键字。
SVG_MARKERUNITS_UNKNOWN 其他某个值。

SVGMarkerElement 上定义的数字标记方向类型常量用于表示 orient 属性可以取的值类型。其含义如下:

常量 含义
SVG_MARKER_ORIENT_AUTO auto 关键字。
SVG_MARKER_ORIENT_ANGLE 表示方向角度的 <angle><number> 值。
SVG_MARKER_ORIENT_UNKNOWN 其他某个值。

markerUnits IDL 属性 反映 markerUnits 内容属性。数字类型值 对于 markerUnits 如上所述于数字标记单位类型常量表中。

orientTypeorientAngleorient IDL 属性都反映 orient 内容属性。数字类型值 对于 orient 如下:

数字类型值
auto SVG_MARKER_ORIENT_AUTO
auto-start-reverse SVG_MARKER_ORIENT_UNKNOWN
<angle> | <number> SVG_MARKER_ORIENT_ANGLE

refXrefYmarkerWidthmarkerHeight IDL 属性反映 refXrefYmarkerWidthmarkerHeight 内容属性,分别。

setOrientToAuto 方法用于将 orient 属性的值设置为 'auto'。当调用 setOrientToAuto() 时,orient 属性简单地被设置为 'auto'

setOrientToAngle 方法用于将 orient 属性的值设置为特定的角度值。当调用 setOrientToAngle(angle) 时,orient 属性使用 angle 作为值进行 重新序列化