墨迹 API

社区组报告草案,

此版本:
https://wicg.github.io/ink-enhancement
最新发布版本:
https://www.w3.org/TR/2021/ink-api
反馈:
GitHub
编辑:
Ben Mathwig (微软公司)

摘要

提供一个 Web API,用于渐进增强 Web 墨迹书写延迟。

本文档状态

本规范由 Web 平台孵化器 社区组发布。 它不是 W3C 标准,也不在 W3C 标准轨道上。 请注意,根据 W3C 社区 贡献者许可协议(CLA),存在有限的选择退出权,并适用其他条件。 了解更多关于 W3C 社区组和商业组的信息。

1. 引言

在 Web 上实现低延迟对于出色的墨迹书写体验至关重要。通常,Web 上的墨迹书写 涉及消费 PointerEvent 事件,并将笔画渲染到 canvas、 WebGL,甚至 SVG。

虽然目前已经有一些渐进增强可用,例如 getPredictedEvents() 和 Desyncronized canvas,但这些都没有利用由操作系统提供的系统合成器来实现更好的延迟。 操作系统合成器通常会引入一帧延迟,以便将所有窗口组合在一起。在这一帧延迟期间,输入可能会被传递给 应用程序,但应用程序要到下一帧才能用这个新输入来更新已渲染的帧。系统合成器可能有能力代表应用程序处理此输入,并 相应地更新当前帧。Ink API 的目的,是将系统合成器的这一功能公开给 Web 应用程序,作为一种渐进增强选项,使其在受支持的系统上能够实现与原生应用程序相当的延迟。 它不是对现有渐进式墨迹增强的替代,而是提供另一种选择。

2. 范围

3. Ink API

3.1. 引言

为了让系统合成器能够以足够高的保真度绘制后续输入点,应用程序 需要向合成器描述最后一个已渲染的点。如果系统知道最后一个已渲染的 点,它就可以为已传递给 Web 应用程序但尚未渲染的笔输入事件生成墨迹轨迹片段。

例如,考虑一个已经将所有墨迹笔画渲染到当前输入帧的应用程序:

应用程序已将一段部分墨迹轨迹渲染到当前输入帧。笔位于更前方。

这里,笔继续在数字化仪上移动,但应用程序还没有机会处理 此输入以进行渲染。为了实现“superwet”墨迹书写体验,系统合成器需要为这些输入叠加 墨迹片段:

由应用程序渲染的同一段部分墨迹轨迹,由系统合成器叠加的墨迹片段补全到笔的位置,以实现“superwet”墨迹书写体验

PointerEvent 被传递给 Web 应用程序时,应用程序可以无缝地用应用程序渲染的笔画替换系统合成器墨迹,并 将其渲染的最后一个事件点更新给合成器:

应用程序处理完所有用户输入事件后渲染出的完整墨迹轨迹。

Ink API 提供 DelegatedInkTrailPresenter 接口,用于公开底层操作系统 API 以实现这一点,并保持可扩展性开放, 以便将来支持更多 presenter。

3.2. Ink 接口

[Exposed=Window]
interface Ink {
    Promise<DelegatedInkTrailPresenter> requestPresenter(
        optional InkPresenterParam param = {});
};
requestPresenter(param)

此方法会在一个 Promise 中返回 DelegatedInkTrailPresenter 对象的实例,该对象可用于在 PointerEvent 分派之间渲染墨迹笔画。每次调用此方法时,都必须创建一个新的 DelegatedInkTrailPresenter 实例。

3.3. InkPresenterParam 字典

dictionary InkPresenterParam {
    Element? presentationArea = null;
};
presentationArea 类型为 Element,可为空,默认值为 null

一个可选的 Element, 它将墨迹轨迹的渲染限制在该元素所限定的区域内。presentationArea 必须 为 null,或者与 Ink 接口位于同一个文档中,否则抛出错误并中止。

3.4. DelegatedInkTrailPresenter 接口

[Exposed=Window]
interface DelegatedInkTrailPresenter {
    readonly attribute Element? presentationArea;

    undefined updateInkTrailStartPoint(PointerEvent event, InkTrailStyle style);
};
presentationArea 类型为 Element,只读,可为空

