第15章:脚本和交互性

15.1. 引言

SVG 内容可以通过利用以下 SVG 语言中的特性实现交互性(即响应用户发起的事件):

本章描述:

相关信息可以在其他章节中找到:

15.2. 支持的事件

SVG 2 要求: 支持锚点更改事件。
解决方案: SVG 2 将考虑将 HTML 文档范围内的事件(包括 hashchange)应用于 SVG 文档,前提是这些事件适用。
目的: 允许作者在根 SVG 元素上使用与 HTML body 或根元素相同的事件监听器属性。
所有者: Cameron (ACTION-3278)
SVG 2 要求: 在适当的接口上有事件监听器属性。
解决方案: SVG 2 将根据 HTML 中的类似操作将所有事件监听器属性移动到 Element。
目的: 与 HTML 对齐。
所有者: Cameron (ACTION-3283)
SVG 2 要求: 在事件处理程序中将 evt 作为 event 的别名引入。
解决方案: 我们决定通过在事件处理程序中引入 evt 作为 event 的别名来解决 ISSUE-2176。
目的: 与 HTML 对齐。
所有者: Cameron (ACTION-3093)
SVG 2 要求: 支持拖放功能。
解决方案: SVG 2 可能要求拖放功能,我们将调查 HTML5 的功能。
目的: 允许在 SVG 中更轻松地进行拖放,并与 HTML 对齐。
所有者: Erik (ACTION-3328)

以下 SVG 的方面受到事件的影响:

在 SVG 1.1 中定义的一些事件,如SVGLoadSVGError等,已被UI 事件HTML中定义的等效无前缀事件替代。

应有一些使用事件的现代示例,例如触摸事件(参考触摸事件规范)。设备方向事件可能也很有趣。

以下表格列出了本规范定义的事件,或与定义它们的规范相比具有进一步要求或澄清的事件。

第一列中的事件名称是用在 SVG 的动画元素中定义可以启动或结束动画的事件名称。第二列中的UI 事件名称是在定义DOM 事件监听器时使用的名称([DOM], 第 3.6 节)。

对于表中未列出的事件,如在 HTML 或 UI 事件中引入的事件,相关的事件类型是用在 SVG 的动画元素中的名称。

表中关于事件是否冒泡或可取消的要求仅适用于由用户代理创建和分发的事件。使用Document接口上的createEvent方法从脚本创建的这些类型的事件可以通过initEvent方法设置为冒泡或可取消。

事件名称和描述 UI 事件名称 事件类别 事件属性名称

load

load 事件仅在结构外部元素Window上分发,当相应的外部资源加载完成时。请注意,由于其与关系,在svg元素上的 load 事件仅在文档中的所有资源完全加载时分发。

load 事件和结构外部元素上的错误事件是互斥的,在处理相关元素时,必须分发这两个事件中的一个。

load 事件不冒泡且不可取消。

在以前的 SVG 规范中,load 事件称为 SVGLoad,并且可以在解析元素后立即分发,但在相关资源完全加载之前。

(相同) onload

unload

仅适用于最外层 SVG 元素。unload 事件在 DOM 实现从窗口或框架中移除文档时发生。

unload 事件不冒泡且不可取消。

(相同) onunload

error

error 事件在结构外部元素未能正确加载或在脚本执行期间发生错误时发生。

error 事件会冒泡,但不可取消。

(相同) onerror

beginEvent

当动画元素开始时发生。详情请参阅SMIL 动画规范中的时间事件接口描述。

onbegin

endEvent

当动画元素结束时发生。详情请参阅SMIL 动画规范中的时间事件接口描述。

onend

repeatEvent

当动画元素重复时发生。它在元素每次重复时触发,第一次迭代后。详情请参阅SMIL 动画规范中的时间事件接口描述。

onrepeat

关于为 UI 事件类型的事件监听器传递的参数的详细信息可以在 ([uievents]) 和 ([DOM]) 规范中找到。其他事件类型的参数在本规范的其他地方描述。

同样,事件值时间指定符动画元素beginend属性中使用,仅在向相关元素派发“冒泡”和“目标阶段”事件时解析为具体时间。

15.2.1. 与 UI 事件的关系

