@editframe/elements 0.16.0-beta.1 → 0.16.1-beta.0

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.
@@ -19,7 +19,9 @@ declare global {
19
19
  declare class TriggerCanvas {
20
20
  private canvas;
21
21
  private ctx;
22
+ private canvasInitialized;
22
23
  constructor();
24
+ initialize(): void;
23
25
  trigger(): void;
24
26
  }
25
27
  export declare class EFFramegen {
@@ -3,27 +3,30 @@ import { deepGetElementsWithFrameTasks } from "./elements/EFTemporal.js";
3
3
  import { shallowGetTimegroups } from "./elements/EFTimegroup.js";
4
4
  class TriggerCanvas {
5
5
  constructor() {
6
+ this.canvasInitialized = false;
6
7
  this.canvas = document.createElement("canvas");
8
+ const ctx = this.canvas.getContext("2d", { willReadFrequently: true });
9
+ if (!ctx) throw new Error("Canvas 2d context not ready");
10
+ this.ctx = ctx;
11
+ this.ctx.fillStyle = "transparent";
12
+ }
13
+ initialize() {
14
+ if (this.canvasInitialized) return;
15
+ this.canvasInitialized = true;
7
16
  this.canvas.width = 1;
8
17
  this.canvas.height = 1;
9
18
  Object.assign(this.canvas.style, {
10
19
  position: "fixed",
11
20
  top: "0px",
12
21
  left: "0px",
13
- width: "1px",
14
- height: "1px",
22
+ width: "100%",
23
+ height: "100%",
15
24
  zIndex: "100000"
16
25
  });
17
26
  document.body.appendChild(this.canvas);
18
- const ctx = this.canvas.getContext("2d", { willReadFrequently: true });
19
- if (!ctx) throw new Error("Canvas 2d context not ready");
20
- this.ctx = ctx;
21
- this.ctx.fillStyle = "transparent";
22
27
  }
23
28
  trigger() {
24
- console.log("TRIGGERING CANVAS");
25
29
  this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
26
- this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
27
30
  }
28
31
  }
29
32
  class EFFramegen {
@@ -119,13 +122,9 @@ class EFFramegen {
119
122
  }
120
123
  this.time = this.renderOptions.encoderOptions.fromMs + frameNumber * this.frameDurationMs;
121
124
  firstGroup.currentTimeMs = this.time;
122
- console.log("trace: Awaiting initialBusyTasks");
123
125
  await this.initialBusyTasks;
124
- console.log("trace: Awaiting microtask");
125
126
  await new Promise(queueMicrotask);
126
- console.log("trace: Awaiting frame tasks");
127
127
  const now = performance.now();
128
- console.log("trace: HTML", document.body.innerHTML);
129
128
  await Promise.all(
130
129
  temporals.filter((temporal) => temporal.frameTask.status < TaskStatus.COMPLETE).map((temporal) => {
131
130
  return temporal.frameTask;
@@ -259,6 +259,7 @@ const EFTemporal = (superClass) => {
259
259
  );
260
260
  return previous.startTimeMs + previous.durationMs - parentTimegroup.overlapMs;
261
261
  }
262
+ case "fit":
262
263
  case "contain":
263
264
  case "fixed":
264
265
  startTimeMsCache.set(
@@ -6,7 +6,7 @@ export declare class EFTimegroup extends EFTimegroup_base {
6
6
  #private;
7
7
  static styles: import('lit').CSSResult;
8
8
  _timeGroupContext: this;
9
- mode: "fixed" | "sequence" | "contain";
9
+ mode: "fit" | "fixed" | "sequence" | "contain";
10
10
  overlapMs: number;
11
11
  fit: "none" | "contain" | "cover";
12
12
  set currentTime(time: number);
@@ -130,24 +130,34 @@ let EFTimegroup = class extends EFTemporal(LitElement) {
130
130
  }
131
131
  get durationMs() {
132
132
  switch (this.mode) {
133
+ case "fit": {
134
+ if (!this.parentTimegroup) {
135
+ return 0;
136
+ }
137
+ return this.parentTimegroup.durationMs;
138
+ }
133
139
  case "fixed":
134
140
  return super.durationMs;
135
141
  case "sequence": {
136
142
  let duration = 0;
137
- this.childTemporals.forEach((node, index) => {
143
+ this.childTemporals.forEach((child, index) => {
144
+ if (child instanceof EFTimegroup && child.mode === "fit") {
145
+ return;
146
+ }
138
147
  if (index > 0) {
139
148
  duration -= this.overlapMs;
140
149
  }
141
- duration += node.durationMs;
150
+ duration += child.durationMs;
142
151
  });
143
152
  return duration;
144
153
  }
145
154
  case "contain": {
146
155
  let maxDuration = 0;
147
- for (const node of this.childTemporals) {
148
- if (node.intrinsicDurationMs !== void 0) {
149
- maxDuration = Math.max(maxDuration, node.durationMs);
156
+ for (const child of this.childTemporals) {
157
+ if (child instanceof EFTimegroup && child.mode === "fit") {
158
+ continue;
150
159
  }
160
+ maxDuration = Math.max(maxDuration, child.durationMs);
151
161
  }
152
162
  return maxDuration;
153
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/elements",
3
- "version": "0.16.0-beta.1",
3
+ "version": "0.16.1-beta.0",
4
4
  "description": "",
5
5
  "exports": {
6
6
  ".": {
@@ -27,7 +27,7 @@
27
27
  "license": "UNLICENSED",
28
28
  "dependencies": {
29
29
  "@bramus/style-observer": "^1.3.0",
30
- "@editframe/assets": "0.16.0-beta.1",
30
+ "@editframe/assets": "0.16.1-beta.0",
31
31
  "@lit/context": "^1.1.2",
32
32
  "@lit/task": "^1.0.1",
33
33
  "d3": "^7.9.0",
@@ -556,6 +556,7 @@ export const EFTemporal = <T extends Constructor<LitElement>>(
556
556
  parentTimegroup.overlapMs
557
557
  );
558
558
  }
559
+ case "fit":
559
560
  case "contain":
560
561
  case "fixed":
561
562
  startTimeMsCache.set(
@@ -55,6 +55,72 @@ const renderTimegroup = (result: TemplateResult) => {
55
55
  return firstChild;
56
56
  };
57
57
 
58
+ describe(`<ef-timegroup mode='fit'>`, () => {
59
+ test("duration is zero when there is no parent to fit into", () => {
60
+ const timegroup = renderTimegroup(
61
+ html`<ef-timegroup mode="fit"></ef-timegroup>`,
62
+ );
63
+ assert.equal(timegroup.durationMs, 0);
64
+ });
65
+
66
+ test("duration is zero when there is no parent to fit into, even if there are children with duration", () => {
67
+ const timegroup = renderTimegroup(
68
+ html`<ef-timegroup mode="fit">
69
+ <ef-timegroup mode="fixed" duration="5s"></ef-timegroup>
70
+ </ef-timegroup>`,
71
+ );
72
+ assert.equal(timegroup.durationMs, 0);
73
+ });
74
+
75
+ test("duration is the duration of the parent timegroup", () => {
76
+ const timegroup = renderTimegroup(
77
+ html`<ef-timegroup mode="fixed" duration="10s">
78
+ <ef-timegroup id="child" mode="fit"></ef-timegroup>
79
+ </ef-timegroup>`,
80
+ );
81
+ const child = timegroup.querySelector("#child") as EFTimegroup;
82
+ assert.equal(child.durationMs, 10_000);
83
+ });
84
+
85
+ test("fit mode items inside a sequence are given zero duration and do not factor into the duration of the sequence", () => {
86
+ const timegroup = renderTimegroup(
87
+ html`<ef-timegroup mode="sequence">
88
+ <ef-timegroup id="child" mode="fit"></ef-timegroup>
89
+ </ef-timegroup>`,
90
+ );
91
+ const child = timegroup.querySelector("#child") as EFTimegroup;
92
+ assert.equal(child.durationMs, 0);
93
+ assert.equal(timegroup.durationMs, 0);
94
+ });
95
+
96
+ test("fit mode can be used to constrain a 'background' timegroup into a 'foreground' sequence", async () => {
97
+ const timegroup = renderTimegroup(
98
+ html`
99
+ <ef-timegroup mode="contain">
100
+ <ef-timegroup id="foreground" mode="sequence">
101
+ <ef-timegroup mode="fixed" duration="10s"></ef-timegroup>
102
+ <ef-timegroup mode="fixed" duration="10s"></ef-timegroup>
103
+ </ef-timegroup>
104
+ <ef-timegroup id="background" mode="fit">
105
+ <ef-timegroup mode="fixed" duration="30s"></ef-timegroup>
106
+ </ef-timegroup>
107
+ </ef-timegroup>
108
+ `,
109
+ );
110
+
111
+ const foreground = timegroup.querySelector("#foreground") as EFTimegroup;
112
+ const background = timegroup.querySelector("#background") as EFTimegroup;
113
+ assert.equal(foreground.durationMs, 20_000);
114
+ console.log("INFO", {
115
+ mode: background.mode,
116
+ duration: background.durationMs,
117
+ parentTimegroup: background.parentTimegroup,
118
+ });
119
+ console.log(background.parentTimegroup?.durationMs);
120
+ assert.equal(background.durationMs, 20_000);
121
+ });
122
+ });
123
+
58
124
  describe(`<ef-timegroup mode="fixed">`, () => {
59
125
  test("can explicitly set a duration in seconds", async () => {
60
126
  const timegroup = renderTimegroup(
@@ -54,7 +54,7 @@ export class EFTimegroup extends EFTemporal(LitElement) {
54
54
  type: String,
55
55
  attribute: "mode",
56
56
  })
57
- mode: "fixed" | "sequence" | "contain" = "contain";
57
+ mode: "fit" | "fixed" | "sequence" | "contain" = "contain";
58
58
 
59
59
  @property({
60
60
  type: Number,
@@ -146,26 +146,38 @@ export class EFTimegroup extends EFTemporal(LitElement) {
146
146
  return undefined;
147
147
  }
148
148
 
149
- get durationMs() {
149
+ get durationMs(): number {
150
150
  switch (this.mode) {
151
+ case "fit": {
152
+ if (!this.parentTimegroup) {
153
+ return 0;
154
+ }
155
+ return this.parentTimegroup.durationMs;
156
+ }
151
157
  case "fixed":
152
158
  return super.durationMs;
153
159
  case "sequence": {
154
160
  let duration = 0;
155
- this.childTemporals.forEach((node, index) => {
161
+ this.childTemporals.forEach((child, index) => {
162
+ if (child instanceof EFTimegroup && child.mode === "fit") {
163
+ return;
164
+ }
156
165
  if (index > 0) {
157
166
  duration -= this.overlapMs;
158
167
  }
159
- duration += node.durationMs;
168
+ duration += child.durationMs;
160
169
  });
161
170
  return duration;
162
171
  }
163
172
  case "contain": {
164
173
  let maxDuration = 0;
165
- for (const node of this.childTemporals) {
166
- if (node.intrinsicDurationMs !== undefined) {
167
- maxDuration = Math.max(maxDuration, node.durationMs);
174
+ for (const child of this.childTemporals) {
175
+ // fit timegroups look "up" to their parent timegroup for their duration
176
+ // so we need to skip them to avoid an infinite loop
177
+ if (child instanceof EFTimegroup && child.mode === "fit") {
178
+ continue;
168
179
  }
180
+ maxDuration = Math.max(maxDuration, child.durationMs);
169
181
  }
170
182
  return maxDuration;
171
183
  }