This feature is not Baseline because it does not work in some of the most widely-used browsers.
Experimental: This is an experimental technology
Check the Browser compatibility table carefully before using this in production.
The DelegatedInkTrailPresenter interface of the Ink API provides the ability to instruct the OS-level compositor to render ink strokes between pointer event dispatches.
expectedImprovement Deprecated Non-standard Read only
Returns a value, in milliseconds, indicating the latency improvement that can be expected using this presenter.
presentationArea Experimental Read only
Returns the Element inside which rendering of ink strokes is confined.
updateInkTrailStartPoint() Experimental
Passes the PointerEvent that was used as the last rendering point for the current frame, allowing the OS-level compositor to render a delegated ink trail ahead of the next pointer event being dispatched.
In this example, we draw a trail onto a 2D canvas. Near the start of the code, we call Ink.requestPresenter(), passing it the canvas as the presentation area for it to take care of and storing the promise it returns in the presenter variable.
Later on, in the pointermove event listener, the new position of the trailhead is drawn onto the canvas each time the event fires. In addition, the DelegatedInkTrailPresenter object returned when the presenter promise fulfills has its updateInkTrailStartPoint() method invoked; this is passed:
style object containing color and diameter settings.The result is that a delegated ink trail is drawn ahead of the default browser rendering on the app's behalf, in the specified style, until the next time it receives a pointermove event.
const ctx = canvas.getContext("2d");
let presenter = navigator.ink.requestPresenter({ presentationArea: canvas });
let move_cnt = 0;
let style = { color: "rgb(0 0 255 / 100%)", diameter: 10 };
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
canvas.addEventListener("pointermove", (evt) => {
const pointSize = 10;
ctx.fillStyle = "black";
ctx.fillRect(evt.pageX, evt.pageY, pointSize, pointSize);
if (move_cnt === 50) {
let r = getRandomInt(0, 255);
let g = getRandomInt(0, 255);
let b = getRandomInt(0, 255);
style = {
color: `rgb(${r} ${g} ${b} / 100%)`,
diameter: 10,
};
move_cnt = 0;
document.getElementById("div").style.backgroundColor =
`rgb(${r} ${g} ${b} / 100%)`;
}
move_cnt += 1;
presenter.then((v) => {
v.updateInkTrailStartPoint(evt, style);
});
});
window.addEventListener("pointerdown", (evt) => {
evt.pointerId;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
});
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
Note: See this example running live — Delegated ink trail.
| Specification |
|---|
| Ink API> # delegatedinktrailpresenter> |
| Desktop | Mobile | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on IOS | Samsung Internet | WebView Android | WebView on iOS | |
DelegatedInkTrailPresenter |
94 | 93 | No | 80 | No | 94 | No | 66 | No | 17.0 | 94 | No |
expectedImprovement |
94–130 | 93–130 | No | 80–115 | No | 94–130 | No | 66–86 | No | 17.0–28.0 | 94–130 | No |
presentationArea |
94 | 93 | No | 80 | No | 94 | No | 66 | No | 17.0 | 94 | No |
updateInkTrailStartPoint |
94 | 93 | No | 80 | No | 94 | No | 66 | No | 17.0 | 94 | No |
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/DelegatedInkTrailPresenter