SVG DOM 与UI 事件中定义的所有接口和所有事件类型兼容,并且与剪贴板 API 和事件中定义的事件类型兼容([uievents], [clipboard-apis]).

SVG 命名空间中的所有元素都支持事件属性;匹配的 IDL 属性通过SVGElement 接口中的GlobalEventHandlersDocumentAndElementEventHandlers混合器分别包含。

作为 SVG DOM 支持的一部分,符合规范的 SVG 软件必须支持这些规范中定义的所有(非弃用、非过时)事件类型,如果相关事件可能在软件的使用中发生。即使 SVG 软件不支持用户交互,也应实现对无需交互即可触发的事件的支持,例如loaderror事件。

SVG 动画元素(在SVG 动画第 2 级规范中定义)支持额外的事件和事件属性。以下事件类型由于动画中的状态变化而被触发。

这些动画事件的事件属性对其他元素没有影响。

15.3. 用户界面事件

在支持交互的用户代理上,作者通常会定义 SVG 文档,使其能够响应用户界面事件。在可能的用户事件集中包括指针事件、键盘事件和文档事件。

作为对用户界面(UI)事件的响应,作者可能会启动动画,执行超链接到另一个网页,突出显示文档的一部分(例如,更改指针下图形元素的颜色),启动“滚动”效果(例如,使一些先前隐藏的图形元素出现在指针附近)或启动与远程数据库通信的脚本。

15.4. 指针事件

由于用户在指针设备上执行的操作而发生的用户界面事件称为指针事件。

许多系统支持指针设备,如鼠标或轨迹球。在使用鼠标的系统上,指针事件包括鼠标移动和鼠标点击等操作。在使用不同指针设备的系统上,指针设备通常通过提供等效用户操作的机制来模拟鼠标的行为,例如按下等同于鼠标点击的按钮。

对于每个指针事件,SVG 用户代理确定给定指针事件的目标元素。目标元素是事件发生时,指针下方的最上层图形元素(其相关图形内容在指针下方)。(有关如何确定元素的相关图形内容是否在指针下方的描述,请参见pointer-events属性,以及在何种情况下该图形元素可以成为指针事件的目标元素。)当元素未显示时(即当该元素或其祖先的display属性值为none),该元素不能成为指针事件的目标。

如果存在指针事件的目标元素,则事件根据正常的事件流调度到该元素([uievents], 第 3.1 节)。对于通过use元素或脚本创建的阴影树,事件必须遵循调度事件 [dom]。

如果不存在指针事件的目标元素,则该事件被忽略。

15.5. 用户界事件的命中测试和处理顺序

命中测试
确定指针是否与给定图形元素相交的过程。命中测试用于确定将鼠标事件调度到哪个元素,这可能是由于用户移动指针设备或文档中元素的位置、形状及其他属性的变化而完成的。命中测试也称为命中检测选择。另请参见pointer-events属性的定义。

指针设备与元素或区域的交互有两个不同的方面:

  1. 命中测试,以确定指针事件(如鼠标移动或鼠标点击)是否发生在元素的交互区域内,以及后续的 DOM 事件流;
  2. 与任何相关元素关联的操作的功能处理。

15.5.1. 命中测试

确定指针事件是否导致积极的命中测试,取决于指针的位置、图形元素的大小和形状,以及该元素上pointer-events属性的计算值。下面对pointer-events属性的定义描述了特定类型图形元素对指针事件敏感的确切区域。

请注意,svg元素不是图形元素,而在符合标准的 SVG 独立文件中,最外层 svg 元素将永远不会成为指针事件的目标,尽管事件可以冒泡到此元素。如果指针事件在图形元素上未导致积极的命中测试,则应引发任何特定于用户代理的窗口行为,例如显示上下文菜单或允许缩放和移动 SVG 文档片段的控件。

本规范未定义指针事件在由引用或包含嵌入在其他文档中的 SVG 图像的最外层 svg 元素上的行为,例如,嵌入在 HTML 文档中的最外层 svg 元素是否拦截鼠标点击事件;未来的规范可能会定义此行为,但就本规范而言,此行为是实现特定的。

15.5.2. 事件处理

