@ixfx/components 0.4.2 → 0.4.4
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/bundle/index.d.ts +435 -1193
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +7765 -20670
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.d.ts +12 -7
- package/dist/ac-text.d.ts.map +1 -1
- package/dist/ac-text.js +2 -3
- package/dist/ac-text.js.map +1 -1
- package/dist/{button-C3fLMKUv.js → button-DxYee1ZH.js} +2 -2
- package/dist/{button-C3fLMKUv.js.map → button-DxYee1ZH.js.map} +1 -1
- package/dist/button.d.ts +1 -2
- package/dist/button.d.ts.map +1 -1
- package/dist/button.js +1 -2
- package/dist/checkbox.d.ts +0 -1
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/{colour-picker-0sgAha1T.js → colour-picker-BacNRabo.js} +14 -16
- package/dist/colour-picker-BacNRabo.js.map +1 -0
- package/dist/colour-picker.d.ts +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.d.ts +5 -2
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +45 -20
- package/dist/crumbs.js.map +1 -1
- package/dist/data-display.d.ts +1 -2
- package/dist/data-display.d.ts.map +1 -1
- package/dist/data-display.js +25 -23
- package/dist/data-display.js.map +1 -1
- package/dist/{data-provider-DgI909FP.js → data-provider-35TyWclX.js} +2 -2
- package/dist/data-provider-35TyWclX.js.map +1 -0
- package/dist/{decorate-DdjvVHS-.js → decorate-VRK8rslU.js} +2 -2
- package/dist/{decorate-DdjvVHS-.js.map → decorate-VRK8rslU.js.map} +1 -1
- package/dist/editable-label.d.ts +1 -2
- package/dist/editable-label.d.ts.map +1 -1
- package/dist/editable-label.js +1 -1
- package/dist/editable-label.js.map +1 -1
- package/dist/{hex-editor-WZrjRtvL.js → hex-editor-Bk6rxhfg.js} +9 -11
- package/dist/hex-editor-Bk6rxhfg.js.map +1 -0
- package/dist/{hex-editor-CMIxtNgT.d.ts → hex-editor-Caq8vNQk.d.ts} +2 -3
- package/dist/hex-editor-Caq8vNQk.d.ts.map +1 -0
- package/dist/hex.d.ts +1 -1
- package/dist/hex.js +1 -1
- package/dist/highlight-B-eQrhhb.js.map +1 -1
- package/dist/{icon-Ndo40kNO.js → icon-B22XVlCt.js} +6 -4
- package/dist/{icon-Ndo40kNO.js.map → icon-B22XVlCt.js.map} +1 -1
- package/dist/{icon-epZd-JIO.d.ts → icon-DpA9x2Ve.d.ts} +3 -4
- package/dist/icon-DpA9x2Ve.d.ts.map +1 -0
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +1 -1
- package/dist/{incr-search-CeERfijK.js → incr-search-2pz21xtR.js} +9 -6
- package/dist/incr-search-2pz21xtR.js.map +1 -0
- package/dist/incr-search.d.ts +1 -1
- package/dist/incr-search.js +1 -1
- package/dist/{index-CowKi2mo.d.ts → index-BeuCXtiO.d.ts} +3 -4
- package/dist/index-BeuCXtiO.d.ts.map +1 -0
- package/dist/{index-D87kRcEs.d.ts → index-BtGFYfaK.d.ts} +2 -1
- package/dist/index-BtGFYfaK.d.ts.map +1 -0
- package/dist/{index-JuEVfmr-.d.ts → index-CoqtMSd9.d.ts} +6 -4
- package/dist/index-CoqtMSd9.d.ts.map +1 -0
- package/dist/{index-9fGVAg1d.d.ts → index-Cxwxtj6g.d.ts} +3 -3
- package/dist/index-Cxwxtj6g.d.ts.map +1 -0
- package/dist/index-D_ftz_IT.d.ts +184 -0
- package/dist/index-D_ftz_IT.d.ts.map +1 -0
- package/dist/{index-_RTQSKHi.d.ts → index-DfEkTGvT.d.ts} +11 -11
- package/dist/index-DfEkTGvT.d.ts.map +1 -0
- package/dist/index.d.ts +45 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +304 -3075
- package/dist/index.js.map +1 -1
- package/dist/keyboard-B5xD7Fz-.js +36 -0
- package/dist/keyboard-B5xD7Fz-.js.map +1 -0
- package/dist/{labelled-input-base-Cz6qE6Dk.d.ts → labelled-input-base-DiTme1JO.d.ts} +2 -3
- package/dist/labelled-input-base-DiTme1JO.d.ts.map +1 -0
- package/dist/{labelled-input-base-9K_w3oLj.js → labelled-input-base-hoKGwyKT.js} +2 -2
- package/dist/{labelled-input-base-9K_w3oLj.js.map → labelled-input-base-hoKGwyKT.js.map} +1 -1
- package/dist/labelled-radial-input.d.ts +6 -5
- package/dist/labelled-radial-input.d.ts.map +1 -1
- package/dist/labelled-radial-input.js +7 -3
- package/dist/labelled-radial-input.js.map +1 -1
- package/dist/labelled-range-input.d.ts +1 -1
- package/dist/labelled-range-input.js +27 -3
- package/dist/labelled-range-input.js.map +1 -1
- package/dist/led.d.ts +1 -2
- package/dist/led.d.ts.map +1 -1
- package/dist/led.js +1 -1
- package/dist/led.js.map +1 -1
- package/dist/{menu-vjoiHZ13.js → menu-g6yd7ddN.js} +8 -9
- package/dist/menu-g6yd7ddN.js.map +1 -0
- package/dist/{menu-item-COx-Azgj.d.ts → menu-item-DSyf9f_L.d.ts} +4 -4
- package/dist/menu-item-DSyf9f_L.d.ts.map +1 -0
- package/dist/{menu-item-BrIuORYD.js → menu-item-NUKwJ4s5.js} +3 -4
- package/dist/{menu-item-BrIuORYD.js.map → menu-item-NUKwJ4s5.js.map} +1 -1
- package/dist/menu.d.ts +2 -2
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +8 -5
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +22 -24
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.d.ts +7 -3
- package/dist/narrowed-text.d.ts.map +1 -1
- package/dist/narrowed-text.js +73 -47
- package/dist/narrowed-text.js.map +1 -1
- package/dist/panel.d.ts +1 -1
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +2 -2
- package/dist/panel.js.map +1 -1
- package/dist/plots.d.ts +2 -2
- package/dist/plots.js +1 -1
- package/dist/polar-pad.d.ts +15 -3
- package/dist/polar-pad.d.ts.map +1 -1
- package/dist/polar-pad.js +64 -11
- package/dist/polar-pad.js.map +1 -1
- package/dist/{radial-input-CpQPs1Mp.d.ts → radial-input-DXMN55Nz.d.ts} +6 -4
- package/dist/radial-input-DXMN55Nz.d.ts.map +1 -0
- package/dist/{radial-input-DZ7eQCcM.js → radial-input-DxCrt_NE.js} +41 -19
- package/dist/radial-input-DxCrt_NE.js.map +1 -0
- package/dist/radial-input.d.ts +1 -1
- package/dist/radial-input.js +1 -1
- package/dist/range-input.d.ts +15 -4
- package/dist/range-input.d.ts.map +1 -1
- package/dist/range-input.js +23 -2
- package/dist/range-input.js.map +1 -1
- package/dist/range.d.ts +15 -4
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +23 -2
- package/dist/range.js.map +1 -1
- package/dist/selecthorizontal.d.ts +1 -2
- package/dist/selecthorizontal.d.ts.map +1 -1
- package/dist/selecthorizontal.js +1 -1
- package/dist/selecthorizontal.js.map +1 -1
- package/dist/slider-input-DFpG23bS.js +1592 -0
- package/dist/slider-input-DFpG23bS.js.map +1 -0
- package/dist/slider-input-XppH3vcy.d.ts +160 -0
- package/dist/slider-input-XppH3vcy.d.ts.map +1 -0
- package/dist/slider-input.d.ts +2 -0
- package/dist/slider-input.js +2 -0
- package/dist/snap-container.d.ts +1 -2
- package/dist/snap-container.d.ts.map +1 -1
- package/dist/snap-container.js +6 -5
- package/dist/snap-container.js.map +1 -1
- package/dist/split-layout.d.ts +1 -2
- package/dist/split-layout.d.ts.map +1 -1
- package/dist/split-layout.js +6 -4
- package/dist/split-layout.js.map +1 -1
- package/dist/swipe.d.ts +12 -2
- package/dist/swipe.d.ts.map +1 -1
- package/dist/swipe.js +22 -3
- package/dist/swipe.js.map +1 -1
- package/dist/{tab-list-DLzb-m-I.d.ts → tab-list-BohmbvqF.d.ts} +14 -5
- package/dist/tab-list-BohmbvqF.d.ts.map +1 -0
- package/dist/tab-list-DzknpdSo.js +592 -0
- package/dist/tab-list-DzknpdSo.js.map +1 -0
- package/dist/tabs.d.ts +2 -2
- package/dist/tabs.js +1 -208
- package/dist/{tickled-controller-BjYCzGrU.d.ts → tickled-controller-BF2Ea0DE.d.ts} +2 -31
- package/dist/tickled-controller-BF2Ea0DE.d.ts.map +1 -0
- package/dist/tickled-styles-fNDdqf6l.js.map +1 -1
- package/dist/{timeline-2OFtN4Ta.js → timeline-B2fgDL4U.js} +37 -1438
- package/dist/timeline-B2fgDL4U.js.map +1 -0
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/{tooltip-RGVIwHrZ.d.ts → tooltip-BlvBUQxx.d.ts} +3 -3
- package/dist/tooltip-BlvBUQxx.d.ts.map +1 -0
- package/dist/{tree-D84RUgFC.js → tree-BnvzhsAw.js} +8 -9
- package/dist/tree-BnvzhsAw.js.map +1 -0
- package/dist/{tree-component-BaCSPWg1.d.ts → tree-component-DCmmKZ4j.d.ts} +8 -124
- package/dist/tree-component-DCmmKZ4j.d.ts.map +1 -0
- package/dist/tree.d.ts +10 -4
- package/dist/tree.d.ts.map +1 -1
- package/dist/tree.js +1 -1
- package/dist/types-DO3gt5vg.d.ts +130 -0
- package/dist/types-DO3gt5vg.d.ts.map +1 -0
- package/dist/wheel-nudge-BlSCe_hD.js +86 -0
- package/dist/wheel-nudge-BlSCe_hD.js.map +1 -0
- package/dist/wheel-nudge-DGrNzWuE.d.ts +29 -0
- package/dist/wheel-nudge-DGrNzWuE.d.ts.map +1 -0
- package/dist/{xy-axis-CEI7ojks.d.ts → xy-axis-5KhVTNoX.d.ts} +75 -29
- package/dist/xy-axis-5KhVTNoX.d.ts.map +1 -0
- package/dist/xy-axis-CxHC8z5E.js +1849 -0
- package/dist/xy-axis-CxHC8z5E.js.map +1 -0
- package/dist/xy-pad.d.ts +13 -2
- package/dist/xy-pad.d.ts.map +1 -1
- package/dist/xy-pad.js +47 -6
- package/dist/xy-pad.js.map +1 -1
- package/docs-user/radial-input.md +2 -2
- package/package.json +22 -21
- package/dist/colour-C3MQIjFJ-vRCdr8W-.js +0 -3732
- package/dist/colour-C3MQIjFJ-vRCdr8W-.js.map +0 -1
- package/dist/colour-picker-0sgAha1T.js.map +0 -1
- package/dist/data-provider-DgI909FP.js.map +0 -1
- package/dist/dist-CA13FvMn.js +0 -980
- package/dist/dist-CA13FvMn.js.map +0 -1
- package/dist/hex-editor-CMIxtNgT.d.ts.map +0 -1
- package/dist/hex-editor-WZrjRtvL.js.map +0 -1
- package/dist/icon-epZd-JIO.d.ts.map +0 -1
- package/dist/incr-search-CeERfijK.js.map +0 -1
- package/dist/index-9fGVAg1d.d.ts.map +0 -1
- package/dist/index-CowKi2mo.d.ts.map +0 -1
- package/dist/index-D87kRcEs.d.ts.map +0 -1
- package/dist/index-DgXpCg_G.d.ts +0 -1244
- package/dist/index-DgXpCg_G.d.ts.map +0 -1
- package/dist/index-JuEVfmr-.d.ts.map +0 -1
- package/dist/index-_RTQSKHi.d.ts.map +0 -1
- package/dist/keyboard-CimiEskD.js +0 -20
- package/dist/keyboard-CimiEskD.js.map +0 -1
- package/dist/labelled-input-base-Cz6qE6Dk.d.ts.map +0 -1
- package/dist/menu-item-COx-Azgj.d.ts.map +0 -1
- package/dist/menu-vjoiHZ13.js.map +0 -1
- package/dist/radial-input-CpQPs1Mp.d.ts.map +0 -1
- package/dist/radial-input-DZ7eQCcM.js.map +0 -1
- package/dist/tab-list-DLzb-m-I.d.ts.map +0 -1
- package/dist/tabs.js.map +0 -1
- package/dist/tickled-controller-BjYCzGrU.d.ts.map +0 -1
- package/dist/timeline-2OFtN4Ta.js.map +0 -1
- package/dist/tooltip-RGVIwHrZ.d.ts.map +0 -1
- package/dist/tree-D84RUgFC.js.map +0 -1
- package/dist/tree-component-BaCSPWg1.d.ts.map +0 -1
- package/dist/types-DSfbtHs3.d.ts +0 -8
- package/dist/types-DSfbtHs3.d.ts.map +0 -1
- package/dist/xy-axis-CEI7ojks.d.ts.map +0 -1
- package/dist/xy-axis-DbPezP6A.js +0 -7849
- package/dist/xy-axis-DbPezP6A.js.map +0 -1
- /package/bundle/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
- /package/dist/{chunk-D7D4PA-g.js → rolldown-runtime-D7D4PA-g.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { n as safeCustomElement, t as __decorate
|
|
1
|
+
import { n as safeCustomElement, t as __decorate } from "./decorate-VRK8rslU.js";
|
|
2
2
|
import { LitElement, css, html, nothing } from "lit";
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { property, state } from "lit/decorators.js";
|
|
4
|
+
import "@clinth/vcanvas";
|
|
5
5
|
//#region src/timeline/timeline-controller.ts
|
|
6
6
|
/**
|
|
7
7
|
* External adapter class that can configure a timeline element
|
|
@@ -256,7 +256,7 @@ function drawEventRects(ctx, region, events, trackLayout, selectedIds, tickledId
|
|
|
256
256
|
const x = evt.start * ppu;
|
|
257
257
|
const w = (evt.end - evt.start) * ppu;
|
|
258
258
|
const y = layout.y + padding;
|
|
259
|
-
const h = layout.height -
|
|
259
|
+
const h = layout.height - 6;
|
|
260
260
|
if (w < 1) continue;
|
|
261
261
|
const isSelected = selectedIds.has(evt.id);
|
|
262
262
|
const isTickled = tickledId === evt.id;
|
|
@@ -992,1425 +992,24 @@ let TimelineTrackTabElement = class TimelineTrackTabElement extends LitElement {
|
|
|
992
992
|
this.style.cursor = ``;
|
|
993
993
|
}
|
|
994
994
|
};
|
|
995
|
-
__decorate
|
|
996
|
-
__decorate
|
|
995
|
+
__decorate([property({ type: String })], TimelineTrackTabElement.prototype, "label", void 0);
|
|
996
|
+
__decorate([property({
|
|
997
997
|
type: String,
|
|
998
998
|
attribute: `track-key`
|
|
999
999
|
})], TimelineTrackTabElement.prototype, "trackKey", void 0);
|
|
1000
|
-
__decorate
|
|
1000
|
+
__decorate([property({
|
|
1001
1001
|
type: Boolean,
|
|
1002
1002
|
reflect: true
|
|
1003
1003
|
})], TimelineTrackTabElement.prototype, "selected", void 0);
|
|
1004
|
-
__decorate
|
|
1004
|
+
__decorate([property({
|
|
1005
1005
|
type: Boolean,
|
|
1006
1006
|
reflect: true
|
|
1007
1007
|
})], TimelineTrackTabElement.prototype, "reorderable", void 0);
|
|
1008
|
-
__decorate
|
|
1008
|
+
__decorate([property({
|
|
1009
1009
|
type: Boolean,
|
|
1010
1010
|
reflect: true
|
|
1011
1011
|
})], TimelineTrackTabElement.prototype, "resizable", void 0);
|
|
1012
|
-
TimelineTrackTabElement = __decorate
|
|
1013
|
-
//#endregion
|
|
1014
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/convert.js
|
|
1015
|
-
/**
|
|
1016
|
-
* Converts viewport-relative coordinates to canvas-relative (logical) coordinates.
|
|
1017
|
-
*
|
|
1018
|
-
* This function accounts for the current scroll position and content offset to translate
|
|
1019
|
-
* coordinates from the visible viewport space to the logical canvas space.
|
|
1020
|
-
*
|
|
1021
|
-
* @param x - The x-coordinate in viewport space (pixels from left edge of viewport)
|
|
1022
|
-
* @param y - The y-coordinate in viewport space (pixels from top)
|
|
1023
|
-
* @param scrollLeft - The current horizontal scroll position in pixels
|
|
1024
|
-
* @param contentOffset - The horizontal offset applied to center content in single-tile mode
|
|
1025
|
-
* @param scrollTop - The current vertical scroll position in pixels
|
|
1026
|
-
* @param contentOffsetY - The vertical offset applied to center content in single-tile-row mode
|
|
1027
|
-
* @returns The point in canvas (logical) coordinate space
|
|
1028
|
-
*
|
|
1029
|
-
* @example
|
|
1030
|
-
* ```typescript
|
|
1031
|
-
* // Viewport coordinate (100, 50) with scroll at 500 and no offset
|
|
1032
|
-
* const canvasPoint = viewportToCanvas(100, 50, 500, 0, 0, 0);
|
|
1033
|
-
* // Returns: { x: 600, y: 50 }
|
|
1034
|
-
* ```
|
|
1035
|
-
*/
|
|
1036
|
-
function viewportToCanvas(x, y, scrollLeft, contentOffset, scrollTop = 0, contentOffsetY = 0) {
|
|
1037
|
-
return {
|
|
1038
|
-
x: x + scrollLeft - contentOffset,
|
|
1039
|
-
y: y + scrollTop - contentOffsetY
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
/**
|
|
1043
|
-
* Converts canvas-relative (logical) coordinates to viewport-relative coordinates.
|
|
1044
|
-
*
|
|
1045
|
-
* This function translates coordinates from the logical canvas space back to the
|
|
1046
|
-
* visible viewport space, accounting for scroll position and content offset.
|
|
1047
|
-
*
|
|
1048
|
-
* @param x - The x-coordinate in canvas (logical) space
|
|
1049
|
-
* @param y - The y-coordinate in canvas (logical) space
|
|
1050
|
-
* @param scrollLeft - The current horizontal scroll position in pixels
|
|
1051
|
-
* @param contentOffset - The horizontal offset applied to center content in single-tile mode
|
|
1052
|
-
* @param scrollTop - The current vertical scroll position in pixels
|
|
1053
|
-
* @param contentOffsetY - The vertical offset applied to center content in single-tile-row mode
|
|
1054
|
-
* @returns The point in viewport coordinate space
|
|
1055
|
-
*
|
|
1056
|
-
* @example
|
|
1057
|
-
* ```typescript
|
|
1058
|
-
* // Canvas coordinate (600, 50) with scroll at 500 and no offset
|
|
1059
|
-
* const viewportPoint = canvasToViewport(600, 50, 500, 0, 0, 0);
|
|
1060
|
-
* // Returns: { x: 100, y: 50 }
|
|
1061
|
-
* ```
|
|
1062
|
-
*/
|
|
1063
|
-
function canvasToViewport(x, y, scrollLeft, contentOffset, scrollTop = 0, contentOffsetY = 0) {
|
|
1064
|
-
return {
|
|
1065
|
-
x: x - scrollLeft + contentOffset,
|
|
1066
|
-
y: y - scrollTop + contentOffsetY
|
|
1067
|
-
};
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* Clamps a numeric value between a minimum and maximum bound.
|
|
1071
|
-
*
|
|
1072
|
-
* This is a utility function to constrain values within a valid range.
|
|
1073
|
-
*
|
|
1074
|
-
* @param value - The value to clamp
|
|
1075
|
-
* @param min - The minimum allowed value
|
|
1076
|
-
* @param max - The maximum allowed value
|
|
1077
|
-
* @returns The clamped value, guaranteed to be between min and max (inclusive)
|
|
1078
|
-
*
|
|
1079
|
-
* @example
|
|
1080
|
-
* ```typescript
|
|
1081
|
-
* clamp(15, 0, 10); // Returns: 10
|
|
1082
|
-
* clamp(-5, 0, 10); // Returns: 0
|
|
1083
|
-
* clamp(5, 0, 10); // Returns: 5
|
|
1084
|
-
* ```
|
|
1085
|
-
*/
|
|
1086
|
-
function clamp(value, min, max) {
|
|
1087
|
-
return Math.max(min, Math.min(value, max));
|
|
1088
|
-
}
|
|
1089
|
-
//#endregion
|
|
1090
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/styles.js
|
|
1091
|
-
/**
|
|
1092
|
-
* CSS styles for the VCanvas component.
|
|
1093
|
-
*
|
|
1094
|
-
* These styles define the layout and positioning of:
|
|
1095
|
-
* - The host element (`:host`)
|
|
1096
|
-
* - The scroll container (`.scroll-container`)
|
|
1097
|
-
* - The content spacer (`.spacer`)
|
|
1098
|
-
* - The tile pool container (`.tile-pool`)
|
|
1099
|
-
* - Canvas elements
|
|
1100
|
-
* - The children container for slotted elements (`.children-container`)
|
|
1101
|
-
*
|
|
1102
|
-
* The styles use absolute positioning to create a virtualized scrolling experience
|
|
1103
|
-
* where tiles are rendered only when visible in the viewport.
|
|
1104
|
-
*
|
|
1105
|
-
* @example
|
|
1106
|
-
* ```typescript
|
|
1107
|
-
* import { vcanvasStyles } from '@clinth/vcanvas';
|
|
1108
|
-
*
|
|
1109
|
-
* // Styles are automatically applied when using the VCanvas component
|
|
1110
|
-
* // You typically don't need to use these directly unless extending the component
|
|
1111
|
-
* ```
|
|
1112
|
-
*/
|
|
1113
|
-
const vcanvasStyles = css`
|
|
1114
|
-
:host {
|
|
1115
|
-
display: block;
|
|
1116
|
-
position: relative;
|
|
1117
|
-
overflow: hidden;
|
|
1118
|
-
}
|
|
1119
|
-
|
|
1120
|
-
.scroll-container {
|
|
1121
|
-
overflow-x: auto;
|
|
1122
|
-
overflow-y: clip;
|
|
1123
|
-
width: 100%;
|
|
1124
|
-
height: 100%;
|
|
1125
|
-
position: relative;
|
|
1126
|
-
touch-action: pan-x;
|
|
1127
|
-
scrollbar-width: var(--scrollbar-width, auto);
|
|
1128
|
-
scrollbar-color: var(--scrollbar-color, auto);
|
|
1129
|
-
}
|
|
1130
|
-
|
|
1131
|
-
.scroll-container.vertical {
|
|
1132
|
-
overflow-y: auto;
|
|
1133
|
-
touch-action: pan-x pan-y;
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
.spacer {
|
|
1137
|
-
position: absolute;
|
|
1138
|
-
left: 0;
|
|
1139
|
-
top: 0;
|
|
1140
|
-
pointer-events: none;
|
|
1141
|
-
z-index: -1;
|
|
1142
|
-
}
|
|
1143
|
-
|
|
1144
|
-
.tile-pool {
|
|
1145
|
-
position: absolute;
|
|
1146
|
-
top: 0;
|
|
1147
|
-
left: 0;
|
|
1148
|
-
height: 100%;
|
|
1149
|
-
width: 100%;
|
|
1150
|
-
pointer-events: none;
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
|
-
canvas {
|
|
1154
|
-
position: absolute;
|
|
1155
|
-
top: 0;
|
|
1156
|
-
pointer-events: auto;
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
.children-container {
|
|
1160
|
-
position: absolute;
|
|
1161
|
-
top: 0;
|
|
1162
|
-
height: 100%;
|
|
1163
|
-
left: 0;
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
@property --left-fade {
|
|
1167
|
-
syntax: "<length>";
|
|
1168
|
-
inherits: false;
|
|
1169
|
-
initial-value: 0;
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
@property --right-fade {
|
|
1173
|
-
syntax: "<length>";
|
|
1174
|
-
inherits: false;
|
|
1175
|
-
initial-value: 0;
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
@keyframes scrollfade {
|
|
1179
|
-
0% {
|
|
1180
|
-
--left-fade: 0;
|
|
1181
|
-
}
|
|
1182
|
-
10%,
|
|
1183
|
-
100% {
|
|
1184
|
-
--left-fade: 3rem;
|
|
1185
|
-
}
|
|
1186
|
-
0%,
|
|
1187
|
-
90% {
|
|
1188
|
-
--right-fade: 3rem;
|
|
1189
|
-
}
|
|
1190
|
-
100% {
|
|
1191
|
-
--right-fade: 0;
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
.scrollable {
|
|
1196
|
-
mask: linear-gradient(to right, #0000, #ffff var(--left-fade) calc(100% - var(--right-fade)), #0000);
|
|
1197
|
-
animation: scrollfade;
|
|
1198
|
-
animation-timeline: --scrollfade;
|
|
1199
|
-
scroll-timeline: --scrollfade x;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
`;
|
|
1203
|
-
//#endregion
|
|
1204
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/tile-calculator.js
|
|
1205
|
-
/**
|
|
1206
|
-
* Calculates the width of a tile based on viewport width and multiplier.
|
|
1207
|
-
*
|
|
1208
|
-
* @param viewportWidth - The width of the viewport in pixels
|
|
1209
|
-
* @param multiplier - The multiplier to apply (typically 0.25 to 1.0)
|
|
1210
|
-
* @returns The calculated tile width in pixels
|
|
1211
|
-
*
|
|
1212
|
-
* @example
|
|
1213
|
-
* ```typescript
|
|
1214
|
-
* getTileWidth(1000, 0.5); // Returns: 500
|
|
1215
|
-
* ```
|
|
1216
|
-
*/
|
|
1217
|
-
function getTileWidth(viewportWidth, multiplier) {
|
|
1218
|
-
return viewportWidth * multiplier;
|
|
1219
|
-
}
|
|
1220
|
-
/**
|
|
1221
|
-
* Determines if the content fits within a single tile (single-tile mode).
|
|
1222
|
-
*
|
|
1223
|
-
* In single-tile mode, the content is centered in the viewport rather than
|
|
1224
|
-
* being scrollable. This also returns true when viewport width is 0 as a
|
|
1225
|
-
* defensive edge case.
|
|
1226
|
-
*
|
|
1227
|
-
* @param logicalWidth - The total logical width of the content
|
|
1228
|
-
* @param viewportWidth - The width of the viewport in pixels
|
|
1229
|
-
* @returns `true` if content fits in single tile, `false` otherwise
|
|
1230
|
-
*
|
|
1231
|
-
* @example
|
|
1232
|
-
* ```typescript
|
|
1233
|
-
* isSingleTileMode(500, 1000); // Returns: true
|
|
1234
|
-
* isSingleTileMode(1500, 1000); // Returns: false
|
|
1235
|
-
* ```
|
|
1236
|
-
*/
|
|
1237
|
-
function isSingleTileMode(logicalWidth, viewportWidth) {
|
|
1238
|
-
if (viewportWidth === 0) return true;
|
|
1239
|
-
return logicalWidth <= viewportWidth;
|
|
1240
|
-
}
|
|
1241
|
-
/**
|
|
1242
|
-
* Calculates the horizontal offset to center content in single-tile mode.
|
|
1243
|
-
*
|
|
1244
|
-
* In multi-tile mode (when content exceeds viewport), this returns 0.
|
|
1245
|
-
* In single-tile mode, this calculates the offset needed to center the content.
|
|
1246
|
-
*
|
|
1247
|
-
* @param logicalWidth - The total logical width of the content
|
|
1248
|
-
* @param viewportWidth - The width of the viewport in pixels
|
|
1249
|
-
* @returns The horizontal offset in pixels, or 0 in multi-tile mode
|
|
1250
|
-
*
|
|
1251
|
-
* @example
|
|
1252
|
-
* ```typescript
|
|
1253
|
-
* // Content width 500 in viewport 1000: center it with 250px offset
|
|
1254
|
-
* getContentOffset(500, 1000); // Returns: 250
|
|
1255
|
-
*
|
|
1256
|
-
* // Content width 2000 in viewport 1000: no offset needed
|
|
1257
|
-
* getContentOffset(2000, 1000); // Returns: 0
|
|
1258
|
-
* ```
|
|
1259
|
-
*/
|
|
1260
|
-
function getContentOffset(logicalWidth, viewportWidth) {
|
|
1261
|
-
if (logicalWidth < 0 || viewportWidth === 0) return 0;
|
|
1262
|
-
return isSingleTileMode(logicalWidth, viewportWidth) ? (viewportWidth - logicalWidth) / 2 : 0;
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
* Calculates the clipped width of a tile at a specific logical position.
|
|
1266
|
-
*
|
|
1267
|
-
* This accounts for:
|
|
1268
|
-
* - Single-tile mode (returns logicalWidth)
|
|
1269
|
-
* - Content boundaries (clips tiles extending beyond content)
|
|
1270
|
-
* - Overscroll area (if enabled)
|
|
1271
|
-
*
|
|
1272
|
-
* @param logicalX - The x-coordinate of the tile's left edge in logical space
|
|
1273
|
-
* @param tileWidth - The full width of the tile
|
|
1274
|
-
* @param logicalWidth - The total logical width of the content
|
|
1275
|
-
* @param viewportWidth - The width of the viewport in pixels
|
|
1276
|
-
* @param overscrollMultiplier - Multiplier for overscroll padding
|
|
1277
|
-
* @returns The clipped width of the tile (may be 0 if tile is outside valid area)
|
|
1278
|
-
*
|
|
1279
|
-
* @example
|
|
1280
|
-
* ```typescript
|
|
1281
|
-
* // Standard tile within bounds
|
|
1282
|
-
* getTileClippedWidth(0, 500, 2000, 1000, 1); // Returns: 500
|
|
1283
|
-
*
|
|
1284
|
-
* // Tile at end of content that needs clipping
|
|
1285
|
-
* getTileClippedWidth(2950, 500, 2000, 1000, 1); // Returns: 50
|
|
1286
|
-
* ```
|
|
1287
|
-
*/
|
|
1288
|
-
function getTileClippedWidth(logicalX, tileWidth, logicalWidth, viewportWidth, overscrollMultiplier) {
|
|
1289
|
-
if (tileWidth === 0) return 0;
|
|
1290
|
-
if (logicalX < 0) return 0;
|
|
1291
|
-
const maxLogicalX = logicalWidth + viewportWidth * overscrollMultiplier;
|
|
1292
|
-
if (logicalX >= maxLogicalX) return 0;
|
|
1293
|
-
if (isSingleTileMode(logicalWidth, viewportWidth)) return logicalWidth;
|
|
1294
|
-
if (logicalX + tileWidth > maxLogicalX) return Math.max(0, maxLogicalX - logicalX);
|
|
1295
|
-
return tileWidth;
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Calculates the range of tiles needed to render the current viewport.
|
|
1299
|
-
*
|
|
1300
|
-
* This determines which tiles are visible based on scroll position and
|
|
1301
|
-
* includes buffer tiles for smooth scrolling. Respects maxPoolSize limits.
|
|
1302
|
-
*
|
|
1303
|
-
* @param scrollLeft - The current horizontal scroll position in pixels
|
|
1304
|
-
* @param viewportWidth - The width of the viewport in pixels
|
|
1305
|
-
* @param logicalWidth - The total logical width of the content
|
|
1306
|
-
* @param options - Configuration options for tile calculation
|
|
1307
|
-
* @returns Information about the tile range including indices and positions
|
|
1308
|
-
*
|
|
1309
|
-
* @example
|
|
1310
|
-
* ```typescript
|
|
1311
|
-
* const options = {
|
|
1312
|
-
* tileWidthMultiplier: 0.5,
|
|
1313
|
-
* tilesBuffer: 2,
|
|
1314
|
-
* maxPoolSize: 5,
|
|
1315
|
-
* // ... other options
|
|
1316
|
-
* };
|
|
1317
|
-
* const result = calculateTileRange(600, 1000, 10000, options);
|
|
1318
|
-
* // Returns: { firstTile: 1, lastTile: 3, tiles: [...] }
|
|
1319
|
-
* ```
|
|
1320
|
-
*/
|
|
1321
|
-
function calculateTileRange(scrollLeft, viewportWidth, logicalWidth, options) {
|
|
1322
|
-
if (logicalWidth === 0) return {
|
|
1323
|
-
firstTile: 0,
|
|
1324
|
-
lastTile: 0,
|
|
1325
|
-
tiles: []
|
|
1326
|
-
};
|
|
1327
|
-
const tileWidth = getTileWidth(viewportWidth, options.tileWidthMultiplier);
|
|
1328
|
-
if (isSingleTileMode(logicalWidth, viewportWidth)) return {
|
|
1329
|
-
firstTile: 0,
|
|
1330
|
-
lastTile: 0,
|
|
1331
|
-
tiles: [{
|
|
1332
|
-
index: 0,
|
|
1333
|
-
logicalX: 0
|
|
1334
|
-
}]
|
|
1335
|
-
};
|
|
1336
|
-
const firstTile = Math.floor(scrollLeft / tileWidth);
|
|
1337
|
-
const lastTile = Math.floor((scrollLeft + viewportWidth - 1) / tileWidth);
|
|
1338
|
-
const maxTileIndex = Math.max(0, Math.ceil(logicalWidth / tileWidth) - 1);
|
|
1339
|
-
const tiles = [];
|
|
1340
|
-
const startI = firstTile;
|
|
1341
|
-
const endI = Math.min(lastTile + options.tilesBuffer, maxTileIndex);
|
|
1342
|
-
for (let i = startI; i <= endI; i++) {
|
|
1343
|
-
const logicalX = i * tileWidth;
|
|
1344
|
-
if (logicalX >= logicalWidth) continue;
|
|
1345
|
-
tiles.push({
|
|
1346
|
-
index: i,
|
|
1347
|
-
logicalX
|
|
1348
|
-
});
|
|
1349
|
-
if (tiles.length >= options.maxPoolSize) break;
|
|
1350
|
-
}
|
|
1351
|
-
return {
|
|
1352
|
-
firstTile: Math.max(0, firstTile),
|
|
1353
|
-
lastTile: tiles.length > 0 ? tiles[tiles.length - 1].index : 0,
|
|
1354
|
-
tiles
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
/**
|
|
1358
|
-
* Calculates the height of a tile based on viewport height and multiplier.
|
|
1359
|
-
*/
|
|
1360
|
-
function getTileHeight(viewportHeight, multiplier) {
|
|
1361
|
-
return viewportHeight * multiplier;
|
|
1362
|
-
}
|
|
1363
|
-
/**
|
|
1364
|
-
* Determines if content fits within a single tile row (no vertical virtualization needed).
|
|
1365
|
-
* Returns true when effectiveLogicalHeight fits within the viewport.
|
|
1366
|
-
*/
|
|
1367
|
-
function isSingleTileModeY(effectiveLogicalHeight, viewportHeight) {
|
|
1368
|
-
if (viewportHeight === 0) return true;
|
|
1369
|
-
return effectiveLogicalHeight <= viewportHeight;
|
|
1370
|
-
}
|
|
1371
|
-
/**
|
|
1372
|
-
* Calculates the vertical offset to center content in single-tile-row mode.
|
|
1373
|
-
*/
|
|
1374
|
-
function getContentOffsetY(effectiveLogicalHeight, viewportHeight) {
|
|
1375
|
-
if (effectiveLogicalHeight < 0 || viewportHeight === 0) return 0;
|
|
1376
|
-
return isSingleTileModeY(effectiveLogicalHeight, viewportHeight) ? (viewportHeight - effectiveLogicalHeight) / 2 : 0;
|
|
1377
|
-
}
|
|
1378
|
-
/**
|
|
1379
|
-
* Calculates the clipped height of a tile at a specific logical Y position.
|
|
1380
|
-
*/
|
|
1381
|
-
function getTileClippedHeight(logicalY, tileHeight, effectiveLogicalHeight, viewportHeight, overscrollMultiplier) {
|
|
1382
|
-
if (tileHeight === 0) return 0;
|
|
1383
|
-
if (logicalY < 0) return 0;
|
|
1384
|
-
const maxLogicalY = effectiveLogicalHeight + viewportHeight * overscrollMultiplier;
|
|
1385
|
-
if (logicalY >= maxLogicalY) return 0;
|
|
1386
|
-
if (isSingleTileModeY(effectiveLogicalHeight, viewportHeight)) return effectiveLogicalHeight;
|
|
1387
|
-
if (logicalY + tileHeight > maxLogicalY) return Math.max(0, maxLogicalY - logicalY);
|
|
1388
|
-
return tileHeight;
|
|
1389
|
-
}
|
|
1390
|
-
/**
|
|
1391
|
-
* Calculates the range of tile rows needed to render the current viewport vertically.
|
|
1392
|
-
*
|
|
1393
|
-
* @param scrollTop - The current vertical scroll position in pixels
|
|
1394
|
-
* @param viewportHeight - The height of the viewport in pixels
|
|
1395
|
-
* @param effectiveLogicalHeight - The effective total logical height (logicalHeight || viewportHeight)
|
|
1396
|
-
* @param options - Configuration options for tile calculation
|
|
1397
|
-
*/
|
|
1398
|
-
function calculateTileRowRange(scrollTop, viewportHeight, effectiveLogicalHeight, options) {
|
|
1399
|
-
if (effectiveLogicalHeight === 0) return {
|
|
1400
|
-
firstRow: 0,
|
|
1401
|
-
lastRow: 0,
|
|
1402
|
-
rows: []
|
|
1403
|
-
};
|
|
1404
|
-
const tileHeight = getTileHeight(viewportHeight, options.tileHeightMultiplier);
|
|
1405
|
-
if (isSingleTileModeY(effectiveLogicalHeight, viewportHeight)) return {
|
|
1406
|
-
firstRow: 0,
|
|
1407
|
-
lastRow: 0,
|
|
1408
|
-
rows: [{
|
|
1409
|
-
row: 0,
|
|
1410
|
-
logicalY: 0
|
|
1411
|
-
}]
|
|
1412
|
-
};
|
|
1413
|
-
const firstRow = Math.floor(scrollTop / tileHeight);
|
|
1414
|
-
const lastRow = Math.floor((scrollTop + viewportHeight - 1) / tileHeight);
|
|
1415
|
-
const maxRowIndex = Math.max(0, Math.ceil(effectiveLogicalHeight / tileHeight) - 1);
|
|
1416
|
-
const rows = [];
|
|
1417
|
-
const endI = Math.min(lastRow + options.tilesBuffer, maxRowIndex);
|
|
1418
|
-
for (let i = firstRow; i <= endI; i++) {
|
|
1419
|
-
const logicalY = i * tileHeight;
|
|
1420
|
-
if (logicalY >= effectiveLogicalHeight) continue;
|
|
1421
|
-
rows.push({
|
|
1422
|
-
row: i,
|
|
1423
|
-
logicalY
|
|
1424
|
-
});
|
|
1425
|
-
if (rows.length >= options.maxPoolSize) break;
|
|
1426
|
-
}
|
|
1427
|
-
return {
|
|
1428
|
-
firstRow: Math.max(0, firstRow),
|
|
1429
|
-
lastRow: rows.length > 0 ? rows[rows.length - 1].row : 0,
|
|
1430
|
-
rows
|
|
1431
|
-
};
|
|
1432
|
-
}
|
|
1433
|
-
//#endregion
|
|
1434
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/util/debouncer.js
|
|
1435
|
-
/**
|
|
1436
|
-
* Creates a debounced version of a function that delays execution until after
|
|
1437
|
-
* a specified timeout has elapsed since the last call.
|
|
1438
|
-
*
|
|
1439
|
-
* Debouncing is useful for handling rapidly firing events (like scroll or resize)
|
|
1440
|
-
* by ensuring the function only executes once after the event stream settles.
|
|
1441
|
-
*
|
|
1442
|
-
* @template T - The type of the function to debounce
|
|
1443
|
-
* @param fn - The function to debounce
|
|
1444
|
-
* @param timeoutMs - The delay in milliseconds before executing the function
|
|
1445
|
-
* @returns A debounced version of the function with a `cancel` method
|
|
1446
|
-
*
|
|
1447
|
-
* @example
|
|
1448
|
-
* ```typescript
|
|
1449
|
-
* const debouncedLog = debouncer((msg: string) => {
|
|
1450
|
-
* console.log(msg);
|
|
1451
|
-
* }, 100);
|
|
1452
|
-
*
|
|
1453
|
-
* debouncedLog('Hello'); // Will log after 100ms
|
|
1454
|
-
* debouncedLog('World'); // Resets timer, will log 'World' after 100ms
|
|
1455
|
-
*
|
|
1456
|
-
* // Cancel pending execution
|
|
1457
|
-
* debouncedLog.cancel();
|
|
1458
|
-
* ```
|
|
1459
|
-
*/
|
|
1460
|
-
function debouncer(fn, timeoutMs) {
|
|
1461
|
-
let timer = null;
|
|
1462
|
-
const debounced = (...args) => {
|
|
1463
|
-
if (timer) clearTimeout(timer);
|
|
1464
|
-
timer = setTimeout(() => {
|
|
1465
|
-
fn(...args);
|
|
1466
|
-
}, timeoutMs);
|
|
1467
|
-
};
|
|
1468
|
-
debounced.cancel = () => {
|
|
1469
|
-
if (timer) {
|
|
1470
|
-
clearTimeout(timer);
|
|
1471
|
-
timer = null;
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
return debounced;
|
|
1475
|
-
}
|
|
1476
|
-
//#endregion
|
|
1477
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/util/draw.js
|
|
1478
|
-
/** Color palette for debug tile visualization */
|
|
1479
|
-
const TILE_COLORS = [
|
|
1480
|
-
`#FF6B6B`,
|
|
1481
|
-
`#4ECDC4`,
|
|
1482
|
-
`#45B7D1`,
|
|
1483
|
-
`#96CEB4`,
|
|
1484
|
-
`#FFEAA7`,
|
|
1485
|
-
`#DDA0DD`,
|
|
1486
|
-
`#98D8C8`,
|
|
1487
|
-
`#F7DC6F`,
|
|
1488
|
-
`#BB8FCE`,
|
|
1489
|
-
`#85C1E9`
|
|
1490
|
-
];
|
|
1491
|
-
/**
|
|
1492
|
-
* Gets a color for a tile based on its index.
|
|
1493
|
-
* Colors cycle through the TILE_COLORS palette.
|
|
1494
|
-
*
|
|
1495
|
-
* @param index - The tile index
|
|
1496
|
-
* @returns A hex color string
|
|
1497
|
-
*/
|
|
1498
|
-
function getTileColor(index) {
|
|
1499
|
-
return TILE_COLORS[index % TILE_COLORS.length];
|
|
1500
|
-
}
|
|
1501
|
-
/**
|
|
1502
|
-
* Draws debug visualization graphics on a tile canvas.
|
|
1503
|
-
*
|
|
1504
|
-
* This function renders diagnostic information useful for debugging tile
|
|
1505
|
-
* boundaries, positions, and sizing. It draws:
|
|
1506
|
-
* - A colored background
|
|
1507
|
-
* - Diagonal cross lines
|
|
1508
|
-
* - Center crosshair
|
|
1509
|
-
* - Border rectangle
|
|
1510
|
-
* - Text information (tile index, position, size, total width)
|
|
1511
|
-
*
|
|
1512
|
-
* @param tileIndex - The index of the tile being drawn
|
|
1513
|
-
* @param tilesTotal - The total number of tiles in the pool
|
|
1514
|
-
* @param widthTotal - The total logical width of the virtual canvas
|
|
1515
|
-
* @param ctx - The canvas 2D rendering context
|
|
1516
|
-
* @param region - The rectangular region of the tile in logical coordinates
|
|
1517
|
-
*
|
|
1518
|
-
* @example
|
|
1519
|
-
* ```typescript
|
|
1520
|
-
* // Enable debug drawing
|
|
1521
|
-
* vcanvas.debugDraw = true;
|
|
1522
|
-
*
|
|
1523
|
-
* // The debug graphics will be drawn on each tile automatically
|
|
1524
|
-
* ```
|
|
1525
|
-
*/
|
|
1526
|
-
function drawDebugGraphic(tileIndex, tilesTotal, widthTotal, ctx, region) {
|
|
1527
|
-
ctx.fillStyle = `whitesmoke`;
|
|
1528
|
-
ctx.fillRect(region.x, region.y, region.width, region.height);
|
|
1529
|
-
ctx.fillStyle = getTileColor(tileIndex);
|
|
1530
|
-
ctx.strokeStyle = getTileColor(tileIndex);
|
|
1531
|
-
ctx.lineWidth = 2;
|
|
1532
|
-
ctx.beginPath();
|
|
1533
|
-
ctx.moveTo(region.x, region.y);
|
|
1534
|
-
ctx.lineTo(region.x + region.width, region.y + region.height);
|
|
1535
|
-
ctx.moveTo(region.x + region.width, region.y);
|
|
1536
|
-
ctx.lineTo(region.x, region.y + region.height);
|
|
1537
|
-
ctx.stroke();
|
|
1538
|
-
ctx.font = `24pt system-ui`;
|
|
1539
|
-
ctx.textBaseline = `top`;
|
|
1540
|
-
ctx.fillText(`#${tileIndex}/${tilesTotal}`, region.x + 20, region.y + 20);
|
|
1541
|
-
ctx.font = `18pt system-ui`;
|
|
1542
|
-
ctx.fillText(`Pos: ${Math.round(region.x)},${Math.round(region.y)}`, region.x + 20, region.y + 60);
|
|
1543
|
-
ctx.fillText(`Size: ${Math.round(region.width)}x${Math.round(region.height)}`, region.x + 20, region.y + 90);
|
|
1544
|
-
ctx.fillText(`VCanvas width: ${Math.round(widthTotal)}`, region.x + 20, region.y + 120);
|
|
1545
|
-
const centerX = region.x + region.width / 2;
|
|
1546
|
-
const centerY = region.y + region.height / 2;
|
|
1547
|
-
ctx.beginPath();
|
|
1548
|
-
ctx.moveTo(region.x, centerY);
|
|
1549
|
-
ctx.lineTo(region.x + region.width, centerY);
|
|
1550
|
-
ctx.moveTo(centerX, region.y);
|
|
1551
|
-
ctx.lineTo(centerX, region.y + region.height);
|
|
1552
|
-
ctx.stroke();
|
|
1553
|
-
ctx.strokeRect(region.x, region.y, region.width, region.height);
|
|
1554
|
-
}
|
|
1555
|
-
//#endregion
|
|
1556
|
-
//#region node_modules/.pnpm/@clinth+vcanvas@0.0.3/node_modules/@clinth/vcanvas/dist/vcanvas.js
|
|
1557
|
-
var __decorate = function(decorators, target, key, desc) {
|
|
1558
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1559
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1560
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1561
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1562
|
-
};
|
|
1563
|
-
const tileKey = (col, row) => `${col},${row}`;
|
|
1564
|
-
const DEFAULT_TILE_WIDTH_MULTIPLIER = .5;
|
|
1565
|
-
const DEFAULT_TILE_HEIGHT_MULTIPLIER = .5;
|
|
1566
|
-
const DEFAULT_TILES_BUFFER = 2;
|
|
1567
|
-
const DEFAULT_OVERLAP_PERCENT = .01;
|
|
1568
|
-
const DEFAULT_OVERSCROLL_PAD_MULTIPLIER = 1;
|
|
1569
|
-
const DEFAULT_MAX_POOL_SIZE = 3;
|
|
1570
|
-
const DEFAULT_SCROLL_DEBOUNCE_MS = 100;
|
|
1571
|
-
let VCanvas = class VCanvas extends LitElement {
|
|
1572
|
-
_emitScrollEndEvent(userGesture) {
|
|
1573
|
-
const event = new CustomEvent(`scrollend-virtual`, {
|
|
1574
|
-
detail: {
|
|
1575
|
-
logicalScrollLeft: this._scrollLeft,
|
|
1576
|
-
logicalScrollTop: this._scrollTop,
|
|
1577
|
-
userGesture,
|
|
1578
|
-
containerScrollLeft: this._scrollContainer?.scrollLeft ?? 0,
|
|
1579
|
-
containerScrollTop: this._scrollContainer?.scrollTop ?? 0
|
|
1580
|
-
},
|
|
1581
|
-
bubbles: true,
|
|
1582
|
-
composed: true
|
|
1583
|
-
});
|
|
1584
|
-
this.dispatchEvent(event);
|
|
1585
|
-
}
|
|
1586
|
-
constructor() {
|
|
1587
|
-
super();
|
|
1588
|
-
/**
|
|
1589
|
-
* Enables detailed console logging of tile operations for debugging.
|
|
1590
|
-
*
|
|
1591
|
-
* When `true`, the component logs information about tile creation,
|
|
1592
|
-
* positioning, and rendering to the console. Useful for debugging
|
|
1593
|
-
* tile-related issues during development.
|
|
1594
|
-
*
|
|
1595
|
-
* @default false
|
|
1596
|
-
*/
|
|
1597
|
-
this.debugTrace = false;
|
|
1598
|
-
this.debugDraw = false;
|
|
1599
|
-
/**
|
|
1600
|
-
* Enables visual hinting for scroll position at container edges.
|
|
1601
|
-
*
|
|
1602
|
-
* When `true`, applies the 'scrollable' class to the scroll container which
|
|
1603
|
-
* adds CSS scroll-driven fade animations at the left and right edges,
|
|
1604
|
-
* providing visual feedback about scroll availability.
|
|
1605
|
-
*
|
|
1606
|
-
* @default false
|
|
1607
|
-
*/
|
|
1608
|
-
this.hinting = false;
|
|
1609
|
-
this._viewportWidth = 0;
|
|
1610
|
-
this._viewportHeight = 0;
|
|
1611
|
-
this._scrollLeft = 0;
|
|
1612
|
-
this._scrollTop = 0;
|
|
1613
|
-
this._logicalHeight = 0;
|
|
1614
|
-
this._tilePool = /* @__PURE__ */ new Map();
|
|
1615
|
-
this._visibleTiles = /* @__PURE__ */ new Set();
|
|
1616
|
-
this._pendingDraws = /* @__PURE__ */ new Map();
|
|
1617
|
-
this._scrollContainer = null;
|
|
1618
|
-
this._spacer = null;
|
|
1619
|
-
this._tilePoolEl = null;
|
|
1620
|
-
this._childrenContainerEl = null;
|
|
1621
|
-
this._resizeObserver = null;
|
|
1622
|
-
this._positionedChildren = /* @__PURE__ */ new Map();
|
|
1623
|
-
this._boundOnScroll = this._onScroll.bind(this);
|
|
1624
|
-
this._renderingOptions = {
|
|
1625
|
-
tileWidthMultiplier: DEFAULT_TILE_WIDTH_MULTIPLIER,
|
|
1626
|
-
tileHeightMultiplier: DEFAULT_TILE_HEIGHT_MULTIPLIER,
|
|
1627
|
-
tilesBuffer: DEFAULT_TILES_BUFFER,
|
|
1628
|
-
overlapPercent: DEFAULT_OVERLAP_PERCENT,
|
|
1629
|
-
overscrollPadMultiplier: DEFAULT_OVERSCROLL_PAD_MULTIPLIER,
|
|
1630
|
-
maxPoolSize: DEFAULT_MAX_POOL_SIZE,
|
|
1631
|
-
scrollDebounceMs: DEFAULT_SCROLL_DEBOUNCE_MS
|
|
1632
|
-
};
|
|
1633
|
-
this._dpr = window.devicePixelRatio || 1;
|
|
1634
|
-
this._logicalWidth = 0;
|
|
1635
|
-
this.logicalWidth = 0;
|
|
1636
|
-
this.logicalHeight = 0;
|
|
1637
|
-
this.drawCallback = null;
|
|
1638
|
-
this._scrollDebounce = debouncer(() => {
|
|
1639
|
-
this._requestRedrawAll(`scrollDebounce`);
|
|
1640
|
-
}, this._renderingOptions.scrollDebounceMs);
|
|
1641
|
-
this._scrollEndDebounce = debouncer(() => {
|
|
1642
|
-
this._emitScrollEndEvent(true);
|
|
1643
|
-
}, this._renderingOptions.scrollDebounceMs);
|
|
1644
|
-
this._resizeDebounce = debouncer(() => {
|
|
1645
|
-
this._onResize();
|
|
1646
|
-
}, this._renderingOptions.scrollDebounceMs);
|
|
1647
|
-
}
|
|
1648
|
-
static {
|
|
1649
|
-
this.styles = vcanvasStyles;
|
|
1650
|
-
}
|
|
1651
|
-
connectedCallback() {
|
|
1652
|
-
super.connectedCallback();
|
|
1653
|
-
this._setupResizeObserver();
|
|
1654
|
-
}
|
|
1655
|
-
disconnectedCallback() {
|
|
1656
|
-
super.disconnectedCallback();
|
|
1657
|
-
this._resizeObserver?.disconnect();
|
|
1658
|
-
this._resizeObserver = null;
|
|
1659
|
-
this._scrollEndDebounce.cancel();
|
|
1660
|
-
this._pendingDraws.forEach((ctrl) => ctrl.abort());
|
|
1661
|
-
this._tilePool.clear();
|
|
1662
|
-
this._scrollContainer?.removeEventListener(`scroll`, this._boundOnScroll);
|
|
1663
|
-
}
|
|
1664
|
-
firstUpdated() {
|
|
1665
|
-
const scrollContainer = this.shadowRoot?.querySelector(`.scroll-container`);
|
|
1666
|
-
this._scrollContainer = scrollContainer;
|
|
1667
|
-
this._spacer = this.shadowRoot?.querySelector(`.spacer`);
|
|
1668
|
-
this._tilePoolEl = this.shadowRoot?.querySelector(`.tile-pool`);
|
|
1669
|
-
this._childrenContainerEl = this.shadowRoot?.querySelector(`.children-container`);
|
|
1670
|
-
if (this._scrollContainer) this._scrollContainer.addEventListener(`scroll`, this._boundOnScroll);
|
|
1671
|
-
requestAnimationFrame(() => {
|
|
1672
|
-
this._updateViewportDimensions();
|
|
1673
|
-
this._updateSpacer();
|
|
1674
|
-
this._updateScrollContainerClass();
|
|
1675
|
-
this._recalculateTiles(`firstUpdated cb`);
|
|
1676
|
-
this._positionChildren(`firstUpdated cb`);
|
|
1677
|
-
});
|
|
1678
|
-
}
|
|
1679
|
-
/**
|
|
1680
|
-
* The total logical width of the virtual canvas content.
|
|
1681
|
-
*
|
|
1682
|
-
* This represents the full width of the scrollable content in logical units.
|
|
1683
|
-
* Setting this property triggers recalculation of tiles and updates the spacer
|
|
1684
|
-
* element that enables native scroll behavior.
|
|
1685
|
-
*
|
|
1686
|
-
* @example
|
|
1687
|
-
* ```typescript
|
|
1688
|
-
* // Create a virtual canvas 10,000 logical units wide
|
|
1689
|
-
* vcanvas.logicalWidth = 10000;
|
|
1690
|
-
* ```
|
|
1691
|
-
*/
|
|
1692
|
-
set logicalWidth(value) {
|
|
1693
|
-
this._logicalWidth = value;
|
|
1694
|
-
this._updateSpacer();
|
|
1695
|
-
this._updateScrollContainerClass();
|
|
1696
|
-
if (this.hasUpdated) {
|
|
1697
|
-
this._updateTileWidths(`set logicalWidth`);
|
|
1698
|
-
this._recalculateTiles(`set logicalWidth`);
|
|
1699
|
-
}
|
|
1700
|
-
}
|
|
1701
|
-
get logicalWidth() {
|
|
1702
|
-
return this._logicalWidth;
|
|
1703
|
-
}
|
|
1704
|
-
/**
|
|
1705
|
-
* The total logical height of the virtual canvas content.
|
|
1706
|
-
*
|
|
1707
|
-
* When set to 0 (default), the component uses the actual viewport height,
|
|
1708
|
-
* meaning no vertical virtualization is applied. Set to a value greater than
|
|
1709
|
-
* the viewport height to enable vertical scrolling and tile-based virtualization.
|
|
1710
|
-
*
|
|
1711
|
-
* @example
|
|
1712
|
-
* ```typescript
|
|
1713
|
-
* // Create a canvas virtualized in both axes
|
|
1714
|
-
* vcanvas.logicalWidth = 10000;
|
|
1715
|
-
* vcanvas.logicalHeight = 5000;
|
|
1716
|
-
* ```
|
|
1717
|
-
*/
|
|
1718
|
-
set logicalHeight(value) {
|
|
1719
|
-
this._logicalHeight = value;
|
|
1720
|
-
this._updateSpacer();
|
|
1721
|
-
this._updateScrollContainerClass();
|
|
1722
|
-
if (this.hasUpdated) this._recalculateTiles(`set logicalHeight`);
|
|
1723
|
-
}
|
|
1724
|
-
get logicalHeight() {
|
|
1725
|
-
return this._logicalHeight;
|
|
1726
|
-
}
|
|
1727
|
-
/** Effective logical width: uses viewport width when logicalWidth is 0 (no horizontal virtualization). */
|
|
1728
|
-
get effectiveLogicalWidth() {
|
|
1729
|
-
return this._logicalWidth || this._viewportWidth;
|
|
1730
|
-
}
|
|
1731
|
-
/** Effective logical height: uses viewport height when logicalHeight is 0 (no vertical virtualization). */
|
|
1732
|
-
get effectiveLogicalHeight() {
|
|
1733
|
-
return this._logicalHeight || this._viewportHeight;
|
|
1734
|
-
}
|
|
1735
|
-
_setupResizeObserver() {
|
|
1736
|
-
this._resizeObserver = new ResizeObserver(() => {
|
|
1737
|
-
this._resizeDebounce();
|
|
1738
|
-
});
|
|
1739
|
-
this._resizeObserver.observe(this);
|
|
1740
|
-
}
|
|
1741
|
-
_onResize() {
|
|
1742
|
-
const oldWidth = this._viewportWidth;
|
|
1743
|
-
const oldHeight = this._viewportHeight;
|
|
1744
|
-
this._updateViewportDimensions();
|
|
1745
|
-
const widthChanged = oldWidth !== this._viewportWidth;
|
|
1746
|
-
const heightChanged = oldHeight !== this._viewportHeight;
|
|
1747
|
-
if (widthChanged || heightChanged) {
|
|
1748
|
-
this._updateSpacer();
|
|
1749
|
-
this._updateScrollContainerClass();
|
|
1750
|
-
this._recalculateTiles(`onResize`);
|
|
1751
|
-
}
|
|
1752
|
-
}
|
|
1753
|
-
_updateTileWidths(reason) {
|
|
1754
|
-
const tileWidth = this._getTileWidth();
|
|
1755
|
-
for (const tile of this._tilePool.values()) {
|
|
1756
|
-
const clippedWidth = this._getTileClippedWidth(tile.logicalX, tileWidth);
|
|
1757
|
-
tile.canvas.width = clippedWidth * this._dpr;
|
|
1758
|
-
tile.canvas.style.width = `${clippedWidth}px`;
|
|
1759
|
-
tile.ctx.scale(this._dpr, this._dpr);
|
|
1760
|
-
}
|
|
1761
|
-
this._requestRedrawAll(`updateTileWidths (${reason})`);
|
|
1762
|
-
}
|
|
1763
|
-
_updateViewportDimensions() {
|
|
1764
|
-
const rect = this.getBoundingClientRect();
|
|
1765
|
-
this._viewportWidth = rect.width;
|
|
1766
|
-
this._viewportHeight = rect.height;
|
|
1767
|
-
}
|
|
1768
|
-
_onScroll() {
|
|
1769
|
-
if (!this._scrollContainer) return;
|
|
1770
|
-
const newScrollLeft = this._scrollContainer.scrollLeft;
|
|
1771
|
-
const newScrollTop = this._scrollContainer.scrollTop;
|
|
1772
|
-
if (newScrollLeft === this._scrollLeft && newScrollTop === this._scrollTop) return;
|
|
1773
|
-
this._scrollLeft = newScrollLeft;
|
|
1774
|
-
this._scrollTop = newScrollTop;
|
|
1775
|
-
this._recalculateTiles(`onScroll`);
|
|
1776
|
-
this._emitScrollEvent(true);
|
|
1777
|
-
this._scrollDebounce();
|
|
1778
|
-
this._scrollEndDebounce();
|
|
1779
|
-
}
|
|
1780
|
-
_updateSpacer() {
|
|
1781
|
-
if (!this._spacer) return;
|
|
1782
|
-
const noHorizontalScroll = isSingleTileMode(this.effectiveLogicalWidth, this._viewportWidth);
|
|
1783
|
-
const noVerticalScroll = isSingleTileModeY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
1784
|
-
if (noHorizontalScroll && noVerticalScroll) this._spacer.style.display = `none`;
|
|
1785
|
-
else {
|
|
1786
|
-
this._spacer.style.display = `block`;
|
|
1787
|
-
this._spacer.style.width = `${this.effectiveLogicalWidth}px`;
|
|
1788
|
-
this._spacer.style.height = `${this.effectiveLogicalHeight}px`;
|
|
1789
|
-
}
|
|
1790
|
-
if (this._childrenContainerEl) {
|
|
1791
|
-
this._childrenContainerEl.style.width = `${this.effectiveLogicalWidth}px`;
|
|
1792
|
-
this._childrenContainerEl.style.height = `${this.effectiveLogicalHeight}px`;
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
_updateScrollContainerClass() {
|
|
1796
|
-
if (!this._scrollContainer) return;
|
|
1797
|
-
const verticalScroll = this.effectiveLogicalHeight > this._viewportHeight;
|
|
1798
|
-
this._scrollContainer.classList.toggle(`vertical`, verticalScroll);
|
|
1799
|
-
}
|
|
1800
|
-
_getTileWidth() {
|
|
1801
|
-
return getTileWidth(this._viewportWidth, this._renderingOptions.tileWidthMultiplier);
|
|
1802
|
-
}
|
|
1803
|
-
_getTileHeight() {
|
|
1804
|
-
return getTileHeight(this._viewportHeight, this._renderingOptions.tileHeightMultiplier);
|
|
1805
|
-
}
|
|
1806
|
-
_getTileClippedWidth(logicalX, tileWidth) {
|
|
1807
|
-
return getTileClippedWidth(logicalX, tileWidth, this.effectiveLogicalWidth, this._viewportWidth, this._renderingOptions.overscrollPadMultiplier);
|
|
1808
|
-
}
|
|
1809
|
-
_getTileClippedHeight(logicalY, tileHeight) {
|
|
1810
|
-
return getTileClippedHeight(logicalY, tileHeight, this.effectiveLogicalHeight, this._viewportHeight, this._renderingOptions.overscrollPadMultiplier);
|
|
1811
|
-
}
|
|
1812
|
-
_calculateTileRange() {
|
|
1813
|
-
return calculateTileRange(this._scrollLeft, this._viewportWidth, this.effectiveLogicalWidth, this._renderingOptions);
|
|
1814
|
-
}
|
|
1815
|
-
_calculateTileRowRange() {
|
|
1816
|
-
return calculateTileRowRange(this._scrollTop, this._viewportHeight, this.effectiveLogicalHeight, this._renderingOptions);
|
|
1817
|
-
}
|
|
1818
|
-
_recalculateTiles(reason) {
|
|
1819
|
-
this._updateViewportDimensions();
|
|
1820
|
-
const { tiles } = this._calculateTileRange();
|
|
1821
|
-
const { rows } = this._calculateTileRowRange();
|
|
1822
|
-
const neededKeys = /* @__PURE__ */ new Set();
|
|
1823
|
-
for (const { index: col, logicalX } of tiles) for (const { row, logicalY } of rows) {
|
|
1824
|
-
neededKeys.add(tileKey(col, row));
|
|
1825
|
-
if (!this._tilePool.has(tileKey(col, row))) this._tilePool.set(tileKey(col, row), this._createTile(col, row, logicalX, logicalY));
|
|
1826
|
-
}
|
|
1827
|
-
const maxPoolSize = this._renderingOptions.maxPoolSize * Math.max(1, rows.length);
|
|
1828
|
-
const reuseCandidates = [...this._tilePool.keys()].filter((k) => !neededKeys.has(k));
|
|
1829
|
-
const missingKeys = [...neededKeys].filter((k) => !this._tilePool.has(k));
|
|
1830
|
-
const tilesToReuse = Math.min(reuseCandidates.length, missingKeys.length);
|
|
1831
|
-
for (let i = 0; i < tilesToReuse; i++) {
|
|
1832
|
-
const oldKey = reuseCandidates[i];
|
|
1833
|
-
const newKey = missingKeys[i];
|
|
1834
|
-
const tile = this._tilePool.get(oldKey);
|
|
1835
|
-
if (tile && newKey) {
|
|
1836
|
-
const [colStr, rowStr] = newKey.split(`,`);
|
|
1837
|
-
const col = Number(colStr);
|
|
1838
|
-
const row = Number(rowStr);
|
|
1839
|
-
this._tilePool.delete(oldKey);
|
|
1840
|
-
tile.col = col;
|
|
1841
|
-
tile.row = row;
|
|
1842
|
-
tile.logicalX = col * this._getTileWidth();
|
|
1843
|
-
tile.logicalY = row * this._getTileHeight();
|
|
1844
|
-
tile.visible = false;
|
|
1845
|
-
tile.canvas.dataset.tileKey = newKey;
|
|
1846
|
-
this._tilePool.set(newKey, tile);
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
const keysAfterReuse = [...this._tilePool.keys()];
|
|
1850
|
-
if (keysAfterReuse.length > maxPoolSize) {
|
|
1851
|
-
const excessCount = keysAfterReuse.length - maxPoolSize;
|
|
1852
|
-
keysAfterReuse.filter((k) => !neededKeys.has(k)).slice(0, excessCount).forEach((k) => {
|
|
1853
|
-
const tile = this._tilePool.get(k);
|
|
1854
|
-
if (tile) {
|
|
1855
|
-
this._tilePool.delete(k);
|
|
1856
|
-
tile.canvas.remove();
|
|
1857
|
-
}
|
|
1858
|
-
});
|
|
1859
|
-
}
|
|
1860
|
-
this._updateTiles(`recalculateTiles (${reason})`);
|
|
1861
|
-
}
|
|
1862
|
-
_createTile(col, row, logicalX, logicalY) {
|
|
1863
|
-
const canvas = document.createElement(`canvas`);
|
|
1864
|
-
const key = tileKey(col, row);
|
|
1865
|
-
canvas.dataset.tileKey = key;
|
|
1866
|
-
const tileWidth = this._getTileWidth();
|
|
1867
|
-
const tileHeight = this._getTileHeight();
|
|
1868
|
-
const clippedWidth = this._getTileClippedWidth(logicalX, tileWidth);
|
|
1869
|
-
const clippedHeight = this._getTileClippedHeight(logicalY, tileHeight);
|
|
1870
|
-
const ctx = canvas.getContext(`2d`);
|
|
1871
|
-
if (!ctx) throw new Error(`Could not get canvas context`);
|
|
1872
|
-
if (this._viewportHeight === 0) this.#debug(`Warning: Creating tile ${key} with viewport height 0. The VCanvas component may not be properly sized or visible.`);
|
|
1873
|
-
canvas.width = clippedWidth * this._dpr;
|
|
1874
|
-
canvas.height = clippedHeight * this._dpr;
|
|
1875
|
-
canvas.style.width = `${clippedWidth}px`;
|
|
1876
|
-
canvas.style.height = `${clippedHeight}px`;
|
|
1877
|
-
ctx.scale(this._dpr, this._dpr);
|
|
1878
|
-
this.#debug(`Created tile ${key} at logicalX ${logicalX} logicalY ${logicalY}`);
|
|
1879
|
-
return {
|
|
1880
|
-
canvas,
|
|
1881
|
-
ctx,
|
|
1882
|
-
logicalX,
|
|
1883
|
-
logicalY,
|
|
1884
|
-
col,
|
|
1885
|
-
row,
|
|
1886
|
-
visible: false,
|
|
1887
|
-
isInDOM: false
|
|
1888
|
-
};
|
|
1889
|
-
}
|
|
1890
|
-
_updateTiles(reason) {
|
|
1891
|
-
const { tiles, firstTile, lastTile } = this._calculateTileRange();
|
|
1892
|
-
const { rows, firstRow, lastRow } = this._calculateTileRowRange();
|
|
1893
|
-
const tileWidth = this._getTileWidth();
|
|
1894
|
-
const tileHeight = this._getTileHeight();
|
|
1895
|
-
const isSingleTileX = isSingleTileMode(this.effectiveLogicalWidth, this._viewportWidth);
|
|
1896
|
-
const isSingleTileY = isSingleTileModeY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
1897
|
-
const contentOffsetX = getContentOffset(this.effectiveLogicalWidth, this._viewportWidth);
|
|
1898
|
-
const contentOffsetY = getContentOffsetY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
1899
|
-
const tilesBuffer = this._renderingOptions.tilesBuffer;
|
|
1900
|
-
const tilesRedrawn = [];
|
|
1901
|
-
for (const tile of this._tilePool.values()) tile.visible = false;
|
|
1902
|
-
this._visibleTiles.clear();
|
|
1903
|
-
for (const [key, tile] of this._tilePool) {
|
|
1904
|
-
const colVisible = isSingleTileX ? tile.col === 0 : tile.col >= firstTile - tilesBuffer && tile.col <= lastTile + tilesBuffer;
|
|
1905
|
-
const rowVisible = isSingleTileY ? tile.row === 0 : tile.row >= firstRow - tilesBuffer && tile.row <= lastRow + tilesBuffer;
|
|
1906
|
-
if (colVisible && rowVisible) {
|
|
1907
|
-
this._visibleTiles.add(key);
|
|
1908
|
-
const newLogicalX = tile.col * tileWidth;
|
|
1909
|
-
const newLogicalY = tile.row * tileHeight;
|
|
1910
|
-
const visualX = isSingleTileX ? contentOffsetX : newLogicalX;
|
|
1911
|
-
const visualY = isSingleTileY ? contentOffsetY : newLogicalY;
|
|
1912
|
-
const clippedWidth = this._getTileClippedWidth(newLogicalX, tileWidth);
|
|
1913
|
-
const clippedHeight = this._getTileClippedHeight(newLogicalY, tileHeight);
|
|
1914
|
-
if (!tile.visible || tile.logicalX !== newLogicalX || tile.logicalY !== newLogicalY || tile.canvas.style.left !== `${visualX}px` || tile.canvas.style.top !== `${visualY}px` || tile.canvas.width !== clippedWidth * this._dpr || tile.canvas.height !== clippedHeight * this._dpr) {
|
|
1915
|
-
tile.logicalX = newLogicalX;
|
|
1916
|
-
tile.logicalY = newLogicalY;
|
|
1917
|
-
tile.canvas.width = clippedWidth * this._dpr;
|
|
1918
|
-
tile.canvas.style.width = `${clippedWidth}px`;
|
|
1919
|
-
tile.canvas.height = clippedHeight * this._dpr;
|
|
1920
|
-
tile.canvas.style.height = `${clippedHeight}px`;
|
|
1921
|
-
tile.canvas.style.left = `${visualX}px`;
|
|
1922
|
-
tile.canvas.style.top = `${visualY}px`;
|
|
1923
|
-
tile.ctx.scale(this._dpr, this._dpr);
|
|
1924
|
-
if (!tile.isInDOM && this._tilePoolEl) {
|
|
1925
|
-
this._tilePoolEl.appendChild(tile.canvas);
|
|
1926
|
-
tile.isInDOM = true;
|
|
1927
|
-
}
|
|
1928
|
-
if (!tile.visible) {
|
|
1929
|
-
tilesRedrawn.push(key);
|
|
1930
|
-
this._requestTileDraw(`updateTiles(${reason})`, key);
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
tile.visible = true;
|
|
1934
|
-
} else if (tile.visible) {
|
|
1935
|
-
tile.visible = false;
|
|
1936
|
-
tile.isInDOM = false;
|
|
1937
|
-
tile.canvas.remove();
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
for (const { index: col, logicalX } of tiles) for (const { row, logicalY } of rows) {
|
|
1941
|
-
const key = tileKey(col, row);
|
|
1942
|
-
if (!this._tilePool.has(key) && this._tilePoolEl) {
|
|
1943
|
-
const newTile = this._createTile(col, row, logicalX, logicalY);
|
|
1944
|
-
const visualX = isSingleTileX ? contentOffsetX : logicalX;
|
|
1945
|
-
const visualY = isSingleTileY ? contentOffsetY : logicalY;
|
|
1946
|
-
newTile.canvas.style.left = `${visualX}px`;
|
|
1947
|
-
newTile.canvas.style.top = `${visualY}px`;
|
|
1948
|
-
newTile.visible = true;
|
|
1949
|
-
newTile.isInDOM = true;
|
|
1950
|
-
this._tilePoolEl.appendChild(newTile.canvas);
|
|
1951
|
-
this._tilePool.set(key, newTile);
|
|
1952
|
-
this._visibleTiles.add(key);
|
|
1953
|
-
tilesRedrawn.push(key);
|
|
1954
|
-
this._requestTileDraw(`updateTiles(${reason})`, key);
|
|
1955
|
-
}
|
|
1956
|
-
}
|
|
1957
|
-
return tilesRedrawn;
|
|
1958
|
-
}
|
|
1959
|
-
_requestRedrawAll(reason) {
|
|
1960
|
-
this.#debug(`Requesting _requestRedrawAll: ${reason} visible tiles: ${this._visibleTiles.size} pending draws: ${this._pendingDraws.size}`);
|
|
1961
|
-
this._pendingDraws.forEach((ctrl) => ctrl.abort());
|
|
1962
|
-
this._pendingDraws.clear();
|
|
1963
|
-
for (const tileIndex of this._visibleTiles) this._requestTileDraw(`requestRedrawAll(${reason})`, tileIndex);
|
|
1964
|
-
}
|
|
1965
|
-
#debug(msg) {
|
|
1966
|
-
if (!this.debugTrace) return;
|
|
1967
|
-
console.log(`[VCanvas]`, msg);
|
|
1968
|
-
}
|
|
1969
|
-
_requestTileDraw(_reason, tileKey, region) {
|
|
1970
|
-
const tile = this._tilePool.get(tileKey);
|
|
1971
|
-
if (!tile || !this.drawCallback) return;
|
|
1972
|
-
const abortCtrl = new AbortController();
|
|
1973
|
-
this._pendingDraws.set(tileKey, abortCtrl);
|
|
1974
|
-
const tileWidth = this._getTileWidth();
|
|
1975
|
-
const tileHeight = this._getTileHeight();
|
|
1976
|
-
const isSingleTileX = isSingleTileMode(this.effectiveLogicalWidth, this._viewportWidth);
|
|
1977
|
-
const isSingleTileY = isSingleTileModeY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
1978
|
-
let drawRegion;
|
|
1979
|
-
if (region) drawRegion = region;
|
|
1980
|
-
else {
|
|
1981
|
-
const overlapX = tileWidth * this._renderingOptions.overlapPercent;
|
|
1982
|
-
const overlapY = tileHeight * this._renderingOptions.overlapPercent;
|
|
1983
|
-
drawRegion = {
|
|
1984
|
-
x: isSingleTileX ? 0 : tile.logicalX - overlapX,
|
|
1985
|
-
y: isSingleTileY ? 0 : tile.logicalY - overlapY,
|
|
1986
|
-
width: isSingleTileX ? this.effectiveLogicalWidth : tileWidth + overlapX * 2,
|
|
1987
|
-
height: isSingleTileY ? this.effectiveLogicalHeight : tileHeight + overlapY * 2
|
|
1988
|
-
};
|
|
1989
|
-
}
|
|
1990
|
-
tile.ctx.save();
|
|
1991
|
-
tile.ctx.translate(-tile.logicalX, -tile.logicalY);
|
|
1992
|
-
const localX = drawRegion.x - tile.logicalX;
|
|
1993
|
-
const localY = drawRegion.y - tile.logicalY;
|
|
1994
|
-
if (region) {
|
|
1995
|
-
tile.ctx.beginPath();
|
|
1996
|
-
tile.ctx.rect(localX, localY, drawRegion.width, drawRegion.height);
|
|
1997
|
-
tile.ctx.clip();
|
|
1998
|
-
tile.ctx.clearRect(localX, localY, drawRegion.width, drawRegion.height);
|
|
1999
|
-
} else tile.ctx.clearRect(0, 0, tile.canvas.width, tile.canvas.height);
|
|
2000
|
-
if (this.debugDraw) drawDebugGraphic(tile.col, this._tilePool.size, this.effectiveLogicalWidth, tile.ctx, drawRegion);
|
|
2001
|
-
try {
|
|
2002
|
-
this.drawCallback(tile.ctx, drawRegion, abortCtrl.signal);
|
|
2003
|
-
} finally {
|
|
2004
|
-
if (tile) tile.ctx.restore();
|
|
2005
|
-
this._pendingDraws.delete(tileKey);
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
_emitScrollEvent(userGesture) {
|
|
2009
|
-
const event = new CustomEvent(`scroll-virtual`, {
|
|
2010
|
-
detail: {
|
|
2011
|
-
logicalScrollLeft: this._scrollLeft,
|
|
2012
|
-
logicalScrollTop: this._scrollTop,
|
|
2013
|
-
userGesture,
|
|
2014
|
-
containerScrollLeft: this._scrollContainer?.scrollLeft ?? 0,
|
|
2015
|
-
containerScrollTop: this._scrollContainer?.scrollTop ?? 0,
|
|
2016
|
-
viewportStartLogical: this._scrollLeft,
|
|
2017
|
-
viewportEndLogical: this._scrollLeft + this._viewportWidth,
|
|
2018
|
-
viewportStartLogicalY: this._scrollTop,
|
|
2019
|
-
viewportEndLogicalY: this._scrollTop + this._viewportHeight
|
|
2020
|
-
},
|
|
2021
|
-
bubbles: true,
|
|
2022
|
-
composed: true
|
|
2023
|
-
});
|
|
2024
|
-
this.dispatchEvent(event);
|
|
2025
|
-
}
|
|
2026
|
-
/**
|
|
2027
|
-
* Checks if any part of a rectangular region is currently visible in the viewport.
|
|
2028
|
-
*
|
|
2029
|
-
* This method is useful for determining whether content needs to be rendered
|
|
2030
|
-
* or updated based on its visibility status. The region is specified using
|
|
2031
|
-
* logical coordinates relative to the virtual canvas content.
|
|
2032
|
-
*
|
|
2033
|
-
* @param rect - The rectangular region to check, in logical coordinates
|
|
2034
|
-
* @returns true if any part of the region overlaps with the visible viewport
|
|
2035
|
-
*
|
|
2036
|
-
* @example
|
|
2037
|
-
* ```typescript
|
|
2038
|
-
* const region = { x: 1000, y: 0, width: 500, height: 1000 };
|
|
2039
|
-
* if (vcanvas.isRegionVisible(region)) {
|
|
2040
|
-
* // Region is at least partially visible, render it
|
|
2041
|
-
* }
|
|
2042
|
-
* ```
|
|
2043
|
-
*/
|
|
2044
|
-
isRegionVisible(rect) {
|
|
2045
|
-
const viewportLeft = this._scrollLeft;
|
|
2046
|
-
const viewportRight = this._scrollLeft + this._viewportWidth;
|
|
2047
|
-
const xVisible = rect.x + rect.width > viewportLeft && rect.x < viewportRight;
|
|
2048
|
-
const viewportTop = this._scrollTop;
|
|
2049
|
-
const viewportBottom = this._scrollTop + this._viewportHeight;
|
|
2050
|
-
const yVisible = rect.y + rect.height > viewportTop && rect.y < viewportBottom;
|
|
2051
|
-
return xVisible && yVisible;
|
|
2052
|
-
}
|
|
2053
|
-
_updateScrollPosition(userGesture) {
|
|
2054
|
-
if (this._scrollContainer) {
|
|
2055
|
-
this._scrollContainer.scrollLeft = this._scrollLeft;
|
|
2056
|
-
this._scrollContainer.scrollTop = this._scrollTop;
|
|
2057
|
-
}
|
|
2058
|
-
this._recalculateTiles(`updateScrollPosition`);
|
|
2059
|
-
this._emitScrollEvent(userGesture);
|
|
2060
|
-
this._scrollDebounce();
|
|
2061
|
-
}
|
|
2062
|
-
get logicalScrollLeft() {
|
|
2063
|
-
return this._scrollLeft;
|
|
2064
|
-
}
|
|
2065
|
-
/**
|
|
2066
|
-
* The current logical scroll position.
|
|
2067
|
-
*
|
|
2068
|
-
* Setting this property smoothly scrolls the virtual canvas to the specified
|
|
2069
|
-
* position. The value is automatically clamped to valid bounds (0 to
|
|
2070
|
-
* logicalWidth - viewportWidth).
|
|
2071
|
-
*
|
|
2072
|
-
* @example
|
|
2073
|
-
* ```typescript
|
|
2074
|
-
* // Scroll to position 5000
|
|
2075
|
-
* vcanvas.logicalScrollLeft = 5000;
|
|
2076
|
-
*
|
|
2077
|
-
* // Get current scroll position
|
|
2078
|
-
* console.log(vcanvas.logicalScrollLeft);
|
|
2079
|
-
* ```
|
|
2080
|
-
*/
|
|
2081
|
-
set logicalScrollLeft(value) {
|
|
2082
|
-
const oldValue = this._scrollLeft;
|
|
2083
|
-
const clampedValue = clamp(value, 0, Math.max(0, this.effectiveLogicalWidth - this._viewportWidth));
|
|
2084
|
-
if (clampedValue !== this._scrollLeft) {
|
|
2085
|
-
this._scrollLeft = clampedValue;
|
|
2086
|
-
this.requestUpdate(`logicalScrollLeft`, oldValue);
|
|
2087
|
-
this._updateScrollPosition(false);
|
|
2088
|
-
}
|
|
2089
|
-
}
|
|
2090
|
-
get logicalScrollTop() {
|
|
2091
|
-
return this._scrollTop;
|
|
2092
|
-
}
|
|
2093
|
-
set logicalScrollTop(value) {
|
|
2094
|
-
const oldValue = this._scrollTop;
|
|
2095
|
-
const clampedValue = clamp(value, 0, Math.max(0, this.effectiveLogicalHeight - this._viewportHeight));
|
|
2096
|
-
if (clampedValue !== this._scrollTop) {
|
|
2097
|
-
this._scrollTop = clampedValue;
|
|
2098
|
-
this.requestUpdate(`logicalScrollTop`, oldValue);
|
|
2099
|
-
this._updateScrollPosition(false);
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
get containerScrollLeft() {
|
|
2103
|
-
return this._scrollContainer?.scrollLeft ?? 0;
|
|
2104
|
-
}
|
|
2105
|
-
get containerScrollTop() {
|
|
2106
|
-
return this._scrollContainer?.scrollTop ?? 0;
|
|
2107
|
-
}
|
|
2108
|
-
/**
|
|
2109
|
-
* The current viewport width in pixels.
|
|
2110
|
-
*
|
|
2111
|
-
* This value is automatically updated when the component is resized.
|
|
2112
|
-
* Read-only - use CSS to control the component's size.
|
|
2113
|
-
*
|
|
2114
|
-
* @example
|
|
2115
|
-
* ```typescript
|
|
2116
|
-
* const vw = vcanvas.viewportWidth;
|
|
2117
|
-
* ```
|
|
2118
|
-
*/
|
|
2119
|
-
get viewportWidth() {
|
|
2120
|
-
return this._viewportWidth;
|
|
2121
|
-
}
|
|
2122
|
-
/**
|
|
2123
|
-
* The current viewport height in pixels.
|
|
2124
|
-
*
|
|
2125
|
-
* This value is automatically updated when the component is resized.
|
|
2126
|
-
* Read-only - use CSS to control the component's size.
|
|
2127
|
-
*
|
|
2128
|
-
* @example
|
|
2129
|
-
* ```typescript
|
|
2130
|
-
* const vh = vcanvas.viewportHeight;
|
|
2131
|
-
* ```
|
|
2132
|
-
*/
|
|
2133
|
-
get viewportHeight() {
|
|
2134
|
-
return this._viewportHeight;
|
|
2135
|
-
}
|
|
2136
|
-
/**
|
|
2137
|
-
* Updates rendering options for the virtual canvas.
|
|
2138
|
-
*
|
|
2139
|
-
* Pass a partial options object to update specific settings. Any options
|
|
2140
|
-
* not provided retain their current values. After updating options,
|
|
2141
|
-
* tiles are recalculated to reflect the new configuration.
|
|
2142
|
-
*
|
|
2143
|
-
* @param options - Partial options object specifying which settings to change
|
|
2144
|
-
*
|
|
2145
|
-
* @example
|
|
2146
|
-
* ```typescript
|
|
2147
|
-
* // Reduce tile size and increase pool for smoother scrolling
|
|
2148
|
-
* vcanvas.setRenderingOptions({
|
|
2149
|
-
* tileWidthMultiplier: 0.25,
|
|
2150
|
-
* maxPoolSize: 8,
|
|
2151
|
-
* });
|
|
2152
|
-
*
|
|
2153
|
-
* // Restore defaults
|
|
2154
|
-
* vcanvas.setRenderingOptions({
|
|
2155
|
-
* tileWidthMultiplier: 0.5,
|
|
2156
|
-
* tilesBuffer: 2,
|
|
2157
|
-
* maxPoolSize: 5,
|
|
2158
|
-
* });
|
|
2159
|
-
* ```
|
|
2160
|
-
*/
|
|
2161
|
-
setRenderingOptions(options) {
|
|
2162
|
-
this._renderingOptions = {
|
|
2163
|
-
...this._renderingOptions,
|
|
2164
|
-
...options
|
|
2165
|
-
};
|
|
2166
|
-
this._recalculateTiles(`setRenderingOptions`);
|
|
2167
|
-
}
|
|
2168
|
-
/**
|
|
2169
|
-
* Gets the current rendering options.
|
|
2170
|
-
*
|
|
2171
|
-
* Returns a copy of the current configuration options controlling tile
|
|
2172
|
-
* rendering, pool management, and scroll behavior.
|
|
2173
|
-
*
|
|
2174
|
-
* @returns The current VCanvasRenderingOptions configuration
|
|
2175
|
-
*
|
|
2176
|
-
* @example
|
|
2177
|
-
* ```typescript
|
|
2178
|
-
* const options = vcanvas.getRenderingOptions();
|
|
2179
|
-
* console.log('Current tile width multiplier:', options.tileWidthMultiplier);
|
|
2180
|
-
* ```
|
|
2181
|
-
*/
|
|
2182
|
-
getRenderingOptions() {
|
|
2183
|
-
return this._renderingOptions;
|
|
2184
|
-
}
|
|
2185
|
-
/**
|
|
2186
|
-
* Forces a complete redraw of all visible tiles.
|
|
2187
|
-
*
|
|
2188
|
-
* Call this when the visual appearance of the content needs to change
|
|
2189
|
-
* but the logical dimensions remain the same. This aborts any pending
|
|
2190
|
-
* draw operations and triggers new ones for all visible tiles.
|
|
2191
|
-
*
|
|
2192
|
-
* @example
|
|
2193
|
-
* ```typescript
|
|
2194
|
-
* // Redraw after theme change
|
|
2195
|
-
* theme.addEventListener('change', () => {
|
|
2196
|
-
* vcanvas.invalidateAll();
|
|
2197
|
-
* });
|
|
2198
|
-
* ```
|
|
2199
|
-
*/
|
|
2200
|
-
invalidateAll() {
|
|
2201
|
-
this._requestRedrawAll(`invalidateAll`);
|
|
2202
|
-
}
|
|
2203
|
-
/**
|
|
2204
|
-
* Forces redraw of tiles that intersect with the specified region.
|
|
2205
|
-
*
|
|
2206
|
-
* Use this for partial invalidation when only a portion of the content
|
|
2207
|
-
* has changed. More efficient than invalidateAll() for localized updates.
|
|
2208
|
-
*
|
|
2209
|
-
* @param x - The x-coordinate of the region's left edge (logical coordinates)
|
|
2210
|
-
* @param y - The y-coordinate of the region's top edge (logical coordinates)
|
|
2211
|
-
* @param width - The width of the region to invalidate
|
|
2212
|
-
* @param height - The height of the region to invalidate
|
|
2213
|
-
*
|
|
2214
|
-
* @example
|
|
2215
|
-
* ```typescript
|
|
2216
|
-
* // Redraw a specific area after updating content
|
|
2217
|
-
* vcanvas.invalidateRegion(1000, 0, 500, 1000);
|
|
2218
|
-
* ```
|
|
2219
|
-
*/
|
|
2220
|
-
invalidateRegion(x, y, width, height) {
|
|
2221
|
-
this.#debug(`invalidateRegion: ${x},${y},${width},${height}`);
|
|
2222
|
-
const tileWidth = this._getTileWidth();
|
|
2223
|
-
const tileHeight = this._getTileHeight();
|
|
2224
|
-
const { firstTile, lastTile } = this._calculateTileRange();
|
|
2225
|
-
const { firstRow, lastRow } = this._calculateTileRowRange();
|
|
2226
|
-
const overlap = this._renderingOptions.overlapPercent;
|
|
2227
|
-
const startCol = Math.floor(x / tileWidth);
|
|
2228
|
-
const endCol = Math.ceil((x + width) / tileWidth);
|
|
2229
|
-
const startRow = Math.floor(y / tileHeight);
|
|
2230
|
-
const endRow = Math.ceil((y + height) / tileHeight);
|
|
2231
|
-
for (let col = Math.max(firstTile, startCol); col <= Math.min(lastTile, endCol); col++) for (let row = Math.max(firstRow, startRow); row <= Math.min(lastRow, endRow); row++) {
|
|
2232
|
-
const key = tileKey(col, row);
|
|
2233
|
-
if (this._visibleTiles.has(key)) {
|
|
2234
|
-
const tile = this._tilePool.get(key);
|
|
2235
|
-
if (tile) {
|
|
2236
|
-
const overlapX = tileWidth * overlap;
|
|
2237
|
-
const overlapY = tileHeight * overlap;
|
|
2238
|
-
const tileStartX = tile.logicalX - overlapX;
|
|
2239
|
-
const tileEndX = tile.logicalX + tileWidth + overlapX;
|
|
2240
|
-
const tileStartY = tile.logicalY - overlapY;
|
|
2241
|
-
const tileEndY = tile.logicalY + tileHeight + overlapY;
|
|
2242
|
-
const intersectX = Math.max(x, tileStartX);
|
|
2243
|
-
const intersectWidth = Math.min(x + width, tileEndX) - intersectX;
|
|
2244
|
-
const intersectY = Math.max(y, tileStartY);
|
|
2245
|
-
const intersectHeight = Math.min(y + height, tileEndY) - intersectY;
|
|
2246
|
-
if (intersectWidth > 0 && intersectHeight > 0) {
|
|
2247
|
-
const region = {
|
|
2248
|
-
x: intersectX,
|
|
2249
|
-
y: intersectY,
|
|
2250
|
-
width: intersectWidth,
|
|
2251
|
-
height: intersectHeight
|
|
2252
|
-
};
|
|
2253
|
-
this._requestTileDraw(`invalidateRegion`, key, region);
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
/**
|
|
2260
|
-
* Converts viewport-relative coordinates to canvas-relative (logical) coordinates.
|
|
2261
|
-
*
|
|
2262
|
-
* Viewport coordinates are relative to the visible area, while canvas coordinates
|
|
2263
|
-
* are in the logical coordinate system of the virtual canvas content.
|
|
2264
|
-
*
|
|
2265
|
-
* @param x - The x-coordinate in viewport space
|
|
2266
|
-
* @param y - The y-coordinate in viewport space
|
|
2267
|
-
* @returns The coordinates in canvas (logical) space
|
|
2268
|
-
*
|
|
2269
|
-
* @example
|
|
2270
|
-
* ```typescript
|
|
2271
|
-
* // Convert mouse position to logical coordinates for hit testing
|
|
2272
|
-
* vcanvas.addEventListener('click', (e) => {
|
|
2273
|
-
* const logical = vcanvas.convertFromViewportToCanvas(e.offsetX, e.offsetY);
|
|
2274
|
-
* console.log('Clicked at logical position:', logical.x);
|
|
2275
|
-
* });
|
|
2276
|
-
* ```
|
|
2277
|
-
*/
|
|
2278
|
-
convertFromViewportToCanvas(x, y) {
|
|
2279
|
-
const contentOffsetX = getContentOffset(this.effectiveLogicalWidth, this._viewportWidth);
|
|
2280
|
-
const contentOffsetY = getContentOffsetY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
2281
|
-
return viewportToCanvas(x, y, this._scrollLeft, contentOffsetX, this._scrollTop, contentOffsetY);
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Converts canvas-relative (logical) coordinates to viewport-relative coordinates.
|
|
2285
|
-
*
|
|
2286
|
-
* This is the inverse of `convertFromViewportToCanvas`. Use this to convert
|
|
2287
|
-
* logical positions back to viewport coordinates for positioning UI elements.
|
|
2288
|
-
*
|
|
2289
|
-
* @param x - The x-coordinate in logical space
|
|
2290
|
-
* @param y - The y-coordinate in logical space
|
|
2291
|
-
* @returns The coordinates in viewport space
|
|
2292
|
-
*
|
|
2293
|
-
* @example
|
|
2294
|
-
* ```typescript
|
|
2295
|
-
* // Convert logical marker position to viewport for tooltip positioning
|
|
2296
|
-
* const viewportPos = vcanvas.convertFromCanvasToViewport(markerX, 0);
|
|
2297
|
-
* tooltip.style.left = `${viewportPos.x}px`;
|
|
2298
|
-
* ```
|
|
2299
|
-
*/
|
|
2300
|
-
convertFromCanvasToViewport(x, y) {
|
|
2301
|
-
const contentOffsetX = getContentOffset(this.effectiveLogicalWidth, this._viewportWidth);
|
|
2302
|
-
const contentOffsetY = getContentOffsetY(this.effectiveLogicalHeight, this._viewportHeight);
|
|
2303
|
-
return canvasToViewport(x, y, this._scrollLeft, contentOffsetX, this._scrollTop, contentOffsetY);
|
|
2304
|
-
}
|
|
2305
|
-
/**
|
|
2306
|
-
* Positions light DOM child elements matching the query within a logical coordinate range.
|
|
2307
|
-
*
|
|
2308
|
-
* This method allows you to position HTML elements (like tooltips, markers, or overlays)
|
|
2309
|
-
* at specific logical coordinates within the virtual canvas. The elements will scroll
|
|
2310
|
-
* with the canvas content, maintaining their logical position.
|
|
2311
|
-
*
|
|
2312
|
-
* @param query - A CSS selector string to match child elements
|
|
2313
|
-
* @param startX - The starting x-coordinate in logical space
|
|
2314
|
-
* @param endX - The ending x-coordinate in logical space (determines width)
|
|
2315
|
-
* @param startY - The starting y-coordinate in logical space (optional)
|
|
2316
|
-
* @param endY - The ending y-coordinate in logical space (optional)
|
|
2317
|
-
*
|
|
2318
|
-
* @example
|
|
2319
|
-
* ```typescript
|
|
2320
|
-
* // Position a marker element at logical position x=200 spanning 200px
|
|
2321
|
-
* vcanvas.positionChildRange('#marker', 200, 400);
|
|
2322
|
-
*
|
|
2323
|
-
* // Position multiple elements with a class
|
|
2324
|
-
* vcanvas.positionChildRange('.timeline-item', 0, 1000);
|
|
2325
|
-
* ```
|
|
2326
|
-
*/
|
|
2327
|
-
positionChildRange(query, startX, endX, startY, endY) {
|
|
2328
|
-
if (Number.isNaN(startX) || Number.isNaN(endX)) {
|
|
2329
|
-
console.warn(`positionChildRange: Invalid startX or endX values: ${startX}, ${endX}`);
|
|
2330
|
-
return;
|
|
2331
|
-
}
|
|
2332
|
-
const children = Array.from(this.children).filter((child) => child.matches?.(query));
|
|
2333
|
-
const resolvedStartY = startY ?? 0;
|
|
2334
|
-
const resolvedEndY = endY ?? this.effectiveLogicalHeight;
|
|
2335
|
-
for (const child of children) this._positionedChildren.set(child, {
|
|
2336
|
-
startX,
|
|
2337
|
-
endX,
|
|
2338
|
-
startY: resolvedStartY,
|
|
2339
|
-
endY: resolvedEndY
|
|
2340
|
-
});
|
|
2341
|
-
this._positionChildren(`positionChildRange`);
|
|
2342
|
-
}
|
|
2343
|
-
/**
|
|
2344
|
-
* Manually triggers an update of child element positioning.
|
|
2345
|
-
*
|
|
2346
|
-
* This is useful when the viewport dimensions have changed outside the normal
|
|
2347
|
-
* update cycle and you need to reposition slotted children immediately.
|
|
2348
|
-
* Normally, child positioning is automatically updated during scroll and resize.
|
|
2349
|
-
*
|
|
2350
|
-
* @example
|
|
2351
|
-
* ```typescript
|
|
2352
|
-
* // Force immediate update after custom layout changes
|
|
2353
|
-
* vcanvas.manualChildPositioningUpdate();
|
|
2354
|
-
* ```
|
|
2355
|
-
*/
|
|
2356
|
-
manualChildPositioningUpdate() {
|
|
2357
|
-
this._positionChildren(`manualChildPositioningUpdate`);
|
|
2358
|
-
}
|
|
2359
|
-
/**
|
|
2360
|
-
* Stops positioning child elements matching the query and resets their styles.
|
|
2361
|
-
*
|
|
2362
|
-
* This removes children from the positioning system and clears any inline
|
|
2363
|
-
* styles that were applied by `positionChildRange()`. The children remain
|
|
2364
|
-
* in the DOM but are no longer positioned by the virtual canvas.
|
|
2365
|
-
*
|
|
2366
|
-
* @param query - A CSS selector string to match child elements
|
|
2367
|
-
*
|
|
2368
|
-
* @example
|
|
2369
|
-
* ```typescript
|
|
2370
|
-
* // Stop positioning a specific child element
|
|
2371
|
-
* vcanvas.positionChildClear('#child-0');
|
|
2372
|
-
*
|
|
2373
|
-
* // Stop positioning all children with a specific class
|
|
2374
|
-
* vcanvas.positionChildClear('.my-element');
|
|
2375
|
-
* ```
|
|
2376
|
-
*/
|
|
2377
|
-
positionChildClear(query) {
|
|
2378
|
-
for (const [child] of this._positionedChildren) if (child.matches?.(query)) {
|
|
2379
|
-
this._positionedChildren.delete(child);
|
|
2380
|
-
child.removeAttribute(`style`);
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
_positionChildren(source) {
|
|
2384
|
-
this.#debug(`_positionChildren: ${source} positionedChildren: ${this._positionedChildren.size}`);
|
|
2385
|
-
if (!this.hasUpdated) return;
|
|
2386
|
-
if (!this._childrenContainerEl) return;
|
|
2387
|
-
for (const [child, config] of this._positionedChildren) {
|
|
2388
|
-
const width = config.endX - config.startX;
|
|
2389
|
-
const height = config.endY - config.startY;
|
|
2390
|
-
child.setAttribute(`style`, `position: absolute; left: ${config.startX}px; top: ${config.startY}px; width: ${width}px; height: ${height}px;`);
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
render() {
|
|
2394
|
-
return html`
|
|
2395
|
-
<div class=${classMap({
|
|
2396
|
-
"scroll-container": true,
|
|
2397
|
-
"scrollable": this.hinting
|
|
2398
|
-
})}>
|
|
2399
|
-
<div class="spacer"></div>
|
|
2400
|
-
<div class="tile-pool"></div>
|
|
2401
|
-
<div class="children-container">
|
|
2402
|
-
<slot></slot>
|
|
2403
|
-
</div>
|
|
2404
|
-
</div>
|
|
2405
|
-
`;
|
|
2406
|
-
}
|
|
2407
|
-
};
|
|
2408
|
-
__decorate([property({ type: Boolean })], VCanvas.prototype, "hinting", void 0);
|
|
2409
|
-
__decorate([property()], VCanvas.prototype, "logicalWidth", null);
|
|
2410
|
-
__decorate([property()], VCanvas.prototype, "logicalHeight", null);
|
|
2411
|
-
__decorate([property({ type: Number })], VCanvas.prototype, "logicalScrollLeft", null);
|
|
2412
|
-
__decorate([property({ type: Number })], VCanvas.prototype, "logicalScrollTop", null);
|
|
2413
|
-
VCanvas = __decorate([customElement(`x-vcanvas`)], VCanvas);
|
|
1012
|
+
TimelineTrackTabElement = __decorate([safeCustomElement(`ixfx-timeline-track-tab`)], TimelineTrackTabElement);
|
|
2414
1013
|
//#endregion
|
|
2415
1014
|
//#region src/timeline/timeline-element.ts
|
|
2416
1015
|
/** Reasonable maximum ppu to prevent infinite zoom-in */
|
|
@@ -3100,54 +1699,54 @@ let IxfxTimelineElement = class IxfxTimelineElement extends LitElement {
|
|
|
3100
1699
|
}));
|
|
3101
1700
|
}
|
|
3102
1701
|
};
|
|
3103
|
-
__decorate
|
|
3104
|
-
__decorate
|
|
3105
|
-
__decorate
|
|
3106
|
-
__decorate
|
|
3107
|
-
__decorate
|
|
1702
|
+
__decorate([property({ type: Array })], IxfxTimelineElement.prototype, "tracks", void 0);
|
|
1703
|
+
__decorate([property({ type: Array })], IxfxTimelineElement.prototype, "events", void 0);
|
|
1704
|
+
__decorate([property({ type: Number })], IxfxTimelineElement.prototype, "min", void 0);
|
|
1705
|
+
__decorate([property({ type: Number })], IxfxTimelineElement.prototype, "max", void 0);
|
|
1706
|
+
__decorate([property({
|
|
3108
1707
|
type: String,
|
|
3109
1708
|
attribute: `track-height`
|
|
3110
1709
|
})], IxfxTimelineElement.prototype, "trackHeight", void 0);
|
|
3111
|
-
__decorate
|
|
1710
|
+
__decorate([property({
|
|
3112
1711
|
type: String,
|
|
3113
1712
|
attribute: `user-scale`
|
|
3114
1713
|
})], IxfxTimelineElement.prototype, "userScale", void 0);
|
|
3115
|
-
__decorate
|
|
3116
|
-
__decorate
|
|
1714
|
+
__decorate([property({ type: Boolean })], IxfxTimelineElement.prototype, "reorderable", void 0);
|
|
1715
|
+
__decorate([property({
|
|
3117
1716
|
type: Boolean,
|
|
3118
1717
|
attribute: `meta`
|
|
3119
1718
|
})], IxfxTimelineElement.prototype, "metaEnabled", void 0);
|
|
3120
|
-
__decorate
|
|
1719
|
+
__decorate([property({
|
|
3121
1720
|
type: Boolean,
|
|
3122
1721
|
attribute: `alt-major-bg`
|
|
3123
1722
|
})], IxfxTimelineElement.prototype, "altMajorBg", void 0);
|
|
3124
|
-
__decorate
|
|
1723
|
+
__decorate([property({
|
|
3125
1724
|
type: Number,
|
|
3126
1725
|
attribute: `default-track-height`
|
|
3127
1726
|
})], IxfxTimelineElement.prototype, "defaultTrackHeight", void 0);
|
|
3128
|
-
__decorate
|
|
1727
|
+
__decorate([property({
|
|
3129
1728
|
type: String,
|
|
3130
1729
|
attribute: `grid-mode`
|
|
3131
1730
|
})], IxfxTimelineElement.prototype, "gridMode", void 0);
|
|
3132
|
-
__decorate
|
|
1731
|
+
__decorate([property({
|
|
3133
1732
|
type: Number,
|
|
3134
1733
|
attribute: `minor-step`
|
|
3135
1734
|
})], IxfxTimelineElement.prototype, "minorStep", void 0);
|
|
3136
|
-
__decorate
|
|
3137
|
-
__decorate
|
|
3138
|
-
__decorate
|
|
3139
|
-
__decorate
|
|
3140
|
-
__decorate
|
|
3141
|
-
__decorate
|
|
3142
|
-
__decorate
|
|
3143
|
-
__decorate
|
|
3144
|
-
__decorate
|
|
3145
|
-
__decorate
|
|
3146
|
-
__decorate
|
|
3147
|
-
__decorate
|
|
3148
|
-
__decorate
|
|
3149
|
-
IxfxTimelineElement = __decorate
|
|
1735
|
+
__decorate([property({ type: Object })], IxfxTimelineElement.prototype, "onDragging", void 0);
|
|
1736
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_ppu", void 0);
|
|
1737
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_viewRange", void 0);
|
|
1738
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_vViewRange", void 0);
|
|
1739
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_vScale", void 0);
|
|
1740
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_selectedIds", void 0);
|
|
1741
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_tickledId", void 0);
|
|
1742
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_drag", void 0);
|
|
1743
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_metaHeight", void 0);
|
|
1744
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_trackHeightOverrides", void 0);
|
|
1745
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_trackLayout", void 0);
|
|
1746
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_internalEvents", void 0);
|
|
1747
|
+
__decorate([state()], IxfxTimelineElement.prototype, "_internalTracks", void 0);
|
|
1748
|
+
IxfxTimelineElement = __decorate([safeCustomElement(`ixfx-timeline`)], IxfxTimelineElement);
|
|
3150
1749
|
//#endregion
|
|
3151
1750
|
export { resolveCssVars as a, attachTimelineInteractions as i, TimelineTrackTabElement as n, resolveGrid as o, timelineStyles as r, TimelineController as s, IxfxTimelineElement as t };
|
|
3152
1751
|
|
|
3153
|
-
//# sourceMappingURL=timeline-
|
|
1752
|
+
//# sourceMappingURL=timeline-B2fgDL4U.js.map
|