etro 0.8.0 → 0.8.3
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/.github/workflows/nodejs.yml +3 -1
- package/.github/workflows/shipjs-trigger.yml +29 -0
- package/CHANGELOG.md +36 -13
- package/CODE_OF_CONDUCT.md +5 -5
- package/CONTRIBUTING.md +22 -72
- package/README.md +2 -2
- package/dist/effect/base.d.ts +14 -1
- package/dist/etro-cjs.js +189 -230
- package/dist/etro-iife.js +189 -230
- package/dist/layer/base.d.ts +13 -0
- package/eslint.conf.js +2 -1
- package/eslint.test-conf.js +1 -0
- package/examples/application/readme-screenshot.html +4 -8
- package/examples/application/video-player.html +3 -4
- package/examples/introduction/effects.html +23 -4
- package/karma.conf.js +4 -2
- package/package.json +8 -4
- package/scripts/gen-effect-samples.html +0 -3
- package/ship.config.js +80 -0
- package/src/effect/base.ts +29 -10
- package/src/effect/gaussian-blur.ts +10 -10
- package/src/effect/pixelate.ts +1 -2
- package/src/effect/shader.ts +18 -22
- package/src/effect/stack.ts +8 -4
- package/src/effect/transform.ts +13 -14
- package/src/event.ts +8 -14
- package/src/layer/audio-source.ts +16 -14
- package/src/layer/audio.ts +1 -2
- package/src/layer/base.ts +26 -7
- package/src/layer/visual.ts +11 -6
- package/src/movie.ts +70 -64
- package/src/util.ts +50 -57
- package/docs/effect.js.html +0 -1215
- package/docs/event.js.html +0 -145
- package/docs/index.html +0 -81
- package/docs/index.js.html +0 -92
- package/docs/layer.js.html +0 -888
- package/docs/module-effect-GaussianBlurComponent.html +0 -345
- package/docs/module-effect.Brightness.html +0 -339
- package/docs/module-effect.Channels.html +0 -319
- package/docs/module-effect.ChromaKey.html +0 -611
- package/docs/module-effect.Contrast.html +0 -339
- package/docs/module-effect.EllipticalMask.html +0 -200
- package/docs/module-effect.GaussianBlur.html +0 -202
- package/docs/module-effect.GaussianBlurHorizontal.html +0 -242
- package/docs/module-effect.GaussianBlurVertical.html +0 -242
- package/docs/module-effect.Pixelate.html +0 -330
- package/docs/module-effect.Shader.html +0 -1227
- package/docs/module-effect.Stack.html +0 -406
- package/docs/module-effect.Transform.Matrix.html +0 -193
- package/docs/module-effect.Transform.html +0 -1174
- package/docs/module-effect.html +0 -148
- package/docs/module-event.html +0 -473
- package/docs/module-index.html +0 -186
- package/docs/module-layer-Media.html +0 -1116
- package/docs/module-layer-MediaMixin.html +0 -164
- package/docs/module-layer.Audio.html +0 -1188
- package/docs/module-layer.Base.html +0 -629
- package/docs/module-layer.Image.html +0 -1421
- package/docs/module-layer.Text.html +0 -1731
- package/docs/module-layer.Video.html +0 -1938
- package/docs/module-layer.Visual.html +0 -1698
- package/docs/module-layer.html +0 -137
- package/docs/module-movie.html +0 -3118
- package/docs/module-util.Color.html +0 -702
- package/docs/module-util.Font.html +0 -395
- package/docs/module-util.html +0 -845
- package/docs/movie.js.html +0 -689
- package/docs/scripts/collapse.js +0 -20
- package/docs/scripts/linenumber.js +0 -25
- package/docs/scripts/nav.js +0 -12
- package/docs/scripts/polyfill.js +0 -4
- package/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/docs/scripts/prettify/lang-css.js +0 -2
- package/docs/scripts/prettify/prettify.js +0 -28
- package/docs/scripts/search.js +0 -83
- package/docs/styles/jsdoc.css +0 -671
- package/docs/styles/prettify.css +0 -79
- package/docs/util.js.html +0 -503
- package/spec/assets/effect/gaussian-blur-horizontal.png +0 -0
- package/spec/assets/effect/gaussian-blur-vertical.png +0 -0
- package/spec/assets/effect/grayscale.png +0 -0
- package/spec/assets/effect/original.png +0 -0
- package/spec/assets/effect/pixelate.png +0 -0
- package/spec/assets/effect/transform/multiply.png +0 -0
- package/spec/assets/effect/transform/rotate.png +0 -0
- package/spec/assets/effect/transform/scale-fraction.png +0 -0
- package/spec/assets/effect/transform/scale.png +0 -0
- package/spec/assets/effect/transform/translate-fraction.png +0 -0
- package/spec/assets/effect/transform/translate.png +0 -0
- package/spec/assets/layer/audio.wav +0 -0
- package/spec/assets/layer/image.jpg +0 -0
- package/spec/effect.spec.js +0 -421
- package/spec/event.spec.js +0 -39
- package/spec/layer.spec.js +0 -307
- package/spec/movie.spec.js +0 -346
- package/spec/util.spec.js +0 -294
package/dist/etro-cjs.js
CHANGED
|
@@ -52,14 +52,11 @@ var TypeId = /** @class */ (function () {
|
|
|
52
52
|
this._parts = id.split('.');
|
|
53
53
|
}
|
|
54
54
|
TypeId.prototype.contains = function (other) {
|
|
55
|
-
if (other._parts.length > this._parts.length)
|
|
55
|
+
if (other._parts.length > this._parts.length)
|
|
56
56
|
return false;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (other._parts[i] !== this._parts[i]) {
|
|
57
|
+
for (var i = 0; i < other._parts.length; i++)
|
|
58
|
+
if (other._parts[i] !== this._parts[i])
|
|
60
59
|
return false;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
60
|
return true;
|
|
64
61
|
};
|
|
65
62
|
TypeId.prototype.toString = function () {
|
|
@@ -76,9 +73,8 @@ var TypeId = /** @class */ (function () {
|
|
|
76
73
|
* @param listener
|
|
77
74
|
*/
|
|
78
75
|
function subscribe(target, type, listener) {
|
|
79
|
-
if (!listeners.has(target))
|
|
76
|
+
if (!listeners.has(target))
|
|
80
77
|
listeners.set(target, []);
|
|
81
|
-
}
|
|
82
78
|
listeners.get(target).push({ type: new TypeId(type), listener: listener });
|
|
83
79
|
}
|
|
84
80
|
/**
|
|
@@ -92,9 +88,8 @@ function subscribe(target, type, listener) {
|
|
|
92
88
|
function unsubscribe(target, listener) {
|
|
93
89
|
// Make sure `listener` has been added with `subscribe`.
|
|
94
90
|
if (!listeners.has(target) ||
|
|
95
|
-
!listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener))
|
|
91
|
+
!listeners.get(target).map(function (pair) { return pair.listener; }).includes(listener))
|
|
96
92
|
throw new Error('No matching event listener to remove');
|
|
97
|
-
}
|
|
98
93
|
var removed = listeners.get(target)
|
|
99
94
|
.filter(function (pair) { return pair.listener !== listener; });
|
|
100
95
|
listeners.set(target, removed);
|
|
@@ -111,17 +106,15 @@ function publish(target, type, event) {
|
|
|
111
106
|
event.target = target; // could be a proxy
|
|
112
107
|
event.type = type;
|
|
113
108
|
var t = new TypeId(type);
|
|
114
|
-
if (!listeners.has(target))
|
|
109
|
+
if (!listeners.has(target))
|
|
115
110
|
// No event fired
|
|
116
111
|
return null;
|
|
117
|
-
}
|
|
118
112
|
// Call event listeners for this event.
|
|
119
113
|
var listenersForType = [];
|
|
120
114
|
for (var i = 0; i < listeners.get(target).length; i++) {
|
|
121
115
|
var item = listeners.get(target)[i];
|
|
122
|
-
if (t.contains(item.type))
|
|
116
|
+
if (t.contains(item.type))
|
|
123
117
|
listenersForType.push(item.listener);
|
|
124
|
-
}
|
|
125
118
|
}
|
|
126
119
|
for (var i = 0; i < listenersForType.length; i++) {
|
|
127
120
|
var listener = listenersForType[i];
|
|
@@ -149,9 +142,8 @@ var event = /*#__PURE__*/Object.freeze({
|
|
|
149
142
|
function getPropertyDescriptor(obj, name) {
|
|
150
143
|
do {
|
|
151
144
|
var propDesc = Object.getOwnPropertyDescriptor(obj, name);
|
|
152
|
-
if (propDesc)
|
|
145
|
+
if (propDesc)
|
|
153
146
|
return propDesc;
|
|
154
|
-
}
|
|
155
147
|
obj = Object.getPrototypeOf(obj);
|
|
156
148
|
} while (obj);
|
|
157
149
|
return undefined;
|
|
@@ -166,35 +158,30 @@ function getPropertyDescriptor(obj, name) {
|
|
|
166
158
|
function applyOptions(options, destObj) {
|
|
167
159
|
var defaultOptions = destObj.getDefaultOptions();
|
|
168
160
|
// Validate; make sure `keys` doesn't have any extraneous items
|
|
169
|
-
for (var option in options)
|
|
161
|
+
for (var option in options)
|
|
170
162
|
// eslint-disable-next-line no-prototype-builtins
|
|
171
|
-
if (!defaultOptions.hasOwnProperty(option))
|
|
163
|
+
if (!defaultOptions.hasOwnProperty(option))
|
|
172
164
|
throw new Error("Invalid option: '" + option + "'");
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
165
|
// Merge options and defaultOptions
|
|
176
166
|
options = __assign(__assign({}, defaultOptions), options);
|
|
177
167
|
// Copy options
|
|
178
168
|
for (var option in options) {
|
|
179
169
|
var propDesc = getPropertyDescriptor(destObj, option);
|
|
180
170
|
// Update the property as long as the property has not been set (unless if it has a setter)
|
|
181
|
-
if (!propDesc || propDesc.set)
|
|
171
|
+
if (!propDesc || propDesc.set)
|
|
182
172
|
destObj[option] = options[option];
|
|
183
|
-
}
|
|
184
173
|
}
|
|
185
174
|
}
|
|
186
175
|
// This must be cleared at the start of each frame
|
|
187
176
|
var valCache = new WeakMap();
|
|
188
177
|
function cacheValue(element, path, value) {
|
|
189
178
|
// Initiate movie cache
|
|
190
|
-
if (!valCache.has(element.movie))
|
|
179
|
+
if (!valCache.has(element.movie))
|
|
191
180
|
valCache.set(element.movie, new WeakMap());
|
|
192
|
-
}
|
|
193
181
|
var movieCache = valCache.get(element.movie);
|
|
194
182
|
// Iniitate element cache
|
|
195
|
-
if (!movieCache.has(element))
|
|
183
|
+
if (!movieCache.has(element))
|
|
196
184
|
movieCache.set(element, {});
|
|
197
|
-
}
|
|
198
185
|
var elementCache = movieCache.get(element);
|
|
199
186
|
// Cache the value
|
|
200
187
|
elementCache[path] = value;
|
|
@@ -234,16 +221,13 @@ var KeyFrame = /** @class */ (function () {
|
|
|
234
221
|
return this;
|
|
235
222
|
};
|
|
236
223
|
KeyFrame.prototype.evaluate = function (time) {
|
|
237
|
-
if (this.value.length === 0)
|
|
224
|
+
if (this.value.length === 0)
|
|
238
225
|
throw new Error('Empty keyframe');
|
|
239
|
-
|
|
240
|
-
if (time === undefined) {
|
|
226
|
+
if (time === undefined)
|
|
241
227
|
throw new Error('|time| is undefined or null');
|
|
242
|
-
}
|
|
243
228
|
var firstTime = this.value[0][0];
|
|
244
|
-
if (time < firstTime)
|
|
229
|
+
if (time < firstTime)
|
|
245
230
|
throw new Error('No keyframe point before |time|');
|
|
246
|
-
}
|
|
247
231
|
// I think reduce are slow to do per-frame (or more)?
|
|
248
232
|
for (var i = 0; i < this.value.length; i++) {
|
|
249
233
|
var startTime = this.value[i][0];
|
|
@@ -252,7 +236,7 @@ var KeyFrame = /** @class */ (function () {
|
|
|
252
236
|
if (i + 1 < this.value.length) {
|
|
253
237
|
var endTime = this.value[i + 1][0];
|
|
254
238
|
var endValue = this.value[i + 1][1];
|
|
255
|
-
if (startTime <= time && time < endTime)
|
|
239
|
+
if (startTime <= time && time < endTime)
|
|
256
240
|
// No need for endValue if it is flat interpolation
|
|
257
241
|
// TODO: support custom interpolation for 'other' types?
|
|
258
242
|
if (!(typeof startValue === 'number' || typeof endValue === 'object')) {
|
|
@@ -268,7 +252,6 @@ var KeyFrame = /** @class */ (function () {
|
|
|
268
252
|
endValue, // eslint-disable-line @typescript-eslint/ban-types
|
|
269
253
|
percentProgress, this.interpolationKeys);
|
|
270
254
|
}
|
|
271
|
-
}
|
|
272
255
|
}
|
|
273
256
|
else {
|
|
274
257
|
// Repeat last value forever
|
|
@@ -294,28 +277,23 @@ var KeyFrame = /** @class */ (function () {
|
|
|
294
277
|
// TODO: Is this function efficient?
|
|
295
278
|
// TODO: Update doc @params to allow for keyframes
|
|
296
279
|
function val(element, path, time) {
|
|
297
|
-
if (hasCachedValue(element, path))
|
|
280
|
+
if (hasCachedValue(element, path))
|
|
298
281
|
return getCachedValue(element, path);
|
|
299
|
-
}
|
|
300
282
|
// Get property of element at path
|
|
301
283
|
var pathParts = path.split('.');
|
|
302
284
|
var property = element[pathParts.shift()];
|
|
303
|
-
while (pathParts.length > 0)
|
|
285
|
+
while (pathParts.length > 0)
|
|
304
286
|
property = property[pathParts.shift()];
|
|
305
|
-
}
|
|
306
287
|
// Property filter function
|
|
307
288
|
var process = element.propertyFilters[path];
|
|
308
289
|
var value;
|
|
309
|
-
if (property instanceof KeyFrame)
|
|
290
|
+
if (property instanceof KeyFrame)
|
|
310
291
|
value = property.evaluate(time);
|
|
311
|
-
|
|
312
|
-
else if (typeof property === 'function') {
|
|
292
|
+
else if (typeof property === 'function')
|
|
313
293
|
value = property(element, time); // TODO? add more args
|
|
314
|
-
|
|
315
|
-
else {
|
|
294
|
+
else
|
|
316
295
|
// Simple value
|
|
317
296
|
value = property;
|
|
318
|
-
}
|
|
319
297
|
return cacheValue(element, path, process ? process.call(element, value) : value);
|
|
320
298
|
}
|
|
321
299
|
/* export function floorInterp(x1, x2, t, objectKeys) {
|
|
@@ -326,18 +304,15 @@ function val(element, path, time) {
|
|
|
326
304
|
}, Object.create(Object.getPrototypeOf(x1)));
|
|
327
305
|
} */
|
|
328
306
|
function linearInterp(x1, x2, t, objectKeys) {
|
|
329
|
-
if (typeof x1 !== typeof x2)
|
|
307
|
+
if (typeof x1 !== typeof x2)
|
|
330
308
|
throw new Error('Type mismatch');
|
|
331
|
-
|
|
332
|
-
if (typeof x1 !== 'number' && typeof x1 !== 'object') {
|
|
309
|
+
if (typeof x1 !== 'number' && typeof x1 !== 'object')
|
|
333
310
|
// Flat interpolation (floor)
|
|
334
311
|
return x1;
|
|
335
|
-
}
|
|
336
312
|
if (typeof x1 === 'object') { // to work with objects (including arrays)
|
|
337
313
|
// TODO: make this code DRY
|
|
338
|
-
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
314
|
+
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
339
315
|
throw new Error('Prototype mismatch');
|
|
340
|
-
}
|
|
341
316
|
// Preserve prototype of objects
|
|
342
317
|
var int = Object.create(Object.getPrototypeOf(x1));
|
|
343
318
|
// Take the intersection of properties
|
|
@@ -345,9 +320,8 @@ function linearInterp(x1, x2, t, objectKeys) {
|
|
|
345
320
|
for (var i = 0; i < keys.length; i++) {
|
|
346
321
|
var key = keys[i];
|
|
347
322
|
// eslint-disable-next-line no-prototype-builtins
|
|
348
|
-
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
323
|
+
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
349
324
|
continue;
|
|
350
|
-
}
|
|
351
325
|
int[key] = linearInterp(x1[key], x2[key], t);
|
|
352
326
|
}
|
|
353
327
|
return int;
|
|
@@ -355,17 +329,14 @@ function linearInterp(x1, x2, t, objectKeys) {
|
|
|
355
329
|
return (1 - t) * x1 + t * x2;
|
|
356
330
|
}
|
|
357
331
|
function cosineInterp(x1, x2, t, objectKeys) {
|
|
358
|
-
if (typeof x1 !== typeof x2)
|
|
332
|
+
if (typeof x1 !== typeof x2)
|
|
359
333
|
throw new Error('Type mismatch');
|
|
360
|
-
|
|
361
|
-
if (typeof x1 !== 'number' && typeof x1 !== 'object') {
|
|
334
|
+
if (typeof x1 !== 'number' && typeof x1 !== 'object')
|
|
362
335
|
// Flat interpolation (floor)
|
|
363
336
|
return x1;
|
|
364
|
-
}
|
|
365
337
|
if (typeof x1 === 'object' && typeof x2 === 'object') { // to work with objects (including arrays)
|
|
366
|
-
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
338
|
+
if (Object.getPrototypeOf(x1) !== Object.getPrototypeOf(x2))
|
|
367
339
|
throw new Error('Prototype mismatch');
|
|
368
|
-
}
|
|
369
340
|
// Preserve prototype of objects
|
|
370
341
|
var int = Object.create(Object.getPrototypeOf(x1));
|
|
371
342
|
// Take the intersection of properties
|
|
@@ -373,9 +344,8 @@ function cosineInterp(x1, x2, t, objectKeys) {
|
|
|
373
344
|
for (var i = 0; i < keys.length; i++) {
|
|
374
345
|
var key = keys[i];
|
|
375
346
|
// eslint-disable-next-line no-prototype-builtins
|
|
376
|
-
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
347
|
+
if (!x1.hasOwnProperty(key) || !x2.hasOwnProperty(key))
|
|
377
348
|
continue;
|
|
378
|
-
}
|
|
379
349
|
int[key] = cosineInterp(x1[key], x2[key], t);
|
|
380
350
|
}
|
|
381
351
|
return int;
|
|
@@ -505,12 +475,10 @@ function mapPixels(mapper, canvas, ctx, x, y, width, height, flush) {
|
|
|
505
475
|
width = width || canvas.width;
|
|
506
476
|
height = height || canvas.height;
|
|
507
477
|
var frame = ctx.getImageData(x, y, width, height);
|
|
508
|
-
for (var i = 0, l = frame.data.length; i < l; i += 4)
|
|
478
|
+
for (var i = 0, l = frame.data.length; i < l; i += 4)
|
|
509
479
|
mapper(frame.data, i);
|
|
510
|
-
|
|
511
|
-
if (flush) {
|
|
480
|
+
if (flush)
|
|
512
481
|
ctx.putImageData(frame, x, y);
|
|
513
|
-
}
|
|
514
482
|
}
|
|
515
483
|
/**
|
|
516
484
|
* <p>Emits "change" event when public properties updated, recursively.
|
|
@@ -527,17 +495,17 @@ function watchPublic(target) {
|
|
|
527
495
|
// Public API property updated, emit 'modify' event.
|
|
528
496
|
publish(proxy, target.type + ".change.modify", { property: getPath(receiver, prop), newValue: val });
|
|
529
497
|
};
|
|
530
|
-
var
|
|
498
|
+
var canWatch = function (receiver, prop) { return !prop.startsWith('_') &&
|
|
499
|
+
(receiver.publicExcludes === undefined || !receiver.publicExcludes.includes(prop)); };
|
|
531
500
|
// The path to each child property (each is a unique proxy)
|
|
532
501
|
var paths = new WeakMap();
|
|
533
502
|
var handler = {
|
|
534
503
|
set: function (obj, prop, val, receiver) {
|
|
535
504
|
// Recurse
|
|
536
|
-
if (typeof val === 'object' && val !== null && !paths.has(val) &&
|
|
505
|
+
if (typeof val === 'object' && val !== null && !paths.has(val) && canWatch(receiver, prop)) {
|
|
537
506
|
val = new Proxy(val, handler);
|
|
538
507
|
paths.set(val, getPath(receiver, prop));
|
|
539
508
|
}
|
|
540
|
-
var was = prop in obj;
|
|
541
509
|
// Set property or attribute
|
|
542
510
|
// Search prototype chain for the closest setter
|
|
543
511
|
var objProto = obj;
|
|
@@ -549,15 +517,12 @@ function watchPublic(target) {
|
|
|
549
517
|
break;
|
|
550
518
|
}
|
|
551
519
|
}
|
|
552
|
-
if (!objProto)
|
|
520
|
+
if (!objProto)
|
|
553
521
|
// Couldn't find setter; set value on instance
|
|
554
522
|
obj[prop] = val;
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
// on root object.
|
|
558
|
-
if (obj !== target || (was && check(prop))) {
|
|
523
|
+
// Check if the property isn't blacklisted in publicExcludes.
|
|
524
|
+
if (canWatch(receiver, prop))
|
|
559
525
|
callback(prop, val, receiver);
|
|
560
|
-
}
|
|
561
526
|
return true;
|
|
562
527
|
}
|
|
563
528
|
};
|
|
@@ -597,23 +562,20 @@ function AudioSourceMixin(superclass) {
|
|
|
597
562
|
applyOptions(options, _this);
|
|
598
563
|
var load = function () {
|
|
599
564
|
// TODO: && ?
|
|
600
|
-
if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0)
|
|
565
|
+
if ((options.duration || (_this.source.duration - _this.sourceStartTime)) < 0)
|
|
601
566
|
throw new Error('Invalid options.duration or options.sourceStartTime');
|
|
602
|
-
}
|
|
603
567
|
_this._unstretchedDuration = options.duration || (_this.source.duration - _this.sourceStartTime);
|
|
604
568
|
_this.duration = _this._unstretchedDuration / (_this.playbackRate);
|
|
605
569
|
// onload will use `this`, and can't bind itself because it's before
|
|
606
570
|
// super()
|
|
607
571
|
onload && onload.bind(_this)(_this.source, options);
|
|
608
572
|
};
|
|
609
|
-
if (_this.source.readyState >= 2)
|
|
573
|
+
if (_this.source.readyState >= 2)
|
|
610
574
|
// this frame's data is available now
|
|
611
575
|
load();
|
|
612
|
-
|
|
613
|
-
else {
|
|
576
|
+
else
|
|
614
577
|
// when this frame's data is available
|
|
615
578
|
_this.source.addEventListener('loadedmetadata', load);
|
|
616
|
-
}
|
|
617
579
|
_this.source.addEventListener('durationchange', function () {
|
|
618
580
|
_this.duration = options.duration || (_this.source.duration - _this.sourceStartTime);
|
|
619
581
|
});
|
|
@@ -623,11 +585,9 @@ function AudioSourceMixin(superclass) {
|
|
|
623
585
|
var _this = this;
|
|
624
586
|
_super.prototype.attach.call(this, movie);
|
|
625
587
|
subscribe(movie, 'movie.seek', function () {
|
|
626
|
-
|
|
627
|
-
if (time < _this.startTime || time >= _this.startTime + _this.duration) {
|
|
588
|
+
if (_this.currentTime < 0 || _this.currentTime >= _this.duration)
|
|
628
589
|
return;
|
|
629
|
-
|
|
630
|
-
_this.source.currentTime = time - _this.startTime;
|
|
590
|
+
_this.source.currentTime = _this.currentTime + _this.sourceStartTime;
|
|
631
591
|
});
|
|
632
592
|
// TODO: on unattach?
|
|
633
593
|
subscribe(movie, 'movie.audiodestinationupdate', function (event) {
|
|
@@ -639,7 +599,7 @@ function AudioSourceMixin(superclass) {
|
|
|
639
599
|
}
|
|
640
600
|
});
|
|
641
601
|
// connect to audiocontext
|
|
642
|
-
this._audioNode = movie.actx.createMediaElementSource(this.source);
|
|
602
|
+
this._audioNode = this.audioNode || movie.actx.createMediaElementSource(this.source);
|
|
643
603
|
// Spy on connect and disconnect to remember if it connected to
|
|
644
604
|
// actx.destination (for Movie#record).
|
|
645
605
|
var oldConnect = this._audioNode.connect.bind(this.audioNode);
|
|
@@ -650,14 +610,16 @@ function AudioSourceMixin(superclass) {
|
|
|
650
610
|
var oldDisconnect = this._audioNode.disconnect.bind(this.audioNode);
|
|
651
611
|
this._audioNode.disconnect = function (destination, output, input) {
|
|
652
612
|
if (_this._connectedToDestination &&
|
|
653
|
-
destination === movie.actx.destination)
|
|
613
|
+
destination === movie.actx.destination)
|
|
654
614
|
_this._connectedToDestination = false;
|
|
655
|
-
}
|
|
656
615
|
return oldDisconnect(destination, output, input);
|
|
657
616
|
};
|
|
658
617
|
// Connect to actx.destination by default (can be rewired by user)
|
|
659
618
|
this.audioNode.connect(movie.actx.destination);
|
|
660
619
|
};
|
|
620
|
+
MixedAudioSource.prototype.detach = function () {
|
|
621
|
+
this.audioNode.disconnect(this.movie.actx.destination);
|
|
622
|
+
};
|
|
661
623
|
MixedAudioSource.prototype.start = function () {
|
|
662
624
|
this.source.currentTime = this.currentTime + this.sourceStartTime;
|
|
663
625
|
this.source.play();
|
|
@@ -689,9 +651,8 @@ function AudioSourceMixin(superclass) {
|
|
|
689
651
|
},
|
|
690
652
|
set: function (value) {
|
|
691
653
|
this._playbackRate = value;
|
|
692
|
-
if (this._unstretchedDuration !== undefined)
|
|
654
|
+
if (this._unstretchedDuration !== undefined)
|
|
693
655
|
this.duration = this._unstretchedDuration / value;
|
|
694
|
-
}
|
|
695
656
|
},
|
|
696
657
|
enumerable: false,
|
|
697
658
|
configurable: true
|
|
@@ -771,20 +732,36 @@ var Base = /** @class */ (function () {
|
|
|
771
732
|
});
|
|
772
733
|
return newThis;
|
|
773
734
|
}
|
|
774
|
-
|
|
735
|
+
/**
|
|
736
|
+
* Attaches this layer to `movie` if not already attached.
|
|
737
|
+
* @ignore
|
|
738
|
+
*/
|
|
739
|
+
Base.prototype.tryAttach = function (movie) {
|
|
740
|
+
if (this._occurrenceCount === 0)
|
|
741
|
+
this.attach(movie);
|
|
775
742
|
this._occurrenceCount++;
|
|
743
|
+
};
|
|
744
|
+
Base.prototype.attach = function (movie) {
|
|
776
745
|
this._movie = movie;
|
|
777
746
|
};
|
|
778
|
-
|
|
779
|
-
|
|
747
|
+
/**
|
|
748
|
+
* Dettaches this layer from its movie if the number of times `tryDetach` has
|
|
749
|
+
* been called (including this call) equals the number of times `tryAttach`
|
|
750
|
+
* has been called.
|
|
751
|
+
*
|
|
752
|
+
* @ignore
|
|
753
|
+
*/
|
|
754
|
+
Base.prototype.tryDetach = function () {
|
|
755
|
+
if (this.movie === null)
|
|
780
756
|
throw new Error('No movie to detach from');
|
|
781
|
-
}
|
|
782
757
|
this._occurrenceCount--;
|
|
783
758
|
// If this layer occurs in another place in a `layers` array, do not unset
|
|
784
759
|
// _movie. (For calling `unshift` on the `layers` proxy)
|
|
785
|
-
if (this._occurrenceCount === 0)
|
|
786
|
-
this.
|
|
787
|
-
|
|
760
|
+
if (this._occurrenceCount === 0)
|
|
761
|
+
this.detach();
|
|
762
|
+
};
|
|
763
|
+
Base.prototype.detach = function () {
|
|
764
|
+
this._movie = null;
|
|
788
765
|
};
|
|
789
766
|
/**
|
|
790
767
|
* Called when the layer is activated
|
|
@@ -873,9 +850,8 @@ var Audio = /** @class */ (function (_super) {
|
|
|
873
850
|
*/
|
|
874
851
|
function Audio(options) {
|
|
875
852
|
var _this = _super.call(this, options) || this;
|
|
876
|
-
if (_this.duration === undefined)
|
|
853
|
+
if (_this.duration === undefined)
|
|
877
854
|
_this.duration = (_this).source.duration - _this.sourceStartTime;
|
|
878
|
-
}
|
|
879
855
|
return _this;
|
|
880
856
|
}
|
|
881
857
|
Audio.prototype.getDefaultOptions = function () {
|
|
@@ -913,9 +889,8 @@ var Visual = /** @class */ (function (_super) {
|
|
|
913
889
|
set: function (target, property, value) {
|
|
914
890
|
if (!isNaN(Number(property))) {
|
|
915
891
|
// The property is a number (index)
|
|
916
|
-
if (target[property])
|
|
892
|
+
if (target[property])
|
|
917
893
|
target[property].detach();
|
|
918
|
-
}
|
|
919
894
|
value.attach(_this);
|
|
920
895
|
}
|
|
921
896
|
target[property] = value;
|
|
@@ -928,6 +903,11 @@ var Visual = /** @class */ (function (_super) {
|
|
|
928
903
|
* Render visual output
|
|
929
904
|
*/
|
|
930
905
|
Visual.prototype.render = function () {
|
|
906
|
+
// Prevent empty canvas errors if the width or height is 0
|
|
907
|
+
var width = val(this, 'width', this.currentTime);
|
|
908
|
+
var height = val(this, 'height', this.currentTime);
|
|
909
|
+
if (width === 0 || height === 0)
|
|
910
|
+
return;
|
|
931
911
|
this.beginRender();
|
|
932
912
|
this.doRender();
|
|
933
913
|
this.endRender();
|
|
@@ -958,18 +938,16 @@ var Visual = /** @class */ (function (_super) {
|
|
|
958
938
|
Visual.prototype.endRender = function () {
|
|
959
939
|
var w = val(this, 'width', this.currentTime) || val(this.movie, 'width', this.movie.currentTime);
|
|
960
940
|
var h = val(this, 'height', this.currentTime) || val(this.movie, 'height', this.movie.currentTime);
|
|
961
|
-
if (w * h > 0)
|
|
941
|
+
if (w * h > 0)
|
|
962
942
|
this._applyEffects();
|
|
963
|
-
}
|
|
964
943
|
// else InvalidStateError for drawing zero-area image in some effects, right?
|
|
965
944
|
};
|
|
966
945
|
Visual.prototype._applyEffects = function () {
|
|
967
946
|
for (var i = 0; i < this.effects.length; i++) {
|
|
968
947
|
var effect = this.effects[i];
|
|
969
|
-
if (effect.enabled)
|
|
948
|
+
if (effect && effect.enabled)
|
|
970
949
|
// Pass relative time
|
|
971
950
|
effect.apply(this, this.movie.currentTime - this.startTime);
|
|
972
|
-
}
|
|
973
951
|
}
|
|
974
952
|
};
|
|
975
953
|
/**
|
|
@@ -1213,28 +1191,43 @@ var Base$1 = /** @class */ (function () {
|
|
|
1213
1191
|
newThis._target = null;
|
|
1214
1192
|
// Propogate up to target
|
|
1215
1193
|
subscribe(newThis, 'effect.change.modify', function (event) {
|
|
1216
|
-
if (!newThis._target)
|
|
1194
|
+
if (!newThis._target)
|
|
1217
1195
|
return;
|
|
1218
|
-
}
|
|
1219
1196
|
var type = newThis._target.type + ".change.effect.modify";
|
|
1220
1197
|
publish(newThis._target, type, __assign(__assign({}, event), { target: newThis._target, source: newThis, type: type }));
|
|
1221
1198
|
});
|
|
1222
1199
|
return newThis;
|
|
1223
1200
|
}
|
|
1224
|
-
|
|
1201
|
+
/**
|
|
1202
|
+
* Attaches this effect to `target` if not already attached.
|
|
1203
|
+
* @ignore
|
|
1204
|
+
*/
|
|
1205
|
+
Base.prototype.tryAttach = function (target) {
|
|
1206
|
+
if (this._occurrenceCount === 0)
|
|
1207
|
+
this.attach(target);
|
|
1225
1208
|
this._occurrenceCount++;
|
|
1226
|
-
this._target = target;
|
|
1227
1209
|
};
|
|
1228
|
-
Base.prototype.
|
|
1229
|
-
|
|
1210
|
+
Base.prototype.attach = function (movie) {
|
|
1211
|
+
this._target = movie;
|
|
1212
|
+
};
|
|
1213
|
+
/**
|
|
1214
|
+
* Dettaches this effect from its target if the number of times `tryDetach`
|
|
1215
|
+
* has been called (including this call) equals the number of times
|
|
1216
|
+
* `tryAttach` has been called.
|
|
1217
|
+
*
|
|
1218
|
+
* @ignore
|
|
1219
|
+
*/
|
|
1220
|
+
Base.prototype.tryDetach = function () {
|
|
1221
|
+
if (this._target === null)
|
|
1230
1222
|
throw new Error('No movie to detach from');
|
|
1231
|
-
}
|
|
1232
1223
|
this._occurrenceCount--;
|
|
1233
1224
|
// If this effect occurs in another place in the containing array, do not
|
|
1234
1225
|
// unset _target. (For calling `unshift` on the `layers` proxy)
|
|
1235
|
-
if (this._occurrenceCount === 0)
|
|
1236
|
-
this.
|
|
1237
|
-
|
|
1226
|
+
if (this._occurrenceCount === 0)
|
|
1227
|
+
this.detach();
|
|
1228
|
+
};
|
|
1229
|
+
Base.prototype.detach = function () {
|
|
1230
|
+
this._target = null;
|
|
1238
1231
|
};
|
|
1239
1232
|
// subclasses must implement apply
|
|
1240
1233
|
/**
|
|
@@ -1314,18 +1307,16 @@ var Shader = /** @class */ (function (_super) {
|
|
|
1314
1307
|
Shader.prototype._initGl = function () {
|
|
1315
1308
|
this._canvas = document.createElement('canvas');
|
|
1316
1309
|
var gl = this._canvas.getContext('webgl');
|
|
1317
|
-
if (gl === null)
|
|
1310
|
+
if (gl === null)
|
|
1318
1311
|
throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.');
|
|
1319
|
-
}
|
|
1320
1312
|
this._gl = gl;
|
|
1321
1313
|
return gl;
|
|
1322
1314
|
};
|
|
1323
1315
|
Shader.prototype._initTextures = function (userUniforms, userTextures, sourceTextureOptions) {
|
|
1324
1316
|
var gl = this._gl;
|
|
1325
1317
|
var maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS);
|
|
1326
|
-
if (userTextures.length > maxTextures)
|
|
1318
|
+
if (userTextures.length > maxTextures)
|
|
1327
1319
|
console.warn('Too many textures!');
|
|
1328
|
-
}
|
|
1329
1320
|
this._userTextures = {};
|
|
1330
1321
|
for (var name_1 in userTextures) {
|
|
1331
1322
|
var userOptions = userTextures[name_1];
|
|
@@ -1338,9 +1329,8 @@ var Shader = /** @class */ (function (_super) {
|
|
|
1338
1329
|
* textures, without having to define multiple properties in the effect
|
|
1339
1330
|
* object.
|
|
1340
1331
|
*/
|
|
1341
|
-
if (userUniforms[name_1])
|
|
1332
|
+
if (userUniforms[name_1])
|
|
1342
1333
|
throw new Error("Texture - uniform naming conflict: " + name_1 + "!");
|
|
1343
|
-
}
|
|
1344
1334
|
// Add this as a "user uniform".
|
|
1345
1335
|
userUniforms[name_1] = '1i'; // texture pointer
|
|
1346
1336
|
}
|
|
@@ -1478,13 +1468,11 @@ var Shader = /** @class */ (function (_super) {
|
|
|
1478
1468
|
// Set the shader uniforms.
|
|
1479
1469
|
// Tell the shader we bound the texture to texture unit 0.
|
|
1480
1470
|
// All base (Shader class) uniforms are optional.
|
|
1481
|
-
if (this._uniformLocations.source)
|
|
1471
|
+
if (this._uniformLocations.source)
|
|
1482
1472
|
gl.uniform1i(this._uniformLocations.source, 0);
|
|
1483
|
-
}
|
|
1484
1473
|
// All base (Shader class) uniforms are optional.
|
|
1485
|
-
if (this._uniformLocations.size)
|
|
1474
|
+
if (this._uniformLocations.size)
|
|
1486
1475
|
gl.uniform2iv(this._uniformLocations.size, [target.canvas.width, target.canvas.height]);
|
|
1487
|
-
}
|
|
1488
1476
|
for (var unprefixed in this._userUniforms) {
|
|
1489
1477
|
var options = this._userUniforms[unprefixed];
|
|
1490
1478
|
var value = val(this, unprefixed, reltime);
|
|
@@ -1535,40 +1523,35 @@ var Shader = /** @class */ (function (_super) {
|
|
|
1535
1523
|
var i = 0;
|
|
1536
1524
|
for (var name_4 in this._userTextures) {
|
|
1537
1525
|
var testValue = val(this, name_4, reltime);
|
|
1538
|
-
if (value === testValue)
|
|
1526
|
+
if (value === testValue)
|
|
1539
1527
|
value = Shader.INTERNAL_TEXTURE_UNITS + i; // after the internal texture units
|
|
1540
|
-
}
|
|
1541
1528
|
i++;
|
|
1542
1529
|
}
|
|
1543
1530
|
}
|
|
1544
1531
|
if (outputType === '3fv') {
|
|
1545
1532
|
// allow 4-component vectors; TODO: why?
|
|
1546
|
-
if (Array.isArray(value) && (value.length === 3 || value.length === 4))
|
|
1533
|
+
if (Array.isArray(value) && (value.length === 3 || value.length === 4))
|
|
1547
1534
|
return value;
|
|
1548
|
-
}
|
|
1549
1535
|
// kind of loose so this can be changed if needed
|
|
1550
|
-
if (typeof value === 'object')
|
|
1536
|
+
if (typeof value === 'object')
|
|
1551
1537
|
return [
|
|
1552
1538
|
value.r !== undefined ? value.r : def,
|
|
1553
1539
|
value.g !== undefined ? value.g : def,
|
|
1554
1540
|
value.b !== undefined ? value.b : def
|
|
1555
1541
|
];
|
|
1556
|
-
}
|
|
1557
1542
|
throw new Error("Invalid type: " + outputType + " or value: " + value);
|
|
1558
1543
|
}
|
|
1559
1544
|
if (outputType === '4fv') {
|
|
1560
|
-
if (Array.isArray(value) && value.length === 4)
|
|
1545
|
+
if (Array.isArray(value) && value.length === 4)
|
|
1561
1546
|
return value;
|
|
1562
|
-
}
|
|
1563
1547
|
// kind of loose so this can be changed if needed
|
|
1564
|
-
if (typeof value === 'object')
|
|
1548
|
+
if (typeof value === 'object')
|
|
1565
1549
|
return [
|
|
1566
1550
|
value.r !== undefined ? value.r : def,
|
|
1567
1551
|
value.g !== undefined ? value.g : def,
|
|
1568
1552
|
value.b !== undefined ? value.b : def,
|
|
1569
1553
|
value.a !== undefined ? value.a : def
|
|
1570
1554
|
];
|
|
1571
|
-
}
|
|
1572
1555
|
throw new Error("Invalid type: " + outputType + " or value: " + value);
|
|
1573
1556
|
}
|
|
1574
1557
|
return value;
|
|
@@ -1662,9 +1645,8 @@ var Shader = /** @class */ (function (_super) {
|
|
|
1662
1645
|
else {
|
|
1663
1646
|
// No, it's not a power of 2. Turn off mips and set
|
|
1664
1647
|
// wrapping to clamp to edge
|
|
1665
|
-
if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
|
|
1648
|
+
if (wrapS !== gl.CLAMP_TO_EDGE || wrapT !== gl.CLAMP_TO_EDGE)
|
|
1666
1649
|
console.warn('Wrap mode is not CLAMP_TO_EDGE for a non-power-of-two texture. Defaulting to CLAMP_TO_EDGE');
|
|
1667
|
-
}
|
|
1668
1650
|
gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1669
1651
|
gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1670
1652
|
}
|
|
@@ -1900,6 +1882,7 @@ var Stack = /** @class */ (function (_super) {
|
|
|
1900
1882
|
function Stack(options) {
|
|
1901
1883
|
var _this = _super.call(this) || this;
|
|
1902
1884
|
_this._effectsBack = [];
|
|
1885
|
+
// TODO: Throw 'change' events in handlers
|
|
1903
1886
|
_this.effects = new Proxy(_this._effectsBack, {
|
|
1904
1887
|
deleteProperty: function (target, property) {
|
|
1905
1888
|
var value = target[property];
|
|
@@ -1910,9 +1893,8 @@ var Stack = /** @class */ (function (_super) {
|
|
|
1910
1893
|
set: function (target, property, value) {
|
|
1911
1894
|
// TODO: make sure type check works
|
|
1912
1895
|
if (!isNaN(Number(property))) { // if property is a number (index)
|
|
1913
|
-
if (target[property])
|
|
1896
|
+
if (target[property])
|
|
1914
1897
|
target[property].detach(); // Detach old effect from movie
|
|
1915
|
-
}
|
|
1916
1898
|
value.attach(this._target); // Attach effect to movie
|
|
1917
1899
|
}
|
|
1918
1900
|
target[property] = value;
|
|
@@ -1921,23 +1903,26 @@ var Stack = /** @class */ (function (_super) {
|
|
|
1921
1903
|
});
|
|
1922
1904
|
options.effects.forEach(function (effect) { return _this.effects.push(effect); });
|
|
1923
1905
|
return _this;
|
|
1906
|
+
// TODO: Propogate 'change' events from children up
|
|
1924
1907
|
}
|
|
1925
1908
|
Stack.prototype.attach = function (movie) {
|
|
1926
1909
|
_super.prototype.attach.call(this, movie);
|
|
1927
|
-
this.effects.forEach(function (effect) {
|
|
1910
|
+
this.effects.filter(function (effect) { return !!effect; }).forEach(function (effect) {
|
|
1928
1911
|
effect.detach();
|
|
1929
1912
|
effect.attach(movie);
|
|
1930
1913
|
});
|
|
1931
1914
|
};
|
|
1932
1915
|
Stack.prototype.detach = function () {
|
|
1933
1916
|
_super.prototype.detach.call(this);
|
|
1934
|
-
this.effects.forEach(function (effect) {
|
|
1917
|
+
this.effects.filter(function (effect) { return !!effect; }).forEach(function (effect) {
|
|
1935
1918
|
effect.detach();
|
|
1936
1919
|
});
|
|
1937
1920
|
};
|
|
1938
1921
|
Stack.prototype.apply = function (target, reltime) {
|
|
1939
1922
|
for (var i = 0; i < this.effects.length; i++) {
|
|
1940
1923
|
var effect = this.effects[i];
|
|
1924
|
+
if (!effect)
|
|
1925
|
+
continue;
|
|
1941
1926
|
effect.apply(target, reltime);
|
|
1942
1927
|
}
|
|
1943
1928
|
};
|
|
@@ -2001,10 +1986,9 @@ var GaussianBlurComponent = /** @class */ (function (_super) {
|
|
|
2001
1986
|
}
|
|
2002
1987
|
GaussianBlurComponent.prototype.apply = function (target, reltime) {
|
|
2003
1988
|
var radiusVal = val(this, 'radius', reltime);
|
|
2004
|
-
if (radiusVal !== this._radiusCache)
|
|
1989
|
+
if (radiusVal !== this._radiusCache)
|
|
2005
1990
|
// Regenerate gaussian distribution canvas.
|
|
2006
1991
|
this.shape = GaussianBlurComponent._render1DKernel(GaussianBlurComponent._gen1DKernel(radiusVal));
|
|
2007
|
-
}
|
|
2008
1992
|
this._radiusCache = radiusVal;
|
|
2009
1993
|
_super.prototype.apply.call(this, target, reltime);
|
|
2010
1994
|
};
|
|
@@ -2037,27 +2021,23 @@ var GaussianBlurComponent = /** @class */ (function (_super) {
|
|
|
2037
2021
|
var pascal = GaussianBlurComponent._genPascalRow(2 * radius + 1);
|
|
2038
2022
|
// don't use `reduce` and `map` (overhead?)
|
|
2039
2023
|
var sum = 0;
|
|
2040
|
-
for (var i = 0; i < pascal.length; i++)
|
|
2024
|
+
for (var i = 0; i < pascal.length; i++)
|
|
2041
2025
|
sum += pascal[i];
|
|
2042
|
-
|
|
2043
|
-
for (var i = 0; i < pascal.length; i++) {
|
|
2026
|
+
for (var i = 0; i < pascal.length; i++)
|
|
2044
2027
|
pascal[i] /= sum;
|
|
2045
|
-
}
|
|
2046
2028
|
return pascal;
|
|
2047
2029
|
};
|
|
2048
2030
|
GaussianBlurComponent._genPascalRow = function (index) {
|
|
2049
|
-
if (index < 0)
|
|
2031
|
+
if (index < 0)
|
|
2050
2032
|
throw new Error("Invalid index " + index);
|
|
2051
|
-
}
|
|
2052
2033
|
var currRow = [1];
|
|
2053
2034
|
for (var i = 1; i < index; i++) {
|
|
2054
2035
|
var nextRow = [];
|
|
2055
2036
|
nextRow.length = currRow.length + 1;
|
|
2056
2037
|
// edges are always 1's
|
|
2057
2038
|
nextRow[0] = nextRow[nextRow.length - 1] = 1;
|
|
2058
|
-
for (var j = 1; j < nextRow.length - 1; j++)
|
|
2039
|
+
for (var j = 1; j < nextRow.length - 1; j++)
|
|
2059
2040
|
nextRow[j] = currRow[j - 1] + currRow[j];
|
|
2060
|
-
}
|
|
2061
2041
|
currRow = nextRow;
|
|
2062
2042
|
}
|
|
2063
2043
|
return currRow;
|
|
@@ -2135,9 +2115,8 @@ var Pixelate = /** @class */ (function (_super) {
|
|
|
2135
2115
|
}
|
|
2136
2116
|
Pixelate.prototype.apply = function (target, reltime) {
|
|
2137
2117
|
var ps = val(this, 'pixelSize', reltime);
|
|
2138
|
-
if (ps % 1 !== 0 || ps < 0)
|
|
2118
|
+
if (ps % 1 !== 0 || ps < 0)
|
|
2139
2119
|
throw new Error('Pixel size must be a nonnegative integer');
|
|
2140
|
-
}
|
|
2141
2120
|
_super.prototype.apply.call(this, target, reltime);
|
|
2142
2121
|
};
|
|
2143
2122
|
return Pixelate;
|
|
@@ -2166,12 +2145,10 @@ var Transform = /** @class */ (function (_super) {
|
|
|
2166
2145
|
return _this;
|
|
2167
2146
|
}
|
|
2168
2147
|
Transform.prototype.apply = function (target, reltime) {
|
|
2169
|
-
if (target.canvas.width !== this._tmpCanvas.width)
|
|
2148
|
+
if (target.canvas.width !== this._tmpCanvas.width)
|
|
2170
2149
|
this._tmpCanvas.width = target.canvas.width;
|
|
2171
|
-
|
|
2172
|
-
if (target.canvas.height !== this._tmpCanvas.height) {
|
|
2150
|
+
if (target.canvas.height !== this._tmpCanvas.height)
|
|
2173
2151
|
this._tmpCanvas.height = target.canvas.height;
|
|
2174
|
-
}
|
|
2175
2152
|
// Use data, since that's the underlying storage
|
|
2176
2153
|
this._tmpMatrix.data = val(this, 'matrix.data', reltime);
|
|
2177
2154
|
this._tmpCtx.setTransform(this._tmpMatrix.a, this._tmpMatrix.b, this._tmpMatrix.c, this._tmpMatrix.d, this._tmpMatrix.e, this._tmpMatrix.f);
|
|
@@ -2197,9 +2174,8 @@ var Transform = /** @class */ (function (_super) {
|
|
|
2197
2174
|
];
|
|
2198
2175
|
}
|
|
2199
2176
|
Matrix.prototype.identity = function () {
|
|
2200
|
-
for (var i = 0; i < this.data.length; i++)
|
|
2177
|
+
for (var i = 0; i < this.data.length; i++)
|
|
2201
2178
|
this.data[i] = Matrix.IDENTITY.data[i];
|
|
2202
|
-
}
|
|
2203
2179
|
return this;
|
|
2204
2180
|
};
|
|
2205
2181
|
/**
|
|
@@ -2208,9 +2184,8 @@ var Transform = /** @class */ (function (_super) {
|
|
|
2208
2184
|
* @param [val]
|
|
2209
2185
|
*/
|
|
2210
2186
|
Matrix.prototype.cell = function (x, y, val) {
|
|
2211
|
-
if (val !== undefined)
|
|
2187
|
+
if (val !== undefined)
|
|
2212
2188
|
this.data[3 * y + x] = val;
|
|
2213
|
-
}
|
|
2214
2189
|
return this.data[3 * y + x];
|
|
2215
2190
|
};
|
|
2216
2191
|
Object.defineProperty(Matrix.prototype, "a", {
|
|
@@ -2262,19 +2237,16 @@ var Transform = /** @class */ (function (_super) {
|
|
|
2262
2237
|
*/
|
|
2263
2238
|
Matrix.prototype.multiply = function (other) {
|
|
2264
2239
|
// copy to temporary matrix to avoid modifying `this` while reading from it
|
|
2265
|
-
for (var x = 0; x < 3; x++)
|
|
2240
|
+
for (var x = 0; x < 3; x++)
|
|
2266
2241
|
for (var y = 0; y < 3; y++) {
|
|
2267
2242
|
var sum = 0;
|
|
2268
|
-
for (var i = 0; i < 3; i++)
|
|
2243
|
+
for (var i = 0; i < 3; i++)
|
|
2269
2244
|
sum += this.cell(x, i) * other.cell(i, y);
|
|
2270
|
-
}
|
|
2271
2245
|
Matrix._TMP_MATRIX.cell(x, y, sum);
|
|
2272
2246
|
}
|
|
2273
|
-
}
|
|
2274
2247
|
// copy data from TMP_MATRIX to this
|
|
2275
|
-
for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++)
|
|
2248
|
+
for (var i = 0; i < Matrix._TMP_MATRIX.data.length; i++)
|
|
2276
2249
|
this.data[i] = Matrix._TMP_MATRIX.data[i];
|
|
2277
|
-
}
|
|
2278
2250
|
return this;
|
|
2279
2251
|
};
|
|
2280
2252
|
/**
|
|
@@ -8804,7 +8776,7 @@ var Movie = /** @class */ (function () {
|
|
|
8804
8776
|
// Refresh screen when effect is removed, if the movie isn't playing
|
|
8805
8777
|
// already.
|
|
8806
8778
|
var value = target[property];
|
|
8807
|
-
value.
|
|
8779
|
+
value.tryDetach();
|
|
8808
8780
|
delete target[property];
|
|
8809
8781
|
publish(that, 'movie.change.effect.remove', { effect: value });
|
|
8810
8782
|
return true;
|
|
@@ -8816,10 +8788,10 @@ var Movie = /** @class */ (function () {
|
|
|
8816
8788
|
publish(that, 'movie.change.effect.remove', {
|
|
8817
8789
|
effect: target[property]
|
|
8818
8790
|
});
|
|
8819
|
-
target[property].
|
|
8791
|
+
target[property].tryDetach();
|
|
8820
8792
|
}
|
|
8821
8793
|
// Attach effect to movie
|
|
8822
|
-
value.
|
|
8794
|
+
value.tryAttach(that);
|
|
8823
8795
|
target[property] = value;
|
|
8824
8796
|
// Refresh screen when effect is set, if the movie isn't playing
|
|
8825
8797
|
// already.
|
|
@@ -8836,12 +8808,11 @@ var Movie = /** @class */ (function () {
|
|
|
8836
8808
|
deleteProperty: function (target, property) {
|
|
8837
8809
|
var oldDuration = this.duration;
|
|
8838
8810
|
var value = target[property];
|
|
8839
|
-
value.
|
|
8811
|
+
value.tryDetach(that);
|
|
8840
8812
|
delete target[property];
|
|
8841
8813
|
var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
|
|
8842
|
-
if (current)
|
|
8814
|
+
if (current)
|
|
8843
8815
|
publish(that, 'movie.change.layer.remove', { layer: value });
|
|
8844
|
-
}
|
|
8845
8816
|
publish(that, 'movie.change.duration', { oldDuration: oldDuration });
|
|
8846
8817
|
return true;
|
|
8847
8818
|
},
|
|
@@ -8853,16 +8824,15 @@ var Movie = /** @class */ (function () {
|
|
|
8853
8824
|
publish(that, 'movie.change.layer.remove', {
|
|
8854
8825
|
layer: target[property]
|
|
8855
8826
|
});
|
|
8856
|
-
target[property].
|
|
8827
|
+
target[property].tryDetach();
|
|
8857
8828
|
}
|
|
8858
8829
|
// Attach layer to movie
|
|
8859
|
-
value.
|
|
8830
|
+
value.tryAttach(that);
|
|
8860
8831
|
target[property] = value;
|
|
8861
8832
|
// Refresh screen when a relevant layer is added or removed
|
|
8862
8833
|
var current = that.currentTime >= value.startTime && that.currentTime < value.startTime + value.duration;
|
|
8863
|
-
if (current)
|
|
8834
|
+
if (current)
|
|
8864
8835
|
publish(that, 'movie.change.layer.add', { layer: value });
|
|
8865
|
-
}
|
|
8866
8836
|
publish(that, 'movie.change.duration', { oldDuration: oldDuration });
|
|
8867
8837
|
}
|
|
8868
8838
|
else {
|
|
@@ -8886,14 +8856,12 @@ var Movie = /** @class */ (function () {
|
|
|
8886
8856
|
this._lastPlayedOffset = -1;
|
|
8887
8857
|
// newThis._updateInterval = 0.1; // time in seconds between each "timeupdate" event
|
|
8888
8858
|
// newThis._lastUpdate = -1;
|
|
8889
|
-
if (newThis.autoRefresh)
|
|
8859
|
+
if (newThis.autoRefresh)
|
|
8890
8860
|
newThis.refresh(); // render single frame on creation
|
|
8891
|
-
}
|
|
8892
8861
|
// Subscribe to own event "change" (child events propogate up)
|
|
8893
8862
|
subscribe(newThis, 'movie.change', function () {
|
|
8894
|
-
if (newThis.autoRefresh && !newThis.rendering)
|
|
8863
|
+
if (newThis.autoRefresh && !newThis.rendering)
|
|
8895
8864
|
newThis.refresh();
|
|
8896
|
-
}
|
|
8897
8865
|
});
|
|
8898
8866
|
// Subscribe to own event "ended"
|
|
8899
8867
|
subscribe(newThis, 'movie.recordended', function () {
|
|
@@ -8911,16 +8879,14 @@ var Movie = /** @class */ (function () {
|
|
|
8911
8879
|
Movie.prototype.play = function () {
|
|
8912
8880
|
var _this = this;
|
|
8913
8881
|
return new Promise(function (resolve) {
|
|
8914
|
-
if (!_this.paused)
|
|
8882
|
+
if (!_this.paused)
|
|
8915
8883
|
throw new Error('Already playing');
|
|
8916
|
-
}
|
|
8917
8884
|
_this._paused = _this._ended = false;
|
|
8918
8885
|
_this._lastPlayed = performance.now();
|
|
8919
8886
|
_this._lastPlayedOffset = _this.currentTime;
|
|
8920
|
-
if (!_this.renderingFrame)
|
|
8887
|
+
if (!_this.renderingFrame)
|
|
8921
8888
|
// Not rendering (and not playing), so play.
|
|
8922
8889
|
_this._render(true, undefined, resolve);
|
|
8923
|
-
}
|
|
8924
8890
|
// Stop rendering frame if currently doing so, because playing has higher
|
|
8925
8891
|
// priority. This will effect the next _render call.
|
|
8926
8892
|
_this._renderingFrame = false;
|
|
@@ -8944,12 +8910,13 @@ var Movie = /** @class */ (function () {
|
|
|
8944
8910
|
// TODO: improve recording performance to increase frame rate?
|
|
8945
8911
|
Movie.prototype.record = function (options) {
|
|
8946
8912
|
var _this = this;
|
|
8947
|
-
if (options.video === false && options.audio === false)
|
|
8913
|
+
if (options.video === false && options.audio === false)
|
|
8948
8914
|
throw new Error('Both video and audio cannot be disabled');
|
|
8949
|
-
|
|
8950
|
-
if (!this.paused) {
|
|
8915
|
+
if (!this.paused)
|
|
8951
8916
|
throw new Error('Cannot record movie while already playing or recording');
|
|
8952
|
-
|
|
8917
|
+
var mimeType = options.type || 'video/webm';
|
|
8918
|
+
if (MediaRecorder && MediaRecorder.isTypeSupported && !MediaRecorder.isTypeSupported(mimeType))
|
|
8919
|
+
throw new Error('Please pass a valid MIME type for the exported video');
|
|
8953
8920
|
return new Promise(function (resolve, reject) {
|
|
8954
8921
|
var canvasCache = _this.canvas;
|
|
8955
8922
|
// Record on a temporary canvas context
|
|
@@ -8977,12 +8944,12 @@ var Movie = /** @class */ (function () {
|
|
|
8977
8944
|
publish(_this, 'movie.audiodestinationupdate', { movie: _this, destination: audioDestination });
|
|
8978
8945
|
}
|
|
8979
8946
|
var stream = new MediaStream(tracks);
|
|
8980
|
-
var
|
|
8947
|
+
var mediaRecorderOptions = __assign(__assign({}, (options.mediaRecorderOptions || {})), { mimeType: mimeType });
|
|
8948
|
+
var mediaRecorder = new MediaRecorder(stream, mediaRecorderOptions);
|
|
8981
8949
|
mediaRecorder.ondataavailable = function (event) {
|
|
8982
8950
|
// if (this._paused) reject(new Error("Recording was interrupted"));
|
|
8983
|
-
if (event.data.size > 0)
|
|
8951
|
+
if (event.data.size > 0)
|
|
8984
8952
|
recordedChunks.push(event.data);
|
|
8985
|
-
}
|
|
8986
8953
|
};
|
|
8987
8954
|
// TODO: publish to movie, not layers
|
|
8988
8955
|
mediaRecorder.onstop = function () {
|
|
@@ -8993,7 +8960,7 @@ var Movie = /** @class */ (function () {
|
|
|
8993
8960
|
_this._mediaRecorder = null;
|
|
8994
8961
|
// Construct the exported video out of all the frame blobs.
|
|
8995
8962
|
resolve(new Blob(recordedChunks, {
|
|
8996
|
-
type:
|
|
8963
|
+
type: mimeType
|
|
8997
8964
|
}));
|
|
8998
8965
|
};
|
|
8999
8966
|
mediaRecorder.onerror = reject;
|
|
@@ -9011,11 +8978,12 @@ var Movie = /** @class */ (function () {
|
|
|
9011
8978
|
Movie.prototype.pause = function () {
|
|
9012
8979
|
this._paused = true;
|
|
9013
8980
|
// Deactivate all layers
|
|
9014
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
8981
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
8982
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i)) {
|
|
8983
|
+
var layer = this.layers[i];
|
|
8984
|
+
layer.stop();
|
|
8985
|
+
layer.active = false;
|
|
8986
|
+
}
|
|
9019
8987
|
publish(this, 'movie.pause', {});
|
|
9020
8988
|
return this;
|
|
9021
8989
|
};
|
|
@@ -9041,17 +9009,15 @@ var Movie = /** @class */ (function () {
|
|
|
9041
9009
|
if (!this.rendering) {
|
|
9042
9010
|
// (!this.paused || this._renderingFrame) is true so it's playing or it's
|
|
9043
9011
|
// rendering a single frame.
|
|
9044
|
-
if (done)
|
|
9012
|
+
if (done)
|
|
9045
9013
|
done();
|
|
9046
|
-
}
|
|
9047
9014
|
return;
|
|
9048
9015
|
}
|
|
9049
9016
|
this._updateCurrentTime(timestamp);
|
|
9050
9017
|
var recordingEnd = this.recording ? this._recordEndTime : this.duration;
|
|
9051
9018
|
var recordingEnded = this.currentTime > recordingEnd;
|
|
9052
|
-
if (recordingEnded)
|
|
9019
|
+
if (recordingEnded)
|
|
9053
9020
|
publish(this, 'movie.recordended', { movie: this });
|
|
9054
|
-
}
|
|
9055
9021
|
// Bad for performance? (remember, it's calling Array.reduce)
|
|
9056
9022
|
var end = this.duration;
|
|
9057
9023
|
var ended = this.currentTime > end;
|
|
@@ -9066,41 +9032,38 @@ var Movie = /** @class */ (function () {
|
|
|
9066
9032
|
if (!this.repeat || this.recording) {
|
|
9067
9033
|
this._ended = true;
|
|
9068
9034
|
// Deactivate all layers
|
|
9069
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9035
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
9036
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i)) {
|
|
9037
|
+
var layer = this.layers[i];
|
|
9038
|
+
// A layer that has been deleted before layers.length has been updated
|
|
9039
|
+
// (see the layers proxy in the constructor).
|
|
9040
|
+
if (!layer)
|
|
9041
|
+
continue;
|
|
9042
|
+
layer.stop();
|
|
9043
|
+
layer.active = false;
|
|
9075
9044
|
}
|
|
9076
|
-
layer.stop();
|
|
9077
|
-
layer.active = false;
|
|
9078
|
-
}
|
|
9079
9045
|
}
|
|
9080
9046
|
}
|
|
9081
9047
|
// Stop playback or recording if done
|
|
9082
9048
|
if (recordingEnded || (ended && !this.repeat)) {
|
|
9083
|
-
if (done)
|
|
9049
|
+
if (done)
|
|
9084
9050
|
done();
|
|
9085
|
-
}
|
|
9086
9051
|
return;
|
|
9087
9052
|
}
|
|
9088
9053
|
// Do render
|
|
9089
9054
|
this._renderBackground(timestamp);
|
|
9090
9055
|
var frameFullyLoaded = this._renderLayers();
|
|
9091
9056
|
this._applyEffects();
|
|
9092
|
-
if (frameFullyLoaded)
|
|
9057
|
+
if (frameFullyLoaded)
|
|
9093
9058
|
publish(this, 'movie.loadeddata', { movie: this });
|
|
9094
|
-
}
|
|
9095
9059
|
// If didn't load in this instant, repeatedly frame-render until frame is
|
|
9096
9060
|
// loaded.
|
|
9097
9061
|
// If the expression below is false, don't publish an event, just silently
|
|
9098
9062
|
// stop render loop.
|
|
9099
9063
|
if (!repeat || (this._renderingFrame && frameFullyLoaded)) {
|
|
9100
9064
|
this._renderingFrame = false;
|
|
9101
|
-
if (done)
|
|
9065
|
+
if (done)
|
|
9102
9066
|
done();
|
|
9103
|
-
}
|
|
9104
9067
|
return;
|
|
9105
9068
|
}
|
|
9106
9069
|
window.requestAnimationFrame(function (timestamp) {
|
|
@@ -9135,12 +9098,13 @@ var Movie = /** @class */ (function () {
|
|
|
9135
9098
|
Movie.prototype._renderLayers = function () {
|
|
9136
9099
|
var frameFullyLoaded = true;
|
|
9137
9100
|
for (var i = 0; i < this.layers.length; i++) {
|
|
9101
|
+
if (!Object.prototype.hasOwnProperty.call(this.layers, i))
|
|
9102
|
+
continue;
|
|
9138
9103
|
var layer = this.layers[i];
|
|
9139
9104
|
// A layer that has been deleted before layers.length has been updated
|
|
9140
9105
|
// (see the layers proxy in the constructor).
|
|
9141
|
-
if (!layer)
|
|
9106
|
+
if (!layer)
|
|
9142
9107
|
continue;
|
|
9143
|
-
}
|
|
9144
9108
|
var reltime = this.currentTime - layer.startTime;
|
|
9145
9109
|
// Cancel operation if layer disabled or outside layer time interval
|
|
9146
9110
|
if (!val(layer, 'enabled', reltime) ||
|
|
@@ -9162,18 +9126,16 @@ var Movie = /** @class */ (function () {
|
|
|
9162
9126
|
layer.active = true;
|
|
9163
9127
|
}
|
|
9164
9128
|
// if the layer has an input file
|
|
9165
|
-
if ('source' in layer)
|
|
9129
|
+
if ('source' in layer)
|
|
9166
9130
|
frameFullyLoaded = frameFullyLoaded && layer.source.readyState >= 2;
|
|
9167
|
-
}
|
|
9168
9131
|
layer.render();
|
|
9169
9132
|
// if the layer has visual component
|
|
9170
9133
|
if (layer instanceof Visual) {
|
|
9171
9134
|
var canvas = layer.canvas;
|
|
9172
9135
|
// layer.canvas.width and layer.canvas.height should already be interpolated
|
|
9173
9136
|
// if the layer has an area (else InvalidStateError from canvas)
|
|
9174
|
-
if (canvas.width * canvas.height > 0)
|
|
9137
|
+
if (canvas.width * canvas.height > 0)
|
|
9175
9138
|
this.cctx.drawImage(canvas, val(layer, 'x', reltime), val(layer, 'y', reltime), canvas.width, canvas.height);
|
|
9176
|
-
}
|
|
9177
9139
|
}
|
|
9178
9140
|
}
|
|
9179
9141
|
return frameFullyLoaded;
|
|
@@ -9183,9 +9145,8 @@ var Movie = /** @class */ (function () {
|
|
|
9183
9145
|
var effect = this.effects[i];
|
|
9184
9146
|
// An effect that has been deleted before effects.length has been updated
|
|
9185
9147
|
// (see the effectsproxy in the constructor).
|
|
9186
|
-
if (!effect)
|
|
9148
|
+
if (!effect)
|
|
9187
9149
|
continue;
|
|
9188
|
-
}
|
|
9189
9150
|
effect.apply(this, this.currentTime);
|
|
9190
9151
|
}
|
|
9191
9152
|
};
|
|
@@ -9204,9 +9165,9 @@ var Movie = /** @class */ (function () {
|
|
|
9204
9165
|
* Convienence method
|
|
9205
9166
|
*/
|
|
9206
9167
|
Movie.prototype._publishToLayers = function (type, event) {
|
|
9207
|
-
for (var i = 0; i < this.layers.length; i++)
|
|
9208
|
-
|
|
9209
|
-
|
|
9168
|
+
for (var i = 0; i < this.layers.length; i++)
|
|
9169
|
+
if (Object.prototype.hasOwnProperty.call(this.layers, i))
|
|
9170
|
+
publish(this.layers[i], type, event);
|
|
9210
9171
|
};
|
|
9211
9172
|
Object.defineProperty(Movie.prototype, "rendering", {
|
|
9212
9173
|
/**
|
|
@@ -9319,13 +9280,11 @@ var Movie = /** @class */ (function () {
|
|
|
9319
9280
|
return new Promise(function (resolve, reject) {
|
|
9320
9281
|
_this._currentTime = time;
|
|
9321
9282
|
publish(_this, 'movie.seek', {});
|
|
9322
|
-
if (refresh)
|
|
9283
|
+
if (refresh)
|
|
9323
9284
|
// Pass promise callbacks to `refresh`
|
|
9324
9285
|
_this.refresh().then(resolve).catch(reject);
|
|
9325
|
-
|
|
9326
|
-
else {
|
|
9286
|
+
else
|
|
9327
9287
|
resolve();
|
|
9328
|
-
}
|
|
9329
9288
|
});
|
|
9330
9289
|
};
|
|
9331
9290
|
Object.defineProperty(Movie.prototype, "canvas", {
|