잉크 API

커뮤니티 그룹 보고서 초안,

이 버전:
https://wicg.github.io/ink-enhancement
최신 공개 버전:
https://www.w3.org/TR/2021/ink-api
피드백:
GitHub
편집자:
Ben Mathwig (Microsoft Corporation)

초록

웹 잉킹 지연 시간의 점진적 향상을 위한 Web API를 제공합니다.

이 문서의 상태

이 명세는 Web Platform Incubator Community Group에서 발행했습니다. 이는 W3C 표준이 아니며 W3C 표준 트랙에도 속하지 않습니다. W3C 커뮤니티 기여자 라이선스 계약(CLA)에 따라 제한적인 옵트아웃 및 기타 조건이 적용됨에 유의하십시오. W3C Community and Business Groups에 대해 자세히 알아보십시오.

1. 소개

낮은 지연 시간을 달성하는 것은 웹에서 훌륭한 잉킹 경험을 제공하는 데 매우 중요합니다. 일반적으로 웹에서의 잉킹은 PointerEvent 이벤트를 소비하고 스트로크를 canvas, WebGL 또는 SVG에 렌더링하는 일을 포함합니다.

현재 getPredictedEvents() 및 비동기화된 canvas와 같은 점진적 향상이 제공되고 있지만, 이들 중 어느 것도 더 나은 지연 시간을 달성하기 위해 운영 체제가 제공하는 시스템 컴포지터를 활용하지 않습니다. 운영 체제 컴포지터는 일반적으로 모든 창을 함께 합성하기 위해 한 프레임의 지연 시간을 도입합니다. 이 지연 시간 프레임 동안 입력이 애플리케이션에 전달될 수 있지만 애플리케이션은 다음 프레임까지 이 새 입력으로 렌더링된 프레임을 업데이트할 수 없습니다. 시스템 컴포지터는 애플리케이션을 대신하여 이 입력을 처리하고 현재 프레임을 그에 따라 업데이트할 수 있는 능력을 가질 수 있습니다. Ink API의 목적은 시스템 컴포지터의 이러한 기능을 웹 애플리케이션에 점진적 향상 옵션으로 노출하여, 지원되는 시스템에서 네이티브 애플리케이션과 지연 시간 동등성을 달성할 수 있게 하는 것입니다. 이는 이미 존재하는 기존의 점진적 잉크 향상을 대체하는 것이 아니라 또 다른 옵션을 제공합니다.

2. 범위

3. Ink API

3.1. 소개

시스템 컴포지터가 후속 입력 지점을 충분한 충실도로 그릴 수 있으려면, 애플리케이션은 마지막으로 렌더링된 지점을 컴포지터에 설명해야 합니다. 시스템이 마지막으로 렌더링된 지점을 알면, 웹 애플리케이션에 전달되었지만 아직 렌더링되지 않은 펜 입력 이벤트에 대해 잉크 궤적의 세그먼트를 생성할 수 있습니다.

예를 들어, 현재 입력 프레임까지 모든 잉크 스트로크를 렌더링한 애플리케이션을 생각해 보십시오.

부분적인 잉크 궤적이 현재 입력 프레임까지 애플리케이션에 의해 렌더링됩니다. 펜은 더 앞쪽에 있습니다.

여기서 펜은 디지타이저 위에서 계속 이동했지만, 애플리케이션은 렌더링을 위해 이 입력을 처리할 기회를 아직 갖지 못했습니다. "superwet" 잉킹 경험을 달성하려면, 시스템 컴포지터가 이러한 입력에 대한 잉크 세그먼트를 오버레이해야 합니다.

애플리케이션이 렌더링한 동일한 부분 잉크 궤적이며, 'superwet' 잉킹 경험을 달성하기 위해 펜의 위치까지 시스템 컴포지터가 오버레이한 잉크 세그먼트로 완성됩니다

PointerEvent가 웹 애플리케이션에 전달되면, 애플리케이션은 시스템 컴포지터 잉크를 애플리케이션이 렌더링한 스트로크로 매끄럽게 대체하고 자신이 렌더링한 마지막 이벤트 지점으로 컴포지터를 업데이트할 수 있습니다.

모든 사용자 입력 이벤트를 처리한 후 애플리케이션이 렌더링한 전체 잉크 궤적입니다.

Ink API는 이를 달성하기 위해 기본 운영 체제 API를 노출하는 DelegatedInkTrailPresenter 인터페이스를 제공하며, 향후 추가 프리젠터를 지원할 수 있도록 확장 가능성을 열어 둡니다.

