@vectoriox/iox-ui 5.75.3 → 5.76.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/vectoriox-iox-ui-media-core.mjs +148 -107
- package/fesm2022/vectoriox-iox-ui-media-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs +10 -8
- package/fesm2022/vectoriox-iox-ui-scene-core.mjs.map +1 -1
- package/media-core/index.d.ts +36 -42
- package/package.json +1 -1
- package/src/media-core/frames.ts +145 -121
- package/src/scene-core/scroll-driver.ts +10 -8
|
@@ -86,22 +86,6 @@ function framePosition(played, count) {
|
|
|
86
86
|
}
|
|
87
87
|
/** On a Video whose pictures are drawing: the poster has done its job and steps aside. */
|
|
88
88
|
const FRAMES_SHOWING_ATTRIBUTE = 'data-iox-frames-showing';
|
|
89
|
-
/**
|
|
90
|
-
* Below this many pictures a second the film stops following the scroll exactly and lands on its own. A landing scroll
|
|
91
|
-
* slows exponentially, so the last picture or two would take most of a second as one slow dissolve between two places:
|
|
92
|
-
* the subject showing twice, and then settling. Landing at least this fast keeps the end of the move a move.
|
|
93
|
-
*/
|
|
94
|
-
const FILM_LANDING_SPEED = 10;
|
|
95
|
-
/** With no word from the driver on where the scroll is going, how fast a landing scroll is assumed to slow (per second). */
|
|
96
|
-
const FILM_LANDING_DECAY = 5;
|
|
97
|
-
/** How quickly the film catches up with a scroll that turned back while it was landing ahead of it (per second). */
|
|
98
|
-
const FILM_CATCH_RATE = 25;
|
|
99
|
-
/** How quickly the film's reading of the scroll's speed follows it (per second). */
|
|
100
|
-
const FILM_SPEED_RATE = 30;
|
|
101
|
-
/** A step this short is the same frame asked twice: it moves nothing and reads no speed. */
|
|
102
|
-
const FILM_SAME_FRAME_SECONDS = 0.002;
|
|
103
|
-
const FILM_MAX_STEP_SECONDS = 0.1;
|
|
104
|
-
const FILM_EPSILON = 1e-6;
|
|
105
89
|
/** How finely two neighbours mix. Finer than the eye reads, and a scroll that moves less than a step draws nothing. */
|
|
106
90
|
const FRAME_BLEND_STEPS = 32;
|
|
107
91
|
/**
|
|
@@ -118,45 +102,6 @@ function frameBlendAt(loaded, position) {
|
|
|
118
102
|
const nearest = nearestLoadedFrame(loaded, Math.round(position));
|
|
119
103
|
return nearest < 0 ? null : { from: nearest, to: nearest, mix: 0 };
|
|
120
104
|
}
|
|
121
|
-
/** Where a film stands before its first step: on the moment asked for, still. */
|
|
122
|
-
function filmAt(wanted) {
|
|
123
|
-
return { position: wanted, wanted, speed: 0, direction: 1 };
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* One step of the film. Moving fast, it stands exactly where the scroll asks. Landing (slower than FILM_LANDING_SPEED
|
|
127
|
-
* pictures a second) it runs on at that speed to the whole picture nearest where the scroll will stop, and stands there:
|
|
128
|
-
* it never crawls through a dissolve, never stops between two pictures, and never steps back over a picture it reached
|
|
129
|
-
* unless the scroll turns. `aim` is where the scroll is heading, when the driver knows it (its undamped target); without it, it is guessed.
|
|
130
|
-
*/
|
|
131
|
-
function stepFilm(motion, wanted, seconds, last, aim) {
|
|
132
|
-
const sameFrame = seconds < FILM_SAME_FRAME_SECONDS;
|
|
133
|
-
const step = Math.min(FILM_MAX_STEP_SECONDS, seconds);
|
|
134
|
-
const moved = wanted - motion.wanted;
|
|
135
|
-
const speed = sameFrame ? motion.speed : motion.speed + (moved / step - motion.speed) * (1 - Math.exp(-FILM_SPEED_RATE * step));
|
|
136
|
-
const heading = aim === undefined ? moved : aim - wanted;
|
|
137
|
-
const direction = Math.abs(heading) > FILM_EPSILON ? (heading > 0 ? 1 : -1) : Math.abs(moved) > FILM_EPSILON ? (moved > 0 ? 1 : -1) : motion.direction;
|
|
138
|
-
// Moving: with the scroll, but never back over a picture a landing already reached unless the scroll turned.
|
|
139
|
-
if (Math.abs(speed) >= FILM_LANDING_SPEED) {
|
|
140
|
-
const position = direction > 0 ? Math.max(wanted, Math.min(motion.position, Math.ceil(wanted))) : Math.min(wanted, Math.max(motion.position, Math.floor(wanted)));
|
|
141
|
-
return { position, wanted, speed, direction };
|
|
142
|
-
}
|
|
143
|
-
if (sameFrame)
|
|
144
|
-
return { ...motion, wanted, direction };
|
|
145
|
-
const clamp = (value) => Math.min(last, Math.max(0, value));
|
|
146
|
-
const stop = aim ?? wanted + speed / FILM_LANDING_DECAY;
|
|
147
|
-
// The picture nearest the stop, unless reaching it would show a step back: then the next whole one on the way.
|
|
148
|
-
const nearest = Math.round(stop);
|
|
149
|
-
const back = (motion.position - nearest) * direction > 1 / FRAME_BLEND_STEPS;
|
|
150
|
-
const goal = clamp(back ? (direction > 0 ? Math.ceil(motion.position) : Math.floor(motion.position)) : nearest);
|
|
151
|
-
const behind = (wanted - motion.position) * direction;
|
|
152
|
-
const reach = Math.max(FILM_LANDING_SPEED * step, behind > 0 ? behind * (1 - Math.exp(-FILM_CATCH_RATE * step)) : 0);
|
|
153
|
-
const position = direction > 0 ? Math.min(goal, motion.position + reach) : Math.max(goal, motion.position - reach);
|
|
154
|
-
return { position, wanted, speed, direction };
|
|
155
|
-
}
|
|
156
|
-
/** Whether a film has landed: still, on a whole picture beside where the scroll stands. */
|
|
157
|
-
function filmLanded(motion) {
|
|
158
|
-
return Math.abs(motion.speed) < 0.01 && Number.isInteger(motion.position) && Math.abs(motion.position - motion.wanted) < 1;
|
|
159
|
-
}
|
|
160
105
|
/** The picture at `played` % of a set of `count`. */
|
|
161
106
|
function frameIndexAt(played, count) {
|
|
162
107
|
if (count <= 1)
|
|
@@ -195,6 +140,30 @@ function nearestLoadedFrame(loaded, index) {
|
|
|
195
140
|
}
|
|
196
141
|
return -1;
|
|
197
142
|
}
|
|
143
|
+
/**
|
|
144
|
+
* How much unpacked picture one player holds at once. A browser keeps few of 300 unpacked pictures (a wide set is 1.7 GB
|
|
145
|
+
* unpacked) and unpacked again on the page's own thread, at the moment of drawing, 22 ms a 1600×900 picture: longer than a
|
|
146
|
+
* whole frame, so the film and the page beside it skipped a beat for every new picture (Doron's recording, 2026-11-04).
|
|
147
|
+
*/
|
|
148
|
+
const FRAMES_UNPACKED_BYTES = 96 * 1024 * 1024;
|
|
149
|
+
const MIN_UNPACKED = 6;
|
|
150
|
+
const MAX_UNPACKED = 24;
|
|
151
|
+
/** How many pictures of `width`×`height` a player holds unpacked. */
|
|
152
|
+
function unpackedFrameCount(width, height) {
|
|
153
|
+
return Math.min(MAX_UNPACKED, Math.max(MIN_UNPACKED, Math.floor(FRAMES_UNPACKED_BYTES / (width * height * 4))));
|
|
154
|
+
}
|
|
155
|
+
/** The `size` pictures to hold unpacked around `position`, nearest first, each side in turn starting ahead. */
|
|
156
|
+
function framesToHold(position, count, size) {
|
|
157
|
+
const from = Math.min(count - 1, Math.max(0, Math.floor(position)));
|
|
158
|
+
const held = [from];
|
|
159
|
+
for (let distance = 1; held.length < Math.min(size, count); distance++) {
|
|
160
|
+
if (from + distance < count)
|
|
161
|
+
held.push(from + distance);
|
|
162
|
+
if (from - distance >= 0 && held.length < size)
|
|
163
|
+
held.push(from - distance);
|
|
164
|
+
}
|
|
165
|
+
return held;
|
|
166
|
+
}
|
|
198
167
|
/** The longest side of a wide picture and of a phone picture. A phone's is not its width: a landscape video covers a
|
|
199
168
|
* tall stage by its height, so a picture sized to the phone's width would be enlarged five times. */
|
|
200
169
|
const WIDE_LONG_SIDE = 1600;
|
|
@@ -238,6 +207,7 @@ var FramesClass;
|
|
|
238
207
|
FramesClass["Canvas"] = "iox-video__frames";
|
|
239
208
|
})(FramesClass || (FramesClass = {}));
|
|
240
209
|
const LOAD_CONCURRENCY = 6;
|
|
210
|
+
const UNPACK_CONCURRENCY = 4;
|
|
241
211
|
const NEAR_MARGIN = '100% 0px';
|
|
242
212
|
/** Under these the visitor keeps the poster: nobody on a metered 2G connection asked to download a film. */
|
|
243
213
|
const SLOW_CONNECTIONS = new Set(['slow-2g', '2g']);
|
|
@@ -245,15 +215,17 @@ const SLOW_CONNECTIONS = new Set(['slow-2g', '2g']);
|
|
|
245
215
|
* The player: draws the picture nearest what the scroll asked for on a canvas laid over the poster, and nothing until a
|
|
246
216
|
* first picture has arrived, so the poster is what a visitor sees until then, and for good if the pictures never come.
|
|
247
217
|
* Browser only. It writes and never reads, so the driver can call it in its write phase.
|
|
218
|
+
*
|
|
219
|
+
* Each picture is downloaded as a file and unpacked off the page's thread (`createImageBitmap` of the file), a window of
|
|
220
|
+
* them around where the film stands, so drawing one never waits for it. A browser that cannot (no `fetch` or
|
|
221
|
+
* `createImageBitmap`, or storage that refuses the download) plays from `<img>` pictures, as before: it works, and pays the
|
|
222
|
+
* unpacking on the page's thread.
|
|
248
223
|
*/
|
|
249
224
|
class FramePlayer {
|
|
250
225
|
constructor(el, sequence, options = {}) {
|
|
251
226
|
this.el = el;
|
|
252
227
|
this.sequence = sequence;
|
|
253
228
|
this.played = null;
|
|
254
|
-
this.motion = null;
|
|
255
|
-
this.steppedAt = 0;
|
|
256
|
-
this.landingFrame = null;
|
|
257
229
|
this.observer = null;
|
|
258
230
|
this.canvas = null;
|
|
259
231
|
this.context = null;
|
|
@@ -262,13 +234,21 @@ class FramePlayer {
|
|
|
262
234
|
this.loading = 0;
|
|
263
235
|
this.started = false;
|
|
264
236
|
this.destroyed = false;
|
|
237
|
+
this.held = new Set();
|
|
238
|
+
this.unpacked = new Map();
|
|
239
|
+
this.unpacking = new Set();
|
|
265
240
|
this.pending = new Set();
|
|
266
241
|
this.host = options.host ?? window;
|
|
267
242
|
const { set, info } = frameSetFor(sequence, !!options.phone);
|
|
268
243
|
this.set = set;
|
|
269
244
|
this.info = info;
|
|
270
|
-
this.
|
|
245
|
+
this.ready = new Array(info.count).fill(null);
|
|
246
|
+
this.files = new Array(info.count).fill(null);
|
|
271
247
|
this.order = frameLoadOrder(info.count);
|
|
248
|
+
this.holdCount = unpackedFrameCount(info.width, info.height);
|
|
249
|
+
this.fromFiles = typeof this.host.fetch === 'function' && typeof this.host.createImageBitmap === 'function';
|
|
250
|
+
const Controller = this.host.AbortController;
|
|
251
|
+
this.downloads = this.fromFiles && Controller ? new Controller() : null;
|
|
272
252
|
if (!this.allowed())
|
|
273
253
|
return;
|
|
274
254
|
const Observer = this.host.IntersectionObserver;
|
|
@@ -283,35 +263,15 @@ class FramePlayer {
|
|
|
283
263
|
this.observer.observe(options.near ?? el);
|
|
284
264
|
}
|
|
285
265
|
/**
|
|
286
|
-
* Stand at `played` %,
|
|
287
|
-
*
|
|
266
|
+
* Stand at `played` %, exactly. The film keeps no motion of its own: the scroll's glide, and the slowing at its end,
|
|
267
|
+
* are the caller's, so the film slows with the page and stops when it stops. Between two pictures it blends them.
|
|
288
268
|
*/
|
|
289
|
-
seek(played
|
|
290
|
-
if (played === this.played
|
|
269
|
+
seek(played) {
|
|
270
|
+
if (played === this.played)
|
|
291
271
|
return;
|
|
292
272
|
this.played = played;
|
|
293
|
-
this.
|
|
294
|
-
this.step(now ?? this.host.performance?.now() ?? 0);
|
|
295
|
-
}
|
|
296
|
-
/** One step toward the moment asked for, drawn now; a landing goes on by itself until it stands on a whole picture. */
|
|
297
|
-
step(now) {
|
|
298
|
-
if (this.destroyed || this.played === null)
|
|
299
|
-
return;
|
|
300
|
-
const wanted = framePosition(this.played, this.info.count);
|
|
301
|
-
const aim = this.aim === undefined ? undefined : framePosition(this.aim, this.info.count);
|
|
302
|
-
this.motion = this.motion ? stepFilm(this.motion, wanted, (now - this.steppedAt) / 1000, this.info.count - 1, aim) : filmAt(wanted);
|
|
303
|
-
this.steppedAt = now;
|
|
273
|
+
this.hold();
|
|
304
274
|
this.draw();
|
|
305
|
-
if (!filmLanded(this.motion) && this.landingFrame === null)
|
|
306
|
-
this.landingFrame = this.host.requestAnimationFrame(time => {
|
|
307
|
-
this.landingFrame = null;
|
|
308
|
-
this.step(time);
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
stopLanding() {
|
|
312
|
-
if (this.landingFrame !== null)
|
|
313
|
-
this.host.cancelAnimationFrame?.(this.landingFrame);
|
|
314
|
-
this.landingFrame = null;
|
|
315
275
|
}
|
|
316
276
|
/** Whether a re-render took the canvas away with the markup it sat in. */
|
|
317
277
|
get detached() {
|
|
@@ -319,16 +279,19 @@ class FramePlayer {
|
|
|
319
279
|
}
|
|
320
280
|
destroy() {
|
|
321
281
|
this.destroyed = true;
|
|
322
|
-
this.stopLanding();
|
|
323
282
|
this.el.removeAttribute(FRAMES_SHOWING_ATTRIBUTE);
|
|
324
283
|
this.observer?.disconnect();
|
|
325
284
|
this.observer = null;
|
|
285
|
+
this.downloads?.abort();
|
|
326
286
|
for (const image of this.pending) {
|
|
327
287
|
image.onload = null;
|
|
328
288
|
image.onerror = null;
|
|
329
289
|
image.src = '';
|
|
330
290
|
}
|
|
331
291
|
this.pending.clear();
|
|
292
|
+
for (const bitmap of this.unpacked.values())
|
|
293
|
+
bitmap.close();
|
|
294
|
+
this.unpacked.clear();
|
|
332
295
|
this.canvas?.remove();
|
|
333
296
|
this.canvas = null;
|
|
334
297
|
this.context = null;
|
|
@@ -347,26 +310,55 @@ class FramePlayer {
|
|
|
347
310
|
}
|
|
348
311
|
pump() {
|
|
349
312
|
while (!this.destroyed && this.loading < LOAD_CONCURRENCY && this.nextToLoad < this.order.length) {
|
|
350
|
-
this.
|
|
313
|
+
const index = this.order[this.nextToLoad++];
|
|
314
|
+
if (this.fromFiles)
|
|
315
|
+
this.download(index);
|
|
316
|
+
else
|
|
317
|
+
this.loadImage(index);
|
|
351
318
|
}
|
|
352
319
|
}
|
|
353
|
-
|
|
320
|
+
loaded(arrived) {
|
|
321
|
+
this.loading--;
|
|
322
|
+
if (this.destroyed)
|
|
323
|
+
return;
|
|
324
|
+
if (arrived)
|
|
325
|
+
this.draw();
|
|
326
|
+
this.pump();
|
|
327
|
+
}
|
|
328
|
+
download(index) {
|
|
329
|
+
this.loading++;
|
|
330
|
+
const url = frameUrl(this.sequence, this.set, index);
|
|
331
|
+
this.host.fetch(url, this.downloads ? { signal: this.downloads.signal } : undefined)
|
|
332
|
+
.then(response => (response.ok ? response.blob() : null))
|
|
333
|
+
.then(file => {
|
|
334
|
+
if (this.destroyed)
|
|
335
|
+
return;
|
|
336
|
+
// A picture that failed is a gap: its neighbours stand in.
|
|
337
|
+
this.files[index] = file;
|
|
338
|
+
this.loading--;
|
|
339
|
+
this.hold();
|
|
340
|
+
this.pump();
|
|
341
|
+
}, () => {
|
|
342
|
+
if (this.destroyed)
|
|
343
|
+
return;
|
|
344
|
+
// Storage that refuses a download from the page's address still serves an <img>: play from those.
|
|
345
|
+
this.fromFiles = false;
|
|
346
|
+
this.loading--;
|
|
347
|
+
this.loadImage(index);
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
loadImage(index) {
|
|
354
351
|
const image = this.host.document.createElement('img');
|
|
355
352
|
image.decoding = 'async';
|
|
356
353
|
this.loading++;
|
|
357
354
|
this.pending.add(image);
|
|
358
355
|
const done = (arrived) => {
|
|
359
356
|
this.pending.delete(image);
|
|
360
|
-
this.
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
if (arrived) {
|
|
364
|
-
this.images[index] = image;
|
|
365
|
-
this.draw();
|
|
366
|
-
}
|
|
367
|
-
this.pump();
|
|
357
|
+
if (!this.destroyed && arrived)
|
|
358
|
+
this.ready[index] = image;
|
|
359
|
+
this.loaded(arrived);
|
|
368
360
|
};
|
|
369
|
-
// Decoded before it counts, or
|
|
361
|
+
// Decoded before it counts, or its first draw decodes on the driver's frame.
|
|
370
362
|
image.onload = () => {
|
|
371
363
|
const decoded = image.decode?.();
|
|
372
364
|
if (decoded)
|
|
@@ -374,42 +366,91 @@ class FramePlayer {
|
|
|
374
366
|
else
|
|
375
367
|
done(true);
|
|
376
368
|
};
|
|
377
|
-
// A picture that failed is a gap: its neighbours stand in.
|
|
378
369
|
image.onerror = () => done(false);
|
|
379
370
|
image.src = frameUrl(this.sequence, this.set, index);
|
|
380
371
|
}
|
|
372
|
+
/** Unpack the pictures around where the film stands, nearest first, and let go of the ones it has left. */
|
|
373
|
+
hold() {
|
|
374
|
+
if (this.destroyed)
|
|
375
|
+
return;
|
|
376
|
+
const wanted = framesToHold(framePosition(this.played ?? 0, this.info.count), this.info.count, this.holdCount);
|
|
377
|
+
this.held = new Set(wanted);
|
|
378
|
+
for (const [index, bitmap] of this.unpacked) {
|
|
379
|
+
if (this.held.has(index))
|
|
380
|
+
continue;
|
|
381
|
+
bitmap.close();
|
|
382
|
+
this.unpacked.delete(index);
|
|
383
|
+
this.ready[index] = null;
|
|
384
|
+
}
|
|
385
|
+
for (const index of wanted) {
|
|
386
|
+
if (this.unpacking.size >= UNPACK_CONCURRENCY)
|
|
387
|
+
return;
|
|
388
|
+
if (this.files[index] && !this.ready[index] && !this.unpacking.has(index))
|
|
389
|
+
this.unpack(index);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
unpack(index) {
|
|
393
|
+
this.unpacking.add(index);
|
|
394
|
+
this.host.createImageBitmap(this.files[index]).then(bitmap => {
|
|
395
|
+
this.unpacking.delete(index);
|
|
396
|
+
if (this.destroyed || !this.held.has(index)) {
|
|
397
|
+
bitmap.close();
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
this.unpacked.set(index, bitmap);
|
|
401
|
+
this.ready[index] = bitmap;
|
|
402
|
+
this.draw();
|
|
403
|
+
}
|
|
404
|
+
this.hold();
|
|
405
|
+
}, () => {
|
|
406
|
+
// A file that will not unpack is a gap, like one that never came.
|
|
407
|
+
this.unpacking.delete(index);
|
|
408
|
+
this.files[index] = null;
|
|
409
|
+
this.hold();
|
|
410
|
+
});
|
|
411
|
+
}
|
|
381
412
|
draw() {
|
|
382
|
-
if (
|
|
413
|
+
if (this.destroyed || this.played === null)
|
|
383
414
|
return;
|
|
384
|
-
const blend = frameBlendAt(this.
|
|
415
|
+
const blend = frameBlendAt(this.ready, framePosition(this.played, this.info.count));
|
|
385
416
|
const last = this.drawn;
|
|
386
417
|
if (!blend || (last && last.from === blend.from && last.to === blend.to && last.mix === blend.mix))
|
|
387
418
|
return;
|
|
388
|
-
const
|
|
389
|
-
if (!this.ensureCanvas(
|
|
419
|
+
const picture = this.ready[blend.from];
|
|
420
|
+
if (!this.ensureCanvas(picture))
|
|
390
421
|
return;
|
|
391
422
|
const context = this.context;
|
|
392
423
|
const { width, height } = this.canvas;
|
|
393
424
|
context.clearRect(0, 0, width, height);
|
|
394
|
-
context.drawImage(image, 0, 0, width, height);
|
|
395
425
|
if (blend.mix > 0) {
|
|
426
|
+
// A true mix, (1 − mix)·from + mix·to, even where a see-through film has nothing on one side. Drawing `to` over
|
|
427
|
+
// an opaque `from` kept `from`'s outline whole until the next picture, so the subject's edge jumped a picture at
|
|
428
|
+
// a time instead of moving.
|
|
429
|
+
context.globalCompositeOperation = 'lighter';
|
|
430
|
+
context.globalAlpha = 1 - blend.mix;
|
|
431
|
+
context.drawImage(picture, 0, 0, width, height);
|
|
396
432
|
context.globalAlpha = blend.mix;
|
|
397
|
-
context.drawImage(this.
|
|
433
|
+
context.drawImage(this.ready[blend.to], 0, 0, width, height);
|
|
398
434
|
context.globalAlpha = 1;
|
|
435
|
+
context.globalCompositeOperation = 'source-over';
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
context.drawImage(picture, 0, 0, width, height);
|
|
399
439
|
}
|
|
400
440
|
// Over a transparent film the poster would show through: a second, stiller subject behind the moving one.
|
|
401
441
|
if (!this.drawn)
|
|
402
442
|
this.el.setAttribute(FRAMES_SHOWING_ATTRIBUTE, '');
|
|
403
443
|
this.drawn = blend;
|
|
404
444
|
}
|
|
405
|
-
ensureCanvas(
|
|
445
|
+
ensureCanvas(picture) {
|
|
406
446
|
if (this.canvas)
|
|
407
447
|
return !!this.context;
|
|
448
|
+
const size = picture;
|
|
408
449
|
const canvas = this.host.document.createElement('canvas');
|
|
409
450
|
canvas.className = FramesClass.Canvas;
|
|
410
451
|
canvas.setAttribute('aria-hidden', 'true');
|
|
411
|
-
canvas.width =
|
|
412
|
-
canvas.height =
|
|
452
|
+
canvas.width = size.naturalWidth || Number(size.width) || this.info.width;
|
|
453
|
+
canvas.height = size.naturalHeight || Number(size.height) || this.info.height;
|
|
413
454
|
this.context = canvas.getContext('2d');
|
|
414
455
|
if (!this.context)
|
|
415
456
|
return false;
|
|
@@ -1039,5 +1080,5 @@ function videoRuntimeOf(el) {
|
|
|
1039
1080
|
* Generated bundle index. Do not edit.
|
|
1040
1081
|
*/
|
|
1041
1082
|
|
|
1042
|
-
export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT,
|
|
1083
|
+
export { CONSENT_GRANT_EVENT, CONSENT_PREFERENCES_EVENT, FRAMES_PHONE_MAX_WIDTH, FRAMES_SHOWING_ATTRIBUTE, FRAMES_UNPACKED_BYTES, FRAME_BLEND_STEPS, FRAME_SEQUENCE_ID, FrameExtension, FramePlayer, FrameSet, FramesClass, MAX_FRAMES, MAX_FRAME_BYTES, PHONE_LONG_SIDE, VIDEO_EMBED_ORIGINS, VIDEO_NODE_TYPE, VIDEO_PROVIDER_COMPANY, VIDEO_PROVIDER_LABEL, VIDEO_WORDS, VideoAttribute, VideoClass, VideoIcon, VideoKind, VideoMode, VideoRuntime, VideoSource, VideoTrait, WIDE_LONG_SIDE, attachVideoAt, attachVideos, documentConsentTransport, fittedFrameSize, frameBlendAt, frameFileName, frameIndexAt, frameLoadOrder, framePosition, frameSetFor, frameSummary, frameUrl, framesToHold, isThirdPartyPoster, nearestLoadedFrame, normalizeFrameSequence, parseVideoUrl, phoneFrameCount, phoneFrameSrcset, planVideo, readConsentRecord, sampledFrameIndexes, serializeVideoAttributes, sortFrameFiles, unpackedFrameCount, videoConsentCategory, videoEmbedUrl, videoFrameCount, videoInnerHtml, videoPlayLabel, videoPosterFileName, videoProp, videoRefOf, videoRootAttributes, videoRuntimeOf, videoSourceOf, videoThumbnailRequest, videoWords };
|
|
1043
1084
|
//# sourceMappingURL=vectoriox-iox-ui-media-core.mjs.map
|