@rcarls/rc-virtual-canvas 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @rcarls/rc-virtual-canvas
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 5c006de: Ship component CSS minified. Package builds now run the CSS in Lit `css` styles
8
+ and light-DOM structural styles through Lightning CSS, removing comments and
9
+ whitespace while keeping source maps that resolve to each template. Rendered
10
+ styles are unchanged.
11
+
12
+ `@rcarls/rc-common` adds `cssText`, an identity tag that marks a plain CSS
13
+ string for minification. `rc-chip`, `rc-disclosure`, and `rc-accordion` now
14
+ depend on `@rcarls/rc-common` for it.
15
+
16
+ - 1740c28: Map browser client coordinates to content CSS pixels independently of the canvas
17
+ backing-store resolution. Pointer coordinates no longer double under a 2x
18
+ backing store, and CSS zoom no longer changes the meaning of content positions.
19
+ `canvasScaleX` and `canvasScaleY` now report backing-store pixels per local CSS
20
+ pixel, so they remain accurate when an ancestor applies CSS zoom.
21
+
3
22
  ## 0.6.0
4
23
 
5
24
  ### Patch Changes
package/README.md CHANGED
@@ -77,21 +77,21 @@ that triggers native scroll events.
77
77
 
78
78
  ### Read-only properties
79
79
 
80
- | Property | Type | Description |
81
- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------- |
82
- | `canvasScaleX` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the x-axis (≈ `devicePixelRatio` when `autoResizeCanvas` is `true`) |
83
- | `canvasScaleY` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the y-axis |
80
+ | Property | Type | Description |
81
+ | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
82
+ | `canvasScaleX` | `number` | Ratio of canvas backing-store pixels to local CSS pixels along the x-axis; CSS zoom can make it differ from `devicePixelRatio` |
83
+ | `canvasScaleY` | `number` | Ratio of canvas backing-store pixels to CSS pixels along the y-axis |
84
84
 
85
85
  ### Methods
86
86
 
87
- | Method | Description |
88
- | ----------------------------------- | ------------------------------------------------------------------------------------------------ |
89
- | `getViewRect()` | Returns an immutable snapshot of the current viewport rectangle |
90
- | `scrollToContent(x, y, options?)` | Scrolls so the content coordinate is at the viewport origin |
91
- | `centerOnContent(x, y, options?)` | Scrolls so the content coordinate is centered in the viewport |
92
- | `clientToContent(clientX, clientY)` | Converts browser client coordinates to content coordinates using the current backing-store scale |
93
- | `contentToClient(x, y)` | Converts content coordinates back to browser client coordinates |
94
- | `requestRender(reason?)` | Queues a render event; required when `renderMode` is `'manual'` |
87
+ | Method | Description |
88
+ | ----------------------------------- | ------------------------------------------------------------------------ |
89
+ | `getViewRect()` | Returns an immutable snapshot of the current viewport rectangle |
90
+ | `scrollToContent(x, y, options?)` | Scrolls so the content coordinate is at the viewport origin |
91
+ | `centerOnContent(x, y, options?)` | Scrolls so the content coordinate is centered in the viewport |
92
+ | `clientToContent(clientX, clientY)` | Converts browser client coordinates to content coordinates in CSS pixels |
93
+ | `contentToClient(x, y)` | Converts content coordinates back to browser client coordinates |
94
+ | `requestRender(reason?)` | Queues a render event; required when `renderMode` is `'manual'` |
95
95
 
96
96
  ### CSS custom properties
97
97
 
@@ -123,8 +123,8 @@ that triggers native scroll events.
123
123
 
124
124
  ```ts
125
125
  type ViewRect = {
126
- x: number; // Scroll offset — the x origin of the visible window in content space
127
- y: number; // Scroll offset — the y origin of the visible window in content space
126
+ x: number; // Scroll offset; the x origin of the visible window in content space
127
+ y: number; // Scroll offset; the y origin of the visible window in content space
128
128
  width: number; // Visible width in device pixels (from ResizeObserver devicePixelContentBoxSize)
129
129
  height: number; // Visible height in device pixels
130
130
  };
@@ -152,9 +152,14 @@ The component maps scroll position directly to content coordinates:
152
152
  - `viewRect.y` = `scrollTop` of the internal scroll container
153
153
  - `viewRect.width` / `viewRect.height` = canvas dimensions in device pixels (high-DPI aware)
154
154
 
155
+ `clientToContent()` and `contentToClient()` use CSS-pixel content coordinates. The
156
+ canvas backing-store resolution does not change pointer coordinates. Use
157
+ `canvasScaleX` and `canvasScaleY` only when scaling the drawing context.
158
+
155
159
  When drawing, offset your scene by `viewRect.x` and `viewRect.y` to align the visible portion with the canvas origin:
156
160
 
157
161
  ```js
162
+ ctx.setTransform(vc.canvasScaleX, 0, 0, vc.canvasScaleY, 0, 0);
158
163
  ctx.translate(-viewRect.x, -viewRect.y);
159
164
  drawEntireScene(ctx);
160
165
  ctx.resetTransform();
@@ -300,14 +300,14 @@
300
300
  "type": {
301
301
  "text": "number"
302
302
  },
303
- "description": "Content x coordinate in CSS pixels"
303
+ "description": "content x coordinate in CSS pixels"
304
304
  },
305
305
  {
306
306
  "name": "y",
307
307
  "type": {
308
308
  "text": "number"
309
309
  },
310
- "description": "Content y coordinate in CSS pixels"
310
+ "description": "content y coordinate in CSS pixels"
311
311
  },
312
312
  {
313
313
  "name": "options",
@@ -315,7 +315,7 @@
315
315
  "type": {
316
316
  "text": "ScrollOptions"
317
317
  },
318
- "description": "Native scroll options passed to scrollTo"
318
+ "description": "native scroll options passed to scrollTo"
319
319
  }
320
320
  ],
321
321
  "description": "Scrolls so the content coordinate is at the viewport origin."
@@ -329,14 +329,14 @@
329
329
  "type": {
330
330
  "text": "number"
331
331
  },
332
- "description": "Content x coordinate in CSS pixels"
332
+ "description": "content x coordinate in CSS pixels"
333
333
  },
334
334
  {
335
335
  "name": "y",
336
336
  "type": {
337
337
  "text": "number"
338
338
  },
339
- "description": "Content y coordinate in CSS pixels"
339
+ "description": "content y coordinate in CSS pixels"
340
340
  },
341
341
  {
342
342
  "name": "options",
@@ -344,7 +344,7 @@
344
344
  "type": {
345
345
  "text": "ScrollOptions"
346
346
  },
347
- "description": "Native scroll options passed to scrollTo"
347
+ "description": "native scroll options passed to scrollTo"
348
348
  }
349
349
  ],
350
350
  "description": "Scrolls so the content coordinate is centered in the viewport."
@@ -358,17 +358,17 @@
358
358
  "type": {
359
359
  "text": "number"
360
360
  },
361
- "description": "Browser client x coordinate (e.g. from a pointer event)"
361
+ "description": "browser client x coordinate (e.g. from a pointer event)"
362
362
  },
363
363
  {
364
364
  "name": "clientY",
365
365
  "type": {
366
366
  "text": "number"
367
367
  },
368
- "description": "Browser client y coordinate"
368
+ "description": "browser client y coordinate"
369
369
  }
370
370
  ],
371
- "description": "Converts browser client coordinates to content coordinates using the current\nbacking-store scale."
371
+ "description": "Converts browser client coordinates to CSS-pixel content coordinates.\nCanvas backing-store resolution does not change content coordinates."
372
372
  },
373
373
  {
374
374
  "kind": "method",
@@ -379,14 +379,14 @@
379
379
  "type": {
380
380
  "text": "number"
381
381
  },
382
- "description": "Content x coordinate in CSS pixels"
382
+ "description": "content x coordinate in CSS pixels"
383
383
  },
384
384
  {
385
385
  "name": "y",
386
386
  "type": {
387
387
  "text": "number"
388
388
  },
389
- "description": "Content y coordinate in CSS pixels"
389
+ "description": "content y coordinate in CSS pixels"
390
390
  }
391
391
  ],
392
392
  "description": "Converts content coordinates back to browser client coordinates."
@@ -401,7 +401,7 @@
401
401
  "type": {
402
402
  "text": "RCVirtualCanvasRenderReason"
403
403
  },
404
- "description": "Render reason reported in the event detail"
404
+ "description": "render reason reported in the event detail"
405
405
  }
406
406
  ],
407
407
  "description": "Queues a render event on the next animation frame.\n\nRequired when `renderMode` is `'manual'`. In other modes the component\nschedules renders automatically; calling this with reason `'animation-frame'`\nis a no-op when `renderMode` is `'viewport-change'`."
@@ -412,7 +412,7 @@
412
412
  "type": {
413
413
  "text": "number"
414
414
  },
415
- "description": "Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n\nEquals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale\nfactor in `ctx.scale()` to draw at CSS pixel resolution.",
415
+ "description": "Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n\nUse as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\nWhen `autoResizeCanvas` is true, CSS zoom changes this ratio along with\nthe backing-store resolution.",
416
416
  "readonly": true
417
417
  },
418
418
  {
@@ -421,7 +421,7 @@
421
421
  "type": {
422
422
  "text": "number"
423
423
  },
424
- "description": "Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n\nEquals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale\nfactor in `ctx.scale()` to draw at CSS pixel resolution.",
424
+ "description": "Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n\nUse as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\nCSS zoom can make this ratio differ from `devicePixelRatio`.",
425
425
  "readonly": true
426
426
  },
427
427
  {
@@ -466,7 +466,7 @@
466
466
  "type": {
467
467
  "text": "DOMHighResTimeStamp"
468
468
  },
469
- "description": "High-resolution timestamp from `requestAnimationFrame`"
469
+ "description": "high-resolution timestamp from `requestAnimationFrame`"
470
470
  }
471
471
  ],
472
472
  "description": "RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode."
@@ -522,11 +522,36 @@
522
522
  },
