@web-ppt/viewer-core 0.5.0-beta.2 → 0.5.0-beta.7
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/CHANGELOG.md +171 -0
- package/README.md +3 -0
- package/dist/comments.d.ts +7 -0
- package/dist/comments.js +26 -0
- package/dist/element-playback.d.ts +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/media-playback.d.ts +9 -0
- package/dist/playback.d.ts +3 -15
- package/dist/reveal-clip.d.ts +33 -0
- package/dist/settled.d.ts +9 -0
- package/dist/state.d.ts +14 -1
- package/dist/video/media-overlay.d.ts +30 -0
- package/dist/video/mix.d.ts +31 -0
- package/dist/video/scene.d.ts +17 -0
- package/dist/video/timing.d.ts +56 -0
- package/dist/video/webm.d.ts +25 -0
- package/dist/video.d.ts +10 -0
- package/dist/video.js +1248 -0
- package/dist/viewer-core.js +912 -353
- package/dist/viewer.d.ts +9 -0
- package/package.json +12 -4
package/dist/video.js
ADDED
|
@@ -0,0 +1,1248 @@
|
|
|
1
|
+
import { transitionPreferredDirection as bt, slideToSvgFile as vt, groupSteps as Mt, hiddenBefore as kt, staticHidden as xt } from "@web-ppt/core";
|
|
2
|
+
const H = 6;
|
|
3
|
+
function M(r) {
|
|
4
|
+
return `${Math.round(r * 1e3) / 1e3}%`;
|
|
5
|
+
}
|
|
6
|
+
function ct(r, t) {
|
|
7
|
+
const e = r === "vert", a = [];
|
|
8
|
+
for (let n = 0; n < H; n++) {
|
|
9
|
+
const o = n / H * 100, s = (n + 1) / H * 100, c = t ? s : o;
|
|
10
|
+
a.push(e ? x(o, 0, c, 100) : x(0, o, 100, c));
|
|
11
|
+
}
|
|
12
|
+
return z(a);
|
|
13
|
+
}
|
|
14
|
+
const lt = [
|
|
15
|
+
"linear-gradient(#000,#000)",
|
|
16
|
+
"linear-gradient(#000,#000)",
|
|
17
|
+
"linear-gradient(#000,#000)",
|
|
18
|
+
"linear-gradient(#000,#000)"
|
|
19
|
+
].join(", "), yt = { l: 0, t: 0, w: 100, h: 100 };
|
|
20
|
+
function wt(r) {
|
|
21
|
+
return r.l === 0 && r.t === 0 && r.w === 100 && r.h === 100;
|
|
22
|
+
}
|
|
23
|
+
function q(r, t = yt) {
|
|
24
|
+
if (wt(t)) {
|
|
25
|
+
const c = r ? 50 : 0, l = `100% ${c}%, 100% ${c}%, ${c}% 100%, ${c}% 100%`;
|
|
26
|
+
return {
|
|
27
|
+
opacity: 1,
|
|
28
|
+
maskImage: lt,
|
|
29
|
+
maskRepeat: "no-repeat",
|
|
30
|
+
maskPosition: "center top, center bottom, left center, right center",
|
|
31
|
+
maskSize: l,
|
|
32
|
+
maskOrigin: "fill-box",
|
|
33
|
+
maskClip: "fill-box"
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const e = r ? 0.501 : 0, a = t.h * e, n = t.w * e, o = 100 - (t.t + t.h), s = 100 - (t.l + t.w);
|
|
37
|
+
return {
|
|
38
|
+
opacity: 1,
|
|
39
|
+
maskImage: lt,
|
|
40
|
+
maskRepeat: "no-repeat",
|
|
41
|
+
// 位置在两帧里不变,只让尺寸插值。底边和右边钉在墨迹框上,条带向中心长。
|
|
42
|
+
maskPosition: [
|
|
43
|
+
`left ${M(t.l)} top ${M(t.t)}`,
|
|
44
|
+
`left ${M(t.l)} bottom ${M(o)}`,
|
|
45
|
+
`left ${M(t.l)} top ${M(t.t)}`,
|
|
46
|
+
`right ${M(s)} top ${M(t.t)}`
|
|
47
|
+
].join(", "),
|
|
48
|
+
maskSize: [
|
|
49
|
+
`${M(t.w)} ${M(a)}`,
|
|
50
|
+
`${M(t.w)} ${M(a)}`,
|
|
51
|
+
`${M(n)} ${M(t.h)}`,
|
|
52
|
+
`${M(n)} ${M(t.h)}`
|
|
53
|
+
].join(", "),
|
|
54
|
+
maskOrigin: "fill-box",
|
|
55
|
+
maskClip: "fill-box"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function U(r, t = yt) {
|
|
59
|
+
if (wt(t))
|
|
60
|
+
return r ? "inset(0% 0% 0% 0%) fill-box" : "inset(50% 50% 50% 50%) fill-box";
|
|
61
|
+
const e = r ? t.t : t.t + t.h / 2, a = r ? t.l : t.l + t.w / 2, n = r ? 100 - (t.t + t.h) : 100 - (t.t + t.h / 2), o = r ? 100 - (t.l + t.w) : 100 - (t.l + t.w / 2);
|
|
62
|
+
return `inset(${M(e)} ${M(o)} ${M(n)} ${M(a)}) fill-box`;
|
|
63
|
+
}
|
|
64
|
+
function z(r, t = []) {
|
|
65
|
+
return {
|
|
66
|
+
opacity: 1,
|
|
67
|
+
maskImage: r.map(() => "linear-gradient(#000,#000)").join(", "),
|
|
68
|
+
maskRepeat: "no-repeat",
|
|
69
|
+
maskPosition: r.map((e, a) => {
|
|
70
|
+
var n, o;
|
|
71
|
+
return `${((n = t[a]) == null ? void 0 : n.x) === "right" ? `right ${M(100 - e[2][0])}` : `left ${M(e[0][0])}`} ${((o = t[a]) == null ? void 0 : o.y) === "bottom" ? `bottom ${M(100 - e[2][1])}` : `top ${M(e[0][1])}`}`;
|
|
72
|
+
}).join(", "),
|
|
73
|
+
maskSize: r.map((e) => `${M(e[2][0] - e[0][0])} ${M(e[2][1] - e[0][1])}`).join(", "),
|
|
74
|
+
maskOrigin: "fill-box",
|
|
75
|
+
maskClip: "fill-box"
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function Q(r, t = !1) {
|
|
79
|
+
const e = (o) => Math.round(o * 1e3) / 1e3, a = r.map((o) => `M${e(o[0][0])} ${e(o[0][1])} ` + o.slice(1).map(([s, c]) => `L${e(s)} ${e(c)}`).join(" ") + " Z").join(" "), n = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none"><path fill="#000" fill-rule="${t ? "evenodd" : "nonzero"}" d="${a}"/></svg>`;
|
|
80
|
+
return {
|
|
81
|
+
opacity: 1,
|
|
82
|
+
maskImage: `url("data:image/svg+xml,${encodeURIComponent(n)}")`,
|
|
83
|
+
maskRepeat: "no-repeat",
|
|
84
|
+
maskPosition: "center",
|
|
85
|
+
maskSize: "100% 100%",
|
|
86
|
+
maskOrigin: "fill-box",
|
|
87
|
+
maskClip: "fill-box"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function x(r, t, e, a) {
|
|
91
|
+
return [[r, t], [e, t], [e, a], [r, a]];
|
|
92
|
+
}
|
|
93
|
+
function ft(r, t) {
|
|
94
|
+
const e = (r == null ? void 0 : r.endsWith("vert")) ?? !0, a = (r == null ? void 0 : r.startsWith("in")) ?? !1, n = t ? 50 : 0;
|
|
95
|
+
return z(e ? a ? [x(0, 0, n, 100), x(100 - n, 0, 100, 100)] : [x(50 - n, 0, 50, 100), x(50, 0, 50 + n, 100)] : a ? [x(0, 0, 100, n), x(0, 100 - n, 100, 100)] : [x(0, 50 - n, 100, 50), x(0, 50, 100, 50 + n)]);
|
|
96
|
+
}
|
|
97
|
+
function ut(r, t) {
|
|
98
|
+
const e = [];
|
|
99
|
+
for (let a = 0; a < 6; a++) for (let n = 0; n < 8; n++) {
|
|
100
|
+
const o = n * 12.5, s = a * (100 / 6), c = o + 12.5, l = s + 100 / 6, f = (a + n) % 2 === 1;
|
|
101
|
+
r === "down" ? e.push(x(
|
|
102
|
+
o,
|
|
103
|
+
f ? l - (t ? l - s : 0) : s,
|
|
104
|
+
c,
|
|
105
|
+
f ? l : s + (t ? l - s : 0)
|
|
106
|
+
)) : e.push(x(
|
|
107
|
+
f ? c - (t ? c - o : 0) : o,
|
|
108
|
+
s,
|
|
109
|
+
f ? c : o + (t ? c - o : 0),
|
|
110
|
+
l
|
|
111
|
+
));
|
|
112
|
+
}
|
|
113
|
+
return z(e);
|
|
114
|
+
}
|
|
115
|
+
function Z(r, t) {
|
|
116
|
+
const e = r === "vert", a = 128, n = typeof t == "boolean" ? Number(t) : t, o = [];
|
|
117
|
+
for (let s = 0; s < a; s++) {
|
|
118
|
+
const c = s * 100 / a, l = (s + 1) * 100 / a, f = s * 73 % a, u = Math.min(1, Math.max(0, n * a - f)) * (l - c);
|
|
119
|
+
o.push(e ? x(c, 0, c + u, 100) : x(0, c, 100, c + u));
|
|
120
|
+
}
|
|
121
|
+
return z(o);
|
|
122
|
+
}
|
|
123
|
+
function J(r, t) {
|
|
124
|
+
const e = (r == null ? void 0 : r.startsWith("l")) ?? !1, a = (r == null ? void 0 : r.endsWith("u")) ?? !1, n = typeof t == "boolean" ? Number(t) : t, o = 8, s = [];
|
|
125
|
+
for (let c = 0; c < o; c++) {
|
|
126
|
+
const l = c * 100 / o, f = (c + 1) * 100 / o, u = (a ? o - c - 1 : c) / (2 * o), h = Math.min(1, Math.max(0, (n - u) / (1 - (o - 1) / (2 * o)))) * 100;
|
|
127
|
+
s.push(e ? x(100 - h, l, 100, f) : x(0, l, h, f));
|
|
128
|
+
}
|
|
129
|
+
return z(s, e ? s.map(() => ({ x: "right" })) : []);
|
|
130
|
+
}
|
|
131
|
+
function $t(r, t) {
|
|
132
|
+
if (r === "circle") return Array.from({ length: 40 }, (a, n) => {
|
|
133
|
+
const o = n * Math.PI / 20 - Math.PI / 2;
|
|
134
|
+
return [50 + t * Math.cos(o), 50 + t * Math.sin(o)];
|
|
135
|
+
});
|
|
136
|
+
if (r === "diamond") return [
|
|
137
|
+
[50, 50 - t],
|
|
138
|
+
[50 + t, 50],
|
|
139
|
+
[50, 50 + t],
|
|
140
|
+
[50 - t, 50]
|
|
141
|
+
];
|
|
142
|
+
const e = t / 3;
|
|
143
|
+
return [
|
|
144
|
+
[50 - e, 50 - t],
|
|
145
|
+
[50 + e, 50 - t],
|
|
146
|
+
[50 + e, 50 - e],
|
|
147
|
+
[50 + t, 50 - e],
|
|
148
|
+
[50 + t, 50 + e],
|
|
149
|
+
[50 + e, 50 + e],
|
|
150
|
+
[50 + e, 50 + t],
|
|
151
|
+
[50 - e, 50 + t],
|
|
152
|
+
[50 - e, 50 + e],
|
|
153
|
+
[50 - t, 50 + e],
|
|
154
|
+
[50 - t, 50 - e],
|
|
155
|
+
[50 - e, 50 - e]
|
|
156
|
+
];
|
|
157
|
+
}
|
|
158
|
+
function tt(r, t, e) {
|
|
159
|
+
const a = typeof e == "boolean" ? Number(e) : e;
|
|
160
|
+
if (r === "plus" && t === "in") {
|
|
161
|
+
const c = a * 50;
|
|
162
|
+
return z([
|
|
163
|
+
x(0, 0, c, c),
|
|
164
|
+
x(100 - c, 0, 100, c),
|
|
165
|
+
x(0, 100 - c, c, 100),
|
|
166
|
+
x(100 - c, 100 - c, 100, 100)
|
|
167
|
+
], [{}, { x: "right" }, { y: "bottom" }, { x: "right", y: "bottom" }]);
|
|
168
|
+
}
|
|
169
|
+
const n = r === "circle" ? 72 : r === "diamond" ? 101 : 151, o = (t === "in" ? 1 - a : a) * n, s = $t(r, o);
|
|
170
|
+
return t === "in" ? Q([x(0, 0, 100, 100), s], !0) : Q([s]);
|
|
171
|
+
}
|
|
172
|
+
function et(r, t) {
|
|
173
|
+
const e = [1, 2, 3, 4, 8].includes(Number(r)) ? Number(r) : 1, a = typeof t == "boolean" ? Number(t) : t, n = [];
|
|
174
|
+
for (let o = 0; o < e; o++) {
|
|
175
|
+
const s = -Math.PI / 2 + o * 2 * Math.PI / e, c = a * 2 * Math.PI / e, l = [[50, 50]];
|
|
176
|
+
for (let f = 0; f <= 16; f++) {
|
|
177
|
+
const u = s + c * f / 16;
|
|
178
|
+
l.push([50 + 200 * Math.cos(u), 50 + 200 * Math.sin(u)]);
|
|
179
|
+
}
|
|
180
|
+
n.push(l);
|
|
181
|
+
}
|
|
182
|
+
return Q(n);
|
|
183
|
+
}
|
|
184
|
+
function rt(r, t) {
|
|
185
|
+
const e = typeof r == "boolean" ? Number(r) : r, a = [];
|
|
186
|
+
for (let n = 0; n < 8; n++) for (let o = 0; o < 10; o++) {
|
|
187
|
+
const s = o * 10, c = n * 12.5, l = (o + 1) * 10, f = (n + 1) * 12.5;
|
|
188
|
+
let u = Math.imul(n * 10 + o + t * 101, 73244475);
|
|
189
|
+
u = Math.imul(u ^ u >>> 16, 73244475), u = (u ^ u >>> 16) >>> 0;
|
|
190
|
+
const i = u % 17 / 17, h = s + (l - s) * i, d = c + (f - c) * (1 - i), w = (u >>> 8) % 8, v = Math.min(1, Math.max(0, e * 8 - w));
|
|
191
|
+
a.push(x(
|
|
192
|
+
h + (s - h) * v,
|
|
193
|
+
d + (c - d) * v,
|
|
194
|
+
h + (l - h) * v,
|
|
195
|
+
d + (f - d) * v
|
|
196
|
+
));
|
|
197
|
+
}
|
|
198
|
+
return z(a);
|
|
199
|
+
}
|
|
200
|
+
const Et = 2147483647;
|
|
201
|
+
function Pt(r, t, e) {
|
|
202
|
+
const a = r.querySelector("audio,video");
|
|
203
|
+
if (!a) return null;
|
|
204
|
+
if (!Number.isFinite(e) || e < 0)
|
|
205
|
+
throw new Error(`媒体调用的起始时间无效:${e}ms`);
|
|
206
|
+
let n = null, o = e, s = !1, c = !1, l, f;
|
|
207
|
+
const u = new Promise((w, v) => {
|
|
208
|
+
l = w, f = v;
|
|
209
|
+
}), i = () => {
|
|
210
|
+
c = !0, Promise.resolve(a.play()).then(l, f);
|
|
211
|
+
}, h = () => {
|
|
212
|
+
if (n = null, !s)
|
|
213
|
+
try {
|
|
214
|
+
switch (t.action) {
|
|
215
|
+
case "play":
|
|
216
|
+
t.fromSeconds !== void 0 && (a.currentTime = t.fromSeconds), i();
|
|
217
|
+
return;
|
|
218
|
+
case "resume":
|
|
219
|
+
i();
|
|
220
|
+
return;
|
|
221
|
+
case "pause":
|
|
222
|
+
a.pause();
|
|
223
|
+
break;
|
|
224
|
+
case "stop":
|
|
225
|
+
a.pause(), a.currentTime = 0;
|
|
226
|
+
break;
|
|
227
|
+
case "togglePause":
|
|
228
|
+
if (a.paused) {
|
|
229
|
+
i();
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
a.pause();
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
l();
|
|
236
|
+
} catch (w) {
|
|
237
|
+
f(w);
|
|
238
|
+
}
|
|
239
|
+
}, d = () => {
|
|
240
|
+
if (o === 0) {
|
|
241
|
+
h();
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const w = Math.min(o, Et);
|
|
245
|
+
n = setTimeout(() => {
|
|
246
|
+
o -= w, d();
|
|
247
|
+
}, w);
|
|
248
|
+
};
|
|
249
|
+
return d(), {
|
|
250
|
+
finished: u,
|
|
251
|
+
cancel: () => {
|
|
252
|
+
s = !0, n !== null && clearTimeout(n), c && a.pause(), l();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
const C = 1.15;
|
|
257
|
+
function St(r) {
|
|
258
|
+
switch (r) {
|
|
259
|
+
case "l":
|
|
260
|
+
return [-100 * C, 0];
|
|
261
|
+
case "r":
|
|
262
|
+
return [100 * C, 0];
|
|
263
|
+
case "u":
|
|
264
|
+
return [0, -100 * C];
|
|
265
|
+
case "d":
|
|
266
|
+
return [0, 100 * C];
|
|
267
|
+
case "lu":
|
|
268
|
+
return [-100 * C, -100 * C];
|
|
269
|
+
case "ru":
|
|
270
|
+
return [100 * C, -100 * C];
|
|
271
|
+
case "ld":
|
|
272
|
+
return [-100 * C, 100 * C];
|
|
273
|
+
case "rd":
|
|
274
|
+
return [100 * C, 100 * C];
|
|
275
|
+
default:
|
|
276
|
+
return [0, 100 * C];
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function At(r, t, e) {
|
|
280
|
+
const a = r.querySelector("svg");
|
|
281
|
+
if (!a || typeof a.getBoundingClientRect != "function" || typeof t.getBoundingClientRect != "function") return null;
|
|
282
|
+
const n = a.getBoundingClientRect(), o = t.getBoundingClientRect();
|
|
283
|
+
if (n.width < 1 || n.height < 1 || o.width < 1 || o.height < 1) return null;
|
|
284
|
+
const s = (n.left - o.right - 4) / o.width * 100, c = (n.right - o.left + 4) / o.width * 100, l = (n.top - o.bottom - 4) / o.height * 100, f = (n.bottom - o.top + 4) / o.height * 100, u = e != null && e.includes("l") ? s : e != null && e.includes("r") ? c : 0, i = e != null && e.includes("u") ? l : e != null && e.includes("d") || !e ? f : 0;
|
|
285
|
+
return `translate(${u}%, ${i}%)`;
|
|
286
|
+
}
|
|
287
|
+
function X(r, t) {
|
|
288
|
+
return r === t ? `scale(${r})` : `scale(${r}, ${t})`;
|
|
289
|
+
}
|
|
290
|
+
const Ct = ["maskImage", "maskRepeat", "maskPosition", "maskSize"];
|
|
291
|
+
function Nt(r) {
|
|
292
|
+
var i, h;
|
|
293
|
+
const t = (i = r.getBoundingClientRect) == null ? void 0 : i.call(r), e = (h = r.ownerDocument) == null ? void 0 : h.createRange;
|
|
294
|
+
if (!t || t.width < 1 || t.height < 1 || typeof e != "function") return null;
|
|
295
|
+
const a = e.call(r.ownerDocument);
|
|
296
|
+
a.selectNodeContents(r);
|
|
297
|
+
const n = a.getBoundingClientRect();
|
|
298
|
+
if (n.width < 1 || n.height < 1) return null;
|
|
299
|
+
const o = Math.min(100, Math.max(0, (n.left - t.left) / t.width * 100)), s = Math.min(100, Math.max(0, (n.top - t.top) / t.height * 100)), c = Math.min(100, Math.max(o, (n.right - t.left) / t.width * 100)), l = Math.min(100, Math.max(s, (n.bottom - t.top) / t.height * 100)), f = c - o, u = l - s;
|
|
300
|
+
return f < 1 || u < 1 ? null : { l: o, t: s, w: f, h: u };
|
|
301
|
+
}
|
|
302
|
+
function Tt(r, t) {
|
|
303
|
+
if (!t || typeof r.querySelectorAll != "function") return [];
|
|
304
|
+
const e = [];
|
|
305
|
+
for (const n of r.querySelectorAll("[data-p]")) {
|
|
306
|
+
const o = Number(n.getAttribute("data-p"));
|
|
307
|
+
Number.isInteger(o) && o >= t.start && o <= t.end && e.push(n);
|
|
308
|
+
}
|
|
309
|
+
if (e.length) return e;
|
|
310
|
+
const a = [];
|
|
311
|
+
for (const n of r.querySelectorAll("foreignObject > :first-child")) {
|
|
312
|
+
const o = [...n.children].filter((s) => s.localName === "div");
|
|
313
|
+
for (let s = t.start; s <= t.end && s < o.length; s++)
|
|
314
|
+
a.push(o[s]);
|
|
315
|
+
}
|
|
316
|
+
return a;
|
|
317
|
+
}
|
|
318
|
+
function Ft(r, t, e) {
|
|
319
|
+
if (r.kind !== "emphasis" && r.kind !== "motion" && r.effect === "zoom" && (r.dir === "in" || r.dir === "out")) {
|
|
320
|
+
const a = Nt(t);
|
|
321
|
+
if (a) {
|
|
322
|
+
const n = r.dir === "in" ? {
|
|
323
|
+
from: q(!1, a),
|
|
324
|
+
to: q(!0, a)
|
|
325
|
+
} : {
|
|
326
|
+
from: { opacity: 1, clipPath: U(!1, a) },
|
|
327
|
+
to: { opacity: 1, clipPath: U(!0, a) }
|
|
328
|
+
}, o = r.kind === "exit" ? [n.to, n.from] : [n.from, n.to];
|
|
329
|
+
return ot(o);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return ot(e);
|
|
333
|
+
}
|
|
334
|
+
function ot(r) {
|
|
335
|
+
const t = (e) => e.clipPath !== void 0 || e.maskSize !== void 0;
|
|
336
|
+
return r.some(t) ? r.map((e) => {
|
|
337
|
+
const a = {};
|
|
338
|
+
e.clipPath !== void 0 && (a.clipPath = String(e.clipPath).replace(/ fill-box/g, ""));
|
|
339
|
+
for (const n of Ct) e[n] !== void 0 && (a[n] = e[n]);
|
|
340
|
+
return e.maskSize !== void 0 && (a.maskOrigin = "border-box", a.maskClip = "border-box"), e.offset !== void 0 && (a.offset = e.offset), a;
|
|
341
|
+
}) : null;
|
|
342
|
+
}
|
|
343
|
+
function V(r, t) {
|
|
344
|
+
const e = t ? 100 : 0;
|
|
345
|
+
switch (r) {
|
|
346
|
+
case "l":
|
|
347
|
+
return `inset(0 ${e}% 0 0)`;
|
|
348
|
+
case "r":
|
|
349
|
+
return `inset(0 0 0 ${e}%)`;
|
|
350
|
+
case "u":
|
|
351
|
+
return `inset(0 0 ${e}% 0)`;
|
|
352
|
+
case "horz":
|
|
353
|
+
return `inset(0 ${e / 2}% 0 ${e / 2}%)`;
|
|
354
|
+
case "vert":
|
|
355
|
+
return `inset(${e / 2}% 0 ${e / 2}% 0)`;
|
|
356
|
+
default:
|
|
357
|
+
return `inset(${e}% 0 0 0)`;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
const Ot = {
|
|
361
|
+
d: { origin: "center bottom", axis: "scaleY" },
|
|
362
|
+
u: { origin: "center top", axis: "scaleY" },
|
|
363
|
+
l: { origin: "left center", axis: "scaleX" },
|
|
364
|
+
r: { origin: "right center", axis: "scaleX" },
|
|
365
|
+
lu: { origin: "left top", axis: "scale" },
|
|
366
|
+
ru: { origin: "right top", axis: "scale" },
|
|
367
|
+
ld: { origin: "left bottom", axis: "scale" },
|
|
368
|
+
rd: { origin: "right bottom", axis: "scale" }
|
|
369
|
+
};
|
|
370
|
+
function It(r) {
|
|
371
|
+
return (r ? Ot[r] : void 0) ?? { origin: "center", axis: "scaleX" };
|
|
372
|
+
}
|
|
373
|
+
function nt(r, t) {
|
|
374
|
+
const e = Math.round(Math.sin(2.5 * Math.PI * t) * 1e4) / 1e4;
|
|
375
|
+
return {
|
|
376
|
+
opacity: t,
|
|
377
|
+
transform: r === "horz" ? `scaleY(${e})` : `scaleX(${e})`
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function st(r) {
|
|
381
|
+
var t, e, a, n, o, s, c, l, f, u;
|
|
382
|
+
switch (r.effect) {
|
|
383
|
+
case "appear":
|
|
384
|
+
return { from: { opacity: 0 }, to: { opacity: 1 } };
|
|
385
|
+
case "fly": {
|
|
386
|
+
const [i, h] = St(r.dir);
|
|
387
|
+
return {
|
|
388
|
+
from: { opacity: 0, transform: `translate(${i}%, ${h}%)` },
|
|
389
|
+
to: { opacity: 1, transform: "translate(0, 0)" }
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
case "zoom":
|
|
393
|
+
return r.dir === "in" ? { from: q(!1), to: q(!0) } : r.dir === "out" ? {
|
|
394
|
+
from: { opacity: 1, clipPath: U(!1) },
|
|
395
|
+
to: { opacity: 1, clipPath: U(!0) }
|
|
396
|
+
} : {
|
|
397
|
+
from: { opacity: 0, transform: X(((t = r.scale) == null ? void 0 : t.fromX) ?? 0, ((e = r.scale) == null ? void 0 : e.fromY) ?? 0) },
|
|
398
|
+
to: { opacity: 1, transform: X(((a = r.scale) == null ? void 0 : a.toX) ?? 1, ((n = r.scale) == null ? void 0 : n.toY) ?? 1) }
|
|
399
|
+
};
|
|
400
|
+
case "grow":
|
|
401
|
+
return {
|
|
402
|
+
from: { opacity: 1, transform: `${X(((o = r.scale) == null ? void 0 : o.fromX) ?? 0, ((s = r.scale) == null ? void 0 : s.fromY) ?? 0)} rotate(${((c = r.rotation) == null ? void 0 : c.from) ?? 0}deg)` },
|
|
403
|
+
to: { opacity: 1, transform: `${X(((l = r.scale) == null ? void 0 : l.toX) ?? 1, ((f = r.scale) == null ? void 0 : f.toY) ?? 1)} rotate(${((u = r.rotation) == null ? void 0 : u.to) ?? 90}deg)` }
|
|
404
|
+
};
|
|
405
|
+
case "spin":
|
|
406
|
+
return { from: { opacity: 0, transform: "rotate(-180deg) scale(0.4)" }, to: { opacity: 1, transform: "rotate(0) scale(1)" } };
|
|
407
|
+
case "swivel":
|
|
408
|
+
return { from: nt(r.dir, 0), to: nt(r.dir, 1) };
|
|
409
|
+
case "float":
|
|
410
|
+
return { from: { opacity: 0, transform: "translateY(30%)" }, to: { opacity: 1, transform: "translateY(0)" } };
|
|
411
|
+
case "bounce":
|
|
412
|
+
return { from: { opacity: 0, transform: "translateY(-60%)" }, to: { opacity: 1, transform: "translateY(0)" } };
|
|
413
|
+
case "stretch": {
|
|
414
|
+
if (r.scale)
|
|
415
|
+
return {
|
|
416
|
+
from: { opacity: 0, transform: X(r.scale.fromX, r.scale.fromY) },
|
|
417
|
+
to: { opacity: 1, transform: X(r.scale.toX, r.scale.toY) }
|
|
418
|
+
};
|
|
419
|
+
const { origin: i, axis: h } = It(r.dir);
|
|
420
|
+
return {
|
|
421
|
+
from: { opacity: 1, transform: `${h}(0)`, transformOrigin: i },
|
|
422
|
+
to: { opacity: 1, transform: `${h}(1)`, transformOrigin: i }
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
case "blinds":
|
|
426
|
+
return {
|
|
427
|
+
from: ct(r.dir, !1),
|
|
428
|
+
to: ct(r.dir, !0)
|
|
429
|
+
};
|
|
430
|
+
case "checkerboard":
|
|
431
|
+
return {
|
|
432
|
+
from: ut(r.dir, !1),
|
|
433
|
+
to: ut(r.dir, !0)
|
|
434
|
+
};
|
|
435
|
+
case "randomBar":
|
|
436
|
+
return {
|
|
437
|
+
from: Z(r.dir, !1),
|
|
438
|
+
to: Z(r.dir, !0)
|
|
439
|
+
};
|
|
440
|
+
case "strips":
|
|
441
|
+
return {
|
|
442
|
+
from: J(r.dir, !1),
|
|
443
|
+
to: J(r.dir, !0)
|
|
444
|
+
};
|
|
445
|
+
case "circle":
|
|
446
|
+
case "diamond":
|
|
447
|
+
case "plus":
|
|
448
|
+
return {
|
|
449
|
+
from: tt(r.effect, r.dir, !1),
|
|
450
|
+
to: tt(r.effect, r.dir, !0)
|
|
451
|
+
};
|
|
452
|
+
case "wipe":
|
|
453
|
+
return {
|
|
454
|
+
from: { opacity: 1, clipPath: V(r.dir, !0) },
|
|
455
|
+
to: { opacity: 1, clipPath: V(r.dir, !1) }
|
|
456
|
+
};
|
|
457
|
+
case "split":
|
|
458
|
+
return {
|
|
459
|
+
from: ft(r.dir, !1),
|
|
460
|
+
to: ft(r.dir, !0)
|
|
461
|
+
};
|
|
462
|
+
case "wheel":
|
|
463
|
+
return {
|
|
464
|
+
from: et(r.dir, !1),
|
|
465
|
+
to: et(r.dir, !0)
|
|
466
|
+
};
|
|
467
|
+
case "dissolve":
|
|
468
|
+
return {
|
|
469
|
+
from: rt(!1, r.target),
|
|
470
|
+
to: rt(!0, r.target)
|
|
471
|
+
};
|
|
472
|
+
case "random":
|
|
473
|
+
return st({ ...r, effect: ["fly", "wipe", "zoom"][r.target % 3], dir: "d" });
|
|
474
|
+
case "fade":
|
|
475
|
+
default:
|
|
476
|
+
return { from: { opacity: 0 }, to: { opacity: 1 } };
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
function Rt(r) {
|
|
480
|
+
const t = st({ ...r, kind: "entrance" });
|
|
481
|
+
return { from: t.to, to: t.from };
|
|
482
|
+
}
|
|
483
|
+
function Yt(r) {
|
|
484
|
+
var t, e, a, n;
|
|
485
|
+
switch (r.effect) {
|
|
486
|
+
case "spin":
|
|
487
|
+
return { from: { transform: "rotate(0)" }, to: { transform: "rotate(360deg)" } };
|
|
488
|
+
case "grow":
|
|
489
|
+
return {
|
|
490
|
+
from: { transform: X(((t = r.scale) == null ? void 0 : t.fromX) ?? 1, ((e = r.scale) == null ? void 0 : e.fromY) ?? 1) },
|
|
491
|
+
to: { transform: X(((a = r.scale) == null ? void 0 : a.toX) ?? 1.25, ((n = r.scale) == null ? void 0 : n.toY) ?? 1.25) }
|
|
492
|
+
};
|
|
493
|
+
default:
|
|
494
|
+
return { from: { opacity: 1 }, to: { opacity: 0.5 } };
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
function Wt(r) {
|
|
498
|
+
return r.kind === "exit" ? Rt(r) : r.kind === "emphasis" ? Yt(r) : r.kind === "motion" ? { from: { opacity: 1 }, to: { opacity: 1 } } : st(r);
|
|
499
|
+
}
|
|
500
|
+
function Lt(r, t) {
|
|
501
|
+
var l, f, u;
|
|
502
|
+
const e = [], a = [], n = [];
|
|
503
|
+
let o = !1, s = 0, c = 0;
|
|
504
|
+
for (const i of t) {
|
|
505
|
+
const h = i.trigger === "afterPrev" ? c + i.delayMs : i.trigger === "withPrev" ? s + i.delayMs : i.delayMs;
|
|
506
|
+
s = h, c = h + i.durationMs;
|
|
507
|
+
const d = r.querySelector(`[data-el="${i.target}"]`);
|
|
508
|
+
if (!d) continue;
|
|
509
|
+
if (i.mediaCommand) {
|
|
510
|
+
const g = Pt(d, i.mediaCommand, h);
|
|
511
|
+
g && n.push(g);
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
i.kind === "exit" && a.push(d);
|
|
515
|
+
const { from: w, to: v } = Wt(i);
|
|
516
|
+
if (d.style.visibility = "visible", i.kind === "entrance" && (d.style.opacity = ""), i.effect === "fly" && (i.kind === "entrance" || i.kind === "exit")) {
|
|
517
|
+
const g = At(r, d, i.dir);
|
|
518
|
+
g && (i.kind === "entrance" ? w.transform = g : v.transform = g);
|
|
519
|
+
}
|
|
520
|
+
const E = (l = i.motionPath) == null ? void 0 : l.reduce((g, [m, R], N, p) => (N === 0 ? g.push(0) : g.push(g[N - 1] + Math.hypot(m - p[N - 1][0], R - p[N - 1][1])), g), []), A = (E == null ? void 0 : E[E.length - 1]) ?? 0, I = (f = i.motionPath) != null && f.length ? i.motionPath.map(([g, m], R) => ({
|
|
521
|
+
transform: `translate(${g}px, ${m}px)`,
|
|
522
|
+
offset: A > 0 ? E[R] / A : R / (i.motionPath.length - 1)
|
|
523
|
+
})) : i.effect === "randomBar" ? Array.from({ length: 13 }, (g, m) => ({
|
|
524
|
+
...Z(i.dir, i.kind === "exit" ? 1 - m / 12 : m / 12),
|
|
525
|
+
offset: m / 12
|
|
526
|
+
})) : i.effect === "strips" ? Array.from({ length: 21 }, (g, m) => ({
|
|
527
|
+
...J(i.dir, i.kind === "exit" ? 1 - m / 20 : m / 20),
|
|
528
|
+
offset: m / 20
|
|
529
|
+
})) : i.effect === "wheel" ? Array.from({ length: 73 }, (g, m) => ({
|
|
530
|
+
...et(i.dir, i.kind === "exit" ? 1 - m / 72 : m / 72),
|
|
531
|
+
offset: m / 72
|
|
532
|
+
})) : i.effect === "circle" || i.effect === "diamond" || i.effect === "plus" && i.dir !== "in" ? Array.from({ length: 37 }, (g, m) => ({
|
|
533
|
+
...tt(
|
|
534
|
+
i.effect,
|
|
535
|
+
i.dir,
|
|
536
|
+
i.kind === "exit" ? 1 - m / 36 : m / 36
|
|
537
|
+
),
|
|
538
|
+
offset: m / 36
|
|
539
|
+
})) : i.effect === "dissolve" ? Array.from({ length: 9 }, (g, m) => ({
|
|
540
|
+
...rt(i.kind === "exit" ? 1 - m / 8 : m / 8, i.target),
|
|
541
|
+
offset: m / 8
|
|
542
|
+
})) : i.effect === "swivel" && (i.kind === "entrance" || i.kind === "exit") ? Array.from({ length: 41 }, (g, m) => ({
|
|
543
|
+
...nt(i.dir, i.kind === "exit" ? 1 - m / 40 : m / 40),
|
|
544
|
+
offset: m / 40
|
|
545
|
+
})) : i.effect === "bounce" && i.kind === "entrance" ? [
|
|
546
|
+
{ opacity: 0, transform: "translateY(-60%)", offset: 0 },
|
|
547
|
+
{ opacity: 1, transform: "translateY(10%)", offset: 0.5 },
|
|
548
|
+
{ opacity: 1, transform: "translateY(-8%)", offset: 0.7 },
|
|
549
|
+
{ opacity: 1, transform: "translateY(3%)", offset: 0.85 },
|
|
550
|
+
{ opacity: 1, transform: "translateY(0)", offset: 1 }
|
|
551
|
+
] : [w, v];
|
|
552
|
+
try {
|
|
553
|
+
const g = (u = i.motionPath) != null && u.length || i.effect === "randomBar" || i.effect === "strips" || i.effect === "wheel" || i.effect === "circle" || i.effect === "diamond" || i.effect === "plus" || i.effect === "dissolve" || i.effect === "bounce" || i.effect === "swivel" ? "linear" : i.effect === "appear" && i.kind === "entrance" ? "steps(1, start)" : i.effect === "appear" && i.kind === "exit" ? "steps(1, end)" : "cubic-bezier(0.25, 0.46, 0.45, 0.94)", m = d.animate(I, {
|
|
554
|
+
duration: i.durationMs,
|
|
555
|
+
delay: h,
|
|
556
|
+
// 路径动画在 PowerPoint 里是匀速,不能套入场用的缓动
|
|
557
|
+
easing: g,
|
|
558
|
+
fill: "both"
|
|
559
|
+
});
|
|
560
|
+
i.kind === "exit" && m.finished.then(() => {
|
|
561
|
+
o || (d.style.visibility = "hidden");
|
|
562
|
+
}).catch(() => {
|
|
563
|
+
}), e.push(m);
|
|
564
|
+
const R = ot(I);
|
|
565
|
+
if (!R || typeof d.querySelectorAll != "function") continue;
|
|
566
|
+
const N = Tt(d, i.paragraphRange), p = N.length ? N : d.querySelectorAll("foreignObject > :first-child");
|
|
567
|
+
for (const b of p) {
|
|
568
|
+
if (!(b instanceof HTMLElement)) continue;
|
|
569
|
+
const P = N.length ? Ft(i, b, I) : R;
|
|
570
|
+
P && e.push(b.animate(P, {
|
|
571
|
+
duration: i.durationMs,
|
|
572
|
+
delay: h,
|
|
573
|
+
easing: g,
|
|
574
|
+
fill: "both"
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
} catch {
|
|
578
|
+
Object.assign(d.style, I[I.length - 1] ?? v), i.kind === "exit" && (d.style.visibility = "hidden");
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return {
|
|
582
|
+
animations: e,
|
|
583
|
+
cancel: () => {
|
|
584
|
+
o = !0, e.forEach((i) => {
|
|
585
|
+
try {
|
|
586
|
+
i.finish();
|
|
587
|
+
} catch {
|
|
588
|
+
}
|
|
589
|
+
}), n.forEach((i) => i.cancel());
|
|
590
|
+
for (const i of a) i.style.visibility = "hidden";
|
|
591
|
+
},
|
|
592
|
+
// 等全部视觉与媒体调用落定后再报告:媒体失败不能让批次提前收尾、截断仍在播的视觉动画。
|
|
593
|
+
finished: Promise.all([
|
|
594
|
+
Promise.all(e.map((i) => i.finished.catch(() => {
|
|
595
|
+
}))),
|
|
596
|
+
Promise.allSettled(n.map((i) => i.finished))
|
|
597
|
+
]).then(([, i]) => {
|
|
598
|
+
const h = i.find((d) => d.status === "rejected");
|
|
599
|
+
if (h) throw h.reason;
|
|
600
|
+
})
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function ht(r, t) {
|
|
604
|
+
const e = r.dir ?? bt(r.type) ?? "", a = (o, s) => `translate(${o}, ${s})`, n = () => {
|
|
605
|
+
const o = {
|
|
606
|
+
l: ["-100%", "0"],
|
|
607
|
+
r: ["100%", "0"],
|
|
608
|
+
u: ["0", "-100%"],
|
|
609
|
+
d: ["0", "100%"],
|
|
610
|
+
lu: ["-100%", "-100%"],
|
|
611
|
+
ld: ["-100%", "100%"],
|
|
612
|
+
ru: ["100%", "-100%"],
|
|
613
|
+
rd: ["100%", "100%"]
|
|
614
|
+
};
|
|
615
|
+
return o[e] ?? o.d;
|
|
616
|
+
};
|
|
617
|
+
switch (r.type) {
|
|
618
|
+
case "cut":
|
|
619
|
+
return t ? [
|
|
620
|
+
{ opacity: 0, offset: 0 },
|
|
621
|
+
{ opacity: 0, offset: 0.49 },
|
|
622
|
+
{ opacity: 1, offset: 0.5 },
|
|
623
|
+
{ opacity: 1, offset: 1 }
|
|
624
|
+
] : [
|
|
625
|
+
{ opacity: 1, offset: 0 },
|
|
626
|
+
{ opacity: 1, offset: 0.49 },
|
|
627
|
+
{ opacity: 0, offset: 0.5 },
|
|
628
|
+
{ opacity: 0, offset: 1 }
|
|
629
|
+
];
|
|
630
|
+
case "push":
|
|
631
|
+
case "pull": {
|
|
632
|
+
const [o, s] = n(), c = r.type === "pull" ? -1 : 1, l = (f) => f === "0" ? "0" : `${-parseFloat(f) * c}%`;
|
|
633
|
+
return t ? [{ transform: a(c > 0 ? o : l(o), c > 0 ? s : l(s)) }, { transform: "translate(0,0)" }] : [{ transform: "translate(0,0)" }, { transform: a(l(o), l(s)) }];
|
|
634
|
+
}
|
|
635
|
+
case "cover": {
|
|
636
|
+
const [o, s] = n();
|
|
637
|
+
return t ? [{ transform: a(o, s) }, { transform: "translate(0,0)" }] : [{ opacity: 1 }, { opacity: 1 }];
|
|
638
|
+
}
|
|
639
|
+
case "wipe": {
|
|
640
|
+
const o = V(e || "d", !0), s = V(e || "d", !1);
|
|
641
|
+
return t ? [{ clipPath: o }, { clipPath: s }] : [{ opacity: 1 }, { opacity: 1 }];
|
|
642
|
+
}
|
|
643
|
+
case "split": {
|
|
644
|
+
const o = e.startsWith("vert"), s = e.endsWith("out"), c = o ? "inset(0 50% 0 50%)" : "inset(50% 0 50% 0)", l = "inset(0 0 0 0)";
|
|
645
|
+
return t ? s ? [{ clipPath: c }, { clipPath: l }] : [{ clipPath: l }, { clipPath: l }] : [{ clipPath: l }, { clipPath: c }];
|
|
646
|
+
}
|
|
647
|
+
case "zoom":
|
|
648
|
+
return t ? [{ opacity: 0, transform: e === "out" ? "scale(1.4)" : "scale(0.6)" }, { opacity: 1, transform: "scale(1)" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
649
|
+
case "wheel":
|
|
650
|
+
case "circle":
|
|
651
|
+
case "diamond":
|
|
652
|
+
case "plus":
|
|
653
|
+
case "wedge":
|
|
654
|
+
return t ? [{ opacity: 0, transform: "scale(0.7)" }, { opacity: 1, transform: "scale(1)" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
655
|
+
case "ripple": {
|
|
656
|
+
const o = {
|
|
657
|
+
lu: "0% 0%",
|
|
658
|
+
ld: "0% 100%",
|
|
659
|
+
ru: "100% 0%",
|
|
660
|
+
rd: "100% 100%",
|
|
661
|
+
center: "50% 50%"
|
|
662
|
+
}, s = o[e] ?? o.center;
|
|
663
|
+
return t ? [{ clipPath: `circle(0% at ${s})` }, { clipPath: `circle(145% at ${s})` }] : [{ opacity: 1 }, { opacity: 1 }];
|
|
664
|
+
}
|
|
665
|
+
case "vortex": {
|
|
666
|
+
const [o, s] = n(), c = e === "r" || e === "d" ? 180 : -180;
|
|
667
|
+
return t ? [{ opacity: 0, transformOrigin: `${o === "0" ? "50%" : o.startsWith("-") ? "0%" : "100%"} ${s === "0" ? "50%" : s.startsWith("-") ? "0%" : "100%"}`, transform: `scale(0.2) rotate(${c}deg)` }, { opacity: 1, transform: "none" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
668
|
+
}
|
|
669
|
+
case "honeycomb":
|
|
670
|
+
return t ? [{ opacity: 0, transform: "scale(0.85) rotate(-6deg)" }, { opacity: 1, transform: "none" }] : [{ opacity: 1, transform: "none" }, { opacity: 0, transform: "scale(1.1)" }];
|
|
671
|
+
case "glitter":
|
|
672
|
+
return t ? [{ opacity: 0, clipPath: V(e || "l", !0) }, { opacity: 1, clipPath: V(e || "l", !1) }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
673
|
+
case "shred": {
|
|
674
|
+
const o = e === "out";
|
|
675
|
+
return t ? [{ opacity: 0, transform: o ? "scale(1.35) rotate(5deg)" : "scale(0.72) rotate(-5deg)" }, { opacity: 1, transform: "none" }] : [{ opacity: 1, transform: "none" }, { opacity: 0, transform: o ? "scaleY(0.72)" : "scaleY(1.2)" }];
|
|
676
|
+
}
|
|
677
|
+
case "flash":
|
|
678
|
+
return t ? [{ opacity: 0, filter: "brightness(3)" }, { opacity: 1, filter: "brightness(1)" }] : [{ opacity: 1, filter: "brightness(1)" }, { opacity: 0, filter: "brightness(3)" }];
|
|
679
|
+
case "reveal": {
|
|
680
|
+
const [o, s] = n();
|
|
681
|
+
return t ? [{ opacity: 0, transform: a(o, s) }, { opacity: 1, transform: "translate(0,0)" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
682
|
+
}
|
|
683
|
+
case "wheelReverse":
|
|
684
|
+
return t ? [{ opacity: 0, transform: "scale(1.3) rotate(20deg)" }, { opacity: 1, transform: "none" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
685
|
+
case "doors":
|
|
686
|
+
return t ? [{ clipPath: e === "horz" ? "inset(50% 0 50% 0)" : "inset(0 50% 0 50%)" }, { clipPath: "inset(0 0 0 0)" }] : [{ opacity: 1 }, { opacity: 1 }];
|
|
687
|
+
case "window":
|
|
688
|
+
return t ? [{ clipPath: e === "horz" ? "inset(0 50% 0 50%)" : "inset(50% 0 50% 0)" }, { clipPath: "inset(0 0 0 0)" }] : [{ opacity: 1 }, { opacity: 1 }];
|
|
689
|
+
case "switch":
|
|
690
|
+
case "flip": {
|
|
691
|
+
const o = (r.type === "flip" ? -1 : 1) * (e === "r" ? -1 : 1);
|
|
692
|
+
return t ? [
|
|
693
|
+
{ opacity: 0, transform: `perspective(1400px) rotateY(${o * -80}deg)` },
|
|
694
|
+
{ opacity: 1, transform: "perspective(1400px) rotateY(0)" }
|
|
695
|
+
] : [
|
|
696
|
+
{ opacity: 1, transform: "perspective(1400px) rotateY(0)" },
|
|
697
|
+
{ opacity: 0, transform: `perspective(1400px) rotateY(${o * 80}deg)` }
|
|
698
|
+
];
|
|
699
|
+
}
|
|
700
|
+
case "prism": {
|
|
701
|
+
const o = e === "u" || e === "d", s = e === "r" || e === "d" ? -1 : 1, c = (l) => o ? `rotateX(${l}deg)` : `rotateY(${l}deg)`;
|
|
702
|
+
return t ? [
|
|
703
|
+
{ opacity: 0, transform: `perspective(1400px) ${c(s * -70)}` },
|
|
704
|
+
{ opacity: 1, transform: `perspective(1400px) ${c(0)}` }
|
|
705
|
+
] : [
|
|
706
|
+
{ opacity: 1, transform: `perspective(1400px) ${c(0)}` },
|
|
707
|
+
{ opacity: 0, transform: `perspective(1400px) ${c(s * 70)}` }
|
|
708
|
+
];
|
|
709
|
+
}
|
|
710
|
+
case "ferris": {
|
|
711
|
+
const o = e === "r" ? -1 : 1;
|
|
712
|
+
return t ? [
|
|
713
|
+
{ opacity: 0, transform: `perspective(1400px) rotateX(${o * 70}deg)` },
|
|
714
|
+
{ opacity: 1, transform: "perspective(1400px) rotateX(0)" }
|
|
715
|
+
] : [
|
|
716
|
+
{ opacity: 1, transform: "perspective(1400px) rotateX(0)" },
|
|
717
|
+
{ opacity: 0, transform: `perspective(1400px) rotateX(${o * -70}deg)` }
|
|
718
|
+
];
|
|
719
|
+
}
|
|
720
|
+
case "gallery":
|
|
721
|
+
case "conveyor": {
|
|
722
|
+
const o = r.type === "conveyor" ? 25 : 12, s = e.includes("l") ? "-100%" : "100%", c = e.includes("l") ? "100%" : "-100%";
|
|
723
|
+
return t ? [
|
|
724
|
+
{ transform: `perspective(1600px) translateX(${s}) rotateY(${o}deg)` },
|
|
725
|
+
{ transform: "perspective(1600px) translateX(0) rotateY(0)" }
|
|
726
|
+
] : [
|
|
727
|
+
{ transform: "perspective(1600px) translateX(0) rotateY(0)" },
|
|
728
|
+
{ transform: `perspective(1600px) translateX(${c}) rotateY(${-o}deg)` }
|
|
729
|
+
];
|
|
730
|
+
}
|
|
731
|
+
case "pan": {
|
|
732
|
+
const [o, s] = n(), c = (l) => l === "0" ? "0" : `${-parseFloat(l)}%`;
|
|
733
|
+
return t ? [{ transform: a(o, s) }, { transform: "translate(0,0)" }] : [{ transform: "translate(0,0)" }, { transform: a(c(o), c(s)) }];
|
|
734
|
+
}
|
|
735
|
+
case "flythrough":
|
|
736
|
+
return t ? [{ opacity: 0, transform: `perspective(1000px) scale(${e === "out" ? 2.2 : 0.15})` }, { opacity: 1, transform: "none" }] : [{ opacity: 1, transform: "none" }, { opacity: 0, transform: `perspective(1000px) scale(${e === "out" ? 0.15 : 2.2})` }];
|
|
737
|
+
case "warp": {
|
|
738
|
+
const o = e === "out";
|
|
739
|
+
return t ? [{ opacity: 0, transform: o ? "skewX(-18deg) scale(1.35)" : "skewX(18deg) scale(0.65)" }, { opacity: 1, transform: "none" }] : [{ opacity: 1, transform: "none" }, { opacity: 0, transform: o ? "skewX(18deg) scale(0.65)" : "skewX(-18deg) scale(1.35)" }];
|
|
740
|
+
}
|
|
741
|
+
case "blinds":
|
|
742
|
+
case "checker":
|
|
743
|
+
case "randomBar": {
|
|
744
|
+
const o = V(e, !0);
|
|
745
|
+
return t ? [{ opacity: 0.2, clipPath: o }, { opacity: 1, clipPath: V(e, !1) }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
746
|
+
}
|
|
747
|
+
case "comb":
|
|
748
|
+
return t ? [{ opacity: 0, transform: e === "vert" ? "translateY(-100%)" : "translateX(-100%)" }, { opacity: 1, transform: "translate(0,0)" }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
749
|
+
case "strips": {
|
|
750
|
+
const o = {
|
|
751
|
+
lu: "0% 0%",
|
|
752
|
+
ld: "0% 100%",
|
|
753
|
+
ru: "100% 0%",
|
|
754
|
+
rd: "100% 100%"
|
|
755
|
+
}, s = o[e] ?? o.rd;
|
|
756
|
+
return t ? [{ opacity: 0, clipPath: `circle(0% at ${s})` }, { opacity: 1, clipPath: `circle(145% at ${s})` }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
757
|
+
}
|
|
758
|
+
case "newsflash":
|
|
759
|
+
case "dissolve":
|
|
760
|
+
case "fade":
|
|
761
|
+
case "morph":
|
|
762
|
+
default:
|
|
763
|
+
return t ? [{ opacity: 0 }, { opacity: 1 }] : [{ opacity: 1 }, { opacity: 0 }];
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
function Xt(r, t) {
|
|
767
|
+
const e = /* @__PURE__ */ new Map();
|
|
768
|
+
r.querySelectorAll("[data-el]").forEach((n) => {
|
|
769
|
+
const o = n.getBoundingClientRect();
|
|
770
|
+
(o.width > 0 || o.height > 0) && e.set(n.getAttribute("data-el") ?? "", o);
|
|
771
|
+
});
|
|
772
|
+
const a = [];
|
|
773
|
+
return t.querySelectorAll("[data-el]").forEach((n) => {
|
|
774
|
+
const o = e.get(n.getAttribute("data-el") ?? "");
|
|
775
|
+
if (!o) return;
|
|
776
|
+
const s = n.getBoundingClientRect();
|
|
777
|
+
s.width <= 0 && s.height <= 0 || a.push({ node: n, from: o, to: s });
|
|
778
|
+
}), a;
|
|
779
|
+
}
|
|
780
|
+
const G = "http://www.w3.org/2000/svg", dt = ["transform", "transform-origin", "transform-box", "opacity", "clip-path", "filter", "visibility"];
|
|
781
|
+
class Vt {
|
|
782
|
+
constructor(t, e) {
|
|
783
|
+
this.pres = t, this.showComments = e, this.host = document.createElement("div"), this.svg = document.createElementNS(G, "svg"), this.animations = [], this.host.style.cssText = `position:fixed;left:-20000px;top:0;width:${t.width}px;height:${t.height}px;pointer-events:none;contain:layout style;`, this.host.setAttribute("aria-hidden", "true"), this.svg.setAttribute("xmlns", G), this.svg.setAttribute("width", String(t.width)), this.svg.setAttribute("height", String(t.height)), this.svg.setAttribute("viewBox", `0 0 ${t.width} ${t.height}`), this.host.append(this.svg), document.body.append(this.host);
|
|
784
|
+
}
|
|
785
|
+
async page(t, e) {
|
|
786
|
+
const a = await vt(this.pres, t, e, { showComments: this.showComments });
|
|
787
|
+
if (/<image\b[^>]*\bhref="(?:blob:|https?:)/.test(a) || /@font-face\{[^}]*src:url\(['"]?(?:blob:|https?:)/.test(a)) throw new Error("视频资源内联失败");
|
|
788
|
+
const n = new DOMParser().parseFromString(a, "image/svg+xml");
|
|
789
|
+
if (n.querySelector("parsererror")) throw new Error("视频页面 SVG 无效");
|
|
790
|
+
const o = document.createElementNS(G, "g");
|
|
791
|
+
return o.style.transformBox = "fill-box", o.style.transformOrigin = "center", o.append(document.importNode(n.documentElement, !0)), this.svg.append(o), o;
|
|
792
|
+
}
|
|
793
|
+
pause(t) {
|
|
794
|
+
for (const e of t)
|
|
795
|
+
e.pause(), e.currentTime = 0;
|
|
796
|
+
return this.animations.push(...t), [...t];
|
|
797
|
+
}
|
|
798
|
+
group(t, e) {
|
|
799
|
+
return this.pause(Lt(t, e).animations);
|
|
800
|
+
}
|
|
801
|
+
transition(t, e, a) {
|
|
802
|
+
const n = a.transition;
|
|
803
|
+
if (!n || n.type === "none") return [];
|
|
804
|
+
const o = [], s = (c, l) => {
|
|
805
|
+
const f = c.animate(l, { duration: n.durationMs, easing: "ease-in-out", fill: "both" });
|
|
806
|
+
f.finished.catch(() => {
|
|
807
|
+
}), o.push(f);
|
|
808
|
+
};
|
|
809
|
+
if (n.type === "morph") {
|
|
810
|
+
const c = Xt(t, e), l = new Set(c.map((f) => f.node.getAttribute("data-el")));
|
|
811
|
+
for (const { node: f, from: u, to: i } of c) s(f, [{ transformOrigin: "left top", transform: `translate(${u.left - i.left}px,${u.top - i.top}px) scale(${i.width ? u.width / i.width : 1},${i.height ? u.height / i.height : 1})` }, { transformOrigin: "left top", transform: "none" }]);
|
|
812
|
+
for (const f of t.querySelectorAll("[data-el]")) s(f, l.has(f.getAttribute("data-el")) ? [{ opacity: 0 }, { opacity: 0 }] : [{ opacity: 1 }, { opacity: 0 }]);
|
|
813
|
+
for (const f of e.querySelectorAll("[data-el]")) l.has(f.getAttribute("data-el")) || s(f, [{ opacity: 0 }, { opacity: 1 }]);
|
|
814
|
+
} else
|
|
815
|
+
s(t, ht(n, !1)), s(e, ht(n, !0));
|
|
816
|
+
return this.pause(o);
|
|
817
|
+
}
|
|
818
|
+
settle(t) {
|
|
819
|
+
for (const e of t) {
|
|
820
|
+
const a = e.effect, n = a == null ? void 0 : a.target;
|
|
821
|
+
if (a && n) {
|
|
822
|
+
e.currentTime = Number(a.getComputedTiming().endTime);
|
|
823
|
+
const o = getComputedStyle(n);
|
|
824
|
+
for (const s of dt) n.style.setProperty(s, o.getPropertyValue(s));
|
|
825
|
+
}
|
|
826
|
+
e.cancel(), this.animations.splice(this.animations.indexOf(e), 1);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
async draw(t, e, a) {
|
|
830
|
+
const n = this.svg.cloneNode(!0), o = [this.svg, ...this.svg.querySelectorAll("*")], s = [n, ...n.querySelectorAll("*")], c = new Set(this.animations.map((f) => {
|
|
831
|
+
var u;
|
|
832
|
+
return (u = f.effect) == null ? void 0 : u.target;
|
|
833
|
+
}));
|
|
834
|
+
for (let f = 0; f < o.length; f++) if (c.has(o[f])) {
|
|
835
|
+
const u = getComputedStyle(o[f]);
|
|
836
|
+
for (const i of dt) s[f].style.setProperty(i, u.getPropertyValue(i));
|
|
837
|
+
}
|
|
838
|
+
const l = new Image();
|
|
839
|
+
l.decoding = "sync", await new Promise((f, u) => {
|
|
840
|
+
l.onload = () => f(), l.onerror = () => u(new Error("视频帧 SVG 渲染失败")), l.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(new XMLSerializer().serializeToString(n))}`;
|
|
841
|
+
}), t.fillStyle = "#fff", t.fillRect(0, 0, e, a), t.drawImage(l, 0, 0, e, a);
|
|
842
|
+
}
|
|
843
|
+
dispose() {
|
|
844
|
+
for (const t of this.animations) t.cancel();
|
|
845
|
+
this.animations.length = 0, this.host.remove();
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
const gt = (r) => new TextEncoder().encode(r);
|
|
849
|
+
function at(r, t = Math.max(1, Math.ceil(Math.log2(r + 1) / 8))) {
|
|
850
|
+
const e = new Uint8Array(t);
|
|
851
|
+
for (let a = t - 1; a >= 0; a--)
|
|
852
|
+
e[a] = r % 256, r = Math.floor(r / 256);
|
|
853
|
+
return e;
|
|
854
|
+
}
|
|
855
|
+
function zt(r) {
|
|
856
|
+
const t = new Uint8Array(r.reduce((a, n) => a + n.length, 0));
|
|
857
|
+
let e = 0;
|
|
858
|
+
for (const a of r)
|
|
859
|
+
t.set(a, e), e += a.length;
|
|
860
|
+
return t;
|
|
861
|
+
}
|
|
862
|
+
function $(r, ...t) {
|
|
863
|
+
const e = t.reduce((o, s) => o + s.length, 0);
|
|
864
|
+
let a = 1;
|
|
865
|
+
for (; e >= 2 ** (7 * a) - 1; ) a++;
|
|
866
|
+
const n = at(e, a);
|
|
867
|
+
return n[0] |= 1 << 8 - a, zt([at(r), n, ...t]);
|
|
868
|
+
}
|
|
869
|
+
const k = (r, t) => $(r, at(t)), D = (r, t) => $(r, gt(t));
|
|
870
|
+
function mt(r, t) {
|
|
871
|
+
const e = new Uint8Array(8);
|
|
872
|
+
return new DataView(e.buffer).setFloat64(0, t), $(r, e);
|
|
873
|
+
}
|
|
874
|
+
class Bt {
|
|
875
|
+
constructor(t, e, a, n, o) {
|
|
876
|
+
if (this.width = t, this.height = e, this.fps = a, this.codec = n, this.audio = o, this.clusters = [], this.last = -1, this.audioLast = -1, this.audioBlocks = 0, this.duration = 0, this.length = 0, this.closed = !1, ![t, e, a].every((s) => Number.isInteger(s) && s > 0) || t * e > 8388608 || a > 60) throw new Error("WebM 视频尺寸或帧率无效");
|
|
877
|
+
if (o && (!Number.isInteger(o.sampleRate) || o.sampleRate <= 0)) throw new Error("WebM 音频采样率无效");
|
|
878
|
+
}
|
|
879
|
+
clusterFor(t, e) {
|
|
880
|
+
let a = this.clusters[this.clusters.length - 1];
|
|
881
|
+
return (!a || t - a.time > 32767 || e && t - a.time >= 1e3 || t - a.time >= 3e4) && (a = { time: t, blocks: [], key: e }, this.clusters.push(a)), a;
|
|
882
|
+
}
|
|
883
|
+
addFrame(t, e, a, n) {
|
|
884
|
+
if (this.closed) throw new Error("WebM 已结束");
|
|
885
|
+
if (!Number.isSafeInteger(e) || e <= this.last || e < 0 || !Number.isSafeInteger(a) || a <= 0) throw new Error("WebM 帧时间必须严格递增");
|
|
886
|
+
if (!t.length || t.length > 32 * 1024 * 1024 || this.length + t.length > 256 * 1024 * 1024) throw new Error("WebM 视频超过导出大小限制");
|
|
887
|
+
if (!this.clusters.length && !n) throw new Error("WebM 第一帧必须是关键帧");
|
|
888
|
+
const o = Math.round(e / 1e3), s = this.clusterFor(o, n), c = new Uint8Array(4);
|
|
889
|
+
c[0] = 129, new DataView(c.buffer).setInt16(1, o - s.time), c[3] = n ? 128 : 0, s.blocks.push($(163, c, t)), this.length += t.length, this.last = e, this.duration = (e + a) / 1e3;
|
|
890
|
+
}
|
|
891
|
+
/** Opus 音频块:时间戳毫秒、流内严格递增;与视频块按簇交错 */
|
|
892
|
+
addAudio(t, e) {
|
|
893
|
+
if (this.closed) throw new Error("WebM 已结束");
|
|
894
|
+
if (!this.audio) throw new Error("WebM 未声明音频轨");
|
|
895
|
+
if (!Number.isSafeInteger(e) || e < 0 || e <= this.audioLast) throw new Error("WebM 音频时间必须严格递增");
|
|
896
|
+
if (!t.length || t.length > 1024 * 1024) throw new Error("WebM 音频块为空或超限");
|
|
897
|
+
const a = Math.round(e), n = this.clusterFor(a, !1), o = new Uint8Array(4);
|
|
898
|
+
o[0] = 130, new DataView(o.buffer).setInt16(1, Math.max(0, a - n.time)), n.blocks.push($(163, o, t)), this.audioBlocks++, this.audioLast = e, this.length += t.length;
|
|
899
|
+
}
|
|
900
|
+
finish() {
|
|
901
|
+
if (this.closed) throw new Error("WebM 已结束");
|
|
902
|
+
if (!this.clusters.length) throw new Error("没有可导出的视频帧");
|
|
903
|
+
if (this.audio && !this.audioBlocks) throw new Error("声明了音频轨但没有音频块");
|
|
904
|
+
this.closed = !0;
|
|
905
|
+
const t = $(440786851, k(17030, 1), k(17143, 1), k(17138, 4), k(17139, 8), D(17026, "webm"), k(17031, 4), k(17029, 2)), e = $(357149030, k(2807729, 1e6), mt(17545, this.duration), D(19840, "Web-PPT"), D(22337, "Web-PPT")), n = [$(174, k(215, 1), k(29637, 1), k(131, 1), k(156, 0), D(134, `V_${this.codec}`), k(2352003, Math.round(1e9 / this.fps)), $(224, k(176, this.width), k(186, this.height)))];
|
|
906
|
+
if (this.audio) {
|
|
907
|
+
const u = new Uint8Array(19);
|
|
908
|
+
u.set(gt("OpusHead"), 0), u[8] = 1, u[9] = this.audio.channels, new DataView(u.buffer).setUint16(10, 312, !0), new DataView(u.buffer).setUint32(12, this.audio.sampleRate, !0), n.push($(
|
|
909
|
+
174,
|
|
910
|
+
k(215, 2),
|
|
911
|
+
k(29637, 2),
|
|
912
|
+
k(131, 2),
|
|
913
|
+
k(156, 0),
|
|
914
|
+
D(134, "A_OPUS"),
|
|
915
|
+
$(25506, u),
|
|
916
|
+
$(225, mt(181, this.audio.sampleRate), k(159, this.audio.channels))
|
|
917
|
+
));
|
|
918
|
+
}
|
|
919
|
+
const o = $(374648427, ...n), s = [], c = [];
|
|
920
|
+
let l = e.length + o.length;
|
|
921
|
+
for (const u of this.clusters) {
|
|
922
|
+
const i = $(524531317, k(231, u.time), ...u.blocks);
|
|
923
|
+
u.key && c.push($(187, k(179, u.time), $(183, k(247, 1), k(241, l)))), s.push(i), l += i.length;
|
|
924
|
+
}
|
|
925
|
+
const f = $(408125543, e, o, ...s, $(475249515, ...c));
|
|
926
|
+
return this.clusters.length = 0, new Blob([t.buffer, f.buffer], { type: "video/webm" });
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
function _(r) {
|
|
930
|
+
let t = 0, e = 0, a = 0;
|
|
931
|
+
for (const n of r) {
|
|
932
|
+
if (![n.delayMs, n.durationMs].every((o) => Number.isFinite(o) && o >= 0 && o <= 36e5)) throw new Error("视频动画时长无效");
|
|
933
|
+
t = (n.trigger === "afterPrev" ? e : n.trigger === "withPrev" ? t : 0) + n.delayMs, e = t + n.durationMs, a = Math.max(a, e);
|
|
934
|
+
}
|
|
935
|
+
return a;
|
|
936
|
+
}
|
|
937
|
+
function Dt(r, t) {
|
|
938
|
+
const e = t.fps ?? 24, a = t.scale ?? 1, n = t.slideDurationMs ?? 3e3, o = t.clickDelayMs ?? 700;
|
|
939
|
+
if (!Number.isInteger(e) || e < 1 || e > 60 || !Number.isFinite(a) || a <= 0 || ![n, o].every((h) => Number.isFinite(h) && h >= 0 && h <= 36e5)) throw new Error("视频帧率、倍率或停留时长无效");
|
|
940
|
+
const s = Math.round(r.width * a), c = Math.round(r.height * a);
|
|
941
|
+
if (![s, c].every((h) => Number.isFinite(h) && h > 0 && h <= 4096) || s * c > 8388608) throw new Error("视频尺寸需要在 4096 边长、800 万像素以内");
|
|
942
|
+
const l = t.bitrate ?? Math.max(1e6, s * c * e * 0.15);
|
|
943
|
+
if (!Number.isFinite(l) || l < 1e4 || l > 1e8) throw new Error("视频码率无效");
|
|
944
|
+
const f = (h) => Math.max(1, Math.ceil(h * e / 1e3)), u = r.slides.flatMap((h, d) => {
|
|
945
|
+
var A, I, g;
|
|
946
|
+
if (t.skipHidden && h.hidden) return [];
|
|
947
|
+
const w = t.animations === !1 ? [] : Mt(h.animations), v = t.transitions !== !1 && ((A = h.transition) == null ? void 0 : A.type) !== "none" ? ((I = h.transition) == null ? void 0 : I.durationMs) ?? 0 : 0, E = ((g = h.transition) == null ? void 0 : g.advanceAfterMs) ?? n;
|
|
948
|
+
if (![E, v].every((m) => Number.isFinite(m) && m >= 0 && m <= 36e5)) throw new Error("视频页面时长无效");
|
|
949
|
+
return [{ slide: h, slideNumber: d + 1, groups: w, transition: v, hold: E, click: o }];
|
|
950
|
+
}), i = u.reduce((h, d, w) => h + (w && d.transition ? f(d.transition) : 0) + f(d.hold) + d.groups.reduce((v, E) => v + (o ? f(o) : 0) + f(_(E)), 0), 0);
|
|
951
|
+
if (!u.length) throw new Error("没有可导出的视频页面");
|
|
952
|
+
if (i / e > 3600 || i > 108e3) throw new Error("视频不能超过一小时或 108000 帧");
|
|
953
|
+
return { width: s, height: c, fps: e, bitrate: Math.round(l), pages: u, total: i, frames: f };
|
|
954
|
+
}
|
|
955
|
+
function _t(r, t, e) {
|
|
956
|
+
const a = r.samples.length / r.channels;
|
|
957
|
+
if (!Number.isInteger(a)) return null;
|
|
958
|
+
let n = t;
|
|
959
|
+
if (r.loop) n %= a;
|
|
960
|
+
else if (t < 0 || t >= a) return null;
|
|
961
|
+
const o = Math.floor(n), s = n - o, c = Math.min(o + 1, a - 1), l = r.samples[o * r.channels + e], f = r.samples[c * r.channels + e];
|
|
962
|
+
return l + (f - l) * s;
|
|
963
|
+
}
|
|
964
|
+
function qt(r, t, e = {}) {
|
|
965
|
+
const a = e.sampleRate ?? 48e3, n = e.channels ?? 2;
|
|
966
|
+
if (!Number.isFinite(t) || t < 0) throw new Error("混音总时长必须是非负毫秒");
|
|
967
|
+
if (!Number.isInteger(a) || a <= 0) throw new Error("输出采样率必须是正整数");
|
|
968
|
+
if (r.some((l) => !Number.isInteger(l.sampleRate) || l.sampleRate <= 0)) throw new Error("片段采样率必须是正整数");
|
|
969
|
+
if (r.some((l) => l.channels !== 1 && l.channels !== 2)) throw new Error("片段声道数只支持单声道或立体声");
|
|
970
|
+
if (r.some((l) => !Number.isFinite(l.startMs) || l.startMs < 0)) throw new Error("片段起始时间必须是非负毫秒");
|
|
971
|
+
if (r.some((l) => l.samples.length % l.channels !== 0)) throw new Error("片段样本长度必须是声道数的整数倍");
|
|
972
|
+
const o = r.map((l) => l.volume ?? 1);
|
|
973
|
+
if (o.some((l) => !Number.isFinite(l) || l < 0 || l > 1)) throw new Error("片段音量必须在 [0,1]");
|
|
974
|
+
const s = Math.ceil(t / 1e3 * a), c = new Float32Array(s * n);
|
|
975
|
+
for (const [l, f] of r.entries()) {
|
|
976
|
+
if (f.endMs !== void 0 && f.endMs < f.startMs) throw new Error("片段截止时间早于起始时间");
|
|
977
|
+
const u = f.endMs ?? Number.POSITIVE_INFINITY, i = Math.floor(f.startMs / 1e3 * a);
|
|
978
|
+
for (let h = Math.max(i, 0); h < s && !(h / a * 1e3 >= u); h++) {
|
|
979
|
+
const d = (h - f.startMs / 1e3 * a) * f.sampleRate / a;
|
|
980
|
+
for (let w = 0; w < n; w++) {
|
|
981
|
+
const v = _t(f, d, f.channels === 1 ? 0 : w);
|
|
982
|
+
v !== null && (c[h * n + w] += v * o[l]);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
for (let l = 0; l < c.length; l++) c[l] = Math.max(-1, Math.min(1, c[l]));
|
|
987
|
+
return c;
|
|
988
|
+
}
|
|
989
|
+
const Ut = 5e3, jt = 500, Ht = (r) => new Promise((t) => {
|
|
990
|
+
const e = (s) => {
|
|
991
|
+
clearTimeout(o), r.removeEventListener("loadeddata", a), r.removeEventListener("error", n), t(s && Number.isFinite(r.duration));
|
|
992
|
+
}, a = () => e(!0), n = () => e(!1), o = setTimeout(n, Ut);
|
|
993
|
+
r.addEventListener("loadeddata", a), r.addEventListener("error", n), r.readyState >= 2 && e(!0);
|
|
994
|
+
}), Gt = (r, t) => new Promise((e) => {
|
|
995
|
+
const a = (s) => {
|
|
996
|
+
clearTimeout(o), r.removeEventListener("seeked", n), e(s);
|
|
997
|
+
}, n = () => a(!0), o = setTimeout(() => a(!1), jt);
|
|
998
|
+
r.addEventListener("seeked", n), r.currentTime = t;
|
|
999
|
+
}), K = (r) => {
|
|
1000
|
+
r.removeAttribute("src"), r.load();
|
|
1001
|
+
};
|
|
1002
|
+
class Kt {
|
|
1003
|
+
constructor(t) {
|
|
1004
|
+
this.warn = t, this.videos = /* @__PURE__ */ new Map(), this.disposed = !1;
|
|
1005
|
+
}
|
|
1006
|
+
/** 预加载页面的视频媒体(每页一个列表;须在导出循环前调用) */
|
|
1007
|
+
async load(t, e, a, n) {
|
|
1008
|
+
const o = [], s = (f) => {
|
|
1009
|
+
for (const u of f)
|
|
1010
|
+
if (u.kind === "image" && u.media && u.media.kind === "video" && u.media.src) {
|
|
1011
|
+
const i = u.media.playback;
|
|
1012
|
+
if (!i) continue;
|
|
1013
|
+
const h = n.length ? n[Math.min(i.clickGroup, n.length - 1)] : 0, d = document.createElement("video");
|
|
1014
|
+
d.muted = !0, d.preload = "auto", d.playsInline = !0, d.src = u.media.src, o.push({ el: d, x: u.x, y: u.y, w: u.w, h: u.h, startMs: h, name: u.name ?? "", frameWarned: !1 });
|
|
1015
|
+
} else u.kind === "group" && s(u.children);
|
|
1016
|
+
};
|
|
1017
|
+
if (s(e.elements), !o.length) return;
|
|
1018
|
+
const c = await Promise.all(o.map((f) => Ht(f.el)));
|
|
1019
|
+
if (this.disposed) {
|
|
1020
|
+
for (const f of o) K(f.el);
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
const l = o.filter((f, u) => {
|
|
1024
|
+
var i;
|
|
1025
|
+
return c[u] ? !0 : (K(f.el), (i = this.warn) == null || i.call(this, "video-overlay-unavailable", { slideNumber: a, elementName: f.name }), !1);
|
|
1026
|
+
});
|
|
1027
|
+
this.videos.set(a, l);
|
|
1028
|
+
}
|
|
1029
|
+
/**
|
|
1030
|
+
* 把当前时间轴的视频帧画到画布。在 SVG 光栅化之后调用,叠加在海报帧之上。
|
|
1031
|
+
* scaleX/scaleY 把幻灯片坐标换算到导出画布坐标。
|
|
1032
|
+
*/
|
|
1033
|
+
async draw(t, e, a, n, o) {
|
|
1034
|
+
var c;
|
|
1035
|
+
const s = this.videos.get(e);
|
|
1036
|
+
if (s)
|
|
1037
|
+
for (const l of s) {
|
|
1038
|
+
const f = (a - l.startMs) / 1e3;
|
|
1039
|
+
if (f < 0) continue;
|
|
1040
|
+
const u = Math.min(f, l.el.duration);
|
|
1041
|
+
(!(Math.abs(l.el.currentTime - u) <= 1 / 30 || await Gt(l.el, u)) || l.el.readyState < 2) && (l.frameWarned || (l.frameWarned = !0, (c = this.warn) == null || c.call(this, "video-overlay-frame-unavailable", { slideNumber: e, elementName: l.name })), l.el.readyState < 2) || t.drawImage(l.el, l.x * n, l.y * o, l.w * n, l.h * o);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
dispose() {
|
|
1045
|
+
this.disposed = !0;
|
|
1046
|
+
for (const t of this.videos.values()) for (const e of t) K(e.el);
|
|
1047
|
+
this.videos.clear();
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
const pt = (r) => {
|
|
1051
|
+
const t = [], e = (a) => {
|
|
1052
|
+
for (const n of a)
|
|
1053
|
+
n.kind === "image" && n.media && n.media.playback && n.media.src ? t.push(n) : n.kind === "group" && e(n.children);
|
|
1054
|
+
};
|
|
1055
|
+
return e(r), t;
|
|
1056
|
+
};
|
|
1057
|
+
async function Qt(r, t) {
|
|
1058
|
+
const e = await fetch(r, { signal: t });
|
|
1059
|
+
if (!e.ok) throw new Error(`音频媒体读取失败:HTTP ${e.status}`);
|
|
1060
|
+
const a = await e.arrayBuffer(), n = globalThis.OfflineAudioContext;
|
|
1061
|
+
if (!n) throw new Error("当前浏览器不支持音频解码(OfflineAudioContext 缺失)");
|
|
1062
|
+
const o = await new n(1, 1, 48e3).decodeAudioData(a), s = new Float32Array(o.length * o.numberOfChannels);
|
|
1063
|
+
for (let c = 0; c < o.numberOfChannels; c++)
|
|
1064
|
+
s.set(o.getChannelData(c), c * o.length);
|
|
1065
|
+
return { samples: s, sampleRate: o.sampleRate, channels: Math.min(2, o.numberOfChannels) };
|
|
1066
|
+
}
|
|
1067
|
+
async function Zt(r, t, e, a, n) {
|
|
1068
|
+
const o = { codec: "opus", sampleRate: e, numberOfChannels: a, bitrate: 96e3 };
|
|
1069
|
+
if (typeof AudioEncoder > "u" || typeof AudioData > "u" || !(await AudioEncoder.isConfigSupported(o)).supported) throw new Error("当前浏览器不支持 Opus 音频编码");
|
|
1070
|
+
let s;
|
|
1071
|
+
const c = new AudioEncoder({ output: (f) => {
|
|
1072
|
+
try {
|
|
1073
|
+
const u = new Uint8Array(f.byteLength);
|
|
1074
|
+
f.copyTo(u), r.addAudio(u, Math.round(f.timestamp / 1e3));
|
|
1075
|
+
} catch (u) {
|
|
1076
|
+
s = u;
|
|
1077
|
+
}
|
|
1078
|
+
}, error: (f) => {
|
|
1079
|
+
s = f;
|
|
1080
|
+
} }), l = () => {
|
|
1081
|
+
c.state !== "closed" && c.close();
|
|
1082
|
+
};
|
|
1083
|
+
n == null || n.addEventListener("abort", l, { once: !0 });
|
|
1084
|
+
try {
|
|
1085
|
+
c.configure(o);
|
|
1086
|
+
const f = Math.round(e * 0.02);
|
|
1087
|
+
for (let u = 0; u * a < t.length; u += f) {
|
|
1088
|
+
if (n != null && n.aborted) throw new DOMException("视频导出已取消", "AbortError");
|
|
1089
|
+
if (s) throw s;
|
|
1090
|
+
const i = Math.min(f, Math.floor(t.length / a) - u);
|
|
1091
|
+
if (i <= 0) break;
|
|
1092
|
+
const h = new AudioData({
|
|
1093
|
+
format: "f32",
|
|
1094
|
+
sampleRate: e,
|
|
1095
|
+
numberOfFrames: i,
|
|
1096
|
+
numberOfChannels: a,
|
|
1097
|
+
timestamp: Math.round(u / e * 1e6),
|
|
1098
|
+
data: new Float32Array(t.subarray(u * a, (u + i) * a))
|
|
1099
|
+
});
|
|
1100
|
+
try {
|
|
1101
|
+
c.encode(h);
|
|
1102
|
+
} finally {
|
|
1103
|
+
h.close();
|
|
1104
|
+
}
|
|
1105
|
+
c.encodeQueueSize >= 16 && await new Promise((d) => {
|
|
1106
|
+
const w = () => {
|
|
1107
|
+
(c.encodeQueueSize < 16 || s) && (c.removeEventListener("dequeue", w), d());
|
|
1108
|
+
};
|
|
1109
|
+
c.addEventListener("dequeue", w), w();
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
if (await c.flush(), s) throw s;
|
|
1113
|
+
} finally {
|
|
1114
|
+
n == null || n.removeEventListener("abort", l), l();
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
async function te(r, t = {}) {
|
|
1118
|
+
var m, R, N;
|
|
1119
|
+
const e = Dt(r, t), a = () => {
|
|
1120
|
+
var p;
|
|
1121
|
+
if ((p = t.signal) != null && p.aborted) throw new DOMException("视频导出已取消", "AbortError");
|
|
1122
|
+
};
|
|
1123
|
+
if (a(), typeof VideoEncoder > "u" || typeof VideoFrame > "u" || typeof document > "u") throw new Error("当前浏览器不支持 WebCodecs 视频编码,请使用支持的 HTTPS 或本机浏览器");
|
|
1124
|
+
const n = (p) => p.some((b) => b.kind === "image" && !!b.media || b.kind === "group" && n(b.children));
|
|
1125
|
+
if (!t.mediaPosters && e.pages.some((p) => n(p.slide.elements))) throw new Error("文稿含内嵌音视频,导出时可能以静态封面呈现(含 audio / videoOverlay 未覆盖或失败的媒体);请设置 mediaPosters: true 显式允许");
|
|
1126
|
+
let o, s = "VP9";
|
|
1127
|
+
for (const p of ["vp09.00.10.08", "vp8"]) {
|
|
1128
|
+
const b = { codec: p, width: e.width, height: e.height, framerate: e.fps, bitrate: e.bitrate, latencyMode: "realtime" };
|
|
1129
|
+
if ((await VideoEncoder.isConfigSupported(b)).supported) {
|
|
1130
|
+
o = b, s = p === "vp8" ? "VP8" : "VP9";
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
if (!o) throw new Error("当前浏览器没有支持此尺寸的 VP8/VP9 视频编码器");
|
|
1135
|
+
a();
|
|
1136
|
+
const c = !!t.audio && e.pages.some((p) => pt(p.slide.elements).length > 0), l = new Bt(e.width, e.height, e.fps, s, c ? { sampleRate: 48e3, channels: 2 } : void 0);
|
|
1137
|
+
let f, u = 0;
|
|
1138
|
+
const i = new VideoEncoder({
|
|
1139
|
+
output: (p) => {
|
|
1140
|
+
try {
|
|
1141
|
+
const b = new Uint8Array(p.byteLength);
|
|
1142
|
+
p.copyTo(b), l.addFrame(b, p.timestamp, p.duration ?? Math.round(1e6 / e.fps), p.type === "key");
|
|
1143
|
+
} catch (b) {
|
|
1144
|
+
f = b;
|
|
1145
|
+
}
|
|
1146
|
+
},
|
|
1147
|
+
error: (p) => {
|
|
1148
|
+
f = p;
|
|
1149
|
+
}
|
|
1150
|
+
}), h = document.createElement("canvas");
|
|
1151
|
+
h.width = e.width, h.height = e.height;
|
|
1152
|
+
const d = h.getContext("2d");
|
|
1153
|
+
if (!d)
|
|
1154
|
+
throw i.close(), new Error("无法获取视频画布");
|
|
1155
|
+
const w = new Vt(r, !!t.showComments), v = t.videoOverlay ? new Kt(t.onWarning) : null, E = () => {
|
|
1156
|
+
i.state !== "closed" && i.close();
|
|
1157
|
+
};
|
|
1158
|
+
(m = t.signal) == null || m.addEventListener("abort", E, { once: !0 });
|
|
1159
|
+
const A = () => {
|
|
1160
|
+
if (a(), f) throw f;
|
|
1161
|
+
}, I = async () => {
|
|
1162
|
+
i.encodeQueueSize < 8 || (await new Promise((p, b) => {
|
|
1163
|
+
var T;
|
|
1164
|
+
const P = () => {
|
|
1165
|
+
var F;
|
|
1166
|
+
clearTimeout(W), i.removeEventListener("dequeue", y), (F = t.signal) == null || F.removeEventListener("abort", Y);
|
|
1167
|
+
}, y = () => {
|
|
1168
|
+
(i.encodeQueueSize < 8 || f) && (P(), p());
|
|
1169
|
+
}, Y = () => {
|
|
1170
|
+
P(), b(new DOMException("视频导出已取消", "AbortError"));
|
|
1171
|
+
}, W = setTimeout(() => {
|
|
1172
|
+
P(), b(new Error("视频编码器等待超时"));
|
|
1173
|
+
}, 3e4);
|
|
1174
|
+
i.addEventListener("dequeue", y), (T = t.signal) == null || T.addEventListener("abort", Y, { once: !0 }), y();
|
|
1175
|
+
}), A());
|
|
1176
|
+
}, g = async (p, b, P = [], y) => {
|
|
1177
|
+
var W;
|
|
1178
|
+
const Y = e.frames(p);
|
|
1179
|
+
for (let T = 0; T < Y; T++) {
|
|
1180
|
+
A();
|
|
1181
|
+
for (const L of P) L.currentTime = p * T / Y;
|
|
1182
|
+
await w.draw(d, e.width, e.height), A(), v && await v.draw(d, b, (y ?? 0) + p * T / Y, e.width / r.width, e.height / r.height), await I();
|
|
1183
|
+
const F = Math.round(u * 1e6 / e.fps), O = Math.round((u + 1) * 1e6 / e.fps), S = new VideoFrame(h, { timestamp: F, duration: O - F });
|
|
1184
|
+
try {
|
|
1185
|
+
i.encode(S, { keyFrame: u % (e.fps * 2) === 0 });
|
|
1186
|
+
} finally {
|
|
1187
|
+
S.close();
|
|
1188
|
+
}
|
|
1189
|
+
u++, (W = t.onProgress) == null || W.call(t, { completed: u, total: e.total, slideNumber: b });
|
|
1190
|
+
}
|
|
1191
|
+
w.settle(P), await Promise.resolve();
|
|
1192
|
+
};
|
|
1193
|
+
try {
|
|
1194
|
+
const p = [];
|
|
1195
|
+
i.configure(o);
|
|
1196
|
+
let b, P = 0;
|
|
1197
|
+
for (const y of e.pages) {
|
|
1198
|
+
A();
|
|
1199
|
+
const Y = y.groups.length ? kt(y.groups, 0) : xt(y.slide), W = b && y.transition ? y.transition : 0, T = await w.page(y.slide, [...Y]);
|
|
1200
|
+
A();
|
|
1201
|
+
const F = [];
|
|
1202
|
+
{
|
|
1203
|
+
let S = P + W;
|
|
1204
|
+
for (const L of y.groups)
|
|
1205
|
+
F.push(S), S += (y.click ?? 0) + _(L);
|
|
1206
|
+
}
|
|
1207
|
+
v && await v.load(r, y.slide, y.slideNumber, F);
|
|
1208
|
+
let O = P;
|
|
1209
|
+
if (W && (await g(y.transition, y.slideNumber, w.transition(b, T, y.slide), O), O += W), b == null || b.remove(), t.audio)
|
|
1210
|
+
for (const S of pt(y.slide.elements)) {
|
|
1211
|
+
const L = S.media.playback, it = F.length ? F[Math.min(L.clickGroup, F.length - 1)] : P + W;
|
|
1212
|
+
let B;
|
|
1213
|
+
try {
|
|
1214
|
+
B = await Qt(S.media.src, t.signal);
|
|
1215
|
+
} catch (j) {
|
|
1216
|
+
if (!(j instanceof DOMException && j.name === "AbortError") && S.media.kind === "video") {
|
|
1217
|
+
(R = t.onWarning) == null || R.call(t, "video-audio-decode-failed", { slideNumber: y.slideNumber, elementName: S.name ?? "" });
|
|
1218
|
+
continue;
|
|
1219
|
+
}
|
|
1220
|
+
throw j;
|
|
1221
|
+
}
|
|
1222
|
+
A(), p.push({
|
|
1223
|
+
samples: B.samples,
|
|
1224
|
+
sampleRate: B.sampleRate,
|
|
1225
|
+
channels: B.channels,
|
|
1226
|
+
startMs: it,
|
|
1227
|
+
loop: L.loop,
|
|
1228
|
+
volume: L.volume,
|
|
1229
|
+
endMs: L.loop ? void 0 : it + B.samples.length / B.channels / B.sampleRate * 1e3
|
|
1230
|
+
});
|
|
1231
|
+
}
|
|
1232
|
+
for (const S of y.groups)
|
|
1233
|
+
y.click && (await g(y.click, y.slideNumber, void 0, O), O += y.click), await g(_(S), y.slideNumber, w.group(T, S), O), O += _(S);
|
|
1234
|
+
await g(y.hold, y.slideNumber, void 0, O), O += y.hold, P = O, b = T;
|
|
1235
|
+
}
|
|
1236
|
+
if (await i.flush(), A(), t.audio && p.length) {
|
|
1237
|
+
const y = Math.round(u / e.fps * 1e3), Y = qt(p, y, { sampleRate: 48e3, channels: 2 });
|
|
1238
|
+
await Zt(l, Y, 48e3, 2, t.signal);
|
|
1239
|
+
}
|
|
1240
|
+
return l.finish();
|
|
1241
|
+
} finally {
|
|
1242
|
+
(N = t.signal) == null || N.removeEventListener("abort", E), E(), v == null || v.dispose(), w.dispose(), h.width = h.height = 0;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
export {
|
|
1246
|
+
te as presentationToVideo,
|
|
1247
|
+
Dt as videoPlan
|
|
1248
|
+
};
|