Signatur
Beschreibung
DelegatedInkTrailPresenter gehört zur experimentellen Ink API. Zeichnet eine Web-App auf einem <canvas>, hängt der gezeichnete Strich meist ein paar Bildschirmaktualisierungen hinter der Stift- oder Mausspitze her. Der Grund: Jedes pointermove-Ereignis muss erst den Hauptthread, das Rendering und den Kompositor durchlaufen, bevor der Strich auf dem Bildschirm erscheint. Mit dem Presenter übergibt die Seite den letzten Punkt, den sie selbst gezeichnet hat, an den Kompositor des Systems. Der Kompositor zeichnet dann das fehlende Stück bis zur aktuellen Zeigerposition direkt mit den neuesten Eingabedaten. Die Wirkung entspricht einer „Vorhersage“ des Strichs.
Eine Instanz erzeugt man nicht mit einem Konstruktor, sondern mit navigator.ink.requestPresenter(). Das Promise wird mit einem DelegatedInkTrailPresenter erfüllt. Die Schnittstelle hat zwei Bestandteile:
presentationArea(nur lesbar,Element | null): das Element, dessen Bereich den vom System gezeichneten Strich begrenzt. Ist der Wertnull, gilt der gesamte Viewport.updateInkTrailStartPoint(event, style): meldet dem Kompositor, bis zu welchemPointerEventdie App selbst gezeichnet hat und wie der vorläufige Strich aussehen soll (color,diameter). Rückgabewert:undefined.
Am besten ruft man updateInkTrailStartPoint() in jedem pointermove-Handler auf, nachdem das Segment auf dem Canvas gezeichnet wurde. Der vorläufige Strich des Kompositors verschwindet mit dem nächsten Frame und wird dabei durch den echten Strich der App ersetzt. Farbe und Durchmesser sollten deshalb genau zum eigenen Pinsel passen, sonst flackert die Darstellung sichtbar.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $event Pflicht | PointerEvent | Parameter von updateInkTrailStartPoint(): das vertrauenswürdige Zeigerereignis (isTrusted === true), bis zu dessen Position die App den Strich bereits selbst gezeichnet hat. Meist das aktuelle pointermove-Ereignis. |
|
| $style Pflicht | { color: string, diameter: number } | Parameter von updateInkTrailStartPoint(): das Aussehen des vorläufigen Strichs. color ist eine CSS-Farbangabe (z. B. "#1e40af" oder "rgb(0 0 0)"), diameter die Strichstärke in CSS-Pixeln (größer als 0). |
Beispiele
Presenter anfordern und Eigenschaft auslesen
const canvas = document.querySelector('#zeichenflaeche');
const initInk = async () => {
if (!('ink' in navigator)) {
console.log('Ink API nicht verfügbar – normales Zeichnen ohne Beschleunigung');
return null;
}
const presenter = await navigator.ink.requestPresenter({ presentationArea: canvas });
console.log(presenter instanceof DelegatedInkTrailPresenter);
console.log(presenter.presentationArea === canvas);
return presenter;
};
initInk();
Zeichen-App mit beschleunigtem Tintenstrich
const canvas = document.querySelector('#zeichenflaeche');
const ctx = canvas.getContext('2d');
const stil = { color: '#1e40af', diameter: 4 };
ctx.strokeStyle = stil.color;
ctx.lineWidth = stil.diameter;
ctx.lineCap = 'round';
const start = async () => {
const presenter = 'ink' in navigator
? await navigator.ink.requestPresenter({ presentationArea: canvas })
: null;
let zeichnet = false;
canvas.addEventListener('pointerdown', (e) => {
zeichnet = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
});
canvas.addEventListener('pointermove', (e) => {
if (!zeichnet) return;
// Alle zusammengefassten Zwischenpunkte zeichnen
for (const p of e.getCoalescedEvents?.() ?? [e]) {
ctx.lineTo(p.offsetX, p.offsetY);
}
ctx.stroke();
// Kompositor zeichnet ab hier bis zur aktuellen Stiftposition weiter
presenter?.updateInkTrailStartPoint(e, stil);
});
const stopp = () => { zeichnet = false; };
canvas.addEventListener('pointerup', stopp);
canvas.addEventListener('pointerleave', stopp);
};
start();
Pinselwechsel: Stil synchron halten
const canvas = document.querySelector('#zeichenflaeche');
const ctx = canvas.getContext('2d');
const pinsel = { color: 'black', diameter: 2 };
const setzePinsel = (color, diameter) => {
pinsel.color = color;
pinsel.diameter = diameter;
ctx.strokeStyle = color;
ctx.lineWidth = diameter;
};
const presenterPromise = navigator.ink?.requestPresenter({ presentationArea: canvas });
canvas.addEventListener('pointermove', async (e) => {
if (e.buttons !== 1) return;
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
const presenter = await presenterPromise;
// Immer denselben Stil wie auf dem Canvas übergeben
presenter?.updateInkTrailStartPoint(e, { ...pinsel });
});
document.querySelector('#rot').addEventListener('click', () => setzePinsel('red', 6));
// Wichtig · Fallstricke
- Experimentell: Die API läuft nur in Chromium-basierten Browsern ab Version 94. Vor der Nutzung immer mit
'ink' in navigatorprüfen und eine Ausweichlösung ohne Beschleunigung vorsehen. - Nur echte Ereignisse:
updateInkTrailStartPoint()wirft einen Fehler, wenn das Ereignis synthetisch ist (isTrusted === false, etwa überdispatchEvent()erzeugt). Auch eine ungültige Farbe oder ein Durchmesser von 0 oder weniger führt zu einem Fehler. presentationAreamuss ein Element im selben Dokument sein. Außerhalb seiner Grenzen zeichnet der Kompositor nichts. Wird der Canvas verschoben oder skaliert, sollte der Strich trotzdem korrekt begrenzt bleiben. Transformationen und Sonderfälle wiedevicePixelRatiosollte man trotzdem testen.- Der vorläufige Strich ist ein einfacher runder Strich in einer Farbe. Strukturpinsel, Deckkraftverläufe oder druckabhängige Strichstärken lassen sich damit nicht nachbilden. Weicht der eigene Pinsel stark davon ab, entstehen sichtbare Sprünge.
- Den Aufruf nach dem eigenen Zeichnen im selben Handler ausführen, ohne zusätzliche Verzögerung (z. B.
setTimeout). Sonst verpufft der Geschwindigkeitsvorteil.