作为用户界面事件目标的元素可能具有特定的交互行为,具体取决于元素的类型以及它是否具有明确关联的交互,例如脚本事件监听器、CSS 伪类匹配或具有基于事件的定时的声明式动画。对于给定目标元素在调度 DOM 事件后处理用户界面事件的算法和顺序如下:

  1. 如果在此元素上注册的事件处理程序调用了preventDefault() DOM 方法,则不再对该元素进行进一步处理,事件遵循事件调度和 DOM 事件流处理([uievents]);
  2. 如果元素有相关的标题或描述,例如title元素,并且用户代理支持显示此类信息(例如通过工具提示或状态栏消息),则应根据指针事件的类型适当地显示该信息;
  3. 如果元素匹配与指针事件类型相关的任何相关动态伪类选择器,例如:hover:active:focus,如[CSS2]第 5.11 节所述,则应用相关类属性;
  4. 如果元素与通过使用event-value定时说明符的声明式动画的激活或取消相关联,则必须解析任何相应的实例时间,并执行该实例时间解析的任何后续操作(例如立即启动或停止动画);
  5. 如果元素是超链接(例如,它是a元素的后代),并且指针事件是激活该超链接的类型(例如通过鼠标点击),并且如果超链接遍历更改了内容的上下文(例如,打开不同的文档,或通过移动到同一文档的另一部分使指针离开该元素),则不再对该元素进行进一步处理;
  6. 如果元素是文本内容元素,并且事件类型是用户代理识别为文本选择操作的一部分的类型(例如,鼠标点击和拖动或双击),则执行文本选择算法;
  7. 如果事件类型是用户代理与唤起特殊用户界面控件(例如,右键单击或命令单击唤起上下文菜单)关联的类型,则用户代理应唤起这种特定于用户代理的行为,例如显示上下文菜单或允许缩放和移动 SVG 文档片段的控件。

15.6. ‘pointer-events’ 属性

在不同情况下,作者可能希望控制特定图形元素何时可以成为指针事件的目标。例如,作者可能希望给定元素仅在指针位于给定形状的描边周围时接收指针事件。在其他情况下,作者可能希望给定元素在任何情况下都忽略指针事件,以便下面的图形元素成为指针事件的目标。

遮罩和剪切对指针事件的影响有所不同。剪切路径是几何边界,给定点显然位于该边界的内部或外部;因此,指针事件必须在剪切元素的渲染区域正常捕获,但不得在剪切区域捕获,如剪切路径的定义中所述。相反,遮罩不是二进制过渡,而是像素操作,对于完全透明和几乎完全透明的不同表现可能会令人困惑;因此,对于应用了遮罩的元素,即使在遮罩的透明度为零的区域,指针事件仍必须被捕获。如果作者希望实现一个效果,使遮罩的透明部分允许指针事件传递到下面的元素,可以使用遮罩和剪切的组合。

filter 属性对指针事件处理没有影响,在这种情况下必须视为未指定该filter

例如,假设一个圆圈具有red(即,轮廓为实心红色)的描边none(即,内部未涂色)的填充,直接渲染在具有blue填充的矩形上方。作者可能希望圆圈仅在指针位于圆圈的周边时成为指针事件的目标。当指针位于圆圈的内部时,作者可能希望底层矩形成为指针事件的目标元素。

pointer-events 属性指定在什么情况下给定元素可以成为指针事件的目标元素。它影响以下事件的处理情况:

