@ixfx/components 0.2.6 → 0.3.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/bundle/index.d.ts +213 -117
- package/bundle/index.d.ts.map +1 -1
- package/bundle/index.js +1356 -658
- package/bundle/index.js.map +1 -1
- package/dist/ac-text.js +3 -3
- package/dist/ac-text.js.map +1 -1
- package/dist/{button-B9ztaKyl.js → button-DMt5XWUK.js} +4 -4
- package/dist/{button-B9ztaKyl.js.map → button-DMt5XWUK.js.map} +1 -1
- package/dist/button.js +1 -1
- package/dist/checkbox.d.ts +2 -3
- package/dist/checkbox.d.ts.map +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.js.map +1 -1
- package/dist/{colour-C3MQIjFJ-BJV-QC-3.js → colour-C3MQIjFJ-BLXg8W3U.js} +2 -2
- package/dist/{colour-C3MQIjFJ-BJV-QC-3.js.map → colour-C3MQIjFJ-BLXg8W3U.js.map} +1 -1
- package/dist/{colour-picker-BNqDz4wK.js → colour-picker-K6zu82lm.js} +5 -5
- package/dist/{colour-picker-BNqDz4wK.js.map → colour-picker-K6zu82lm.js.map} +1 -1
- package/dist/colour-picker.js +1 -1
- package/dist/crumbs.d.ts +2 -3
- package/dist/crumbs.d.ts.map +1 -1
- package/dist/crumbs.js +10 -10
- package/dist/crumbs.js.map +1 -1
- package/dist/data-display.js +3 -3
- package/dist/{decorate-O4m1U4l3.js → decorate-D7rC1gLP.js} +10 -8
- package/dist/decorate-D7rC1gLP.js.map +1 -0
- package/dist/{defaults-FEZaGiYZ.js → defaults-C7elhuyJ.js} +2 -2
- package/dist/{defaults-FEZaGiYZ.js.map → defaults-C7elhuyJ.js.map} +1 -1
- package/dist/{dist-By5URG0Y.js → dist-BX0OVIm7.js} +2 -2
- package/dist/{dist-By5URG0Y.js.map → dist-BX0OVIm7.js.map} +1 -1
- package/dist/{dist-D7kJgnSE.js → dist-TAGYwaju.js} +1 -1
- package/dist/{dist-D7kJgnSE.js.map → dist-TAGYwaju.js.map} +1 -1
- package/dist/editable-label.d.ts +6 -1
- package/dist/editable-label.d.ts.map +1 -1
- package/dist/editable-label.js +49 -2
- package/dist/editable-label.js.map +1 -1
- package/dist/{hex-editor-gH3mteMr.js → hex-editor-CsN_ySkH.js} +85 -85
- package/dist/hex-editor-CsN_ySkH.js.map +1 -0
- package/dist/{hex-editor-2_s0Ua5t.d.ts → hex-editor-DlfoA65y.d.ts} +5 -5
- package/dist/{hex-editor-2_s0Ua5t.d.ts.map → hex-editor-DlfoA65y.d.ts.map} +1 -1
- package/dist/hex.d.ts +1 -1
- package/dist/hex.js +1 -1
- package/dist/{highlight-CAjwQ4GE.js → highlight-TPbSHruI.js} +3 -3
- package/dist/highlight-TPbSHruI.js.map +1 -0
- package/dist/{icon-CYACf6o8.js → icon-9NWTXtE1.js} +4 -5
- package/dist/icon-9NWTXtE1.js.map +1 -0
- package/dist/icon-CeTDJhC7.d.ts.map +1 -1
- package/dist/icons.js +3 -3
- package/dist/{incr-search-BZawvrfl.js → incr-search-DSKKsk6w.js} +12 -10
- package/dist/incr-search-DSKKsk6w.js.map +1 -0
- package/dist/incr-search.d.ts +1 -1
- package/dist/incr-search.js +2 -2
- package/dist/{index-CwGkb9s1.d.ts → index--hrxPBkQ.d.ts} +69 -69
- package/dist/index--hrxPBkQ.d.ts.map +1 -0
- package/dist/{index-kY5gxbkI.d.ts → index-DSlPeWLK.d.ts} +15 -15
- package/dist/{index-kY5gxbkI.d.ts.map → index-DSlPeWLK.d.ts.map} +1 -1
- package/dist/{index-V2cJorlA.d.ts → index-hXFn14tM.d.ts} +4 -4
- package/dist/index-hXFn14tM.d.ts.map +1 -0
- package/dist/index.d.ts +109 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +666 -24
- package/dist/index.js.map +1 -1
- package/dist/keyboard-De_vOHLg.js.map +1 -1
- package/dist/{labelled-input-base-BvgH7ldm.js → labelled-input-base-CqPL5rKm.js} +2 -2
- package/dist/labelled-input-base-CqPL5rKm.js.map +1 -0
- package/dist/labelled-radial-input.js +3 -3
- package/dist/labelled-radial-input.js.map +1 -1
- package/dist/labelled-range-input.js +2 -2
- package/dist/led.js +1 -1
- package/dist/{menu-C3eANB5M.js → menu-DJJuCm-5.js} +48 -48
- package/dist/menu-DJJuCm-5.js.map +1 -0
- package/dist/{menu-item-6IU5weHi.js → menu-item-CKRfP0pN.js} +10 -10
- package/dist/menu-item-CKRfP0pN.js.map +1 -0
- package/dist/menu.d.ts +1 -1
- package/dist/menu.js +2 -2
- package/dist/miller.d.ts +5 -7
- package/dist/miller.d.ts.map +1 -1
- package/dist/miller.js +14 -14
- package/dist/miller.js.map +1 -1
- package/dist/narrowed-text.d.ts.map +1 -1
- package/dist/narrowed-text.js +4 -4
- package/dist/narrowed-text.js.map +1 -1
- package/dist/panel.js +2 -2
- package/dist/panel.js.map +1 -1
- package/dist/plots.js +1 -1
- package/dist/polar-pad.d.ts.map +1 -1
- package/dist/polar-pad.js +1 -1
- package/dist/polar-pad.js.map +1 -1
- package/dist/{popup-Ddx9LCzY.js → popup-ImtS9KnS.js} +1 -1
- package/dist/{popup-Ddx9LCzY.js.map → popup-ImtS9KnS.js.map} +1 -1
- package/dist/{prominence-CreDBdCs.js → prominence--ic9uWBl.js} +1 -1
- package/dist/{prominence-CreDBdCs.js.map → prominence--ic9uWBl.js.map} +1 -1
- package/dist/{radial-input-Dbc6fgCK.js → radial-input-DZA6WaFu.js} +14 -14
- package/dist/radial-input-DZA6WaFu.js.map +1 -0
- package/dist/radial-input.js +1 -1
- package/dist/range-input.js +1 -1
- package/dist/range.js +2 -2
- package/dist/{registry-CZEB1YI9.js → registry-Q2gYQCHM.js} +1 -1
- package/dist/{registry-CZEB1YI9.js.map → registry-Q2gYQCHM.js.map} +1 -1
- package/dist/selecthorizontal.js +1 -1
- package/dist/snap-container.js +1 -1
- package/dist/split-layout.js +4 -4
- package/dist/split-layout.js.map +1 -1
- package/dist/swipe.d.ts +1 -2
- package/dist/swipe.d.ts.map +1 -1
- package/dist/swipe.js +2 -2
- package/dist/swipe.js.map +1 -1
- package/dist/tabs.js +2 -2
- package/dist/tabs.js.map +1 -1
- package/dist/{timeline-B62Sz6J_.js → timeline-Cv75Th2U.js} +120 -116
- package/dist/timeline-Cv75Th2U.js.map +1 -0
- package/dist/timeline.d.ts +1 -1
- package/dist/timeline.js +1 -1
- package/dist/tooltip-CwGfb4lp.d.ts.map +1 -1
- package/dist/tree-CvvKbO-f.js +1330 -0
- package/dist/tree-CvvKbO-f.js.map +1 -0
- package/dist/{tree-component-CQpoPo4s.d.ts → tree-component-D8Bg48tt.d.ts} +12 -12
- package/dist/{tree-component-CQpoPo4s.d.ts.map → tree-component-D8Bg48tt.d.ts.map} +1 -1
- package/dist/tree.d.ts +1 -1
- package/dist/tree.js +1 -1143
- package/dist/xy-axis-D9uwpGTT.d.ts.map +1 -1
- package/dist/{xy-axis-C7fNxDwY.js → xy-axis-DL0tfJDr.js} +10 -10
- package/dist/{xy-axis-C7fNxDwY.js.map → xy-axis-DL0tfJDr.js.map} +1 -1
- package/dist/xy-pad.js +2 -2
- package/package.json +3 -3
- package/dist/decorate-O4m1U4l3.js.map +0 -1
- package/dist/hex-editor-gH3mteMr.js.map +0 -1
- package/dist/highlight-CAjwQ4GE.js.map +0 -1
- package/dist/icon-CYACf6o8.js.map +0 -1
- package/dist/incr-search-BZawvrfl.js.map +0 -1
- package/dist/index-CwGkb9s1.d.ts.map +0 -1
- package/dist/index-V2cJorlA.d.ts.map +0 -1
- package/dist/labelled-input-base-BvgH7ldm.js.map +0 -1
- package/dist/menu-C3eANB5M.js.map +0 -1
- package/dist/menu-item-6IU5weHi.js.map +0 -1
- package/dist/radial-input-Dbc6fgCK.js.map +0 -1
- package/dist/timeline-B62Sz6J_.js.map +0 -1
- package/dist/tree-data-model-DGvRVOFY.js +0 -190
- package/dist/tree-data-model-DGvRVOFY.js.map +0 -1
- package/dist/tree.js.map +0 -1
- /package/dist/{interaction-CQDQJf2Q.js → interaction-DG7X1rhI.js} +0 -0
|
@@ -1,7 +1,71 @@
|
|
|
1
|
-
import { n as safeCustomElement, t as __decorate } from "./decorate-
|
|
1
|
+
import { n as safeCustomElement, t as __decorate } from "./decorate-D7rC1gLP.js";
|
|
2
2
|
import { LitElement, css, html, nothing } from "lit";
|
|
3
3
|
import { property, state } from "lit/decorators.js";
|
|
4
4
|
import "@clinth/vcanvas";
|
|
5
|
+
//#region src/timeline/timeline-controller.ts
|
|
6
|
+
/**
|
|
7
|
+
* External adapter class that can configure a timeline element
|
|
8
|
+
* with musical time, custom label formatting, etc.
|
|
9
|
+
*
|
|
10
|
+
* The controller has no import of any timeline element type.
|
|
11
|
+
* Users create a controller, pass it the component instance,
|
|
12
|
+
* and the controller calls the component's public API.
|
|
13
|
+
*/
|
|
14
|
+
var TimelineController = class {
|
|
15
|
+
#host;
|
|
16
|
+
#config;
|
|
17
|
+
#bpm = 120;
|
|
18
|
+
#timeSignatureNumerator = 4;
|
|
19
|
+
#timeSignatureDenominator = 4;
|
|
20
|
+
constructor(timeline, config) {
|
|
21
|
+
this.#host = timeline;
|
|
22
|
+
this.#config = config;
|
|
23
|
+
timeline.min = config.logicalMin;
|
|
24
|
+
timeline.max = config.logicalMax;
|
|
25
|
+
if (config.labelFormatter) timeline.formatLabel = config.labelFormatter;
|
|
26
|
+
timeline.addEventListener(`track-select`, this.#onTrackSelect);
|
|
27
|
+
}
|
|
28
|
+
/** Update the tempo (BPM) for musical time calculations. */
|
|
29
|
+
setTempo(bpm) {
|
|
30
|
+
this.#bpm = bpm;
|
|
31
|
+
this.#updateFormatLabel();
|
|
32
|
+
}
|
|
33
|
+
/** Update the time signature for musical time calculations. */
|
|
34
|
+
setTimeSignature(numerator, denominator) {
|
|
35
|
+
this.#timeSignatureNumerator = numerator;
|
|
36
|
+
this.#timeSignatureDenominator = denominator;
|
|
37
|
+
this.#updateFormatLabel();
|
|
38
|
+
}
|
|
39
|
+
/** Set the visible view range on the timeline. */
|
|
40
|
+
setViewRange(range) {
|
|
41
|
+
this.#host.setViewRange(range);
|
|
42
|
+
}
|
|
43
|
+
/** Clean up any resources held by the controller. */
|
|
44
|
+
dispose() {
|
|
45
|
+
this.#host.removeEventListener(`track-select`, this.#onTrackSelect);
|
|
46
|
+
}
|
|
47
|
+
#onTrackSelect = (e) => {
|
|
48
|
+
const detail = e.detail;
|
|
49
|
+
const trackEventIds = this.#host.getTrackEvents(detail.trackKey).map((e) => e.id);
|
|
50
|
+
if (detail.shiftKey) {
|
|
51
|
+
const current = new Set(this.#host.selectedIds);
|
|
52
|
+
for (const id of trackEventIds) if (current.has(id)) current.delete(id);
|
|
53
|
+
else current.add(id);
|
|
54
|
+
this.#host.selectedIds = [...current];
|
|
55
|
+
} else this.#host.selectedIds = trackEventIds;
|
|
56
|
+
};
|
|
57
|
+
#updateFormatLabel() {
|
|
58
|
+
if (this.#config.labelFormatter) return;
|
|
59
|
+
this.#bpm;
|
|
60
|
+
const num = this.#timeSignatureNumerator;
|
|
61
|
+
this.#host.formatLabel = (v) => {
|
|
62
|
+
const beatsPerBar = num;
|
|
63
|
+
const totalBeats = v;
|
|
64
|
+
return `${Math.floor(totalBeats / beatsPerBar) + 1}.${Math.floor(totalBeats % beatsPerBar) + 1}`;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
5
69
|
//#region src/timeline/timeline-draw.ts
|
|
6
70
|
const NICE_STEPS = [
|
|
7
71
|
1,
|
|
@@ -12,15 +76,15 @@ const NICE_STEPS = [
|
|
|
12
76
|
/**
|
|
13
77
|
* Dispatch to adaptive or fixed grid mode.
|
|
14
78
|
*/
|
|
15
|
-
|
|
79
|
+
function resolveGrid(viewRange, userScale, viewportWidth, mode = `adaptive`, fixedMinorStep, ppu) {
|
|
16
80
|
if (mode === `fixed` && fixedMinorStep !== void 0 && ppu !== void 0) return resolveFixedGrid(fixedMinorStep, ppu);
|
|
17
81
|
return resolveAdaptiveGrid(viewRange, userScale, viewportWidth);
|
|
18
|
-
}
|
|
82
|
+
}
|
|
19
83
|
/**
|
|
20
84
|
* Compute a nice major/minor grid resolution for the current view.
|
|
21
85
|
* Uses a 1-2-5-10 "nice number" algorithm.
|
|
22
86
|
*/
|
|
23
|
-
|
|
87
|
+
function resolveAdaptiveGrid(viewRange, userScale, viewportWidth) {
|
|
24
88
|
const span = viewRange.max - viewRange.min;
|
|
25
89
|
if (span <= 0 || viewportWidth <= 0) return {
|
|
26
90
|
majorStep: 100,
|
|
@@ -29,7 +93,7 @@ const resolveAdaptiveGrid = (viewRange, userScale, viewportWidth) => {
|
|
|
29
93
|
};
|
|
30
94
|
const targetPx = 80 * scaleMultiplier(userScale);
|
|
31
95
|
const rawStep = span / Math.max(2, Math.floor(viewportWidth / targetPx));
|
|
32
|
-
const magnitude =
|
|
96
|
+
const magnitude = 10 ** Math.floor(Math.log10(rawStep));
|
|
33
97
|
let bestStep = magnitude;
|
|
34
98
|
for (const n of NICE_STEPS) {
|
|
35
99
|
const candidate = n * magnitude;
|
|
@@ -46,14 +110,14 @@ const resolveAdaptiveGrid = (viewRange, userScale, viewportWidth) => {
|
|
|
46
110
|
minorDivisions,
|
|
47
111
|
minorStep
|
|
48
112
|
};
|
|
49
|
-
}
|
|
113
|
+
}
|
|
50
114
|
/**
|
|
51
115
|
* Fixed grid: user specifies a base minor step in logical units.
|
|
52
116
|
* If the minor step at current zoom would produce lines < 5px apart,
|
|
53
117
|
* double the effective step until they're >= 5px.
|
|
54
118
|
* Major = 4× effective minor.
|
|
55
119
|
*/
|
|
56
|
-
|
|
120
|
+
function resolveFixedGrid(baseMinorStep, ppu) {
|
|
57
121
|
const MIN_PX_BETWEEN = 5;
|
|
58
122
|
let effectiveMinor = baseMinorStep;
|
|
59
123
|
while (effectiveMinor * ppu < MIN_PX_BETWEEN && effectiveMinor < 0xe8d4a51000) effectiveMinor *= 2;
|
|
@@ -63,8 +127,8 @@ const resolveFixedGrid = (baseMinorStep, ppu) => {
|
|
|
63
127
|
minorDivisions,
|
|
64
128
|
minorStep: effectiveMinor
|
|
65
129
|
};
|
|
66
|
-
}
|
|
67
|
-
|
|
130
|
+
}
|
|
131
|
+
function scaleMultiplier(scale) {
|
|
68
132
|
switch (scale) {
|
|
69
133
|
case `x-wide`: return 2;
|
|
70
134
|
case `wide`: return 1.5;
|
|
@@ -73,8 +137,8 @@ const scaleMultiplier = (scale) => {
|
|
|
73
137
|
case `x-slim`: return .5;
|
|
74
138
|
default: return 1;
|
|
75
139
|
}
|
|
76
|
-
}
|
|
77
|
-
|
|
140
|
+
}
|
|
141
|
+
function drawMajorMinorGrid(ctx, region, resolution, altMajorBg, vars, ppu) {
|
|
78
142
|
const { majorStep, minorStep } = resolution;
|
|
79
143
|
if (majorStep <= 0) return;
|
|
80
144
|
const regionEnd = region.x + region.width;
|
|
@@ -88,7 +152,7 @@ const drawMajorMinorGrid = (ctx, region, resolution, altMajorBg, vars, ppu) => {
|
|
|
88
152
|
}
|
|
89
153
|
if (minorStep > 0) {
|
|
90
154
|
ctx.strokeStyle = vars[`--timeline-grid-minor-color`] ?? `rgba(255,255,255,0.05)`;
|
|
91
|
-
ctx.lineWidth = parseFloat(vars[`--timeline-grid-minor-width`] ?? `0.5`);
|
|
155
|
+
ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-minor-width`] ?? `0.5`);
|
|
92
156
|
ctx.beginPath();
|
|
93
157
|
const firstMinor = Math.floor(region.x / minorStep) * minorStep;
|
|
94
158
|
for (let val = firstMinor; val < regionEnd; val += minorStep) {
|
|
@@ -100,7 +164,7 @@ const drawMajorMinorGrid = (ctx, region, resolution, altMajorBg, vars, ppu) => {
|
|
|
100
164
|
ctx.stroke();
|
|
101
165
|
}
|
|
102
166
|
ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;
|
|
103
|
-
ctx.lineWidth = parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);
|
|
167
|
+
ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);
|
|
104
168
|
ctx.beginPath();
|
|
105
169
|
const firstMajor = Math.floor(region.x / majorStep) * majorStep;
|
|
106
170
|
for (let val = firstMajor; val < regionEnd; val += majorStep) {
|
|
@@ -109,13 +173,13 @@ const drawMajorMinorGrid = (ctx, region, resolution, altMajorBg, vars, ppu) => {
|
|
|
109
173
|
ctx.lineTo(px, region.y + region.height);
|
|
110
174
|
}
|
|
111
175
|
ctx.stroke();
|
|
112
|
-
}
|
|
176
|
+
}
|
|
113
177
|
/**
|
|
114
178
|
* Draw the axis header band. With 2D virtualization the axis is "sticky" —
|
|
115
179
|
* it is always drawn at the current vertical scroll position (`scrollTop`)
|
|
116
180
|
* so it appears fixed at the viewport top.
|
|
117
181
|
*/
|
|
118
|
-
|
|
182
|
+
function drawAxis(ctx, region, resolution, axisHeight, formatLabel, vars, ppu, scrollTop = 0) {
|
|
119
183
|
const { majorStep } = resolution;
|
|
120
184
|
if (majorStep <= 0 || axisHeight <= 0) return;
|
|
121
185
|
const axisTop = scrollTop;
|
|
@@ -127,7 +191,7 @@ const drawAxis = (ctx, region, resolution, axisHeight, formatLabel, vars, ppu, s
|
|
|
127
191
|
const bgLeft = region.x * ppu;
|
|
128
192
|
ctx.fillRect(bgLeft, axisTop, region.width * ppu, bgHeight);
|
|
129
193
|
ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;
|
|
130
|
-
ctx.lineWidth = parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);
|
|
194
|
+
ctx.lineWidth = Number.parseFloat(vars[`--timeline-grid-major-width`] ?? `1`);
|
|
131
195
|
ctx.beginPath();
|
|
132
196
|
const firstMajor = Math.ceil(region.x / majorStep) * majorStep;
|
|
133
197
|
for (let val = firstMajor; val < regionEnd; val += majorStep) {
|
|
@@ -152,8 +216,8 @@ const drawAxis = (ctx, region, resolution, axisHeight, formatLabel, vars, ppu, s
|
|
|
152
216
|
ctx.fillText(formatLabel(val), px + labelPadding, axisTop + bgHeight / 2);
|
|
153
217
|
}
|
|
154
218
|
ctx.textAlign = `start`;
|
|
155
|
-
}
|
|
156
|
-
|
|
219
|
+
}
|
|
220
|
+
function drawTrackBackgrounds(ctx, region, trackLayout, tracks, vars, ppu) {
|
|
157
221
|
const bgDefault = vars[`--timeline-track-bg`] ?? `#1a1a1a`;
|
|
158
222
|
const bgAlt = vars[`--timeline-track-bg-alt`] ?? `#1e1e1e`;
|
|
159
223
|
for (let i = 0; i < trackLayout.length; i++) {
|
|
@@ -161,7 +225,7 @@ const drawTrackBackgrounds = (ctx, region, trackLayout, tracks, vars, ppu) => {
|
|
|
161
225
|
if (layout.y + layout.height < region.y) continue;
|
|
162
226
|
if (layout.y > region.y + region.height) break;
|
|
163
227
|
const track = tracks.find((t) => t.key === layout.trackKey);
|
|
164
|
-
ctx.fillStyle = track?.color ? track.color
|
|
228
|
+
ctx.fillStyle = track?.color ? `${track.color}22` : i % 2 === 0 ? bgDefault : bgAlt;
|
|
165
229
|
ctx.fillRect(region.x * ppu, layout.y, region.width * ppu, layout.height);
|
|
166
230
|
ctx.strokeStyle = vars[`--timeline-grid-major-color`] ?? `rgba(255,255,255,0.12)`;
|
|
167
231
|
ctx.lineWidth = .5;
|
|
@@ -170,13 +234,13 @@ const drawTrackBackgrounds = (ctx, region, trackLayout, tracks, vars, ppu) => {
|
|
|
170
234
|
ctx.lineTo((region.x + region.width) * ppu, layout.y + layout.height);
|
|
171
235
|
ctx.stroke();
|
|
172
236
|
}
|
|
173
|
-
}
|
|
174
|
-
|
|
237
|
+
}
|
|
238
|
+
function drawEventRects(ctx, region, events, trackLayout, selectedIds, tickledId, drag, vars, ppu) {
|
|
175
239
|
const eventBg = vars[`--timeline-event-bg`] ?? `#3498db`;
|
|
176
240
|
const eventSelectedBg = vars[`--timeline-event-selected-bg`] ?? `#5dade2`;
|
|
177
241
|
const eventTickledBg = vars[`--timeline-event-tickled-bg`] ?? `#444`;
|
|
178
242
|
const eventLabelColor = vars[`--timeline-event-label-color`] ?? `#fff`;
|
|
179
|
-
const radius = parseFloat(vars[`--timeline-event-radius`] ?? `4`);
|
|
243
|
+
const radius = Number.parseFloat(vars[`--timeline-event-radius`] ?? `4`);
|
|
180
244
|
const regionEnd = region.x + region.width;
|
|
181
245
|
const padding = 3;
|
|
182
246
|
for (const evt of events) {
|
|
@@ -230,8 +294,8 @@ const drawEventRects = (ctx, region, events, trackLayout, selectedIds, tickledId
|
|
|
230
294
|
ctx.restore();
|
|
231
295
|
}
|
|
232
296
|
}
|
|
233
|
-
}
|
|
234
|
-
|
|
297
|
+
}
|
|
298
|
+
function drawMarquee(ctx, drag, ppu) {
|
|
235
299
|
if (drag.kind !== `marquee`) return;
|
|
236
300
|
const x1 = Math.min(drag.startLogicalX, drag.currentLogicalX) * ppu;
|
|
237
301
|
const x2 = Math.max(drag.startLogicalX, drag.currentLogicalX) * ppu;
|
|
@@ -242,8 +306,8 @@ const drawMarquee = (ctx, drag, ppu) => {
|
|
|
242
306
|
ctx.strokeStyle = `rgba(100, 150, 255, 0.6)`;
|
|
243
307
|
ctx.lineWidth = 1;
|
|
244
308
|
ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
|
|
245
|
-
}
|
|
246
|
-
|
|
309
|
+
}
|
|
310
|
+
function drawRoundRect(ctx, x, y, w, h, r) {
|
|
247
311
|
r = Math.max(0, r);
|
|
248
312
|
ctx.moveTo(x + r, y);
|
|
249
313
|
ctx.arcTo(x + w, y, x + w, y + h, r);
|
|
@@ -251,7 +315,7 @@ const drawRoundRect = (ctx, x, y, w, h, r) => {
|
|
|
251
315
|
ctx.arcTo(x, y + h, x, y, r);
|
|
252
316
|
ctx.arcTo(x, y, x + w, y, r);
|
|
253
317
|
ctx.closePath();
|
|
254
|
-
}
|
|
318
|
+
}
|
|
255
319
|
const TIMELINE_CSS_VARS = [
|
|
256
320
|
`--timeline-bg`,
|
|
257
321
|
`--timeline-track-bg`,
|
|
@@ -268,12 +332,12 @@ const TIMELINE_CSS_VARS = [
|
|
|
268
332
|
`--timeline-event-radius`,
|
|
269
333
|
`--timeline-axis-label-color`
|
|
270
334
|
];
|
|
271
|
-
|
|
335
|
+
function resolveCssVars(host) {
|
|
272
336
|
const computed = getComputedStyle(host);
|
|
273
337
|
const vars = {};
|
|
274
338
|
for (const v of TIMELINE_CSS_VARS) vars[v] = computed.getPropertyValue(v).trim();
|
|
275
339
|
return vars;
|
|
276
|
-
}
|
|
340
|
+
}
|
|
277
341
|
//#endregion
|
|
278
342
|
//#region src/timeline/timeline-interactions.ts
|
|
279
343
|
/** Hit zone near the edge of an event (px in screen space) */
|
|
@@ -282,13 +346,17 @@ const EDGE_HIT_PX = 8;
|
|
|
282
346
|
* Convert a vcanvas logical (pixel) coordinate to timeline logical units.
|
|
283
347
|
* vcanvas pixel coordinates are in the 1:1 pixel space; divide by ppu then add min.
|
|
284
348
|
*/
|
|
285
|
-
|
|
349
|
+
function canvasToTimeline(canvasX, ppu, min) {
|
|
350
|
+
return canvasX / ppu + min;
|
|
351
|
+
}
|
|
286
352
|
/**
|
|
287
353
|
* Convert screen-space pixel distance to timeline logical units.
|
|
288
354
|
* Used for edge hit threshold: how many logical units does EDGE_HIT_PX correspond to.
|
|
289
355
|
*/
|
|
290
|
-
|
|
291
|
-
|
|
356
|
+
function pxToLogicalUnits(ppu) {
|
|
357
|
+
return ppu > 0 ? 1 / ppu : 1;
|
|
358
|
+
}
|
|
359
|
+
function hitTest(logicalX, y, events, trackLayout, ppu) {
|
|
292
360
|
const track = trackLayout.find((tl) => y >= tl.y && y < tl.y + tl.height);
|
|
293
361
|
if (!track) return {
|
|
294
362
|
kind: `empty`,
|
|
@@ -321,17 +389,19 @@ const hitTest = (logicalX, y, events, trackLayout, ppu) => {
|
|
|
321
389
|
y,
|
|
322
390
|
trackKey: track.trackKey
|
|
323
391
|
};
|
|
324
|
-
}
|
|
325
|
-
|
|
392
|
+
}
|
|
393
|
+
function trackAtY(y, trackLayout) {
|
|
326
394
|
return trackLayout.find((tl) => y >= tl.y && y < tl.y + tl.height)?.trackKey;
|
|
327
|
-
}
|
|
395
|
+
}
|
|
328
396
|
/** Sensitivity: how many pixels of vertical drag = 1 e-fold of zoom */
|
|
329
397
|
const ZOOM_SENSITIVITY_PX = 100;
|
|
330
398
|
/**
|
|
331
399
|
* Subtract a deadzone from a value.
|
|
332
400
|
* Returns 0 if |value| <= deadzone, otherwise value shifted toward zero by deadzone.
|
|
333
401
|
*/
|
|
334
|
-
|
|
402
|
+
function applyDeadzone(value, deadzone) {
|
|
403
|
+
return Math.abs(value) > deadzone ? value - Math.sign(value) * deadzone : 0;
|
|
404
|
+
}
|
|
335
405
|
/**
|
|
336
406
|
* Compute new ppu + viewMin from an axis-zoom drag.
|
|
337
407
|
* Vertical delta (dy) controls zoom (up = zoom in, down = zoom out), anchored at `anchorUnit`.
|
|
@@ -339,7 +409,7 @@ const applyDeadzone = (value, deadzone) => Math.abs(value) > deadzone ? value -
|
|
|
339
409
|
*
|
|
340
410
|
* Returns { ppu, viewMin } — the caller uses host.setZoomPan() to apply.
|
|
341
411
|
*/
|
|
342
|
-
|
|
412
|
+
function computeAxisZoom(startViewMin, startPpu, anchorUnit, dx, dy) {
|
|
343
413
|
const newPpu = startPpu * Math.exp(-dy / ZOOM_SENSITIVITY_PX);
|
|
344
414
|
let newMin = anchorUnit - (anchorUnit - startViewMin) * startPpu / newPpu;
|
|
345
415
|
if (newPpu > 0) newMin += -dx / newPpu;
|
|
@@ -347,7 +417,7 @@ const computeAxisZoom = (startViewMin, startPpu, anchorUnit, dx, dy) => {
|
|
|
347
417
|
ppu: newPpu,
|
|
348
418
|
viewMin: newMin
|
|
349
419
|
};
|
|
350
|
-
}
|
|
420
|
+
}
|
|
351
421
|
/**
|
|
352
422
|
* Compute new vertical view range from a v-axis-zoom drag.
|
|
353
423
|
* Horizontal delta (dx) controls zoom (right = zoom in, left = zoom out),
|
|
@@ -356,7 +426,7 @@ const computeAxisZoom = (startViewMin, startPpu, anchorUnit, dx, dy) => {
|
|
|
356
426
|
*
|
|
357
427
|
* Returns { vMin, vMax } — the caller uses host.setVerticalZoomPan() to apply.
|
|
358
428
|
*/
|
|
359
|
-
|
|
429
|
+
function computeVerticalAxisZoom(startVMin, startVMax, startVScale, anchorBaseY, dx, dy) {
|
|
360
430
|
const startSpan = startVMax - startVMin;
|
|
361
431
|
const newSpan = startSpan * Math.exp(-dx / ZOOM_SENSITIVITY_PX);
|
|
362
432
|
let newMin = anchorBaseY - (startSpan > 0 ? (anchorBaseY - startVMin) / startSpan : .5) * newSpan;
|
|
@@ -365,12 +435,12 @@ const computeVerticalAxisZoom = (startVMin, startVMax, startVScale, anchorBaseY,
|
|
|
365
435
|
vMin: newMin,
|
|
366
436
|
vMax: newMin + newSpan
|
|
367
437
|
};
|
|
368
|
-
}
|
|
438
|
+
}
|
|
369
439
|
/**
|
|
370
440
|
* Attaches pointer and keyboard interaction handlers to the timeline.
|
|
371
441
|
* Returns a cleanup function.
|
|
372
442
|
*/
|
|
373
|
-
|
|
443
|
+
function attachTimelineInteractions(host, vcanvasEl) {
|
|
374
444
|
const ac = new AbortController();
|
|
375
445
|
const signal = ac.signal;
|
|
376
446
|
vcanvasEl.addEventListener(`pointerdown`, (e) => {
|
|
@@ -431,7 +501,6 @@ const attachTimelineInteractions = (host, vcanvasEl) => {
|
|
|
431
501
|
currentLogicalX: lx,
|
|
432
502
|
currentY: ly
|
|
433
503
|
};
|
|
434
|
-
return;
|
|
435
504
|
}
|
|
436
505
|
}, { signal });
|
|
437
506
|
vcanvasEl.addEventListener(`pointermove`, (e) => {
|
|
@@ -504,7 +573,6 @@ const attachTimelineInteractions = (host, vcanvasEl) => {
|
|
|
504
573
|
end: newEnd
|
|
505
574
|
} : ev);
|
|
506
575
|
vcanvasEl.invalidateAll();
|
|
507
|
-
return;
|
|
508
576
|
}
|
|
509
577
|
}, { signal });
|
|
510
578
|
vcanvasEl.addEventListener(`pointerup`, (e) => {
|
|
@@ -577,8 +645,8 @@ const attachTimelineInteractions = (host, vcanvasEl) => {
|
|
|
577
645
|
}
|
|
578
646
|
}, { signal });
|
|
579
647
|
return () => ac.abort();
|
|
580
|
-
}
|
|
581
|
-
|
|
648
|
+
}
|
|
649
|
+
function handleHover(host, vcanvasEl, e) {
|
|
582
650
|
const ppu = host.pxPerUnit;
|
|
583
651
|
const canvasCoord = vcanvasEl.convertFromViewportToCanvas(e.offsetX, e.offsetY);
|
|
584
652
|
const lx = canvasToTimeline(canvasCoord.x, ppu, host.min);
|
|
@@ -602,22 +670,22 @@ const handleHover = (host, vcanvasEl, e) => {
|
|
|
602
670
|
host._tickledId = newTickledId;
|
|
603
671
|
vcanvasEl.invalidateAll();
|
|
604
672
|
}
|
|
605
|
-
}
|
|
606
|
-
|
|
673
|
+
}
|
|
674
|
+
function toggleSelection(host, eventId) {
|
|
607
675
|
const next = new Set(host._selectedIds);
|
|
608
676
|
if (next.has(eventId)) next.delete(eventId);
|
|
609
677
|
else next.add(eventId);
|
|
610
678
|
host._selectedIds = next;
|
|
611
679
|
fireSelectionChange(host);
|
|
612
680
|
host.getVCanvas()?.invalidateAll();
|
|
613
|
-
}
|
|
614
|
-
|
|
681
|
+
}
|
|
682
|
+
function fireSelectionChange(host) {
|
|
615
683
|
host.dispatchEvent(new CustomEvent(`selection-change`, {
|
|
616
684
|
detail: { selectedIds: [...host._selectedIds] },
|
|
617
685
|
bubbles: true,
|
|
618
686
|
composed: true
|
|
619
687
|
}));
|
|
620
|
-
}
|
|
688
|
+
}
|
|
621
689
|
//#endregion
|
|
622
690
|
//#region src/timeline/timeline-styles.ts
|
|
623
691
|
const timelineStyles = css`
|
|
@@ -1679,70 +1747,6 @@ __decorate([state()], IxfxTimelineElement.prototype, "_internalEvents", void 0);
|
|
|
1679
1747
|
__decorate([state()], IxfxTimelineElement.prototype, "_internalTracks", void 0);
|
|
1680
1748
|
IxfxTimelineElement = __decorate([safeCustomElement(`ixfx-timeline`)], IxfxTimelineElement);
|
|
1681
1749
|
//#endregion
|
|
1682
|
-
|
|
1683
|
-
/**
|
|
1684
|
-
* External adapter class that can configure a timeline element
|
|
1685
|
-
* with musical time, custom label formatting, etc.
|
|
1686
|
-
*
|
|
1687
|
-
* The controller has no import of any timeline element type.
|
|
1688
|
-
* Users create a controller, pass it the component instance,
|
|
1689
|
-
* and the controller calls the component's public API.
|
|
1690
|
-
*/
|
|
1691
|
-
var TimelineController = class {
|
|
1692
|
-
#host;
|
|
1693
|
-
#config;
|
|
1694
|
-
#bpm = 120;
|
|
1695
|
-
#timeSignatureNumerator = 4;
|
|
1696
|
-
#timeSignatureDenominator = 4;
|
|
1697
|
-
constructor(timeline, config) {
|
|
1698
|
-
this.#host = timeline;
|
|
1699
|
-
this.#config = config;
|
|
1700
|
-
timeline.min = config.logicalMin;
|
|
1701
|
-
timeline.max = config.logicalMax;
|
|
1702
|
-
if (config.labelFormatter) timeline.formatLabel = config.labelFormatter;
|
|
1703
|
-
timeline.addEventListener(`track-select`, this.#onTrackSelect);
|
|
1704
|
-
}
|
|
1705
|
-
/** Update the tempo (BPM) for musical time calculations. */
|
|
1706
|
-
setTempo(bpm) {
|
|
1707
|
-
this.#bpm = bpm;
|
|
1708
|
-
this.#updateFormatLabel();
|
|
1709
|
-
}
|
|
1710
|
-
/** Update the time signature for musical time calculations. */
|
|
1711
|
-
setTimeSignature(numerator, denominator) {
|
|
1712
|
-
this.#timeSignatureNumerator = numerator;
|
|
1713
|
-
this.#timeSignatureDenominator = denominator;
|
|
1714
|
-
this.#updateFormatLabel();
|
|
1715
|
-
}
|
|
1716
|
-
/** Set the visible view range on the timeline. */
|
|
1717
|
-
setViewRange(range) {
|
|
1718
|
-
this.#host.setViewRange(range);
|
|
1719
|
-
}
|
|
1720
|
-
/** Clean up any resources held by the controller. */
|
|
1721
|
-
dispose() {
|
|
1722
|
-
this.#host.removeEventListener(`track-select`, this.#onTrackSelect);
|
|
1723
|
-
}
|
|
1724
|
-
#onTrackSelect = (e) => {
|
|
1725
|
-
const detail = e.detail;
|
|
1726
|
-
const trackEventIds = this.#host.getTrackEvents(detail.trackKey).map((e) => e.id);
|
|
1727
|
-
if (detail.shiftKey) {
|
|
1728
|
-
const current = new Set(this.#host.selectedIds);
|
|
1729
|
-
for (const id of trackEventIds) if (current.has(id)) current.delete(id);
|
|
1730
|
-
else current.add(id);
|
|
1731
|
-
this.#host.selectedIds = [...current];
|
|
1732
|
-
} else this.#host.selectedIds = trackEventIds;
|
|
1733
|
-
};
|
|
1734
|
-
#updateFormatLabel() {
|
|
1735
|
-
if (this.#config.labelFormatter) return;
|
|
1736
|
-
this.#bpm;
|
|
1737
|
-
const num = this.#timeSignatureNumerator;
|
|
1738
|
-
this.#host.formatLabel = (v) => {
|
|
1739
|
-
const beatsPerBar = num;
|
|
1740
|
-
const totalBeats = v;
|
|
1741
|
-
return `${Math.floor(totalBeats / beatsPerBar) + 1}.${Math.floor(totalBeats % beatsPerBar) + 1}`;
|
|
1742
|
-
};
|
|
1743
|
-
}
|
|
1744
|
-
};
|
|
1745
|
-
//#endregion
|
|
1746
|
-
export { attachTimelineInteractions as a, timelineStyles as i, IxfxTimelineElement as n, resolveCssVars as o, TimelineTrackTabElement as r, resolveGrid as s, TimelineController as t };
|
|
1750
|
+
export { resolveCssVars as a, attachTimelineInteractions as i, TimelineTrackTabElement as n, resolveGrid as o, timelineStyles as r, TimelineController as s, IxfxTimelineElement as t };
|
|
1747
1751
|
|
|
1748
|
-
//# sourceMappingURL=timeline-
|
|
1752
|
+
//# sourceMappingURL=timeline-Cv75Th2U.js.map
|