523
523
  {
524
524
  "kind": "method",
525
- "name": "_getViewportScaleX",
525
+ "name": "_getCanvasCssWidth",
526
526
  "privacy": "protected",
527
+ "return": {
528
+ "type": {
529
+ "text": "number"
530
+ }
531
+ }
532
+ },
533
+ {
534
+ "kind": "method",
535
+ "name": "_getCanvasCssHeight",
536
+ "privacy": "protected",
537
+ "return": {
538
+ "type": {
539
+ "text": "number"
540
+ }
541
+ }
542
+ },
543
+ {
544
+ "kind": "method",
545
+ "name": "_getClientToContentScaleX",
546
+ "privacy": "protected",
547
+ "return": {
548
+ "type": {
549
+ "text": "number"
550
+ }
551
+ },
527
552
  "parameters": [
528
553
  {
529
- "name": "canvasRect",
554
+ "name": "canvasViewportRect",
530
555
  "type": {
531
556
  "text": "DOMRect"
532
557
  }
@@ -535,11 +560,16 @@
535
560
  },
536
561
  {
537
562
  "kind": "method",
538
- "name": "_getViewportScaleY",
563
+ "name": "_getClientToContentScaleY",
539
564
  "privacy": "protected",
565
+ "return": {
566
+ "type": {
567
+ "text": "number"
568
+ }
569
+ },
540
570
  "parameters": [
541
571
  {
542
- "name": "canvasRect",
572
+ "name": "canvasViewportRect",
543
573
  "type": {
544
574
  "text": "DOMRect"
545
575
  }
@@ -1,79 +1,11 @@
1
- import { css as _, LitElement as p, html as g } from "lit";
2
- import { property as h, query as u, state as l } from "lit/decorators.js";
1
+ import { css as _, LitElement as g, html as p } from "lit";
2
+ import { property as h, query as u, state as d } from "lit/decorators.js";
3
3
  import { styleMap as b } from "lit/directives/style-map.js";
4
- const w = _`
5
- *,
6
- *::before,
7
- *::after {
8
- box-sizing: border-box;
9
- }
10
-
11
- :host {
12
- position: relative;
13
- display: block;
14
- width: max-content;
15
- line-height: 0; /* remove extra space under slotted <canvas> element(s) */
16
- }
17
-
18
- :host([hidden]) {
19
- display: none;
20
- }
21
-
22
- #root {
23
- position: absolute;
24
- top: 0;
25
- left: 0;
26
- width: 100%;
27
- height: 100%;
28
-
29
- overflow: auto;
30
- scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);
31
- }
32
-
33
- #root::-webkit-scrollbar {
34
- width: var(--rc-virtual-canvas-scrollbar-size, auto);
35
- height: var(--rc-virtual-canvas-scrollbar-size, auto);
36
- }
37
-
38
- #root::-webkit-scrollbar-thumb {
39
- background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);
40
- }
41
-
42
- #root::-webkit-scrollbar-button {
43
- background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);
44
- }
45
-
46
- #root::-webkit-scrollbar-track {
47
- background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);
48
- }
49
-
50
- #placeholder {
51
- pointer-events: none;
52
- }
53
-
54
- #overlay {
55
- position: sticky;
56
- left: 0;
57
- top: 0;
58
- z-index: 1;
59
- display: block;
60
- width: 100%;
61
- height: 0;
62
- pointer-events: none;
63
- }
64
-
65
- ::slotted([slot='overlay']) {
66
- pointer-events: auto;
67
- }
68
-
69
- ::slotted(canvas) {
70
- image-rendering: var(--rc-virtual-canvas-image-rendering, auto);
71
- }
72
- `;
73
- var R = Object.defineProperty, f = Object.getOwnPropertyDescriptor, o = (r, t, e, i) => {
74
- for (var s = i > 1 ? void 0 : i ? f(t, e) : t, a = r.length - 1, d; a >= 0; a--)
75
- (d = r[a]) && (s = (i ? d(t, e, s) : d(s)) || s);
76
- return i && s && R(t, e, s), s;
4
+ const w = _`*,:before,:after{box-sizing:border-box}:host{width:max-content;line-height:0;display:block;position:relative}:host([hidden]){display:none}#root{scrollbar-width:var(--rc-virtual-canvas-scrollbar-width,thin);width:100%;height:100%;position:absolute;top:0;left:0;overflow:auto}#root::-webkit-scrollbar{width:var(--rc-virtual-canvas-scrollbar-size,auto);height:var(--rc-virtual-canvas-scrollbar-size,auto)}#root::-webkit-scrollbar-thumb{background:var(--rc-virtual-canvas-scrollbar-thumb-background,ButtonFace)}#root::-webkit-scrollbar-button{background:var(--rc-virtual-canvas-scrollbar-button-background,ButtonFace)}#root::-webkit-scrollbar-track{background:var(--rc-virtual-canvas-scrollbar-track-background,Canvas)}#placeholder{pointer-events:none}#overlay{z-index:1;pointer-events:none;width:100%;height:0;display:block;position:sticky;top:0;left:0}::slotted([slot=overlay]){pointer-events:auto}::slotted(canvas){image-rendering:var(--rc-virtual-canvas-image-rendering,auto)}`;
5
+ var C = Object.defineProperty, f = Object.getOwnPropertyDescriptor, o = (r, t, e, n) => {
6
+ for (var s = n > 1 ? void 0 : n ? f(t, e) : t, a = r.length - 1, l; a >= 0; a--)
7
+ (l = r[a]) && (s = (n ? l(t, e, s) : l(s)) || s);
8
+ return n && s && C(t, e, s), s;
77
9
  };
78
10
  function c(r) {
79
11
  return Object.freeze({
@@ -83,7 +15,7 @@ function c(r) {
83
15
  height: r.height
84
16
  });
85
17
  }
86
- const v = class v extends p {
18
+ const v = class v extends g {
87
19
  constructor() {
88
20
  super(...arguments), this._rafHandle = 0, this._handledPointerEvents = /* @__PURE__ */ new WeakSet(), this._boundUpdate = (t) => this._update(t), this._boundPointerEvent = (t) => this._onPointerEvent(t), this._contentWidth = 0, this._contentHeight = 0, this.autoResizeCanvas = !0, this.renderMode = "continuous", this.imageRendering = "auto", this._$canvas = null, this._viewRect = {
89
21
  x: 0,
@@ -97,11 +29,11 @@ const v = class v extends p {
97
29
  height: 0
98
30
  }, this._resizeObserver = new ResizeObserver((t) => {
99
31
  for (const e of t) {
100
- const i = Array.isArray(e.devicePixelContentBoxSize) ? e.devicePixelContentBoxSize[0] : e.devicePixelContentBoxSize;
32
+ const n = Array.isArray(e.devicePixelContentBoxSize) ? e.devicePixelContentBoxSize[0] : e.devicePixelContentBoxSize;
101
33
  this._viewRect.width = this._getMeasuredCanvasWidth(
102
- i?.inlineSize ?? Math.round(e.contentRect.width * window.devicePixelRatio)
34
+ n?.inlineSize ?? Math.round(e.contentRect.width * window.devicePixelRatio)
103
35
  ), this._viewRect.height = this._getMeasuredCanvasHeight(
104
- i?.blockSize ?? Math.round(e.contentRect.height * window.devicePixelRatio)
36
+ n?.blockSize ?? Math.round(e.contentRect.height * window.devicePixelRatio)
105
37
  ), this._syncCanvasBackingStore(), this._scheduleRender("viewport-change");
106
38
  }
107
39
  });
@@ -159,13 +91,13 @@ const v = class v extends p {
159
91
  /**
160
92
  * Scrolls so the content coordinate is at the viewport origin.
161
93
  *
162
- * @param x - Content x coordinate in CSS pixels
163
- * @param y - Content y coordinate in CSS pixels
164
- * @param options - Native scroll options passed to scrollTo
94
+ * @param x - content x coordinate in CSS pixels
95
+ * @param y - content y coordinate in CSS pixels
96
+ * @param options - native scroll options passed to scrollTo
165
97
  */
166
- scrollToContent(t, e, i = {}) {
98
+ scrollToContent(t, e, n = {}) {
167
99
  this._$root.scrollTo({
168
- ...i,
100
+ ...n,
169
101
  left: t,
170
102
  top: e
171
103
  }), this._viewRect.x = this._$root.scrollLeft, this._viewRect.y = this._$root.scrollTop, this._scheduleRender("viewport-change");
@@ -173,23 +105,23 @@ const v = class v extends p {
173
105
  /**
174
106
  * Scrolls so the content coordinate is centered in the viewport.
175
107
  *
176
- * @param x - Content x coordinate in CSS pixels
177
- * @param y - Content y coordinate in CSS pixels
178
- * @param options - Native scroll options passed to scrollTo
108
+ * @param x - content x coordinate in CSS pixels
109
+ * @param y - content y coordinate in CSS pixels
110
+ * @param options - native scroll options passed to scrollTo
179
111
  */
180
- centerOnContent(t, e, i = {}) {
112
+ centerOnContent(t, e, n = {}) {
181
113
  this.scrollToContent(
182
114
  t - this._$root.clientWidth * 0.5,
183
115
  e - this._$root.clientHeight * 0.5,
184
- i
116
+ n
185
117
  );
186
118
  }
187
119
  /**
188
- * Converts browser client coordinates to content coordinates using the current
189
- * backing-store scale.
120
+ * Converts browser client coordinates to CSS-pixel content coordinates.
121
+ * Canvas backing-store resolution does not change content coordinates.
190
122
  *
191
- * @param clientX - Browser client x coordinate (e.g. from a pointer event)
192
- * @param clientY - Browser client y coordinate
123
+ * @param clientX - browser client x coordinate (e.g. from a pointer event)
124
+ * @param clientY - browser client y coordinate
193
125
  *
194
126
  * @example
195
127
  * vc.addEventListener('pointerdown', (e) => {
@@ -198,28 +130,27 @@ const v = class v extends p {
198
130
  * });
199
131
  */
200
132
  clientToContent(t, e) {
201
- const i = this._getCanvasClientRect(), s = this._getViewportScaleX(i), a = this._getViewportScaleY(i);
133
+ const n = this._getCanvasClientRect(), s = this._getClientToContentScaleX(n), a = this._getClientToContentScaleY(n);
202
134
  return Object.freeze({
203
- x: this._viewRect.x + (t - i.left) * s,
204
- y: this._viewRect.y + (e - i.top) * a
135
+ x: this._viewRect.x + (t - n.left) * s,
136
+ y: this._viewRect.y + (e - n.top) * a
205
137
  });
206
138
  }
207
139
  /**
208
140
  * Converts content coordinates back to browser client coordinates.
209
141
  *
210
- * @param x - Content x coordinate in CSS pixels
211
- * @param y - Content y coordinate in CSS pixels
142
+ * @param x - content x coordinate in CSS pixels
143
+ * @param y - content y coordinate in CSS pixels
212
144
  *
213
145
  * @example
214
146
  * const { x, y } = vc.contentToClient(contentX, contentY);
215
- * tooltip.style.left = `${x}px`;
216
- * tooltip.style.top = `${y}px`;
147
+ * const elementAtPoint = document.elementFromPoint(x, y);
217
148
  */
218
149
  contentToClient(t, e) {
219
- const i = this._getCanvasClientRect(), s = this._getViewportScaleX(i), a = this._getViewportScaleY(i);
150
+ const n = this._getCanvasClientRect(), s = this._getClientToContentScaleX(n), a = this._getClientToContentScaleY(n);
220
151
  return Object.freeze({
221
- x: i.left + (t - this._viewRect.x) / s,
222
- y: i.top + (e - this._viewRect.y) / a
152
+ x: n.left + (t - this._viewRect.x) / s,
153
+ y: n.top + (e - this._viewRect.y) / a
223
154
  });
224
155
  }
225
156
  /**
@@ -229,7 +160,7 @@ const v = class v extends p {
229
160
  * schedules renders automatically; calling this with reason `'animation-frame'`
230
161
  * is a no-op when `renderMode` is `'viewport-change'`.
231
162
  *
232
- * @param reason - Render reason reported in the event detail
163
+ * @param reason - render reason reported in the event detail
233
164
  */
234
165
  requestRender(t = "manual") {
235
166
  this._scheduleRender(t);
@@ -237,8 +168,9 @@ const v = class v extends p {
237
168
  /**
238
169
  * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.
239
170
  *
240
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale
241
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
171
+ * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
172
+ * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with
173
+ * the backing-store resolution.
242
174
  *
243
175
  * @example
244
176
  * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {
@@ -249,18 +181,18 @@ const v = class v extends p {
249
181
  * });
250
182
  */
251
183
  get canvasScaleX() {
252
- const t = this._getCanvasClientRect();
253
- return this._getViewportScaleX(t);
184
+ const t = this._getCanvasCssWidth();
185
+ return t > 0 ? this._viewRect.width / t : 1;
254
186
  }
255
187
  /**
256
188
  * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.
257
189
  *
258
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale
259
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
190
+ * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
191
+ * CSS zoom can make this ratio differ from `devicePixelRatio`.
260
192
  */
261
193
  get canvasScaleY() {
262
- const t = this._getCanvasClientRect();
263
- return this._getViewportScaleY(t);
194
+ const t = this._getCanvasCssHeight();
195
+ return t > 0 ? this._viewRect.height / t : 1;
264
196
  }
265
197
  /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */
266
198
  _onPointerEvent(t) {
@@ -297,7 +229,7 @@ const v = class v extends p {
297
229
  /**
298
230
  * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.
299
231
  *
300
- * @param time - High-resolution timestamp from `requestAnimationFrame`
232
+ * @param time - high-resolution timestamp from `requestAnimationFrame`
301
233
  */
302
234
  _update(t) {
303
235
  if (this._rafHandle = 0, !this.isConnected || this._$canvas == null)
@@ -346,14 +278,22 @@ const v = class v extends p {
346
278
  _getMeasuredCanvasHeight(t) {
347
279
  return !this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0 ? this._$canvas.height : t;
348
280
  }
349
- _getViewportScaleX(t) {
350
- return t.width > 0 ? this._viewRect.width / t.width : 1;
281
+ _getCanvasCssWidth() {
282
+ return this._$canvas?.clientWidth ?? this.clientWidth;
283
+ }
284
+ _getCanvasCssHeight() {
285
+ return this._$canvas?.clientHeight ?? this.clientHeight;
286
+ }
287
+ _getClientToContentScaleX(t) {
288
+ const e = this._getCanvasCssWidth();
289
+ return t.width > 0 && e > 0 ? e / t.width : 1;
351
290
  }
352
- _getViewportScaleY(t) {
353
- return t.height > 0 ? this._viewRect.height / t.height : 1;
291
+ _getClientToContentScaleY(t) {
292
+ const e = this._getCanvasCssHeight();
293
+ return t.height > 0 && e > 0 ? e / t.height : 1;
354
294
  }
355
295
  render() {
356
- return g`
296
+ return p`
357
297
  <div
358
298
  id="root"
359
299
  part="scroller"
@@ -383,38 +323,38 @@ const v = class v extends p {
383
323
  }
384
324
  };
385
325
  v.styles = [w];
386
- let n = v;
326
+ let i = v;
387
327
  o([
388
328
  h({ type: Number, attribute: "content-width" })
389
- ], n.prototype, "contentWidth", 1);
329
+ ], i.prototype, "contentWidth", 1);
390
330
  o([
391
331
  h({ type: Number, attribute: "content-height" })
392
- ], n.prototype, "contentHeight", 1);
332
+ ], i.prototype, "contentHeight", 1);
393
333
  o([
394
334
  h({ attribute: "auto-resize-canvas", type: Boolean })
395
- ], n.prototype, "autoResizeCanvas", 2);
335
+ ], i.prototype, "autoResizeCanvas", 2);
396
336
  o([
397
337
  h({ attribute: "render-mode" })
398
- ], n.prototype, "renderMode", 2);
338
+ ], i.prototype, "renderMode", 2);
399
339
  o([
400
340
  h({ attribute: "image-rendering" })
401
- ], n.prototype, "imageRendering", 2);
341
+ ], i.prototype, "imageRendering", 2);
402
342
  o([
403
343
  u("#root", !0)
404
- ], n.prototype, "_$root", 2);
344
+ ], i.prototype, "_$root", 2);
405
345
  o([
406
346
  u("#placeholder", !0)
407
- ], n.prototype, "_$placeholder", 2);
347
+ ], i.prototype, "_$placeholder", 2);
408
348
  o([
409
- l()
410
- ], n.prototype, "_$canvas", 2);
349
+ d()
350
+ ], i.prototype, "_$canvas", 2);
411
351
  o([
412
- l()
413
- ], n.prototype, "_viewRect", 2);
352
+ d()
353
+ ], i.prototype, "_viewRect", 2);
414
354
  o([
415
- l()
416
- ], n.prototype, "_contentRect", 2);
355
+ d()
356
+ ], i.prototype, "_contentRect", 2);
417
357
  export {
418
- n as R
358
+ i as R
419
359
  };
420
- //# sourceMappingURL=rc-virtual-canvas-BBZvxU4D.js.map
360
+ //# sourceMappingURL=rc-virtual-canvas-DIy-ABTk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-virtual-canvas-DIy-ABTk.js","sources":["../src/rc-virtual-canvas.styles.ts","../src/rc-virtual-canvas.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const virtualCanvasStyles = css`\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n :host {\n position: relative;\n display: block;\n width: max-content;\n line-height: 0; /* remove extra space under slotted <canvas> element(s) */\n }\n\n :host([hidden]) {\n display: none;\n }\n\n #root {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n overflow: auto;\n scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);\n }\n\n #root::-webkit-scrollbar {\n width: var(--rc-virtual-canvas-scrollbar-size, auto);\n height: var(--rc-virtual-canvas-scrollbar-size, auto);\n }\n\n #root::-webkit-scrollbar-thumb {\n background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-button {\n background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-track {\n background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);\n }\n\n #placeholder {\n pointer-events: none;\n }\n\n #overlay {\n position: sticky;\n left: 0;\n top: 0;\n z-index: 1;\n display: block;\n width: 100%;\n height: 0;\n pointer-events: none;\n }\n\n ::slotted([slot='overlay']) {\n pointer-events: auto;\n }\n\n ::slotted(canvas) {\n image-rendering: var(--rc-virtual-canvas-image-rendering, auto);\n }\n`;\n\nexport default virtualCanvasStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport virtualCanvasStyles from './rc-virtual-canvas.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-virtual-canvas': RCVirtualCanvas;\n }\n\n interface HTMLElementEventMap {\n 'rc-virtual-canvas-render': CustomEvent<RCVirtualCanvasRenderInit>;\n 'rc-virtual-canvas-pointer': CustomEvent<RCVirtualCanvasPointerInit>;\n }\n}\n\n/**\n * Scrollable virtual canvas for rendering large coordinate-space content.\n *\n * `x` and `y` are scroll offsets in CSS pixels; `width` and `height` are the canvas\n * backing-store dimensions in device pixels (DPR-accurate when `autoResizeCanvas` is `true`).\n */\nexport type RCVirtualCanvasViewRect = Readonly<{\n /** Scroll offset x in content space (CSS px) */\n x: number;\n\n /** Scroll offset y in content space (CSS px) */\n y: number;\n\n /** Visible width in device pixels */\n width: number;\n\n /** Visible height in device pixels */\n height: number;\n}>;\n\n/** Controls when `rc-virtual-canvas-render` events are dispatched */\nexport type RCVirtualCanvasRenderMode = 'continuous' | 'viewport-change' | 'manual';\n\n/** Identifies what triggered a render event */\nexport type RCVirtualCanvasRenderReason = 'animation-frame' | 'viewport-change' | 'manual';\n\n/** Content-space coordinate pair returned by coordinate-conversion methods */\nexport type RCVirtualCanvasPoint = Readonly<{\n /** Content space x coordinate in CSS pixels */\n x: number;\n\n /** Content space y coordinate in CSS pixels */\n y: number;\n}>;\n\n/**\n * Detail shape for `rc-virtual-canvas-pointer` events.\n *\n * Carries the source event's coordinates in both browser-client and content space,\n * along with all modifier key state.\n */\nexport type RCVirtualCanvasPointerInit = {\n /** DOM event type (e.g. `'pointerdown'`, `'click'`) */\n type: string;\n\n /** Browser client x coordinate from the source event */\n clientX: number;\n\n /** Browser client y coordinate from the source event */\n clientY: number;\n\n /** Content x coordinate in CSS pixels */\n contentX: number;\n\n /** Content y coordinate in CSS pixels */\n contentY: number;\n\n /** Frozen viewport snapshot at the moment the pointer event fired */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Mouse button index from the source event */\n button: number;\n\n /** Active button bitmask from the source event */\n buttons: number;\n\n /** Whether the Alt key was held */\n altKey: boolean;\n\n /** Whether the Ctrl key was held */\n ctrlKey: boolean;\n\n /** Whether the Shift key was held */\n shiftKey: boolean;\n\n /** Whether the Meta key was held */\n metaKey: boolean;\n\n /** The original DOM event that produced this detail */\n sourceEvent: PointerEvent | MouseEvent;\n};\n\n/** CSS `image-rendering` value applied to the slotted canvas */\nexport type RCVirtualCanvasImageRendering = 'auto' | 'crisp-edges' | 'pixelated';\n\n/** Detail shape for `rc-virtual-canvas-render` events */\nexport type RCVirtualCanvasRenderInit = {\n /** High-resolution timestamp from `requestAnimationFrame` */\n time: DOMHighResTimeStamp;\n\n /** What triggered this render */\n reason: RCVirtualCanvasRenderReason;\n\n /** Frozen snapshot of the viewport for this frame */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Frozen snapshot of the full content bounds for this frame */\n contentRect: RCVirtualCanvasViewRect;\n};\n\nfunction createRectSnapshot(rect: RCVirtualCanvasViewRect) {\n return Object.freeze({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n}\n\n/**\n * A scrollable virtual canvas component.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas rc-virtual-canvas docs}\n *\n * @slot - The HTMLCanvasElement\n * @slot overlay - Optional viewport-positioned content rendered inside the\n * scroll container above the canvas.\n *\n * @fires rc-virtual-canvas-render - Fires with viewport data when the canvas should redraw.\n * @fires rc-virtual-canvas-pointer - Fires pointer/mouse input mapped to virtual content coordinates.\n *\n * @csspart scroller - Internal scroll container that owns the virtual content scroll range.\n * @csspart overlay - Viewport-positioned overlay container rendered inside the scroll container.\n *\n * @attr content-width - Total pixel width of the virtual content.\n * @attr content-height - Total pixel height of the virtual content.\n * @attr auto-resize-canvas - Keep the slotted canvas backing store aligned to the viewport.\n * @attr render-mode - Controls when render events are dispatched.\n * @attr image-rendering - Convenience `image-rendering` value applied to the slotted canvas.\n *\n * @cssprop [--rc-virtual-canvas-scrollbar-width=thin] - `scrollbar-width` of the internal\n * scroll container.\n * @cssprop [--rc-virtual-canvas-scrollbar-size=auto] - WebKit scrollbar thickness.\n * @cssprop [--rc-virtual-canvas-scrollbar-thumb-background=ButtonFace] - WebKit scrollbar\n * thumb color.\n * @cssprop [--rc-virtual-canvas-scrollbar-button-background=ButtonFace] - WebKit scrollbar\n * button color.\n * @cssprop [--rc-virtual-canvas-scrollbar-track-background=Canvas] - WebKit scrollbar\n * track color.\n * @cssprop [--rc-virtual-canvas-image-rendering=auto] - `image-rendering` applied to the\n * slotted canvas; kept in sync with the `imageRendering` property.\n */\nexport class RCVirtualCanvas extends LitElement {\n static styles = [virtualCanvasStyles];\n\n protected _rafHandle: number = 0;\n protected _pendingRenderReason?: RCVirtualCanvasRenderReason;\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV && !this.querySelector(':scope > canvas')) {\n console.warn(\n '[rc-virtual-canvas] No direct child <canvas> found. Place a native <canvas> inside <rc-virtual-canvas>.',\n this,\n );\n }\n }\n\n protected readonly _handledPointerEvents = new WeakSet<Event>();\n\n // Stored bound reference so the same closure is used for scheduling and\n // cancellation — `bind()` returns a new function every call.\n protected readonly _boundUpdate = (time: DOMHighResTimeStamp) => this._update(time);\n\n protected readonly _boundPointerEvent = (event: PointerEvent | MouseEvent) =>\n this._onPointerEvent(event);\n\n /** Pixel width of the virtual content */\n @property({ type: Number, attribute: 'content-width' })\n set contentWidth(val: number) {\n const oldValue = this._contentWidth;\n\n this._contentWidth = val;\n\n this._contentRect.width = this._contentWidth;\n this.requestUpdate('contentWidth', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentWidth() {\n return this._contentWidth;\n }\n\n private _contentWidth: number = 0;\n\n /** Pixel height of the virtual content */\n @property({ type: Number, attribute: 'content-height' })\n set contentHeight(val: number) {\n const oldValue = this._contentHeight;\n\n this._contentHeight = val;\n\n this._contentRect.height = this._contentHeight;\n this.requestUpdate('contentHeight', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentHeight() {\n return this._contentHeight;\n }\n\n private _contentHeight: number = 0;\n\n /** When true, keep the slotted canvas backing store aligned to the viewport. */\n @property({ attribute: 'auto-resize-canvas', type: Boolean })\n autoResizeCanvas: boolean = true;\n\n /** Controls when render events are dispatched. */\n @property({ attribute: 'render-mode' })\n renderMode: RCVirtualCanvasRenderMode = 'continuous';\n\n /** Convenience image-rendering value applied to the slotted canvas. */\n @property({ attribute: 'image-rendering' })\n imageRendering: RCVirtualCanvasImageRendering = 'auto';\n\n /** Shadow DOM scroll container that owns pointer interaction and native scrolling */\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n /** Absolutely-positioned div that establishes the virtual scroll range */\n @query('#placeholder', true)\n protected _$placeholder!: HTMLDivElement;\n\n /** Currently-tracked slotted canvas element; `null` when no canvas is slotted */\n @state()\n protected _$canvas: HTMLCanvasElement | null = null;\n\n /** Mutable current-frame viewport geometry; call `getViewRect()` for a frozen snapshot */\n @state()\n protected _viewRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Mutable content bounds; updated when `contentWidth` or `contentHeight` change */\n @state()\n protected _contentRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Watches the slotted canvas for DPR-accurate dimension changes */\n protected _resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const devicePixelBoxSize = Array.isArray(entry.devicePixelContentBoxSize)\n ? entry.devicePixelContentBoxSize[0]\n : entry.devicePixelContentBoxSize;\n\n this._viewRect.width = this._getMeasuredCanvasWidth(\n devicePixelBoxSize?.inlineSize ??\n Math.round(entry.contentRect.width * window.devicePixelRatio),\n );\n\n this._viewRect.height = this._getMeasuredCanvasHeight(\n devicePixelBoxSize?.blockSize ??\n Math.round(entry.contentRect.height * window.devicePixelRatio),\n );\n\n this._syncCanvasBackingStore();\n this._scheduleRender('viewport-change');\n }\n });\n\n /** Reads scroll position from the root container and schedules a render */\n protected _onScroll() {\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n\n this._scheduleRender('viewport-change');\n }\n\n /** Replaces canvas tracking and re-registers the resize observer when slot content changes */\n protected _onSlotChange(e: Event) {\n this._resizeObserver.disconnect();\n\n this._$canvas =\n (e.currentTarget as HTMLSlotElement)\n .assignedElements()\n .filter((el) => el instanceof HTMLCanvasElement)[0] ?? null;\n\n if (this._$canvas != null) {\n this._viewRect = {\n x: this._$root.scrollLeft ?? 0,\n y: this._$root.scrollTop ?? 0,\n width: this._getMeasuredCanvasWidth(this._$canvas.clientWidth),\n height: this._getMeasuredCanvasHeight(this._$canvas.clientHeight),\n };\n\n this._syncCanvasBackingStore();\n this._observeCanvasResize(this._$canvas);\n\n this._scheduleRender('viewport-change');\n }\n }\n\n /** Observes canvas size with DPR-accurate boxes when the browser supports them */\n protected _observeCanvasResize($canvas: HTMLCanvasElement) {\n try {\n this._resizeObserver.observe($canvas, {\n box: 'device-pixel-content-box',\n });\n } catch (error) {\n if (!(error instanceof TypeError)) {\n throw error;\n }\n\n this._resizeObserver.observe($canvas);\n }\n }\n\n /**\n * Returns a frozen snapshot of the current viewport rectangle.\n *\n * Safe to keep between frames — the returned object will not be mutated\n * by future scroll or resize work.\n */\n getViewRect() {\n return createRectSnapshot(this._viewRect);\n }\n\n /**\n * Scrolls so the content coordinate is at the viewport origin.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n * @param options - native scroll options passed to scrollTo\n */\n scrollToContent(x: number, y: number, options: ScrollOptions = {}) {\n this._$root.scrollTo({\n ...options,\n left: x,\n top: y,\n });\n\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n this._scheduleRender('viewport-change');\n }\n\n /**\n * Scrolls so the content coordinate is centered in the viewport.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n * @param options - native scroll options passed to scrollTo\n */\n centerOnContent(x: number, y: number, options: ScrollOptions = {}) {\n this.scrollToContent(\n x - this._$root.clientWidth * 0.5,\n y - this._$root.clientHeight * 0.5,\n options,\n );\n }\n\n /**\n * Converts browser client coordinates to CSS-pixel content coordinates.\n * Canvas backing-store resolution does not change content coordinates.\n *\n * @param clientX - browser client x coordinate (e.g. from a pointer event)\n * @param clientY - browser client y coordinate\n *\n * @example\n * vc.addEventListener('pointerdown', (e) => {\n * const { x, y } = vc.clientToContent(e.clientX, e.clientY);\n * placeMarkerAt(x, y);\n * });\n */\n clientToContent(clientX: number, clientY: number) {\n const canvasViewportRect = this._getCanvasClientRect();\n const clientToContentScaleX = this._getClientToContentScaleX(canvasViewportRect);\n const clientToContentScaleY = this._getClientToContentScaleY(canvasViewportRect);\n\n return Object.freeze({\n x: this._viewRect.x + (clientX - canvasViewportRect.left) * clientToContentScaleX,\n y: this._viewRect.y + (clientY - canvasViewportRect.top) * clientToContentScaleY,\n });\n }\n\n /**\n * Converts content coordinates back to browser client coordinates.\n *\n * @param x - content x coordinate in CSS pixels\n * @param y - content y coordinate in CSS pixels\n *\n * @example\n * const { x, y } = vc.contentToClient(contentX, contentY);\n * const elementAtPoint = document.elementFromPoint(x, y);\n */\n contentToClient(x: number, y: number) {\n const canvasViewportRect = this._getCanvasClientRect();\n const clientToContentScaleX = this._getClientToContentScaleX(canvasViewportRect);\n const clientToContentScaleY = this._getClientToContentScaleY(canvasViewportRect);\n\n return Object.freeze({\n x: canvasViewportRect.left + (x - this._viewRect.x) / clientToContentScaleX,\n y: canvasViewportRect.top + (y - this._viewRect.y) / clientToContentScaleY,\n });\n }\n\n /**\n * Queues a render event on the next animation frame.\n *\n * Required when `renderMode` is `'manual'`. In other modes the component\n * schedules renders automatically; calling this with reason `'animation-frame'`\n * is a no-op when `renderMode` is `'viewport-change'`.\n *\n * @param reason - render reason reported in the event detail\n */\n requestRender(reason: RCVirtualCanvasRenderReason = 'manual') {\n this._scheduleRender(reason);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n *\n * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\n * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with\n * the backing-store resolution.\n *\n * @example\n * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {\n * ctx.save();\n * ctx.scale(vc.canvasScaleX, vc.canvasScaleY);\n * drawScene(ctx, viewRect);\n * ctx.restore();\n * });\n */\n get canvasScaleX(): number {\n const cssWidth = this._getCanvasCssWidth();\n\n return cssWidth > 0 ? this._viewRect.width / cssWidth : 1;\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n *\n * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.\n * CSS zoom can make this ratio differ from `devicePixelRatio`.\n */\n get canvasScaleY(): number {\n const cssHeight = this._getCanvasCssHeight();\n\n return cssHeight > 0 ? this._viewRect.height / cssHeight : 1;\n }\n\n /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */\n protected _onPointerEvent(event: PointerEvent | MouseEvent) {\n if (this._handledPointerEvents.has(event)) {\n return;\n }\n\n if (this._isOverlayEvent(event)) {\n return;\n }\n\n this._handledPointerEvents.add(event);\n\n const contentPoint = this.clientToContent(event.clientX, event.clientY);\n\n const shouldContinue = this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasPointerInit>('rc-virtual-canvas-pointer', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: {\n type: event.type,\n clientX: event.clientX,\n clientY: event.clientY,\n contentX: contentPoint.x,\n contentY: contentPoint.y,\n viewRect: createRectSnapshot(this._viewRect),\n button: event.button,\n buttons: event.buttons,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n shiftKey: event.shiftKey,\n metaKey: event.metaKey,\n sourceEvent: event,\n },\n }),\n );\n\n if (!shouldContinue) {\n event.preventDefault();\n }\n }\n\n protected _isOverlayEvent(event: Event): boolean {\n return event\n .composedPath()\n .some(($node) => $node instanceof HTMLSlotElement && $node.name === 'overlay');\n }\n\n /**\n * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.\n *\n * @param time - high-resolution timestamp from `requestAnimationFrame`\n */\n protected _update(time: DOMHighResTimeStamp) {\n this._rafHandle = 0;\n\n if (!this.isConnected || this._$canvas == null) {\n return;\n }\n\n const reason =\n this._pendingRenderReason ??\n (this.renderMode === 'continuous' ? 'animation-frame' : 'manual');\n\n this._pendingRenderReason = undefined;\n\n this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasRenderInit>('rc-virtual-canvas-render', {\n bubbles: true,\n composed: true,\n detail: {\n time,\n reason,\n viewRect: createRectSnapshot(this._viewRect),\n contentRect: createRectSnapshot(this._contentRect),\n },\n }),\n );\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Registers pointer event listeners and starts rendering in continuous mode */\n override connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('pointerdown', this._boundPointerEvent);\n this.addEventListener('pointermove', this._boundPointerEvent);\n this.addEventListener('pointerup', this._boundPointerEvent);\n this.addEventListener('click', this._boundPointerEvent);\n this.addEventListener('dblclick', this._boundPointerEvent);\n this.addEventListener('contextmenu', this._boundPointerEvent);\n\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n }\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Cancels any pending animation frame, disconnects the resize observer, and removes pointer listeners */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n this._resizeObserver.disconnect();\n\n this.removeEventListener('pointerdown', this._boundPointerEvent);\n this.removeEventListener('pointermove', this._boundPointerEvent);\n this.removeEventListener('pointerup', this._boundPointerEvent);\n this.removeEventListener('click', this._boundPointerEvent);\n this.removeEventListener('dblclick', this._boundPointerEvent);\n this.removeEventListener('contextmenu', this._boundPointerEvent);\n }\n\n /** Reacts to `renderMode`, `autoResizeCanvas`, and `imageRendering` property changes */\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('renderMode')) {\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n } else if (this._pendingRenderReason === 'animation-frame') {\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n\n this._rafHandle = 0;\n }\n\n this._pendingRenderReason = undefined;\n } else if (this.renderMode === 'viewport-change') {\n this._scheduleRender('viewport-change');\n }\n }\n\n if (changed.has('autoResizeCanvas')) {\n this._syncCanvasBackingStore();\n }\n\n if (changed.has('imageRendering')) {\n this.style.setProperty('--rc-virtual-canvas-image-rendering', this.imageRendering);\n }\n }\n\n protected _scheduleRender(reason: RCVirtualCanvasRenderReason) {\n if (this.renderMode === 'manual' && reason !== 'manual') {\n return;\n }\n\n if (this.renderMode === 'viewport-change' && reason === 'animation-frame') {\n return;\n }\n\n this._pendingRenderReason = reason;\n\n if (!this.isConnected || this._rafHandle) {\n return;\n }\n\n this._rafHandle = window.requestAnimationFrame(this._boundUpdate);\n }\n\n protected _syncCanvasBackingStore() {\n if (!this.autoResizeCanvas || this._$canvas == null) {\n return;\n }\n\n const width = Math.max(0, Math.round(this._viewRect.width));\n const height = Math.max(0, Math.round(this._viewRect.height));\n\n if (this._$canvas.width !== width) {\n this._$canvas.width = width;\n }\n\n if (this._$canvas.height !== height) {\n this._$canvas.height = height;\n }\n }\n\n protected _getCanvasClientRect() {\n if (this._$canvas == null) {\n return this.getBoundingClientRect();\n }\n\n return this._$canvas.getBoundingClientRect();\n }\n\n protected _getMeasuredCanvasWidth(fallbackWidth: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.width > 0) {\n return this._$canvas.width;\n }\n\n return fallbackWidth;\n }\n\n protected _getMeasuredCanvasHeight(fallbackHeight: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0) {\n return this._$canvas.height;\n }\n\n return fallbackHeight;\n }\n\n protected _getCanvasCssWidth(): number {\n return this._$canvas?.clientWidth ?? this.clientWidth;\n }\n\n protected _getCanvasCssHeight(): number {\n return this._$canvas?.clientHeight ?? this.clientHeight;\n }\n\n protected _getClientToContentScaleX(canvasViewportRect: DOMRect): number {\n const canvasCssWidth = this._getCanvasCssWidth();\n\n return canvasViewportRect.width > 0 && canvasCssWidth > 0\n ? canvasCssWidth / canvasViewportRect.width\n : 1;\n }\n\n protected _getClientToContentScaleY(canvasViewportRect: DOMRect): number {\n const canvasCssHeight = this._getCanvasCssHeight();\n\n return canvasViewportRect.height > 0 && canvasCssHeight > 0\n ? canvasCssHeight / canvasViewportRect.height\n : 1;\n }\n\n render() {\n return html`\n <div\n id=\"root\"\n part=\"scroller\"\n @scroll=${this._onScroll}\n @pointerdown=${this._onPointerEvent}\n @pointermove=${this._onPointerEvent}\n @pointerup=${this._onPointerEvent}\n @click=${this._onPointerEvent}\n @dblclick=${this._onPointerEvent}\n @contextmenu=${this._onPointerEvent}\n >\n <div id=\"overlay\" part=\"overlay\">\n <slot name=\"overlay\"></slot>\n </div>\n\n <div\n id=\"placeholder\"\n style=${styleMap({\n width: `${this.contentWidth}px`,\n height: `${this.contentHeight}px`,\n })}\n ></div>\n </div>\n\n <slot @slotchange=${this._onSlotChange}></slot>\n `;\n }\n}\n\nexport default RCVirtualCanvas;\n"],"names":["virtualCanvasStyles","css","createRectSnapshot","rect","_RCVirtualCanvas","LitElement","time","event","entries","entry","devicePixelBoxSize","val","oldValue","e","el","$canvas","error","x","y","options","clientX","clientY","canvasViewportRect","clientToContentScaleX","clientToContentScaleY","reason","cssWidth","cssHeight","contentPoint","$node","changed","width","height","fallbackWidth","fallbackHeight","canvasCssWidth","canvasCssHeight","html","styleMap","RCVirtualCanvas","__decorateClass","property","query","state"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { R as a } from "./rc-virtual-canvas-BBZvxU4D.js";
1
+ import { R as a } from "./rc-virtual-canvas-DIy-ABTk.js";
2
2
  customElements.get("rc-virtual-canvas") || customElements.define("rc-virtual-canvas", a);
3
3
  export {
4
4
  a as RCVirtualCanvas
@@ -1,4 +1,4 @@
1
- import { R as o } from "./rc-virtual-canvas-BBZvxU4D.js";
1
+ import { R as o } from "./rc-virtual-canvas-DIy-ABTk.js";
2
2
  export {
3
3
  o as RCVirtualCanvas
4
4
  };
@@ -48,9 +48,9 @@ export type RCVirtualCanvasPointerInit = {
48
48
  clientX: number;
49
49
  /** Browser client y coordinate from the source event */
50
50
  clientY: number;
51
- /** Content x coordinate mapped through the current backing-store scale */
51
+ /** Content x coordinate in CSS pixels */
52
52
  contentX: number;
53
- /** Content y coordinate mapped through the current backing-store scale */
53
+ /** Content y coordinate in CSS pixels */
54
54
  contentY: number;
55
55
  /** Frozen viewport snapshot at the moment the pointer event fired */
56
56
  viewRect: RCVirtualCanvasViewRect;
@@ -180,25 +180,25 @@ export declare class RCVirtualCanvas extends LitElement {
180
180
  /**
181
181
  * Scrolls so the content coordinate is at the viewport origin.
182
182
  *
183
- * @param x - Content x coordinate in CSS pixels
184
- * @param y - Content y coordinate in CSS pixels
185
- * @param options - Native scroll options passed to scrollTo
183
+ * @param x - content x coordinate in CSS pixels
184
+ * @param y - content y coordinate in CSS pixels
185
+ * @param options - native scroll options passed to scrollTo
186
186
  */
187
187
  scrollToContent(x: number, y: number, options?: ScrollOptions): void;
188
188
  /**
189
189
  * Scrolls so the content coordinate is centered in the viewport.
190
190
  *
191
- * @param x - Content x coordinate in CSS pixels
192
- * @param y - Content y coordinate in CSS pixels
193
- * @param options - Native scroll options passed to scrollTo
191
+ * @param x - content x coordinate in CSS pixels
192
+ * @param y - content y coordinate in CSS pixels
193
+ * @param options - native scroll options passed to scrollTo
194
194
  */
195
195
  centerOnContent(x: number, y: number, options?: ScrollOptions): void;
196
196
  /**
197
- * Converts browser client coordinates to content coordinates using the current
198
- * backing-store scale.
197
+ * Converts browser client coordinates to CSS-pixel content coordinates.
198
+ * Canvas backing-store resolution does not change content coordinates.
199
199
  *
200
- * @param clientX - Browser client x coordinate (e.g. from a pointer event)
201
- * @param clientY - Browser client y coordinate
200
+ * @param clientX - browser client x coordinate (e.g. from a pointer event)
201
+ * @param clientY - browser client y coordinate
202
202
  *
203
203
  * @example
204
204
  * vc.addEventListener('pointerdown', (e) => {
@@ -213,13 +213,12 @@ export declare class RCVirtualCanvas extends LitElement {
213
213
  /**
214
214
  * Converts content coordinates back to browser client coordinates.
215
215
  *
216
- * @param x - Content x coordinate in CSS pixels
217
- * @param y - Content y coordinate in CSS pixels
216
+ * @param x - content x coordinate in CSS pixels
217
+ * @param y - content y coordinate in CSS pixels
218
218
  *
219
219
  * @example
220
220
  * const { x, y } = vc.contentToClient(contentX, contentY);
221
- * tooltip.style.left = `${x}px`;
222
- * tooltip.style.top = `${y}px`;
221
+ * const elementAtPoint = document.elementFromPoint(x, y);
223
222
  */
224
223
  contentToClient(x: number, y: number): Readonly<{
225
224
  x: number;
@@ -232,14 +231,15 @@ export declare class RCVirtualCanvas extends LitElement {
232
231
  * schedules renders automatically; calling this with reason `'animation-frame'`
233
232
  * is a no-op when `renderMode` is `'viewport-change'`.
234
233
  *
235
- * @param reason - Render reason reported in the event detail
234
+ * @param reason - render reason reported in the event detail
236
235
  */
237
236
  requestRender(reason?: RCVirtualCanvasRenderReason): void;
238
237
  /**
239
238
  * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.
240
239
  *
241
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale
242
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
240
+ * Use as the x-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
241
+ * When `autoResizeCanvas` is true, CSS zoom changes this ratio along with
242
+ * the backing-store resolution.
243
243
  *
244
244
  * @example
245
245
  * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {
@@ -253,8 +253,8 @@ export declare class RCVirtualCanvas extends LitElement {
253
253
  /**
254
254
  * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.
255
255
  *
256
- * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale
257
- * factor in `ctx.scale()` to draw at CSS pixel resolution.
256
+ * Use as the y-scale factor in `ctx.scale()` to draw at CSS pixel resolution.
257
+ * CSS zoom can make this ratio differ from `devicePixelRatio`.
258
258
  */
259
259
  get canvasScaleY(): number;
260
260
  /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */
@@ -263,7 +263,7 @@ export declare class RCVirtualCanvas extends LitElement {
263
263
  /**
264
264
  * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.
265
265
  *
266
- * @param time - High-resolution timestamp from `requestAnimationFrame`
266
+ * @param time - high-resolution timestamp from `requestAnimationFrame`
267
267
  */
268
268
  protected _update(time: DOMHighResTimeStamp): void;
269
269
  /** Registers pointer event listeners and starts rendering in continuous mode */
@@ -277,8 +277,10 @@ export declare class RCVirtualCanvas extends LitElement {
277
277
  protected _getCanvasClientRect(): DOMRect;
278
278
  protected _getMeasuredCanvasWidth(fallbackWidth: number): number;
279
279
  protected _getMeasuredCanvasHeight(fallbackHeight: number): number;
280
- protected _getViewportScaleX(canvasRect: DOMRect): number;
281
- protected _getViewportScaleY(canvasRect: DOMRect): number;
282
- render(): import('lit').TemplateResult<1>;
280
+ protected _getCanvasCssWidth(): number;
281
+ protected _getCanvasCssHeight(): number;
282
+ protected _getClientToContentScaleX(canvasViewportRect: DOMRect): number;
283
+ protected _getClientToContentScaleY(canvasViewportRect: DOMRect): number;
284
+ render(): import('lit-html').TemplateResult<1>;
283
285
  }
284
286
  export default RCVirtualCanvas;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.0",
6
+ "version": "0.7.0",
7
7
  "description": "Scrollable virtual canvas for rendering large coordinate-space content.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-virtual-canvas-BBZvxU4D.js","sources":["../src/rc-virtual-canvas.styles.ts","../src/rc-virtual-canvas.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const virtualCanvasStyles = css`\n *,\n *::before,\n *::after {\n box-sizing: border-box;\n }\n\n :host {\n position: relative;\n display: block;\n width: max-content;\n line-height: 0; /* remove extra space under slotted <canvas> element(s) */\n }\n\n :host([hidden]) {\n display: none;\n }\n\n #root {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n\n overflow: auto;\n scrollbar-width: var(--rc-virtual-canvas-scrollbar-width, thin);\n }\n\n #root::-webkit-scrollbar {\n width: var(--rc-virtual-canvas-scrollbar-size, auto);\n height: var(--rc-virtual-canvas-scrollbar-size, auto);\n }\n\n #root::-webkit-scrollbar-thumb {\n background: var(--rc-virtual-canvas-scrollbar-thumb-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-button {\n background: var(--rc-virtual-canvas-scrollbar-button-background, ButtonFace);\n }\n\n #root::-webkit-scrollbar-track {\n background: var(--rc-virtual-canvas-scrollbar-track-background, Canvas);\n }\n\n #placeholder {\n pointer-events: none;\n }\n\n #overlay {\n position: sticky;\n left: 0;\n top: 0;\n z-index: 1;\n display: block;\n width: 100%;\n height: 0;\n pointer-events: none;\n }\n\n ::slotted([slot='overlay']) {\n pointer-events: auto;\n }\n\n ::slotted(canvas) {\n image-rendering: var(--rc-virtual-canvas-image-rendering, auto);\n }\n`;\n\nexport default virtualCanvasStyles;\n","import { LitElement, html } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport virtualCanvasStyles from './rc-virtual-canvas.styles.js';\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-virtual-canvas': RCVirtualCanvas;\n }\n\n interface HTMLElementEventMap {\n 'rc-virtual-canvas-render': CustomEvent<RCVirtualCanvasRenderInit>;\n 'rc-virtual-canvas-pointer': CustomEvent<RCVirtualCanvasPointerInit>;\n }\n}\n\n/**\n * Scrollable virtual canvas for rendering large coordinate-space content.\n *\n * `x` and `y` are scroll offsets in CSS pixels; `width` and `height` are the canvas\n * backing-store dimensions in device pixels (DPR-accurate when `autoResizeCanvas` is `true`).\n */\nexport type RCVirtualCanvasViewRect = Readonly<{\n /** Scroll offset x in content space (CSS px) */\n x: number;\n\n /** Scroll offset y in content space (CSS px) */\n y: number;\n\n /** Visible width in device pixels */\n width: number;\n\n /** Visible height in device pixels */\n height: number;\n}>;\n\n/** Controls when `rc-virtual-canvas-render` events are dispatched */\nexport type RCVirtualCanvasRenderMode = 'continuous' | 'viewport-change' | 'manual';\n\n/** Identifies what triggered a render event */\nexport type RCVirtualCanvasRenderReason = 'animation-frame' | 'viewport-change' | 'manual';\n\n/** Content-space coordinate pair returned by coordinate-conversion methods */\nexport type RCVirtualCanvasPoint = Readonly<{\n /** Content space x coordinate in CSS pixels */\n x: number;\n\n /** Content space y coordinate in CSS pixels */\n y: number;\n}>;\n\n/**\n * Detail shape for `rc-virtual-canvas-pointer` events.\n *\n * Carries the source event's coordinates in both browser-client and content space,\n * along with all modifier key state.\n */\nexport type RCVirtualCanvasPointerInit = {\n /** DOM event type (e.g. `'pointerdown'`, `'click'`) */\n type: string;\n\n /** Browser client x coordinate from the source event */\n clientX: number;\n\n /** Browser client y coordinate from the source event */\n clientY: number;\n\n /** Content x coordinate mapped through the current backing-store scale */\n contentX: number;\n\n /** Content y coordinate mapped through the current backing-store scale */\n contentY: number;\n\n /** Frozen viewport snapshot at the moment the pointer event fired */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Mouse button index from the source event */\n button: number;\n\n /** Active button bitmask from the source event */\n buttons: number;\n\n /** Whether the Alt key was held */\n altKey: boolean;\n\n /** Whether the Ctrl key was held */\n ctrlKey: boolean;\n\n /** Whether the Shift key was held */\n shiftKey: boolean;\n\n /** Whether the Meta key was held */\n metaKey: boolean;\n\n /** The original DOM event that produced this detail */\n sourceEvent: PointerEvent | MouseEvent;\n};\n\n/** CSS `image-rendering` value applied to the slotted canvas */\nexport type RCVirtualCanvasImageRendering = 'auto' | 'crisp-edges' | 'pixelated';\n\n/** Detail shape for `rc-virtual-canvas-render` events */\nexport type RCVirtualCanvasRenderInit = {\n /** High-resolution timestamp from `requestAnimationFrame` */\n time: DOMHighResTimeStamp;\n\n /** What triggered this render */\n reason: RCVirtualCanvasRenderReason;\n\n /** Frozen snapshot of the viewport for this frame */\n viewRect: RCVirtualCanvasViewRect;\n\n /** Frozen snapshot of the full content bounds for this frame */\n contentRect: RCVirtualCanvasViewRect;\n};\n\nfunction createRectSnapshot(rect: RCVirtualCanvasViewRect) {\n return Object.freeze({\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n });\n}\n\n/**\n * A scrollable virtual canvas component.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-virtual-canvas rc-virtual-canvas docs}\n *\n * @slot - The HTMLCanvasElement\n * @slot overlay - Optional viewport-positioned content rendered inside the\n * scroll container above the canvas.\n *\n * @fires rc-virtual-canvas-render - Fires with viewport data when the canvas should redraw.\n * @fires rc-virtual-canvas-pointer - Fires pointer/mouse input mapped to virtual content coordinates.\n *\n * @csspart scroller - Internal scroll container that owns the virtual content scroll range.\n * @csspart overlay - Viewport-positioned overlay container rendered inside the scroll container.\n *\n * @attr content-width - Total pixel width of the virtual content.\n * @attr content-height - Total pixel height of the virtual content.\n * @attr auto-resize-canvas - Keep the slotted canvas backing store aligned to the viewport.\n * @attr render-mode - Controls when render events are dispatched.\n * @attr image-rendering - Convenience `image-rendering` value applied to the slotted canvas.\n *\n * @cssprop [--rc-virtual-canvas-scrollbar-width=thin] - `scrollbar-width` of the internal\n * scroll container.\n * @cssprop [--rc-virtual-canvas-scrollbar-size=auto] - WebKit scrollbar thickness.\n * @cssprop [--rc-virtual-canvas-scrollbar-thumb-background=ButtonFace] - WebKit scrollbar\n * thumb color.\n * @cssprop [--rc-virtual-canvas-scrollbar-button-background=ButtonFace] - WebKit scrollbar\n * button color.\n * @cssprop [--rc-virtual-canvas-scrollbar-track-background=Canvas] - WebKit scrollbar\n * track color.\n * @cssprop [--rc-virtual-canvas-image-rendering=auto] - `image-rendering` applied to the\n * slotted canvas; kept in sync with the `imageRendering` property.\n */\nexport class RCVirtualCanvas extends LitElement {\n static styles = [virtualCanvasStyles];\n\n protected _rafHandle: number = 0;\n protected _pendingRenderReason?: RCVirtualCanvasRenderReason;\n\n protected override firstUpdated(): void {\n if (import.meta.env.DEV && !this.querySelector(':scope > canvas')) {\n console.warn(\n '[rc-virtual-canvas] No direct child <canvas> found. Place a native <canvas> inside <rc-virtual-canvas>.',\n this,\n );\n }\n }\n\n protected readonly _handledPointerEvents = new WeakSet<Event>();\n\n // Stored bound reference so the same closure is used for scheduling and\n // cancellation — `bind()` returns a new function every call.\n protected readonly _boundUpdate = (time: DOMHighResTimeStamp) => this._update(time);\n\n protected readonly _boundPointerEvent = (event: PointerEvent | MouseEvent) =>\n this._onPointerEvent(event);\n\n /** Pixel width of the virtual content */\n @property({ type: Number, attribute: 'content-width' })\n set contentWidth(val: number) {\n const oldValue = this._contentWidth;\n\n this._contentWidth = val;\n\n this._contentRect.width = this._contentWidth;\n this.requestUpdate('contentWidth', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentWidth() {\n return this._contentWidth;\n }\n\n private _contentWidth: number = 0;\n\n /** Pixel height of the virtual content */\n @property({ type: Number, attribute: 'content-height' })\n set contentHeight(val: number) {\n const oldValue = this._contentHeight;\n\n this._contentHeight = val;\n\n this._contentRect.height = this._contentHeight;\n this.requestUpdate('contentHeight', oldValue);\n this._scheduleRender('viewport-change');\n }\n\n get contentHeight() {\n return this._contentHeight;\n }\n\n private _contentHeight: number = 0;\n\n /** When true, keep the slotted canvas backing store aligned to the viewport. */\n @property({ attribute: 'auto-resize-canvas', type: Boolean })\n autoResizeCanvas: boolean = true;\n\n /** Controls when render events are dispatched. */\n @property({ attribute: 'render-mode' })\n renderMode: RCVirtualCanvasRenderMode = 'continuous';\n\n /** Convenience image-rendering value applied to the slotted canvas. */\n @property({ attribute: 'image-rendering' })\n imageRendering: RCVirtualCanvasImageRendering = 'auto';\n\n /** Shadow DOM scroll container that owns pointer interaction and native scrolling */\n @query('#root', true)\n protected _$root!: HTMLDivElement;\n\n /** Absolutely-positioned div that establishes the virtual scroll range */\n @query('#placeholder', true)\n protected _$placeholder!: HTMLDivElement;\n\n /** Currently-tracked slotted canvas element; `null` when no canvas is slotted */\n @state()\n protected _$canvas: HTMLCanvasElement | null = null;\n\n /** Mutable current-frame viewport geometry; call `getViewRect()` for a frozen snapshot */\n @state()\n protected _viewRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Mutable content bounds; updated when `contentWidth` or `contentHeight` change */\n @state()\n protected _contentRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n };\n\n /** Watches the slotted canvas for DPR-accurate dimension changes */\n protected _resizeObserver = new ResizeObserver((entries: ResizeObserverEntry[]) => {\n for (const entry of entries) {\n const devicePixelBoxSize = Array.isArray(entry.devicePixelContentBoxSize)\n ? entry.devicePixelContentBoxSize[0]\n : entry.devicePixelContentBoxSize;\n\n this._viewRect.width = this._getMeasuredCanvasWidth(\n devicePixelBoxSize?.inlineSize ??\n Math.round(entry.contentRect.width * window.devicePixelRatio),\n );\n\n this._viewRect.height = this._getMeasuredCanvasHeight(\n devicePixelBoxSize?.blockSize ??\n Math.round(entry.contentRect.height * window.devicePixelRatio),\n );\n\n this._syncCanvasBackingStore();\n this._scheduleRender('viewport-change');\n }\n });\n\n /** Reads scroll position from the root container and schedules a render */\n protected _onScroll() {\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n\n this._scheduleRender('viewport-change');\n }\n\n /** Replaces canvas tracking and re-registers the resize observer when slot content changes */\n protected _onSlotChange(e: Event) {\n this._resizeObserver.disconnect();\n\n this._$canvas =\n (e.currentTarget as HTMLSlotElement)\n .assignedElements()\n .filter((el) => el instanceof HTMLCanvasElement)[0] ?? null;\n\n if (this._$canvas != null) {\n this._viewRect = {\n x: this._$root.scrollLeft ?? 0,\n y: this._$root.scrollTop ?? 0,\n width: this._getMeasuredCanvasWidth(this._$canvas.clientWidth),\n height: this._getMeasuredCanvasHeight(this._$canvas.clientHeight),\n };\n\n this._syncCanvasBackingStore();\n this._observeCanvasResize(this._$canvas);\n\n this._scheduleRender('viewport-change');\n }\n }\n\n /** Observes canvas size with DPR-accurate boxes when the browser supports them */\n protected _observeCanvasResize($canvas: HTMLCanvasElement) {\n try {\n this._resizeObserver.observe($canvas, {\n box: 'device-pixel-content-box',\n });\n } catch (error) {\n if (!(error instanceof TypeError)) {\n throw error;\n }\n\n this._resizeObserver.observe($canvas);\n }\n }\n\n /**\n * Returns a frozen snapshot of the current viewport rectangle.\n *\n * Safe to keep between frames — the returned object will not be mutated\n * by future scroll or resize work.\n */\n getViewRect() {\n return createRectSnapshot(this._viewRect);\n }\n\n /**\n * Scrolls so the content coordinate is at the viewport origin.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n * @param options - Native scroll options passed to scrollTo\n */\n scrollToContent(x: number, y: number, options: ScrollOptions = {}) {\n this._$root.scrollTo({\n ...options,\n left: x,\n top: y,\n });\n\n this._viewRect.x = this._$root.scrollLeft;\n this._viewRect.y = this._$root.scrollTop;\n this._scheduleRender('viewport-change');\n }\n\n /**\n * Scrolls so the content coordinate is centered in the viewport.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n * @param options - Native scroll options passed to scrollTo\n */\n centerOnContent(x: number, y: number, options: ScrollOptions = {}) {\n this.scrollToContent(\n x - this._$root.clientWidth * 0.5,\n y - this._$root.clientHeight * 0.5,\n options,\n );\n }\n\n /**\n * Converts browser client coordinates to content coordinates using the current\n * backing-store scale.\n *\n * @param clientX - Browser client x coordinate (e.g. from a pointer event)\n * @param clientY - Browser client y coordinate\n *\n * @example\n * vc.addEventListener('pointerdown', (e) => {\n * const { x, y } = vc.clientToContent(e.clientX, e.clientY);\n * placeMarkerAt(x, y);\n * });\n */\n clientToContent(clientX: number, clientY: number) {\n const canvasRect = this._getCanvasClientRect();\n const scaleX = this._getViewportScaleX(canvasRect);\n const scaleY = this._getViewportScaleY(canvasRect);\n\n return Object.freeze({\n x: this._viewRect.x + (clientX - canvasRect.left) * scaleX,\n y: this._viewRect.y + (clientY - canvasRect.top) * scaleY,\n });\n }\n\n /**\n * Converts content coordinates back to browser client coordinates.\n *\n * @param x - Content x coordinate in CSS pixels\n * @param y - Content y coordinate in CSS pixels\n *\n * @example\n * const { x, y } = vc.contentToClient(contentX, contentY);\n * tooltip.style.left = `${x}px`;\n * tooltip.style.top = `${y}px`;\n */\n contentToClient(x: number, y: number) {\n const canvasRect = this._getCanvasClientRect();\n const scaleX = this._getViewportScaleX(canvasRect);\n const scaleY = this._getViewportScaleY(canvasRect);\n\n return Object.freeze({\n x: canvasRect.left + (x - this._viewRect.x) / scaleX,\n y: canvasRect.top + (y - this._viewRect.y) / scaleY,\n });\n }\n\n /**\n * Queues a render event on the next animation frame.\n *\n * Required when `renderMode` is `'manual'`. In other modes the component\n * schedules renders automatically; calling this with reason `'animation-frame'`\n * is a no-op when `renderMode` is `'viewport-change'`.\n *\n * @param reason - Render reason reported in the event detail\n */\n requestRender(reason: RCVirtualCanvasRenderReason = 'manual') {\n this._scheduleRender(reason);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the x-axis.\n *\n * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the x-scale\n * factor in `ctx.scale()` to draw at CSS pixel resolution.\n *\n * @example\n * vc.addEventListener('rc-virtual-canvas-render', ({ detail: { viewRect } }) => {\n * ctx.save();\n * ctx.scale(vc.canvasScaleX, vc.canvasScaleY);\n * drawScene(ctx, viewRect);\n * ctx.restore();\n * });\n */\n get canvasScaleX(): number {\n const canvasRect = this._getCanvasClientRect();\n\n return this._getViewportScaleX(canvasRect);\n }\n\n /**\n * Ratio of canvas backing-store pixels to CSS pixels along the y-axis.\n *\n * Equals `devicePixelRatio` when `autoResizeCanvas` is `true`. Use as the y-scale\n * factor in `ctx.scale()` to draw at CSS pixel resolution.\n */\n get canvasScaleY(): number {\n const canvasRect = this._getCanvasClientRect();\n\n return this._getViewportScaleY(canvasRect);\n }\n\n /** Maps pointer and mouse events to content coordinates and dispatches `rc-virtual-canvas-pointer` */\n protected _onPointerEvent(event: PointerEvent | MouseEvent) {\n if (this._handledPointerEvents.has(event)) {\n return;\n }\n\n if (this._isOverlayEvent(event)) {\n return;\n }\n\n this._handledPointerEvents.add(event);\n\n const contentPoint = this.clientToContent(event.clientX, event.clientY);\n\n const shouldContinue = this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasPointerInit>('rc-virtual-canvas-pointer', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: {\n type: event.type,\n clientX: event.clientX,\n clientY: event.clientY,\n contentX: contentPoint.x,\n contentY: contentPoint.y,\n viewRect: createRectSnapshot(this._viewRect),\n button: event.button,\n buttons: event.buttons,\n altKey: event.altKey,\n ctrlKey: event.ctrlKey,\n shiftKey: event.shiftKey,\n metaKey: event.metaKey,\n sourceEvent: event,\n },\n }),\n );\n\n if (!shouldContinue) {\n event.preventDefault();\n }\n }\n\n protected _isOverlayEvent(event: Event): boolean {\n return event\n .composedPath()\n .some(($node) => $node instanceof HTMLSlotElement && $node.name === 'overlay');\n }\n\n /**\n * RAF callback. Dispatches `rc-virtual-canvas-render` and re-schedules in continuous mode.\n *\n * @param time - High-resolution timestamp from `requestAnimationFrame`\n */\n protected _update(time: DOMHighResTimeStamp) {\n this._rafHandle = 0;\n\n if (!this.isConnected || this._$canvas == null) {\n return;\n }\n\n const reason =\n this._pendingRenderReason ??\n (this.renderMode === 'continuous' ? 'animation-frame' : 'manual');\n\n this._pendingRenderReason = undefined;\n\n this.dispatchEvent(\n new CustomEvent<RCVirtualCanvasRenderInit>('rc-virtual-canvas-render', {\n bubbles: true,\n composed: true,\n detail: {\n time,\n reason,\n viewRect: createRectSnapshot(this._viewRect),\n contentRect: createRectSnapshot(this._contentRect),\n },\n }),\n );\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Registers pointer event listeners and starts rendering in continuous mode */\n override connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('pointerdown', this._boundPointerEvent);\n this.addEventListener('pointermove', this._boundPointerEvent);\n this.addEventListener('pointerup', this._boundPointerEvent);\n this.addEventListener('click', this._boundPointerEvent);\n this.addEventListener('dblclick', this._boundPointerEvent);\n this.addEventListener('contextmenu', this._boundPointerEvent);\n\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n }\n\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n }\n }\n\n /** Cancels any pending animation frame, disconnects the resize observer, and removes pointer listeners */\n override disconnectedCallback() {\n super.disconnectedCallback();\n\n cancelAnimationFrame(this._rafHandle);\n this._rafHandle = 0;\n this._resizeObserver.disconnect();\n\n this.removeEventListener('pointerdown', this._boundPointerEvent);\n this.removeEventListener('pointermove', this._boundPointerEvent);\n this.removeEventListener('pointerup', this._boundPointerEvent);\n this.removeEventListener('click', this._boundPointerEvent);\n this.removeEventListener('dblclick', this._boundPointerEvent);\n this.removeEventListener('contextmenu', this._boundPointerEvent);\n }\n\n /** Reacts to `renderMode`, `autoResizeCanvas`, and `imageRendering` property changes */\n protected override updated(changed: Map<string, unknown>) {\n if (changed.has('renderMode')) {\n if (this.renderMode === 'continuous') {\n this._scheduleRender('animation-frame');\n } else if (this._pendingRenderReason === 'animation-frame') {\n if (this._rafHandle) {\n cancelAnimationFrame(this._rafHandle);\n\n this._rafHandle = 0;\n }\n\n this._pendingRenderReason = undefined;\n } else if (this.renderMode === 'viewport-change') {\n this._scheduleRender('viewport-change');\n }\n }\n\n if (changed.has('autoResizeCanvas')) {\n this._syncCanvasBackingStore();\n }\n\n if (changed.has('imageRendering')) {\n this.style.setProperty('--rc-virtual-canvas-image-rendering', this.imageRendering);\n }\n }\n\n protected _scheduleRender(reason: RCVirtualCanvasRenderReason) {\n if (this.renderMode === 'manual' && reason !== 'manual') {\n return;\n }\n\n if (this.renderMode === 'viewport-change' && reason === 'animation-frame') {\n return;\n }\n\n this._pendingRenderReason = reason;\n\n if (!this.isConnected || this._rafHandle) {\n return;\n }\n\n this._rafHandle = window.requestAnimationFrame(this._boundUpdate);\n }\n\n protected _syncCanvasBackingStore() {\n if (!this.autoResizeCanvas || this._$canvas == null) {\n return;\n }\n\n const width = Math.max(0, Math.round(this._viewRect.width));\n const height = Math.max(0, Math.round(this._viewRect.height));\n\n if (this._$canvas.width !== width) {\n this._$canvas.width = width;\n }\n\n if (this._$canvas.height !== height) {\n this._$canvas.height = height;\n }\n }\n\n protected _getCanvasClientRect() {\n if (this._$canvas == null) {\n return this.getBoundingClientRect();\n }\n\n return this._$canvas.getBoundingClientRect();\n }\n\n protected _getMeasuredCanvasWidth(fallbackWidth: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.width > 0) {\n return this._$canvas.width;\n }\n\n return fallbackWidth;\n }\n\n protected _getMeasuredCanvasHeight(fallbackHeight: number) {\n if (!this.autoResizeCanvas && this._$canvas && this._$canvas.height > 0) {\n return this._$canvas.height;\n }\n\n return fallbackHeight;\n }\n\n protected _getViewportScaleX(canvasRect: DOMRect) {\n return canvasRect.width > 0 ? this._viewRect.width / canvasRect.width : 1;\n }\n\n protected _getViewportScaleY(canvasRect: DOMRect) {\n return canvasRect.height > 0 ? this._viewRect.height / canvasRect.height : 1;\n }\n\n render() {\n return html`\n <div\n id=\"root\"\n part=\"scroller\"\n @scroll=${this._onScroll}\n @pointerdown=${this._onPointerEvent}\n @pointermove=${this._onPointerEvent}\n @pointerup=${this._onPointerEvent}\n @click=${this._onPointerEvent}\n @dblclick=${this._onPointerEvent}\n @contextmenu=${this._onPointerEvent}\n >\n <div id=\"overlay\" part=\"overlay\">\n <slot name=\"overlay\"></slot>\n </div>\n\n <div\n id=\"placeholder\"\n style=${styleMap({\n width: `${this.contentWidth}px`,\n height: `${this.contentHeight}px`,\n })}\n ></div>\n </div>\n\n <slot @slotchange=${this._onSlotChange}></slot>\n `;\n }\n}\n\nexport default RCVirtualCanvas;\n"],"names":["virtualCanvasStyles","css","createRectSnapshot","rect","_RCVirtualCanvas","LitElement","time","event","entries","entry","devicePixelBoxSize","val","oldValue","e","el","$canvas","error","x","y","options","clientX","clientY","canvasRect","scaleX","scaleY","reason","contentPoint","$node","changed","width","height","fallbackWidth","fallbackHeight","html","styleMap","RCVirtualCanvas","__decorateClass","property","query","state"],"mappings":"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"}