名称: pointer-events
值: bounding-box | visiblePainted | visibleFill | visibleStroke | visible | painted | fill | stroke | all | none
初始: visiblePainted
适用对象: 容器元素图形元素use
继承:
百分比: N/A
媒体: 视觉
计算值: 按指定值
可动画
bounding-box
当指针位于元素的边界框时,该元素必须成为指针事件的目标元素。
visiblePainted
visibility 属性设置为visible并且指针位于“已绘制”区域时,给定元素可以成为指针事件的目标元素。如果指针位于元素的内部(即,填充)并且fill 属性具有实际值而非none,或者如果它位于元素的周边(即,描边)并且stroke 属性设置为非none的值,则指针位于绘制区域。
visibleFill
visibility 属性设置为visible并且指针位于元素的内部(即,填充)时,给定元素可以成为指针事件的目标元素。fill 属性的值不会影响事件处理。
visibleStroke
visibility 属性设置为visible并且指针位于元素的周边(即,描边)时,给定元素可以成为指针事件的目标元素。stroke 属性的值不会影响事件处理。
visible
visibility 属性设置为visible并且指针位于元素的内部(即,填充)或周边(即,描边)时,给定元素可以成为指针事件的目标元素。fillstroke 的值不会影响事件处理。
painted
当指针位于“已绘制”区域时,给定元素可以成为指针事件的目标元素。如果指针位于元素的内部(即,填充)并且fill 属性具有实际值而非none,或者它位于元素的周边(即,描边)并且stroke 属性具有实际值而非none,则指针位于绘制区域。visibility 属性的值不会影响事件处理。
fill
当指针位于元素的内部(即,填充)时,给定元素可以成为指针事件的目标元素。fillvisibility 属性的值不会影响事件处理。
stroke
当指针位于元素的周边(即,描边)时,给定元素可以成为指针事件的目标元素。strokevisibility 属性的值不会影响事件处理。
all
当指针位于元素的内部(即,填充)或周边(即,描边)时,给定元素可以成为指针事件的目标元素。fillstrokevisibility 属性的值不会影响事件处理。
none
给定元素不会接收指针事件。

对于文本元素,命中测试是基于字符单元进行的:

对于光栅图像,命中测试要么在整个图像的基础上进行(即,图像的矩形区域是图像是否接收事件的决定因素之一),要么在每个像素的基础上进行(即,指针下的像素的 alpha 值帮助确定图像是否接收事件):

请注意,对于光栅图像,属性 opacityfill-opacitystroke-opacityfillstroke 的值不会影响事件处理。

15.7. 放大和缩放

SVG 2 要求: 支持细节级别控制。
解析度: 我们将在 SVG 2 中支持细节级别控制。
目的: 根据缩放级别控制元素的可见性(例如,在地图中非常有用)。
所有者: Doug(无操作)
备注: 请参见 SVG 1.2 Tiny 的瓦片和分层模块

放大表示对 SVG 文档片段的完整统一变换,其中放大操作按相同的比例缩放所有图形元素。放大操作的效果是在 SVG 文档片段的最外层(即在 最外层 svg 元素 外部)施加一个附加的缩放和平移变换。

缩放表示对 SVG 文档片段的平移(即移动)变换,以响应用户界面操作。

在交互能力用户环境中运行的 SVG 用户代理必须支持放大和缩放的能力。

SVG 文档片段中的 最外层 svg 元素 具有属性 zoomAndPan,其可能的值为 disablemagnify,默认值为 magnify

zoomAndPan 属性存在风险,因其没有已知的实现,且不太可能被实现。见 Github issue #56

名称 初始值 可动画
zoomAndPan [ disable | magnify ] disable no

如果 disable,用户代理应禁用任何放大和缩放控件,并不允许用户在给定文档片段上放大或缩放。

如果 magnify,在支持用户交互的环境中,用户代理应提供控件,允许用户对文档片段执行“放大”操作。

如果将 zoomAndPan 属性分配给内部的 svg 元素,则内部 zoomAndPan 设置 对 SVG 用户代理将无效。

15.8. 焦点

SVG 使用与 HTML 相同的焦点模型, 针对 SVG 进行了修改,如本节所述。 每个文档中至多有一个元素处于焦点状态; 如果整个文档具有系统焦点,则该元素成为所有键盘事件的目标。

当一个元素获得焦点时, 该元素匹配CSS :focus伪类。 交互式用户代理必须在由于键盘或其他非指点设备的用户输入事件而更改焦点时,视觉上指示焦点(通常用轮廓), 并可以在所有时间指示焦点。 作者可以使用:focus伪类用更适合图形的视觉效果替换视觉指示, (如形状的轮廓), 但不应使用它完全去除焦点的视觉指示。

以下 SVG 元素在交互式文档中是可聚焦的。 在使用元素阴影树中的任何此类元素实例也可聚焦。 为了符合 HTML 焦点模型,交互式用户代理必须将它们视为 可聚焦区域 ,其tabindex 焦点标志应设置:

在用户代理提供的控件情况下, 元素可以有多个可聚焦区域, 每个子控件对应一个。

此外,所有有效链接的a元素都是可聚焦的, 并且它们的tabindex 焦点标志必须设置 除非用户代理通常提供替代方法 来进行链接的键盘遍历。