3.2. Ink 인터페이스

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

이 메서드는 DelegatedInkTrailPresenter 객체의 인스턴스를 Promise 안에서 반환하며, 이 객체는 PointerEvent 디스패치 사이에 잉크 스트로크를 렌더링하는 데 사용할 수 있습니다. 이 메서드가 호출될 때마다 새 DelegatedInkTrailPresenter 인스턴스가 생성되어야 합니다.

3.3. InkPresenterParam 딕셔너리

dictionary InkPresenterParam {
    Element? presentationArea = null;
};
presentationArea, 타입은 Element, nullable, 기본값은 null

잉크 궤적의 렌더링을 해당 요소가 경계로 하는 영역으로 제한하는 선택적 Element입니다. presentationArea는 null이거나 Ink 인터페이스와 같은 문서에 있어야 하며, 그렇지 않으면 오류를 발생시키고 중단합니다.

3.4. DelegatedInkTrailPresenter 인터페이스

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

    undefined updateInkTrailStartPoint(PointerEvent event, InkTrailStyle style);
};
presentationArea, 타입은 Element, readonly, nullable

제공된 영역 밖에서 잉크 표시가 이루어지는 것을 방지하기 위해 프리젠터의 범위가 지정되는 DOM 요소에 대한 참조입니다. 이 영역은 항상 해당 요소의 border box에 대한 클라이언트 좌표이므로, 요소를 이동하거나 요소를 스크롤해도 작성자가 다시 계산할 필요가 없습니다. 이것이 제공되지 않으면 기본값은 포함하는 viewport를 사용하는 것입니다. 이 요소는 DelegatedInkTrailPresenter가 연결된 동일한 문서에 있어야 하며, PointerEvent들을 수신하는 동일한 문서에 있어야 합니다. 그렇지 않으면 오류가 발생합니다. presentationArea가 문서에서 제거되면, 다음 updateInkTrailStartPoint는 오류를 발생시키고 중단해야 합니다.

updateInkTrailStartPoint(event, style)

이 메서드는 현재 프레임의 마지막 렌더링 지점으로 어떤 PointerEvent가 사용되었는지를 프리젠터에 나타냅니다. 이는 DelegatedInkTrailPresenter와 같은 문서에 있는 신뢰된 이벤트여야 합니다. 생성된 위임 잉크 궤적은 다음 애니메이션 프레임 동안 렌더링된 뒤 제거되어야 합니다.

3.5. InkTrailStyle 딕셔너리

dictionary InkTrailStyle {
    required DOMString color;
    required unrestricted double diameter;
};
color, 타입은 DOMString

이는 잉크 궤적을 렌더링할 때 프리젠터가 사용할 CSS 색상 코드를 지정합니다. 유효한 CSS 색상이어야 하며, 그렇지 않으면 오류를 발생시키고 중단합니다.

diameter, 타입은 unrestricted double

이는 잉크 궤적을 표시할 때 프리젠터가 사용할 지름을 지정합니다. 0보다 커야 하며, 그렇지 않으면 오류를 발생시키고 중단합니다.

이 partial 인터페이스는 Navigator 인터페이스에 대한 확장을 정의합니다
[Exposed=Window]
partial interface Navigator {
    [SameObject] readonly attribute Ink ink;
};
ink, 타입은 Ink, readonly

현재 문서에 대한 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.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"을 사용하여 규범적 텍스트와 구분됩니다. 다음과 같습니다.

이는 정보 제공용 예제의 한 예입니다.

정보 제공용 참고는 “참고”라는 말로 시작하며 class="note"를 사용하여 규범적 텍스트와 구분됩니다. 다음과 같습니다.

참고, 이는 정보 제공용 참고입니다.

색인

이 명세에서 정의된 용어

참조로 정의된 용어

참고 문헌

규범적 참고 문헌

[DOM]
Anne van Kesteren. DOM Standard. 현행 표준 표준. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. 현행 표준 표준. URL: https://html.spec.whatwg.org/multipage/
[POINTEREVENTS3]
Patrick Lauke; Robert Flack. Pointer Events. URL: https://w3c.github.io/pointerevents/
[RFC2119]
S. Bradner. RFC에서 요구 수준을 나타내기 위해 사용하는 핵심 단어. 1997년 3월. 현재 모범 관행. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 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;
};