@editframe/elements 0.12.0-beta.2 → 0.12.0-beta.21
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/elements/EFAudio.d.ts +1 -1
- package/dist/elements/EFCaptions.d.ts +5 -5
- package/dist/elements/EFImage.d.ts +1 -1
- package/dist/elements/EFMedia.browsertest.d.ts +1 -1
- package/dist/elements/EFMedia.d.ts +1 -2
- package/dist/elements/{src/elements/EFMedia.js → EFMedia.js} +72 -15
- package/dist/elements/EFTemporal.browsertest.d.ts +1 -1
- package/dist/elements/EFTemporal.d.ts +4 -1
- package/dist/elements/{src/elements/EFTemporal.js → EFTemporal.js} +3 -0
- package/dist/elements/EFTimegroup.browsertest.d.ts +2 -2
- package/dist/elements/EFTimegroup.d.ts +3 -3
- package/dist/elements/EFVideo.d.ts +1 -1
- package/dist/elements/{src/elements/EFVideo.js → EFVideo.js} +10 -2
- package/dist/elements/EFWaveform.d.ts +7 -4
- package/dist/elements/{src/elements/EFWaveform.js → EFWaveform.js} +48 -56
- package/dist/elements/TimegroupController.d.ts +2 -2
- package/dist/elements/util.d.ts +1 -1
- package/dist/gui/ContextMixin.browsertest.d.ts +1 -1
- package/dist/gui/ContextMixin.d.ts +1 -1
- package/dist/{elements/src/gui → gui}/ContextMixin.js +8 -4
- package/dist/gui/EFFilmstrip.d.ts +7 -7
- package/dist/gui/EFPreview.d.ts +1 -1
- package/dist/{elements/src/gui → gui}/EFPreview.js +3 -1
- package/dist/gui/EFScrubber.d.ts +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +1 -1
- package/dist/gui/EFToggleLoop.d.ts +1 -1
- package/dist/gui/EFTogglePlay.d.ts +1 -3
- package/dist/{elements/src/gui → gui}/EFTogglePlay.js +1 -9
- package/dist/gui/EFWorkbench.d.ts +1 -1
- package/dist/{elements/src/gui → gui}/TWMixin.css.js +1 -1
- package/dist/gui/efContext.d.ts +1 -1
- package/dist/index.d.ts +14 -14
- package/package.json +5 -4
- package/src/elements/EFAudio.ts +3 -3
- package/src/elements/EFCaptions.browsertest.ts +3 -3
- package/src/elements/EFCaptions.ts +9 -9
- package/src/elements/EFImage.browsertest.ts +2 -2
- package/src/elements/EFImage.ts +4 -4
- package/src/elements/EFMedia.browsertest.ts +7 -5
- package/src/elements/EFMedia.ts +91 -19
- package/src/elements/EFSourceMixin.ts +3 -3
- package/src/elements/EFTemporal.browsertest.ts +1 -1
- package/src/elements/EFTemporal.ts +9 -3
- package/src/elements/EFTimegroup.browsertest.ts +5 -5
- package/src/elements/EFTimegroup.ts +6 -6
- package/src/elements/EFVideo.ts +15 -4
- package/src/elements/EFWaveform.ts +82 -98
- package/src/elements/FetchMixin.ts +2 -2
- package/src/elements/TimegroupController.ts +2 -2
- package/src/elements/durationConverter.ts +1 -1
- package/src/elements/util.ts +1 -1
- package/src/gui/ContextMixin.browsertest.ts +3 -3
- package/src/gui/ContextMixin.ts +18 -12
- package/src/gui/EFFilmstrip.ts +15 -15
- package/src/gui/EFPreview.ts +5 -3
- package/src/gui/EFScrubber.ts +3 -3
- package/src/gui/EFTimeDisplay.ts +2 -2
- package/src/gui/EFToggleLoop.ts +4 -4
- package/src/gui/EFTogglePlay.ts +4 -10
- package/src/gui/EFWorkbench.ts +2 -2
- package/src/gui/efContext.ts +1 -1
- package/dist/assets/src/EncodedAsset.js +0 -560
- package/dist/assets/src/MP4File.js +0 -172
- package/dist/assets/src/memoize.js +0 -14
- package/dist/elements/src/elements/util.js +0 -11
- package/dist/{elements/src/EF_FRAMEGEN.js → EF_FRAMEGEN.js} +0 -0
- package/dist/{elements/src/EF_INTERACTIVE.js → EF_INTERACTIVE.js} +0 -0
- package/dist/{elements/src/EF_RENDERING.js → EF_RENDERING.js} +0 -0
- package/dist/elements/{src/elements/CrossUpdateController.js → CrossUpdateController.js} +0 -0
- package/dist/elements/{src/elements/EFAudio.js → EFAudio.js} +2 -2
- package/dist/elements/{src/elements/EFCaptions.js → EFCaptions.js} +0 -0
- package/dist/elements/{src/elements/EFImage.js → EFImage.js} +0 -0
- package/dist/elements/{src/elements/EFSourceMixin.js → EFSourceMixin.js} +1 -1
- package/dist/elements/{src/elements/EFTimegroup.js → EFTimegroup.js} +0 -0
- package/dist/elements/{src/elements/FetchMixin.js → FetchMixin.js} +0 -0
- package/dist/elements/{src/elements/TimegroupController.js → TimegroupController.js} +0 -0
- package/dist/elements/{src/elements/durationConverter.js → durationConverter.js} +0 -0
- package/dist/elements/{src/elements/parseTimeToMs.js → parseTimeToMs.js} +0 -0
- package/dist/{elements/src/gui → gui}/EFFilmstrip.js +0 -0
- package/dist/{elements/src/gui → gui}/EFScrubber.js +0 -0
- package/dist/{elements/src/gui → gui}/EFTimeDisplay.js +0 -0
- package/dist/{elements/src/gui → gui}/EFToggleLoop.js +1 -1
- /package/dist/{elements/src/gui → gui}/EFWorkbench.js +0 -0
- /package/dist/{elements/src/gui → gui}/TWMixin.js +0 -0
- /package/dist/{elements/src/gui → gui}/apiHostContext.js +0 -0
- /package/dist/{elements/src/gui → gui}/efContext.js +0 -0
- /package/dist/{elements/src/gui → gui}/fetchContext.js +0 -0
- /package/dist/{elements/src/gui → gui}/focusContext.js +0 -0
- /package/dist/{elements/src/gui → gui}/focusedElementContext.js +0 -0
- /package/dist/{elements/src/gui → gui}/playingContext.js +0 -0
- /package/dist/{elements/src/index.js → index.js} +0 -0
- /package/dist/{elements/src/msToTimeCode.js → msToTimeCode.js} +0 -0
|
@@ -4,17 +4,17 @@ import debug from "debug";
|
|
|
4
4
|
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
5
5
|
import { customElement, property } from "lit/decorators.js";
|
|
6
6
|
|
|
7
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.
|
|
8
|
-
import { isContextMixin } from "../gui/ContextMixin.
|
|
9
|
-
import { deepGetMediaElements } from "./EFMedia.
|
|
7
|
+
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
8
|
+
import { isContextMixin } from "../gui/ContextMixin.js";
|
|
9
|
+
import { deepGetMediaElements } from "./EFMedia.js";
|
|
10
10
|
import {
|
|
11
11
|
EFTemporal,
|
|
12
12
|
isEFTemporal,
|
|
13
13
|
shallowGetTemporalElements,
|
|
14
14
|
timegroupContext,
|
|
15
|
-
} from "./EFTemporal.
|
|
16
|
-
import { TimegroupController } from "./TimegroupController.
|
|
17
|
-
import { durationConverter } from "./durationConverter.
|
|
15
|
+
} from "./EFTemporal.js";
|
|
16
|
+
import { TimegroupController } from "./TimegroupController.js";
|
|
17
|
+
import { durationConverter } from "./durationConverter.js";
|
|
18
18
|
|
|
19
19
|
const log = debug("ef:elements:EFTimegroup");
|
|
20
20
|
|
package/src/elements/EFVideo.ts
CHANGED
|
@@ -3,8 +3,8 @@ import { css, html } from "lit";
|
|
|
3
3
|
import { customElement } from "lit/decorators.js";
|
|
4
4
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
5
5
|
|
|
6
|
-
import { TWMixin } from "../gui/TWMixin.
|
|
7
|
-
import { EFMedia } from "./EFMedia.
|
|
6
|
+
import { TWMixin } from "../gui/TWMixin.js";
|
|
7
|
+
import { EFMedia } from "./EFMedia.js";
|
|
8
8
|
|
|
9
9
|
@customElement("ef-video")
|
|
10
10
|
export class EFVideo extends TWMixin(EFMedia) {
|
|
@@ -78,9 +78,20 @@ export class EFVideo extends TWMixin(EFMedia) {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
if (frame?.codedWidth && frame?.codedHeight) {
|
|
82
|
+
if (
|
|
83
|
+
this.canvasElement.width !== frame.codedWidth ||
|
|
84
|
+
this.canvasElement.height !== frame.codedHeight
|
|
85
|
+
) {
|
|
86
|
+
this.canvasElement.width = frame.codedWidth;
|
|
87
|
+
this.canvasElement.height = frame.codedHeight;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
83
90
|
|
|
91
|
+
if (frame.format === null) {
|
|
92
|
+
console.warn("Frame format is null", frame);
|
|
93
|
+
return seekToMs;
|
|
94
|
+
}
|
|
84
95
|
ctx.drawImage(
|
|
85
96
|
frame,
|
|
86
97
|
0,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { EFAudio } from "./EFAudio.
|
|
1
|
+
import { EFAudio } from "./EFAudio.js";
|
|
2
2
|
|
|
3
3
|
import { Task } from "@lit/task";
|
|
4
4
|
import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
5
5
|
import { customElement, property } from "lit/decorators.js";
|
|
6
6
|
import { type Ref, createRef, ref } from "lit/directives/ref.js";
|
|
7
|
-
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.
|
|
8
|
-
import { TWMixin } from "../gui/TWMixin.
|
|
9
|
-
import { CrossUpdateController } from "./CrossUpdateController.
|
|
10
|
-
import { EFTemporal } from "./EFTemporal.
|
|
11
|
-
import { EFVideo } from "./EFVideo.
|
|
7
|
+
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
8
|
+
import { TWMixin } from "../gui/TWMixin.js";
|
|
9
|
+
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
10
|
+
import { EFTemporal } from "./EFTemporal.js";
|
|
11
|
+
import { EFVideo } from "./EFVideo.js";
|
|
12
12
|
|
|
13
13
|
@customElement("ef-waveform")
|
|
14
14
|
export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
@@ -24,6 +24,9 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
24
24
|
canvasRef: Ref<HTMLCanvasElement> = createRef();
|
|
25
25
|
private ctx: CanvasRenderingContext2D | null = null;
|
|
26
26
|
|
|
27
|
+
private resizeObserver?: ResizeObserver;
|
|
28
|
+
private mutationObserver?: MutationObserver;
|
|
29
|
+
|
|
27
30
|
createRenderRoot() {
|
|
28
31
|
return this;
|
|
29
32
|
}
|
|
@@ -61,10 +64,43 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
61
64
|
if (this.targetElement) {
|
|
62
65
|
new CrossUpdateController(this.targetElement, this);
|
|
63
66
|
}
|
|
67
|
+
|
|
68
|
+
// Initialize ResizeObserver
|
|
69
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
70
|
+
this.resizeCanvas();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Observe the host element
|
|
74
|
+
this.resizeObserver.observe(this);
|
|
75
|
+
|
|
76
|
+
// Initialize MutationObserver
|
|
77
|
+
this.mutationObserver = new MutationObserver((mutationsList) => {
|
|
78
|
+
for (const mutation of mutationsList) {
|
|
79
|
+
if (mutation.type === "attributes") {
|
|
80
|
+
this.frameTask.run();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Observe attribute changes on the element
|
|
86
|
+
this.mutationObserver.observe(this, { attributes: true });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
disconnectedCallback() {
|
|
90
|
+
super.disconnectedCallback();
|
|
91
|
+
// Disconnect the observers when the element is removed from the DOM
|
|
92
|
+
this.resizeObserver?.disconnect();
|
|
93
|
+
this.mutationObserver?.disconnect();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private resizeCanvas() {
|
|
97
|
+
this.ctx = this.initCanvas();
|
|
98
|
+
if (this.ctx) {
|
|
99
|
+
this.frameTask.run(); // Redraw the canvas
|
|
100
|
+
}
|
|
64
101
|
}
|
|
65
102
|
|
|
66
103
|
protected initCanvas() {
|
|
67
|
-
console.count("initCanvas");
|
|
68
104
|
const canvas = this.canvasRef.value;
|
|
69
105
|
if (!canvas) return null;
|
|
70
106
|
|
|
@@ -87,9 +123,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
87
123
|
}
|
|
88
124
|
|
|
89
125
|
protected drawBars(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array) {
|
|
90
|
-
ctx.strokeStyle = this.color;
|
|
91
|
-
ctx.fillStyle = this.color;
|
|
92
|
-
|
|
93
126
|
const canvas = ctx.canvas;
|
|
94
127
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
95
128
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -111,9 +144,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
111
144
|
ctx: CanvasRenderingContext2D,
|
|
112
145
|
frequencyData: Uint8Array,
|
|
113
146
|
) {
|
|
114
|
-
ctx.strokeStyle = this.color;
|
|
115
|
-
ctx.fillStyle = this.color;
|
|
116
|
-
|
|
117
147
|
const canvas = ctx.canvas;
|
|
118
148
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
119
149
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -144,9 +174,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
144
174
|
}
|
|
145
175
|
|
|
146
176
|
protected drawLine(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array) {
|
|
147
|
-
ctx.strokeStyle = this.color;
|
|
148
|
-
ctx.fillStyle = this.color;
|
|
149
|
-
|
|
150
177
|
const canvas = ctx.canvas;
|
|
151
178
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
152
179
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -173,9 +200,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
173
200
|
ctx: CanvasRenderingContext2D,
|
|
174
201
|
frequencyData: Uint8Array,
|
|
175
202
|
) {
|
|
176
|
-
ctx.strokeStyle = this.color;
|
|
177
|
-
ctx.fillStyle = this.color;
|
|
178
|
-
|
|
179
203
|
const canvas = ctx.canvas;
|
|
180
204
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
181
205
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -202,9 +226,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
202
226
|
ctx: CanvasRenderingContext2D,
|
|
203
227
|
frequencyData: Uint8Array,
|
|
204
228
|
) {
|
|
205
|
-
ctx.strokeStyle = this.color;
|
|
206
|
-
ctx.fillStyle = this.color;
|
|
207
|
-
|
|
208
229
|
const canvas = ctx.canvas;
|
|
209
230
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
210
231
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -234,9 +255,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
234
255
|
ctx: CanvasRenderingContext2D,
|
|
235
256
|
frequencyData: Uint8Array,
|
|
236
257
|
) {
|
|
237
|
-
ctx.strokeStyle = this.color;
|
|
238
|
-
ctx.fillStyle = this.color;
|
|
239
|
-
|
|
240
258
|
const canvas = ctx.canvas;
|
|
241
259
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
242
260
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -263,9 +281,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
263
281
|
ctx: CanvasRenderingContext2D,
|
|
264
282
|
frequencyData: Uint8Array,
|
|
265
283
|
) {
|
|
266
|
-
ctx.strokeStyle = this.color;
|
|
267
|
-
ctx.fillStyle = this.color;
|
|
268
|
-
|
|
269
284
|
const canvas = ctx.canvas;
|
|
270
285
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
271
286
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -284,9 +299,6 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
protected drawWave(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array) {
|
|
287
|
-
ctx.strokeStyle = this.color;
|
|
288
|
-
ctx.fillStyle = this.color;
|
|
289
|
-
|
|
290
302
|
const canvas = ctx.canvas;
|
|
291
303
|
const waveWidth = canvas.width / devicePixelRatio;
|
|
292
304
|
const waveHeight = canvas.height / devicePixelRatio;
|
|
@@ -300,7 +312,7 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
300
312
|
ctx.moveTo(0, baseline);
|
|
301
313
|
ctx.lineTo(waveWidth, baseline);
|
|
302
314
|
ctx.strokeStyle = this.color;
|
|
303
|
-
ctx.lineWidth =
|
|
315
|
+
ctx.lineWidth = 1;
|
|
304
316
|
ctx.stroke();
|
|
305
317
|
|
|
306
318
|
// Draw bars
|
|
@@ -313,21 +325,10 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
313
325
|
});
|
|
314
326
|
}
|
|
315
327
|
|
|
316
|
-
// Add this property to store the last frame timestamp
|
|
317
|
-
private lastFrameTime = 0;
|
|
318
|
-
|
|
319
328
|
frameTask = new Task(this, {
|
|
320
329
|
autoRun: EF_INTERACTIVE,
|
|
321
330
|
args: () => [this.targetElement.audioBufferTask.status] as const,
|
|
322
331
|
task: async () => {
|
|
323
|
-
// Calculate and log time since last frame
|
|
324
|
-
const currentTime = performance.now();
|
|
325
|
-
const timeSinceLastFrame = this.lastFrameTime
|
|
326
|
-
? currentTime - this.lastFrameTime
|
|
327
|
-
: 0;
|
|
328
|
-
console.log(`Time since last frame: ${timeSinceLastFrame.toFixed(2)}ms`);
|
|
329
|
-
this.lastFrameTime = currentTime;
|
|
330
|
-
|
|
331
332
|
await this.targetElement.audioBufferTask.taskComplete;
|
|
332
333
|
// Lazy initialize canvas, if we don't stash it, we re-init
|
|
333
334
|
// every frame, which blanks the canvas, causing flicker.
|
|
@@ -338,61 +339,44 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
338
339
|
if (!this.targetElement.audioBufferTask.value) return;
|
|
339
340
|
|
|
340
341
|
if (this.targetElement.trimAdjustedOwnCurrentTimeMs > 0) {
|
|
341
|
-
const
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
const dataLength = multiFrameData[0]?.length ?? 0;
|
|
379
|
-
|
|
380
|
-
// Average and enhance dynamics
|
|
381
|
-
const smoothedData = new Uint8Array(dataLength);
|
|
382
|
-
for (let i = 0; i < smoothedData.length; i++) {
|
|
383
|
-
let sum = 0;
|
|
384
|
-
for (const frameData of multiFrameData) {
|
|
385
|
-
sum += frameData[i] ?? 0;
|
|
386
|
-
}
|
|
387
|
-
let avg = sum / FRAMES_TO_ANALYZE;
|
|
388
|
-
|
|
389
|
-
// Enhance dynamics by applying a subtle exponential curve
|
|
390
|
-
avg = (avg / 255) ** 1.2 * 255;
|
|
391
|
-
|
|
392
|
-
smoothedData[i] = Math.round(avg);
|
|
342
|
+
const FRAME_DURATION_MS = 48000 / 1000;
|
|
343
|
+
const FRAME_SMEAR_MS = FRAME_DURATION_MS * 1;
|
|
344
|
+
const FRAME_SMEAR_S = FRAME_SMEAR_MS / 1000;
|
|
345
|
+
|
|
346
|
+
const audioContext = new OfflineAudioContext(2, 48000 / 25, 48000);
|
|
347
|
+
const audioBufferSource = audioContext.createBufferSource();
|
|
348
|
+
audioBufferSource.buffer =
|
|
349
|
+
this.targetElement.audioBufferTask.value.buffer;
|
|
350
|
+
const analyser = audioContext.createAnalyser();
|
|
351
|
+
|
|
352
|
+
// Adjust FFT size for better frequency resolution
|
|
353
|
+
analyser.fftSize = 128 * 8;
|
|
354
|
+
|
|
355
|
+
audioBufferSource.connect(analyser);
|
|
356
|
+
|
|
357
|
+
const startTime = Math.max(
|
|
358
|
+
0,
|
|
359
|
+
(this.targetElement.trimAdjustedOwnCurrentTimeMs -
|
|
360
|
+
this.targetElement.audioBufferTask.value.startOffsetMs) /
|
|
361
|
+
1000,
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
audioBufferSource.start(0, startTime, FRAME_SMEAR_S);
|
|
365
|
+
await audioContext.startRendering();
|
|
366
|
+
|
|
367
|
+
const frameData = new Uint8Array(analyser.frequencyBinCount);
|
|
368
|
+
analyser.getByteFrequencyData(frameData);
|
|
369
|
+
|
|
370
|
+
const smoothedData = frameData.slice(0, frameData.length / 2);
|
|
371
|
+
|
|
372
|
+
if (this.color === "currentColor") {
|
|
373
|
+
const computedStyle = getComputedStyle(this);
|
|
374
|
+
const currentColor = computedStyle.color;
|
|
375
|
+
ctx.strokeStyle = currentColor;
|
|
376
|
+
ctx.fillStyle = currentColor;
|
|
377
|
+
} else {
|
|
393
378
|
}
|
|
394
379
|
|
|
395
|
-
// Use smoothedData for rendering
|
|
396
380
|
switch (this.mode) {
|
|
397
381
|
case "bars":
|
|
398
382
|
this.drawBars(ctx, smoothedData);
|
|
@@ -438,8 +422,8 @@ export class EFWaveform extends EFTemporal(TWMixin(LitElement)) {
|
|
|
438
422
|
protected updated(changedProperties: PropertyValueMap<this>): void {
|
|
439
423
|
super.updated(changedProperties);
|
|
440
424
|
|
|
441
|
-
// Trigger a redraw if
|
|
442
|
-
if (changedProperties.
|
|
425
|
+
// Trigger a redraw if any property changes
|
|
426
|
+
if (changedProperties.size > 0) {
|
|
443
427
|
// Request a new frame
|
|
444
428
|
this.frameTask.run();
|
|
445
429
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { LitElement } from "lit";
|
|
2
1
|
import { consume } from "@lit/context";
|
|
2
|
+
import type { LitElement } from "lit";
|
|
3
3
|
import { state } from "lit/decorators/state.js";
|
|
4
4
|
|
|
5
|
-
import { fetchContext } from "../gui/fetchContext.
|
|
5
|
+
import { fetchContext } from "../gui/fetchContext.js";
|
|
6
6
|
|
|
7
7
|
export declare class FetchMixinInterface {
|
|
8
8
|
fetch: typeof fetch;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { EFTimegroup } from "./EFTimegroup.
|
|
1
|
+
import type { LitElement, ReactiveController } from "lit";
|
|
2
|
+
import type { EFTimegroup } from "./EFTimegroup.js";
|
|
3
3
|
|
|
4
4
|
export class TimegroupController implements ReactiveController {
|
|
5
5
|
constructor(
|
package/src/elements/util.ts
CHANGED
|
@@ -3,11 +3,11 @@ import { customElement } from "lit/decorators/custom-element.js";
|
|
|
3
3
|
import { describe, expect, test, vi } from "vitest";
|
|
4
4
|
|
|
5
5
|
import { consume } from "@lit/context";
|
|
6
|
-
import { ContextMixin } from "./ContextMixin.
|
|
7
|
-
import { apiHostContext } from "./apiHostContext.
|
|
6
|
+
import { ContextMixin } from "./ContextMixin.js";
|
|
7
|
+
import { apiHostContext } from "./apiHostContext.js";
|
|
8
8
|
|
|
9
9
|
// Required to test timeupdate event, we need a duration, and timegroups are a quick way to do that
|
|
10
|
-
import "../elements/EFTimegroup.
|
|
10
|
+
import "../elements/EFTimegroup.js";
|
|
11
11
|
|
|
12
12
|
@customElement("test-context")
|
|
13
13
|
class TestContext extends ContextMixin(LitElement) {}
|
package/src/gui/ContextMixin.ts
CHANGED
|
@@ -3,13 +3,13 @@ import type { LitElement } from "lit";
|
|
|
3
3
|
import { property, state } from "lit/decorators.js";
|
|
4
4
|
|
|
5
5
|
import { createRef } from "lit/directives/ref.js";
|
|
6
|
-
import type { EFTimegroup } from "../elements/EFTimegroup.
|
|
7
|
-
import { apiHostContext } from "./apiHostContext.
|
|
8
|
-
import { efContext } from "./efContext.
|
|
9
|
-
import { fetchContext } from "./fetchContext.
|
|
10
|
-
import { type FocusContext, focusContext } from "./focusContext.
|
|
11
|
-
import { focusedElementContext } from "./focusedElementContext.
|
|
12
|
-
import { loopContext, playingContext } from "./playingContext.
|
|
6
|
+
import type { EFTimegroup } from "../elements/EFTimegroup.js";
|
|
7
|
+
import { apiHostContext } from "./apiHostContext.js";
|
|
8
|
+
import { efContext } from "./efContext.js";
|
|
9
|
+
import { fetchContext } from "./fetchContext.js";
|
|
10
|
+
import { type FocusContext, focusContext } from "./focusContext.js";
|
|
11
|
+
import { focusedElementContext } from "./focusedElementContext.js";
|
|
12
|
+
import { loopContext, playingContext } from "./playingContext.js";
|
|
13
13
|
|
|
14
14
|
export declare class ContextMixinInterface extends LitElement {
|
|
15
15
|
signingURL?: string;
|
|
@@ -136,18 +136,19 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
|
|
|
136
136
|
const canvasHeight = canvasElement.clientHeight;
|
|
137
137
|
const stageRatio = stageWidth / stageHeight;
|
|
138
138
|
const canvasRatio = canvasWidth / canvasHeight;
|
|
139
|
+
|
|
139
140
|
if (stageRatio > canvasRatio) {
|
|
140
141
|
const scale = stageHeight / canvasHeight;
|
|
141
142
|
if (this.stageScale !== scale) {
|
|
142
143
|
canvasElement.style.transform = `scale(${scale})`;
|
|
143
|
-
canvasElement.style.transformOrigin = "
|
|
144
|
+
canvasElement.style.transformOrigin = "center";
|
|
144
145
|
}
|
|
145
146
|
this.stageScale = scale;
|
|
146
147
|
} else {
|
|
147
148
|
const scale = stageWidth / canvasWidth;
|
|
148
149
|
if (this.stageScale !== scale) {
|
|
149
150
|
canvasElement.style.transform = `scale(${scale})`;
|
|
150
|
-
canvasElement.style.transformOrigin = "
|
|
151
|
+
canvasElement.style.transformOrigin = "center";
|
|
151
152
|
}
|
|
152
153
|
this.stageScale = scale;
|
|
153
154
|
}
|
|
@@ -251,6 +252,14 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
|
|
|
251
252
|
await timegroup.waitForMediaDurations();
|
|
252
253
|
|
|
253
254
|
let currentMs = timegroup.currentTimeMs;
|
|
255
|
+
const fromMs = currentMs;
|
|
256
|
+
const toMs = timegroup.endTimeMs;
|
|
257
|
+
|
|
258
|
+
if (fromMs >= toMs) {
|
|
259
|
+
this.pause();
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
254
263
|
let bufferCount = 0;
|
|
255
264
|
this.#playbackAudioContext = new AudioContext({
|
|
256
265
|
latencyHint: "playback",
|
|
@@ -280,9 +289,6 @@ export function ContextMixin<T extends Constructor<LitElement>>(superClass: T) {
|
|
|
280
289
|
}
|
|
281
290
|
};
|
|
282
291
|
|
|
283
|
-
const fromMs = currentMs;
|
|
284
|
-
const toMs = timegroup.endTimeMs;
|
|
285
|
-
|
|
286
292
|
const queueBufferSource = async () => {
|
|
287
293
|
if (currentMs >= toMs) {
|
|
288
294
|
return false;
|
package/src/gui/EFFilmstrip.ts
CHANGED
|
@@ -17,21 +17,21 @@ import {
|
|
|
17
17
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
18
18
|
import { styleMap } from "lit/directives/style-map.js";
|
|
19
19
|
|
|
20
|
-
import { EFAudio } from "../elements/EFAudio.
|
|
21
|
-
import { EFCaptions, EFCaptionsActiveWord } from "../elements/EFCaptions.
|
|
22
|
-
import { EFImage } from "../elements/EFImage.
|
|
23
|
-
import type { TemporalMixinInterface } from "../elements/EFTemporal.
|
|
24
|
-
import { EFTimegroup } from "../elements/EFTimegroup.
|
|
25
|
-
import { EFVideo } from "../elements/EFVideo.
|
|
26
|
-
import { EFWaveform } from "../elements/EFWaveform.
|
|
27
|
-
import { TimegroupController } from "../elements/TimegroupController.
|
|
28
|
-
import { msToTimeCode } from "../msToTimeCode.
|
|
29
|
-
import type { EFPreview } from "./EFPreview.
|
|
30
|
-
import type { EFWorkbench } from "./EFWorkbench.
|
|
31
|
-
import { TWMixin } from "./TWMixin.
|
|
32
|
-
import { type FocusContext, focusContext } from "./focusContext.
|
|
33
|
-
import { focusedElementContext } from "./focusedElementContext.
|
|
34
|
-
import { loopContext, playingContext } from "./playingContext.
|
|
20
|
+
import { EFAudio } from "../elements/EFAudio.js";
|
|
21
|
+
import { EFCaptions, EFCaptionsActiveWord } from "../elements/EFCaptions.js";
|
|
22
|
+
import { EFImage } from "../elements/EFImage.js";
|
|
23
|
+
import type { TemporalMixinInterface } from "../elements/EFTemporal.js";
|
|
24
|
+
import { EFTimegroup } from "../elements/EFTimegroup.js";
|
|
25
|
+
import { EFVideo } from "../elements/EFVideo.js";
|
|
26
|
+
import { EFWaveform } from "../elements/EFWaveform.js";
|
|
27
|
+
import { TimegroupController } from "../elements/TimegroupController.js";
|
|
28
|
+
import { msToTimeCode } from "../msToTimeCode.js";
|
|
29
|
+
import type { EFPreview } from "./EFPreview.js";
|
|
30
|
+
import type { EFWorkbench } from "./EFWorkbench.js";
|
|
31
|
+
import { TWMixin } from "./TWMixin.js";
|
|
32
|
+
import { type FocusContext, focusContext } from "./focusContext.js";
|
|
33
|
+
import { focusedElementContext } from "./focusedElementContext.js";
|
|
34
|
+
import { loopContext, playingContext } from "./playingContext.js";
|
|
35
35
|
|
|
36
36
|
class ElementFilmstripController implements ReactiveController {
|
|
37
37
|
constructor(
|
package/src/gui/EFPreview.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { LitElement,
|
|
1
|
+
import { LitElement, css, html } from "lit";
|
|
2
2
|
import { customElement } from "lit/decorators.js";
|
|
3
3
|
import { ref } from "lit/directives/ref.js";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { ContextMixin } from "./ContextMixin.js";
|
|
6
|
+
import { TWMixin } from "./TWMixin.js";
|
|
7
7
|
|
|
8
8
|
@customElement("ef-preview")
|
|
9
9
|
export class EFPreview extends ContextMixin(TWMixin(LitElement)) {
|
|
@@ -26,7 +26,9 @@ export class EFPreview extends ContextMixin(TWMixin(LitElement)) {
|
|
|
26
26
|
<slot
|
|
27
27
|
${ref(this.canvasRef)}
|
|
28
28
|
class="inline-block"
|
|
29
|
+
name="canvas"
|
|
29
30
|
></slot>
|
|
31
|
+
<slot name="controls"></slot>
|
|
30
32
|
</div>
|
|
31
33
|
`;
|
|
32
34
|
}
|
package/src/gui/EFScrubber.ts
CHANGED
|
@@ -3,9 +3,9 @@ import { LitElement, css, html } from "lit";
|
|
|
3
3
|
import { customElement, state } from "lit/decorators.js";
|
|
4
4
|
|
|
5
5
|
import { ref } from "lit/directives/ref.js";
|
|
6
|
-
import type { ContextMixinInterface } from "./ContextMixin.
|
|
7
|
-
import { efContext } from "./efContext.
|
|
8
|
-
import { playingContext } from "./playingContext.
|
|
6
|
+
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
7
|
+
import { efContext } from "./efContext.js";
|
|
8
|
+
import { playingContext } from "./playingContext.js";
|
|
9
9
|
|
|
10
10
|
@customElement("ef-scrubber")
|
|
11
11
|
export class EFScrubber extends LitElement {
|
package/src/gui/EFTimeDisplay.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { consume } from "@lit/context";
|
|
2
2
|
import { LitElement, css, html } from "lit";
|
|
3
3
|
import { customElement } from "lit/decorators.js";
|
|
4
|
-
import type { ContextMixinInterface } from "./ContextMixin.
|
|
5
|
-
import { efContext } from "./efContext.
|
|
4
|
+
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
5
|
+
import { efContext } from "./efContext.js";
|
|
6
6
|
|
|
7
7
|
@customElement("ef-time-display")
|
|
8
8
|
export class EFTimeDisplay extends LitElement {
|
package/src/gui/EFToggleLoop.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { css, html, LitElement } from "lit";
|
|
2
|
-
import { customElement } from "lit/decorators.js";
|
|
3
1
|
import { consume } from "@lit/context";
|
|
2
|
+
import { LitElement, css, html } from "lit";
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
5
|
+
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
6
|
+
import { efContext } from "./efContext.js";
|
|
7
7
|
|
|
8
8
|
@customElement("ef-toggle-loop")
|
|
9
9
|
export class EFToggleLoop extends LitElement {
|
package/src/gui/EFTogglePlay.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { consume } from "@lit/context";
|
|
2
2
|
import { LitElement, css, html } from "lit";
|
|
3
|
-
import { customElement
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
4
4
|
|
|
5
|
-
import type { ContextMixinInterface } from "./ContextMixin.
|
|
6
|
-
import { efContext } from "./efContext.
|
|
7
|
-
import { playingContext } from "./playingContext.
|
|
5
|
+
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
6
|
+
import { efContext } from "./efContext.js";
|
|
7
|
+
import { playingContext } from "./playingContext.js";
|
|
8
8
|
|
|
9
9
|
@customElement("ef-toggle-play")
|
|
10
10
|
export class EFTogglePlay extends LitElement {
|
|
@@ -23,12 +23,6 @@ export class EFTogglePlay extends LitElement {
|
|
|
23
23
|
@consume({ context: playingContext, subscribe: true })
|
|
24
24
|
playing = false;
|
|
25
25
|
|
|
26
|
-
@property({ type: String })
|
|
27
|
-
play = '<button class="text-2xl cursor-pointer">▶️</button>';
|
|
28
|
-
|
|
29
|
-
@property({ type: String })
|
|
30
|
-
pause = '<button class="text-2xl cursor-pointer">⏸️</button>';
|
|
31
|
-
|
|
32
26
|
render() {
|
|
33
27
|
return html`
|
|
34
28
|
<div
|
package/src/gui/EFWorkbench.ts
CHANGED
|
@@ -2,8 +2,8 @@ import { LitElement, type PropertyValueMap, css, html } from "lit";
|
|
|
2
2
|
import { customElement, eventOptions } from "lit/decorators.js";
|
|
3
3
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
4
4
|
|
|
5
|
-
import { ContextMixin } from "./ContextMixin.
|
|
6
|
-
import { TWMixin } from "./TWMixin.
|
|
5
|
+
import { ContextMixin } from "./ContextMixin.js";
|
|
6
|
+
import { TWMixin } from "./TWMixin.js";
|
|
7
7
|
|
|
8
8
|
@customElement("ef-workbench")
|
|
9
9
|
export class EFWorkbench extends ContextMixin(TWMixin(LitElement)) {
|
package/src/gui/efContext.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createContext } from "@lit/context";
|
|
2
|
-
import type { ContextMixinInterface } from "./ContextMixin.
|
|
2
|
+
import type { ContextMixinInterface } from "./ContextMixin.js";
|
|
3
3
|
|
|
4
4
|
export const efContext = createContext<ContextMixinInterface | null>(
|
|
5
5
|
Symbol("efContext"),
|