为了与使用SVG Tiny 1.2 focusable属性的内容兼容, 用户代理应将该属性值为 true的元素视为可聚焦。 在新内容中,作者应省略focusable属性, 或仅与对应的tabindex0结合使用。

用户代理可能将其他元素视为可聚焦的, 特别是在键盘交互是唯一或主要的用户输入方式时。 特别是,用户代理可能支持使用键盘焦点 来显示title元素 文本作为工具提示, 并且可能允许焦点到达已分配 鼠标、指针或焦点事件的监听器的元素。 作者不应依赖这种行为; 所有交互元素应直接支持键盘交互。

顺序焦点顺序由所有可聚焦 元素生成, 按照与HTML 元素的 tabindex 属性相同的方式处理 SVG 元素的tabindex属性。 在使用元素阴影树中的内容 按照它是use元素的子内容插入焦点顺序。

一个非渲染元素永远无法获得焦点, 无论tabindex属性的值如何, 如果脚本程序matically将焦点分配给非渲染 或其他无法聚焦的元素,聚焦调用将被中止。 但是,请注意,不可见或屏幕外的元素仍可能被渲染

当用户代理支持 SVG 文档的滚动或平移, 并且焦点移动到当前在 SVG 视口外的元素时, 用户代理应滚动或平移文档, 直到聚焦元素在 SVG 视口内。

与 HTML 中一样,可聚焦的 SVG 元素 但没有定义的 激活行为 具有无操作的激活行为 (除非脚本特别对此做出响应)。

这意味着,仅因其tabindex属性而可聚焦的元素 将在非鼠标激活的情况下触发click事件 (例如,在元素处于焦点状态时按下“回车”键)。

对于包含内联 HTML 和 SVG 的文档, 焦点是为整个文档处理的 (具有组合顺序焦点), 而不是将每个内联 SVG 或 HTML 片段视为独立的子文档。

例如,在以下文档中,按 Tab 键会在元素 A、B 和 C 之间循环焦点,按该顺序。

<!DOCTYPE html>
<button id="A" tabindex="1">第一件事</button>
<button id="C" tabindex="2">第三件事</button>
<svg width="200" height="200">
  <text id="B" tabindex="1" x="100" y="100">第二件事</text>
</svg>

请注意,SVG 元素没有 HTML 的 accesskey 属性的等效项。

15.9. 事件属性

事件属性
事件属性的名称始终以 "on" 开头,后面跟着事件名称。它指定在给定类型的事件被调度到指定属性的元素时要运行的脚本。

对于用户代理支持的每种事件类型,SVG将其支持为事件属性,遵循与事件处理内容属性相同的要求[HTML]。 事件属性在所有SVG元素上可用。

事件属性的内容始终被解释为ECMAScript,就像使用媒体类型'application/ecmascript'处理一样。 [rfc2046][rfc4329]

事件属性不可动画化

实现者可以将事件属性的设置视为在EventListener上的创建和注册 EventTarget。这样的事件监听器仅在“冒泡”和“目标”阶段调用,仿佛在addEventListeneruseCapture参数中指定了false。 此EventListener的行为与在EventTarget上注册的任何其他事件监听器相同。

如果表示事件监听器的属性被更改,这可以视为移除之前注册的EventListener并注册一个新的。 此外,没有规定事件属性与EventTarget上的其他事件监听器接收事件的顺序。

在ECMAScript中,建立事件监听器的一种方法是定义一个函数并将该函数传递给addEventListener方法:

function myAction1(evt) {
  // 处理事件
}
// ... 后面 ...
myElement.addEventListener("click", myAction1, false)

在ECMAScript中,事件属性的字符数据内容成为响应事件时被调用的ECMAScript函数的定义。与所有注册的ECMAScript事件监听器函数一样,此函数接收一个Event对象作为参数,事件对象的名称为evt。例如,可以编写:

<rect onclick="MyClickHandler(evt)" .../>

这将把Event对象evt传递给函数MyClickHandler

15.9.1. 动画事件属性

以下是动画事件属性的定义。 这些可以在动画元素上指定。

属性定义:

