@editframe/elements 0.15.0-beta.1 → 0.15.0-beta.10
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/dist/EF_FRAMEGEN.js +0 -2
- package/dist/elements/EFAudio.d.ts +0 -1
- package/dist/elements/EFAudio.js +1 -5
- package/dist/elements/EFCaptions.js +1 -1
- package/dist/elements/EFMedia.d.ts +2 -1
- package/dist/elements/EFMedia.js +125 -14
- package/dist/elements/EFTemporal.d.ts +3 -3
- package/dist/elements/EFTemporal.js +6 -2
- package/dist/elements/EFTimegroup.d.ts +1 -5
- package/dist/elements/EFTimegroup.js +4 -5
- package/dist/elements/EFWaveform.d.ts +14 -6
- package/dist/elements/EFWaveform.js +155 -53
- package/dist/elements/TargetController.d.ts +25 -0
- package/dist/elements/TargetController.js +164 -0
- package/dist/elements/TargetController.test.d.ts +19 -0
- package/dist/gui/EFPreview.d.ts +1 -1
- package/dist/gui/EFPreview.js +1 -0
- package/dist/gui/TWMixin.css.js +1 -1
- package/dist/style.css +3 -0
- package/package.json +9 -4
- package/src/elements/EFAudio.ts +1 -4
- package/src/elements/EFCaptions.ts +1 -1
- package/src/elements/EFMedia.ts +158 -22
- package/src/elements/EFTemporal.ts +10 -10
- package/src/elements/EFTimegroup.ts +4 -9
- package/src/elements/EFWaveform.ts +214 -70
- package/src/elements/TargetController.test.ts +229 -0
- package/src/elements/TargetController.ts +219 -0
- package/src/gui/EFPreview.ts +10 -9
- package/types.json +1 -0
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { EFAudio } from "./EFAudio.js";
|
|
2
1
|
import { CSSStyleObserver } from "@bramus/style-observer";
|
|
3
2
|
import { Task } from "@lit/task";
|
|
4
3
|
import { html, css, LitElement } from "lit";
|
|
5
|
-
import { property, customElement } from "lit/decorators.js";
|
|
4
|
+
import { property, state, customElement } from "lit/decorators.js";
|
|
6
5
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
7
6
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
8
7
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
9
8
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
10
9
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
11
10
|
import { EFTemporal } from "./EFTemporal.js";
|
|
12
|
-
import {
|
|
11
|
+
import { TargetController } from "./TargetController.js";
|
|
13
12
|
var __defProp = Object.defineProperty;
|
|
14
13
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
15
14
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -28,11 +27,18 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
28
27
|
this.styleObserver = null;
|
|
29
28
|
this.mode = "bars";
|
|
30
29
|
this.color = "currentColor";
|
|
31
|
-
this.
|
|
30
|
+
this.target = "";
|
|
31
|
+
this.targetElement = null;
|
|
32
32
|
this.lineWidth = 4;
|
|
33
|
+
this.targetController = new TargetController(this);
|
|
33
34
|
this.frameTask = new Task(this, {
|
|
34
35
|
autoRun: EF_INTERACTIVE,
|
|
35
|
-
args: () =>
|
|
36
|
+
args: () => {
|
|
37
|
+
return [
|
|
38
|
+
this.targetElement,
|
|
39
|
+
this.targetElement?.frequencyDataTask.value
|
|
40
|
+
];
|
|
41
|
+
},
|
|
36
42
|
task: async () => {
|
|
37
43
|
if (!this.targetElement) return;
|
|
38
44
|
await this.targetElement.frequencyDataTask.taskComplete;
|
|
@@ -40,12 +46,17 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
40
46
|
const ctx = this.ctx;
|
|
41
47
|
if (!ctx) return;
|
|
42
48
|
const frequencyData = this.targetElement.frequencyDataTask.value;
|
|
43
|
-
|
|
49
|
+
const byteTimeData = this.targetElement.byteTimeDomainTask.value;
|
|
50
|
+
if (!frequencyData || !byteTimeData) return;
|
|
51
|
+
ctx.save();
|
|
44
52
|
if (this.color === "currentColor") {
|
|
45
53
|
const computedStyle = getComputedStyle(this);
|
|
46
54
|
const currentColor = computedStyle.color;
|
|
47
55
|
ctx.strokeStyle = currentColor;
|
|
48
56
|
ctx.fillStyle = currentColor;
|
|
57
|
+
} else {
|
|
58
|
+
ctx.strokeStyle = this.color;
|
|
59
|
+
ctx.fillStyle = this.color;
|
|
49
60
|
}
|
|
50
61
|
switch (this.mode) {
|
|
51
62
|
case "bars":
|
|
@@ -55,7 +66,10 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
55
66
|
this.drawBricks(ctx, frequencyData);
|
|
56
67
|
break;
|
|
57
68
|
case "line":
|
|
58
|
-
this.drawLine(ctx,
|
|
69
|
+
this.drawLine(ctx, byteTimeData);
|
|
70
|
+
break;
|
|
71
|
+
case "curve":
|
|
72
|
+
this.drawCurve(ctx, byteTimeData);
|
|
59
73
|
break;
|
|
60
74
|
case "pixel":
|
|
61
75
|
this.drawPixel(ctx, frequencyData);
|
|
@@ -63,19 +77,20 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
63
77
|
case "wave":
|
|
64
78
|
this.drawWave(ctx, frequencyData);
|
|
65
79
|
break;
|
|
80
|
+
case "spikes":
|
|
81
|
+
this.drawSpikes(ctx, frequencyData);
|
|
82
|
+
break;
|
|
66
83
|
case "roundBars":
|
|
67
84
|
this.drawRoundBars(ctx, frequencyData);
|
|
68
85
|
break;
|
|
69
86
|
}
|
|
87
|
+
ctx.restore();
|
|
70
88
|
}
|
|
71
89
|
});
|
|
72
90
|
}
|
|
73
91
|
render() {
|
|
74
92
|
return html`<canvas ${ref(this.canvasRef)}></canvas>`;
|
|
75
93
|
}
|
|
76
|
-
set target(value) {
|
|
77
|
-
this.targetSelector = value;
|
|
78
|
-
}
|
|
79
94
|
connectedCallback() {
|
|
80
95
|
super.connectedCallback();
|
|
81
96
|
try {
|
|
@@ -130,27 +145,25 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
130
145
|
const ctx = canvas.getContext("2d");
|
|
131
146
|
if (!ctx) return null;
|
|
132
147
|
ctx.reset();
|
|
133
|
-
ctx.scale(dpr, dpr);
|
|
134
148
|
return ctx;
|
|
135
149
|
}
|
|
136
150
|
drawBars(ctx, frequencyData) {
|
|
137
151
|
const canvas = ctx.canvas;
|
|
138
152
|
const waveWidth = canvas.width;
|
|
139
153
|
const waveHeight = canvas.height;
|
|
140
|
-
const baseline = waveHeight / 4;
|
|
141
154
|
const totalBars = frequencyData.length;
|
|
142
155
|
const paddingInner = 0.5;
|
|
143
156
|
const paddingOuter = 0.01;
|
|
144
|
-
const availableWidth = waveWidth
|
|
157
|
+
const availableWidth = waveWidth;
|
|
145
158
|
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
146
159
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
147
160
|
const path = new Path2D();
|
|
148
161
|
frequencyData.forEach((value, i) => {
|
|
149
|
-
const normalizedValue = value / 255;
|
|
150
|
-
const
|
|
162
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
163
|
+
const barHeight = normalizedValue * waveHeight;
|
|
164
|
+
const y = (waveHeight - barHeight) / 2;
|
|
151
165
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
152
|
-
|
|
153
|
-
path.rect(x, y, barWidth, height * 2);
|
|
166
|
+
path.rect(x, y, barWidth, barHeight);
|
|
154
167
|
});
|
|
155
168
|
ctx.fill(path);
|
|
156
169
|
}
|
|
@@ -162,11 +175,14 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
162
175
|
const path = new Path2D();
|
|
163
176
|
const columnWidth = waveWidth / frequencyData.length;
|
|
164
177
|
const boxSize = columnWidth * 0.9;
|
|
178
|
+
const verticalGap = boxSize * 0.2;
|
|
179
|
+
const maxBricks = Math.floor(waveHeight / (boxSize + verticalGap));
|
|
165
180
|
frequencyData.forEach((value, i) => {
|
|
166
|
-
const
|
|
167
|
-
|
|
181
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
182
|
+
const brickCount = Math.floor(normalizedValue * maxBricks);
|
|
183
|
+
for (let j = 0; j < brickCount; j++) {
|
|
168
184
|
const x = columnWidth * i;
|
|
169
|
-
const y = waveHeight - (j *
|
|
185
|
+
const y = waveHeight - (j + 1) * (boxSize + verticalGap);
|
|
170
186
|
path.rect(x, y, boxSize, boxSize);
|
|
171
187
|
}
|
|
172
188
|
});
|
|
@@ -176,29 +192,28 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
176
192
|
const canvas = ctx.canvas;
|
|
177
193
|
const waveWidth = canvas.width;
|
|
178
194
|
const waveHeight = canvas.height;
|
|
179
|
-
const baseline = waveHeight / 4;
|
|
180
195
|
const totalBars = frequencyData.length;
|
|
181
196
|
const paddingInner = 0.5;
|
|
182
197
|
const paddingOuter = 0.01;
|
|
183
|
-
const availableWidth = waveWidth
|
|
198
|
+
const availableWidth = waveWidth;
|
|
184
199
|
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
185
200
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
186
201
|
const path = new Path2D();
|
|
187
202
|
frequencyData.forEach((value, i) => {
|
|
188
|
-
const normalizedValue = value / 255;
|
|
189
|
-
const height = normalizedValue *
|
|
203
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
204
|
+
const height = normalizedValue * waveHeight;
|
|
190
205
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
191
|
-
const y =
|
|
192
|
-
path.roundRect(x, y, barWidth, height
|
|
206
|
+
const y = (waveHeight - height) / 2;
|
|
207
|
+
path.roundRect(x, y, barWidth, height, barWidth / 2);
|
|
193
208
|
});
|
|
194
209
|
ctx.fill(path);
|
|
195
210
|
}
|
|
196
211
|
drawEqualizer(ctx, frequencyData) {
|
|
197
212
|
const canvas = ctx.canvas;
|
|
198
213
|
const waveWidth = canvas.width;
|
|
199
|
-
const waveHeight = canvas.height
|
|
200
|
-
const barWidth = waveWidth / frequencyData.length * 0.8;
|
|
214
|
+
const waveHeight = canvas.height;
|
|
201
215
|
const baseline = waveHeight / 2;
|
|
216
|
+
const barWidth = waveWidth / frequencyData.length * 0.8;
|
|
202
217
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
203
218
|
const baselinePath = new Path2D();
|
|
204
219
|
const barsPath = new Path2D();
|
|
@@ -217,7 +232,29 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
217
232
|
drawLine(ctx, frequencyData) {
|
|
218
233
|
const canvas = ctx.canvas;
|
|
219
234
|
const waveWidth = canvas.width;
|
|
220
|
-
const waveHeight = canvas.height
|
|
235
|
+
const waveHeight = canvas.height;
|
|
236
|
+
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
237
|
+
const path = new Path2D();
|
|
238
|
+
const sampleRate = 4;
|
|
239
|
+
for (let i = 0; i < frequencyData.length; i += sampleRate) {
|
|
240
|
+
const x = i / frequencyData.length * waveWidth;
|
|
241
|
+
const y = (1 - (frequencyData[i] ?? 0) / 255) * waveHeight;
|
|
242
|
+
if (i === 0) {
|
|
243
|
+
path.moveTo(x, y);
|
|
244
|
+
} else {
|
|
245
|
+
path.lineTo(x, y);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const lastX = waveWidth;
|
|
249
|
+
const lastY = (1 - (frequencyData[frequencyData.length - 1] ?? 0) / 255) * waveHeight;
|
|
250
|
+
path.lineTo(lastX, lastY);
|
|
251
|
+
ctx.lineWidth = this.lineWidth;
|
|
252
|
+
ctx.stroke(path);
|
|
253
|
+
}
|
|
254
|
+
drawCurve(ctx, frequencyData) {
|
|
255
|
+
const canvas = ctx.canvas;
|
|
256
|
+
const waveWidth = canvas.width;
|
|
257
|
+
const waveHeight = canvas.height;
|
|
221
258
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
222
259
|
const path = new Path2D();
|
|
223
260
|
frequencyData.forEach((value, i) => {
|
|
@@ -226,7 +263,11 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
226
263
|
if (i === 0) {
|
|
227
264
|
path.moveTo(x, y);
|
|
228
265
|
} else {
|
|
229
|
-
|
|
266
|
+
const prevX = (i - 1) / frequencyData.length * waveWidth;
|
|
267
|
+
const prevY = (1 - (frequencyData[i - 1] ?? 0) / 255) * waveHeight;
|
|
268
|
+
const xc = (prevX + x) / 2;
|
|
269
|
+
const yc = (prevY + y) / 2;
|
|
270
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
230
271
|
}
|
|
231
272
|
});
|
|
232
273
|
ctx.lineWidth = this.lineWidth;
|
|
@@ -235,14 +276,15 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
235
276
|
drawPixel(ctx, frequencyData) {
|
|
236
277
|
const canvas = ctx.canvas;
|
|
237
278
|
const waveWidth = canvas.width;
|
|
238
|
-
const waveHeight = canvas.height
|
|
279
|
+
const waveHeight = canvas.height;
|
|
239
280
|
const baseline = waveHeight / 2;
|
|
240
281
|
const barWidth = waveWidth / frequencyData.length;
|
|
241
282
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
242
283
|
const path = new Path2D();
|
|
243
284
|
frequencyData.forEach((value, i) => {
|
|
285
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
244
286
|
const x = i * (waveWidth / frequencyData.length);
|
|
245
|
-
const barHeight =
|
|
287
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
246
288
|
const y = baseline - barHeight;
|
|
247
289
|
path.rect(x, y, barWidth, barHeight * 2);
|
|
248
290
|
});
|
|
@@ -252,53 +294,110 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
252
294
|
const canvas = ctx.canvas;
|
|
253
295
|
const waveWidth = canvas.width;
|
|
254
296
|
const waveHeight = canvas.height;
|
|
255
|
-
const
|
|
297
|
+
const paddingOuter = 0.01;
|
|
298
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
299
|
+
const startX = waveWidth * paddingOuter;
|
|
256
300
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
257
301
|
const path = new Path2D();
|
|
258
|
-
|
|
302
|
+
const firstValue = Math.min((frequencyData[0] ?? 0) / 255 * 2, 1);
|
|
303
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
304
|
+
path.moveTo(startX, firstY);
|
|
259
305
|
frequencyData.forEach((value, i) => {
|
|
260
|
-
const normalizedValue = value / 255;
|
|
261
|
-
const x = i / (frequencyData.length - 1) *
|
|
262
|
-
const
|
|
306
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
307
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
308
|
+
const barHeight = normalizedValue * waveHeight;
|
|
309
|
+
const y = (waveHeight - barHeight) / 2;
|
|
263
310
|
if (i === 0) {
|
|
264
311
|
path.moveTo(x, y);
|
|
265
312
|
} else {
|
|
266
|
-
const prevX = (i - 1) / (frequencyData.length - 1) *
|
|
313
|
+
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
314
|
+
const prevValue = Math.min((frequencyData[i - 1] ?? 0) / 255 * 2, 1);
|
|
315
|
+
const prevBarHeight = prevValue * waveHeight;
|
|
316
|
+
const prevY = (waveHeight - prevBarHeight) / 2;
|
|
317
|
+
const xc = (prevX + x) / 2;
|
|
318
|
+
const yc = (prevY + y) / 2;
|
|
319
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
323
|
+
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
324
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
325
|
+
const barHeight = normalizedValue * waveHeight;
|
|
326
|
+
const y = (waveHeight + barHeight) / 2;
|
|
327
|
+
if (i === frequencyData.length - 1) {
|
|
328
|
+
path.lineTo(x, y);
|
|
329
|
+
} else {
|
|
330
|
+
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
331
|
+
const nextValue = Math.min((frequencyData[i + 1] ?? 0) / 255 * 2, 1);
|
|
332
|
+
const nextBarHeight = nextValue * waveHeight;
|
|
333
|
+
const nextY = (waveHeight + nextBarHeight) / 2;
|
|
334
|
+
const xc = (nextX + x) / 2;
|
|
335
|
+
const yc = (nextY + y) / 2;
|
|
336
|
+
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
340
|
+
const controlX = startX;
|
|
341
|
+
const controlY = (lastY + firstY) / 2;
|
|
342
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
343
|
+
ctx.fill(path);
|
|
344
|
+
}
|
|
345
|
+
drawSpikes(ctx, frequencyData) {
|
|
346
|
+
const canvas = ctx.canvas;
|
|
347
|
+
const waveWidth = canvas.width;
|
|
348
|
+
const waveHeight = canvas.height;
|
|
349
|
+
const paddingOuter = 0.01;
|
|
350
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
351
|
+
const startX = waveWidth * paddingOuter;
|
|
352
|
+
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
353
|
+
const path = new Path2D();
|
|
354
|
+
const firstValue = (frequencyData[0] ?? 0) / 255;
|
|
355
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
356
|
+
path.moveTo(startX, firstY);
|
|
357
|
+
frequencyData.forEach((value, i) => {
|
|
358
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
359
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
360
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
361
|
+
const y = (waveHeight - barHeight * 2) / 2;
|
|
362
|
+
if (i === 0) {
|
|
363
|
+
path.moveTo(x, y);
|
|
364
|
+
} else {
|
|
365
|
+
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
267
366
|
const prevValue = (frequencyData[i - 1] ?? 0) / 255;
|
|
268
|
-
const
|
|
367
|
+
const prevBarHeight = prevValue * (waveHeight / 2);
|
|
368
|
+
const prevY = (waveHeight - prevBarHeight * 2) / 2;
|
|
269
369
|
const xc = (prevX + x) / 2;
|
|
270
370
|
const yc = (prevY + y) / 2;
|
|
271
371
|
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
272
372
|
}
|
|
273
373
|
});
|
|
274
374
|
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
275
|
-
const normalizedValue = (frequencyData[i] ?? 0) / 255;
|
|
276
|
-
const x = i / (frequencyData.length - 1) *
|
|
277
|
-
const
|
|
375
|
+
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
376
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
377
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
378
|
+
const y = (waveHeight + barHeight * 2) / 2;
|
|
278
379
|
if (i === frequencyData.length - 1) {
|
|
279
380
|
path.lineTo(x, y);
|
|
280
381
|
} else {
|
|
281
|
-
const nextX = (i + 1) / (frequencyData.length - 1) *
|
|
382
|
+
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
282
383
|
const nextValue = (frequencyData[i + 1] ?? 0) / 255;
|
|
283
|
-
const
|
|
384
|
+
const nextBarHeight = nextValue * (waveHeight / 2);
|
|
385
|
+
const nextY = (waveHeight + nextBarHeight * 2) / 2;
|
|
284
386
|
const xc = (nextX + x) / 2;
|
|
285
387
|
const yc = (nextY + y) / 2;
|
|
286
388
|
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
287
389
|
}
|
|
288
390
|
}
|
|
391
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
392
|
+
const controlX = startX;
|
|
393
|
+
const controlY = (lastY + firstY) / 2;
|
|
394
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
289
395
|
ctx.fill(path);
|
|
290
396
|
}
|
|
291
397
|
get durationMs() {
|
|
292
398
|
if (!this.targetElement) return 0;
|
|
293
399
|
return this.targetElement.durationMs;
|
|
294
400
|
}
|
|
295
|
-
get targetElement() {
|
|
296
|
-
const target = document.getElementById(this.targetSelector ?? "");
|
|
297
|
-
if (target instanceof EFAudio || target instanceof EFVideo) {
|
|
298
|
-
return target;
|
|
299
|
-
}
|
|
300
|
-
return null;
|
|
301
|
-
}
|
|
302
401
|
updated(changedProperties) {
|
|
303
402
|
super.updated(changedProperties);
|
|
304
403
|
if (changedProperties.size > 0) {
|
|
@@ -331,8 +430,11 @@ __decorateClass([
|
|
|
331
430
|
property({ type: String })
|
|
332
431
|
], EFWaveform.prototype, "color", 2);
|
|
333
432
|
__decorateClass([
|
|
334
|
-
property({ type: String,
|
|
335
|
-
], EFWaveform.prototype, "
|
|
433
|
+
property({ type: String, reflect: true })
|
|
434
|
+
], EFWaveform.prototype, "target", 2);
|
|
435
|
+
__decorateClass([
|
|
436
|
+
state()
|
|
437
|
+
], EFWaveform.prototype, "targetElement", 2);
|
|
336
438
|
__decorateClass([
|
|
337
439
|
property({ type: Number, attribute: "line-width" })
|
|
338
440
|
], EFWaveform.prototype, "lineWidth", 2);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LitElement, ReactiveController } from 'lit';
|
|
2
|
+
type Constructor<T = {}> = new (...args: any[]) => T;
|
|
3
|
+
export declare class TargetableMixinInterface {
|
|
4
|
+
id: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const isEFTargetable: (obj: any) => obj is TargetableMixinInterface;
|
|
7
|
+
export declare const EFTargetable: <T extends Constructor<LitElement>>(superClass: T) => T;
|
|
8
|
+
export declare class TargetController implements ReactiveController {
|
|
9
|
+
private host;
|
|
10
|
+
private targetController;
|
|
11
|
+
private currentTargetString;
|
|
12
|
+
constructor(host: LitElement & {
|
|
13
|
+
targetElement: Element | null;
|
|
14
|
+
target: string;
|
|
15
|
+
});
|
|
16
|
+
private registryCallback;
|
|
17
|
+
private updateTarget;
|
|
18
|
+
private connectToTarget;
|
|
19
|
+
private disconnectFromTarget;
|
|
20
|
+
private get registry();
|
|
21
|
+
hostDisconnected(): void;
|
|
22
|
+
hostConnected(): void;
|
|
23
|
+
hostUpdate(): void;
|
|
24
|
+
}
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
const EF_TARGETABLE = Symbol("EF_TARGETABLE");
|
|
3
|
+
class TargetRegistry {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.idMap = /* @__PURE__ */ new Map();
|
|
6
|
+
this.callbacks = /* @__PURE__ */ new Map();
|
|
7
|
+
}
|
|
8
|
+
subscribe(id, callback) {
|
|
9
|
+
this.callbacks.set(id, this.callbacks.get(id) ?? /* @__PURE__ */ new Set());
|
|
10
|
+
this.callbacks.get(id)?.add(callback);
|
|
11
|
+
}
|
|
12
|
+
unsubscribe(id, callback) {
|
|
13
|
+
if (id === null) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
this.callbacks.get(id)?.delete(callback);
|
|
17
|
+
if (this.callbacks.get(id)?.size === 0) {
|
|
18
|
+
this.callbacks.delete(id);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
get(id) {
|
|
22
|
+
return this.idMap.get(id);
|
|
23
|
+
}
|
|
24
|
+
register(id, target) {
|
|
25
|
+
this.idMap.set(id, target);
|
|
26
|
+
for (const callback of this.callbacks.get(id) ?? []) {
|
|
27
|
+
callback(target);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
unregister(id) {
|
|
31
|
+
for (const callback of this.callbacks.get(id) ?? []) {
|
|
32
|
+
callback(void 0);
|
|
33
|
+
}
|
|
34
|
+
this.idMap.delete(id);
|
|
35
|
+
this.callbacks.delete(id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const documentRegistries = /* @__PURE__ */ new WeakMap();
|
|
39
|
+
const getRegistry = (root) => {
|
|
40
|
+
let registry = documentRegistries.get(root);
|
|
41
|
+
if (!registry) {
|
|
42
|
+
registry = new TargetRegistry();
|
|
43
|
+
documentRegistries.set(root, registry);
|
|
44
|
+
}
|
|
45
|
+
return registry;
|
|
46
|
+
};
|
|
47
|
+
const EFTargetable = (superClass) => {
|
|
48
|
+
class TargetableElement extends superClass {
|
|
49
|
+
#registry = null;
|
|
50
|
+
static get observedAttributes() {
|
|
51
|
+
const parentAttributes = superClass.observedAttributes || [];
|
|
52
|
+
return [.../* @__PURE__ */ new Set([...parentAttributes, "id"])];
|
|
53
|
+
}
|
|
54
|
+
updateRegistry(oldValue, newValue) {
|
|
55
|
+
if (!this.#registry) return;
|
|
56
|
+
if (oldValue === newValue) return;
|
|
57
|
+
if (oldValue) {
|
|
58
|
+
this.#registry.unregister(oldValue);
|
|
59
|
+
}
|
|
60
|
+
if (newValue) {
|
|
61
|
+
this.#registry.register(newValue, this);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
connectedCallback() {
|
|
65
|
+
super.connectedCallback();
|
|
66
|
+
this.#registry = getRegistry(this.getRootNode());
|
|
67
|
+
const initialId = this.getAttribute("id");
|
|
68
|
+
if (initialId) {
|
|
69
|
+
this.updateRegistry("", initialId);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
attributeChangedCallback(name, old, value) {
|
|
73
|
+
super.attributeChangedCallback(name, old, value);
|
|
74
|
+
if (name === "id") {
|
|
75
|
+
this.updateRegistry(old ?? "", value ?? "");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
disconnectedCallback() {
|
|
79
|
+
if (this.#registry) {
|
|
80
|
+
this.updateRegistry(this.id, "");
|
|
81
|
+
this.#registry = null;
|
|
82
|
+
}
|
|
83
|
+
super.disconnectedCallback();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
Object.defineProperty(TargetableElement.prototype, EF_TARGETABLE, {
|
|
87
|
+
value: true
|
|
88
|
+
});
|
|
89
|
+
return TargetableElement;
|
|
90
|
+
};
|
|
91
|
+
class TargetUpdateController {
|
|
92
|
+
constructor(host) {
|
|
93
|
+
this.host = host;
|
|
94
|
+
}
|
|
95
|
+
hostConnected() {
|
|
96
|
+
this.host.requestUpdate();
|
|
97
|
+
}
|
|
98
|
+
hostDisconnected() {
|
|
99
|
+
this.host.requestUpdate();
|
|
100
|
+
}
|
|
101
|
+
hostUpdate() {
|
|
102
|
+
this.host.requestUpdate();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
class TargetController {
|
|
106
|
+
constructor(host) {
|
|
107
|
+
this.targetController = null;
|
|
108
|
+
this.currentTargetString = null;
|
|
109
|
+
this.registryCallback = (target) => {
|
|
110
|
+
this.host.targetElement = target ?? null;
|
|
111
|
+
};
|
|
112
|
+
this.host = host;
|
|
113
|
+
this.host.addController(this);
|
|
114
|
+
this.currentTargetString = this.host.target;
|
|
115
|
+
if (this.currentTargetString) {
|
|
116
|
+
this.registry.subscribe(this.currentTargetString, this.registryCallback);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
updateTarget() {
|
|
120
|
+
const newTarget = this.registry.get(this.host.target);
|
|
121
|
+
if (this.host.targetElement !== newTarget) {
|
|
122
|
+
this.disconnectFromTarget();
|
|
123
|
+
this.host.targetElement = newTarget ?? null;
|
|
124
|
+
this.connectToTarget();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
connectToTarget() {
|
|
128
|
+
if (this.host.targetElement instanceof LitElement) {
|
|
129
|
+
this.targetController = new TargetUpdateController(this.host);
|
|
130
|
+
this.host.targetElement.addController(this.targetController);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
disconnectFromTarget() {
|
|
134
|
+
if (this.host.targetElement instanceof LitElement && this.targetController) {
|
|
135
|
+
this.host.targetElement.removeController(this.targetController);
|
|
136
|
+
this.targetController = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
get registry() {
|
|
140
|
+
const root = this.host.getRootNode();
|
|
141
|
+
return getRegistry(root);
|
|
142
|
+
}
|
|
143
|
+
hostDisconnected() {
|
|
144
|
+
this.disconnectFromTarget();
|
|
145
|
+
}
|
|
146
|
+
hostConnected() {
|
|
147
|
+
this.updateTarget();
|
|
148
|
+
}
|
|
149
|
+
hostUpdate() {
|
|
150
|
+
if (this.currentTargetString !== this.host.target) {
|
|
151
|
+
this.registry.unsubscribe(
|
|
152
|
+
this.currentTargetString,
|
|
153
|
+
this.registryCallback
|
|
154
|
+
);
|
|
155
|
+
this.registry.subscribe(this.host.target, this.registryCallback);
|
|
156
|
+
this.updateTarget();
|
|
157
|
+
this.currentTargetString = this.host.target;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export {
|
|
162
|
+
EFTargetable,
|
|
163
|
+
TargetController
|
|
164
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
declare const TargetableTest_base: typeof LitElement;
|
|
3
|
+
declare class TargetableTest extends TargetableTest_base {
|
|
4
|
+
value: string;
|
|
5
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
6
|
+
}
|
|
7
|
+
declare class TargeterTest extends LitElement {
|
|
8
|
+
private targetController;
|
|
9
|
+
targetElement: Element | null;
|
|
10
|
+
target: string;
|
|
11
|
+
render(): import('lit-html').TemplateResult<1>;
|
|
12
|
+
}
|
|
13
|
+
declare global {
|
|
14
|
+
interface HTMLElementTagNameMap {
|
|
15
|
+
"targetable-test": TargetableTest & Element;
|
|
16
|
+
"targeter-test": TargeterTest & Element;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export {};
|
package/dist/gui/EFPreview.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
2
|
declare const EFPreview_base: (new (...args: any[]) => import('./ContextMixin.js').ContextMixinInterface) & typeof LitElement;
|
|
3
3
|
export declare class EFPreview extends EFPreview_base {
|
|
4
|
+
static styles: import('lit').CSSResult[];
|
|
4
5
|
focusedElement?: HTMLElement;
|
|
5
6
|
constructor();
|
|
6
|
-
static styles: import('lit').CSSResult[];
|
|
7
7
|
render(): import('lit-html').TemplateResult<1>;
|
|
8
8
|
}
|
|
9
9
|
declare global {
|