@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,16 +1,16 @@
|
|
|
1
|
-
import { EFAudio } from "./EFAudio.js";
|
|
2
|
-
|
|
3
1
|
import { CSSStyleObserver } from "@bramus/style-observer";
|
|
4
2
|
import { Task } from "@lit/task";
|
|
5
3
|
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
6
|
-
import { customElement, property } from "lit/decorators.js";
|
|
4
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
7
5
|
import { type Ref, createRef, ref } from "lit/directives/ref.js";
|
|
8
6
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
9
7
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
10
8
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
11
9
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
10
|
+
import type { EFAudio } from "./EFAudio.js";
|
|
12
11
|
import { EFTemporal } from "./EFTemporal.js";
|
|
13
|
-
import { EFVideo } from "./EFVideo.js";
|
|
12
|
+
import type { EFVideo } from "./EFVideo.js";
|
|
13
|
+
import { TargetController } from "./TargetController.ts";
|
|
14
14
|
|
|
15
15
|
@customElement("ef-waveform")
|
|
16
16
|
export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
@@ -45,20 +45,29 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
45
45
|
type: String,
|
|
46
46
|
attribute: "mode",
|
|
47
47
|
})
|
|
48
|
-
mode:
|
|
48
|
+
mode:
|
|
49
|
+
| "roundBars"
|
|
50
|
+
| "bars"
|
|
51
|
+
| "bricks"
|
|
52
|
+
| "line"
|
|
53
|
+
| "curve"
|
|
54
|
+
| "pixel"
|
|
55
|
+
| "wave"
|
|
56
|
+
| "spikes" = "bars";
|
|
49
57
|
|
|
50
58
|
@property({ type: String })
|
|
51
59
|
color = "currentColor";
|
|
52
60
|
|
|
53
|
-
@property({ type: String,
|
|
54
|
-
|
|
61
|
+
@property({ type: String, reflect: true })
|
|
62
|
+
target = "";
|
|
63
|
+
|
|
64
|
+
@state()
|
|
65
|
+
targetElement: EFAudio | EFVideo | null = null;
|
|
55
66
|
|
|
56
67
|
@property({ type: Number, attribute: "line-width" })
|
|
57
68
|
lineWidth = 4;
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
this.targetSelector = value;
|
|
61
|
-
}
|
|
70
|
+
targetController: TargetController = new TargetController(this);
|
|
62
71
|
|
|
63
72
|
connectedCallback() {
|
|
64
73
|
super.connectedCallback();
|
|
@@ -136,8 +145,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
136
145
|
ctx.reset();
|
|
137
146
|
|
|
138
147
|
// Scale all drawing operations by dpr
|
|
139
|
-
ctx.scale(dpr, dpr);
|
|
140
|
-
|
|
141
148
|
return ctx;
|
|
142
149
|
}
|
|
143
150
|
|
|
@@ -145,31 +152,25 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
145
152
|
const canvas = ctx.canvas;
|
|
146
153
|
const waveWidth = canvas.width;
|
|
147
154
|
const waveHeight = canvas.height;
|
|
148
|
-
const baseline = waveHeight / 4;
|
|
149
155
|
|
|
150
|
-
// Calculate bar width with padding
|
|
151
156
|
const totalBars = frequencyData.length;
|
|
152
|
-
const paddingInner = 0.5;
|
|
153
|
-
const paddingOuter = 0.01;
|
|
154
|
-
const availableWidth = waveWidth
|
|
157
|
+
const paddingInner = 0.5;
|
|
158
|
+
const paddingOuter = 0.01;
|
|
159
|
+
const availableWidth = waveWidth;
|
|
155
160
|
const barWidth =
|
|
156
161
|
availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
157
162
|
|
|
158
163
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
159
|
-
|
|
160
|
-
// Create a single Path2D object for all bars
|
|
161
164
|
const path = new Path2D();
|
|
162
165
|
|
|
163
166
|
frequencyData.forEach((value, i) => {
|
|
164
|
-
const normalizedValue = value / 255;
|
|
165
|
-
const
|
|
167
|
+
const normalizedValue = Math.min((value / 255) * 2, 1);
|
|
168
|
+
const barHeight = normalizedValue * waveHeight;
|
|
169
|
+
const y = (waveHeight - barHeight) / 2;
|
|
166
170
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
path.rect(x, y, barWidth, height * 2);
|
|
171
|
+
path.rect(x, y, barWidth, barHeight);
|
|
170
172
|
});
|
|
171
173
|
|
|
172
|
-
// Single fill operation for all bars
|
|
173
174
|
ctx.fill(path);
|
|
174
175
|
}
|
|
175
176
|
|
|
@@ -185,11 +186,16 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
185
186
|
|
|
186
187
|
const columnWidth = waveWidth / frequencyData.length;
|
|
187
188
|
const boxSize = columnWidth * 0.9;
|
|
189
|
+
const verticalGap = boxSize * 0.2; // Add spacing between bricks
|
|
190
|
+
const maxBricks = Math.floor(waveHeight / (boxSize + verticalGap)); // Account for gaps in height calculation
|
|
191
|
+
|
|
188
192
|
frequencyData.forEach((value, i) => {
|
|
189
|
-
const
|
|
190
|
-
|
|
193
|
+
const normalizedValue = Math.min((value / 255) * 2, 1);
|
|
194
|
+
const brickCount = Math.floor(normalizedValue * maxBricks);
|
|
195
|
+
|
|
196
|
+
for (let j = 0; j < brickCount; j++) {
|
|
191
197
|
const x = columnWidth * i;
|
|
192
|
-
const y = waveHeight - (j *
|
|
198
|
+
const y = waveHeight - (j + 1) * (boxSize + verticalGap); // Include gap in position calculation
|
|
193
199
|
path.rect(x, y, boxSize, boxSize);
|
|
194
200
|
}
|
|
195
201
|
});
|
|
@@ -204,13 +210,12 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
204
210
|
const canvas = ctx.canvas;
|
|
205
211
|
const waveWidth = canvas.width;
|
|
206
212
|
const waveHeight = canvas.height;
|
|
207
|
-
const baseline = waveHeight / 4;
|
|
208
213
|
|
|
209
214
|
// Similar padding calculation as drawBars
|
|
210
215
|
const totalBars = frequencyData.length;
|
|
211
216
|
const paddingInner = 0.5;
|
|
212
217
|
const paddingOuter = 0.01;
|
|
213
|
-
const availableWidth = waveWidth
|
|
218
|
+
const availableWidth = waveWidth;
|
|
214
219
|
const barWidth =
|
|
215
220
|
availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
216
221
|
|
|
@@ -220,13 +225,13 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
220
225
|
const path = new Path2D();
|
|
221
226
|
|
|
222
227
|
frequencyData.forEach((value, i) => {
|
|
223
|
-
const normalizedValue = value / 255;
|
|
224
|
-
const height = normalizedValue *
|
|
228
|
+
const normalizedValue = Math.min((value / 255) * 2, 1);
|
|
229
|
+
const height = normalizedValue * waveHeight; // Use full wave height like in drawBars
|
|
225
230
|
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
226
|
-
const y =
|
|
231
|
+
const y = (waveHeight - height) / 2; // Center vertically
|
|
227
232
|
|
|
228
233
|
// Add rounded rectangle to path
|
|
229
|
-
path.roundRect(x, y, barWidth, height
|
|
234
|
+
path.roundRect(x, y, barWidth, height, barWidth / 2);
|
|
230
235
|
});
|
|
231
236
|
|
|
232
237
|
// Single fill operation for all bars
|
|
@@ -239,9 +244,9 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
239
244
|
) {
|
|
240
245
|
const canvas = ctx.canvas;
|
|
241
246
|
const waveWidth = canvas.width;
|
|
242
|
-
const waveHeight = canvas.height
|
|
243
|
-
const barWidth = (waveWidth / frequencyData.length) * 0.8;
|
|
247
|
+
const waveHeight = canvas.height;
|
|
244
248
|
const baseline = waveHeight / 2;
|
|
249
|
+
const barWidth = (waveWidth / frequencyData.length) * 0.8;
|
|
245
250
|
|
|
246
251
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
247
252
|
|
|
@@ -272,13 +277,47 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
272
277
|
protected drawLine(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array) {
|
|
273
278
|
const canvas = ctx.canvas;
|
|
274
279
|
const waveWidth = canvas.width;
|
|
275
|
-
const waveHeight = canvas.height
|
|
280
|
+
const waveHeight = canvas.height;
|
|
276
281
|
|
|
277
282
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
283
|
+
const path = new Path2D();
|
|
284
|
+
|
|
285
|
+
// Sample fewer points to make sharp angles more visible
|
|
286
|
+
const sampleRate = 4; // Only use every 4th point
|
|
278
287
|
|
|
279
|
-
|
|
288
|
+
for (let i = 0; i < frequencyData.length; i += sampleRate) {
|
|
289
|
+
const x = (i / frequencyData.length) * waveWidth;
|
|
290
|
+
const y = (1 - (frequencyData[i] ?? 0) / 255) * waveHeight;
|
|
291
|
+
|
|
292
|
+
if (i === 0) {
|
|
293
|
+
path.moveTo(x, y);
|
|
294
|
+
} else {
|
|
295
|
+
path.lineTo(x, y);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Ensure we draw to the end
|
|
300
|
+
const lastX = waveWidth;
|
|
301
|
+
const lastY =
|
|
302
|
+
(1 - (frequencyData[frequencyData.length - 1] ?? 0) / 255) * waveHeight;
|
|
303
|
+
path.lineTo(lastX, lastY);
|
|
304
|
+
|
|
305
|
+
ctx.lineWidth = this.lineWidth;
|
|
306
|
+
ctx.stroke(path);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
protected drawCurve(
|
|
310
|
+
ctx: CanvasRenderingContext2D,
|
|
311
|
+
frequencyData: Uint8Array,
|
|
312
|
+
) {
|
|
313
|
+
const canvas = ctx.canvas;
|
|
314
|
+
const waveWidth = canvas.width;
|
|
315
|
+
const waveHeight = canvas.height;
|
|
316
|
+
|
|
317
|
+
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
280
318
|
const path = new Path2D();
|
|
281
319
|
|
|
320
|
+
// Draw smooth curves between points using quadratic curves
|
|
282
321
|
frequencyData.forEach((value, i) => {
|
|
283
322
|
const x = (i / frequencyData.length) * waveWidth;
|
|
284
323
|
const y = (1 - value / 255) * waveHeight;
|
|
@@ -286,7 +325,11 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
286
325
|
if (i === 0) {
|
|
287
326
|
path.moveTo(x, y);
|
|
288
327
|
} else {
|
|
289
|
-
|
|
328
|
+
const prevX = ((i - 1) / frequencyData.length) * waveWidth;
|
|
329
|
+
const prevY = (1 - (frequencyData[i - 1] ?? 0) / 255) * waveHeight;
|
|
330
|
+
const xc = (prevX + x) / 2;
|
|
331
|
+
const yc = (prevY + y) / 2;
|
|
332
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
290
333
|
}
|
|
291
334
|
});
|
|
292
335
|
|
|
@@ -300,24 +343,21 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
300
343
|
) {
|
|
301
344
|
const canvas = ctx.canvas;
|
|
302
345
|
const waveWidth = canvas.width;
|
|
303
|
-
const waveHeight = canvas.height
|
|
346
|
+
const waveHeight = canvas.height;
|
|
304
347
|
const baseline = waveHeight / 2;
|
|
305
348
|
const barWidth = waveWidth / frequencyData.length;
|
|
306
349
|
|
|
307
350
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
308
|
-
|
|
309
|
-
// Create a single Path2D object for all pixels
|
|
310
351
|
const path = new Path2D();
|
|
311
352
|
|
|
312
353
|
frequencyData.forEach((value, i) => {
|
|
354
|
+
const normalizedValue = Math.min((value / 255) * 2, 1); // Updated normalization
|
|
313
355
|
const x = i * (waveWidth / frequencyData.length);
|
|
314
|
-
const barHeight = (
|
|
356
|
+
const barHeight = normalizedValue * (waveHeight / 2); // Half height since we extend both ways
|
|
315
357
|
const y = baseline - barHeight;
|
|
316
|
-
|
|
317
|
-
path.rect(x, y, barWidth, barHeight * 2);
|
|
358
|
+
path.rect(x, y, barWidth, barHeight * 2); // Double height to extend both ways
|
|
318
359
|
});
|
|
319
360
|
|
|
320
|
-
// Single fill operation for all pixels
|
|
321
361
|
ctx.fill(path);
|
|
322
362
|
}
|
|
323
363
|
|
|
@@ -325,54 +365,147 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
325
365
|
const canvas = ctx.canvas;
|
|
326
366
|
const waveWidth = canvas.width;
|
|
327
367
|
const waveHeight = canvas.height;
|
|
328
|
-
const
|
|
368
|
+
const paddingOuter = 0.01;
|
|
369
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
370
|
+
const startX = waveWidth * paddingOuter;
|
|
329
371
|
|
|
330
372
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
331
373
|
const path = new Path2D();
|
|
332
|
-
path.moveTo(0, baseline);
|
|
333
374
|
|
|
334
375
|
// Draw top curve
|
|
376
|
+
const firstValue = Math.min(((frequencyData[0] ?? 0) / 255) * 2, 1);
|
|
377
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
378
|
+
path.moveTo(startX, firstY);
|
|
379
|
+
|
|
380
|
+
// Draw top half
|
|
335
381
|
frequencyData.forEach((value, i) => {
|
|
336
|
-
const normalizedValue = value / 255;
|
|
337
|
-
const x = (i / (frequencyData.length - 1)) *
|
|
338
|
-
const
|
|
382
|
+
const normalizedValue = Math.min((value / 255) * 2, 1);
|
|
383
|
+
const x = startX + (i / (frequencyData.length - 1)) * availableWidth;
|
|
384
|
+
const barHeight = normalizedValue * waveHeight;
|
|
385
|
+
const y = (waveHeight - barHeight) / 2;
|
|
339
386
|
|
|
340
387
|
if (i === 0) {
|
|
341
388
|
path.moveTo(x, y);
|
|
342
389
|
} else {
|
|
343
|
-
const prevX =
|
|
390
|
+
const prevX =
|
|
391
|
+
startX + ((i - 1) / (frequencyData.length - 1)) * availableWidth;
|
|
392
|
+
const prevValue = Math.min(((frequencyData[i - 1] ?? 0) / 255) * 2, 1);
|
|
393
|
+
const prevBarHeight = prevValue * waveHeight;
|
|
394
|
+
const prevY = (waveHeight - prevBarHeight) / 2;
|
|
395
|
+
const xc = (prevX + x) / 2;
|
|
396
|
+
const yc = (prevY + y) / 2;
|
|
397
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Draw bottom half
|
|
402
|
+
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
403
|
+
const normalizedValue = Math.min(((frequencyData[i] ?? 0) / 255) * 2, 1);
|
|
404
|
+
const x = startX + (i / (frequencyData.length - 1)) * availableWidth;
|
|
405
|
+
const barHeight = normalizedValue * waveHeight;
|
|
406
|
+
const y = (waveHeight + barHeight) / 2;
|
|
407
|
+
|
|
408
|
+
if (i === frequencyData.length - 1) {
|
|
409
|
+
path.lineTo(x, y);
|
|
410
|
+
} else {
|
|
411
|
+
const nextX =
|
|
412
|
+
startX + ((i + 1) / (frequencyData.length - 1)) * availableWidth;
|
|
413
|
+
const nextValue = Math.min(((frequencyData[i + 1] ?? 0) / 255) * 2, 1);
|
|
414
|
+
const nextBarHeight = nextValue * waveHeight;
|
|
415
|
+
const nextY = (waveHeight + nextBarHeight) / 2;
|
|
416
|
+
const xc = (nextX + x) / 2;
|
|
417
|
+
const yc = (nextY + y) / 2;
|
|
418
|
+
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Close the path with a smooth curve back to start
|
|
423
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
424
|
+
const controlX = startX;
|
|
425
|
+
const controlY = (lastY + firstY) / 2;
|
|
426
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
427
|
+
|
|
428
|
+
ctx.fill(path);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
protected drawSpikes(
|
|
432
|
+
ctx: CanvasRenderingContext2D,
|
|
433
|
+
frequencyData: Uint8Array,
|
|
434
|
+
) {
|
|
435
|
+
const canvas = ctx.canvas;
|
|
436
|
+
const waveWidth = canvas.width;
|
|
437
|
+
const waveHeight = canvas.height;
|
|
438
|
+
const paddingOuter = 0.01;
|
|
439
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
440
|
+
const startX = waveWidth * paddingOuter;
|
|
441
|
+
|
|
442
|
+
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
443
|
+
const path = new Path2D();
|
|
444
|
+
|
|
445
|
+
// Draw top curve
|
|
446
|
+
const firstValue = (frequencyData[0] ?? 0) / 255;
|
|
447
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
448
|
+
path.moveTo(startX, firstY);
|
|
449
|
+
|
|
450
|
+
// Draw top half
|
|
451
|
+
frequencyData.forEach((value, i) => {
|
|
452
|
+
const normalizedValue = Math.min((value / 255) * 2, 1);
|
|
453
|
+
const x = startX + (i / (frequencyData.length - 1)) * availableWidth;
|
|
454
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
455
|
+
const y = (waveHeight - barHeight * 2) / 2;
|
|
456
|
+
|
|
457
|
+
if (i === 0) {
|
|
458
|
+
path.moveTo(x, y);
|
|
459
|
+
} else {
|
|
460
|
+
const prevX =
|
|
461
|
+
startX + ((i - 1) / (frequencyData.length - 1)) * availableWidth;
|
|
344
462
|
const prevValue = (frequencyData[i - 1] ?? 0) / 255;
|
|
345
|
-
const
|
|
463
|
+
const prevBarHeight = prevValue * (waveHeight / 2);
|
|
464
|
+
const prevY = (waveHeight - prevBarHeight * 2) / 2;
|
|
346
465
|
const xc = (prevX + x) / 2;
|
|
347
466
|
const yc = (prevY + y) / 2;
|
|
348
467
|
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
349
468
|
}
|
|
350
469
|
});
|
|
351
470
|
|
|
352
|
-
// Draw bottom
|
|
471
|
+
// Draw bottom half
|
|
353
472
|
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
354
|
-
const normalizedValue = (frequencyData[i] ?? 0) / 255;
|
|
355
|
-
const x = (i / (frequencyData.length - 1)) *
|
|
356
|
-
const
|
|
473
|
+
const normalizedValue = Math.min(((frequencyData[i] ?? 0) / 255) * 2, 1);
|
|
474
|
+
const x = startX + (i / (frequencyData.length - 1)) * availableWidth;
|
|
475
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
476
|
+
const y = (waveHeight + barHeight * 2) / 2;
|
|
357
477
|
|
|
358
478
|
if (i === frequencyData.length - 1) {
|
|
359
479
|
path.lineTo(x, y);
|
|
360
480
|
} else {
|
|
361
|
-
const nextX =
|
|
481
|
+
const nextX =
|
|
482
|
+
startX + ((i + 1) / (frequencyData.length - 1)) * availableWidth;
|
|
362
483
|
const nextValue = (frequencyData[i + 1] ?? 0) / 255;
|
|
363
|
-
const
|
|
484
|
+
const nextBarHeight = nextValue * (waveHeight / 2);
|
|
485
|
+
const nextY = (waveHeight + nextBarHeight * 2) / 2;
|
|
364
486
|
const xc = (nextX + x) / 2;
|
|
365
487
|
const yc = (nextY + y) / 2;
|
|
366
488
|
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
367
489
|
}
|
|
368
490
|
}
|
|
369
491
|
|
|
492
|
+
// Close the path with a smooth curve
|
|
493
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
494
|
+
const controlX = startX;
|
|
495
|
+
const controlY = (lastY + firstY) / 2;
|
|
496
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
497
|
+
|
|
370
498
|
ctx.fill(path);
|
|
371
499
|
}
|
|
372
500
|
|
|
373
501
|
frameTask = new Task(this, {
|
|
374
502
|
autoRun: EF_INTERACTIVE,
|
|
375
|
-
args: () =>
|
|
503
|
+
args: () => {
|
|
504
|
+
return [
|
|
505
|
+
this.targetElement,
|
|
506
|
+
this.targetElement?.frequencyDataTask.value,
|
|
507
|
+
] as const;
|
|
508
|
+
},
|
|
376
509
|
task: async () => {
|
|
377
510
|
if (!this.targetElement) return;
|
|
378
511
|
await this.targetElement.frequencyDataTask.taskComplete;
|
|
@@ -381,13 +514,18 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
381
514
|
if (!ctx) return;
|
|
382
515
|
|
|
383
516
|
const frequencyData = this.targetElement.frequencyDataTask.value;
|
|
384
|
-
|
|
517
|
+
const byteTimeData = this.targetElement.byteTimeDomainTask.value;
|
|
518
|
+
if (!frequencyData || !byteTimeData) return;
|
|
385
519
|
|
|
520
|
+
ctx.save();
|
|
386
521
|
if (this.color === "currentColor") {
|
|
387
522
|
const computedStyle = getComputedStyle(this);
|
|
388
523
|
const currentColor = computedStyle.color;
|
|
389
524
|
ctx.strokeStyle = currentColor;
|
|
390
525
|
ctx.fillStyle = currentColor;
|
|
526
|
+
} else {
|
|
527
|
+
ctx.strokeStyle = this.color;
|
|
528
|
+
ctx.fillStyle = this.color;
|
|
391
529
|
}
|
|
392
530
|
|
|
393
531
|
switch (this.mode) {
|
|
@@ -398,7 +536,10 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
398
536
|
this.drawBricks(ctx, frequencyData);
|
|
399
537
|
break;
|
|
400
538
|
case "line":
|
|
401
|
-
this.drawLine(ctx,
|
|
539
|
+
this.drawLine(ctx, byteTimeData);
|
|
540
|
+
break;
|
|
541
|
+
case "curve":
|
|
542
|
+
this.drawCurve(ctx, byteTimeData);
|
|
402
543
|
break;
|
|
403
544
|
case "pixel":
|
|
404
545
|
this.drawPixel(ctx, frequencyData);
|
|
@@ -406,10 +547,15 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
406
547
|
case "wave":
|
|
407
548
|
this.drawWave(ctx, frequencyData);
|
|
408
549
|
break;
|
|
550
|
+
case "spikes":
|
|
551
|
+
this.drawSpikes(ctx, frequencyData);
|
|
552
|
+
break;
|
|
409
553
|
case "roundBars":
|
|
410
554
|
this.drawRoundBars(ctx, frequencyData);
|
|
411
555
|
break;
|
|
412
556
|
}
|
|
557
|
+
|
|
558
|
+
ctx.restore();
|
|
413
559
|
},
|
|
414
560
|
});
|
|
415
561
|
|
|
@@ -418,14 +564,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
418
564
|
return this.targetElement.durationMs;
|
|
419
565
|
}
|
|
420
566
|
|
|
421
|
-
get targetElement() {
|
|
422
|
-
const target = document.getElementById(this.targetSelector ?? "");
|
|
423
|
-
if (target instanceof EFAudio || target instanceof EFVideo) {
|
|
424
|
-
return target;
|
|
425
|
-
}
|
|
426
|
-
return null;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
567
|
protected updated(changedProperties: PropertyValueMap<this>): void {
|
|
430
568
|
super.updated(changedProperties);
|
|
431
569
|
|
|
@@ -436,3 +574,9 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
436
574
|
}
|
|
437
575
|
}
|
|
438
576
|
}
|
|
577
|
+
|
|
578
|
+
declare global {
|
|
579
|
+
interface HTMLElementTagNameMap {
|
|
580
|
+
"ef-waveform": EFWaveform & Element;
|
|
581
|
+
}
|
|
582
|
+
}
|