名称 初始值 可动画化
onbeginonendonrepeat (见下文) (无)
指定在指定属性的元素上,当对应事件的“冒泡”或“目标”阶段的监听器被触发时要执行的脚本。 请参见支持的事件表以确定这些事件属性对应的事件。 对该属性的值没有限制。

15.10. ‘script’ 元素

SVG 2 要求: 考虑在script上允许async/defer。
解决方案: SVG 2将允许在‘script’上使用async/defer。
目的: 与HTML保持一致。
负责人: Cameron (ACTION-3280)
SVG 2 要求: 整合SVG Tiny 1.2脚本处理模型。
解决方案: SVG 2将定义如何以兼容HTML5的方式处理内联可脚本内容
目的: 在HTML和SVG中拥有一致的脚本运行行为。
负责人: Cameron (ACTION-3282)

script 元素等同于HTML中的script元素,因此是脚本(例如ECMAScript)的放置位置。 在任何script元素内定义的任何函数在当前文档中具有“全局”作用域。

脚本的文本内容不会直接渲染; script元素的display值必须始终由用户代理样式表设置为none, 并且此声明必须高于任何其他CSS规则或表现属性的重要性。

在尝试执行script元素之前,必须检查type的解析媒体类型值。 如果SVG用户代理不支持该脚本语言,则script元素不得执行。

本示例定义了一个函数 circle_click,该函数通过 onclick事件属性 被调用,位于circle元素上。 左侧的绘图是初始图像,右侧的绘图显示了点击圆形后的结果。

  <?xml version="1.0" standalone="no"?>
  <svg width="6cm" height="5cm" viewBox="0 0 600 500"
       xmlns="http://www.w3.org/2000/svg">
    <desc>示例脚本01 - 从onclick事件调用ECMAScript函数
    </desc>
    <!-- ECMAScript每次点击时改变半径 -->
    <script type="application/ecmascript"> <![CDATA[
      function circle_click(evt) {
        var circle = evt.target;
        var currentRadius = circle.getAttribute("r");
        if (currentRadius == 100)
          circle.setAttribute("r", currentRadius*2);
        else
          circle.setAttribute("r", currentRadius*0.5);
      }
    ]]> </script>

    <!-- 用蓝线勾勒绘图区域 -->
    <rect x="1" y="1" width="598" height="498" fill="none" stroke="blue">

    <!-- 处理每个点击事件 -->
    <circle onclick="circle_click(evt)" cx="300" cy="225" r="100"
            fill="red">

    <text x="300" y="480"
          font-family="Verdana" font-size="35" text-anchor="middle">

      点击圆形以改变其大小
    </text>
  </svg>
  
示例演示了onclick事件处理程序对SVG形状的影响。
示例演示如何从onclick事件调用ECMAScript函数 — 第一次点击前  示例演示如何从onclick事件调用ECMAScript函数 — 第一次点击后

在SVG中查看此示例(仅限支持SVG的浏览器)

script
类别:
从不渲染的元素结构外部元素
内容模型:
字符数据。
属性:
DOM接口:

属性定义:

名称 初始值 可动画
crossorigin [ anonymous | use-credentials ]? (见HTML属性定义)

crossorigin属性是一个CORS设置 属性,除非另有说明,否则遵循与html相同的处理规则[HTML].

名称 初始值 可动画
type (见下文) application/ecmascript
确定给定script元素的脚本语言。值 必须是有效的媒体类型,符合 多用途互联网邮件扩展 (MIME) 第二部分[rfc2046]。 如果未提供type,则默认的脚本 语言假定为ECMAScript,像处理 ‘application/ecmascript’媒体类型一样。
名称 初始值 可动画
href URL [URL] (无)
对包含脚本代码的外部资源的URL引用。 请参阅URL引用属性已弃用的XLink属性的共同处理定义。

该URL会被处理,资源会按照链接章节中描述的方式被获取。

15.11. DOM接口

15.11.1. 接口 SVGScriptElement

一个 SVGScriptElement 对象表示 一个script元素在DOM中。

[Exposed=Window]
interface SVGScriptElement : SVGElement {
  attribute DOMString type;
  attribute DOMString? crossOrigin;
};

SVGScriptElement 包含 SVGURIReference;

type IDL属性 反映 type内容属性。

crossOrigin IDL 属性 反映 crossorigin内容属性。