Skip to content

Commit 596c906

Browse files
authored
Merge pull request #59 from WICG/progers-css-transforms
Switch to CSS transforms for hit testing
2 parents ad866f3 + e85b866 commit 596c906

File tree

4 files changed

+11
-32
lines changed

4 files changed

+11
-32
lines changed

Examples/complex-text.html

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</style>
1212

1313
<canvas id="canvas" width="638" height="318" layoutsubtree="true">
14-
<div id="drawElement" style="width: 550px;">
14+
<div id="drawElement" style="width: 550px;" inert>
1515
Hello world!<br>I'm multi-line, <b>formatted</b>,
1616
rotated text with emoji (&#128512;), RTL text
1717
<span dir=rtl>من فارسی صحبت میکنم</span>,
@@ -41,11 +41,7 @@
4141
ctx.rotate((15 * Math.PI) / 180);
4242
let x = 80 * devicePixelRatio;
4343
let y = -20 * devicePixelRatio;
44-
if (typeof ctx.drawElementImage === 'function') {
45-
ctx.drawElementImage(drawElement, x, y);
46-
} else {
47-
ctx.drawElement(drawElement, x, y);
48-
}
44+
ctx.drawElementImage(drawElement, x, y);
4945
});
5046
// See: https://web.dev/articles/device-pixel-content-box
5147
observer.observe(canvas, {box: ['device-pixel-content-box']});

Examples/text-input.html

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,21 +53,10 @@
5353

5454
function draw() {
5555
ctx.reset();
56-
let x = 30 * devicePixelRatio;
57-
let y = 30 * devicePixelRatio;
58-
if (typeof ctx.drawElementImage === 'function') {
59-
ctx.drawElementImage(drawElement, x, y);
60-
} else {
61-
ctx.drawElement(drawElement, x, y);
62-
}
63-
rect = drawElement.getBoundingClientRect();
64-
ctx.setHitTestRegions([
65-
{
66-
element: drawElement,
67-
rect: {x: x, y: y, width: rect.width * devicePixelRatio,
68-
height: rect.height * devicePixelRatio}
69-
}
70-
]);
56+
let x = 30;
57+
let y = 30
58+
ctx.drawElementImage(drawElement, x * devicePixelRatio, y * devicePixelRatio);
59+
drawElement.style.transform = `translate(${x}px, ${y}px)`;
7160
}
7261

7362
onload = () => {

Examples/webGL.html

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
</style>
2424

2525
<canvas id="gl-canvas" width="638" height="318" layoutsubtree="true">
26-
<div id="drawElement">
26+
<div id="drawElement" inert>
2727
Hello world!<br>I'm multi-line, <b>formatted</b>,
2828
rotated text with emoji (&#128512;), RTL text
2929
<span dir=rtl>من فارسی صحبت میکنم</span>,
@@ -60,13 +60,8 @@
6060
const srcFormat = gl.RGBA;
6161
const srcType = gl.UNSIGNED_BYTE;
6262

63-
if (typeof gl.texElementImage2D === 'function') {
64-
gl.texElementImage2D(gl.TEXTURE_2D, level, internalFormat,
63+
gl.texElementImage2D(gl.TEXTURE_2D, level, internalFormat,
6564
srcFormat, srcType, drawElement);
66-
} else {
67-
gl.texElement2D(gl.TEXTURE_2D, level, internalFormat,
68-
srcFormat, srcType, drawElement);
69-
}
7065

7166
// Linear texture filtering produces better results than mipmap with text.
7267
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

README.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,11 @@ There is no web API to easily render complex layouts of text and other content i
2121
* **Composing HTML Elements with Shaders.** A limited set of CSS shaders, such as filter effects, are already available, but there is a desire to use general WebGL shaders with HTML.
2222
* **HTML Rendering in a 3D Context.** 3D aspects of sites and games need to render rich 2D content into surfaces within a 3D scene.
2323

24-
## Proposed solution: `layoutsubtree`, `drawElementImage`/`texElementImage2D`, `fireOnEveryPaint`, and `setHitTestRegions`
24+
## Proposed solution: `layoutsubtree`, `drawElementImage`/`texElementImage2D`, and `fireOnEveryPaint`
2525

26-
* The `layoutsubtree` attribute on a `<canvas>` element allows its descendant elements to have layout (*), and causes the direct children of the `<canvas>` to have a stacking context and become a containing block for all descendants. Descendant elements of the `<canvas>` still do not paint or hit-test, and are not discovered by UA algorithms like find-in-page.
26+
* The `layoutsubtree` attribute on a `<canvas>` element allows its descendant elements to have layout (*), participate in hit testing, accessibility, etc, and causes the direct children of the `<canvas>` to have a stacking context and become a containing block for all descendants. Descendant elements of the `<canvas>` still do not paint.
2727
* The `CanvasRenderingContext2D.drawElementImage(element, x, y)` method renders `element` and its subtree into a 2D canvas at offset x and y, so long as `element` is a direct child of the `<canvas>`. It has no effect if `layoutsubtree` is not specified on the `<canvas>`.
2828
* The `WebGLRenderingContext.texElementImage2D(..., element)` method renders `element` into a WebGL texture. It has no effect if `layoutsubtree` is not specified on the `<canvas>`.
29-
* The `CanvasRenderingContext2D.setHitTestRegions([{element: ., rect: {x: x, y: y, width: ..., height: ...}, ...])` (and `WebGLRenderingContext.setHitTestRegions(...)`) API takes a list of elements and `<canvas>`-relative rects indicating where the element paints relative to the backing buffer of the canvas. These rects are then used to redirect hit tests for mouse and touch events automatically from the `<canvas>` element to the drawn element.
3029

3130
(*) Without `layoutsubtree`, geometry APIs such as `getBoundingClientRect()` on these elements return an empty rect. They do have computed styles, however, and are keyboard-focusable.
3231

@@ -84,7 +83,7 @@ A demo of the same thing using an experimental extension of [three.js](https://t
8483

8584
#### [See here](Examples/text-input.html) for an example of interactive content in canvas.
8685

87-
This example uses the `setHitTestRegions` API to forward input to a form element drawn with `drawElementImage`. The `fireOnEveryPaint` resize observer option is used to update the canvas as needed. The effect is a fully interactive form in canvas.
86+
The `fireOnEveryPaint` resize observer option is used to update the canvas as needed. The effect is a fully interactive form in canvas.
8887

8988
<img width="640" height="320" alt="text-input" src="https://github.com/user-attachments/assets/be2d098f-17ae-4982-a0f9-a069e3c2d1d5" />
9089

0 commit comments

Comments
 (0)