@editframe/elements 0.15.0-beta.17 → 0.15.0-beta.19
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 +1 -1
- package/dist/elements/EFMedia.d.ts +7 -3
- package/dist/elements/EFMedia.js +45 -90
- package/dist/elements/EFTemporal.browsertest.d.ts +4 -3
- package/dist/elements/EFTemporal.d.ts +14 -11
- package/dist/elements/EFTemporal.js +63 -87
- package/dist/elements/EFTimegroup.d.ts +1 -3
- package/dist/elements/EFTimegroup.js +15 -103
- package/dist/elements/EFVideo.js +3 -1
- package/dist/elements/EFWaveform.d.ts +1 -0
- package/dist/elements/EFWaveform.js +6 -2
- package/dist/elements/durationConverter.d.ts +8 -8
- package/dist/elements/durationConverter.js +2 -2
- package/dist/elements/updateAnimations.d.ts +9 -0
- package/dist/elements/updateAnimations.js +62 -0
- package/dist/gui/EFFilmstrip.js +7 -16
- package/dist/gui/EFFitScale.d.ts +25 -0
- package/dist/gui/EFFitScale.js +123 -0
- package/dist/gui/EFWorkbench.d.ts +1 -5
- package/dist/gui/EFWorkbench.js +6 -55
- package/dist/gui/TWMixin.css.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/style.css +3 -3
- package/package.json +2 -2
- package/src/elements/EFMedia.browsertest.ts +10 -10
- package/src/elements/EFMedia.ts +56 -118
- package/src/elements/EFTemporal.browsertest.ts +64 -31
- package/src/elements/EFTemporal.ts +99 -119
- package/src/elements/EFTimegroup.ts +15 -133
- package/src/elements/EFVideo.ts +3 -1
- package/src/elements/EFWaveform.ts +5 -2
- package/src/elements/durationConverter.ts +9 -4
- package/src/elements/updateAnimations.ts +88 -0
- package/src/gui/EFFilmstrip.ts +7 -16
- package/src/gui/EFFitScale.ts +133 -0
- package/src/gui/EFWorkbench.ts +7 -64
- package/types.json +1 -1
|
@@ -6,9 +6,10 @@ import { property, customElement } from "lit/decorators.js";
|
|
|
6
6
|
import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
|
|
7
7
|
import { isContextMixin } from "../gui/ContextMixin.js";
|
|
8
8
|
import { deepGetMediaElements } from "./EFMedia.js";
|
|
9
|
-
import { EFTemporal, shallowGetTemporalElements,
|
|
9
|
+
import { EFTemporal, shallowGetTemporalElements, timegroupContext } from "./EFTemporal.js";
|
|
10
10
|
import { TimegroupController } from "./TimegroupController.js";
|
|
11
11
|
import { durationConverter } from "./durationConverter.js";
|
|
12
|
+
import { updateAnimations } from "./updateAnimations.js";
|
|
12
13
|
var __defProp = Object.defineProperty;
|
|
13
14
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
14
15
|
var __typeError = (msg) => {
|
|
@@ -107,51 +108,26 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
|
|
|
107
108
|
if (this.shouldWrapWithWorkbench()) {
|
|
108
109
|
this.wrapWithWorkbench();
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
this.updateScale();
|
|
115
|
-
requestAnimationFrame(() => this.updateAnimations());
|
|
111
|
+
requestAnimationFrame(() => {
|
|
112
|
+
this.updateAnimations();
|
|
113
|
+
});
|
|
116
114
|
}
|
|
117
115
|
disconnectedCallback() {
|
|
118
116
|
super.disconnectedCallback();
|
|
119
117
|
__privateGet(this, _resizeObserver)?.disconnect();
|
|
120
118
|
}
|
|
121
|
-
get displayedParent() {
|
|
122
|
-
let displayedParent = this.parentElement;
|
|
123
|
-
while (displayedParent && getComputedStyle(displayedParent).display === "contents") {
|
|
124
|
-
displayedParent = displayedParent.parentElement;
|
|
125
|
-
}
|
|
126
|
-
return displayedParent;
|
|
127
|
-
}
|
|
128
|
-
updateScale() {
|
|
129
|
-
if (this.fit === "none") return;
|
|
130
|
-
const displayedParent = this.displayedParent;
|
|
131
|
-
if (!displayedParent) return;
|
|
132
|
-
const contentWidth = this.clientWidth;
|
|
133
|
-
const contentHeight = this.clientHeight;
|
|
134
|
-
const containerWidth = displayedParent.clientWidth;
|
|
135
|
-
const containerHeight = displayedParent.clientHeight;
|
|
136
|
-
const widthRatio = containerWidth / contentWidth;
|
|
137
|
-
const heightRatio = containerHeight / contentHeight;
|
|
138
|
-
let scale;
|
|
139
|
-
if (this.fit === "contain") {
|
|
140
|
-
scale = heightRatio;
|
|
141
|
-
if (contentWidth * scale > containerWidth) {
|
|
142
|
-
scale = widthRatio;
|
|
143
|
-
}
|
|
144
|
-
} else {
|
|
145
|
-
scale = Math.max(widthRatio, heightRatio);
|
|
146
|
-
}
|
|
147
|
-
this.style.transform = `scale(${scale})`;
|
|
148
|
-
}
|
|
149
119
|
get storageKey() {
|
|
150
120
|
if (!this.id) {
|
|
151
121
|
throw new Error("Timegroup must have an id to use localStorage.");
|
|
152
122
|
}
|
|
153
123
|
return `ef-timegroup-${this.id}`;
|
|
154
124
|
}
|
|
125
|
+
get intrinsicDurationMs() {
|
|
126
|
+
if (this.hasExplicitDuration) {
|
|
127
|
+
return this.explicitDurationMs;
|
|
128
|
+
}
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
155
131
|
get durationMs() {
|
|
156
132
|
switch (this.mode) {
|
|
157
133
|
case "fixed":
|
|
@@ -169,7 +145,7 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
|
|
|
169
145
|
case "contain": {
|
|
170
146
|
let maxDuration = 0;
|
|
171
147
|
for (const node of this.childTemporals) {
|
|
172
|
-
if (node.
|
|
148
|
+
if (node.intrinsicDurationMs !== void 0) {
|
|
173
149
|
maxDuration = Math.max(maxDuration, node.durationMs);
|
|
174
150
|
}
|
|
175
151
|
}
|
|
@@ -201,69 +177,7 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
|
|
|
201
177
|
}
|
|
202
178
|
}
|
|
203
179
|
updateAnimations() {
|
|
204
|
-
this
|
|
205
|
-
"--ef-progress",
|
|
206
|
-
`${Math.max(0, Math.min(1, this.currentTimeMs / this.durationMs)) * 100}%`
|
|
207
|
-
);
|
|
208
|
-
const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
|
|
209
|
-
if (this.startTimeMs > timelineTimeMs || this.endTimeMs < timelineTimeMs) {
|
|
210
|
-
this.style.display = "none";
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
this.style.display = "";
|
|
214
|
-
const animations = this.getAnimations({ subtree: true });
|
|
215
|
-
this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
|
|
216
|
-
this.style.setProperty(
|
|
217
|
-
"--ef-transition-duration",
|
|
218
|
-
`${this.parentTimegroup?.overlapMs ?? 0}ms`
|
|
219
|
-
);
|
|
220
|
-
this.style.setProperty(
|
|
221
|
-
"--ef-transition-out-start",
|
|
222
|
-
`${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`
|
|
223
|
-
);
|
|
224
|
-
for (const animation of animations) {
|
|
225
|
-
if (animation.playState === "running") {
|
|
226
|
-
animation.pause();
|
|
227
|
-
}
|
|
228
|
-
const effect = animation.effect;
|
|
229
|
-
if (!(effect && effect instanceof KeyframeEffect)) {
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
const target = effect.target;
|
|
233
|
-
if (!target) {
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (target.closest("ef-timegroup") !== this) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
if (isEFTemporal(target)) {
|
|
240
|
-
const timing = effect.getTiming();
|
|
241
|
-
const duration = Number(timing.duration) ?? 0;
|
|
242
|
-
const delay = Number(timing.delay);
|
|
243
|
-
const newTime = Math.floor(
|
|
244
|
-
Math.min(target.ownCurrentTimeMs, duration - 1 + delay)
|
|
245
|
-
);
|
|
246
|
-
if (Number.isNaN(newTime)) {
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
animation.currentTime = newTime;
|
|
250
|
-
} else if (target) {
|
|
251
|
-
const nearestTimegroup = target.closest("ef-timegroup");
|
|
252
|
-
if (!nearestTimegroup) {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
const timing = effect.getTiming();
|
|
256
|
-
const duration = Number(timing.duration) ?? 0;
|
|
257
|
-
const delay = Number(timing.delay);
|
|
258
|
-
const newTime = Math.floor(
|
|
259
|
-
Math.min(nearestTimegroup.ownCurrentTimeMs, duration - 1 + delay)
|
|
260
|
-
);
|
|
261
|
-
if (Number.isNaN(newTime)) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
animation.currentTime = newTime;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
180
|
+
updateAnimations(this);
|
|
267
181
|
}
|
|
268
182
|
get contextProvider() {
|
|
269
183
|
let parent = this.parentNode;
|
|
@@ -300,9 +214,6 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
|
|
|
300
214
|
filmstrip.setAttribute("target", this.id);
|
|
301
215
|
workbench.append(filmstrip);
|
|
302
216
|
}
|
|
303
|
-
get hasOwnDuration() {
|
|
304
|
-
return true;
|
|
305
|
-
}
|
|
306
217
|
get efElements() {
|
|
307
218
|
return Array.from(
|
|
308
219
|
this.querySelectorAll(
|
|
@@ -378,7 +289,8 @@ EFTimegroup.styles = css`
|
|
|
378
289
|
width: 100%;
|
|
379
290
|
height: 100%;
|
|
380
291
|
position: absolute;
|
|
381
|
-
|
|
292
|
+
top: 0;
|
|
293
|
+
left: 0;
|
|
382
294
|
}
|
|
383
295
|
`;
|
|
384
296
|
__decorateClass([
|
package/dist/elements/EFVideo.js
CHANGED
|
@@ -93,7 +93,9 @@ let EFVideo = class extends TWMixin(EFMedia) {
|
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
95
|
render() {
|
|
96
|
-
return html`
|
|
96
|
+
return html`
|
|
97
|
+
<canvas ${ref(this.canvasRef)}></canvas>
|
|
98
|
+
`;
|
|
97
99
|
}
|
|
98
100
|
get canvasElement() {
|
|
99
101
|
return this.canvasRef.value;
|
|
@@ -16,6 +16,7 @@ export declare class EFWaveform extends EFWaveform_base {
|
|
|
16
16
|
mode: "roundBars" | "bars" | "bricks" | "line" | "curve" | "pixel" | "wave" | "spikes";
|
|
17
17
|
color: string;
|
|
18
18
|
target: string;
|
|
19
|
+
barSpacing: number;
|
|
19
20
|
targetElement: EFAudio | EFVideo | null;
|
|
20
21
|
lineWidth: number;
|
|
21
22
|
targetController: TargetController;
|
|
@@ -28,6 +28,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
28
28
|
this.mode = "bars";
|
|
29
29
|
this.color = "currentColor";
|
|
30
30
|
this.target = "";
|
|
31
|
+
this.barSpacing = 0.5;
|
|
31
32
|
this.targetElement = null;
|
|
32
33
|
this.lineWidth = 4;
|
|
33
34
|
this.targetController = new TargetController(this);
|
|
@@ -152,7 +153,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
152
153
|
const waveWidth = canvas.width;
|
|
153
154
|
const waveHeight = canvas.height;
|
|
154
155
|
const totalBars = frequencyData.length;
|
|
155
|
-
const paddingInner =
|
|
156
|
+
const paddingInner = this.barSpacing;
|
|
156
157
|
const paddingOuter = 0.01;
|
|
157
158
|
const availableWidth = waveWidth;
|
|
158
159
|
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
@@ -193,7 +194,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
|
|
|
193
194
|
const waveWidth = canvas.width;
|
|
194
195
|
const waveHeight = canvas.height;
|
|
195
196
|
const totalBars = frequencyData.length;
|
|
196
|
-
const paddingInner =
|
|
197
|
+
const paddingInner = this.barSpacing;
|
|
197
198
|
const paddingOuter = 0.01;
|
|
198
199
|
const availableWidth = waveWidth;
|
|
199
200
|
const barWidth = availableWidth / (totalBars + (totalBars - 1) * paddingInner);
|
|
@@ -411,6 +412,9 @@ __decorateClass([
|
|
|
411
412
|
__decorateClass([
|
|
412
413
|
property({ type: String, reflect: true })
|
|
413
414
|
], EFWaveform.prototype, "target", 2);
|
|
415
|
+
__decorateClass([
|
|
416
|
+
property({ type: Number, attribute: "bar-spacing" })
|
|
417
|
+
], EFWaveform.prototype, "barSpacing", 2);
|
|
414
418
|
__decorateClass([
|
|
415
419
|
state()
|
|
416
420
|
], EFWaveform.prototype, "targetElement", 2);
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export declare const durationConverter: {
|
|
2
|
-
fromAttribute: (value: string) => number;
|
|
3
|
-
toAttribute: (value: number) => string;
|
|
2
|
+
fromAttribute: (value: string | null) => number | null;
|
|
3
|
+
toAttribute: (value: number | null) => string | null;
|
|
4
4
|
};
|
|
5
5
|
export declare const trimDurationConverter: {
|
|
6
|
-
fromAttribute: (value: string) => number;
|
|
7
|
-
toAttribute: (value: number) => string;
|
|
6
|
+
fromAttribute: (value: string | null) => number | null;
|
|
7
|
+
toAttribute: (value: number | null) => string | null;
|
|
8
8
|
};
|
|
9
9
|
export declare const imageDurationConverter: {
|
|
10
|
-
fromAttribute: (value: string) => number;
|
|
11
|
-
toAttribute: (value: number) => string;
|
|
10
|
+
fromAttribute: (value: string | null) => number | null;
|
|
11
|
+
toAttribute: (value: number | null) => string | null;
|
|
12
12
|
};
|
|
13
13
|
export declare const sourceDurationConverter: {
|
|
14
|
-
fromAttribute: (value: string) => number;
|
|
15
|
-
toAttribute: (value: number) => string;
|
|
14
|
+
fromAttribute: (value: string | null) => number | null;
|
|
15
|
+
toAttribute: (value: number | null) => string | null;
|
|
16
16
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { parseTimeToMs } from "./parseTimeToMs.js";
|
|
2
2
|
const durationConverter = {
|
|
3
|
-
fromAttribute: (value) => parseTimeToMs(value),
|
|
4
|
-
toAttribute: (value) => `${value}s`
|
|
3
|
+
fromAttribute: (value) => value === null ? null : parseTimeToMs(value),
|
|
4
|
+
toAttribute: (value) => value === null ? null : `${value}s`
|
|
5
5
|
};
|
|
6
6
|
export {
|
|
7
7
|
durationConverter
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { EFTimegroup } from './EFTimegroup.ts';
|
|
2
|
+
export declare const updateAnimations: (element: HTMLElement & {
|
|
3
|
+
currentTimeMs: number;
|
|
4
|
+
durationMs: number;
|
|
5
|
+
rootTimegroup?: EFTimegroup;
|
|
6
|
+
parentTimegroup?: EFTimegroup;
|
|
7
|
+
startTimeMs: number;
|
|
8
|
+
endTimeMs: number;
|
|
9
|
+
}) => void;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { isEFTemporal } from "./EFTemporal.js";
|
|
2
|
+
const updateAnimations = (element) => {
|
|
3
|
+
element.style.setProperty(
|
|
4
|
+
"--ef-progress",
|
|
5
|
+
`${Math.max(0, Math.min(1, element.currentTimeMs / element.durationMs)) * 100}%`
|
|
6
|
+
);
|
|
7
|
+
const timelineTimeMs = (element.rootTimegroup ?? element).currentTimeMs;
|
|
8
|
+
if (element.startTimeMs > timelineTimeMs || element.endTimeMs < timelineTimeMs) {
|
|
9
|
+
element.style.display = "none";
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
element.style.display = "";
|
|
13
|
+
const animations = element.getAnimations({ subtree: true });
|
|
14
|
+
element.style.setProperty("--ef-duration", `${element.durationMs}ms`);
|
|
15
|
+
element.style.setProperty(
|
|
16
|
+
"--ef-transition-duration",
|
|
17
|
+
`${element.parentTimegroup?.overlapMs ?? 0}ms`
|
|
18
|
+
);
|
|
19
|
+
element.style.setProperty(
|
|
20
|
+
"--ef-transition-out-start",
|
|
21
|
+
`${element.durationMs - (element.parentTimegroup?.overlapMs ?? 0)}ms`
|
|
22
|
+
);
|
|
23
|
+
for (const animation of animations) {
|
|
24
|
+
if (animation.playState === "running") {
|
|
25
|
+
animation.pause();
|
|
26
|
+
}
|
|
27
|
+
const effect = animation.effect;
|
|
28
|
+
if (!(effect && effect instanceof KeyframeEffect)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const target = effect.target;
|
|
32
|
+
if (!target) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (target.closest("ef-timegroup") !== element) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const timing = effect.getTiming();
|
|
39
|
+
const duration = Number(timing.duration) ?? 0;
|
|
40
|
+
const delay = Number(timing.delay) ?? 0;
|
|
41
|
+
const iterations = Number(timing.iterations) ?? 1;
|
|
42
|
+
const timeTarget = isEFTemporal(target) ? target : target.closest("ef-timegroup");
|
|
43
|
+
if (!timeTarget) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const currentTime = timeTarget.ownCurrentTimeMs;
|
|
47
|
+
if (currentTime < delay) {
|
|
48
|
+
animation.currentTime = 0;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const currentIteration = Math.floor((currentTime - delay) / duration);
|
|
52
|
+
const currentIterationTime = (currentTime - delay) % duration;
|
|
53
|
+
if (currentIteration >= iterations) {
|
|
54
|
+
animation.currentTime = duration - 0.01;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
animation.currentTime = Math.min(currentIterationTime, duration - 0.01) + delay;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
updateAnimations
|
|
62
|
+
};
|
package/dist/gui/EFFilmstrip.js
CHANGED
|
@@ -74,30 +74,21 @@ class FilmstripItem extends TWMixin(LitElement) {
|
|
|
74
74
|
get isFocused() {
|
|
75
75
|
return this.element && this.focusContext?.focusedElement === this.element;
|
|
76
76
|
}
|
|
77
|
+
// Gutter styles represent the entire source media.
|
|
78
|
+
// If there is no trim, then the gutter and trim portion are the same.
|
|
77
79
|
get gutterStyles() {
|
|
78
|
-
if (this.element.sourceInMs || this.element.sourceOutMs) {
|
|
79
|
-
return {
|
|
80
|
-
position: "relative",
|
|
81
|
-
left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.trimStartMs - this.element.sourceInMs)}px`,
|
|
82
|
-
width: `${this.pixelsPerMs * (this.element.durationMs + this.element.trimStartMs + this.element.trimEndMs + this.element.sourceOutMs + this.element.sourceInMs)}px`
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
80
|
return {
|
|
86
81
|
position: "relative",
|
|
87
|
-
left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.
|
|
88
|
-
width: `${this.pixelsPerMs * (this.element.
|
|
82
|
+
left: `${this.pixelsPerMs * (this.element.startTimeWithinParentMs - this.element.sourceStartMs)}px`,
|
|
83
|
+
width: `${this.pixelsPerMs * (this.element.intrinsicDurationMs ?? this.element.durationMs)}px`
|
|
89
84
|
};
|
|
90
85
|
}
|
|
86
|
+
// Trim portion is the section of source that will be placed in the timeline
|
|
87
|
+
// If there is no trim, then the gutter and trim portion are the same.
|
|
91
88
|
get trimPortionStyles() {
|
|
92
|
-
if (this.element.sourceInMs || this.element.sourceOutMs) {
|
|
93
|
-
return {
|
|
94
|
-
width: `${this.pixelsPerMs * this.element.durationMs}px`,
|
|
95
|
-
left: `${this.pixelsPerMs * (this.element.trimStartMs + this.element.sourceInMs)}px`
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
89
|
return {
|
|
99
90
|
width: `${this.pixelsPerMs * this.element.durationMs}px`,
|
|
100
|
-
left: `${this.pixelsPerMs * this.element.
|
|
91
|
+
left: `${this.pixelsPerMs * this.element.sourceStartMs}px`
|
|
101
92
|
};
|
|
102
93
|
}
|
|
103
94
|
render() {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export declare class EFFitScale extends LitElement {
|
|
3
|
+
containerRef: import('lit-html/directives/ref.js').Ref<HTMLDivElement>;
|
|
4
|
+
contentRef: import('lit-html/directives/ref.js').Ref<HTMLSlotElement>;
|
|
5
|
+
createRenderRoot(): this;
|
|
6
|
+
uniqueId: string;
|
|
7
|
+
private scale;
|
|
8
|
+
private animationFrameId?;
|
|
9
|
+
get contentChild(): HTMLElement | null;
|
|
10
|
+
get scaleInfo(): {
|
|
11
|
+
scale: number;
|
|
12
|
+
containerWidth: number;
|
|
13
|
+
containerHeight: number;
|
|
14
|
+
contentWidth: number;
|
|
15
|
+
contentHeight: number;
|
|
16
|
+
};
|
|
17
|
+
setScale: () => void;
|
|
18
|
+
connectedCallback(): void;
|
|
19
|
+
disconnectedCallback(): void;
|
|
20
|
+
}
|
|
21
|
+
declare global {
|
|
22
|
+
interface HTMLElementTagNameMap {
|
|
23
|
+
"ef-fit-scale": EFFitScale;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import { state, customElement } from "lit/decorators.js";
|
|
3
|
+
import { createRef } from "lit/directives/ref.js";
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
7
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
8
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
9
|
+
if (decorator = decorators[i])
|
|
10
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
11
|
+
if (kind && result) __defProp(target, key, result);
|
|
12
|
+
return result;
|
|
13
|
+
};
|
|
14
|
+
let EFFitScale = class extends LitElement {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.containerRef = createRef();
|
|
18
|
+
this.contentRef = createRef();
|
|
19
|
+
this.uniqueId = Math.random().toString(36).substring(2, 15);
|
|
20
|
+
this.scale = 1;
|
|
21
|
+
this.setScale = () => {
|
|
22
|
+
if (this.isConnected) {
|
|
23
|
+
const { scale } = this.scaleInfo;
|
|
24
|
+
if (this.contentChild) {
|
|
25
|
+
const containerRect = this.getBoundingClientRect();
|
|
26
|
+
const contentRect = this.contentChild.getBoundingClientRect();
|
|
27
|
+
const unscaledWidth = contentRect.width / this.scale;
|
|
28
|
+
const unscaledHeight = contentRect.height / this.scale;
|
|
29
|
+
const scaledWidth = unscaledWidth * scale;
|
|
30
|
+
const scaledHeight = unscaledHeight * scale;
|
|
31
|
+
const translateX = (containerRect.width - scaledWidth) / 2;
|
|
32
|
+
const translateY = (containerRect.height - scaledHeight) / 2;
|
|
33
|
+
Object.assign(this.contentChild.style, {
|
|
34
|
+
transform: `translate(${translateX.toFixed(4)}px, ${translateY.toFixed(4)}px) scale(${scale.toFixed(4)})`,
|
|
35
|
+
transformOrigin: "top left"
|
|
36
|
+
});
|
|
37
|
+
this.scale = scale;
|
|
38
|
+
}
|
|
39
|
+
this.animationFrameId = requestAnimationFrame(this.setScale);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
createRenderRoot() {
|
|
44
|
+
Object.assign(this.style, {
|
|
45
|
+
display: "grid",
|
|
46
|
+
width: "100%",
|
|
47
|
+
height: "100%",
|
|
48
|
+
gridTemplateColumns: "100%",
|
|
49
|
+
gridTemplateRows: "100%",
|
|
50
|
+
overflow: "hidden",
|
|
51
|
+
boxSizing: "border-box",
|
|
52
|
+
contain: "strict",
|
|
53
|
+
position: "relative"
|
|
54
|
+
});
|
|
55
|
+
this.id = `${this.uniqueId}`;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
get contentChild() {
|
|
59
|
+
const firstElement = this.children[0];
|
|
60
|
+
if (!firstElement) return null;
|
|
61
|
+
let current = firstElement;
|
|
62
|
+
while (current) {
|
|
63
|
+
if (current instanceof HTMLSlotElement) {
|
|
64
|
+
const assigned = current.assignedElements()[0];
|
|
65
|
+
if (!assigned) break;
|
|
66
|
+
current = assigned;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const display = window.getComputedStyle(current).display;
|
|
70
|
+
if (display !== "contents" && display !== "none") {
|
|
71
|
+
return current;
|
|
72
|
+
}
|
|
73
|
+
const firstChild = current.children[0];
|
|
74
|
+
if (!firstChild) break;
|
|
75
|
+
current = firstChild;
|
|
76
|
+
}
|
|
77
|
+
return firstElement;
|
|
78
|
+
}
|
|
79
|
+
get scaleInfo() {
|
|
80
|
+
if (!this.contentChild) {
|
|
81
|
+
return {
|
|
82
|
+
scale: 1,
|
|
83
|
+
containerWidth: 0,
|
|
84
|
+
containerHeight: 0,
|
|
85
|
+
contentWidth: 0,
|
|
86
|
+
contentHeight: 0
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const containerWidth = this.clientWidth;
|
|
90
|
+
const containerHeight = this.clientHeight;
|
|
91
|
+
const contentWidth = this.contentChild.clientWidth;
|
|
92
|
+
const contentHeight = this.contentChild.clientHeight;
|
|
93
|
+
const containerRatio = containerWidth / containerHeight;
|
|
94
|
+
const contentRatio = contentWidth / contentHeight;
|
|
95
|
+
const scale = containerRatio > contentRatio ? containerHeight / contentHeight : containerWidth / contentWidth;
|
|
96
|
+
return {
|
|
97
|
+
scale,
|
|
98
|
+
containerWidth,
|
|
99
|
+
containerHeight,
|
|
100
|
+
contentWidth,
|
|
101
|
+
contentHeight
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
connectedCallback() {
|
|
105
|
+
super.connectedCallback();
|
|
106
|
+
this.animationFrameId = requestAnimationFrame(this.setScale);
|
|
107
|
+
}
|
|
108
|
+
disconnectedCallback() {
|
|
109
|
+
super.disconnectedCallback();
|
|
110
|
+
if (this.animationFrameId) {
|
|
111
|
+
cancelAnimationFrame(this.animationFrameId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
__decorateClass([
|
|
116
|
+
state()
|
|
117
|
+
], EFFitScale.prototype, "scale", 2);
|
|
118
|
+
EFFitScale = __decorateClass([
|
|
119
|
+
customElement("ef-fit-scale")
|
|
120
|
+
], EFFitScale);
|
|
121
|
+
export {
|
|
122
|
+
EFFitScale
|
|
123
|
+
};
|
|
@@ -2,12 +2,8 @@ import { LitElement, PropertyValueMap } from 'lit';
|
|
|
2
2
|
declare const EFWorkbench_base: (new (...args: any[]) => import('./ContextMixin.js').ContextMixinInterface) & typeof LitElement;
|
|
3
3
|
export declare class EFWorkbench extends EFWorkbench_base {
|
|
4
4
|
static styles: import('lit').CSSResult[];
|
|
5
|
-
stageRef: import('lit-html/directives/ref.js').Ref<HTMLDivElement>;
|
|
6
|
-
canvasRef: import('lit-html/directives/ref.js').Ref<HTMLSlotElement>;
|
|
7
|
-
handleStageWheel(event: WheelEvent): void;
|
|
8
5
|
focusOverlay: import('lit-html/directives/ref.js').Ref<HTMLDivElement>;
|
|
9
|
-
|
|
10
|
-
setStageScale: () => void;
|
|
6
|
+
handleStageWheel(event: WheelEvent): void;
|
|
11
7
|
connectedCallback(): void;
|
|
12
8
|
disconnectedCallback(): void;
|
|
13
9
|
update(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
|
package/dist/gui/EFWorkbench.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { html, css, LitElement } from "lit";
|
|
2
|
-
import { eventOptions,
|
|
2
|
+
import { eventOptions, customElement } from "lit/decorators.js";
|
|
3
3
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
4
4
|
import { ContextMixin } from "./ContextMixin.js";
|
|
5
5
|
import { TWMixin } from "./TWMixin.js";
|
|
@@ -16,45 +16,7 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
16
16
|
let EFWorkbench = class extends ContextMixin(TWMixin(LitElement)) {
|
|
17
17
|
constructor() {
|
|
18
18
|
super(...arguments);
|
|
19
|
-
this.stageRef = createRef();
|
|
20
|
-
this.canvasRef = createRef();
|
|
21
19
|
this.focusOverlay = createRef();
|
|
22
|
-
this.stageScale = 1;
|
|
23
|
-
this.setStageScale = () => {
|
|
24
|
-
if (this.isConnected && !this.rendering) {
|
|
25
|
-
const canvasElement = this.canvasRef.value;
|
|
26
|
-
const stageElement = this.stageRef.value;
|
|
27
|
-
const canvasChild = canvasElement?.assignedElements()[0];
|
|
28
|
-
if (stageElement && canvasElement && canvasChild) {
|
|
29
|
-
canvasElement.style.width = `${canvasChild.clientWidth}px`;
|
|
30
|
-
canvasElement.style.height = `${canvasChild.clientHeight}px`;
|
|
31
|
-
const stageWidth = stageElement.clientWidth;
|
|
32
|
-
const stageHeight = stageElement.clientHeight;
|
|
33
|
-
const canvasWidth = canvasElement.clientWidth;
|
|
34
|
-
const canvasHeight = canvasElement.clientHeight;
|
|
35
|
-
const stageRatio = stageWidth / stageHeight;
|
|
36
|
-
const canvasRatio = canvasWidth / canvasHeight;
|
|
37
|
-
if (stageRatio > canvasRatio) {
|
|
38
|
-
const scale = stageHeight / canvasHeight;
|
|
39
|
-
if (this.stageScale !== scale) {
|
|
40
|
-
canvasElement.style.transform = `scale(${scale})`;
|
|
41
|
-
canvasElement.style.transformOrigin = "top center";
|
|
42
|
-
}
|
|
43
|
-
this.stageScale = scale;
|
|
44
|
-
} else {
|
|
45
|
-
const scale = stageWidth / canvasWidth;
|
|
46
|
-
if (this.stageScale !== scale) {
|
|
47
|
-
canvasElement.style.transform = `scale(${scale})`;
|
|
48
|
-
canvasElement.style.transformOrigin = "center";
|
|
49
|
-
}
|
|
50
|
-
this.stageScale = scale;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (this.isConnected) {
|
|
55
|
-
requestAnimationFrame(this.setStageScale);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
20
|
this.drawOverlays = () => {
|
|
59
21
|
const focusOverlay = this.focusOverlay.value;
|
|
60
22
|
if (focusOverlay) {
|
|
@@ -84,7 +46,6 @@ let EFWorkbench = class extends ContextMixin(TWMixin(LitElement)) {
|
|
|
84
46
|
document.documentElement.style.width = "100%";
|
|
85
47
|
document.documentElement.style.height = "100%";
|
|
86
48
|
super.connectedCallback();
|
|
87
|
-
requestAnimationFrame(this.setStageScale);
|
|
88
49
|
}
|
|
89
50
|
disconnectedCallback() {
|
|
90
51
|
super.disconnectedCallback();
|
|
@@ -102,11 +63,7 @@ let EFWorkbench = class extends ContextMixin(TWMixin(LitElement)) {
|
|
|
102
63
|
render() {
|
|
103
64
|
if (this.rendering) {
|
|
104
65
|
return html`
|
|
105
|
-
<slot
|
|
106
|
-
${ref(this.canvasRef)}
|
|
107
|
-
class="fixed inset-0 h-full w-full"
|
|
108
|
-
name="canvas"
|
|
109
|
-
></slot>
|
|
66
|
+
<slot class="fixed inset-0 h-full w-full" name="canvas"></slot>
|
|
110
67
|
`;
|
|
111
68
|
}
|
|
112
69
|
return html`
|
|
@@ -115,15 +72,12 @@ let EFWorkbench = class extends ContextMixin(TWMixin(LitElement)) {
|
|
|
115
72
|
style="grid-template-rows: 1fr 300px; grid-template-columns: 100%;"
|
|
116
73
|
>
|
|
117
74
|
<div
|
|
118
|
-
|
|
119
|
-
class="relative grid h-full w-full justify-center overflow-hidden"
|
|
75
|
+
class="relative h-full w-full overflow-hidden"
|
|
120
76
|
@wheel=${this.handleStageWheel}
|
|
121
77
|
>
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
class="inline-block"
|
|
126
|
-
></slot>
|
|
78
|
+
<ef-fit-scale class="h-full grid place-content-center">
|
|
79
|
+
<slot name="canvas" class="contents"></slot>
|
|
80
|
+
</ef-fit-scale>
|
|
127
81
|
<div
|
|
128
82
|
class="border border-blue-500 bg-blue-200 bg-opacity-20 absolute"
|
|
129
83
|
${ref(this.focusOverlay)}
|
|
@@ -147,9 +101,6 @@ EFWorkbench.styles = [
|
|
|
147
101
|
__decorateClass([
|
|
148
102
|
eventOptions({ passive: false, capture: true })
|
|
149
103
|
], EFWorkbench.prototype, "handleStageWheel", 1);
|
|
150
|
-
__decorateClass([
|
|
151
|
-
state()
|
|
152
|
-
], EFWorkbench.prototype, "stageScale", 2);
|
|
153
104
|
EFWorkbench = __decorateClass([
|
|
154
105
|
customElement("ef-workbench")
|
|
155
106
|
], EFWorkbench);
|