对 DOM 元素的引用,presenter 的作用域被限制到该元素,以防止在 所提供区域之外呈现墨迹。此区域始终是该元素边框盒的客户端坐标,因此 移动元素或滚动元素无需作者重新计算。如果未提供此项, 默认使用包含它的视口。此元素必须与 DelegatedInkTrailPresenter 所关联的文档处于同一文档中,并且也必须与接收 PointerEvent 的文档相同, 否则将抛出错误。如果 presentationArea 曾从文档中移除,则下一次 updateInkTrailStartPoint 必须抛出错误并中止。

updateInkTrailStartPoint(event, style)

此方法向 presenter 指示哪个 PointerEvent 被用作当前帧的最后一个渲染点。这必须是一个受信任的事件,并且它与 DelegatedInkTrailPresenter 位于同一文档中。所生成的委托墨迹轨迹必须在下一个动画帧期间渲染, 然后移除。

3.5. InkTrailStyle 字典

dictionary InkTrailStyle {
    required DOMString color;
    required unrestricted double diameter;
};
color 类型为 DOMString

这指定 presenter 在渲染墨迹轨迹时要使用的 CSS 颜色代码。它必须是 有效的 CSS 颜色,否则抛出错误并中止。

diameter 类型为 unrestricted double

这指定 presenter 在显示墨迹轨迹时应使用的直径。它必须 大于 0,否则抛出错误并中止。

此局部接口定义了对 Navigator 接口的扩展
[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute Ink ink;
};
ink 类型为 Ink,只读

当前文档的 Ink 实例。它必须与将包含 presentationArea 的文档关联,并且与将接收用于绘制的 PointerEvent 的文档关联。

4. 使用示例

function renderInkStroke(x, y, canvas) {
    // ... 将墨迹笔画渲染到 canvas ...
}

try {
    let canvas = document.querySelector("#canvas");
    let presenter = await navigator.ink.requestPresenter({presentationArea: canvas});

    window.addEventListener('pointermove', function(event) {
        // 渲染所有来自事件队列的点。
        let points = event.getCoalescedEvents();

        points.forEach( p => {
            renderInkStroke(p.x, p.y, canvas);
        });

        // 渲染属于已分派事件的墨迹笔画
        renderInkStroke(event.x, event.y, canvas);

        // 用最后一个已渲染的点更新 presenter,并为其提供样式
        presenter.updateInkTrailStartPoint(event, {
            color: "#7851A9",
            diameter: event.pressure * 4
        });
    });
}

一致性

文档 约定

一致性要求通过描述性断言 和 RFC 2119 术语的组合来表达。 关键词“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY”和“OPTIONAL” 在本文档的规范性部分中 应按 RFC 2119 中所述进行解释。 但是,为了可读性, 这些词在本规范中并不全部以大写字母出现。

本规范的所有文本均为规范性内容, 除非某些章节明确标记为非规范性内容、示例和注释。 [RFC2119]

本规范中的示例会以“例如”这些词引出, 或者通过 class="example" 与规范性文本分隔开, 如下所示:

这是一个信息性示例的例子。

信息性注释以“Note”一词开头, 并通过 class="note" 与规范性文本分隔开, 如下所示:

注意,这是一个信息性注释。

索引

由本 规范定义的术语

由 引用定义的术语

参考文献

规范性引用

[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[POINTEREVENTS3]
Patrick Lauke; Robert Flack. Pointer Events. URL: https://w3c.github.io/pointerevents/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997 年 3 月。Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL 索引

[Exposed=Window]
interface Ink {
    Promise<DelegatedInkTrailPresenter> requestPresenter(
        optional InkPresenterParam param = {});
};

dictionary InkPresenterParam {
    Element? presentationArea = null;
};

[Exposed=Window]
interface DelegatedInkTrailPresenter {
    readonly attribute Element? presentationArea;

    undefined updateInkTrailStartPoint(PointerEvent event, InkTrailStyle style);
};

dictionary InkTrailStyle {
    required DOMString color;
    required unrestricted double diameter;
};

[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute Ink ink;
};