@editframe/elements 0.14.0-beta.2 → 0.15.0-beta.1
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/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 +133 -5
- package/dist/elements/EFTemporal.d.ts +4 -0
- package/dist/elements/EFTemporal.js +14 -0
- package/dist/elements/EFTimegroup.js +1 -1
- package/dist/elements/EFWaveform.d.ts +6 -5
- package/dist/elements/EFWaveform.js +152 -144
- package/dist/gui/EFWorkbench.js +1 -1
- package/package.json +3 -2
- package/src/elements/EFImage.browsertest.ts +33 -2
- package/src/elements/EFImage.ts +10 -3
- package/src/elements/EFMedia.ts +163 -1
- package/src/elements/EFTemporal.ts +33 -1
- package/src/elements/EFTimegroup.ts +5 -2
- package/src/elements/EFWaveform.ts +188 -185
- package/src/gui/EFWorkbench.ts +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { EFAudio } from "./EFAudio.js";
|
|
2
|
+
import { CSSStyleObserver } from "@bramus/style-observer";
|
|
2
3
|
import { Task } from "@lit/task";
|
|
3
4
|
import { html, css, LitElement } from "lit";
|
|
4
5
|
import { property, customElement } from "lit/decorators.js";
|
|
5
6
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
6
7
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
8
|
+
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
7
9
|
import { TWMixin } from "../gui/TWMixin.js";
|
|
8
10
|
import { CrossUpdateController } from "./CrossUpdateController.js";
|
|
9
11
|
import { EFTemporal } from "./EFTemporal.js";
|
|
@@ -23,69 +25,47 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
23
25
|
super(...arguments);
|
|
24
26
|
this.canvasRef = createRef();
|
|
25
27
|
this.ctx = null;
|
|
28
|
+
this.styleObserver = null;
|
|
26
29
|
this.mode = "bars";
|
|
27
30
|
this.color = "currentColor";
|
|
28
31
|
this.targetSelector = "";
|
|
32
|
+
this.lineWidth = 4;
|
|
29
33
|
this.frameTask = new Task(this, {
|
|
30
34
|
autoRun: EF_INTERACTIVE,
|
|
31
|
-
args: () => [this.targetElement.
|
|
35
|
+
args: () => [this.targetElement?.frequencyDataTask.status],
|
|
32
36
|
task: async () => {
|
|
33
|
-
|
|
37
|
+
if (!this.targetElement) return;
|
|
38
|
+
await this.targetElement.frequencyDataTask.taskComplete;
|
|
34
39
|
this.ctx ||= this.initCanvas();
|
|
35
40
|
const ctx = this.ctx;
|
|
36
41
|
if (!ctx) return;
|
|
37
|
-
|
|
38
|
-
if (
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
}
|
|
42
|
+
const frequencyData = this.targetElement.frequencyDataTask.value;
|
|
43
|
+
if (!frequencyData) return;
|
|
44
|
+
if (this.color === "currentColor") {
|
|
45
|
+
const computedStyle = getComputedStyle(this);
|
|
46
|
+
const currentColor = computedStyle.color;
|
|
47
|
+
ctx.strokeStyle = currentColor;
|
|
48
|
+
ctx.fillStyle = currentColor;
|
|
49
|
+
}
|
|
50
|
+
switch (this.mode) {
|
|
51
|
+
case "bars":
|
|
52
|
+
this.drawBars(ctx, frequencyData);
|
|
53
|
+
break;
|
|
54
|
+
case "bricks":
|
|
55
|
+
this.drawBricks(ctx, frequencyData);
|
|
56
|
+
break;
|
|
57
|
+
case "line":
|
|
58
|
+
this.drawLine(ctx, frequencyData);
|
|
59
|
+
break;
|
|
60
|
+
case "pixel":
|
|
61
|
+
this.drawPixel(ctx, frequencyData);
|
|
62
|
+
break;
|
|
63
|
+
case "wave":
|
|
64
|
+
this.drawWave(ctx, frequencyData);
|
|
65
|
+
break;
|
|
66
|
+
case "roundBars":
|
|
67
|
+
this.drawRoundBars(ctx, frequencyData);
|
|
68
|
+
break;
|
|
89
69
|
}
|
|
90
70
|
}
|
|
91
71
|
});
|
|
@@ -98,8 +78,11 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
98
78
|
}
|
|
99
79
|
connectedCallback() {
|
|
100
80
|
super.connectedCallback();
|
|
101
|
-
|
|
102
|
-
|
|
81
|
+
try {
|
|
82
|
+
if (this.targetElement) {
|
|
83
|
+
new CrossUpdateController(this.targetElement, this);
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {
|
|
103
86
|
}
|
|
104
87
|
this.resizeObserver = new ResizeObserver(() => {
|
|
105
88
|
this.resizeCanvas();
|
|
@@ -113,11 +96,18 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
113
96
|
}
|
|
114
97
|
});
|
|
115
98
|
this.mutationObserver.observe(this, { attributes: true });
|
|
99
|
+
if (!EF_RENDERING()) {
|
|
100
|
+
this.styleObserver = new CSSStyleObserver(["color"], () => {
|
|
101
|
+
this.frameTask.run();
|
|
102
|
+
});
|
|
103
|
+
this.styleObserver.attach(this);
|
|
104
|
+
}
|
|
116
105
|
}
|
|
117
106
|
disconnectedCallback() {
|
|
118
107
|
super.disconnectedCallback();
|
|
119
108
|
this.resizeObserver?.disconnect();
|
|
120
109
|
this.mutationObserver?.disconnect();
|
|
110
|
+
this.styleObserver?.detach();
|
|
121
111
|
}
|
|
122
112
|
resizeCanvas() {
|
|
123
113
|
this.ctx = this.initCanvas();
|
|
@@ -128,7 +118,10 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
128
118
|
initCanvas() {
|
|
129
119
|
const canvas = this.canvasRef.value;
|
|
130
120
|
if (!canvas) return null;
|
|
131
|
-
const rect =
|
|
121
|
+
const rect = {
|
|
122
|
+
width: this.offsetWidth,
|
|
123
|
+
height: this.offsetHeight
|
|
124
|
+
};
|
|
132
125
|
const dpr = window.devicePixelRatio;
|
|
133
126
|
canvas.style.width = `${rect.width}px`;
|
|
134
127
|
canvas.style.height = `${rect.height}px`;
|
|
@@ -142,149 +135,161 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
142
135
|
}
|
|
143
136
|
drawBars(ctx, frequencyData) {
|
|
144
137
|
const canvas = ctx.canvas;
|
|
145
|
-
const waveWidth = canvas.width
|
|
146
|
-
const waveHeight = canvas.height
|
|
147
|
-
const
|
|
148
|
-
const
|
|
138
|
+
const waveWidth = canvas.width;
|
|
139
|
+
const waveHeight = canvas.height;
|
|
140
|
+
const baseline = waveHeight / 4;
|
|
141
|
+
const totalBars = frequencyData.length;
|
|
142
|
+
const paddingInner = 0.5;
|
|
143
|
+
const paddingOuter = 0.01;
|
|
144
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
145
|
+
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
149
146
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
147
|
+
const path = new Path2D();
|
|
150
148
|
frequencyData.forEach((value, i) => {
|
|
151
|
-
const
|
|
152
|
-
const
|
|
149
|
+
const normalizedValue = value / 255;
|
|
150
|
+
const height = normalizedValue * (waveHeight / 2);
|
|
151
|
+
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
153
152
|
const y = baseline - height;
|
|
154
|
-
|
|
153
|
+
path.rect(x, y, barWidth, height * 2);
|
|
155
154
|
});
|
|
155
|
+
ctx.fill(path);
|
|
156
156
|
}
|
|
157
157
|
drawBricks(ctx, frequencyData) {
|
|
158
158
|
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;
|
|
159
|
+
const waveWidth = canvas.width;
|
|
160
|
+
const waveHeight = canvas.height;
|
|
184
161
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
185
|
-
|
|
162
|
+
const path = new Path2D();
|
|
163
|
+
const columnWidth = waveWidth / frequencyData.length;
|
|
164
|
+
const boxSize = columnWidth * 0.9;
|
|
186
165
|
frequencyData.forEach((value, i) => {
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
ctx.lineTo(x, y);
|
|
166
|
+
const brickHeight = value / 255 * waveHeight;
|
|
167
|
+
for (let j = 0; j <= brickHeight; j++) {
|
|
168
|
+
const x = columnWidth * i;
|
|
169
|
+
const y = waveHeight - (j * columnWidth + boxSize);
|
|
170
|
+
path.rect(x, y, boxSize, boxSize);
|
|
193
171
|
}
|
|
194
172
|
});
|
|
195
|
-
ctx.
|
|
196
|
-
ctx.stroke();
|
|
173
|
+
ctx.fill(path);
|
|
197
174
|
}
|
|
198
175
|
drawRoundBars(ctx, frequencyData) {
|
|
199
176
|
const canvas = ctx.canvas;
|
|
200
|
-
const waveWidth = canvas.width
|
|
201
|
-
const waveHeight = canvas.height
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
177
|
+
const waveWidth = canvas.width;
|
|
178
|
+
const waveHeight = canvas.height;
|
|
179
|
+
const baseline = waveHeight / 4;
|
|
180
|
+
const totalBars = frequencyData.length;
|
|
181
|
+
const paddingInner = 0.5;
|
|
182
|
+
const paddingOuter = 0.01;
|
|
183
|
+
const availableWidth = waveWidth * (1 - 2 * paddingOuter);
|
|
184
|
+
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
205
185
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
186
|
+
const path = new Path2D();
|
|
206
187
|
frequencyData.forEach((value, i) => {
|
|
207
|
-
const
|
|
208
|
-
const
|
|
188
|
+
const normalizedValue = value / 255;
|
|
189
|
+
const height = normalizedValue * (waveHeight / 2);
|
|
190
|
+
const x = waveWidth * paddingOuter + i * (barWidth * (1 + paddingInner));
|
|
209
191
|
const y = baseline - height;
|
|
210
|
-
|
|
211
|
-
ctx.beginPath();
|
|
212
|
-
ctx.roundRect(x, y, barWidth, Math.max(height * 2, 2), radius);
|
|
213
|
-
ctx.fill();
|
|
192
|
+
path.roundRect(x, y, barWidth, height * 2, barWidth / 2);
|
|
214
193
|
});
|
|
194
|
+
ctx.fill(path);
|
|
215
195
|
}
|
|
216
196
|
drawEqualizer(ctx, frequencyData) {
|
|
217
197
|
const canvas = ctx.canvas;
|
|
218
|
-
const waveWidth = canvas.width
|
|
219
|
-
const waveHeight = canvas.height /
|
|
198
|
+
const waveWidth = canvas.width;
|
|
199
|
+
const waveHeight = canvas.height / 2;
|
|
220
200
|
const barWidth = waveWidth / frequencyData.length * 0.8;
|
|
221
201
|
const baseline = waveHeight / 2;
|
|
222
202
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
ctx.stroke();
|
|
203
|
+
const baselinePath = new Path2D();
|
|
204
|
+
const barsPath = new Path2D();
|
|
205
|
+
baselinePath.moveTo(0, baseline);
|
|
206
|
+
baselinePath.lineTo(waveWidth, baseline);
|
|
228
207
|
frequencyData.forEach((value, i) => {
|
|
229
208
|
const height = value / 255 * (waveHeight / 2);
|
|
230
209
|
const x = i * (waveWidth / frequencyData.length);
|
|
231
210
|
const y = baseline - height;
|
|
232
|
-
|
|
211
|
+
barsPath.rect(x, y, barWidth, Math.max(height * 2, 1));
|
|
233
212
|
});
|
|
213
|
+
ctx.lineWidth = 2;
|
|
214
|
+
ctx.stroke(baselinePath);
|
|
215
|
+
ctx.fill(barsPath);
|
|
234
216
|
}
|
|
235
|
-
|
|
217
|
+
drawLine(ctx, frequencyData) {
|
|
236
218
|
const canvas = ctx.canvas;
|
|
237
|
-
const waveWidth = canvas.width
|
|
238
|
-
const waveHeight = canvas.height /
|
|
219
|
+
const waveWidth = canvas.width;
|
|
220
|
+
const waveHeight = canvas.height / 2;
|
|
239
221
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
240
|
-
|
|
222
|
+
const path = new Path2D();
|
|
241
223
|
frequencyData.forEach((value, i) => {
|
|
242
224
|
const x = i / frequencyData.length * waveWidth;
|
|
243
225
|
const y = (1 - value / 255) * waveHeight;
|
|
244
226
|
if (i === 0) {
|
|
245
|
-
|
|
227
|
+
path.moveTo(x, y);
|
|
246
228
|
} else {
|
|
247
|
-
|
|
229
|
+
path.lineTo(x, y);
|
|
248
230
|
}
|
|
249
231
|
});
|
|
250
|
-
ctx.lineWidth =
|
|
251
|
-
ctx.stroke();
|
|
232
|
+
ctx.lineWidth = this.lineWidth;
|
|
233
|
+
ctx.stroke(path);
|
|
252
234
|
}
|
|
253
235
|
drawPixel(ctx, frequencyData) {
|
|
254
236
|
const canvas = ctx.canvas;
|
|
255
|
-
const waveWidth = canvas.width
|
|
256
|
-
const waveHeight = canvas.height /
|
|
237
|
+
const waveWidth = canvas.width;
|
|
238
|
+
const waveHeight = canvas.height / 2;
|
|
257
239
|
const baseline = waveHeight / 2;
|
|
258
|
-
const barWidth = waveWidth / frequencyData.length
|
|
240
|
+
const barWidth = waveWidth / frequencyData.length;
|
|
259
241
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
242
|
+
const path = new Path2D();
|
|
260
243
|
frequencyData.forEach((value, i) => {
|
|
261
244
|
const x = i * (waveWidth / frequencyData.length);
|
|
262
245
|
const barHeight = value / 255 * baseline;
|
|
263
246
|
const y = baseline - barHeight;
|
|
264
|
-
|
|
247
|
+
path.rect(x, y, barWidth, barHeight * 2);
|
|
265
248
|
});
|
|
249
|
+
ctx.fill(path);
|
|
266
250
|
}
|
|
267
251
|
drawWave(ctx, frequencyData) {
|
|
268
252
|
const canvas = ctx.canvas;
|
|
269
|
-
const waveWidth = canvas.width
|
|
270
|
-
const waveHeight = canvas.height
|
|
271
|
-
const baseline =
|
|
272
|
-
const barWidth = waveWidth / frequencyData.length * 0.97;
|
|
253
|
+
const waveWidth = canvas.width;
|
|
254
|
+
const waveHeight = canvas.height;
|
|
255
|
+
const baseline = canvas.height / 4;
|
|
273
256
|
ctx.clearRect(0, 0, waveWidth, waveHeight);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
ctx.lineTo(waveWidth, baseline);
|
|
277
|
-
ctx.strokeStyle = this.color;
|
|
278
|
-
ctx.lineWidth = 1;
|
|
279
|
-
ctx.stroke();
|
|
257
|
+
const path = new Path2D();
|
|
258
|
+
path.moveTo(0, baseline);
|
|
280
259
|
frequencyData.forEach((value, i) => {
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
const y = baseline -
|
|
284
|
-
|
|
260
|
+
const normalizedValue = value / 255;
|
|
261
|
+
const x = i / (frequencyData.length - 1) * waveWidth;
|
|
262
|
+
const y = baseline - normalizedValue * (waveHeight / 2);
|
|
263
|
+
if (i === 0) {
|
|
264
|
+
path.moveTo(x, y);
|
|
265
|
+
} else {
|
|
266
|
+
const prevX = (i - 1) / (frequencyData.length - 1) * waveWidth;
|
|
267
|
+
const prevValue = (frequencyData[i - 1] ?? 0) / 255;
|
|
268
|
+
const prevY = baseline - prevValue * (waveHeight / 2);
|
|
269
|
+
const xc = (prevX + x) / 2;
|
|
270
|
+
const yc = (prevY + y) / 2;
|
|
271
|
+
path.quadraticCurveTo(prevX, prevY, xc, yc);
|
|
272
|
+
}
|
|
285
273
|
});
|
|
274
|
+
for (let i = frequencyData.length - 1; i >= 0; i--) {
|
|
275
|
+
const normalizedValue = (frequencyData[i] ?? 0) / 255;
|
|
276
|
+
const x = i / (frequencyData.length - 1) * waveWidth;
|
|
277
|
+
const y = baseline + normalizedValue * (waveHeight / 2);
|
|
278
|
+
if (i === frequencyData.length - 1) {
|
|
279
|
+
path.lineTo(x, y);
|
|
280
|
+
} else {
|
|
281
|
+
const nextX = (i + 1) / (frequencyData.length - 1) * waveWidth;
|
|
282
|
+
const nextValue = (frequencyData[i + 1] ?? 0) / 255;
|
|
283
|
+
const nextY = baseline + nextValue * (waveHeight / 2);
|
|
284
|
+
const xc = (nextX + x) / 2;
|
|
285
|
+
const yc = (nextY + y) / 2;
|
|
286
|
+
path.quadraticCurveTo(nextX, nextY, xc, yc);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
ctx.fill(path);
|
|
286
290
|
}
|
|
287
291
|
get durationMs() {
|
|
292
|
+
if (!this.targetElement) return 0;
|
|
288
293
|
return this.targetElement.durationMs;
|
|
289
294
|
}
|
|
290
295
|
get targetElement() {
|
|
@@ -292,7 +297,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
292
297
|
if (target instanceof EFAudio || target instanceof EFVideo) {
|
|
293
298
|
return target;
|
|
294
299
|
}
|
|
295
|
-
|
|
300
|
+
return null;
|
|
296
301
|
}
|
|
297
302
|
updated(changedProperties) {
|
|
298
303
|
super.updated(changedProperties);
|
|
@@ -328,6 +333,9 @@ __decorateClass([
|
|
|
328
333
|
__decorateClass([
|
|
329
334
|
property({ type: String, attribute: "target", reflect: true })
|
|
330
335
|
], EFWaveform.prototype, "targetSelector", 2);
|
|
336
|
+
__decorateClass([
|
|
337
|
+
property({ type: Number, attribute: "line-width" })
|
|
338
|
+
], EFWaveform.prototype, "lineWidth", 2);
|
|
331
339
|
EFWaveform = __decorateClass([
|
|
332
340
|
customElement("ef-waveform")
|
|
333
341
|
], EFWaveform);
|
package/dist/gui/EFWorkbench.js
CHANGED
|
@@ -62,7 +62,7 @@ let EFWorkbench = class extends ContextMixin(TWMixin(LitElement)) {
|
|
|
62
62
|
focusOverlay.style.display = "block";
|
|
63
63
|
const rect = this.focusedElement.getBoundingClientRect();
|
|
64
64
|
Object.assign(focusOverlay.style, {
|
|
65
|
-
position: "
|
|
65
|
+
position: "fixed",
|
|
66
66
|
top: `${rect.top}px`,
|
|
67
67
|
left: `${rect.left}px`,
|
|
68
68
|
width: `${rect.width}px`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@editframe/elements",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0-beta.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"author": "",
|
|
22
22
|
"license": "UNLICENSED",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@
|
|
24
|
+
"@bramus/style-observer": "^1.3.0",
|
|
25
|
+
"@editframe/assets": "0.15.0-beta.1",
|
|
25
26
|
"@lit/context": "^1.1.2",
|
|
26
27
|
"@lit/task": "^1.0.1",
|
|
27
28
|
"d3": "^7.9.0",
|
|
@@ -18,9 +18,9 @@ describe("EFImage", () => {
|
|
|
18
18
|
const workbench = document.createElement("ef-workbench");
|
|
19
19
|
const element = document.createElement("ef-image");
|
|
20
20
|
workbench.appendChild(element);
|
|
21
|
-
element.assetId = "550e8400-e29b-41d4-a716-446655440000
|
|
21
|
+
element.assetId = "550e8400-e29b-41d4-a716-446655440000";
|
|
22
22
|
expect(element.assetPath()).toBe(
|
|
23
|
-
"editframe://api/v1/image_files/550e8400-e29b-41d4-a716-446655440000
|
|
23
|
+
"editframe://api/v1/image_files/550e8400-e29b-41d4-a716-446655440000",
|
|
24
24
|
);
|
|
25
25
|
});
|
|
26
26
|
});
|
|
@@ -46,4 +46,35 @@ describe("EFImage", () => {
|
|
|
46
46
|
expect(image.assetPath()).toBe(`test:///api/v1/image_files/${id}`);
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
|
+
|
|
50
|
+
describe("hasOwnDuration", () => {
|
|
51
|
+
test("is false by default", () => {
|
|
52
|
+
const image = document.createElement("ef-image");
|
|
53
|
+
expect(image.hasOwnDuration).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("is true when duration is set", () => {
|
|
57
|
+
const image = document.createElement("ef-image");
|
|
58
|
+
image.setAttribute("duration", "1s");
|
|
59
|
+
expect(image.hasOwnDuration).toBe(true);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("durationMs", () => {
|
|
64
|
+
test("Can be set on element directly", () => {
|
|
65
|
+
const image = document.createElement("ef-image");
|
|
66
|
+
image.src =
|
|
67
|
+
"https://editframe.dev/api/v1/image_files/550e8400-e29b-41d4-a716-446655440000";
|
|
68
|
+
image.duration = "1s";
|
|
69
|
+
expect(image.durationMs).toBe(1000);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("Can be set through setAttribute", () => {
|
|
73
|
+
const image = document.createElement("ef-image");
|
|
74
|
+
image.src =
|
|
75
|
+
"https://editframe.dev/api/v1/image_files/550e8400-e29b-41d4-a716-446655440000";
|
|
76
|
+
image.setAttribute("duration", "1s");
|
|
77
|
+
expect(image.durationMs).toBe(1000);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
49
80
|
});
|
package/src/elements/EFImage.ts
CHANGED
|
@@ -5,12 +5,15 @@ import { createRef, ref } from "lit/directives/ref.js";
|
|
|
5
5
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
6
6
|
import { EF_RENDERING } from "../EF_RENDERING.js";
|
|
7
7
|
import { EFSourceMixin } from "./EFSourceMixin.js";
|
|
8
|
+
import { EFTemporal } from "./EFTemporal.js";
|
|
8
9
|
import { FetchMixin } from "./FetchMixin.js";
|
|
9
10
|
|
|
10
11
|
@customElement("ef-image")
|
|
11
|
-
export class EFImage extends
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export class EFImage extends EFTemporal(
|
|
13
|
+
EFSourceMixin(FetchMixin(LitElement), {
|
|
14
|
+
assetType: "image_files",
|
|
15
|
+
}),
|
|
16
|
+
) {
|
|
14
17
|
static styles = [
|
|
15
18
|
css`
|
|
16
19
|
:host {
|
|
@@ -52,6 +55,10 @@ export class EFImage extends EFSourceMixin(FetchMixin(LitElement), {
|
|
|
52
55
|
return `/@ef-image/${this.src}`;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
get hasOwnDuration() {
|
|
59
|
+
return this.hasExplicitDuration;
|
|
60
|
+
}
|
|
61
|
+
|
|
55
62
|
fetchImage = new Task(this, {
|
|
56
63
|
autoRun: EF_INTERACTIVE,
|
|
57
64
|
args: () => [this.assetPath(), this.fetch] as const,
|