@editframe/elements 0.14.0-beta.3 → 0.15.0-beta.3
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/EFImage.d.ts +2 -1
- package/dist/elements/EFImage.js +9 -3
- package/dist/elements/EFMedia.d.ts +7 -0
- package/dist/elements/EFMedia.js +159 -8
- package/dist/elements/EFTemporal.d.ts +7 -3
- package/dist/elements/EFTemporal.js +19 -1
- package/dist/elements/EFTimegroup.d.ts +1 -5
- package/dist/elements/EFTimegroup.js +5 -6
- package/dist/elements/EFWaveform.d.ts +16 -8
- package/dist/elements/EFWaveform.js +244 -164
- 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/EFWorkbench.js +1 -1
- package/package.json +3 -2
- package/src/elements/EFAudio.ts +1 -4
- package/src/elements/EFCaptions.ts +1 -1
- package/src/elements/EFImage.browsertest.ts +33 -2
- package/src/elements/EFImage.ts +10 -3
- package/src/elements/EFMedia.ts +187 -6
- package/src/elements/EFTemporal.ts +37 -5
- package/src/elements/EFTimegroup.ts +5 -7
- package/src/elements/EFWaveform.ts +302 -204
- package/src/elements/TargetController.test.ts +229 -0
- package/src/elements/TargetController.ts +219 -0
- package/src/gui/EFPreview.ts +10 -9
- package/src/gui/EFWorkbench.ts +1 -1
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CSSStyleObserver } from "@bramus/style-observer";
|
|
2
2
|
import { Task } from "@lit/task";
|
|
3
3
|
import { html, css, LitElement } from "lit";
|
|
4
|
-
import { property, customElement } from "lit/decorators.js";
|
|
4
|
+
import { property, state, customElement } from "lit/decorators.js";
|
|
5
5
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
6
6
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
7
|
+
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
7
8
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
8
9
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
9
10
|
import { EFTemporal } from "./EFTemporal.js";
|
|
10
|
-
import {
|
|
11
|
+
import { TargetController } from "./TargetController.js";
|
|
11
12
|
var __defProp = Object.defineProperty;
|
|
12
13
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
14
|
var __decorateClass = (decorators, target, key, kind) => {
|
|
@@ -23,83 +24,76 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
23
24
|
super(...arguments);
|
|
24
25
|
this.canvasRef = createRef();
|
|
25
26
|
this.ctx = null;
|
|
27
|
+
this.styleObserver = null;
|
|
26
28
|
this.mode = "bars";
|
|
27
29
|
this.color = "currentColor";
|
|
28
|
-
this.
|
|
30
|
+
this.target = "";
|
|
31
|
+
this.targetElement = null;
|
|
32
|
+
this.lineWidth = 4;
|
|
33
|
+
this.targetController = new TargetController(this);
|
|
29
34
|
this.frameTask = new Task(this, {
|
|
30
35
|
autoRun: EF_INTERACTIVE,
|
|
31
|
-
args: () =>
|
|
36
|
+
args: () => {
|
|
37
|
+
return [
|
|
38
|
+
this.targetElement,
|
|
39
|
+
this.targetElement?.frequencyDataTask.value
|
|
40
|
+
];
|
|
41
|
+
},
|
|
32
42
|
task: async () => {
|
|
33
|
-
|
|
43
|
+
if (!this.targetElement) return;
|
|
44
|
+
await this.targetElement.frequencyDataTask.taskComplete;
|
|
34
45
|
this.ctx ||= this.initCanvas();
|
|
35
46
|
const ctx = this.ctx;
|
|
36
47
|
if (!ctx) return;
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const startTime = Math.max(
|
|
49
|
-
0,
|
|
50
|
-
(this.targetElement.trimAdjustedOwnCurrentTimeMs - this.targetElement.audioBufferTask.value.startOffsetMs) / 1e3
|
|
51
|
-
);
|
|
52
|
-
audioBufferSource.start(0, startTime, FRAME_SMEAR_S);
|
|
53
|
-
await audioContext.startRendering();
|
|
54
|
-
const frameData = new Uint8Array(analyser.frequencyBinCount);
|
|
55
|
-
analyser.getByteFrequencyData(frameData);
|
|
56
|
-
const smoothedData = frameData.slice(0, frameData.length / 2);
|
|
57
|
-
if (this.color === "currentColor") {
|
|
58
|
-
const computedStyle = getComputedStyle(this);
|
|
59
|
-
const currentColor = computedStyle.color;
|
|
60
|
-
ctx.strokeStyle = currentColor;
|
|
61
|
-
ctx.fillStyle = currentColor;
|
|
62
|
-
}
|
|
63
|
-
switch (this.mode) {
|
|
64
|
-
case "bars":
|
|
65
|
-
this.drawBars(ctx, smoothedData);
|
|
66
|
-
break;
|
|
67
|
-
case "bricks":
|
|
68
|
-
this.drawBricks(ctx, smoothedData);
|
|
69
|
-
break;
|
|
70
|
-
case "curve":
|
|
71
|
-
this.drawCurve(ctx, smoothedData);
|
|
72
|
-
break;
|
|
73
|
-
case "line":
|
|
74
|
-
this.drawLine(ctx, smoothedData);
|
|
75
|
-
break;
|
|
76
|
-
case "pixel":
|
|
77
|
-
this.drawPixel(ctx, smoothedData);
|
|
78
|
-
break;
|
|
79
|
-
case "wave":
|
|
80
|
-
this.drawWave(ctx, smoothedData);
|
|
81
|
-
break;
|
|
82
|
-
case "roundBars":
|
|
83
|
-
this.drawRoundBars(ctx, smoothedData);
|
|
84
|
-
break;
|
|
85
|
-
case "equalizer":
|
|
86
|
-
this.drawEqualizer(ctx, smoothedData);
|
|
87
|
-
break;
|
|
88
|
-
}
|
|
48
|
+
const frequencyData = this.targetElement.frequencyDataTask.value;
|
|
49
|
+
if (!frequencyData) return;
|
|
50
|
+
ctx.save();
|
|
51
|
+
if (this.color === "currentColor") {
|
|
52
|
+
const computedStyle = getComputedStyle(this);
|
|
53
|
+
const currentColor = computedStyle.color;
|
|
54
|
+
ctx.strokeStyle = currentColor;
|
|
55
|
+
ctx.fillStyle = currentColor;
|
|
56
|
+
} else {
|
|
57
|
+
ctx.strokeStyle = this.color;
|
|
58
|
+
ctx.fillStyle = this.color;
|
|
89
59
|
}
|
|
60
|
+
switch (this.mode) {
|
|
61
|
+
case "bars":
|
|
62
|
+
this.drawBars(ctx, frequencyData);
|
|
63
|
+
break;
|
|
64
|
+
case "bricks":
|
|
65
|
+
this.drawBricks(ctx, frequencyData);
|
|
66
|
+
break;
|
|
67
|
+
case "line":
|
|
68
|
+
this.drawLine(ctx, frequencyData);
|
|
69
|
+
break;
|
|
70
|
+
case "pixel":
|
|
71
|
+
this.drawPixel(ctx, frequencyData);
|
|
72
|
+
break;
|
|
73
|
+
case "wave":
|
|
74
|
+
this.drawWave(ctx, frequencyData);
|
|
75
|
+
break;
|
|
76
|
+
case "spikes":
|
|
77
|
+
this.drawSpikes(ctx, frequencyData);
|
|
78
|
+
break;
|
|
79
|
+
case "roundBars":
|
|
80
|
+
this.drawRoundBars(ctx, frequencyData);
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
ctx.restore();
|
|
90
84
|
}
|
|
91
85
|
});
|
|
92
86
|
}
|
|
93
87
|
render() {
|
|
94
88
|
return html`<canvas ${ref(this.canvasRef)}></canvas>`;
|
|
95
89
|
}
|
|
96
|
-
set target(value) {
|
|
97
|
-
this.targetSelector = value;
|
|
98
|
-
}
|
|
99
90
|
connectedCallback() {
|
|
100
91
|
super.connectedCallback();
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
try {
|
|
93
|
+
if (this.targetElement) {
|
|
94
|
+
new CrossUpdateController(this.targetElement, this);
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
103
97
|
}
|
|
104
98
|
this.resizeObserver = new ResizeObserver(() => {
|
|
105
99
|
this.resizeCanvas();
|
|
@@ -113,11 +107,18 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
113
107
|
}
|
|
114
108
|
});
|
|
115
109
|
this.mutationObserver.observe(this, { attributes: true });
|
|
110
|
+
if (!EF_RENDERING()) {
|
|
111
|
+
this.styleObserver = new CSSStyleObserver(["color"], () => {
|
|
112
|
+
this.frameTask.run();
|
|
113
|
+
});
|
|
114
|
+
this.styleObserver.attach(this);
|
|
115
|
+
}
|
|
116
116
|
}
|
|
117
117
|
disconnectedCallback() {
|
|
118
118
|
super.disconnectedCallback();
|
|
119
119
|
this.resizeObserver?.disconnect();
|
|
120
120
|
this.mutationObserver?.disconnect();
|
|
121
|
+
this.styleObserver?.detach();
|
|
121
122
|
}
|
|
122
123
|
resizeCanvas() {
|
|
123
124
|
this.ctx = this.initCanvas();
|
|
@@ -128,7 +129,10 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
128
129
|
initCanvas() {
|
|
129
130
|
const canvas = this.canvasRef.value;
|
|
130
131
|
if (!canvas) return null;
|
|
131
|
-
const rect =
|
|
132
|
+
const rect = {
|
|
133
|
+
width: this.offsetWidth,
|
|
134
|
+
height: this.offsetHeight
|
|
135
|
+
};
|
|
132
136
|
const dpr = window.devicePixelRatio;
|
|
133
137
|
canvas.style.width = `${rect.width}px`;
|
|
134
138
|
canvas.style.height = `${rect.height}px`;
|
|
@@ -137,163 +141,233 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
137
141
|
const ctx = canvas.getContext("2d");
|
|
138
142
|
if (!ctx) return null;
|
|
139
143
|
ctx.reset();
|
|
140
|
-
ctx.scale(dpr, dpr);
|
|
141
144
|
return ctx;
|
|
142
145
|
}
|
|
143
146
|
drawBars(ctx, frequencyData) {
|
|
144
147
|
const canvas = ctx.canvas;
|
|
145
|
-
const waveWidth = canvas.width
|
|
146
|
-
const waveHeight = canvas.height
|
|
147
|
-
const
|
|
148
|
-
const
|
|
148
|
+
const waveWidth = canvas.width;
|
|
149
|
+
const waveHeight = canvas.height;
|
|
150
|
+
const totalBars = frequencyData.length;
|
|
151
|
+
const paddingInner = 0.5;
|
|
152
|
+
const paddingOuter = 0.01;
|
|
153
|
+
const availableWidth = waveWidth;
|
|
154
|
+
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
149
155
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
156
|
+
const path = new Path2D();
|
|
150
157
|
frequencyData.forEach((value, i) => {
|
|
151
|
-
const
|
|
152
|
-
const
|
|
153
|
-
const y =
|
|
154
|
-
|
|
158
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
159
|
+
const barHeight = normalizedValue * waveHeight;
|
|
160
|
+
const y = (waveHeight - barHeight) / 2;
|
|
161
|
+
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
162
|
+
path.rect(x, y, barWidth, barHeight);
|
|
155
163
|
});
|
|
164
|
+
ctx.fill(path);
|
|
156
165
|
}
|
|
157
166
|
drawBricks(ctx, frequencyData) {
|
|
158
167
|
const canvas = ctx.canvas;
|
|
159
|
-
const waveWidth = canvas.width
|
|
160
|
-
const waveHeight = canvas.height
|
|
161
|
-
const brickWidth = waveWidth / frequencyData.length;
|
|
162
|
-
const brickHeightFactor = waveHeight / 255 / 2;
|
|
163
|
-
const brickPadding = 2;
|
|
164
|
-
const midHeight = waveHeight / 2;
|
|
165
|
-
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
166
|
-
ctx.beginPath();
|
|
167
|
-
ctx.setLineDash([2]);
|
|
168
|
-
ctx.lineWidth = 4;
|
|
169
|
-
ctx.moveTo(0, midHeight);
|
|
170
|
-
ctx.lineTo(waveWidth, midHeight);
|
|
171
|
-
ctx.stroke();
|
|
172
|
-
ctx.setLineDash([]);
|
|
173
|
-
frequencyData.forEach((value, i) => {
|
|
174
|
-
const x = i * brickWidth;
|
|
175
|
-
const height = value * brickHeightFactor * 2;
|
|
176
|
-
const y = midHeight - height / 2;
|
|
177
|
-
ctx.fillRect(x, y, brickWidth - brickPadding, height);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
drawLine(ctx, frequencyData) {
|
|
181
|
-
const canvas = ctx.canvas;
|
|
182
|
-
const waveWidth = canvas.width / devicePixelRatio;
|
|
183
|
-
const waveHeight = canvas.height / devicePixelRatio;
|
|
168
|
+
const waveWidth = canvas.width;
|
|
169
|
+
const waveHeight = canvas.height;
|
|
184
170
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
185
|
-
|
|
171
|
+
const path = new Path2D();
|
|
172
|
+
const columnWidth = waveWidth / frequencyData.length;
|
|
173
|
+
const boxSize = columnWidth * 0.9;
|
|
174
|
+
const verticalGap = boxSize * 0.2;
|
|
175
|
+
const maxBricks = Math.floor(waveHeight / (boxSize + verticalGap));
|
|
186
176
|
frequencyData.forEach((value, i) => {
|
|
187
|
-
const
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
177
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
178
|
+
const brickCount = Math.floor(normalizedValue * maxBricks);
|
|
179
|
+
for (let j = 0; j < brickCount; j++) {
|
|
180
|
+
const x = columnWidth * i;
|
|
181
|
+
const y = waveHeight - (j + 1) * (boxSize + verticalGap);
|
|
182
|
+
path.rect(x, y, boxSize, boxSize);
|
|
193
183
|
}
|
|
194
184
|
});
|
|
195
|
-
ctx.
|
|
196
|
-
ctx.stroke();
|
|
185
|
+
ctx.fill(path);
|
|
197
186
|
}
|
|
198
187
|
drawRoundBars(ctx, frequencyData) {
|
|
199
188
|
const canvas = ctx.canvas;
|
|
200
|
-
const waveWidth = canvas.width
|
|
201
|
-
const waveHeight = canvas.height
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
189
|
+
const waveWidth = canvas.width;
|
|
190
|
+
const waveHeight = canvas.height;
|
|
191
|
+
const totalBars = frequencyData.length;
|
|
192
|
+
const paddingInner = 0.5;
|
|
193
|
+
const paddingOuter = 0.01;
|
|
194
|
+
const availableWidth = waveWidth;
|
|
195
|
+
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
205
196
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
197
|
+
const path = new Path2D();
|
|
206
198
|
frequencyData.forEach((value, i) => {
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
ctx.roundRect(x, y, barWidth, Math.max(height * 2, 2), radius);
|
|
213
|
-
ctx.fill();
|
|
199
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
200
|
+
const height = normalizedValue * waveHeight;
|
|
201
|
+
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
202
|
+
const y = (waveHeight - height) / 2;
|
|
203
|
+
path.roundRect(x, y, barWidth, height, barWidth / 2);
|
|
214
204
|
});
|
|
205
|
+
ctx.fill(path);
|
|
215
206
|
}
|
|
216
207
|
drawEqualizer(ctx, frequencyData) {
|
|
217
208
|
const canvas = ctx.canvas;
|
|
218
|
-
const waveWidth = canvas.width
|
|
219
|
-
const waveHeight = canvas.height
|
|
220
|
-
const barWidth = waveWidth / frequencyData.length * 0.8;
|
|
209
|
+
const waveWidth = canvas.width;
|
|
210
|
+
const waveHeight = canvas.height;
|
|
221
211
|
const baseline = waveHeight / 2;
|
|
212
|
+
const barWidth = waveWidth / frequencyData.length * 0.8;
|
|
222
213
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
ctx.stroke();
|
|
214
|
+
const baselinePath = new Path2D();
|
|
215
|
+
const barsPath = new Path2D();
|
|
216
|
+
baselinePath.moveTo(0, baseline);
|
|
217
|
+
baselinePath.lineTo(waveWidth, baseline);
|
|
228
218
|
frequencyData.forEach((value, i) => {
|
|
229
219
|
const height = value / 255 * (waveHeight / 2);
|
|
230
220
|
const x = i * (waveWidth / frequencyData.length);
|
|
231
221
|
const y = baseline - height;
|
|
232
|
-
|
|
222
|
+
barsPath.rect(x, y, barWidth, Math.max(height * 2, 1));
|
|
233
223
|
});
|
|
224
|
+
ctx.lineWidth = 2;
|
|
225
|
+
ctx.stroke(baselinePath);
|
|
226
|
+
ctx.fill(barsPath);
|
|
234
227
|
}
|
|
235
|
-
|
|
228
|
+
drawLine(ctx, frequencyData) {
|
|
236
229
|
const canvas = ctx.canvas;
|
|
237
|
-
const waveWidth = canvas.width
|
|
238
|
-
const waveHeight = canvas.height
|
|
230
|
+
const waveWidth = canvas.width;
|
|
231
|
+
const waveHeight = canvas.height;
|
|
239
232
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
240
|
-
|
|
233
|
+
const path = new Path2D();
|
|
241
234
|
frequencyData.forEach((value, i) => {
|
|
242
235
|
const x = i / frequencyData.length * waveWidth;
|
|
243
236
|
const y = (1 - value / 255) * waveHeight;
|
|
244
237
|
if (i === 0) {
|
|
245
|
-
|
|
238
|
+
path.moveTo(x, y);
|
|
246
239
|
} else {
|
|
247
|
-
|
|
240
|
+
path.lineTo(x, y);
|
|
248
241
|
}
|
|
249
242
|
});
|
|
250
|
-
ctx.lineWidth =
|
|
251
|
-
ctx.stroke();
|
|
243
|
+
ctx.lineWidth = this.lineWidth;
|
|
244
|
+
ctx.stroke(path);
|
|
252
245
|
}
|
|
253
246
|
drawPixel(ctx, frequencyData) {
|
|
254
247
|
const canvas = ctx.canvas;
|
|
255
|
-
const waveWidth = canvas.width
|
|
256
|
-
const waveHeight = canvas.height
|
|
248
|
+
const waveWidth = canvas.width;
|
|
249
|
+
const waveHeight = canvas.height;
|
|
257
250
|
const baseline = waveHeight / 2;
|
|
258
|
-
const barWidth = waveWidth / frequencyData.length
|
|
251
|
+
const barWidth = waveWidth / frequencyData.length;
|
|
259
252
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
253
|
+
const path = new Path2D();
|
|
260
254
|
frequencyData.forEach((value, i) => {
|
|
255
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
261
256
|
const x = i * (waveWidth / frequencyData.length);
|
|
262
|
-
const barHeight =
|
|
257
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
263
258
|
const y = baseline - barHeight;
|
|
264
|
-
|
|
259
|
+
path.rect(x, y, barWidth, barHeight * 2);
|
|
265
260
|
});
|
|
261
|
+
ctx.fill(path);
|
|
266
262
|
}
|
|
267
263
|
drawWave(ctx, frequencyData) {
|
|
268
264
|
const canvas = ctx.canvas;
|
|
269
|
-
const waveWidth = canvas.width
|
|
270
|
-
const waveHeight = canvas.height
|
|
271
|
-
const
|
|
272
|
-
const
|
|
265
|
+
const waveWidth = canvas.width;
|
|
266
|
+
const waveHeight = canvas.height;
|
|
267
|
+
const paddingOuter = 0.01;
|
|
268
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
269
|
+
const startX = waveWidth * paddingOuter;
|
|
273
270
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
ctx.lineWidth = 1;
|
|
279
|
-
ctx.stroke();
|
|
271
|
+
const path = new Path2D();
|
|
272
|
+
const firstValue = Math.min((frequencyData[0] ?? 0) / 255 * 2, 1);
|
|
273
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
274
|
+
path.moveTo(startX, firstY);
|
|
280
275
|
frequencyData.forEach((value, i) => {
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const
|
|
284
|
-
|
|
276
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
277
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
278
|
+
const barHeight = normalizedValue * waveHeight;
|
|
279
|
+
const y = (waveHeight - barHeight) / 2;
|
|
280
|
+
if (i === 0) {
|
|
281
|
+
path.moveTo(x, y);
|
|
282
|
+
} else {
|
|
283
|
+
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
284
|
+
const prevValue = Math.min((frequencyData[i - 1] ?? 0) / 255 * 2, 1);
|
|
285
|
+
const prevBarHeight = prevValue * waveHeight;
|
|
286
|
+
const prevY = (waveHeight - prevBarHeight) / 2;
|
|
287
|
+
const xc = (prevX + x) / 2;
|
|
288
|
+
const yc = (prevY + y) / 2;
|
|
289
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
290
|
+
}
|
|
285
291
|
});
|
|
292
|
+
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
293
|
+
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
294
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
295
|
+
const barHeight = normalizedValue * waveHeight;
|
|
296
|
+
const y = (waveHeight + barHeight) / 2;
|
|
297
|
+
if (i === frequencyData.length - 1) {
|
|
298
|
+
path.lineTo(x, y);
|
|
299
|
+
} else {
|
|
300
|
+
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
301
|
+
const nextValue = Math.min((frequencyData[i + 1] ?? 0) / 255 * 2, 1);
|
|
302
|
+
const nextBarHeight = nextValue * waveHeight;
|
|
303
|
+
const nextY = (waveHeight + nextBarHeight) / 2;
|
|
304
|
+
const xc = (nextX + x) / 2;
|
|
305
|
+
const yc = (nextY + y) / 2;
|
|
306
|
+
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
310
|
+
const controlX = startX;
|
|
311
|
+
const controlY = (lastY + firstY) / 2;
|
|
312
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
313
|
+
ctx.fill(path);
|
|
314
|
+
}
|
|
315
|
+
drawSpikes(ctx, frequencyData) {
|
|
316
|
+
const canvas = ctx.canvas;
|
|
317
|
+
const waveWidth = canvas.width;
|
|
318
|
+
const waveHeight = canvas.height;
|
|
319
|
+
const paddingOuter = 0.01;
|
|
320
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
321
|
+
const startX = waveWidth * paddingOuter;
|
|
322
|
+
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
323
|
+
const path = new Path2D();
|
|
324
|
+
const firstValue = (frequencyData[0] ?? 0) / 255;
|
|
325
|
+
const firstY = (waveHeight - firstValue * waveHeight) / 2;
|
|
326
|
+
path.moveTo(startX, firstY);
|
|
327
|
+
frequencyData.forEach((value, i) => {
|
|
328
|
+
const normalizedValue = Math.min(value / 255 * 2, 1);
|
|
329
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
330
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
331
|
+
const y = (waveHeight - barHeight * 2) / 2;
|
|
332
|
+
if (i === 0) {
|
|
333
|
+
path.moveTo(x, y);
|
|
334
|
+
} else {
|
|
335
|
+
const prevX = startX + (i - 1) / (frequencyData.length - 1) * availableWidth;
|
|
336
|
+
const prevValue = (frequencyData[i - 1] ?? 0) / 255;
|
|
337
|
+
const prevBarHeight = prevValue * (waveHeight / 2);
|
|
338
|
+
const prevY = (waveHeight - prevBarHeight * 2) / 2;
|
|
339
|
+
const xc = (prevX + x) / 2;
|
|
340
|
+
const yc = (prevY + y) / 2;
|
|
341
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
345
|
+
const normalizedValue = Math.min((frequencyData[i] ?? 0) / 255 * 2, 1);
|
|
346
|
+
const x = startX + i / (frequencyData.length - 1) * availableWidth;
|
|
347
|
+
const barHeight = normalizedValue * (waveHeight / 2);
|
|
348
|
+
const y = (waveHeight + barHeight * 2) / 2;
|
|
349
|
+
if (i === frequencyData.length - 1) {
|
|
350
|
+
path.lineTo(x, y);
|
|
351
|
+
} else {
|
|
352
|
+
const nextX = startX + (i + 1) / (frequencyData.length - 1) * availableWidth;
|
|
353
|
+
const nextValue = (frequencyData[i + 1] ?? 0) / 255;
|
|
354
|
+
const nextBarHeight = nextValue * (waveHeight / 2);
|
|
355
|
+
const nextY = (waveHeight + nextBarHeight * 2) / 2;
|
|
356
|
+
const xc = (nextX + x) / 2;
|
|
357
|
+
const yc = (nextY + y) / 2;
|
|
358
|
+
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
const lastY = (waveHeight + firstValue * waveHeight) / 2;
|
|
362
|
+
const controlX = startX;
|
|
363
|
+
const controlY = (lastY + firstY) / 2;
|
|
364
|
+
path.quadraticCurveTo(controlX, controlY, startX, firstY);
|
|
365
|
+
ctx.fill(path);
|
|
286
366
|
}
|
|
287
367
|
get durationMs() {
|
|
368
|
+
if (!this.targetElement) return 0;
|
|
288
369
|
return this.targetElement.durationMs;
|
|
289
370
|
}
|
|
290
|
-
get targetElement() {
|
|
291
|
-
const target = document.getElementById(this.targetSelector ?? "");
|
|
292
|
-
if (target instanceof EFAudio || target instanceof EFVideo) {
|
|
293
|
-
return target;
|
|
294
|
-
}
|
|
295
|
-
throw new Error("Invalid target, must be an EFAudio or EFVideo element");
|
|
296
|
-
}
|
|
297
371
|
updated(changedProperties) {
|
|
298
372
|
super.updated(changedProperties);
|
|
299
373
|
if (changedProperties.size > 0) {
|
|
@@ -326,8 +400,14 @@ __decorateClass([
|
|
|
326
400
|
property({ type: String })
|
|
327
401
|
], EFWaveform.prototype, "color", 2);
|
|
328
402
|
__decorateClass([
|
|
329
|
-
property({ type: String,
|
|
330
|
-
], EFWaveform.prototype, "
|
|
403
|
+
property({ type: String, reflect: true })
|
|
404
|
+
], EFWaveform.prototype, "target", 2);
|
|
405
|
+
__decorateClass([
|
|
406
|
+
state()
|
|
407
|
+
], EFWaveform.prototype, "targetElement", 2);
|
|
408
|
+
__decorateClass([
|
|
409
|
+
property({ type: Number, attribute: "line-width" })
|
|
410
|
+
], EFWaveform.prototype, "lineWidth", 2);
|
|
331
411
|
EFWaveform = __decorateClass([
|
|
332
412
|
customElement("ef-waveform")
|
|
333
413
|
], EFWaveform);
|
|
@@ -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 {};
|