Sebastiankay commited on
Commit
52ae39e
1 Parent(s): e69040c

Upload 20 files

Browse files
js/align.js ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Center line reference
2
+ function initLines() {
3
+ if (canvas.getItemById('center_h')) {
4
+ canvas.remove(canvas.getItemById('center_h'));
5
+ canvas.remove(canvas.getItemById('center_v'));
6
+ }
7
+ if (canvas.getItemById('line_h')) {
8
+ canvas.remove(canvas.getItemById('line_h'));
9
+ canvas.remove(canvas.getItemById('line_v'));
10
+ }
11
+
12
+ // Canvas center reference
13
+ canvas.add(
14
+ new fabric.Line(
15
+ [
16
+ canvas.get('width') / 2,
17
+ 0,
18
+ canvas.get('width') / 2,
19
+ canvas.get('height'),
20
+ ],
21
+ {
22
+ opacity: 0,
23
+ selectable: false,
24
+ evented: false,
25
+ id: 'center_h',
26
+ }
27
+ )
28
+ );
29
+ canvas.add(
30
+ new fabric.Line(
31
+ [
32
+ 0,
33
+ canvas.get('height') / 2,
34
+ canvas.get('width'),
35
+ canvas.get('height') / 2,
36
+ ],
37
+ {
38
+ opacity: 0,
39
+ selectable: false,
40
+ evented: false,
41
+ id: 'center_v',
42
+ }
43
+ )
44
+ );
45
+
46
+ // Canvas alignemnt guides
47
+ line_h = new fabric.Line(
48
+ [
49
+ canvas.get('width') / 2,
50
+ artboard.get('top'),
51
+ canvas.get('width') / 2,
52
+ artboard.get('height') + artboard.get('top'),
53
+ ],
54
+ {
55
+ stroke: 'red',
56
+ opacity: 0,
57
+ selectable: false,
58
+ evented: false,
59
+ id: 'line_h',
60
+ }
61
+ );
62
+ line_v = new fabric.Line(
63
+ [
64
+ artboard.get('left'),
65
+ canvas.get('height') / 2,
66
+ artboard.get('width') + artboard.get('left'),
67
+ canvas.get('height') / 2,
68
+ ],
69
+ {
70
+ stroke: 'red',
71
+ opacity: 0,
72
+ selectable: false,
73
+ evented: false,
74
+ id: 'line_v',
75
+ }
76
+ );
77
+ canvas.add(line_h);
78
+ canvas.add(line_v);
79
+ }
80
+
81
+ function alignControls(object, type) {
82
+ if (type == 'align-top') {
83
+ object.set(
84
+ 'top',
85
+ artboard.get('top') +
86
+ (object.get('height') * object.get('scaleY')) / 2
87
+ );
88
+ } else if (type == 'align-center-v') {
89
+ object.set(
90
+ 'top',
91
+ artboard.get('top') + artboard.get('height') / 2
92
+ );
93
+ } else if (type == 'align-bottom') {
94
+ object.set(
95
+ 'top',
96
+ artboard.get('top') +
97
+ artboard.get('height') -
98
+ (object.get('height') * object.get('scaleY')) / 2
99
+ );
100
+ } else if (type == 'align-left') {
101
+ object.set(
102
+ 'left',
103
+ artboard.get('left') +
104
+ (object.get('width') * object.get('scaleX')) / 2
105
+ );
106
+ } else if (type == 'align-center-h') {
107
+ object.set(
108
+ 'left',
109
+ artboard.get('left') + artboard.get('width') / 2
110
+ );
111
+ } else {
112
+ object.set(
113
+ 'left',
114
+ artboard.get('left') +
115
+ artboard.get('width') -
116
+ (object.get('width') * object.get('scaleX')) / 2
117
+ );
118
+ }
119
+ }
120
+
121
+ // Align object
122
+ function alignObject() {
123
+ const type = $(this).attr('id');
124
+ const object = canvas.getActiveObject();
125
+ console.log(canvas.getActiveObject().type);
126
+ if (canvas.getActiveObject().type == 'activeSelection') {
127
+ const tempselection = canvas.getActiveObject();
128
+ canvas.discardActiveObject();
129
+ tempselection._objects.forEach(function (object) {
130
+ alignControls(object, type);
131
+ canvas.renderAll();
132
+ newKeyframe(
133
+ 'left',
134
+ object,
135
+ currenttime,
136
+ object.get('left'),
137
+ true
138
+ );
139
+ newKeyframe(
140
+ 'top',
141
+ object,
142
+ currenttime,
143
+ object.get('top'),
144
+ true
145
+ );
146
+ });
147
+ reselect(tempselection);
148
+ } else {
149
+ alignControls(object, type);
150
+ canvas.renderAll();
151
+ newKeyframe(
152
+ 'left',
153
+ object,
154
+ currenttime,
155
+ object.get('left'),
156
+ true
157
+ );
158
+ newKeyframe('top', object, currenttime, object.get('top'), true);
159
+ }
160
+ }
161
+ $(document).on('click', '.align', alignObject);
162
+
163
+ // Alignment guides
164
+ function centerLines(e) {
165
+ if (!cropping) {
166
+ line_h.opacity = 0;
167
+ line_v.opacity = 0;
168
+ canvas.renderAll();
169
+ const snapZone = 5;
170
+ const obj_left = e.target.left;
171
+ const obj_top = e.target.top;
172
+ const obj_width = e.target.get('width') * e.target.get('scaleX');
173
+ const obj_height =
174
+ e.target.get('height') * e.target.get('scaleY');
175
+ canvas.forEachObject(function (obj, index, array) {
176
+ // Check for horizontal snapping
177
+ function checkHSnap(a, b, snapZone, e, type) {
178
+ if (a > b - snapZone && a < b + snapZone) {
179
+ line_h.opacity = 1;
180
+ line_h.bringToFront();
181
+ var value = b;
182
+ if (type == 1) {
183
+ value = b;
184
+ } else if (type == 2) {
185
+ value =
186
+ b -
187
+ (e.target.get('width') * e.target.get('scaleX')) / 2;
188
+ } else if (type == 3) {
189
+ value =
190
+ b +
191
+ (e.target.get('width') * e.target.get('scaleX')) / 2;
192
+ }
193
+ e.target
194
+ .set({
195
+ left: value,
196
+ })
197
+ .setCoords();
198
+ line_h
199
+ .set({
200
+ x1: b,
201
+ y1: artboard.get('top'),
202
+ x2: b,
203
+ y2: artboard.get('height') + artboard.get('top'),
204
+ })
205
+ .setCoords();
206
+ canvas.renderAll();
207
+ }
208
+ }
209
+
210
+ // Check for vertical snapping
211
+ function checkVSnap(a, b, snapZone, e, type) {
212
+ if (a > b - snapZone && a < b + snapZone) {
213
+ line_v.opacity = 1;
214
+ line_v.bringToFront();
215
+ var value = b;
216
+ if (type == 1) {
217
+ value = b;
218
+ } else if (type == 2) {
219
+ value =
220
+ b -
221
+ (e.target.get('height') * e.target.get('scaleY')) / 2;
222
+ } else if (type == 3) {
223
+ value =
224
+ b +
225
+ (e.target.get('height') * e.target.get('scaleY')) / 2;
226
+ }
227
+ e.target
228
+ .set({
229
+ top: value,
230
+ })
231
+ .setCoords();
232
+ line_v
233
+ .set({
234
+ y1: b,
235
+ x1: artboard.get('left'),
236
+ y2: b,
237
+ x2: artboard.get('width') + artboard.get('left'),
238
+ })
239
+ .setCoords();
240
+ canvas.renderAll();
241
+ }
242
+ }
243
+ if (obj != e.target && obj != line_h && obj != line_v) {
244
+ if (
245
+ obj.get('id') == 'center_h' ||
246
+ obj.get('id') == 'center_v'
247
+ ) {
248
+ var check1 = [[obj_left, obj.get('left'), 1]];
249
+ var check2 = [[obj_top, obj.get('top'), 1]];
250
+
251
+ for (var i = 0; i < check1.length; i++) {
252
+ checkHSnap(
253
+ check1[i][0],
254
+ check1[i][1],
255
+ snapZone,
256
+ e,
257
+ check1[i][2]
258
+ );
259
+ checkVSnap(
260
+ check2[i][0],
261
+ check2[i][1],
262
+ snapZone,
263
+ e,
264
+ check2[i][2]
265
+ );
266
+ }
267
+ } else {
268
+ var check1 = [
269
+ [obj_left, obj.get('left'), 1],
270
+ [
271
+ obj_left,
272
+ obj.get('left') +
273
+ (obj.get('width') * obj.get('scaleX')) / 2,
274
+ 1,
275
+ ],
276
+ [
277
+ obj_left,
278
+ obj.get('left') -
279
+ (obj.get('width') * obj.get('scaleX')) / 2,
280
+ 1,
281
+ ],
282
+ [obj_left + obj_width / 2, obj.get('left'), 2],
283
+ [
284
+ obj_left + obj_width / 2,
285
+ obj.get('left') +
286
+ (obj.get('width') * obj.get('scaleX')) / 2,
287
+ 2,
288
+ ],
289
+ [
290
+ obj_left + obj_width / 2,
291
+ obj.get('left') -
292
+ (obj.get('width') * obj.get('scaleX')) / 2,
293
+ 2,
294
+ ],
295
+ [obj_left - obj_width / 2, obj.get('left'), 3],
296
+ [
297
+ obj_left - obj_width / 2,
298
+ obj.get('left') +
299
+ (obj.get('width') * obj.get('scaleX')) / 2,
300
+ 3,
301
+ ],
302
+ [
303
+ obj_left - obj_width / 2,
304
+ obj.get('left') -
305
+ (obj.get('width') * obj.get('scaleX')) / 2,
306
+ 3,
307
+ ],
308
+ ];
309
+ var check2 = [
310
+ [obj_top, obj.get('top'), 1],
311
+ [
312
+ obj_top,
313
+ obj.get('top') +
314
+ (obj.get('height') * obj.get('scaleY')) / 2,
315
+ 1,
316
+ ],
317
+ [
318
+ obj_top,
319
+ obj.get('top') -
320
+ (obj.get('height') * obj.get('scaleY')) / 2,
321
+ 1,
322
+ ],
323
+ [obj_top + obj_height / 2, obj.get('top'), 2],
324
+ [
325
+ obj_top + obj_height / 2,
326
+ obj.get('top') +
327
+ (obj.get('height') * obj.get('scaleY')) / 2,
328
+ 2,
329
+ ],
330
+ [
331
+ obj_top + obj_height / 2,
332
+ obj.get('top') -
333
+ (obj.get('height') * obj.get('scaleY')) / 2,
334
+ 2,
335
+ ],
336
+ [obj_top - obj_height / 2, obj.get('top'), 3],
337
+ [
338
+ obj_top - obj_height / 2,
339
+ obj.get('top') +
340
+ (obj.get('height') * obj.get('scaleY')) / 2,
341
+ 3,
342
+ ],
343
+ [
344
+ obj_top - obj_height / 2,
345
+ obj.get('top') -
346
+ (obj.get('height') * obj.get('scaleY')) / 2,
347
+ 3,
348
+ ],
349
+ ];
350
+
351
+ for (var i = 0; i < check1.length; i++) {
352
+ checkHSnap(
353
+ check1[i][0],
354
+ check1[i][1],
355
+ snapZone,
356
+ e,
357
+ check1[i][2]
358
+ );
359
+ checkVSnap(
360
+ check2[i][0],
361
+ check2[i][1],
362
+ snapZone,
363
+ e,
364
+ check2[i][2]
365
+ );
366
+ }
367
+ }
368
+ }
369
+ });
370
+ }
371
+ }
js/converter.js ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var workerPath =
2
+ 'https://archive.org/download/ffmpeg_asm/ffmpeg_asm.js';
3
+
4
+ function processInWebWorker() {
5
+ var blob = URL.createObjectURL(
6
+ new Blob(
7
+ [
8
+ 'importScripts("' +
9
+ workerPath +
10
+ '");var now = Date.now;function print(text) {postMessage({"type" : "stdout","data" : text});};onmessage = function(event) {var message = event.data;if (message.type === "command") {var Module = {print: print,printErr: print,files: message.files || [],arguments: message.arguments || [],TOTAL_MEMORY: message.TOTAL_MEMORY||536870912 || false};postMessage({"type" : "start","data" : Module.arguments.join(" ")});postMessage({"type" : "stdout","data" : "Received command: " +Module.arguments.join(" ") +((Module.TOTAL_MEMORY ) ? ". Processing with " + Module.TOTAL_MEMORY + " bits." : "")});var time = now();var result = ffmpeg_run(Module);var totalTime = now() - time;postMessage({"type" : "stdout","data" : "Finished processing (took " + totalTime + "ms)"});postMessage({"type" : "done","data" : result,"time" : totalTime});}};postMessage({"type" : "ready"});',
11
+ ],
12
+ {
13
+ type: 'application/javascript',
14
+ }
15
+ )
16
+ );
17
+
18
+ var worker = new Worker(blob);
19
+ URL.revokeObjectURL(blob);
20
+ return worker;
21
+ }
22
+
23
+ var worker;
24
+
25
+ function convertStreams(videoBlob, setting) {
26
+ var aab;
27
+ var buffersReady;
28
+ var workerReady;
29
+ var posted;
30
+
31
+ var fileReader = new FileReader();
32
+ fileReader.onload = function () {
33
+ aab = this.result;
34
+ postMessage();
35
+ };
36
+ fileReader.readAsArrayBuffer(videoBlob);
37
+
38
+ if (!worker) {
39
+ worker = processInWebWorker();
40
+ }
41
+ worker.onmessage = function (event) {
42
+ var message = event.data;
43
+ if (message.type == 'ready') {
44
+ workerReady = true;
45
+ if (buffersReady) postMessage();
46
+ } else if (message.type == 'done') {
47
+ var result = message.data[0];
48
+ if (setting == 'gif') {
49
+ var blob = new File([result.data], 'test.gif', {
50
+ type: 'image/gif',
51
+ });
52
+ PostBlob(blob);
53
+ } else if (setting == 'mp4') {
54
+ var blob = new File([result.data], 'test.mp4', {
55
+ type: 'video/mp4',
56
+ });
57
+ PostBlob(blob);
58
+ }
59
+ }
60
+ };
61
+ var postMessage = function () {
62
+ posted = true;
63
+ if (setting == 'gif') {
64
+ worker.postMessage({
65
+ type: 'command',
66
+ arguments: '-i video.webm -r 24 output-10.gif'.split(' '),
67
+ files: [
68
+ {
69
+ data: new Uint8Array(aab),
70
+ name: 'video.webm',
71
+ },
72
+ ],
73
+ });
74
+ } else if (setting == 'mp4') {
75
+ worker.postMessage({
76
+ type: 'command',
77
+ arguments:
78
+ '-i video.webm -c:v mpeg4 -b:v 6400k -strict experimental output.mp4'.split(
79
+ ' '
80
+ ),
81
+ files: [
82
+ {
83
+ data: new Uint8Array(aab),
84
+ name: 'video.webm',
85
+ },
86
+ ],
87
+ });
88
+ }
89
+ };
90
+ }
91
+
92
+ function PostBlob(blob) {
93
+ var url = URL.createObjectURL(blob);
94
+ const a = document.createElement('a');
95
+ a.style.display = 'none';
96
+ a.href = url;
97
+ a.download = name;
98
+ document.body.appendChild(a);
99
+ a.click();
100
+ recording = false;
101
+ currenttime = 0;
102
+ animate(false, 0);
103
+ $('#seekbar').offset({
104
+ left:
105
+ offset_left +
106
+ $('#inner-timeline').offset().left +
107
+ currenttime / timelinetime,
108
+ });
109
+ canvas.renderAll();
110
+ resizeCanvas();
111
+ if (background_audio != false) {
112
+ background_audio.pause();
113
+ background_audio = new Audio(background_audio.src);
114
+ }
115
+ $('#download-real').html('Download');
116
+ $('#download-real').removeClass('downloading');
117
+ updateRecordCanvas();
118
+ }
js/database.js ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // For debugging purposes
2
+ db.config.debug = false;
3
+
4
+ // Check if a project exists
5
+ function checkDB() {
6
+ db.collection('projects')
7
+ .get()
8
+ .then((project) => {
9
+ if (project.length == 0) {
10
+ canvas.clipPath = null;
11
+ const inst = canvas.toDatalessJSON([
12
+ 'volume',
13
+ 'audioSrc',
14
+ 'defaultLeft',
15
+ 'defaultTop',
16
+ 'defaultScaleX',
17
+ 'defaultScaleY',
18
+ 'notnew',
19
+ 'starttime',
20
+ 'top',
21
+ 'left',
22
+ 'width',
23
+ 'height',
24
+ 'scaleX',
25
+ 'scaleY',
26
+ 'flipX',
27
+ 'flipY',
28
+ 'originX',
29
+ 'originY',
30
+ 'transformMatrix',
31
+ 'stroke',
32
+ 'strokeWidth',
33
+ 'strokeDashArray',
34
+ 'strokeLineCap',
35
+ 'strokeDashOffset',
36
+ 'strokeLineJoin',
37
+ 'strokeMiterLimit',
38
+ 'angle',
39
+ 'opacity',
40
+ 'fill',
41
+ 'globalCompositeOperation',
42
+ 'shadow',
43
+ 'clipTo',
44
+ 'visible',
45
+ 'backgroundColor',
46
+ 'skewX',
47
+ 'skewY',
48
+ 'fillRule',
49
+ 'paintFirst',
50
+ 'strokeUniform',
51
+ 'rx',
52
+ 'ry',
53
+ 'selectable',
54
+ 'hasControls',
55
+ 'subTargetCheck',
56
+ 'id',
57
+ 'hoverCursor',
58
+ 'defaultCursor',
59
+ 'filesrc',
60
+ 'isEditing',
61
+ 'source',
62
+ 'assetType',
63
+ 'duration',
64
+ 'inGroup',
65
+ 'filters',
66
+ ]);
67
+ canvas.clipPath = artboard;
68
+ db.collection('projects').add({
69
+ id: 1,
70
+ canvas: JSON.stringify(inst),
71
+ keyframes: JSON.stringify(keyframes.slice()),
72
+ p_keyframes: JSON.stringify(p_keyframes.slice()),
73
+ objects: JSON.stringify(objects.slice()),
74
+ colormode: colormode,
75
+ speed: speed,
76
+ duration: duration,
77
+ currenttime: currenttime,
78
+ layercount: layer_count,
79
+ width: artboard.width,
80
+ height: artboard.height,
81
+ animatedtext: JSON.stringify(animatedtext),
82
+ groups: JSON.stringify(groups),
83
+ files: JSON.stringify(files),
84
+ activepreset: activepreset,
85
+ });
86
+ checkstatus = true;
87
+ getAssets();
88
+ } else {
89
+ loadProject();
90
+ }
91
+ });
92
+ }
93
+
94
+ // Automatically save project (locally)
95
+ function autoSave() {
96
+ if (checkstatus) {
97
+ canvas.clipPath = null;
98
+ objects.forEach(async function (object) {
99
+ var obj = canvas.getItemById(object.id);
100
+ if (obj.filters) {
101
+ if (obj.filters.length > 0) {
102
+ object.filters = [];
103
+ obj.filters.forEach(function (filter) {
104
+ if (
105
+ filter.type == 'BlackWhite' ||
106
+ filter.type == 'Invert' ||
107
+ filter.type == 'Sepia' ||
108
+ filter.type == 'Kodachrome' ||
109
+ filter.type == 'Polaroid' ||
110
+ filter.type == 'Technicolor' ||
111
+ filter.type == 'Brownie' ||
112
+ filter.type == 'Vintage'
113
+ ) {
114
+ object.filters.push({ type: filter.type });
115
+ } else if (filter.type == 'Brightness') {
116
+ object.filters.push({
117
+ type: filter.type,
118
+ value: filter.brightness,
119
+ });
120
+ } else if (filter.type == 'Contrast') {
121
+ object.filters.push({
122
+ type: filter.type,
123
+ value: filter.contrast,
124
+ });
125
+ } else if (filter.type == 'Vibrance') {
126
+ object.filters.push({
127
+ type: filter.type,
128
+ value: filter.vibrance,
129
+ });
130
+ } else if (filter.type == 'Saturation') {
131
+ object.filters.push({
132
+ type: filter.type,
133
+ value: filter.saturation,
134
+ });
135
+ } else if (filter.type == 'HueRotation') {
136
+ object.filters.push({
137
+ type: filter.type,
138
+ value: filter.rotation,
139
+ });
140
+ } else if (filter.type == 'Blur') {
141
+ object.filters.push({
142
+ type: filter.type,
143
+ value: filter.blur,
144
+ });
145
+ } else if (filter.type == 'Noise') {
146
+ object.filters.push({
147
+ type: filter.type,
148
+ value: filter.noise,
149
+ });
150
+ } else if (filter.type == 'RemoveColor') {
151
+ object.filters.push({
152
+ type: filter.type,
153
+ distance: filter.distance,
154
+ color: filter.color,
155
+ });
156
+ }
157
+ });
158
+ obj.filters = [];
159
+ obj.applyFilters();
160
+ var backend = fabric.filterBackend;
161
+ if (backend && backend.evictCachesForKey) {
162
+ backend.evictCachesForKey(obj.cacheKey);
163
+ backend.evictCachesForKey(obj.cacheKey + '_filtered');
164
+ }
165
+ if (
166
+ obj.filters.length > 0 &&
167
+ obj.get('id').indexOf('Video') >= 0
168
+ ) {
169
+ await obj.setElement(obj.saveElem);
170
+ }
171
+ } else {
172
+ object.filters = [];
173
+ }
174
+ } else {
175
+ object.filters = [];
176
+ }
177
+ });
178
+ const inst = canvas.toDatalessJSON([
179
+ 'volume',
180
+ 'audioSrc',
181
+ 'defaultLeft',
182
+ 'defaultTop',
183
+ 'defaultScaleX',
184
+ 'defaultScaleY',
185
+ 'notnew',
186
+ 'starttime',
187
+ 'top',
188
+ 'left',
189
+ 'width',
190
+ 'height',
191
+ 'scaleX',
192
+ 'scaleY',
193
+ 'flipX',
194
+ 'flipY',
195
+ 'originX',
196
+ 'originY',
197
+ 'transformMatrix',
198
+ 'stroke',
199
+ 'strokeWidth',
200
+ 'strokeDashArray',
201
+ 'strokeLineCap',
202
+ 'strokeDashOffset',
203
+ 'strokeLineJoin',
204
+ 'strokeMiterLimit',
205
+ 'angle',
206
+ 'opacity',
207
+ 'fill',
208
+ 'globalCompositeOperation',
209
+ 'shadow',
210
+ 'clipTo',
211
+ 'visible',
212
+ 'backgroundColor',
213
+ 'skewX',
214
+ 'skewY',
215
+ 'fillRule',
216
+ 'paintFirst',
217
+ 'strokeUniform',
218
+ 'rx',
219
+ 'ry',
220
+ 'selectable',
221
+ 'hasControls',
222
+ 'subTargetCheck',
223
+ 'id',
224
+ 'hoverCursor',
225
+ 'defaultCursor',
226
+ 'filesrc',
227
+ 'isEditing',
228
+ 'source',
229
+ 'assetType',
230
+ 'duration',
231
+ 'inGroup',
232
+ ]);
233
+ canvas.clipPath = artboard;
234
+ db.collection('projects')
235
+ .doc({ id: 1 })
236
+ .update({
237
+ canvas: JSON.stringify(inst),
238
+ keyframes: JSON.stringify(keyframes.slice()),
239
+ p_keyframes: JSON.stringify(p_keyframes.slice()),
240
+ objects: JSON.stringify(objects.slice()),
241
+ colormode: colormode,
242
+ duration: duration,
243
+ currenttime: currenttime,
244
+ layercount: layer_count,
245
+ speed: speed,
246
+ audiosrc: background_key,
247
+ animatedtext: JSON.stringify(animatedtext),
248
+ files: JSON.stringify(files),
249
+ groups: JSON.stringify(groups),
250
+ activepreset: activepreset,
251
+ width: artboard.width,
252
+ height: artboard.height,
253
+ });
254
+ objects.forEach(function (object) {
255
+ replaceSource(canvas.getItemById(object.id), canvas);
256
+ });
257
+ }
258
+ }
259
+
260
+ var isSameSet = function (arr1, arr2) {
261
+ return (
262
+ $(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0
263
+ );
264
+ };
265
+
266
+ function loadProject() {
267
+ db.collection('projects')
268
+ .doc({ id: 1 })
269
+ .get()
270
+ .then((document) => {
271
+ var project = document;
272
+ keyframes = JSON.parse(project.keyframes);
273
+ p_keyframes = JSON.parse(project.p_keyframes);
274
+ objects = JSON.parse(project.objects);
275
+ files = JSON.parse(project.files);
276
+ colormode = project.colormode;
277
+ duration = project.duration;
278
+ layer_count = project.layercount;
279
+ speed = project.speed;
280
+ animatedtext = JSON.parse(project.animatedtext);
281
+ animatedtext.forEach(function (text, index) {
282
+ var temp = new AnimatedText(text.text, text.props);
283
+ temp.assignTo(text.id);
284
+ animatedtext[index] = temp;
285
+ });
286
+ $('#speed span').html(speed.toFixed(1) + 'x');
287
+ groups = JSON.parse(project.groups);
288
+ activepreset = project.activepreset;
289
+ currenttime = 0;
290
+ canvas.clipPath = null;
291
+ canvas.clear();
292
+ fabric.filterBackend = webglBackend;
293
+ f = fabric.Image.filters;
294
+ canvas.loadFromJSON(JSON.parse(project.canvas), function () {
295
+ canvas.clipPath = artboard;
296
+ canvas.getItemById('line_h').set({ opacity: 0 });
297
+ canvas.getItemById('line_v').set({ opacity: 0 });
298
+ canvas.renderAll();
299
+ $('.object-props').remove();
300
+ $('.layer').remove();
301
+ objects.forEach(function (object) {
302
+ var animatethis = false;
303
+ if (object.animate.length > 5) {
304
+ if (isSameSet(object.animate, props)) {
305
+ animatethis = true;
306
+ }
307
+ }
308
+ renderLayer(canvas.getItemById(object.id), animatethis);
309
+ if (
310
+ !canvas.getItemById(object.id).get('assetType') ||
311
+ canvas.getItemById(object.id).get('assetType') != 'audio'
312
+ ) {
313
+ props.forEach(function (prop) {
314
+ if (
315
+ prop != 'top' &&
316
+ prop != 'scaleY' &&
317
+ prop != 'width' &&
318
+ prop != 'height' &&
319
+ prop != 'shadow.offsetX' &&
320
+ prop != 'shadow.offsetY' &&
321
+ prop != 'shadow.opacity' &&
322
+ prop != 'shadow.blur' &&
323
+ prop != 'lineHeight'
324
+ ) {
325
+ renderProp(prop, canvas.getItemById(object.id));
326
+ }
327
+ });
328
+ replaceSource(canvas.getItemById(object.id), canvas);
329
+ } else {
330
+ renderProp('volume', canvas.getItemById(object.id));
331
+ }
332
+ });
333
+ keyframes.forEach(function (keyframe) {
334
+ if (
335
+ keyframe.name != 'top' &&
336
+ keyframe.name != 'scaleY' &&
337
+ keyframe.name != 'width' &&
338
+ keyframe.name != 'height' &&
339
+ keyframe.name != 'shadow.offsetX' &&
340
+ keyframe.name != 'shadow.offsetY' &&
341
+ keyframe.name != 'shadow.opacity' &&
342
+ keyframe.name != 'shadow.blur' &&
343
+ keyframe.name != 'lineHeight'
344
+ ) {
345
+ renderKeyframe(
346
+ canvas.getItemById(keyframe.id),
347
+ keyframe.name,
348
+ keyframe.t
349
+ );
350
+ }
351
+ });
352
+ artboard.set({
353
+ width: project.width,
354
+ height: project.height,
355
+ });
356
+ canvas.renderAll();
357
+ resizeCanvas();
358
+ updatePanel();
359
+
360
+ animatedtext.forEach(function (text, index) {
361
+ text.reset(text.text, text.props, canvas);
362
+ canvas.renderAll();
363
+ });
364
+
365
+ // Set defaults
366
+ setDuration(duration);
367
+ setTimelineZoom(5);
368
+ checkstatus = true;
369
+
370
+ getAssets();
371
+
372
+ canvas.renderAll();
373
+
374
+ animate(false, 0);
375
+
376
+ //newLottieAnimation(100,100);
377
+ });
378
+ });
379
+ }
380
+
381
+ function blobToBase64(blob) {
382
+ return new Promise((resolve, _) => {
383
+ const reader = new FileReader();
384
+ reader.onloadend = () => resolve(reader.result);
385
+ reader.readAsDataURL(blob);
386
+ });
387
+ }
388
+
389
+ async function saveFile(thumbnail, file, type, name, place, hidden) {
390
+ file = await blobToBase64(file);
391
+ thumbnail = await blobToBase64(thumbnail);
392
+ uploading = false;
393
+ var key = Math.random().toString(36).substr(2, 9);
394
+ db.collection('assets').add({
395
+ key: key,
396
+ src: file,
397
+ thumb: thumbnail,
398
+ name: name,
399
+ type: type,
400
+ hidden: hidden,
401
+ });
402
+ if (type === 'image') {
403
+ uploaded_images.push({
404
+ src: file,
405
+ thumb: thumbnail,
406
+ key: key,
407
+ type: 'image',
408
+ hidden: false,
409
+ });
410
+ populateGrid('images-tab');
411
+ } else if (type === 'video') {
412
+ uploaded_videos.push({
413
+ src: file,
414
+ thumb: thumbnail,
415
+ key: key,
416
+ type: 'video',
417
+ hidden: false,
418
+ });
419
+ populateGrid('videos-tab');
420
+ }
421
+ $('#upload-button').html(
422
+ "<img src='assets/upload.svg'> Upload media"
423
+ );
424
+ $('#upload-button').removeClass('uploading');
425
+ if (place) {
426
+ loadImage(
427
+ file,
428
+ artboard.get('left') + artboard.get('width') / 2,
429
+ artboard.get('top') + artboard.get('height') / 2,
430
+ 200
431
+ );
432
+ }
433
+ save();
434
+ }
435
+
436
+ async function savePixabayImage(url, xpos, ypos, width) {
437
+ $('#load-image').addClass('loading-active');
438
+ fetch(url)
439
+ .then((res) => res.blob())
440
+ .then((blob) => {
441
+ url = blob;
442
+ var reader = new FileReader();
443
+ reader.readAsDataURL(blob);
444
+ reader.onloadend = function () {
445
+ url = reader.result;
446
+ var key = Math.random().toString(36).substr(2, 9);
447
+ db.collection('assets').add({
448
+ key: key,
449
+ src: url,
450
+ thumb: url,
451
+ name: 'test',
452
+ type: 'image',
453
+ hidden: true,
454
+ });
455
+ loadImage(url, xpos, ypos, width, false);
456
+ };
457
+ });
458
+ }
459
+
460
+ async function saveAudio(url) {
461
+ var reader = new FileReader();
462
+ reader.readAsDataURL(url);
463
+ reader.onloadend = function () {
464
+ var key = Math.random().toString(36).substr(2, 9);
465
+ db.collection('assets').add({
466
+ key: key,
467
+ src: reader.result,
468
+ name: 'test',
469
+ type: 'audio',
470
+ hidden: true,
471
+ });
472
+ newAudioLayer(reader.result);
473
+ };
474
+ }
475
+
476
+ async function savePixabayVideo(url, thumb, x, y) {
477
+ $('#load-video').addClass('loading-active');
478
+ fetch(url)
479
+ .then((res) => res.blob())
480
+ .then((blob) => {
481
+ var reader = new FileReader();
482
+ reader.readAsDataURL(blob);
483
+ reader.onloadend = function () {
484
+ fetch(thumb)
485
+ .then((res) => res.blob())
486
+ .then((blob2) => {
487
+ var reader2 = new FileReader();
488
+ reader2.readAsDataURL(blob2);
489
+ reader2.onloadend = function () {
490
+ url = reader.result;
491
+ thumb = reader2.result;
492
+ var key = Math.random().toString(36).substr(2, 9);
493
+ db.collection('assets').add({
494
+ key: key,
495
+ src: url,
496
+ thumb: thumb,
497
+ name: 'test',
498
+ type: 'video',
499
+ hidden: true,
500
+ });
501
+ loadVideo(url, x, y, false);
502
+ };
503
+ });
504
+ };
505
+ });
506
+ }
507
+
508
+ function deleteAsset(key) {
509
+ db.collection('assets')
510
+ .doc({ key: key })
511
+ .get()
512
+ .then((asset) => {
513
+ var temp = files.filter((x) => x.file == asset.src);
514
+ if (temp.length > 0) {
515
+ temp.forEach(function (file) {
516
+ deleteObject(canvas.getItemById(file.name));
517
+ files = $.grep(files, function (a) {
518
+ return a != file;
519
+ });
520
+ });
521
+ }
522
+ db.collection('assets').doc({ key: key }).delete();
523
+ if (asset.type == 'image') {
524
+ uploaded_images = uploaded_images.filter(function (obj) {
525
+ return obj.key !== key;
526
+ });
527
+ populateGrid('images-tab');
528
+ } else {
529
+ uploaded_videos = uploaded_videos.filter(function (obj) {
530
+ return obj.key !== key;
531
+ });
532
+ populateGrid('videos-tab');
533
+ }
534
+ });
535
+ }
536
+
537
+ function getAssets() {
538
+ db.collection('assets')
539
+ .get()
540
+ .then((assets) => {
541
+ // Sometimes the assets aren't ready when importing, really annoying
542
+ if (assets === undefined) {
543
+ getAssets();
544
+ } else if (assets.length > 0) {
545
+ assets.forEach(function (asset) {
546
+ if (asset.type == 'image') {
547
+ uploaded_images.push({
548
+ src: asset.src,
549
+ thumb: asset.thumb,
550
+ key: asset.key,
551
+ type: 'image',
552
+ hidden: asset.hidden,
553
+ });
554
+ } else if (asset.type == 'video') {
555
+ uploaded_videos.push({
556
+ src: asset.src,
557
+ thumb: asset.thumb,
558
+ key: asset.key,
559
+ type: 'video',
560
+ hidden: asset.hidden,
561
+ });
562
+ }
563
+ });
564
+ }
565
+ });
566
+ }
567
+
568
+ function readTextFile(file, callback) {
569
+ var rawFile = new XMLHttpRequest();
570
+ rawFile.overrideMimeType('application/json');
571
+ rawFile.open('GET', file, true);
572
+ rawFile.onreadystatechange = function () {
573
+ if (rawFile.readyState === 4 && rawFile.status == '200') {
574
+ callback(rawFile.responseText);
575
+ }
576
+ };
577
+ rawFile.send(null);
578
+ }
579
+
580
+ async function importProject(e) {
581
+ $('#import-project span').html('Importing...');
582
+ var file = e.target.files[0];
583
+ var path = (window.URL || window.webkitURL).createObjectURL(file);
584
+ readTextFile(path, function (text) {
585
+ var data = JSON.parse(text);
586
+ delete data.project[0].id;
587
+ if (data.project.length > 0) {
588
+ if (data.assets.length > 0) {
589
+ data.assets.forEach(function (asset) {
590
+ delete asset.id;
591
+ db.collection('assets').add(asset);
592
+ });
593
+ }
594
+ db.collection('projects')
595
+ .doc({ id: 1 })
596
+ .update(data.project[0])
597
+ .then((response) => {
598
+ $('#import-project span').html('Import');
599
+ hideModals();
600
+ loadProject();
601
+ });
602
+ } else {
603
+ alert('Wrong file type');
604
+ }
605
+ });
606
+ }
607
+
608
+ function importHandle() {
609
+ $('#import').click();
610
+ }
611
+
612
+ function exportProject() {
613
+ $('#export-project span').html('Exporting...');
614
+ db.collection('projects')
615
+ .get()
616
+ .then((project) => {
617
+ if (project.length > 0) {
618
+ db.collection('assets')
619
+ .get()
620
+ .then((assets) => {
621
+ var exportarr = { project: project, assets: assets };
622
+ $('<a />', {
623
+ download: 'data.json',
624
+ href:
625
+ 'data:application/json,' +
626
+ encodeURIComponent(JSON.stringify(exportarr)),
627
+ })
628
+ .appendTo('body')
629
+ .click(function () {
630
+ $(this).remove();
631
+ $('#export-project span').html('Export');
632
+ })[0]
633
+ .click();
634
+ });
635
+ } else {
636
+ alert('Empty project');
637
+ $('#export-project span').html('Export');
638
+ }
639
+ });
640
+ }
641
+
642
+ $(document).on('click', '#import-project', importHandle);
643
+ $(document).on('click', '#export-project', exportProject);
644
+ $(document).on('change', '#import', importProject);
645
+
646
+ function clearProject() {
647
+ if (
648
+ window.confirm(
649
+ 'Are you sure you want to clear this project? This action cannot be undone.'
650
+ )
651
+ ) {
652
+ db.collection('projects').delete();
653
+ db.collection('assets').delete();
654
+ window.setTimeout(function () {
655
+ location.reload();
656
+ }, 1000);
657
+ }
658
+ hideMore();
659
+ }
660
+ $(document).on('click', '#clear-project', clearProject);
js/encode-worker.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ importScripts('./webm-writer2.js');
2
+
3
+ let webmWriter = null;
4
+ let fileWritableStream = null;
5
+ let frameReader = null;
6
+
7
+ async function startRecording(
8
+ fileHandle,
9
+ frameStream,
10
+ trackSettings
11
+ ) {
12
+ let frameCounter = 0;
13
+
14
+ fileWritableStream = await fileHandle.createWritable();
15
+
16
+ webmWriter = new WebMWriter({
17
+ fileWriter: fileWritableStream,
18
+ codec: 'VP9',
19
+ width: trackSettings.width,
20
+ height: trackSettings.height,
21
+ });
22
+
23
+ frameReader = frameStream.getReader();
24
+
25
+ const init = {
26
+ output: (chunk) => {
27
+ webmWriter.addFrame(chunk);
28
+ },
29
+ error: (e) => {
30
+ console.log(e.message);
31
+ stopRecording();
32
+ },
33
+ };
34
+
35
+ const config = {
36
+ codec: 'vp09.00.10.08',
37
+ width: trackSettings.width,
38
+ height: trackSettings.height,
39
+ bitrate: 10e6,
40
+ };
41
+
42
+ let encoder = new VideoEncoder(init);
43
+ let support = await VideoEncoder.isConfigSupported(config);
44
+ console.assert(support.supported);
45
+ encoder.configure(config);
46
+
47
+ frameReader
48
+ .read()
49
+ .then(async function processFrame({ done, value }) {
50
+ let frame = value;
51
+
52
+ if (done) {
53
+ await encoder.flush();
54
+ encoder.close();
55
+ return;
56
+ }
57
+
58
+ if (encoder.encodeQueueSize <= 30) {
59
+ if (++frameCounter % 20 == 0) {
60
+ console.log(frameCounter + ' frames processed');
61
+ }
62
+
63
+ const insert_keyframe = frameCounter % 150 == 0;
64
+ encoder.encode(frame, { keyFrame: insert_keyframe });
65
+ } else {
66
+ console.log('dropping frame, encoder falling behind');
67
+ }
68
+
69
+ frame.close();
70
+ frameReader.read().then(processFrame);
71
+ });
72
+ }
73
+
74
+ async function stopRecording() {
75
+ await frameReader.cancel();
76
+ await webmWriter.complete();
77
+ fileWritableStream.close();
78
+ frameReader = null;
79
+ webmWriter = null;
80
+ fileWritableStream = null;
81
+ }
82
+
83
+ self.addEventListener('message', function (e) {
84
+ switch (e.data.type) {
85
+ case 'start':
86
+ startRecording(
87
+ e.data.fileHandle,
88
+ e.data.frameStream,
89
+ e.data.trackSettings
90
+ );
91
+ break;
92
+ case 'stop':
93
+ stopRecording();
94
+ break;
95
+ }
96
+ });
js/events.js ADDED
@@ -0,0 +1,1022 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $(document).ready(function () {
2
+ // An object is being moved in the canvas
3
+ canvas.on('object:moving', function (e) {
4
+ e.target.hasControls = false;
5
+ centerLines(e);
6
+ if (cropping) {
7
+ if (
8
+ canvas.getItemById('crop').isContainedWithinObject(cropobj)
9
+ ) {
10
+ cropleft = canvas.getItemById('crop').get('left');
11
+ croptop = canvas.getItemById('crop').get('top');
12
+ cropscalex = canvas.getItemById('crop').get('scaleX');
13
+ cropscaley = canvas.getItemById('crop').get('scaleY');
14
+ }
15
+ crop(canvas.getItemById('cropped'));
16
+ } else if (
17
+ lockmovement &&
18
+ e.e.shiftKey &&
19
+ canvas.getActiveObject()
20
+ ) {
21
+ if (canvasx < shiftx + 30 && canvasx > shiftx - 30) {
22
+ canvas.getActiveObject().set({ left: shiftx });
23
+ canvas.getActiveObject().lockMovementX = true;
24
+ canvas.getActiveObject().lockMovementY = false;
25
+ } else {
26
+ canvas.getActiveObject().set({ top: shifty });
27
+ canvas.getActiveObject().lockMovementX = false;
28
+ canvas.getActiveObject().lockMovementY = true;
29
+ }
30
+ } else if (canvas.getActiveObject() && !e.e.shiftKey) {
31
+ lockmovement = false;
32
+ canvas.getActiveObject().lockMovementX = false;
33
+ canvas.getActiveObject().lockMovementY = false;
34
+ }
35
+ });
36
+
37
+ // An object is being scaled in the canvas
38
+ canvas.on('object:scaling', function (e) {
39
+ e.target.hasControls = false;
40
+ centerLines(e);
41
+ if (cropping) {
42
+ if (
43
+ canvas.getItemById('crop').isContainedWithinObject(cropobj)
44
+ ) {
45
+ cropleft = canvas.getItemById('crop').get('left');
46
+ croptop = canvas.getItemById('crop').get('top');
47
+ cropscalex = canvas.getItemById('crop').get('scaleX');
48
+ cropscaley = canvas.getItemById('crop').get('scaleY');
49
+ }
50
+ crop(canvas.getItemById('cropped'));
51
+ }
52
+ });
53
+
54
+ // An object is being resized in the canvas
55
+ canvas.on('object:resizing', function (e) {
56
+ e.target.hasControls = false;
57
+ centerLines(e);
58
+ if (cropping) {
59
+ if (
60
+ canvas.getItemById('crop').isContainedWithinObject(cropobj)
61
+ ) {
62
+ cropleft = canvas.getItemById('crop').get('left');
63
+ croptop = canvas.getItemById('crop').get('top');
64
+ cropscalex = canvas.getItemById('crop').get('scaleX');
65
+ cropscaley = canvas.getItemById('crop').get('scaleY');
66
+ }
67
+ crop(canvas.getItemById('cropped'));
68
+ }
69
+ });
70
+
71
+ // An object is being rotated in the canvas
72
+ canvas.on('object:rotating', function (e) {
73
+ if (e.e.shiftKey) {
74
+ canvas.getActiveObject().snapAngle = 15;
75
+ } else {
76
+ canvas.getActiveObject().snapAngle = 0;
77
+ }
78
+ e.target.hasControls = false;
79
+ });
80
+
81
+ // An object has been modified in the canvas
82
+ canvas.on('object:modified', function (e) {
83
+ e.target.hasControls = true;
84
+ if (!editinggroup && !cropping) {
85
+ canvas.getActiveObject().lockMovementX = false;
86
+ canvas.getActiveObject().lockMovementY = false;
87
+ canvas.renderAll();
88
+ if (e.target.type == 'activeSelection') {
89
+ const tempselection = canvas.getActiveObject();
90
+ canvas.discardActiveObject();
91
+ e.target._objects.forEach(function (object) {
92
+ autoKeyframe(object, e, true);
93
+ });
94
+ reselect(tempselection);
95
+ } else {
96
+ autoKeyframe(e.target, e, false);
97
+ }
98
+ updatePanelValues();
99
+ save();
100
+ }
101
+ if (cropping) {
102
+ var obj = e.target;
103
+ checkCrop(obj);
104
+ }
105
+ });
106
+
107
+ // A selection has been updated in the canvas
108
+ canvas.on('selection:updated', function (e) {
109
+ updatePanel(true);
110
+ updatePanelValues();
111
+ updateSelection(e);
112
+ closeFilters();
113
+ });
114
+
115
+ // A selection has been made in the canvas
116
+ canvas.on('selection:created', function (e) {
117
+ shiftx = canvas.getActiveObject().get('left');
118
+ shifty = canvas.getActiveObject().get('top');
119
+ if (!editingpanel) {
120
+ updatePanel(true);
121
+ }
122
+ updateSelection(e);
123
+ canvas.renderAll();
124
+ closeFilters();
125
+ });
126
+
127
+ // A selection has been cleared in the canvas
128
+ canvas.on('selection:cleared', function (e) {
129
+ if (!editingpanel && !setting) {
130
+ updatePanel(false);
131
+ }
132
+ $('.layer-selected').removeClass('layer-selected');
133
+ if (cropping) {
134
+ crop(cropobj);
135
+ }
136
+ closeFilters();
137
+ });
138
+
139
+ function kFormatter(num) {
140
+ return Math.abs(num) > 999
141
+ ? Math.sign(num) * (Math.abs(num) / 1000).toFixed(1) + 'k'
142
+ : Math.sign(num) * Math.abs(num);
143
+ }
144
+
145
+ // Zoom in/out of the canvas
146
+ canvas.on('mouse:wheel', function (opt) {
147
+ var delta = opt.e.deltaY;
148
+ var zoom = canvas.getZoom();
149
+ zoom *= 0.999 ** delta;
150
+ $('#zoom-level span').html(
151
+ kFormatter((zoom * 100).toFixed(0)) + '%'
152
+ );
153
+ if (zoom > 20) zoom = 20;
154
+ if (zoom < 0.01) zoom = 0.01;
155
+ canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom);
156
+ opt.e.preventDefault();
157
+ opt.e.stopPropagation();
158
+ });
159
+
160
+ // Start panning if space is down or hand tool is enabled
161
+ canvas.on('mouse:down', function (opt) {
162
+ var e = opt.e;
163
+ if (spaceDown || handtool) {
164
+ this.isDragging = true;
165
+ this.selection = false;
166
+ this.lastPosX = e.clientX;
167
+ this.lastPosY = e.clientY;
168
+ }
169
+ if (opt.target) {
170
+ opt.target.hasControls = true;
171
+ wip = false;
172
+ }
173
+ });
174
+
175
+ // Pan while dragging mouse
176
+ canvas.on('mouse:move', function (opt) {
177
+ var pointer = canvas.getPointer(opt.e);
178
+ canvasx = pointer.x;
179
+ canvasy = pointer.y;
180
+ if (this.isDragging) {
181
+ var e = opt.e;
182
+ var vpt = this.viewportTransform;
183
+ vpt[4] += e.clientX - this.lastPosX;
184
+ vpt[5] += e.clientY - this.lastPosY;
185
+ this.requestRenderAll();
186
+ this.lastPosX = e.clientX;
187
+ this.lastPosY = e.clientY;
188
+ }
189
+ });
190
+
191
+ // Stop panning
192
+ canvas.on('mouse:up', function (opt) {
193
+ this.setViewportTransform(this.viewportTransform);
194
+ this.isDragging = false;
195
+ this.selection = true;
196
+ line_h.opacity = 0;
197
+ line_v.opacity = 0;
198
+ });
199
+
200
+ // Detect mouse over canvas (for dragging objects from the library)
201
+ canvas.on('mouse:move', function (e) {
202
+ overCanvas = true;
203
+ if (
204
+ e.target &&
205
+ !canvas.getActiveObject() &&
206
+ draggingPanel &&
207
+ e.target.type == 'image'
208
+ ) {
209
+ wip = true;
210
+ e.target.hasControls = false;
211
+ canvas.setActiveObject(e.target);
212
+ }
213
+ });
214
+ canvas.on('mouse:out', function (e) {
215
+ overCanvas = false;
216
+ if (wip) {
217
+ e.target.hasControls = true;
218
+ canvas.discardActiveObject();
219
+ wip = false;
220
+ canvas.renderAll();
221
+ }
222
+ });
223
+
224
+ // Double click on image to get into cropping mode
225
+ fabric.util.addListener(
226
+ canvas.upperCanvasEl,
227
+ 'dblclick',
228
+ function (e) {
229
+ var target = canvas.findTarget(e);
230
+ if (target) {
231
+ if (target.type == 'image') {
232
+ cropImage(target);
233
+ }
234
+ }
235
+ }
236
+ );
237
+
238
+ // Key event handling
239
+ $(document)
240
+ .keyup(function (e) {
241
+ // Space bar (panning and playback)
242
+ if (
243
+ e.keyCode == 32 &&
244
+ !editinglayer &&
245
+ !editingproject &&
246
+ $(e.target)[0].tagName != 'INPUT'
247
+ ) {
248
+ spacerelease = true;
249
+ spaceDown = false;
250
+ canvas.defaultCursor = 'default';
251
+ canvas.renderAll();
252
+ if (!spacehold) {
253
+ if (
254
+ !(
255
+ canvas.getActiveObject() &&
256
+ canvas.getActiveObject().isEditing
257
+ )
258
+ ) {
259
+ if (paused) {
260
+ play();
261
+ } else {
262
+ pause();
263
+ }
264
+ }
265
+ } else {
266
+ if (!handtool) {
267
+ $('#hand-tool').removeClass('hand-active');
268
+ $('#hand-tool')
269
+ .find('img')
270
+ .attr('src', 'assets/hand-tool.svg');
271
+ }
272
+ }
273
+ spacehold = false;
274
+ }
275
+ // Delete object/keyframe
276
+ if (
277
+ (e.keyCode == 46 ||
278
+ e.key == 'Delete' ||
279
+ e.code == 'Delete' ||
280
+ e.key == 'Backspace') &&
281
+ !focus &&
282
+ !editinglayer
283
+ ) {
284
+ if (
285
+ $('.show-properties').length > 0 ||
286
+ shiftkeys.length > 0
287
+ ) {
288
+ deleteKeyframe();
289
+ } else {
290
+ deleteSelection();
291
+ }
292
+ }
293
+ // Shift key is up (stop locking horizontal/vertical object movement)
294
+ if (e.keyCode == 16) {
295
+ lockmovement = false;
296
+ shiftdown = false;
297
+ }
298
+ })
299
+ .keydown(function (e) {
300
+ // Space bar (panning and playback)
301
+ if (
302
+ e.keyCode == 32 &&
303
+ !editinglayer &&
304
+ !editingproject &&
305
+ $(e.target)[0].tagName != 'INPUT'
306
+ ) {
307
+ spacerelease = false;
308
+ spaceDown = true;
309
+ canvas.defaultCursor = 'grab';
310
+ canvas.renderAll();
311
+ window.setTimeout(function () {
312
+ if (!spacerelease) {
313
+ spacehold = true;
314
+ if (!handtool) {
315
+ $('#hand-tool').addClass('hand-active');
316
+ $('#hand-tool')
317
+ .find('img')
318
+ .attr('src', 'assets/hand-tool-active.svg');
319
+ }
320
+ }
321
+ }, 1000);
322
+ }
323
+ // Redo
324
+ if (e.which === 90 && (e.ctrlKey || e.metaKey) && e.shiftKey) {
325
+ undoRedo(redo, undo, redoarr, undoarr);
326
+ }
327
+ // Undo
328
+ if (e.which === 90 && (e.ctrlKey || e.metaKey)) {
329
+ undoRedo(undo, redo, undoarr, redoarr);
330
+ }
331
+ // Duplicate object
332
+ if (e.which === 68 && (e.ctrlKey || e.metaKey)) {
333
+ e.preventDefault();
334
+ if (canvas.getActiveObject()) {
335
+ clipboard = canvas.getActiveObject();
336
+ copyObject();
337
+ }
338
+ }
339
+ // Shift key (Lock horizontal/vertical movement for objects)
340
+ if (e.shiftKey) {
341
+ shiftdown = true;
342
+ lockmovement = true;
343
+ if (canvas.getActiveObject()) {
344
+ shiftx = canvas.getActiveObject().get('left');
345
+ shifty = canvas.getActiveObject().get('top');
346
+ }
347
+ }
348
+ // Return (save layer name)
349
+ if (e.keyCode === 13 && editinglayer) {
350
+ saveLayerName();
351
+ }
352
+ // Return (save project name)
353
+ if (e.keyCode === 13 && editingproject) {
354
+ saveProjectName();
355
+ }
356
+ // Left arrow key (move object to the left)
357
+ if (e.keyCode === 37 && canvas.getActiveObject()) {
358
+ var obj = canvas.getActiveObject();
359
+ var step = 2;
360
+ // Bigger step if shift is down
361
+ if (e.shiftKey) {
362
+ step = 7;
363
+ }
364
+ obj.left = obj.left - step;
365
+ canvas.renderAll();
366
+ autoKeyframe(obj, { action: 'drag' }, false);
367
+ }
368
+ // Up arrow key (move object up)
369
+ if (e.keyCode === 38 && canvas.getActiveObject()) {
370
+ var obj = canvas.getActiveObject();
371
+ var step = 2;
372
+ // Bigger step if shift is down
373
+ if (e.shiftKey) {
374
+ step = 7;
375
+ }
376
+ obj.top = obj.top - step;
377
+ canvas.renderAll();
378
+ autoKeyframe(obj, { action: 'drag' }, false);
379
+ }
380
+ // Right arrow key (move object to the right)
381
+ if (e.keyCode === 39 && canvas.getActiveObject()) {
382
+ var obj = canvas.getActiveObject();
383
+ var step = 2;
384
+ // Bigger step if shift is down
385
+ if (e.shiftKey) {
386
+ step = 7;
387
+ }
388
+ obj.left = obj.left + step;
389
+ canvas.renderAll();
390
+ autoKeyframe(obj, { action: 'drag' }, false);
391
+ }
392
+ // Down arrow key (move object down)
393
+ if (e.keyCode === 40 && canvas.getActiveObject()) {
394
+ var obj = canvas.getActiveObject();
395
+ var step = 2;
396
+ // Bigger step if shift is down
397
+ if (e.shiftKey) {
398
+ step = 7;
399
+ }
400
+ obj.top = obj.top + step;
401
+ canvas.renderAll();
402
+ autoKeyframe(obj, { action: 'drag' }, false);
403
+ }
404
+
405
+ // Move object up layer list
406
+ if (
407
+ e.keyCode === 221 &&
408
+ canvas.getActiveObjects() &&
409
+ e.metaKey
410
+ ) {
411
+ if (canvas.getActiveObjects().length == 1) {
412
+ var obj = canvas.getActiveObject();
413
+ $(".layer[data-object='" + obj.id + "']")
414
+ .prev()
415
+ .insertAfter($(".layer[data-object='" + obj.id + "']"));
416
+ $('#' + obj.id)
417
+ .prev()
418
+ .insertAfter($('#' + obj.id));
419
+ orderLayers();
420
+ } else {
421
+ canvas.getActiveObjects().forEach(function (obj) {
422
+ $(".layer[data-object='" + obj.id + "']")
423
+ .prev()
424
+ .insertAfter($(".layer[data-object='" + obj.id + "']"));
425
+ $('#' + obj.id)
426
+ .prev()
427
+ .insertAfter($('#' + obj.id));
428
+ orderLayers();
429
+ });
430
+ }
431
+ }
432
+
433
+ // Move object down layer list
434
+ if (
435
+ e.keyCode === 219 &&
436
+ canvas.getActiveObjects() &&
437
+ e.metaKey
438
+ ) {
439
+ if (canvas.getActiveObjects().length == 1) {
440
+ var obj = canvas.getActiveObject();
441
+ $(".layer[data-object='" + obj.id + "']")
442
+ .next()
443
+ .insertBefore($(".layer[data-object='" + obj.id + "']"));
444
+ $('#' + obj.id)
445
+ .next()
446
+ .insertBefore($('#' + obj.id));
447
+ orderLayers();
448
+ } else {
449
+ canvas.getActiveObjects().forEach(function (obj) {
450
+ $(".layer[data-object='" + obj.id + "']")
451
+ .next()
452
+ .insertBefore(
453
+ $(".layer[data-object='" + obj.id + "']")
454
+ );
455
+ $('#' + obj.id)
456
+ .next()
457
+ .insertBefore($('#' + obj.id));
458
+ orderLayers();
459
+ });
460
+ }
461
+ }
462
+
463
+ // Move object top of layer list
464
+ if (
465
+ e.keyCode === 221 &&
466
+ canvas.getActiveObjects() &&
467
+ e.altKey
468
+ ) {
469
+ if (canvas.getActiveObjects().length == 1) {
470
+ var obj = canvas.getActiveObject();
471
+ $('#layer-inner-list').prepend(
472
+ $(".layer[data-object='" + obj.id + "']")
473
+ );
474
+ $('#inner-timeline').prepend($('#' + obj.id));
475
+ orderLayers();
476
+ } else {
477
+ canvas.getActiveObjects().forEach(function (obj) {
478
+ $('#layer-inner-list').prepend(
479
+ $(".layer[data-object='" + obj.id + "']")
480
+ );
481
+ $('#inner-timeline').prepend($('#' + obj.id));
482
+ orderLayers();
483
+ });
484
+ }
485
+ }
486
+
487
+ // Move object bottom of layer list
488
+ if (e.keyCode === 219 && canvas.getActiveObject() && e.altKey) {
489
+ if (canvas.getActiveObjects().length == 1) {
490
+ var obj = canvas.getActiveObject();
491
+ $('#layer-inner-list').append(
492
+ $(".layer[data-object='" + obj.id + "']")
493
+ );
494
+ $('#inner-timeline').append($('#' + obj.id));
495
+ orderLayers();
496
+ } else {
497
+ canvas.getActiveObjects().forEach(function (obj) {
498
+ $('#layer-inner-list').append(
499
+ $(".layer[data-object='" + obj.id + "']")
500
+ );
501
+ $('#inner-timeline').append($('#' + obj.id));
502
+ orderLayers();
503
+ });
504
+ }
505
+ }
506
+
507
+ // Zoom in
508
+ if (e.keyCode === 187 && e.shiftKey) {
509
+ var zoom = canvas.getZoom() + 0.2;
510
+ if (zoom > 20) zoom = 20;
511
+ if (zoom < 0.01) zoom = 0.01;
512
+ canvas.setZoom(1);
513
+ canvas.renderAll();
514
+ var vpw = canvas.width / zoom;
515
+ var vph = canvas.height / zoom;
516
+ var x = artboard.left + artboard.width / 2 - vpw / 2;
517
+ var y = artboard.top + artboard.height / 2 - vph / 2;
518
+ canvas.absolutePan({ x: x, y: y });
519
+ canvas.setZoom(zoom);
520
+ canvas.renderAll();
521
+ $('#zoom-level span').html(
522
+ (canvas.getZoom() * 100).toFixed(0) + '%'
523
+ );
524
+ }
525
+
526
+ // Zoom out
527
+ if (e.keyCode === 189 && e.shiftKey) {
528
+ var zoom = canvas.getZoom() - 0.2;
529
+ if (zoom > 20) zoom = 20;
530
+ if (zoom < 0.01) zoom = 0.01;
531
+ canvas.setZoom(1);
532
+ canvas.renderAll();
533
+ var vpw = canvas.width / zoom;
534
+ var vph = canvas.height / zoom;
535
+ var x = artboard.left + artboard.width / 2 - vpw / 2;
536
+ var y = artboard.top + artboard.height / 2 - vph / 2;
537
+ canvas.absolutePan({ x: x, y: y });
538
+ canvas.setZoom(zoom);
539
+ canvas.renderAll();
540
+ $('#zoom-level span').html(
541
+ (canvas.getZoom() * 100).toFixed(0) + '%'
542
+ );
543
+ }
544
+ });
545
+
546
+ // Copy event
547
+ window.addEventListener('copy', function (e) {
548
+ // Copy selected object
549
+ if (
550
+ canvas.getActiveObject() &&
551
+ shiftkeys.length == 0 &&
552
+ !canvas.getActiveObject().isEditing
553
+ ) {
554
+ var emptyInp = document.getElementById('emptyInput');
555
+ emptyInp.select();
556
+ emptyInp.focus();
557
+ setTimeout(function () {
558
+ document.execCommand('copy');
559
+ }, 0);
560
+ clipboard = canvas.getActiveObject();
561
+ cliptype = 'object';
562
+ // Copy selected keyframe(s)
563
+ } else if (
564
+ shiftkeys.length > 0 &&
565
+ !canvas.getActiveObject().isEditing
566
+ ) {
567
+ var emptyInp = document.getElementById('emptyInput');
568
+ emptyInp.select();
569
+ emptyInp.focus();
570
+ setTimeout(function () {
571
+ document.execCommand('copy');
572
+ }, 0);
573
+ clipboard = [];
574
+ shiftkeys.forEach(function (keyframe) {
575
+ var drag = $(keyframe.keyframe);
576
+ var keyarr = $.grep(keyframes, function (e) {
577
+ return (
578
+ e.t == drag.attr('data-time') &&
579
+ e.id == drag.attr('data-object') &&
580
+ e.name == drag.attr('data-property')
581
+ );
582
+ });
583
+ clipboard.push(keyarr[0]);
584
+ });
585
+ cliptype = 'keyframe';
586
+ }
587
+ });
588
+
589
+ // Paste event
590
+ window.addEventListener('paste', function (e) {
591
+ var imgs = e.clipboardData.items;
592
+ if (imgs == undefined) return false;
593
+
594
+ // Paste object or keyframe(s)
595
+ if (imgs.length == 1 && e.clipboardData.getData('text') == ' ') {
596
+ copyObject();
597
+ // Paste external image (by uploading it)
598
+ } else {
599
+ for (var i = 0; i < imgs.length; i++) {
600
+ if (imgs[i].type.indexOf('image') == -1) continue;
601
+ var imgObj = imgs[i].getAsFile();
602
+ if (imgObj.size / 1024 / 1024 <= 10) {
603
+ createThumbnail(imgObj, 250).then(function (data) {
604
+ saveFile(
605
+ dataURItoBlob(data),
606
+ imgObj,
607
+ imgObj['type'].split('/')[0],
608
+ 'temp',
609
+ true,
610
+ true
611
+ );
612
+ });
613
+ } else {
614
+ alert('Image is too big');
615
+ }
616
+ }
617
+ }
618
+ });
619
+
620
+ // Stop cropping when clicking on the blacked out properties panel
621
+ $(document).on('click', '#properties-overlay', function () {
622
+ if (cropping) {
623
+ canvas.discardActiveObject();
624
+ }
625
+ });
626
+
627
+ // Scroll horizontally through assets in the library
628
+ $(document).on('click', '.right-arrow', function () {
629
+ $(this).parent().animate({ scrollLeft: '+=1000' }, 500);
630
+ });
631
+ $(document).on('click', '.left-arrow', function () {
632
+ $(this).parent().animate({ scrollLeft: '-=1000' }, 500);
633
+ });
634
+
635
+ // Playback
636
+ $(document).on('click', '#play-button', function () {
637
+ if (paused) {
638
+ play();
639
+ } else {
640
+ pause();
641
+ }
642
+ });
643
+
644
+ // Detect when not clicking on certain elements
645
+ $(document).on('mousedown', function (e) {
646
+ // De-select keyframes
647
+ if (
648
+ !$('#keyframe-properties').is(e.target) &&
649
+ $('#keyframe-properties').has(e.target).length === 0 &&
650
+ !$('.keyframe').is(e.target) &&
651
+ $('.keyframe').has(e.target).length === 0
652
+ ) {
653
+ $('#keyframe-properties').removeClass('show-properties');
654
+ $('.keyframe-selected').removeClass('keyframe-selected');
655
+ shiftkeys = [];
656
+ }
657
+
658
+ // Hide color picker
659
+ if (
660
+ !$('.object-color').is(e.target) &&
661
+ $('.object-color').has(e.target).length === 0 &&
662
+ !$('.pcr-app').is(e.target) &&
663
+ $('.prc-app').has(e.target).length === 0 &&
664
+ !$('.pcr-selection').is(e.target) &&
665
+ $('.pcr-selection').has(e.target).length === 0 &&
666
+ !$('.pcr-swatches').is(e.target) &&
667
+ $('.pcr-swatches').has(e.target).length === 0 &&
668
+ !$('.pcr-interaction').is(e.target) &&
669
+ $('.pcr-interaction').has(e.target).length === 0
670
+ ) {
671
+ o_fill.hide();
672
+ }
673
+
674
+ // Hide zoom controls
675
+ if (
676
+ !$('#other-controls').is(e.target) &&
677
+ $('#other-controls').has(e.target).length === 0
678
+ ) {
679
+ $('#zoom-options').addClass('zoom-hidden');
680
+ $('#zoom-level img').removeClass('zoom-open');
681
+ }
682
+
683
+ // Hide speed settings
684
+ if (
685
+ !$('#speed').is(e.target) &&
686
+ $('#speed').has(e.target).length === 0
687
+ ) {
688
+ $('#speed-settings').removeClass('show-speed');
689
+ $('#speed-arrow').removeClass('arrow-on');
690
+ }
691
+
692
+ // Hide more menu
693
+ if (
694
+ !$('#more-tool').is(e.target) &&
695
+ $('#more-tool').has(e.target).length === 0 &&
696
+ !$('#more-over').is(e.target) &&
697
+ $('#more-over').has(e.target).length === 0
698
+ ) {
699
+ hideMore();
700
+ }
701
+ });
702
+
703
+ // Detect focus on an input in the properties
704
+ $(document)
705
+ .on('focus', '.property-input', function () {
706
+ focus = true;
707
+ })
708
+ .on('focusout', function () {
709
+ focus = false;
710
+ });
711
+
712
+ // Toggle zoom dropdown
713
+ $(document).on('click', '#zoom-level', function () {
714
+ $('#zoom-options').toggleClass('zoom-hidden');
715
+ $('#zoom-level img').toggleClass('zoom-open');
716
+ });
717
+
718
+ // Skip to the beginning or end
719
+ $(document).on('click', '#skip-backward', function () {
720
+ animate(false, 0);
721
+ $('#seekbar').offset({
722
+ left:
723
+ offset_left +
724
+ $('#inner-timeline').offset().left +
725
+ currenttime / timelinetime,
726
+ });
727
+ });
728
+ $(document).on('click', '#skip-forward', function () {
729
+ animate(false, duration);
730
+ $('#seekbar').offset({
731
+ left:
732
+ offset_left +
733
+ $('#inner-timeline').offset().left +
734
+ currenttime / timelinetime,
735
+ });
736
+ });
737
+
738
+ // Change layer name
739
+ $(document).on('dblclick', '.layer-custom-name', function () {
740
+ $(this).prop('readonly', false);
741
+ $(this).addClass('name-active');
742
+ $(this).focus();
743
+ document.execCommand('selectAll', false, null);
744
+ editinglayer = true;
745
+ });
746
+
747
+ // Trigger file picker when clicking the upload button
748
+ $(document).on('click', '#upload-button', function () {
749
+ $('#upload-popup').addClass('upload-show');
750
+ });
751
+
752
+ $(document).on('click', '#upload-overlay', function () {
753
+ $('.upload-show').removeClass('upload-show');
754
+ });
755
+
756
+ $(document).on('click', '#upload-popup-close', function () {
757
+ $('.upload-show').removeClass('upload-show');
758
+ });
759
+
760
+ $(document).on('click', '#upload-drop-area', function () {
761
+ $('#filepick').click();
762
+ });
763
+
764
+ $(document).on('dragover', function (e) {
765
+ e.preventDefault();
766
+ e.stopPropagation();
767
+ });
768
+
769
+ $(document).on('dragover', '#upload-drop-area', function (e) {
770
+ e.preventDefault();
771
+ e.stopPropagation();
772
+ $('#upload-drop-area').addClass('dropping');
773
+ });
774
+
775
+ $(document).on('dragenter', '#upload-drop-area', function (e) {
776
+ e.preventDefault();
777
+ e.stopPropagation();
778
+ $('#upload-drop-area').addClass('dropping');
779
+ });
780
+
781
+ $(document).on('drop', function (e) {
782
+ e.preventDefault();
783
+ e.stopPropagation();
784
+ $('#upload-drop-area').removeClass('dropping');
785
+ handleUpload(e);
786
+ });
787
+
788
+ $(document).on('dragleave', function () {
789
+ $('#upload-drop-area').removeClass('dropping');
790
+ });
791
+
792
+ $(document).on('dragend', function () {
793
+ $('#upload-drop-area').removeClass('dropping');
794
+ });
795
+
796
+ // Upload or remove background audio
797
+ $(document).on('click', '#audio-upload-button', function () {
798
+ $('#filepick2').click();
799
+ });
800
+
801
+ // Sync scrolling for the timeline
802
+ syncScroll($('#layer-inner-list'), $('#timeline'));
803
+ syncScrollHoz($('#timeline'), $('#seekarea'));
804
+
805
+ // Initialize layer sorting
806
+ sortable('#layer-inner-list', {
807
+ customDragImage: (draggedElement, elementOffset, event) => {
808
+ return {
809
+ element: document.getElementById('nothing'),
810
+ posX: event.pageX - elementOffset.left,
811
+ posY: event.pageY - elementOffset.top,
812
+ };
813
+ },
814
+ })[0].addEventListener('sortstop', function (e) {
815
+ const id = $(e.detail.item).attr('data-object');
816
+ const previd = $(e.detail.item).prev().attr('data-object');
817
+ if ($('.sortable-dragging').length == 1) {
818
+ $('.sortable-dragging').remove();
819
+ if (previd == undefined) {
820
+ $('#inner-timeline').prepend($('#' + id));
821
+ } else {
822
+ $('#' + id).insertAfter($('#' + previd));
823
+ }
824
+ orderLayers();
825
+ }
826
+ });
827
+
828
+ // Initialize dropdown for keyframe easing
829
+ $('#easing select').niceSelect();
830
+
831
+ // Initialize properties panel
832
+ updatePanel(false);
833
+
834
+ // Initialize library
835
+ updateBrowser('shape-tool');
836
+
837
+ function initFilterSliders() {
838
+ var filters = [
839
+ 'filter-brightness',
840
+ 'filter-contrast',
841
+ 'filter-saturation',
842
+ 'filter-hue',
843
+ 'filter-vibrance',
844
+ ];
845
+ filters.forEach(function (filter) {
846
+ var selectme = document.getElementById(filter);
847
+ var slider = new RangeSlider(selectme, {
848
+ design: '2d',
849
+ theme: 'default',
850
+ handle: 'round',
851
+ popup: null,
852
+ showMinMaxLabels: false,
853
+ unit: '%',
854
+ min: -100,
855
+ max: 100,
856
+ value: 0,
857
+ step: 1,
858
+ onmove: function (x) {
859
+ if (canvas.getActiveObject()) {
860
+ var obj = canvas.getActiveObject();
861
+ if (filter == 'filter-brightness') {
862
+ if (obj.filters.find((i) => i.type == 'Brightness')) {
863
+ obj.filters.find(
864
+ (i) => i.type == 'Brightness'
865
+ ).brightness = x / 100;
866
+ } else {
867
+ obj.filters.push(
868
+ new f.Brightness({ brightness: x / 100 })
869
+ );
870
+ }
871
+ } else if (filter == 'filter-contrast') {
872
+ if (obj.filters.find((i) => i.type == 'Contrast')) {
873
+ obj.filters.find(
874
+ (i) => i.type == 'Contrast'
875
+ ).contrast = x / 100;
876
+ } else {
877
+ obj.filters.push(
878
+ new f.Contrast({ contrast: x / 100 })
879
+ );
880
+ }
881
+ } else if (filter == 'filter-saturation') {
882
+ if (obj.filters.find((i) => i.type == 'Saturation')) {
883
+ obj.filters.find(
884
+ (i) => i.type == 'Saturation'
885
+ ).saturation = x / 100;
886
+ } else {
887
+ obj.filters.push(
888
+ new f.Saturation({ saturation: x / 100 })
889
+ );
890
+ }
891
+ } else if (filter == 'filter-vibrance') {
892
+ if (obj.filters.find((i) => i.type == 'Vibrance')) {
893
+ obj.filters.find(
894
+ (i) => i.type == 'Vibrance'
895
+ ).vibrance = x / 100;
896
+ } else {
897
+ obj.filters.push(
898
+ new f.Vibrance({ vibrance: x / 100 })
899
+ );
900
+ }
901
+ } else if (filter == 'filter-hue') {
902
+ if (obj.filters.find((i) => i.type == 'HueRotation')) {
903
+ obj.filters.find(
904
+ (i) => i.type == 'HueRotation'
905
+ ).rotation = x / 100;
906
+ } else {
907
+ obj.filters.push(
908
+ new f.HueRotation({ rotation: x / 100 })
909
+ );
910
+ }
911
+ }
912
+ obj.applyFilters();
913
+ canvas.renderAll();
914
+ }
915
+ },
916
+ onfinish: function (x) {
917
+ save();
918
+ },
919
+ });
920
+ sliders.push({ name: filter, slider: slider });
921
+ });
922
+ }
923
+
924
+ var selectchroma = document.getElementById('chroma-distance');
925
+ chromaslider = new RangeSlider(selectchroma, {
926
+ design: '2d',
927
+ theme: 'default',
928
+ handle: 'round',
929
+ popup: null,
930
+ showMinMaxLabels: false,
931
+ unit: '%',
932
+ min: 1,
933
+ max: 100,
934
+ value: 1,
935
+ step: 1,
936
+ onmove: function (x) {
937
+ if (canvas.getActiveObject()) {
938
+ var obj = canvas.getActiveObject();
939
+ if (obj.filters.find((x) => x.type == 'RemoveColor')) {
940
+ obj.filters.find((x) => x.type == 'RemoveColor').distance =
941
+ x / 100;
942
+ }
943
+ obj.applyFilters();
944
+ canvas.renderAll();
945
+ }
946
+ },
947
+ onfinish: function (x) {
948
+ save();
949
+ },
950
+ });
951
+
952
+ var selectnoise = document.getElementById('filter-noise');
953
+ noiseslider = new RangeSlider(selectnoise, {
954
+ design: '2d',
955
+ theme: 'default',
956
+ handle: 'round',
957
+ popup: null,
958
+ showMinMaxLabels: false,
959
+ unit: '%',
960
+ min: 0,
961
+ max: 1000,
962
+ value: 0,
963
+ step: 1,
964
+ onmove: function (x) {
965
+ if (canvas.getActiveObject()) {
966
+ var obj = canvas.getActiveObject();
967
+ if (obj.filters.find((x) => x.type == 'Noise')) {
968
+ obj.filters.find((x) => x.type == 'Noise').noise = x;
969
+ } else {
970
+ obj.filters.push(
971
+ new f.Noise({
972
+ noise: x,
973
+ })
974
+ );
975
+ }
976
+ obj.applyFilters();
977
+ canvas.renderAll();
978
+ }
979
+ },
980
+ onfinish: function (x) {
981
+ save();
982
+ },
983
+ });
984
+
985
+ var selectblur = document.getElementById('filter-blur');
986
+ blurslider = new RangeSlider(selectblur, {
987
+ design: '2d',
988
+ theme: 'default',
989
+ handle: 'round',
990
+ popup: null,
991
+ showMinMaxLabels: false,
992
+ unit: '%',
993
+ min: 0,
994
+ max: 100,
995
+ value: 0,
996
+ step: 1,
997
+ onmove: function (x) {
998
+ if (canvas.getActiveObject()) {
999
+ var obj = canvas.getActiveObject();
1000
+ if (obj.filters.find((x) => x.type == 'Blur')) {
1001
+ obj.filters.find((x) => x.type == 'Blur').blur = x / 100;
1002
+ } else {
1003
+ obj.filters.push(
1004
+ new f.Blur({
1005
+ blur: x / 100,
1006
+ })
1007
+ );
1008
+ }
1009
+ }
1010
+ obj.applyFilters();
1011
+ canvas.renderAll();
1012
+ },
1013
+ onfinish: function (x) {
1014
+ save();
1015
+ },
1016
+ });
1017
+
1018
+ $('#filters-list').val('none');
1019
+ $('#filters-list').niceSelect();
1020
+
1021
+ initFilterSliders();
1022
+ });
js/functions.js ADDED
The diff for this file is too large to render. See raw diff
 
js/init.js ADDED
@@ -0,0 +1,1075 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var API_KEY = 'PIXABAY_API';
2
+ var GOOGLE_FONTS_API_KEY = 'GOOGLE_FONTS_API_KEY';
3
+
4
+ // for legacy browsers
5
+ const AudioContext = window.AudioContext || window.webkitAudioContext;
6
+ const audioContext = new AudioContext();
7
+ var oldsrc, oldobj;
8
+ var oldtimelinepos;
9
+ var speed = 1;
10
+ var page = 1;
11
+ var checkstatus = false;
12
+ let db = new Localbase('db');
13
+ var wip = false;
14
+ var paused = true;
15
+ var currenttime = 0;
16
+ var timelinetime = 5;
17
+ const offset_left = 20;
18
+ var duration = 30000;
19
+ var keyframes = [];
20
+ var p_keyframes = [];
21
+ var props = [
22
+ 'left',
23
+ 'top',
24
+ 'scaleX',
25
+ 'scaleY',
26
+ 'width',
27
+ 'height',
28
+ 'angle',
29
+ 'opacity',
30
+ 'fill',
31
+ 'strokeWidth',
32
+ 'stroke',
33
+ 'shadow.color',
34
+ 'shadow.opacity',
35
+ 'shadow.offsetX',
36
+ 'shadow.offsetY',
37
+ 'shadow.blur',
38
+ 'charSpacing',
39
+ 'lineHeight',
40
+ ];
41
+ var objects = [];
42
+ var o_slider, o_letter_slider, o_line_slider;
43
+ var colormode = 'fill';
44
+ var spaceDown = false;
45
+ var selectedkeyframe;
46
+ var undo = [];
47
+ var undoarr = [];
48
+ var redo = [];
49
+ var groups = [];
50
+ var redoarr = [];
51
+ var state;
52
+ var statearr = [];
53
+ var recording = false;
54
+ var canvasrecord;
55
+ var clipboard;
56
+ var focus = false;
57
+ var editingpanel = false;
58
+ var files = [];
59
+ var re = /(?:\.([^.]+))?$/;
60
+ var filelist = [];
61
+ var timeout;
62
+ var spacehold = false;
63
+ var spacerelease = false;
64
+ var tempselection;
65
+ var line_h, line_v;
66
+ var tempgroup = [];
67
+ var editinggroup = false;
68
+ var tempgroupid;
69
+ var fontPicker;
70
+ var fonts = [];
71
+ var seeking = false;
72
+ var setting = false;
73
+ var handtool = false;
74
+ var canvasx = 0;
75
+ var canvasy = 0;
76
+ var overCanvas = false;
77
+ var draggingPanel = false;
78
+ var cropping = false;
79
+ var cropobj;
80
+ var cropscalex;
81
+ var cropscaley;
82
+ var croptop;
83
+ var cropleft;
84
+ var layer_count = 1;
85
+ var lockmovement = false;
86
+ var shiftx = 0;
87
+ var shifty = 0;
88
+ var editinglayer = false;
89
+ var editingproject = false;
90
+ var shiftkeys = [];
91
+ var shiftdown = false;
92
+ var cliptype = 'object';
93
+ var chromaslider, noiseslider, blurslider;
94
+ var isChrome =
95
+ window.chrome && Object.values(window.chrome).length !== 0;
96
+ var eyeDropper;
97
+ if (isChrome) {
98
+ eyeDropper = new EyeDropper();
99
+ }
100
+ var presets = [
101
+ {
102
+ name: 'Dribbble shot',
103
+ id: 'dribbble',
104
+ width: 1600,
105
+ height: 1200,
106
+ },
107
+ { name: 'Facebook post', id: 'facebook', width: 1280, height: 720 },
108
+ {
109
+ name: 'Facebook ad',
110
+ id: 'facebook-ad',
111
+ width: 1080,
112
+ height: 1080,
113
+ },
114
+ { name: 'Youtube video', id: 'youtube', width: 1920, height: 1080 },
115
+ {
116
+ name: 'Instagram video',
117
+ id: 'instagram-id',
118
+ width: 1080,
119
+ height: 1920,
120
+ },
121
+ {
122
+ name: 'Instagram stories',
123
+ id: 'instagram-stories',
124
+ width: 1080,
125
+ height: 1920,
126
+ },
127
+ { name: 'Twitter video', id: 'twitter', width: 1280, height: 720 },
128
+ { name: 'Snapchat ad', id: 'snapchat', width: 1080, height: 1920 },
129
+ {
130
+ name: 'LinkedIn video',
131
+ id: 'linkedin',
132
+ width: 1920,
133
+ height: 1080,
134
+ },
135
+ {
136
+ name: 'Product Hunt thumbnail',
137
+ id: 'product-hunt',
138
+ width: 600,
139
+ height: 600,
140
+ },
141
+ {
142
+ name: 'Pinterest ad',
143
+ id: 'pinterest',
144
+ width: 1080,
145
+ height: 1920,
146
+ },
147
+ ];
148
+ var activepreset = 'custom';
149
+ var uploaded_images = [];
150
+ var uploaded_videos = [];
151
+ var uploading = false;
152
+ var background_audio = false;
153
+ var temp_audio = false;
154
+ var background_key;
155
+ var sliders = [];
156
+ var hovertime = 0;
157
+ var animatedtext = [];
158
+
159
+ // Get list of fonts
160
+ $.ajax({
161
+ url:
162
+ 'https://www.googleapis.com/webfonts/v1/webfonts?key=' +
163
+ GOOGLE_FONTS_API_KEY +
164
+ '&sort=alpha',
165
+ type: 'GET',
166
+ dataType: 'json', // added data type
167
+ success: function (response) {
168
+ response.items.forEach(function (item) {
169
+ fonts.push(item.family);
170
+ });
171
+ },
172
+ });
173
+
174
+ // Panel variants
175
+ const canvas_panel =
176
+ '<div id="canvas-properties" class="panel-section"><p class="property-title">Canvas settings</p><table><tr><th class="name-col">Preset</th><th class="value-col"><select id="preset"></select></th></tr><tr><th class="name-col">Size</th><th class="value-col"><div id="canvas-w" class="property-input" data-label="W"><input type="number" min=1 value=1000></div><div id="canvas-h" class="property-input" data-label="H"><input type="number" value=1000 min=1></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="canvas-color" class="object-color"><div id="color-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="canvas-color-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Duration</th><th class="value-col" id="duration-cell"><div id="canvas-duration" class="property-input" data-label="s"><input type="number" value=15.00></div></th></tr></table></div>';
177
+ const object_panel =
178
+ '<div id="layout-properties" class="panel-section"><p class="property-title">Layout</p><table><tr><th class="name-col">Position</th><th class="value-col"><div id="object-x" class="property-input" data-label="X"><input type="number" value=1000></div><div id="object-y" class="property-input" data-label="Y"><input value=1000 type="number"></div></th></tr><tr><th class="name-col">Size</th><th class="value-col"><div id="object-w" class="property-input" data-label="W"><input type="number" min=1 value=1000></div><div id="object-h" class="property-input" data-label="H"><input type="number" value=1000 min=1></div></th></tr><tr><th class="name-col">Rotation</th><th class="value-col" id="duration-cell"><div id="object-r" class="property-input" data-label="&#176;"><input type="number" min=0 max=360 value=0></div></th></tr></table></div>';
179
+ const back_panel =
180
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
181
+ const image_panel =
182
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
183
+ const selection_panel =
184
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Group</th><th class="value-col"><div id="group-objects">Group selection</div></th></tr></table></div>';
185
+ const group_panel =
186
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr><tr><th class="name-col">Group</th><th class="value-col"><div id="ungroup-objects">Ungroup selection</div></th></tr></table></div>';
187
+ const other_panel =
188
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Layer</p><table><tr><th class="name-col">Opacity</th><th class="value-col"><div id="select-opacity"></div><div id="object-o" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Mask</th><th class="value-col"><select id="masks"><option value="none">None</option></select></th></tr></table></div>';
189
+ const shape_panel =
190
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Rectangle</p><table><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Radius</th><th class="value-col" id="duration-cell"><div id="object-corners" class="property-input" data-label="px"><input type="number" value=0 min=0></div></th></tr></table></div>';
191
+ const path_panel =
192
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Shape</p><table><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr></table></div>';
193
+ const text_panel =
194
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Text</p><table><tr><th class="name-col">Font</th><th class="value-col"><select id="font-picker"></select></th></tr><tr><th class="name-col">Align</th><th class="value-col"><div class="align-text" id="align-text-left"><img src="assets/align-text-left.svg"></div><div class="align-text" id="align-text-center"><img src="assets/align-text-center.svg"></div><div class="align-text" id="align-text-right"><img src="assets/align-text-right.svg"></div><div class="align-text" id="align-text-justify"><img src="assets/align-text-justify.svg"></div></th></tr><tr><th class="name-col">Format</th><th class="value-col"><div class="format-text" id="format-bold"><img src="assets/bold.svg"></div><div class="format-text" id="format-italic"><img src="assets/italic.svg"></div><div class="format-text" id="format-underline"><img src="assets/underline.svg"></div><div class="format-text" id="format-strike"><img src="assets/strike.svg"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-fill" class="object-color"><div id="color-fill-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-fill-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Letter</th><th class="value-col"><div id="select-letter"></div><div id="text-h" class="property-input" data-label="%"><input type="number" value=1></div></th></tr><tr><th class="name-col">Line</th><th class="value-col"><div id="select-line"></div><div id="text-v" class="property-input" data-label="%"><input type="number" value=1></div></th></tr></table></div>';
195
+ const stroke_panel =
196
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Stroke</p><table><tr><th class="name-col">Type</th><th class="value-col left-col"><div class="line-join" id="miter"><img src="assets/miter.svg"></div><div class="line-join" id="bevel"><img src="assets/bevel.svg"></div><div class="line-join" id="round"><img src="assets/round.svg"></div><div class="line-join" id="small-dash"><img src="assets/dash2.svg"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-stroke" class="object-color"><div id="color-stroke-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-stroke-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Width</th><th class="value-col" id="duration-cell"><div id="object-stroke" class="property-input" data-label="px"><input type="number" min=0 value=0></div></th></tr></table></div>';
197
+ const shadow_panel =
198
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Shadow</p><table><tr><th class="name-col">Offset</th><th class="value-col"><div id="object-shadow-x" class="property-input" data-label="X"><input type="number" value=0></div><div id="object-shadow-y" class="property-input" data-label="Y"><input value=0 type="number"></div></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="object-color-shadow" class="object-color"><div id="color-shadow-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="object-color-shadow-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr><tr><th class="name-col">Blur</th><th class="value-col" id="duration-cell"><div id="object-blur" class="property-input" data-label="px"><input type="number" value=0 min=0></div></th></tr></table></div>';
199
+ const image_more_panel =
200
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Image</p><div id="image-buttons"><div id="filters-button"><img src="assets/filters.svg"> Edit filters</div><div id="crop-image"><img src="assets/crop-icon.svg">Crop image</div></div></div></hr>';
201
+ const video_more_panel =
202
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Video</p><div id="image-buttons"><div id="filters-button" class="filters-video"><img src="assets/filters.svg"> Edit filters</div></div></div></hr>';
203
+ const animated_text_panel =
204
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Text</p><table><tr><th class="name-col">Content</th><th class="value-col" id="duration-cell"><div id="animated-text" class="property-input" data-label=""><input id="animatedinput" type="text" value="text"><div id="animatedset">Set</div></div></th></tr><tr><th class="name-col">Font</th><th class="value-col"><select id="font-picker"></select></th></tr><tr><th class="name-col">Color</th><th class="value-col"><div id="text-color" class="object-color"><div id="color-text-side" class="color-picker"></div><input value="#FFFFFF" disabled="disabled"></div><div id="color-text-opacity" class="property-input" data-label="%"><input type="number" value=100></div></th></tr></table></div>';
205
+ const start_animation_panel =
206
+ '<hr><div id="back-properties" class="panel-section"><p class="property-title">Start animation</p><table><tr><th class="name-col">Preset</th><th class="value-col"><select id="preset-picker"></select></th></tr><tr><th class="name-col">Easing</th><th class="value-col"><select id="easing-picker"><option value="linear">Linear</option><option value="easeInQuad">Ease in</option><option value="easeOutQuad">Ease out</option><option value="easeinOutQuad">Ease in-out</option><option value="easeOutInQuad">Ease out-in</option><option value="easeInBounce">Ease in bounce</option><option value="easeOutBounce">Ease out bounce</option><option value="easeinOutBounce">Ease in-out bounce</option><option value="easeOutInBouce">Ease out-in bounce</option><option value="easeOutInBouce">Ease out-in bounce</option><option value="easeInSine">Ease in sine</option><option value="easeOutSine">Ease out sine</option><option value="easeinOutSine">Ease in-out sine</option><option value="easeOutInSine">Ease out-in sine</option><option value="easeOutInSine">Ease out-in sine</option><option value="easeInCubic">Ease in cubic</option><option value="easeOutCubic">Ease out cubic</option><option value="easeinOutCubic">Ease in-out cubic</option><option value="easeOutInCubic">Ease out-in cubic</option><option value="easeOutInCubic">Ease out-in cubic</option></select></th></tr><tr><th class="name-col">Order</th><th class="value-col"><div id="order-toggle"><div id="order-backward" class="order-toggle-item">Backward</div><div id="order-forward" class="order-toggle-item order-toggle-item-active">Forward</div></div></th></tr><tr><th class="name-col">Order</th><th class="value-col"><div id="order-toggle"><div id="type-letters" class="order-toggle-item-2">Letters</div><div id="type-words" class="order-toggle-item-2 order-toggle-item-active-2">Words</div></div></th></tr><tr><th class="name-col">Duration</th><th class="value-col" id="duration-cell"><div id="animated-text-duration" class="property-input" data-label="s"><input id="durationinput" type="number" value="0"></div></th></tr></table></div>';
207
+ const audio_panel =
208
+ '<div id="layout-properties" class="panel-section"><p class="property-title">Audio</p><table><tr><th class="name-col">Volume</th><th class="value-col" id="duration-cell"><div id="object-volume" class="property-input" data-label="%"><input type="number" value=0></div></th></tr></table></div>';
209
+
210
+ // Browser variants
211
+ const shape_browser =
212
+ '<div id="search-fixed"><p class="property-title">Objects</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><p class="row-title">Shapes</p><div class="gallery-row" id="shapes-row"></div><p class="row-title">Emojis</p><div class="gallery-row" id="emojis-row"></div></div>';
213
+ const image_browser =
214
+ '<div id="search-fixed"><p class="property-title">Images</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><a href="https://pixabay.com" target="_blank" id="pixabay"><img src="assets/pixabay.svg"></a><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><div id="landing"><div id="landing-text">Browse millions of high quality images from Pixabay. Use the search bar above or choose from popular categories below.</div><div id="categories"></div></div><div id="images-grid"></div></div>';
215
+ const text_browser =
216
+ '<div id="search-fixed"><p class="property-title">Text</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><p class="row-title">Basic text</p><div id="heading-text" data-font="Inter" class="add-text noselect">Add a heading</div><div id="subheading-text" data-font="Inter" class="add-text noselect">Add a subheading</div><div id="body-text" data-font="Inter" class="add-text noselect">Add body text</div></div>';
217
+ const video_browser =
218
+ '<div id="search-fixed"><p class="property-title">Videos</p><img id="collapse" src="assets/collapse.svg"><div id="browser-search"><input placeholder="Search..."><a href="https://pixabay.com" target="_blank" id="pixabay"><img src="assets/pixabay.svg"></a><img src="assets/search.svg" id="search-icon"><img src="assets/delete.svg" id="delete-search"><div id="search-button">Go</div></div></div><div id="shapes-cont"><div id="landing"><div id="landing-text">Browse millions of high quality images from Pixabay. Use the search bar above or choose from popular categories below.</div><div id="categories"></div></div><div id="images-grid"></div></div>';
219
+ const upload_browser =
220
+ '<div id="search-fixed"><p class="property-title">Uploads</p><div id="upload-button"><img src="assets/upload.svg"> Upload media</div><img id="collapse" src="assets/collapse.svg"><div id="upload-tabs"><div id="images-tab" class="upload-tab upload-tab-active">Images</div><div id="videos-tab" class="upload-tab">Videos</div></div></div><div id="images-grid"></div>';
221
+ const audio_browser =
222
+ '<div id="search-fixed" class="audio-browser"><p class="property-title">Audio</p><div id="audio-upload-button"><img src="assets/upload.svg"> Upload audio</div><img id="collapse" src="assets/collapse.svg"></div><div id="audio-list-parent"><div id="landing-text" class="audio-landing-text">Audio provided by Pixabay. Browse millions of assets from Pixabay by <a href="https://pixabay.com/music/" target="_blank">clicking here.</a></div><div id="audio-list"></div></div>';
223
+
224
+ // Text animation list
225
+ var text_animation_list = [
226
+ { name: 'fade in', label: 'Fade in', src: 'assets/fade-in.svg' },
227
+ {
228
+ name: 'typewriter',
229
+ label: 'Typewriter',
230
+ src: 'assets/typewriter.svg',
231
+ },
232
+ {
233
+ name: 'slide top',
234
+ label: 'Slide top',
235
+ src: 'assets/slide-top.svg',
236
+ },
237
+ {
238
+ name: 'slide bottom',
239
+ label: 'Slide bottom',
240
+ src: 'assets/slide-bottom.svg',
241
+ },
242
+ {
243
+ name: 'slide left',
244
+ label: 'Slide left',
245
+ src: 'assets/slide-left.svg',
246
+ },
247
+ {
248
+ name: 'slide right',
249
+ label: 'Slide right',
250
+ src: 'assets/slide-right.svg',
251
+ },
252
+ { name: 'scale', label: 'Scale', src: 'assets/scale.svg' },
253
+ { name: 'shrink', label: 'Shrink', src: 'assets/shrink.svg' },
254
+ ];
255
+
256
+ // Shapes list
257
+ var shape_grid_items = [
258
+ 'assets/shapes/rectangle.svg',
259
+ 'assets/shapes/circle.svg',
260
+ 'assets/shapes/triangle.svg',
261
+ 'assets/shapes/polygon.svg',
262
+ 'assets/shapes/star.svg',
263
+ 'assets/thingy.svg',
264
+ 'assets/shapes/heart.svg',
265
+ 'assets/shapes/arrow.svg',
266
+ ];
267
+ var emoji_items = [
268
+ 'assets/twemojis/laughing-emoji.png',
269
+ 'assets/twemojis/crying-emoji.png',
270
+ 'assets/twemojis/surprised-emoji.png',
271
+ 'assets/twemojis/smiling-emoji.png',
272
+ 'assets/twemojis/tongue-emoji.png',
273
+ 'assets/twemojis/heart-eyes-emoji.png',
274
+ 'assets/twemojis/heart-kiss-emoji.png',
275
+ 'assets/twemojis/sunglasses-cool-emoji.png',
276
+ 'assets/twemojis/ghost-emoji.png',
277
+ 'assets/twemojis/skull-emoji.png',
278
+ 'assets/twemojis/mindblown-emoji.png',
279
+ 'assets/twemojis/bomb-emoji.png',
280
+ 'assets/twemojis/hundred-100-points-emoji.png',
281
+ 'assets/twemojis/thought-balloon-emoji.png',
282
+ 'assets/twemojis/wave-emoji.png',
283
+ 'assets/twemojis/point-emoji.png',
284
+ 'assets/twemojis/thumbs-up-emoji.png',
285
+ 'assets/twemojis/clap-emoji.png',
286
+ 'assets/twemojis/raising-hands-emoji.png',
287
+ 'assets/twemojis/praying-hands-emoji.png',
288
+ 'assets/twemojis/nail-polish-emoji.png',
289
+ 'assets/twemojis/eyes-emoji.png',
290
+ 'assets/twemojis/cat-face-emoji.png',
291
+ 'assets/twemojis/dog-face-emoji.png',
292
+ 'assets/twemojis/rose-emoji.png',
293
+ 'assets/twemojis/tulip-emoji.png',
294
+ 'assets/twemojis/pizza-emoji.png',
295
+ 'assets/twemojis/construction-emoji.png',
296
+ 'assets/twemojis/plane-emoji.png',
297
+ 'assets/twemojis/rocket-emoji.png',
298
+ 'assets/twemojis/clock-emoji.png',
299
+ 'assets/twemojis/star-emoji.png',
300
+ 'assets/twemojis/sun-emoji.png',
301
+ 'assets/twemojis/moon-emoji.png',
302
+ 'assets/twemojis/fire-emoji.png',
303
+ 'assets/twemojis/sparkles-emoji.png',
304
+ 'assets/twemojis/party-popper-emoji.png',
305
+ 'assets/twemojis/gift-emoji.png',
306
+ 'assets/twemojis/trophy-emoji.png',
307
+ 'assets/twemojis/target-emoji.png',
308
+ 'assets/twemojis/gem-emoji.png',
309
+ 'assets/twemojis/money-emoji.png',
310
+ 'assets/twemojis/pencil-emoji.png',
311
+ 'assets/twemojis/graph-emoji.png',
312
+ 'assets/twemojis/wip-emoji.png',
313
+ 'assets/twemojis/winking-face-emoji.png',
314
+ 'assets/twemojis/pleading-face-emoji.png',
315
+ 'assets/twemojis/thinking-face-emoji.png',
316
+ ];
317
+
318
+ // Image list
319
+ var image_grid_items = [
320
+ 'https://images.unsplash.com/photo-1609153259378-a8b23c766aec?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=1866&q=80',
321
+ 'https://images.unsplash.com/photo-1614435082296-ef0cbdb16b70?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=934&q=80',
322
+ 'https://images.unsplash.com/photo-1614432254115-7e756705e910?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxMHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
323
+ 'https://images.unsplash.com/photo-1614423234685-544477464e15?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHw4fHx8ZW58MHx8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
324
+ 'https://images.unsplash.com/photo-1614357235247-99fabbee67f9?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
325
+ 'https://images.unsplash.com/photo-1614373371549-c7d2e4885f17?ixid=MXwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxOXx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=900&q=60',
326
+ ];
327
+ var image_categories = [
328
+ { name: 'background', image: 'assets/background.png' },
329
+ { name: 'wallpaper', image: 'assets/wallpaper.png' },
330
+ { name: 'nature', image: 'assets/nature.png' },
331
+ { name: 'summer', image: 'assets/summer.png' },
332
+ { name: 'beach', image: 'assets/beach.png' },
333
+ { name: 'space', image: 'assets/space.png' },
334
+ { name: 'office', image: 'assets/office.png' },
335
+ { name: 'food', image: 'assets/food.png' },
336
+ ];
337
+
338
+ // Video list
339
+ var video_categories = [
340
+ { name: 'rain', image: 'assets/rain.png' },
341
+ { name: 'cars', image: 'assets/cars.png' },
342
+ { name: 'meditation', image: 'assets/meditation.png' },
343
+ { name: 'forest', image: 'assets/forest.png' },
344
+ { name: 'animals', image: 'assets/animals.png' },
345
+ { name: 'street', image: 'assets/street.png' },
346
+ { name: 'travel', image: 'assets/travel.png' },
347
+ { name: 'work', image: 'assets/work.png' },
348
+ ];
349
+
350
+ // Audio list
351
+ var audio_items = [
352
+ {
353
+ name: 'Lofi Study',
354
+ desc: 'FASSounds',
355
+ duration: '2:27',
356
+ thumb: 'assets/audio/lofi-thumb.png',
357
+ src: 'assets/audio/lofi.mp3',
358
+ link: 'https://pixabay.com/users/fassounds-3433550/',
359
+ },
360
+ {
361
+ name: 'Stomping Rock (Four Shots)',
362
+ desc: 'AlexGrohl',
363
+ duration: '1:59',
364
+ thumb: 'assets/audio/stomping-rock-thumb.png',
365
+ src: 'assets/audio/stomping-rock.mp3',
366
+ link: 'https://pixabay.com/users/alexgrohl-25289918/',
367
+ },
368
+ {
369
+ name: 'Everything Feels New',
370
+ desc: 'EvgenyBardyuzha',
371
+ duration: '1:06',
372
+ thumb: 'assets/audio/everything-feels-new-thumb.png',
373
+ src: 'assets/audio/everything-feels-new.mp3',
374
+ link: 'https://pixabay.com/users/evgenybardyuzha-25235210/',
375
+ },
376
+ {
377
+ name: 'Both of Us',
378
+ desc: 'madiRFAN',
379
+ duration: '2:48',
380
+ thumb: 'assets/audio/both-of-us-thumb.png',
381
+ src: 'assets/audio/both-of-us.mp3',
382
+ link: 'https://pixabay.com/users/madirfan-50411/',
383
+ },
384
+ {
385
+ name: 'The Podcast Intro',
386
+ desc: 'Music Unlimited',
387
+ duration: '1:51',
388
+ thumb: 'assets/audio/the-podcast-intro-thumb.png',
389
+ src: 'assets/audio/the-podcast-intro.mp3',
390
+ link: 'https://pixabay.com/users/music_unlimited-27600023/',
391
+ },
392
+ {
393
+ name: 'Epic Cinematic Trailer',
394
+ desc: 'PavelYudin',
395
+ duration: '2:27',
396
+ thumb: 'assets/audio/epic-cinematic-trailer-thumb.png',
397
+ src: 'assets/audio/epic-cinematic-trailer.mp3',
398
+ link: 'https://pixabay.com/users/pavelyudin-27739282/',
399
+ },
400
+ {
401
+ name: 'Inspirational Background',
402
+ desc: 'AudioCoffee',
403
+ duration: '2:19',
404
+ thumb: 'assets/audio/inspirational-background-thumb.png',
405
+ src: 'assets/audio/inspirational-background.mp3',
406
+ link: 'https://pixabay.com/users/audiocoffee-27005420/',
407
+ },
408
+ {
409
+ name: 'Tropical Summer Music',
410
+ desc: 'Music Unlimited',
411
+ duration: '2:35',
412
+ thumb: 'assets/audio/tropical-summer-music-thumb.png',
413
+ src: 'assets/audio/tropical-summer-music.mp3',
414
+ link: 'https://pixabay.com/users/music_unlimited-27600023/',
415
+ },
416
+ ];
417
+
418
+ // Text list
419
+ var text_items = {
420
+ sansserif: [
421
+ { name: 'Roboto', fontname: 'Roboto' },
422
+ { name: 'Montserrat', fontname: 'Montserrat' },
423
+ { name: 'Poppins', fontname: 'Poppins' },
424
+ ],
425
+ serif: [
426
+ { name: 'Playfair Display', fontname: 'Playfair Display' },
427
+ { name: 'Merriweather', fontname: 'Merriweather' },
428
+ { name: 'IBM Plex Serif', fontname: 'IBM Plex Serif' },
429
+ ],
430
+ monospace: [
431
+ { name: 'Roboto Mono', fontname: 'Roboto Mono' },
432
+ { name: 'Inconsolata', fontname: 'Inconsolata' },
433
+ { name: 'Source Code Pro', fontname: 'Source Code Pro' },
434
+ ],
435
+ handwriting: [
436
+ { name: 'Dancing Script', fontname: 'Dancing Script' },
437
+ { name: 'Pacifico', fontname: 'Pacifico' },
438
+ { name: 'Indie Flower', fontname: 'Indie Flower' },
439
+ ],
440
+ display: [
441
+ { name: 'Lobster', fontname: 'Lobster' },
442
+ { name: 'Bebas Neue', fontname: 'Bebas Neue' },
443
+ { name: 'Titan One', fontname: 'Titan One' },
444
+ ],
445
+ };
446
+
447
+ WebFont.load({
448
+ google: {
449
+ families: ['Syne'],
450
+ },
451
+ active: () => {},
452
+ });
453
+
454
+ var webglBackend;
455
+ try {
456
+ webglBackend = new fabric.WebglFilterBackend();
457
+ } catch (e) {
458
+ console.log(e);
459
+ }
460
+ var canvas2dBackend = new fabric.Canvas2dFilterBackend();
461
+
462
+ fabric.filterBackend = fabric.initFilterBackend();
463
+ fabric.filterBackend = webglBackend;
464
+
465
+ // Lottie support
466
+ fabric.Lottie = fabric.util.createClass(fabric.Image, {
467
+ type: 'lottie',
468
+ lockRotation: true,
469
+ lockSkewingX: true,
470
+ lockSkewingY: true,
471
+ srcFromAttribute: false,
472
+
473
+ initialize: function (path, options) {
474
+ if (!options.width) options.width = 480;
475
+ if (!options.height) options.height = 480;
476
+
477
+ this.path = path;
478
+ this.tmpCanvasEl = fabric.util.createCanvasElement();
479
+ this.tmpCanvasEl.width = options.width;
480
+ this.tmpCanvasEl.height = options.height;
481
+
482
+ this.lottieItem = bodymovin.loadAnimation({
483
+ renderer: 'canvas',
484
+ loop: false,
485
+ autoplay: false,
486
+ path: path,
487
+ rendererSettings: {
488
+ context: this.tmpCanvasEl.getContext('2d'),
489
+ preserveAspectRatio: 'xMidYMid meet',
490
+ },
491
+ });
492
+
493
+ this.lottieItem.addEventListener('enterFrame', (e) => {
494
+ this.canvas.requestRenderAll();
495
+ });
496
+
497
+ this.lottieItem.addEventListener('DOMLoaded', () => {
498
+ this.lottieItem.goToAndStop(currenttime, false);
499
+ this.lottieItem.duration =
500
+ this.lottieItem.getDuration(false) * 1000;
501
+ this.canvas.requestRenderAll();
502
+ canvas.renderAll();
503
+ canvas.fire('lottie:loaded', { any: 'payload' });
504
+ });
505
+
506
+ this.callSuper('initialize', this.tmpCanvasEl, options);
507
+ },
508
+
509
+ goToSeconds: function (seconds) {
510
+ this.lottieItem.goToAndStop(seconds, false);
511
+ this.canvas.requestRenderAll();
512
+ },
513
+ goToFrame: function (frame) {
514
+ this.lottieItem.goToAndStop(frame, true);
515
+ },
516
+ getDuration: function () {
517
+ return this.lottieItem.getDuration(false);
518
+ },
519
+ play: function () {
520
+ this.lottieItem.play();
521
+ },
522
+ pause: function () {
523
+ this.lottieItem.pause();
524
+ },
525
+ getSrc: function () {
526
+ return this.path;
527
+ },
528
+ });
529
+
530
+ fabric.Lottie.fromObject = function (_object, callback) {
531
+ const object = fabric.util.object.clone(_object);
532
+ fabric.Image.prototype._initFilters.call(
533
+ object,
534
+ object.filters,
535
+ function (filters) {
536
+ object.filters = filters || [];
537
+ fabric.Image.prototype._initFilters.call(
538
+ object,
539
+ [object.resizeFilter],
540
+ function (resizeFilters) {
541
+ object.resizeFilter = resizeFilters[0];
542
+ fabric.util.enlivenObjects(
543
+ [object.clipPath],
544
+ function (enlivedProps) {
545
+ object.clipPath = enlivedProps[0];
546
+ const fabricLottie = new fabric.Lottie(
547
+ object.src,
548
+ object
549
+ );
550
+ callback(fabricLottie, false);
551
+ }
552
+ );
553
+ }
554
+ );
555
+ }
556
+ );
557
+ };
558
+
559
+ // Initialize canvas
560
+ var canvas = new fabric.Canvas('canvas', {
561
+ preserveObjectStacking: true,
562
+ backgroundColor: '#FFF',
563
+ stateful: true,
564
+ });
565
+ canvas.selection = false;
566
+ canvas.controlsAboveOverlay = true;
567
+
568
+ // Customize controls
569
+ fabric.Object.prototype.set({
570
+ transparentCorners: false,
571
+ borderColor: '#51B9F9',
572
+ cornerColor: '#FFF',
573
+ borderScaleFactor: 2.5,
574
+ cornerStyle: 'circle',
575
+ cornerStrokeColor: '#0E98FC',
576
+ borderOpacityWhenMoving: 1,
577
+ });
578
+
579
+ canvas.selectionColor = 'rgba(46, 115, 252, 0.11)';
580
+ canvas.selectionBorderColor = 'rgba(98, 155, 255, 0.81)';
581
+ canvas.selectionLineWidth = 1.5;
582
+
583
+ var img = document.createElement('img');
584
+ img.src = 'assets/middlecontrol.svg';
585
+
586
+ var img2 = document.createElement('img');
587
+ img2.src = 'assets/middlecontrolhoz.svg';
588
+
589
+ var img3 = document.createElement('img');
590
+ img3.src = 'assets/edgecontrol.svg';
591
+
592
+ var img4 = document.createElement('img');
593
+ img4.src = 'assets/rotateicon.svg';
594
+
595
+ function renderIcon(ctx, left, top, styleOverride, fabricObject) {
596
+ const wsize = 20;
597
+ const hsize = 25;
598
+ ctx.save();
599
+ ctx.translate(left, top);
600
+ ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
601
+ ctx.drawImage(img, -wsize / 2, -hsize / 2, wsize, hsize);
602
+ ctx.restore();
603
+ }
604
+ function renderIconHoz(ctx, left, top, styleOverride, fabricObject) {
605
+ const wsize = 25;
606
+ const hsize = 20;
607
+ ctx.save();
608
+ ctx.translate(left, top);
609
+ ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
610
+ ctx.drawImage(img2, -wsize / 2, -hsize / 2, wsize, hsize);
611
+ ctx.restore();
612
+ }
613
+ function renderIconEdge(ctx, left, top, styleOverride, fabricObject) {
614
+ const wsize = 25;
615
+ const hsize = 25;
616
+ ctx.save();
617
+ ctx.translate(left, top);
618
+ ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
619
+ ctx.drawImage(img3, -wsize / 2, -hsize / 2, wsize, hsize);
620
+ ctx.restore();
621
+ }
622
+
623
+ function renderIconRotate(
624
+ ctx,
625
+ left,
626
+ top,
627
+ styleOverride,
628
+ fabricObject
629
+ ) {
630
+ const wsize = 40;
631
+ const hsize = 40;
632
+ ctx.save();
633
+ ctx.translate(left, top);
634
+ ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
635
+ ctx.drawImage(img4, -wsize / 2, -hsize / 2, wsize, hsize);
636
+ ctx.restore();
637
+ }
638
+ function resetControls() {
639
+ fabric.Object.prototype.controls.ml = new fabric.Control({
640
+ x: -0.5,
641
+ y: 0,
642
+ offsetX: -1,
643
+ cursorStyleHandler:
644
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
645
+ actionHandler: fabric.controlsUtils.scalingXOrSkewingY,
646
+ getActionName: fabric.controlsUtils.scaleOrSkewActionName,
647
+ render: renderIcon,
648
+ });
649
+
650
+ fabric.Object.prototype.controls.mr = new fabric.Control({
651
+ x: 0.5,
652
+ y: 0,
653
+ offsetX: 1,
654
+ cursorStyleHandler:
655
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
656
+ actionHandler: fabric.controlsUtils.scalingXOrSkewingY,
657
+ getActionName: fabric.controlsUtils.scaleOrSkewActionName,
658
+ render: renderIcon,
659
+ });
660
+
661
+ fabric.Object.prototype.controls.mb = new fabric.Control({
662
+ x: 0,
663
+ y: 0.5,
664
+ offsetY: 1,
665
+ cursorStyleHandler:
666
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
667
+ actionHandler: fabric.controlsUtils.scalingYOrSkewingX,
668
+ getActionName: fabric.controlsUtils.scaleOrSkewActionName,
669
+ render: renderIconHoz,
670
+ });
671
+
672
+ fabric.Object.prototype.controls.mt = new fabric.Control({
673
+ x: 0,
674
+ y: -0.5,
675
+ offsetY: -1,
676
+ cursorStyleHandler:
677
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
678
+ actionHandler: fabric.controlsUtils.scalingYOrSkewingX,
679
+ getActionName: fabric.controlsUtils.scaleOrSkewActionName,
680
+ render: renderIconHoz,
681
+ });
682
+
683
+ fabric.Object.prototype.controls.tl = new fabric.Control({
684
+ x: -0.5,
685
+ y: -0.5,
686
+ cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
687
+ actionHandler: fabric.controlsUtils.scalingEqually,
688
+ render: renderIconEdge,
689
+ });
690
+
691
+ fabric.Object.prototype.controls.tr = new fabric.Control({
692
+ x: 0.5,
693
+ y: -0.5,
694
+ cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
695
+ actionHandler: fabric.controlsUtils.scalingEqually,
696
+ render: renderIconEdge,
697
+ });
698
+
699
+ fabric.Object.prototype.controls.bl = new fabric.Control({
700
+ x: -0.5,
701
+ y: 0.5,
702
+ cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
703
+ actionHandler: fabric.controlsUtils.scalingEqually,
704
+ render: renderIconEdge,
705
+ });
706
+
707
+ fabric.Object.prototype.controls.br = new fabric.Control({
708
+ x: 0.5,
709
+ y: 0.5,
710
+ cursorStyleHandler: fabric.controlsUtils.scaleCursorStyleHandler,
711
+ actionHandler: fabric.controlsUtils.scalingEqually,
712
+ render: renderIconEdge,
713
+ });
714
+
715
+ fabric.Object.prototype.controls.mtr = new fabric.Control({
716
+ x: 0,
717
+ y: 0.5,
718
+ cursorStyleHandler: fabric.controlsUtils.rotationStyleHandler,
719
+ actionHandler: fabric.controlsUtils.rotationWithSnapping,
720
+ offsetY: 30,
721
+ withConnecton: false,
722
+ actionName: 'rotate',
723
+ render: renderIconRotate,
724
+ });
725
+ }
726
+ resetControls();
727
+ var textBoxControls = (fabric.Textbox.prototype.controls = {});
728
+
729
+ textBoxControls.mtr = fabric.Object.prototype.controls.mtr;
730
+ textBoxControls.tr = fabric.Object.prototype.controls.tr;
731
+ textBoxControls.br = fabric.Object.prototype.controls.br;
732
+ textBoxControls.tl = fabric.Object.prototype.controls.tl;
733
+ textBoxControls.bl = fabric.Object.prototype.controls.bl;
734
+ textBoxControls.mt = fabric.Object.prototype.controls.mt;
735
+ textBoxControls.mb = fabric.Object.prototype.controls.mb;
736
+
737
+ textBoxControls.ml = new fabric.Control({
738
+ x: -0.5,
739
+ y: 0,
740
+ offsetX: -1,
741
+ cursorStyleHandler:
742
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
743
+ actionHandler: fabric.controlsUtils.changeWidth,
744
+ actionName: 'resizing',
745
+ render: renderIcon,
746
+ });
747
+
748
+ textBoxControls.mr = new fabric.Control({
749
+ x: 0.5,
750
+ y: 0,
751
+ offsetX: 1,
752
+ cursorStyleHandler:
753
+ fabric.controlsUtils.scaleSkewCursorStyleHandler,
754
+ actionHandler: fabric.controlsUtils.changeWidth,
755
+ actionName: 'resizing',
756
+ render: renderIcon,
757
+ });
758
+
759
+ // Get any object by ID
760
+ fabric.Canvas.prototype.getItemById = function (name) {
761
+ var object = null,
762
+ objects = this.getObjects();
763
+ for (var i = 0, len = this.size(); i < len; i++) {
764
+ if (objects[i].get('type') == 'group') {
765
+ if (objects[i].get('id') && objects[i].get('id') === name) {
766
+ object = objects[i];
767
+ break;
768
+ }
769
+ var wip = i;
770
+ for (var o = 0; o < objects[i]._objects.length; o++) {
771
+ if (
772
+ objects[wip]._objects[o].id &&
773
+ objects[wip]._objects[o].id === name
774
+ ) {
775
+ object = objects[wip]._objects[o];
776
+ break;
777
+ }
778
+ }
779
+ } else if (objects[i].id && objects[i].id === name) {
780
+ object = objects[i];
781
+ break;
782
+ }
783
+ }
784
+ return object;
785
+ };
786
+
787
+ // Create the artboard
788
+ var a_width = 600;
789
+ var a_height = 500;
790
+ var artboard = new fabric.Rect({
791
+ left: canvas.get('width') / 2 - a_width / 2,
792
+ top: canvas.get('height') / 2 - a_height / 2,
793
+ width: a_width,
794
+ height: a_height,
795
+ absolutePositioned: true,
796
+ rx: 0,
797
+ ry: 0,
798
+ fill: '#FFF',
799
+ hasControls: true,
800
+ transparentCorners: false,
801
+ borderColor: '#0E98FC',
802
+ cornerColor: '#0E98FC',
803
+ cursorWidth: 1,
804
+ cursorDuration: 1,
805
+ cursorDelay: 250,
806
+ id: 'overlay',
807
+ });
808
+ canvas.renderAll();
809
+
810
+ // Clip canvas to the artboard
811
+ canvas.clipPath = artboard;
812
+ canvas.renderAll();
813
+
814
+ // Initialize color picker (fill)
815
+ var o_fill = Pickr.create({
816
+ el: '#color-picker-fill',
817
+ theme: 'nano',
818
+ inline: true,
819
+ useAsButton: true,
820
+ swatches: null,
821
+ default: '#FFFFFF',
822
+ showAlways: true,
823
+ components: {
824
+ preview: true,
825
+ opacity: true,
826
+ hue: true,
827
+ interaction: {
828
+ hex: true,
829
+ rgba: true,
830
+ hsla: false,
831
+ hsva: false,
832
+ cmyk: false,
833
+ input: true,
834
+ clear: false,
835
+ save: false,
836
+ },
837
+ },
838
+ });
839
+
840
+ // Color picker events
841
+ o_fill
842
+ .on('init', (instance) => {
843
+ o_fill.hide();
844
+ })
845
+ .on('change', (instance) => {
846
+ if (canvas.getActiveObject()) {
847
+ const object = canvas.getActiveObject();
848
+ if (colormode == 'fill') {
849
+ $('#object-color-fill input').val(
850
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
851
+ );
852
+ $('#object-color-fill-opacity input').val(
853
+ Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
854
+ );
855
+ $('#color-fill-side').css(
856
+ 'background-color',
857
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
858
+ );
859
+ object.set('fill', o_fill.getColor().toRGBA().toString());
860
+ if (!seeking && !setting) {
861
+ newKeyframe(
862
+ 'fill',
863
+ object,
864
+ currenttime,
865
+ object.get('fill'),
866
+ true
867
+ );
868
+ }
869
+ } else if (colormode == 'stroke') {
870
+ $('#object-color-stroke input').val(
871
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
872
+ );
873
+ $('#object-color-stroke-opacity input').val(
874
+ Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
875
+ );
876
+ $('#color-stroke-side').css(
877
+ 'background-color',
878
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
879
+ );
880
+ object.set('stroke', o_fill.getColor().toRGBA().toString());
881
+ if (!seeking && !setting) {
882
+ newKeyframe(
883
+ 'stroke',
884
+ object,
885
+ currenttime,
886
+ object.get('stroke'),
887
+ true
888
+ );
889
+ newKeyframe(
890
+ 'strokeWidth',
891
+ object,
892
+ currenttime,
893
+ object.get('strokeWidth'),
894
+ true
895
+ );
896
+ }
897
+ } else if (colormode == 'shadow') {
898
+ $('#object-color-shadow input').val(
899
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
900
+ );
901
+ $('#object-color-shadow-opacity input').val(
902
+ Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
903
+ );
904
+ $('#color-shadow-side').css(
905
+ 'background-color',
906
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
907
+ );
908
+ object.set(
909
+ 'shadow',
910
+ new fabric.Shadow({
911
+ color: o_fill.getColor().toRGBA().toString(),
912
+ offsetX: object.shadow.offsetX,
913
+ offsetY: object.shadow.offsetY,
914
+ blur: object.shadow.blur,
915
+ opacity: object.shadow.opacity,
916
+ })
917
+ );
918
+ if (!seeking && !setting) {
919
+ newKeyframe(
920
+ 'shadow.color',
921
+ object,
922
+ currenttime,
923
+ object.shadow.color,
924
+ true
925
+ );
926
+ }
927
+ } else if (colormode == 'chroma') {
928
+ var obj = canvas.getActiveObject();
929
+ $('#chroma-color input').val(
930
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
931
+ );
932
+ $('#color-chroma-side').css(
933
+ 'background-color',
934
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
935
+ );
936
+ if (obj.filters.find((x) => x.type == 'RemoveColor')) {
937
+ obj.filters.find((x) => x.type == 'RemoveColor').color =
938
+ o_fill.getColor().toRGBA().toString();
939
+ }
940
+ updateChromaValues();
941
+ } else if (colormode == 'text') {
942
+ var obj = canvas.getActiveObject();
943
+ $('#text-color input').val(
944
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
945
+ );
946
+ $('#color-text-side').css(
947
+ 'background-color',
948
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
949
+ );
950
+ animatedtext
951
+ .find((x) => x.id == obj.id)
952
+ .setProps(
953
+ { fill: o_fill.getColor().toRGBA().toString() },
954
+ canvas
955
+ );
956
+ }
957
+ canvas.renderAll();
958
+ } else {
959
+ if (colormode == 'back') {
960
+ $('#canvas-color input').val(
961
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
962
+ );
963
+ $('#canvas-color-opacity input').val(
964
+ Math.round(o_fill.getColor().toRGBA()[3] * 100 * 100) / 100
965
+ );
966
+ $('#color-side').css(
967
+ 'background-color',
968
+ o_fill.getColor().toHEXA().toString().substring(0, 7)
969
+ );
970
+ canvas.setBackgroundColor(
971
+ o_fill.getColor().toRGBA().toString()
972
+ );
973
+ canvas.renderAll();
974
+ }
975
+ }
976
+ })
977
+ .on('show', (instance) => {
978
+ $('.pcr-current-color').html(
979
+ "<img id='eyedropper' src='assets/eyedropper.svg'>"
980
+ );
981
+ });
982
+
983
+ var f = fabric.Image.filters;
984
+
985
+ // Canvas recorder initialization
986
+ var canvasrecord = new fabric.Canvas('canvasrecord', {
987
+ preserveObjectStacking: true,
988
+ backgroundColor: '#FFF',
989
+ width: artboard.width,
990
+ height: artboard.height,
991
+ });
992
+
993
+ var timelineslider = document.getElementById('timeline-zoom');
994
+ var t_slider = new RangeSlider(timelineslider, {
995
+ design: '2d',
996
+ theme: 'default',
997
+ handle: 'round',
998
+ popup: null,
999
+ showMinMaxLabels: false,
1000
+ unit: '%',
1001
+ min: 5,
1002
+ max: 47,
1003
+ value: 47,
1004
+ onmove: function (x) {
1005
+ setTimelineZoom(-1 * (x - 51));
1006
+ },
1007
+ onfinish: function (x) {
1008
+ setTimelineZoom(-1 * (x - 51));
1009
+ },
1010
+ onstart: function (x) {},
1011
+ });
1012
+
1013
+ const selectbox = new SelectionArea({
1014
+ class: 'selection-area',
1015
+ selectables: ['.keyframe'],
1016
+ container: '#timeline',
1017
+ // Query selectors for elements from where a selection can be started from.
1018
+ startareas: ['html'],
1019
+
1020
+ // Query selectors for elements which will be used as boundaries for the selection.
1021
+ boundaries: ['#timeline'],
1022
+
1023
+ startThreshold: 10,
1024
+
1025
+ allowTouch: true,
1026
+
1027
+ intersect: 'touch',
1028
+
1029
+ overlap: 'invert',
1030
+
1031
+ // Configuration in case a selectable gets just clicked.
1032
+ singleTap: {
1033
+ allow: false,
1034
+ intersect: 'native',
1035
+ },
1036
+
1037
+ // Scroll configuration.
1038
+ scrolling: {
1039
+ speedDivider: 10,
1040
+ manualSpeed: 750,
1041
+ },
1042
+ });
1043
+
1044
+ selectbox
1045
+ .on('beforestart', (evt) => {
1046
+ if (
1047
+ $(evt.event.target).hasClass('keyframe') ||
1048
+ $(evt.event.target).attr('id') == 'seekbar' ||
1049
+ $(evt.event.target).parent().hasClass('main-row') ||
1050
+ $(evt.event.target).hasClass('main-row') ||
1051
+ $(evt.event.target).hasClass('trim-row') ||
1052
+ evt.event.which === 3
1053
+ ) {
1054
+ return false;
1055
+ }
1056
+ })
1057
+ .on('start', (evt) => {})
1058
+ .on('move', (evt) => {})
1059
+ .on('stop', (evt) => {
1060
+ $('.keyframe-selected').removeClass('keyframe-selected');
1061
+ shiftkeys = [];
1062
+ if (evt.store.selected.length == 0) {
1063
+ $('.keyframe-selected').removeClass('keyframe-selected');
1064
+ } else {
1065
+ canvas.discardActiveObject();
1066
+ canvas.renderAll();
1067
+ evt.store.selected.forEach(function (key) {
1068
+ shiftkeys.push({
1069
+ keyframe: key,
1070
+ offset: $(key).offset().left,
1071
+ });
1072
+ $(key).addClass('keyframe-selected');
1073
+ });
1074
+ }
1075
+ });
js/libraries/anime.min.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * anime.js v3.2.1
3
+ * (c) 2020 Julian Garnier
4
+ * Released under the MIT license
5
+ * animejs.com
6
+ */
7
+
8
+ !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):n.anime=e()}(this,function(){"use strict";var n={update:null,begin:null,loopBegin:null,changeBegin:null,change:null,changeComplete:null,loopComplete:null,complete:null,loop:1,direction:"normal",autoplay:!0,timelineOffset:0},e={duration:1e3,delay:0,endDelay:0,easing:"easeOutElastic(1, .5)",round:0},t=["translateX","translateY","translateZ","rotate","rotateX","rotateY","rotateZ","scale","scaleX","scaleY","scaleZ","skew","skewX","skewY","perspective","matrix","matrix3d"],r={CSS:{},springs:{}};function a(n,e,t){return Math.min(Math.max(n,e),t)}function o(n,e){return n.indexOf(e)>-1}function u(n,e){return n.apply(null,e)}var i={arr:function(n){return Array.isArray(n)},obj:function(n){return o(Object.prototype.toString.call(n),"Object")},pth:function(n){return i.obj(n)&&n.hasOwnProperty("totalLength")},svg:function(n){return n instanceof SVGElement},inp:function(n){return n instanceof HTMLInputElement},dom:function(n){return n.nodeType||i.svg(n)},str:function(n){return"string"==typeof n},fnc:function(n){return"function"==typeof n},und:function(n){return void 0===n},nil:function(n){return i.und(n)||null===n},hex:function(n){return/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(n)},rgb:function(n){return/^rgb/.test(n)},hsl:function(n){return/^hsl/.test(n)},col:function(n){return i.hex(n)||i.rgb(n)||i.hsl(n)},key:function(t){return!n.hasOwnProperty(t)&&!e.hasOwnProperty(t)&&"targets"!==t&&"keyframes"!==t}};function c(n){var e=/\(([^)]+)\)/.exec(n);return e?e[1].split(",").map(function(n){return parseFloat(n)}):[]}function s(n,e){var t=c(n),o=a(i.und(t[0])?1:t[0],.1,100),u=a(i.und(t[1])?100:t[1],.1,100),s=a(i.und(t[2])?10:t[2],.1,100),f=a(i.und(t[3])?0:t[3],.1,100),l=Math.sqrt(u/o),d=s/(2*Math.sqrt(u*o)),p=d<1?l*Math.sqrt(1-d*d):0,v=1,h=d<1?(d*l-f)/p:-f+l;function g(n){var t=e?e*n/1e3:n;return t=d<1?Math.exp(-t*d*l)*(v*Math.cos(p*t)+h*Math.sin(p*t)):(v+h*t)*Math.exp(-t*l),0===n||1===n?n:1-t}return e?g:function(){var e=r.springs[n];if(e)return e;for(var t=0,a=0;;)if(1===g(t+=1/6)){if(++a>=16)break}else a=0;var o=t*(1/6)*1e3;return r.springs[n]=o,o}}function f(n){return void 0===n&&(n=10),function(e){return Math.ceil(a(e,1e-6,1)*n)*(1/n)}}var l,d,p=function(){var n=11,e=1/(n-1);function t(n,e){return 1-3*e+3*n}function r(n,e){return 3*e-6*n}function a(n){return 3*n}function o(n,e,o){return((t(e,o)*n+r(e,o))*n+a(e))*n}function u(n,e,o){return 3*t(e,o)*n*n+2*r(e,o)*n+a(e)}return function(t,r,a,i){if(0<=t&&t<=1&&0<=a&&a<=1){var c=new Float32Array(n);if(t!==r||a!==i)for(var s=0;s<n;++s)c[s]=o(s*e,t,a);return function(n){return t===r&&a===i?n:0===n||1===n?n:o(f(n),r,i)}}function f(r){for(var i=0,s=1,f=n-1;s!==f&&c[s]<=r;++s)i+=e;var l=i+(r-c[--s])/(c[s+1]-c[s])*e,d=u(l,t,a);return d>=.001?function(n,e,t,r){for(var a=0;a<4;++a){var i=u(e,t,r);if(0===i)return e;e-=(o(e,t,r)-n)/i}return e}(r,l,t,a):0===d?l:function(n,e,t,r,a){for(var u,i,c=0;(u=o(i=e+(t-e)/2,r,a)-n)>0?t=i:e=i,Math.abs(u)>1e-7&&++c<10;);return i}(r,i,i+e,t,a)}}}(),v=(l={linear:function(){return function(n){return n}}},d={Sine:function(){return function(n){return 1-Math.cos(n*Math.PI/2)}},Circ:function(){return function(n){return 1-Math.sqrt(1-n*n)}},Back:function(){return function(n){return n*n*(3*n-2)}},Bounce:function(){return function(n){for(var e,t=4;n<((e=Math.pow(2,--t))-1)/11;);return 1/Math.pow(4,3-t)-7.5625*Math.pow((3*e-2)/22-n,2)}},Elastic:function(n,e){void 0===n&&(n=1),void 0===e&&(e=.5);var t=a(n,1,10),r=a(e,.1,2);return function(n){return 0===n||1===n?n:-t*Math.pow(2,10*(n-1))*Math.sin((n-1-r/(2*Math.PI)*Math.asin(1/t))*(2*Math.PI)/r)}}},["Quad","Cubic","Quart","Quint","Expo"].forEach(function(n,e){d[n]=function(){return function(n){return Math.pow(n,e+2)}}}),Object.keys(d).forEach(function(n){var e=d[n];l["easeIn"+n]=e,l["easeOut"+n]=function(n,t){return function(r){return 1-e(n,t)(1-r)}},l["easeInOut"+n]=function(n,t){return function(r){return r<.5?e(n,t)(2*r)/2:1-e(n,t)(-2*r+2)/2}},l["easeOutIn"+n]=function(n,t){return function(r){return r<.5?(1-e(n,t)(1-2*r))/2:(e(n,t)(2*r-1)+1)/2}}}),l);function h(n,e){if(i.fnc(n))return n;var t=n.split("(")[0],r=v[t],a=c(n);switch(t){case"spring":return s(n,e);case"cubicBezier":return u(p,a);case"steps":return u(f,a);default:return u(r,a)}}function g(n){try{return document.querySelectorAll(n)}catch(n){return}}function m(n,e){for(var t=n.length,r=arguments.length>=2?arguments[1]:void 0,a=[],o=0;o<t;o++)if(o in n){var u=n[o];e.call(r,u,o,n)&&a.push(u)}return a}function y(n){return n.reduce(function(n,e){return n.concat(i.arr(e)?y(e):e)},[])}function b(n){return i.arr(n)?n:(i.str(n)&&(n=g(n)||n),n instanceof NodeList||n instanceof HTMLCollection?[].slice.call(n):[n])}function M(n,e){return n.some(function(n){return n===e})}function x(n){var e={};for(var t in n)e[t]=n[t];return e}function w(n,e){var t=x(n);for(var r in n)t[r]=e.hasOwnProperty(r)?e[r]:n[r];return t}function k(n,e){var t=x(n);for(var r in e)t[r]=i.und(n[r])?e[r]:n[r];return t}function O(n){return i.rgb(n)?(t=/rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(e=n))?"rgba("+t[1]+",1)":e:i.hex(n)?(r=n.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i,function(n,e,t,r){return e+e+t+t+r+r}),a=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(r),"rgba("+parseInt(a[1],16)+","+parseInt(a[2],16)+","+parseInt(a[3],16)+",1)"):i.hsl(n)?function(n){var e,t,r,a=/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(n)||/hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(n),o=parseInt(a[1],10)/360,u=parseInt(a[2],10)/100,i=parseInt(a[3],10)/100,c=a[4]||1;function s(n,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?n+6*(e-n)*t:t<.5?e:t<2/3?n+(e-n)*(2/3-t)*6:n}if(0==u)e=t=r=i;else{var f=i<.5?i*(1+u):i+u-i*u,l=2*i-f;e=s(l,f,o+1/3),t=s(l,f,o),r=s(l,f,o-1/3)}return"rgba("+255*e+","+255*t+","+255*r+","+c+")"}(n):void 0;var e,t,r,a}function C(n){var e=/[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(n);if(e)return e[1]}function P(n,e){return i.fnc(n)?n(e.target,e.id,e.total):n}function I(n,e){return n.getAttribute(e)}function D(n,e,t){if(M([t,"deg","rad","turn"],C(e)))return e;var a=r.CSS[e+t];if(!i.und(a))return a;var o=document.createElement(n.tagName),u=n.parentNode&&n.parentNode!==document?n.parentNode:document.body;u.appendChild(o),o.style.position="absolute",o.style.width=100+t;var c=100/o.offsetWidth;u.removeChild(o);var s=c*parseFloat(e);return r.CSS[e+t]=s,s}function B(n,e,t){if(e in n.style){var r=e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),a=n.style[e]||getComputedStyle(n).getPropertyValue(r)||"0";return t?D(n,a,t):a}}function T(n,e){return i.dom(n)&&!i.inp(n)&&(!i.nil(I(n,e))||i.svg(n)&&n[e])?"attribute":i.dom(n)&&M(t,e)?"transform":i.dom(n)&&"transform"!==e&&B(n,e)?"css":null!=n[e]?"object":void 0}function E(n){if(i.dom(n)){for(var e,t=n.style.transform||"",r=/(\w+)\(([^)]*)\)/g,a=new Map;e=r.exec(t);)a.set(e[1],e[2]);return a}}function F(n,e,t,r){var a,u=o(e,"scale")?1:0+(o(a=e,"translate")||"perspective"===a?"px":o(a,"rotate")||o(a,"skew")?"deg":void 0),i=E(n).get(e)||u;return t&&(t.transforms.list.set(e,i),t.transforms.last=e),r?D(n,i,r):i}function A(n,e,t,r){switch(T(n,e)){case"transform":return F(n,e,r,t);case"css":return B(n,e,t);case"attribute":return I(n,e);default:return n[e]||0}}function N(n,e){var t=/^(\*=|\+=|-=)/.exec(n);if(!t)return n;var r=C(n)||0,a=parseFloat(e),o=parseFloat(n.replace(t[0],""));switch(t[0][0]){case"+":return a+o+r;case"-":return a-o+r;case"*":return a*o+r}}function S(n,e){if(i.col(n))return O(n);if(/\s/g.test(n))return n;var t=C(n),r=t?n.substr(0,n.length-t.length):n;return e?r+e:r}function L(n,e){return Math.sqrt(Math.pow(e.x-n.x,2)+Math.pow(e.y-n.y,2))}function j(n){for(var e,t=n.points,r=0,a=0;a<t.numberOfItems;a++){var o=t.getItem(a);a>0&&(r+=L(e,o)),e=o}return r}function q(n){if(n.getTotalLength)return n.getTotalLength();switch(n.tagName.toLowerCase()){case"circle":return o=n,2*Math.PI*I(o,"r");case"rect":return 2*I(a=n,"width")+2*I(a,"height");case"line":return L({x:I(r=n,"x1"),y:I(r,"y1")},{x:I(r,"x2"),y:I(r,"y2")});case"polyline":return j(n);case"polygon":return t=(e=n).points,j(e)+L(t.getItem(t.numberOfItems-1),t.getItem(0))}var e,t,r,a,o}function H(n,e){var t=e||{},r=t.el||function(n){for(var e=n.parentNode;i.svg(e)&&i.svg(e.parentNode);)e=e.parentNode;return e}(n),a=r.getBoundingClientRect(),o=I(r,"viewBox"),u=a.width,c=a.height,s=t.viewBox||(o?o.split(" "):[0,0,u,c]);return{el:r,viewBox:s,x:s[0]/1,y:s[1]/1,w:u,h:c,vW:s[2],vH:s[3]}}function V(n,e,t){function r(t){void 0===t&&(t=0);var r=e+t>=1?e+t:0;return n.el.getPointAtLength(r)}var a=H(n.el,n.svg),o=r(),u=r(-1),i=r(1),c=t?1:a.w/a.vW,s=t?1:a.h/a.vH;switch(n.property){case"x":return(o.x-a.x)*c;case"y":return(o.y-a.y)*s;case"angle":return 180*Math.atan2(i.y-u.y,i.x-u.x)/Math.PI}}function $(n,e){var t=/[+-]?\d*\.?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/g,r=S(i.pth(n)?n.totalLength:n,e)+"";return{original:r,numbers:r.match(t)?r.match(t).map(Number):[0],strings:i.str(n)||e?r.split(t):[]}}function W(n){return m(n?y(i.arr(n)?n.map(b):b(n)):[],function(n,e,t){return t.indexOf(n)===e})}function X(n){var e=W(n);return e.map(function(n,t){return{target:n,id:t,total:e.length,transforms:{list:E(n)}}})}function Y(n,e){var t=x(e);if(/^spring/.test(t.easing)&&(t.duration=s(t.easing)),i.arr(n)){var r=n.length;2===r&&!i.obj(n[0])?n={value:n}:i.fnc(e.duration)||(t.duration=e.duration/r)}var a=i.arr(n)?n:[n];return a.map(function(n,t){var r=i.obj(n)&&!i.pth(n)?n:{value:n};return i.und(r.delay)&&(r.delay=t?0:e.delay),i.und(r.endDelay)&&(r.endDelay=t===a.length-1?e.endDelay:0),r}).map(function(n){return k(n,t)})}function Z(n,e){var t=[],r=e.keyframes;for(var a in r&&(e=k(function(n){for(var e=m(y(n.map(function(n){return Object.keys(n)})),function(n){return i.key(n)}).reduce(function(n,e){return n.indexOf(e)<0&&n.push(e),n},[]),t={},r=function(r){var a=e[r];t[a]=n.map(function(n){var e={};for(var t in n)i.key(t)?t==a&&(e.value=n[t]):e[t]=n[t];return e})},a=0;a<e.length;a++)r(a);return t}(r),e)),e)i.key(a)&&t.push({name:a,tweens:Y(e[a],n)});return t}function G(n,e){var t;return n.tweens.map(function(r){var a=function(n,e){var t={};for(var r in n){var a=P(n[r],e);i.arr(a)&&1===(a=a.map(function(n){return P(n,e)})).length&&(a=a[0]),t[r]=a}return t.duration=parseFloat(t.duration),t.delay=parseFloat(t.delay),t}(r,e),o=a.value,u=i.arr(o)?o[1]:o,c=C(u),s=A(e.target,n.name,c,e),f=t?t.to.original:s,l=i.arr(o)?o[0]:f,d=C(l)||C(s),p=c||d;return i.und(u)&&(u=f),a.from=$(l,p),a.to=$(N(u,l),p),a.start=t?t.end:0,a.end=a.start+a.delay+a.duration+a.endDelay,a.easing=h(a.easing,a.duration),a.isPath=i.pth(o),a.isPathTargetInsideSVG=a.isPath&&i.svg(e.target),a.isColor=i.col(a.from.original),a.isColor&&(a.round=1),t=a,a})}var Q={css:function(n,e,t){return n.style[e]=t},attribute:function(n,e,t){return n.setAttribute(e,t)},object:function(n,e,t){return n[e]=t},transform:function(n,e,t,r,a){if(r.list.set(e,t),e===r.last||a){var o="";r.list.forEach(function(n,e){o+=e+"("+n+") "}),n.style.transform=o}}};function z(n,e){X(n).forEach(function(n){for(var t in e){var r=P(e[t],n),a=n.target,o=C(r),u=A(a,t,o,n),i=N(S(r,o||C(u)),u),c=T(a,t);Q[c](a,t,i,n.transforms,!0)}})}function _(n,e){return m(y(n.map(function(n){return e.map(function(e){return function(n,e){var t=T(n.target,e.name);if(t){var r=G(e,n),a=r[r.length-1];return{type:t,property:e.name,animatable:n,tweens:r,duration:a.end,delay:r[0].delay,endDelay:a.endDelay}}}(n,e)})})),function(n){return!i.und(n)})}function R(n,e){var t=n.length,r=function(n){return n.timelineOffset?n.timelineOffset:0},a={};return a.duration=t?Math.max.apply(Math,n.map(function(n){return r(n)+n.duration})):e.duration,a.delay=t?Math.min.apply(Math,n.map(function(n){return r(n)+n.delay})):e.delay,a.endDelay=t?a.duration-Math.max.apply(Math,n.map(function(n){return r(n)+n.duration-n.endDelay})):e.endDelay,a}var J=0;var K=[],U=function(){var n;function e(t){for(var r=K.length,a=0;a<r;){var o=K[a];o.paused?(K.splice(a,1),r--):(o.tick(t),a++)}n=a>0?requestAnimationFrame(e):void 0}return"undefined"!=typeof document&&document.addEventListener("visibilitychange",function(){en.suspendWhenDocumentHidden&&(nn()?n=cancelAnimationFrame(n):(K.forEach(function(n){return n._onDocumentVisibility()}),U()))}),function(){n||nn()&&en.suspendWhenDocumentHidden||!(K.length>0)||(n=requestAnimationFrame(e))}}();function nn(){return!!document&&document.hidden}function en(t){void 0===t&&(t={});var r,o=0,u=0,i=0,c=0,s=null;function f(n){var e=window.Promise&&new Promise(function(n){return s=n});return n.finished=e,e}var l,d,p,v,h,g,y,b,M=(d=w(n,l=t),p=w(e,l),v=Z(p,l),h=X(l.targets),g=_(h,v),y=R(g,p),b=J,J++,k(d,{id:b,children:[],animatables:h,animations:g,duration:y.duration,delay:y.delay,endDelay:y.endDelay}));f(M);function x(){var n=M.direction;"alternate"!==n&&(M.direction="normal"!==n?"normal":"reverse"),M.reversed=!M.reversed,r.forEach(function(n){return n.reversed=M.reversed})}function O(n){return M.reversed?M.duration-n:n}function C(){o=0,u=O(M.currentTime)*(1/en.speed)}function P(n,e){e&&e.seek(n-e.timelineOffset)}function I(n){for(var e=0,t=M.animations,r=t.length;e<r;){var o=t[e],u=o.animatable,i=o.tweens,c=i.length-1,s=i[c];c&&(s=m(i,function(e){return n<e.end})[0]||s);for(var f=a(n-s.start-s.delay,0,s.duration)/s.duration,l=isNaN(f)?1:s.easing(f),d=s.to.strings,p=s.round,v=[],h=s.to.numbers.length,g=void 0,y=0;y<h;y++){var b=void 0,x=s.to.numbers[y],w=s.from.numbers[y]||0;b=s.isPath?V(s.value,l*x,s.isPathTargetInsideSVG):w+l*(x-w),p&&(s.isColor&&y>2||(b=Math.round(b*p)/p)),v.push(b)}var k=d.length;if(k){g=d[0];for(var O=0;O<k;O++){d[O];var C=d[O+1],P=v[O];isNaN(P)||(g+=C?P+C:P+" ")}}else g=v[0];Q[o.type](u.target,o.property,g,u.transforms),o.currentValue=g,e++}}function D(n){M[n]&&!M.passThrough&&M[n](M)}function B(n){var e=M.duration,t=M.delay,l=e-M.endDelay,d=O(n);M.progress=a(d/e*100,0,100),M.reversePlayback=d<M.currentTime,r&&function(n){if(M.reversePlayback)for(var e=c;e--;)P(n,r[e]);else for(var t=0;t<c;t++)P(n,r[t])}(d),!M.began&&M.currentTime>0&&(M.began=!0,D("begin")),!M.loopBegan&&M.currentTime>0&&(M.loopBegan=!0,D("loopBegin")),d<=t&&0!==M.currentTime&&I(0),(d>=l&&M.currentTime!==e||!e)&&I(e),d>t&&d<l?(M.changeBegan||(M.changeBegan=!0,M.changeCompleted=!1,D("changeBegin")),D("change"),I(d)):M.changeBegan&&(M.changeCompleted=!0,M.changeBegan=!1,D("changeComplete")),M.currentTime=a(d,0,e),M.began&&D("update"),n>=e&&(u=0,M.remaining&&!0!==M.remaining&&M.remaining--,M.remaining?(o=i,D("loopComplete"),M.loopBegan=!1,"alternate"===M.direction&&x()):(M.paused=!0,M.completed||(M.completed=!0,D("loopComplete"),D("complete"),!M.passThrough&&"Promise"in window&&(s(),f(M)))))}return M.reset=function(){var n=M.direction;M.passThrough=!1,M.currentTime=0,M.progress=0,M.paused=!0,M.began=!1,M.loopBegan=!1,M.changeBegan=!1,M.completed=!1,M.changeCompleted=!1,M.reversePlayback=!1,M.reversed="reverse"===n,M.remaining=M.loop,r=M.children;for(var e=c=r.length;e--;)M.children[e].reset();(M.reversed&&!0!==M.loop||"alternate"===n&&1===M.loop)&&M.remaining++,I(M.reversed?M.duration:0)},M._onDocumentVisibility=C,M.set=function(n,e){return z(n,e),M},M.tick=function(n){i=n,o||(o=i),B((i+(u-o))*en.speed)},M.seek=function(n){B(O(n))},M.pause=function(){M.paused=!0,C()},M.play=function(){M.paused&&(M.completed&&M.reset(),M.paused=!1,K.push(M),C(),U())},M.reverse=function(){x(),M.completed=!M.reversed,C()},M.restart=function(){M.reset(),M.play()},M.remove=function(n){rn(W(n),M)},M.reset(),M.autoplay&&M.play(),M}function tn(n,e){for(var t=e.length;t--;)M(n,e[t].animatable.target)&&e.splice(t,1)}function rn(n,e){var t=e.animations,r=e.children;tn(n,t);for(var a=r.length;a--;){var o=r[a],u=o.animations;tn(n,u),u.length||o.children.length||r.splice(a,1)}t.length||r.length||e.pause()}return en.version="3.2.1",en.speed=1,en.suspendWhenDocumentHidden=!0,en.running=K,en.remove=function(n){for(var e=W(n),t=K.length;t--;)rn(e,K[t])},en.get=A,en.set=z,en.convertPx=D,en.path=function(n,e){var t=i.str(n)?g(n)[0]:n,r=e||100;return function(n){return{property:n,el:t,svg:H(t),totalLength:q(t)*(r/100)}}},en.setDashoffset=function(n){var e=q(n);return n.setAttribute("stroke-dasharray",e),e},en.stagger=function(n,e){void 0===e&&(e={});var t=e.direction||"normal",r=e.easing?h(e.easing):null,a=e.grid,o=e.axis,u=e.from||0,c="first"===u,s="center"===u,f="last"===u,l=i.arr(n),d=l?parseFloat(n[0]):parseFloat(n),p=l?parseFloat(n[1]):0,v=C(l?n[1]:n)||0,g=e.start||0+(l?d:0),m=[],y=0;return function(n,e,i){if(c&&(u=0),s&&(u=(i-1)/2),f&&(u=i-1),!m.length){for(var h=0;h<i;h++){if(a){var b=s?(a[0]-1)/2:u%a[0],M=s?(a[1]-1)/2:Math.floor(u/a[0]),x=b-h%a[0],w=M-Math.floor(h/a[0]),k=Math.sqrt(x*x+w*w);"x"===o&&(k=-x),"y"===o&&(k=-w),m.push(k)}else m.push(Math.abs(u-h));y=Math.max.apply(Math,m)}r&&(m=m.map(function(n){return r(n/y)*y})),"reverse"===t&&(m=m.map(function(n){return o?n<0?-1*n:-n:Math.abs(y-n)}))}return g+(l?(p-d)/y:d)*(Math.round(100*m[e])/100)+v}},en.timeline=function(n){void 0===n&&(n={});var t=en(n);return t.duration=0,t.add=function(r,a){var o=K.indexOf(t),u=t.children;function c(n){n.passThrough=!0}o>-1&&K.splice(o,1);for(var s=0;s<u.length;s++)c(u[s]);var f=k(r,w(e,n));f.targets=f.targets||n.targets;var l=t.duration;f.autoplay=!1,f.direction=t.direction,f.timelineOffset=i.und(a)?l:N(a,l),c(t),t.seek(f.timelineOffset);var d=en(f);c(d),u.push(d);var p=R(u,n);return t.delay=p.delay,t.endDelay=p.endDelay,t.duration=p.duration,t.seek(0),t.reset(),t.autoplay&&t.play(),t},t},en.easing=h,en.penner=v,en.random=function(n,e){return Math.floor(Math.random()*(e-n+1))+n},en});
js/libraries/fabric.min.js ADDED
The diff for this file is too large to render. See raw diff
 
js/libraries/ffmpeg.min.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.FFmpeg=t():e.FFmpeg=t()}(self,(function(){return e={497:(e,t,r)=>{r(72);var n=r(306).devDependencies;e.exports={corePath:"https://unpkg.com/@ffmpeg/core@".concat(n["@ffmpeg/core"].substring(1),"/dist/ffmpeg-core.js")}},663:(e,t,r)=>{function n(e,t,r,n,o,i,a){try{var c=e[i](a),s=c.value}catch(e){return void r(e)}c.done?t(s):Promise.resolve(s).then(n,o)}var o=r(72),i=function(e){return new Promise((function(t,r){var n=new FileReader;n.onload=function(){t(n.result)},n.onerror=function(e){var t=e.target.error.code;r(Error("File could not be read! Code=".concat(t)))},n.readAsArrayBuffer(e)}))};e.exports=function(){var e,t=(e=regeneratorRuntime.mark((function e(t){var r,n;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=t,void 0!==t){e.next=3;break}return e.abrupt("return",new Uint8Array);case 3:if("string"!=typeof t){e.next=16;break}if(!/data:_data\/([a-zA-Z]*);base64,([^"]*)/.test(t)){e.next=8;break}r=atob(t.split(",")[1]).split("").map((function(e){return e.charCodeAt(0)})),e.next=14;break;case 8:return e.next=10,fetch(o(t));case 10:return n=e.sent,e.next=13,n.arrayBuffer();case 13:r=e.sent;case 14:e.next=20;break;case 16:if(!(t instanceof File||t instanceof Blob)){e.next=20;break}return e.next=19,i(t);case 19:r=e.sent;case 20:return e.abrupt("return",new Uint8Array(r));case 21:case"end":return e.stop()}}),e)})),function(){var t=this,r=arguments;return new Promise((function(o,i){var a=e.apply(t,r);function c(e){n(a,o,i,c,s,"next",e)}function s(e){n(a,o,i,c,s,"throw",e)}c(void 0)}))});return function(e){return t.apply(this,arguments)}}()},452:(e,t,r)=>{function n(e,t,r,n,o,i,a){try{var c=e[i](a),s=c.value}catch(e){return void r(e)}c.done?t(s):Promise.resolve(s).then(n,o)}function o(e){return function(){var t=this,r=arguments;return new Promise((function(o,i){var a=e.apply(t,r);function c(e){n(a,o,i,c,s,"next",e)}function s(e){n(a,o,i,c,s,"throw",e)}c(void 0)}))}}var i=r(72),a=r(185).log,c=function(){var e=o(regeneratorRuntime.mark((function e(t,r){var n,o,i;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return a("info","fetch ".concat(t)),e.next=3,fetch(t);case 3:return e.next=5,e.sent.arrayBuffer();case 5:return n=e.sent,a("info","".concat(t," file size = ").concat(n.byteLength," bytes")),o=new Blob([n],{type:r}),i=URL.createObjectURL(o),a("info","".concat(t," blob URL = ").concat(i)),e.abrupt("return",i);case 11:case"end":return e.stop()}}),e)})));return function(t,r){return e.apply(this,arguments)}}();e.exports=function(){var e=o(regeneratorRuntime.mark((function e(t){var r,n,o,s,u;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if("string"==typeof(r=t.corePath)){e.next=3;break}throw Error("corePath should be a string!");case 3:return n=i(r),e.next=6,c(n,"application/javascript");case 6:return o=e.sent,e.next=9,c(n.replace("ffmpeg-core.js","ffmpeg-core.wasm"),"application/wasm");case 9:return s=e.sent,e.next=12,c(n.replace("ffmpeg-core.js","ffmpeg-core.worker.js"),"application/javascript");case 12:if(u=e.sent,"undefined"!=typeof createFFmpegCore){e.next=15;break}return e.abrupt("return",new Promise((function(e){var t=document.createElement("script");t.src=o,t.type="text/javascript",t.addEventListener("load",(function r(){t.removeEventListener("load",r),a("info","ffmpeg-core.js script loaded"),e({createFFmpegCore,corePath:o,wasmPath:s,workerPath:u})})),document.getElementsByTagName("head")[0].appendChild(t)})));case 15:return a("info","ffmpeg-core.js script is loaded already"),e.abrupt("return",Promise.resolve({createFFmpegCore,corePath:o,wasmPath:s,workerPath:u}));case 17:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()},698:(e,t,r)=>{var n=r(497),o=r(452),i=r(663);e.exports={defaultOptions:n,getCreateFFmpegCore:o,fetchFile:i}},500:e=>{e.exports={defaultArgs:["./ffmpeg","-nostdin","-y"],baseOptions:{log:!1,logger:function(){},progress:function(){},corePath:""}}},906:(e,t,r)=>{function n(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return o(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?o(e,t):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}function i(e,t,r,n,o,i,a){try{var c=e[i](a),s=c.value}catch(e){return void r(e)}c.done?t(s):Promise.resolve(s).then(n,o)}function a(e){return function(){var t=this,r=arguments;return new Promise((function(n,o){var a=e.apply(t,r);function c(e){i(a,n,o,c,s,"next",e)}function s(e){i(a,n,o,c,s,"throw",e)}c(void 0)}))}}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function s(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){u(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function u(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function f(e,t){if(null==e)return{};var r,n,o=function(e,t){if(null==e)return{};var r,n,o={},i=Object.keys(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n<i.length;n++)r=i[n],t.indexOf(r)>=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=r(500),p=l.defaultArgs,h=l.baseOptions,m=r(185),g=m.setLogging,d=m.setCustomLogger,y=m.log,v=r(583),b=r(319),w=r(698),x=w.defaultOptions,j=w.getCreateFFmpegCore,E=r(306).version,O=Error("ffmpeg.wasm is not ready, make sure you have completed load().");e.exports=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=s(s(s({},h),x),e),r=t.log,o=t.logger,i=t.progress,c=f(t,["log","logger","progress"]),u=null,l=null,m=null,w=!1,F=i,L=function(e){"FFMPEG_END"===e&&null!==m&&(m(),m=null,w=!1)},P=function(e){var t=e.type,r=e.message;y(t,r),v(r,F),L(r)},k=function(){var e=a(regeneratorRuntime.mark((function e(){var t,r,n,o,i;return regeneratorRuntime.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(y("info","load ffmpeg-core"),null!==u){e.next=17;break}return y("info","loading ffmpeg-core"),e.next=5,j(c);case 5:return t=e.sent,r=t.createFFmpegCore,n=t.corePath,o=t.workerPath,i=t.wasmPath,e.next=12,r({mainScriptUrlOrBlob:n,printErr:function(e){return P({type:"fferr",message:e})},print:function(e){return P({type:"ffout",message:e})},locateFile:function(e,t){if("undefined"!=typeof window){if(void 0!==i&&e.endsWith("ffmpeg-core.wasm"))return i;if(void 0!==o&&e.endsWith("ffmpeg-core.worker.js"))return o}return t+e}});case 12:u=e.sent,l=u.cwrap("proxy_main","number",["number","number"]),y("info","ffmpeg-core loaded"),e.next=18;break;case 17:throw Error("ffmpeg.wasm was loaded, you should not load it again, use ffmpeg.isLoaded() to check next time.");case 18:case"end":return e.stop()}}),e)})));return function(){return e.apply(this,arguments)}}(),S=function(){return null!==u},A=function(){for(var e=arguments.length,t=new Array(e),r=0;r<e;r++)t[r]=arguments[r];if(y("info","run ffmpeg command: ".concat(t.join(" "))),null===u)throw O;if(w)throw Error("ffmpeg.wasm can only run one command at a time");return w=!0,new Promise((function(e){var r=[].concat(n(p),t).filter((function(e){return 0!==e.length}));m=e,l.apply(void 0,n(b(u,r)))}))},_=function(e){for(var t=arguments.length,r=new Array(t>1?t-1:0),n=1;n<t;n++)r[n-1]=arguments[n];if(y("info","run FS.".concat(e," ").concat(r.map((function(e){return"string"==typeof e?e:"<".concat(e.length," bytes binary file>")})).join(" "))),null===u)throw O;var o=null;try{var i;o=(i=u.FS)[e].apply(i,r)}catch(t){throw"readdir"===e?Error("ffmpeg.FS('readdir', '".concat(r[0],"') error. Check if the path exists, ex: ffmpeg.FS('readdir', '/')")):"readFile"===e?Error("ffmpeg.FS('readFile', '".concat(r[0],"') error. Check if the path exists")):Error("Oops, something went wrong in FS operation.")}return o},C=function(){if(null===u)throw O;w=!1,u.exit(1),u=null,l=null,m=null},R=function(e){F=e},T=function(e){d(e)};return g(r),d(o),y("info","use ffmpeg.wasm v".concat(E)),{setProgress:R,setLogger:T,setLogging:g,load:k,isLoaded:S,run:A,exit:C,FS:_}}},352:(e,t,r)=>{r(666);var n=r(906),o=r(698).fetchFile;e.exports={createFFmpeg:n,fetchFile:o}},185:e=>{var t=!1,r=function(){};e.exports={logging:t,setLogging:function(e){t=e},setCustomLogger:function(e){r=e},log:function(e,n){r({type:e,message:n}),t&&console.log("[".concat(e,"] ").concat(n))}}},319:e=>{e.exports=function(e,t){var r=e._malloc(t.length*Uint32Array.BYTES_PER_ELEMENT);return t.forEach((function(t,n){var o=e._malloc(t.length+1);e.writeAsciiToMemory(t,o),e.setValue(r+Uint32Array.BYTES_PER_ELEMENT*n,o,"i32")})),[t.length,r]}},583:e=>{function t(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);r<t;r++)n[r]=e[r];return n}var r=0,n=0,o=function(e){var r,n,o=(r=e.split(":"),n=3,function(e){if(Array.isArray(e))return e}(r)||function(e,t){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e)){var r=[],n=!0,o=!1,i=void 0;try{for(var a,c=e[Symbol.iterator]();!(n=(a=c.next()).done)&&(r.push(a.value),!t||r.length!==t);n=!0);}catch(e){o=!0,i=e}finally{try{n||null==c.return||c.return()}finally{if(o)throw i}}return r}}(r,n)||function(e,r){if(e){if("string"==typeof e)return t(e,r);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?t(e,r):void 0}}(r,n)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),i=o[0],a=o[1],c=o[2];return 60*parseFloat(i)*60+60*parseFloat(a)+parseFloat(c)};e.exports=function(e,t){if("string"==typeof e)if(e.startsWith(" Duration")){var i=e.split(", ")[0].split(": ")[1],a=o(i);t({duration:a,ratio:n}),(0===r||r>a)&&(r=a)}else if(e.startsWith("frame")||e.startsWith("size")){var c=e.split("time=")[1].split(" ")[0],s=o(c);t({ratio:n=s/r,time:s})}else e.startsWith("video:")&&(t({ratio:1}),r=0)}},666:e=>{var t=function(e){"use strict";var t,r=Object.prototype,n=r.hasOwnProperty,o="function"==typeof Symbol?Symbol:{},i=o.iterator||"@@iterator",a=o.asyncIterator||"@@asyncIterator",c=o.toStringTag||"@@toStringTag";function s(e,t,r){return Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}),e[t]}try{s({},"")}catch(e){s=function(e,t,r){return e[t]=r}}function u(e,t,r,n){var o=t&&t.prototype instanceof d?t:d,i=Object.create(o.prototype),a=new k(n||[]);return i._invoke=function(e,t,r){var n=l;return function(o,i){if(n===h)throw new Error("Generator is already running");if(n===m){if("throw"===o)throw i;return A()}for(r.method=o,r.arg=i;;){var a=r.delegate;if(a){var c=F(a,r);if(c){if(c===g)continue;return c}}if("next"===r.method)r.sent=r._sent=r.arg;else if("throw"===r.method){if(n===l)throw n=m,r.arg;r.dispatchException(r.arg)}else"return"===r.method&&r.abrupt("return",r.arg);n=h;var s=f(e,t,r);if("normal"===s.type){if(n=r.done?m:p,s.arg===g)continue;return{value:s.arg,done:r.done}}"throw"===s.type&&(n=m,r.method="throw",r.arg=s.arg)}}}(e,r,a),i}function f(e,t,r){try{return{type:"normal",arg:e.call(t,r)}}catch(e){return{type:"throw",arg:e}}}e.wrap=u;var l="suspendedStart",p="suspendedYield",h="executing",m="completed",g={};function d(){}function y(){}function v(){}var b={};b[i]=function(){return this};var w=Object.getPrototypeOf,x=w&&w(w(S([])));x&&x!==r&&n.call(x,i)&&(b=x);var j=v.prototype=d.prototype=Object.create(b);function E(e){["next","throw","return"].forEach((function(t){s(e,t,(function(e){return this._invoke(t,e)}))}))}function O(e,t){function r(o,i,a,c){var s=f(e[o],e,i);if("throw"!==s.type){var u=s.arg,l=u.value;return l&&"object"==typeof l&&n.call(l,"__await")?t.resolve(l.__await).then((function(e){r("next",e,a,c)}),(function(e){r("throw",e,a,c)})):t.resolve(l).then((function(e){u.value=e,a(u)}),(function(e){return r("throw",e,a,c)}))}c(s.arg)}var o;this._invoke=function(e,n){function i(){return new t((function(t,o){r(e,n,t,o)}))}return o=o?o.then(i,i):i()}}function F(e,r){var n=e.iterator[r.method];if(n===t){if(r.delegate=null,"throw"===r.method){if(e.iterator.return&&(r.method="return",r.arg=t,F(e,r),"throw"===r.method))return g;r.method="throw",r.arg=new TypeError("The iterator does not provide a 'throw' method")}return g}var o=f(n,e.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,g;var i=o.arg;return i?i.done?(r[e.resultName]=i.value,r.next=e.nextLoc,"return"!==r.method&&(r.method="next",r.arg=t),r.delegate=null,g):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,g)}function L(e){var t={tryLoc:e[0]};1 in e&&(t.catchLoc=e[1]),2 in e&&(t.finallyLoc=e[2],t.afterLoc=e[3]),this.tryEntries.push(t)}function P(e){var t=e.completion||{};t.type="normal",delete t.arg,e.completion=t}function k(e){this.tryEntries=[{tryLoc:"root"}],e.forEach(L,this),this.reset(!0)}function S(e){if(e){var r=e[i];if(r)return r.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length)){var o=-1,a=function r(){for(;++o<e.length;)if(n.call(e,o))return r.value=e[o],r.done=!1,r;return r.value=t,r.done=!0,r};return a.next=a}}return{next:A}}function A(){return{value:t,done:!0}}return y.prototype=j.constructor=v,v.constructor=y,y.displayName=s(v,c,"GeneratorFunction"),e.isGeneratorFunction=function(e){var t="function"==typeof e&&e.constructor;return!!t&&(t===y||"GeneratorFunction"===(t.displayName||t.name))},e.mark=function(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,v):(e.__proto__=v,s(e,c,"GeneratorFunction")),e.prototype=Object.create(j),e},e.awrap=function(e){return{__await:e}},E(O.prototype),O.prototype[a]=function(){return this},e.AsyncIterator=O,e.async=function(t,r,n,o,i){void 0===i&&(i=Promise);var a=new O(u(t,r,n,o),i);return e.isGeneratorFunction(r)?a:a.next().then((function(e){return e.done?e.value:a.next()}))},E(j),s(j,c,"Generator"),j[i]=function(){return this},j.toString=function(){return"[object Generator]"},e.keys=function(e){var t=[];for(var r in e)t.push(r);return t.reverse(),function r(){for(;t.length;){var n=t.pop();if(n in e)return r.value=n,r.done=!1,r}return r.done=!0,r}},e.values=S,k.prototype={constructor:k,reset:function(e){if(this.prev=0,this.next=0,this.sent=this._sent=t,this.done=!1,this.delegate=null,this.method="next",this.arg=t,this.tryEntries.forEach(P),!e)for(var r in this)"t"===r.charAt(0)&&n.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=t)},stop:function(){this.done=!0;var e=this.tryEntries[0].completion;if("throw"===e.type)throw e.arg;return this.rval},dispatchException:function(e){if(this.done)throw e;var r=this;function o(n,o){return c.type="throw",c.arg=e,r.next=n,o&&(r.method="next",r.arg=t),!!o}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],c=a.completion;if("root"===a.tryLoc)return o("end");if(a.tryLoc<=this.prev){var s=n.call(a,"catchLoc"),u=n.call(a,"finallyLoc");if(s&&u){if(this.prev<a.catchLoc)return o(a.catchLoc,!0);if(this.prev<a.finallyLoc)return o(a.finallyLoc)}else if(s){if(this.prev<a.catchLoc)return o(a.catchLoc,!0)}else{if(!u)throw new Error("try statement without catch or finally");if(this.prev<a.finallyLoc)return o(a.finallyLoc)}}}},abrupt:function(e,t){for(var r=this.tryEntries.length-1;r>=0;--r){var o=this.tryEntries[r];if(o.tryLoc<=this.prev&&n.call(o,"finallyLoc")&&this.prev<o.finallyLoc){var i=o;break}}i&&("break"===e||"continue"===e)&&i.tryLoc<=t&&t<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=e,a.arg=t,i?(this.method="next",this.next=i.finallyLoc,g):this.complete(a)},complete:function(e,t){if("throw"===e.type)throw e.arg;return"break"===e.type||"continue"===e.type?this.next=e.arg:"return"===e.type?(this.rval=this.arg=e.arg,this.method="return",this.next="end"):"normal"===e.type&&t&&(this.next=t),g},finish:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var r=this.tryEntries[t];if(r.finallyLoc===e)return this.complete(r.completion,r.afterLoc),P(r),g}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var r=this.tryEntries[t];if(r.tryLoc===e){var n=r.completion;if("throw"===n.type){var o=n.arg;P(r)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(e,r,n){return this.delegate={iterator:S(e),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=t),g}},e}(e.exports);try{regeneratorRuntime=t}catch(e){Function("r","regeneratorRuntime = r")(t)}},72:function(e,t,r){var n,o;void 0===(o="function"==typeof(n=function(){return function(){var e=arguments.length;if(0===e)throw new Error("resolveUrl requires at least one argument; got none.");var t=document.createElement("base");if(t.href=arguments[0],1===e)return t.href;var r=document.getElementsByTagName("head")[0];r.insertBefore(t,r.firstChild);for(var n,o=document.createElement("a"),i=1;i<e;i++)o.href=arguments[i],n=o.href,t.href=n;return r.removeChild(t),n}})?n.call(t,r,t,e):n)||(e.exports=o)},306:e=>{"use strict";e.exports=JSON.parse('{"name":"@ffmpeg/ffmpeg","version":"0.10.1","description":"FFmpeg WebAssembly version","main":"src/index.js","types":"src/index.d.ts","directories":{"example":"examples"},"scripts":{"start":"node scripts/server.js","build":"rimraf dist && webpack --config scripts/webpack.config.prod.js","prepublishOnly":"npm run build","lint":"eslint src","wait":"rimraf dist && wait-on http://localhost:3000/dist/ffmpeg.dev.js","test":"npm-run-all -p -r start test:all","test:all":"npm-run-all wait test:browser:ffmpeg test:node:all","test:node":"node --experimental-wasm-threads --experimental-wasm-bulk-memory node_modules/.bin/_mocha --exit --bail --require ./scripts/test-helper.js","test:node:all":"npm run test:node -- ./tests/*.test.js","test:browser":"mocha-headless-chrome -a allow-file-access-from-files -a incognito -a no-sandbox -a disable-setuid-sandbox -a disable-logging -t 300000","test:browser:ffmpeg":"npm run test:browser -- -f ./tests/ffmpeg.test.html"},"browser":{"./src/node/index.js":"./src/browser/index.js"},"repository":{"type":"git","url":"git+https://github.com/ffmpegwasm/ffmpeg.wasm.git"},"keywords":["ffmpeg","WebAssembly","video"],"author":"Jerome Wu <[email protected]>","license":"MIT","bugs":{"url":"https://github.com/ffmpegwasm/ffmpeg.wasm/issues"},"engines":{"node":">=12.16.1"},"homepage":"https://github.com/ffmpegwasm/ffmpeg.wasm#readme","dependencies":{"is-url":"^1.2.4","node-fetch":"^2.6.1","regenerator-runtime":"^0.13.7","resolve-url":"^0.2.1"},"devDependencies":{"@babel/core":"^7.12.3","@babel/preset-env":"^7.12.1","@ffmpeg/core":"^0.10.0","@types/emscripten":"^1.39.4","babel-loader":"^8.1.0","chai":"^4.2.0","cors":"^2.8.5","eslint":"^7.12.1","eslint-config-airbnb-base":"^14.1.0","eslint-plugin-import":"^2.22.1","express":"^4.17.1","mocha":"^8.2.1","mocha-headless-chrome":"^2.0.3","npm-run-all":"^4.1.5","wait-on":"^5.3.0","webpack":"^5.3.2","webpack-cli":"^4.1.0","webpack-dev-middleware":"^4.0.0"}}')}},t={},function r(n){if(t[n])return t[n].exports;var o=t[n]={exports:{}};return e[n].call(o.exports,o,o.exports,r),o.exports}(352);var e,t}));
2
+ //# sourceMappingURL=ffmpeg.min.js.map
js/libraries/jquery.nice-select.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ /* jQuery Nice Select - v1.0
2
+ https://github.com/hernansartorio/jquery-nice-select
3
+ Made by Hernán Sartorio */
4
+ !function(e){e.fn.niceSelect=function(t){function s(t){t.after(e("<div></div>").addClass("nice-select").addClass(t.attr("class")||"").addClass(t.attr("disabled")?"disabled":"").attr("tabindex",t.attr("disabled")?null:"0").html('<span class="current"></span><ul class="list"></ul>'));var s=t.next(),n=t.find("option"),i=t.find("option:selected");s.find(".current").html(i.data("display")||i.text()),n.each(function(t){var n=e(this),i=n.data("display");s.find("ul").append(e("<li></li>").attr("data-value",n.val()).attr("data-display",i||null).addClass("option"+(n.is(":selected")?" selected":"")+(n.is(":disabled")?" disabled":"")).html(n.text()))})}if("string"==typeof t)return"update"==t?this.each(function(){var t=e(this),n=e(this).next(".nice-select"),i=n.hasClass("open");n.length&&(n.remove(),s(t),i&&t.next().trigger("click"))}):"destroy"==t?(this.each(function(){var t=e(this),s=e(this).next(".nice-select");s.length&&(s.remove(),t.css("display",""))}),0==e(".nice-select").length&&e(document).off(".nice_select")):console.log('Method "'+t+'" does not exist.'),this;this.hide(),this.each(function(){var t=e(this);t.next().hasClass("nice-select")||s(t)}),e(document).off(".nice_select"),e(document).on("click.nice_select",".nice-select",function(t){var s=e(this);e(".nice-select").not(s).removeClass("open"),s.toggleClass("open"),s.hasClass("open")?(s.find(".option"),s.find(".focus").removeClass("focus"),s.find(".selected").addClass("focus")):s.focus()}),e(document).on("click.nice_select",function(t){0===e(t.target).closest(".nice-select").length&&e(".nice-select").removeClass("open").find(".option")}),e(document).on("click.nice_select",".nice-select .option:not(.disabled)",function(t){var s=e(this),n=s.closest(".nice-select");n.find(".selected").removeClass("selected"),s.addClass("selected");var i=s.data("display")||s.text();n.find(".current").text(i),n.prev("select").val(s.data("value")).trigger("change")}),e(document).on("keydown.nice_select",".nice-select",function(t){var s=e(this),n=e(s.find(".focus")||s.find(".list .option.selected"));if(32==t.keyCode||13==t.keyCode)return s.hasClass("open")?n.trigger("click"):s.trigger("click"),!1;if(40==t.keyCode){if(s.hasClass("open")){var i=n.nextAll(".option:not(.disabled)").first();i.length>0&&(s.find(".focus").removeClass("focus"),i.addClass("focus"))}else s.trigger("click");return!1}if(38==t.keyCode){if(s.hasClass("open")){var l=n.prevAll(".option:not(.disabled)").first();l.length>0&&(s.find(".focus").removeClass("focus"),l.addClass("focus"))}else s.trigger("click");return!1}if(27==t.keyCode)s.hasClass("open")&&s.trigger("click");else if(9==t.keyCode&&s.hasClass("open"))return!1});var n=document.createElement("a").style;return n.cssText="pointer-events:auto","auto"!==n.pointerEvents&&e("html").addClass("no-csspointerevents"),this}}(jQuery);
js/libraries/localbase.js ADDED
The diff for this file is too large to render. See raw diff
 
js/libraries/pickr.min.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ /*! Pickr 1.7.2 MIT | https://github.com/Simonwep/pickr */
2
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Pickr=e():t.Pickr=e()}(window,(function(){return function(t){var e={};function o(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,o),i.l=!0,i.exports}return o.m=t,o.c=e,o.d=function(t,e,n){o.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},o.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},o.t=function(t,e){if(1&e&&(t=o(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(o.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)o.d(n,i,function(e){return t[e]}.bind(null,i));return n},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,"a",e),e},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o.p="",o(o.s=1)}([function(t){t.exports=JSON.parse('{"a":"1.7.2"}')},function(t,e,o){"use strict";o.r(e);var n={};function i(t,e,o,n,i={}){e instanceof HTMLCollection||e instanceof NodeList?e=Array.from(e):Array.isArray(e)||(e=[e]),Array.isArray(o)||(o=[o]);for(const r of e)for(const e of o)r[t](e,n,{capture:!1,...i});return Array.prototype.slice.call(arguments,1)}o.r(n),o.d(n,"on",(function(){return r})),o.d(n,"off",(function(){return s})),o.d(n,"createElementFromString",(function(){return a})),o.d(n,"createFromTemplate",(function(){return c})),o.d(n,"eventPath",(function(){return l})),o.d(n,"resolveElement",(function(){return p})),o.d(n,"adjustableInputNumbers",(function(){return u}));const r=i.bind(null,"addEventListener"),s=i.bind(null,"removeEventListener");function a(t){const e=document.createElement("div");return e.innerHTML=t.trim(),e.firstElementChild}function c(t){const e=(t,e)=>{const o=t.getAttribute(e);return t.removeAttribute(e),o},o=(t,n={})=>{const i=e(t,":obj"),r=e(t,":ref"),s=i?n[i]={}:n;r&&(n[r]=t);for(const n of Array.from(t.children)){const t=e(n,":arr"),i=o(n,t?{}:s);t&&(s[t]||(s[t]=[])).push(Object.keys(i).length?i:n)}return n};return o(a(t))}function l(t){let e=t.path||t.composedPath&&t.composedPath();if(e)return e;let o=t.target.parentElement;for(e=[t.target,o];o=o.parentElement;)e.push(o);return e.push(document,window),e}function p(t){return t instanceof Element?t:"string"==typeof t?t.split(/>>/g).reduce((t,e,o,n)=>(t=t.querySelector(e),o<n.length-1?t.shadowRoot:t),document):null}function u(t,e=(t=>t)){function o(o){const n=[.001,.01,.1][Number(o.shiftKey||2*o.ctrlKey)]*(o.deltaY<0?1:-1);let i=0,r=t.selectionStart;t.value=t.value.replace(/[\d.]+/g,(t,o)=>o<=r&&o+t.length>=r?(r=o,e(Number(t),n,i)):(i++,t)),t.focus(),t.setSelectionRange(r,r),o.preventDefault(),t.dispatchEvent(new Event("input"))}r(t,"focus",()=>r(window,"wheel",o,{passive:!1})),r(t,"blur",()=>s(window,"wheel",o))}var h=o(0);const{min:d,max:f,floor:m,round:v}=Math;function b(t,e,o){e/=100,o/=100;const n=m(t=t/360*6),i=t-n,r=o*(1-e),s=o*(1-i*e),a=o*(1-(1-i)*e),c=n%6;return[255*[o,s,r,r,a,o][c],255*[a,o,o,s,r,r][c],255*[r,r,a,o,o,s][c]]}function g(t,e,o){const n=(2-(e/=100))*(o/=100)/2;return 0!==n&&(e=1===n?0:n<.5?e*o/(2*n):e*o/(2-2*n)),[t,100*e,100*n]}function y(t,e,o){const n=d(t/=255,e/=255,o/=255),i=f(t,e,o),r=i-n;let s,a;if(0===r)s=a=0;else{a=r/i;const n=((i-t)/6+r/2)/r,c=((i-e)/6+r/2)/r,l=((i-o)/6+r/2)/r;t===i?s=l-c:e===i?s=1/3+n-l:o===i&&(s=2/3+c-n),s<0?s+=1:s>1&&(s-=1)}return[360*s,100*a,100*i]}function _(t,e,o,n){return e/=100,o/=100,[...y(255*(1-d(1,(t/=100)*(1-(n/=100))+n)),255*(1-d(1,e*(1-n)+n)),255*(1-d(1,o*(1-n)+n)))]}function w(t,e,o){e/=100;const n=2*(e*=(o/=100)<.5?o:1-o)/(o+e)*100,i=100*(o+e);return[t,isNaN(n)?0:n,i]}function A(t){return y(...t.match(/.{2}/g).map(t=>parseInt(t,16)))}function C(t){t=t.match(/^[a-zA-Z]+$/)?function(t){if("black"===t.toLowerCase())return"#000";const e=document.createElement("canvas").getContext("2d");return e.fillStyle=t,"#000"===e.fillStyle?null:e.fillStyle}(t):t;const e={cmyk:/^cmyk[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)/i,rgba:/^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hsla:/^((hsla)|hsl)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hsva:/^((hsva)|hsv)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i,hexa:/^#?(([\dA-Fa-f]{3,4})|([\dA-Fa-f]{6})|([\dA-Fa-f]{8}))$/i},o=t=>t.map(t=>/^(|\d+)\.\d+|\d+$/.test(t)?Number(t):void 0);let n;t:for(const i in e){if(!(n=e[i].exec(t)))continue;const r=t=>!!n[2]==("number"==typeof t);switch(i){case"cmyk":{const[,t,e,r,s]=o(n);if(t>100||e>100||r>100||s>100)break t;return{values:_(t,e,r,s),type:i}}case"rgba":{const[,,,t,e,s,a]=o(n);if(t>255||e>255||s>255||a<0||a>1||!r(a))break t;return{values:[...y(t,e,s),a],a:a,type:i}}case"hexa":{let[,t]=n;4!==t.length&&3!==t.length||(t=t.split("").map(t=>t+t).join(""));const e=t.substring(0,6);let o=t.substring(6);return o=o?parseInt(o,16)/255:void 0,{values:[...A(e),o],a:o,type:i}}case"hsla":{const[,,,t,e,s,a]=o(n);if(t>360||e>100||s>100||a<0||a>1||!r(a))break t;return{values:[...w(t,e,s),a],a:a,type:i}}case"hsva":{const[,,,t,e,s,a]=o(n);if(t>360||e>100||s>100||a<0||a>1||!r(a))break t;return{values:[t,e,s,a],a:a,type:i}}}}return{values:null,type:null}}function k(t=0,e=0,o=0,n=1){const i=(t,e)=>(o=-1)=>e(~o?t.map(t=>Number(t.toFixed(o))):t),r={h:t,s:e,v:o,a:n,toHSVA(){const t=[r.h,r.s,r.v,r.a];return t.toString=i(t,t=>"hsva(".concat(t[0],", ").concat(t[1],"%, ").concat(t[2],"%, ").concat(r.a,")")),t},toHSLA(){const t=[...g(r.h,r.s,r.v),r.a];return t.toString=i(t,t=>"hsla(".concat(t[0],", ").concat(t[1],"%, ").concat(t[2],"%, ").concat(r.a,")")),t},toRGBA(){const t=[...b(r.h,r.s,r.v),r.a];return t.toString=i(t,t=>"rgba(".concat(t[0],", ").concat(t[1],", ").concat(t[2],", ").concat(r.a,")")),t},toCMYK(){const t=function(t,e,o){const n=b(t,e,o),i=n[0]/255,r=n[1]/255,s=n[2]/255,a=d(1-i,1-r,1-s);return[100*(1===a?0:(1-i-a)/(1-a)),100*(1===a?0:(1-r-a)/(1-a)),100*(1===a?0:(1-s-a)/(1-a)),100*a]}(r.h,r.s,r.v);return t.toString=i(t,t=>"cmyk(".concat(t[0],"%, ").concat(t[1],"%, ").concat(t[2],"%, ").concat(t[3],"%)")),t},toHEXA(){const t=function(t,e,o){return b(t,e,o).map(t=>v(t).toString(16).padStart(2,"0"))}(r.h,r.s,r.v),e=r.a>=1?"":Number((255*r.a).toFixed(0)).toString(16).toUpperCase().padStart(2,"0");return e&&t.push(e),t.toString=()=>"#".concat(t.join("").toUpperCase()),t},clone:()=>k(r.h,r.s,r.v,r.a)};return r}const S=t=>Math.max(Math.min(t,1),0);function O(t){const e={options:Object.assign({lock:null,onchange:()=>0,onstop:()=>0},t),_keyboard(t){const{options:o}=e,{type:n,key:i}=t;if(document.activeElement===o.wrapper){const{lock:o}=e.options,r="ArrowUp"===i,s="ArrowRight"===i,a="ArrowDown"===i,c="ArrowLeft"===i;if("keydown"===n&&(r||s||a||c)){let n=0,i=0;"v"===o?n=r||s?1:-1:"h"===o?n=r||s?-1:1:(i=r?-1:a?1:0,n=c?-1:s?1:0),e.update(S(e.cache.x+.01*n),S(e.cache.y+.01*i)),t.preventDefault()}else i.startsWith("Arrow")&&(e.options.onstop(),t.preventDefault())}},_tapstart(t){r(document,["mouseup","touchend","touchcancel"],e._tapstop),r(document,["mousemove","touchmove"],e._tapmove),t.cancelable&&t.preventDefault(),e._tapmove(t)},_tapmove(t){const{options:o,cache:n}=e,{lock:i,element:r,wrapper:s}=o,a=s.getBoundingClientRect();let c=0,l=0;if(t){const e=t&&t.touches&&t.touches[0];c=t?(e||t).clientX:0,l=t?(e||t).clientY:0,c<a.left?c=a.left:c>a.left+a.width&&(c=a.left+a.width),l<a.top?l=a.top:l>a.top+a.height&&(l=a.top+a.height),c-=a.left,l-=a.top}else n&&(c=n.x*a.width,l=n.y*a.height);"h"!==i&&(r.style.left="calc(".concat(c/a.width*100,"% - ").concat(r.offsetWidth/2,"px)")),"v"!==i&&(r.style.top="calc(".concat(l/a.height*100,"% - ").concat(r.offsetHeight/2,"px)")),e.cache={x:c/a.width,y:l/a.height};const p=S(c/a.width),u=S(l/a.height);switch(i){case"v":return o.onchange(p);case"h":return o.onchange(u);default:return o.onchange(p,u)}},_tapstop(){e.options.onstop(),s(document,["mouseup","touchend","touchcancel"],e._tapstop),s(document,["mousemove","touchmove"],e._tapmove)},trigger(){e._tapmove()},update(t=0,o=0){const{left:n,top:i,width:r,height:s}=e.options.wrapper.getBoundingClientRect();"h"===e.options.lock&&(o=t),e._tapmove({clientX:n+r*t,clientY:i+s*o})},destroy(){const{options:t,_tapstart:o,_keyboard:n}=e;s(document,["keydown","keyup"],n),s([t.wrapper,t.element],"mousedown",o),s([t.wrapper,t.element],"touchstart",o,{passive:!1})}},{options:o,_tapstart:n,_keyboard:i}=e;return r([o.wrapper,o.element],"mousedown",n),r([o.wrapper,o.element],"touchstart",n,{passive:!1}),r(document,["keydown","keyup"],i),e}function E(t={}){t=Object.assign({onchange:()=>0,className:"",elements:[]},t);const e=r(t.elements,"click",e=>{t.elements.forEach(o=>o.classList[e.target===o?"add":"remove"](t.className)),t.onchange(e)});return{destroy:()=>s(...e)}}
3
+ /*! NanoPop 1.3.0 MIT | https://github.com/Simonwep/nanopop */
4
+ let x=(()=>{class t{constructor(e,o,{positionFlipOrder:n=t.defaultPositionFlipOrder,variantFlipOrder:i=t.defaultVariantFlipOrder,container:r=document.documentElement.getBoundingClientRect(),forceApplyOnFailure:s=!1,margin:a=8,position:c="bottom-start"}={}){this.o={positionFlipOrder:n,variantFlipOrder:i,reference:e,popper:o,position:c,container:r,forceApplyOnFailure:s,margin:a}}update(t=this.o,e=!1){const{container:o,reference:n,popper:i,margin:r,position:s,forceApplyOnFailure:a,variantFlipOrder:c,positionFlipOrder:l}=this.o={...this.o,...t};i.style.left="0",i.style.top="0";const p=n.getBoundingClientRect(),u=i.getBoundingClientRect(),h={t:p.top-u.height-r,b:p.bottom+r,r:p.right+r,l:p.left-u.width-r},d={vm:-u.width/2+(p.left+p.width/2),vs:p.left,ve:p.left+p.width-u.width,hs:p.bottom-p.height,he:p.bottom-u.height,hm:p.bottom-p.height/2-u.height/2},[f,m="middle"]=s.split("-"),v=l[f],b=c[m],{top:g,left:y,bottom:_,right:w}=o;for(const t of v){const o="t"===t||"b"===t,n=h[t],[r,s]=o?["top","left"]:["left","top"],[a,c]=o?[u.height,u.width]:[u.width,u.height],[l,p]=o?[_,w]:[w,_],[f,m]=o?[g,y]:[y,g];if(e||!(n<f||n+a>l))for(const a of b){const l=d[(o?"v":"h")+a];if(e||!(l<m||l+c>p))return i.style[s]=l-u[s]+"px",i.style[r]=n-u[r]+"px",t+a}}return a?this.update(void 0,!0):null}}return t.version="1.3.0",t.defaultVariantFlipOrder={start:"sme",middle:"mse",end:"ems"},t.defaultPositionFlipOrder={top:"tbrl",right:"rltb",bottom:"btrl",left:"lrbt"},t})();function L(t,e,o){return e in t?Object.defineProperty(t,e,{value:o,enumerable:!0,configurable:!0,writable:!0}):t[e]=o,t}class B{constructor(t){L(this,"_initializingActive",!0),L(this,"_recalc",!0),L(this,"_nanopop",null),L(this,"_root",null),L(this,"_color",k()),L(this,"_lastColor",k()),L(this,"_swatchColors",[]),L(this,"_eventListener",{init:[],save:[],hide:[],show:[],clear:[],change:[],changestop:[],cancel:[],swatchselect:[]}),this.options=t=Object.assign({...B.DEFAULT_OPTIONS},t);const{swatches:e,components:o,theme:n,sliders:i,lockOpacity:r,padding:s}=t;["nano","monolith"].includes(n)&&!i&&(t.sliders="h"),o.interaction||(o.interaction={});const{preview:a,opacity:c,hue:l,palette:p}=o;o.opacity=!r&&c,o.palette=p||a||c||l,this._preBuild(),this._buildComponents(),this._bindEvents(),this._finalBuild(),e&&e.length&&e.forEach(t=>this.addSwatch(t));const{button:u,app:h}=this._root;this._nanopop=new x(u,h,{margin:s}),u.setAttribute("role","button"),u.setAttribute("aria-label",this._t("btn:toggle"));const d=this;requestAnimationFrame((function e(){if(!h.offsetWidth)return requestAnimationFrame(e);d.setColor(t.default),d._rePositioningPicker(),t.defaultRepresentation&&(d._representation=t.defaultRepresentation,d.setColorRepresentation(d._representation)),t.showAlways&&d.show(),d._initializingActive=!1,d._emit("init")}))}_preBuild(){const{options:t}=this;for(const e of["el","container"])t[e]=p(t[e]);this._root=(t=>{const{components:e,useAsButton:o,inline:n,appClass:i,theme:r,lockOpacity:s}=t.options,a=t=>t?"":'style="display:none" hidden',l=e=>t._t(e),p=c('\n <div :ref="root" class="pickr">\n\n '.concat(o?"":'<button type="button" :ref="button" class="pcr-button"></button>','\n\n <div :ref="app" class="pcr-app ').concat(i||"",'" data-theme="').concat(r,'" ').concat(n?'style="position: unset"':"",' aria-label="').concat(l("ui:dialog"),'" role="window">\n <div class="pcr-selection" ').concat(a(e.palette),'>\n <div :obj="preview" class="pcr-color-preview" ').concat(a(e.preview),'>\n <button type="button" :ref="lastColor" class="pcr-last-color" aria-label="').concat(l("btn:last-color"),'"></button>\n <div :ref="currentColor" class="pcr-current-color"></div>\n </div>\n\n <div :obj="palette" class="pcr-color-palette">\n <div :ref="picker" class="pcr-picker"></div>\n <div :ref="palette" class="pcr-palette" tabindex="0" aria-label="').concat(l("aria:palette"),'" role="listbox"></div>\n </div>\n\n <div :obj="hue" class="pcr-color-chooser" ').concat(a(e.hue),'>\n <div :ref="picker" class="pcr-picker"></div>\n <div :ref="slider" class="pcr-hue pcr-slider" tabindex="0" aria-label="').concat(l("aria:hue"),'" role="slider"></div>\n </div>\n\n <div :obj="opacity" class="pcr-color-opacity" ').concat(a(e.opacity),'>\n <div :ref="picker" class="pcr-picker"></div>\n <div :ref="slider" class="pcr-opacity pcr-slider" tabindex="0" aria-label="').concat(l("aria:opacity"),'" role="slider"></div>\n </div>\n </div>\n\n <div class="pcr-swatches ').concat(e.palette?"":"pcr-last",'" :ref="swatches"></div>\n\n <div :obj="interaction" class="pcr-interaction" ').concat(a(Object.keys(e.interaction).length),'>\n <input :ref="result" class="pcr-result" type="text" spellcheck="false" ').concat(a(e.interaction.input),' aria-label="').concat(l("aria:input"),'">\n\n <input :arr="options" class="pcr-type" data-type="HEXA" value="').concat(s?"HEX":"HEXA",'" type="button" ').concat(a(e.interaction.hex),'>\n <input :arr="options" class="pcr-type" data-type="RGBA" value="').concat(s?"RGB":"RGBA",'" type="button" ').concat(a(e.interaction.rgba),'>\n <input :arr="options" class="pcr-type" data-type="HSLA" value="').concat(s?"HSL":"HSLA",'" type="button" ').concat(a(e.interaction.hsla),'>\n <input :arr="options" class="pcr-type" data-type="HSVA" value="').concat(s?"HSV":"HSVA",'" type="button" ').concat(a(e.interaction.hsva),'>\n <input :arr="options" class="pcr-type" data-type="CMYK" value="CMYK" type="button" ').concat(a(e.interaction.cmyk),'>\n\n <input :ref="save" class="pcr-save" value="').concat(l("btn:save"),'" type="button" ').concat(a(e.interaction.save),' aria-label="').concat(l("aria:btn:save"),'">\n <input :ref="cancel" class="pcr-cancel" value="').concat(l("btn:cancel"),'" type="button" ').concat(a(e.interaction.cancel),' aria-label="').concat(l("aria:btn:cancel"),'">\n <input :ref="clear" class="pcr-clear" value="').concat(l("btn:clear"),'" type="button" ').concat(a(e.interaction.clear),' aria-label="').concat(l("aria:btn:clear"),'">\n </div>\n </div>\n </div>\n ')),u=p.interaction;return u.options.find(t=>!t.hidden&&!t.classList.add("active")),u.type=()=>u.options.find(t=>t.classList.contains("active")),p})(this),t.useAsButton&&(this._root.button=t.el),t.container.appendChild(this._root.root)}_finalBuild(){const t=this.options,e=this._root;if(t.container.removeChild(e.root),t.inline){const o=t.el.parentElement;t.el.nextSibling?o.insertBefore(e.app,t.el.nextSibling):o.appendChild(e.app)}else t.container.appendChild(e.app);t.useAsButton?t.inline&&t.el.remove():t.el.parentNode.replaceChild(e.root,t.el),t.disabled&&this.disable(),t.comparison||(e.button.style.transition="none",t.useAsButton||(e.preview.lastColor.style.transition="none")),this.hide()}_buildComponents(){const t=this,e=this.options.components,o=(t.options.sliders||"v").repeat(2),[n,i]=o.match(/^[vh]+$/g)?o:[],r=()=>this._color||(this._color=this._lastColor.clone()),s={palette:O({element:t._root.palette.picker,wrapper:t._root.palette.palette,onstop:()=>t._emit("changestop",t),onchange(o,n){if(!e.palette)return;const i=r(),{_root:s,options:a}=t,{lastColor:c,currentColor:l}=s.preview;t._recalc&&(i.s=100*o,i.v=100-100*n,i.v<0&&(i.v=0),t._updateOutput());const p=i.toRGBA().toString(0);this.element.style.background=p,this.wrapper.style.background="\n linear-gradient(to top, rgba(0, 0, 0, ".concat(i.a,"), transparent),\n linear-gradient(to left, hsla(").concat(i.h,", 100%, 50%, ").concat(i.a,"), rgba(255, 255, 255, ").concat(i.a,"))\n "),a.comparison?a.useAsButton||t._lastColor||(c.style.color=p):(s.button.style.color=p,s.button.classList.remove("clear"));const u=i.toHEXA().toString();for(const{el:e,color:o}of t._swatchColors)e.classList[u===o.toHEXA().toString()?"add":"remove"]("pcr-active");l.style.color=p}}),hue:O({lock:"v"===i?"h":"v",element:t._root.hue.picker,wrapper:t._root.hue.slider,onstop:()=>t._emit("changestop",t),onchange(o){if(!e.hue||!e.palette)return;const n=r();t._recalc&&(n.h=360*o),this.element.style.backgroundColor="hsl(".concat(n.h,", 100%, 50%)"),s.palette.trigger()}}),opacity:O({lock:"v"===n?"h":"v",element:t._root.opacity.picker,wrapper:t._root.opacity.slider,onstop:()=>t._emit("changestop",t),onchange(o){if(!e.opacity||!e.palette)return;const n=r();t._recalc&&(n.a=Math.round(100*o)/100),this.element.style.background="rgba(0, 0, 0, ".concat(n.a,")"),s.palette.trigger()}}),selectable:E({elements:t._root.interaction.options,className:"active",onchange(e){t._representation=e.target.getAttribute("data-type").toUpperCase(),t._recalc&&t._updateOutput()}})};this._components=s}_bindEvents(){const{_root:t,options:e}=this,o=[r(t.interaction.clear,"click",()=>this._clearColor()),r([t.interaction.cancel,t.preview.lastColor],"click",()=>{this._emit("cancel",this),this.setHSVA(...(this._lastColor||this._color).toHSVA(),!0)}),r(t.interaction.save,"click",()=>{!this.applyColor()&&!e.showAlways&&this.hide()}),r(t.interaction.result,["keyup","input"],t=>{this.setColor(t.target.value,!0)&&!this._initializingActive&&this._emit("change",this._color),t.stopImmediatePropagation()}),r(t.interaction.result,["focus","blur"],t=>{this._recalc="blur"===t.type,this._recalc&&this._updateOutput()}),r([t.palette.palette,t.palette.picker,t.hue.slider,t.hue.picker,t.opacity.slider,t.opacity.picker],["mousedown","touchstart"],()=>this._recalc=!0,{passive:!0})];if(!e.showAlways){const n=e.closeWithKey;o.push(r(t.button,"click",()=>this.isOpen()?this.hide():this.show()),r(document,"keyup",t=>this.isOpen()&&(t.key===n||t.code===n)&&this.hide()),r(document,["touchstart","mousedown"],e=>{this.isOpen()&&!l(e).some(e=>e===t.app||e===t.button)&&this.hide()},{capture:!0}))}if(e.adjustableNumbers){const e={rgba:[255,255,255,1],hsva:[360,100,100,1],hsla:[360,100,100,1],cmyk:[100,100,100,100]};u(t.interaction.result,(t,o,n)=>{const i=e[this.getColorRepresentation().toLowerCase()];if(i){const e=i[n],r=t+(e>=100?1e3*o:o);return r<=0?0:Number((r<e?r:e).toPrecision(3))}return t})}if(e.autoReposition&&!e.inline){let t=null;const n=this;o.push(r(window,["scroll","resize"],()=>{n.isOpen()&&(e.closeOnScroll&&n.hide(),null===t?(t=setTimeout(()=>t=null,100),requestAnimationFrame((function e(){null!==t&&requestAnimationFrame(e)}))):(clearTimeout(t),t=setTimeout(()=>t=null,100)))},{capture:!0}))}this._eventBindings=o}_rePositioningPicker(){const{options:t}=this;if(!t.inline){if(!this._nanopop.update({container:document.body.getBoundingClientRect(),position:t.position,forceApplyOnFailure:!this._recalc})){const t=this._root.app,e=t.getBoundingClientRect();t.style.top="".concat((window.innerHeight-e.height)/2,"px"),t.style.left="".concat((window.innerWidth-e.width)/2,"px")}}}_updateOutput(){const{_root:t,_color:e,options:o}=this;if(t.interaction.type()){const n="to".concat(t.interaction.type().getAttribute("data-type"));t.interaction.result.value="function"==typeof e[n]?e[n]().toString(o.outputPrecision):""}!this._initializingActive&&this._recalc&&this._emit("change",e)}_clearColor(t=!1){const{_root:e,options:o}=this;o.useAsButton||(e.button.style.color="rgba(0, 0, 0, 0.15)"),e.button.classList.add("clear"),o.showAlways||this.hide(),this._lastColor=null,this._initializingActive||t||(this._emit("save",null),this._emit("clear",this))}_parseLocalColor(t){const{values:e,type:o,a:n}=C(t),{lockOpacity:i}=this.options,r=void 0!==n&&1!==n;return e&&3===e.length&&(e[3]=void 0),{values:!e||i&&r?null:e,type:o}}_t(t){return this.options.i18n[t]||B.I18N_DEFAULTS[t]}_emit(t,...e){this._eventListener[t].forEach(t=>t(...e,this))}on(t,e){return this._eventListener[t].push(e),this}off(t,e){const o=this._eventListener[t]||[],n=o.indexOf(e);return~n&&o.splice(n,1),this}addSwatch(t){const{values:e}=this._parseLocalColor(t);if(e){const{_swatchColors:t,_root:o}=this,n=k(...e),i=a('<button type="button" style="color: '.concat(n.toRGBA().toString(0),'" aria-label="').concat(this._t("btn:swatch"),'"/>'));return o.swatches.appendChild(i),t.push({el:i,color:n}),this._eventBindings.push(r(i,"click",()=>{this.setHSVA(...n.toHSVA(),!0),this._emit("swatchselect",n),this._emit("change",n)})),!0}return!1}removeSwatch(t){const e=this._swatchColors[t];if(e){const{el:o}=e;return this._root.swatches.removeChild(o),this._swatchColors.splice(t,1),!0}return!1}applyColor(t=!1){const{preview:e,button:o}=this._root,n=this._color.toRGBA().toString(0);return e.lastColor.style.color=n,this.options.useAsButton||(o.style.color=n),o.classList.remove("clear"),this._lastColor=this._color.clone(),this._initializingActive||t||this._emit("save",this._color),this}destroy(){this._eventBindings.forEach(t=>s(...t)),Object.keys(this._components).forEach(t=>this._components[t].destroy())}destroyAndRemove(){this.destroy();const{root:t,app:e}=this._root;t.parentElement&&t.parentElement.removeChild(t),e.parentElement.removeChild(e),Object.keys(this).forEach(t=>this[t]=null)}hide(){return this._root.app.classList.remove("visible"),this._emit("hide",this),this}show(){return this.options.disabled||(this._root.app.classList.add("visible"),this._emit("show",this)),this}isOpen(){return this._root.app.classList.contains("visible")}setHSVA(t=360,e=0,o=0,n=1,i=!1){const r=this._recalc;if(this._recalc=!1,t<0||t>360||e<0||e>100||o<0||o>100||n<0||n>1)return!1;this._color=k(t,e,o,n);const{hue:s,opacity:a,palette:c}=this._components;return s.update(t/360),a.update(n),c.update(e/100,1-o/100),i||this.applyColor(),r&&this._updateOutput(),this._recalc=r,!0}setColor(t,e=!1){if(null===t)return this._clearColor(e),!0;const{values:o,type:n}=this._parseLocalColor(t);if(o){const t=n.toUpperCase(),{options:i}=this._root.interaction,r=i.find(e=>e.getAttribute("data-type")===t);if(r&&!r.hidden)for(const t of i)t.classList[t===r?"add":"remove"]("active");return!!this.setHSVA(...o,e)&&this.setColorRepresentation(t)}return!1}setColorRepresentation(t){return t=t.toUpperCase(),!!this._root.interaction.options.find(e=>e.getAttribute("data-type").startsWith(t)&&!e.click())}getColorRepresentation(){return this._representation}getColor(){return this._color}getSelectedColor(){return this._lastColor}getRoot(){return this._root}disable(){return this.hide(),this.options.disabled=!0,this._root.button.classList.add("disabled"),this}enable(){return this.options.disabled=!1,this._root.button.classList.remove("disabled"),this}}L(B,"utils",n),L(B,"version",h.a),L(B,"I18N_DEFAULTS",{"ui:dialog":"color picker dialog","btn:toggle":"toggle color picker dialog","btn:swatch":"color swatch","btn:last-color":"use previous color","btn:save":"Save","btn:cancel":"Cancel","btn:clear":"Clear","aria:btn:save":"save and close","aria:btn:cancel":"cancel and close","aria:btn:clear":"clear and close","aria:input":"color input field","aria:palette":"color selection area","aria:hue":"hue selection slider","aria:opacity":"selection slider"}),L(B,"DEFAULT_OPTIONS",{appClass:null,theme:"classic",useAsButton:!1,padding:8,disabled:!1,comparison:!0,closeOnScroll:!1,outputPrecision:0,lockOpacity:!1,autoReposition:!0,container:"body",components:{interaction:{}},i18n:{},swatches:null,inline:!1,sliders:null,default:"#42445a",defaultRepresentation:null,position:"bottom-middle",adjustableNumbers:!0,showAlways:!1,closeWithKey:"Escape"}),L(B,"create",t=>new B(t));e.default=B}]).default}));
5
+ //# sourceMappingURL=pickr.min.js.map
js/libraries/range-slider.min.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ !function(e,t){"use strict";function s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var i=function(){function e(e,t){for(var s=0;s<t.length;s++){var i=t[s];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,s,i){return s&&e(t.prototype,s),i&&e(t,i),t}}();/*!
2
+ * Range-slider 1.0.0
3
+ * Customizable slider (range) component for JavaScript.
4
+ *
5
+ * Copyright: Alexey Grinko, 2017
6
+ * Git repository: https://github.com/agrinko/range-slider.git
7
+ *
8
+ * @license MIT - https://opensource.org/licenses/MIT
9
+ */
10
+ !function(e){var t={value:0,min:0,max:100,step:1,unit:null,width:null,design:"3d",theme:"default",size:"medium",handle:"square",popup:"top",showMinMaxLabels:!0,showCurrentValueLabel:!1,labelsPosition:"top",onstart:function(){},onmove:function(){},onfinish:function(){}},n=function(){function e(i,n){s(this,e),i instanceof HTMLElement||(i=e._el(),n||(n=i)),this.el=i,this.s=a({},t,n),this._validateSettings(),this._buildDOM(),this._bindEvents(),this.initialValue=this.s.value,this.value=null,this.setValue(this.s.value)}return i(e,[{key:"getValue",value:function(){return this.value}},{key:"getElement",value:function(){return this.el}},{key:"labelValue",value:function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.value)+" "+(this.s.unit||"")}},{key:"setValue",value:function(e){(e=this._normalize(e))<this.s.min||e>this.s.max||(null===this.value||e!=this.value&&this.s.onmove.call(this,e)!==!1)&&(this.value=e,this._updatePopup(),this._updateLabel(),this._moveToValue(e))}},{key:"setWidth",value:function(e){arguments.length&&("number"==typeof e&&(e+="px"),this.el.style.width=e)}},{key:"_validateSettings",value:function(){this.s.value=e.toNumber(this.s.value,t.value),this.s.min=e.toNumber(this.s.min,t.min),this.s.max=e.toNumber(this.s.max,t.max),this.s.step=e.toNumber(this.s.step,t.step)}},{key:"_buildDOM",value:function(){this._setClasses(),this._createBar(),this.setWidth(this.s.width),(this.s.showMinMaxLabels||this.s.showCurrentValueLabel)&&this._createLabels(),this.s.popup&&this._createPopup()}},{key:"_setClasses",value:function(){var e=this;["range-slider","rs-theme-"+this.s.theme,"rs-size-"+this.s.size,"rs-design-"+this.s.design,"rs-handle-"+this.s.handle,this.s.showMinMaxLabels||this.s.showCurrentValueLabel?"rs-labels-"+this.s.labelsPosition:null].forEach(function(t){t&&(e.el.className+=" "+t)})}},{key:"_createBar",value:function(){var t=e._el(),s=e._el(),i=e._el(),n=e._el();t.className="rs-bar",s.className="rs-progress",i.className="rs-wrap",n.className="rs-handle",t.appendChild(i),i.appendChild(s),i.appendChild(n),this.el.appendChild(t),this.bar=t,this.progressBar=s,this.range=i,this.handle=n}},{key:"_createLabels",value:function(){var t=e._el(),s=e._el(),i=e._el(),n=e._el(),a=e._el();t.className="rs-labels",s.className="rs-wrap",i.className="rs-label-left",n.className="rs-label-middle",a.className="rs-label-right",t.appendChild(i),t.appendChild(a),t.appendChild(s),s.appendChild(n),this.el.appendChild(t),this.labels={left:i,right:a,middle:n},this._updateLabels()}},{key:"_updateLabels",value:function(){this.s.showMinMaxLabels&&(this.labels.left.innerText=this.labelValue(this.s.min),this.labels.right.innerText=this.labelValue(this.s.max))}},{key:"_updateLabel",value:function(){this.s.showCurrentValueLabel&&(this.labels.middle.innerText=this.labelValue(this.value))}},{key:"_createPopup",value:function(){var t=e._el();t.className="rs-popup rs-hidden rs-popup-"+this.s.popup,this.handle.appendChild(t),this.popup=t}},{key:"_updatePopup",value:function(){this.s.popup&&(this.popup.innerText=this.labelValue(this.value))}},{key:"_togglePopup",value:function(e){this.s.popup&&(e?(this.popup.className=this.popup.className.replace("rs-hidden",""),this.s.showCurrentValueLabel&&(this.labels.middle.className+=" rs-hidden")):(this.popup.className+=" rs-hidden",this.s.showCurrentValueLabel&&(this.labels.middle.className=this.labels.middle.className.replace("rs-hidden",""))))}},{key:"_bindEvents",value:function(){var e=this;this.bar.addEventListener("mousedown",function(t){0==t.button&&(t.preventDefault(),e._begin(t.clientX,t.target))}),this.bar.addEventListener("touchstart",function(t){t.changedTouches&&t.changedTouches[0]&&(t.preventDefault(),e._begin(t.changedTouches[0].clientX,t.target))})}},{key:"_begin",value:function(e,t){this.s.onstart.call(this,this.value)!==!1&&(this.prevValue=this.value,this.el.className+=" rs-active",this._togglePopup(!0),t!=this.handle?this._move(e):this._ensureNoElementsIntersection(),this._initHandle(e))}},{key:"_initHandle",value:function(e){var t=this,s=this.handle.getBoundingClientRect(),i=e-(s.left+s.width/2),n=function(e){var s=e.changedTouches?e.changedTouches[0].clientX:e.clientX;t._move(s-i),e.preventDefault()},a=function e(){document.removeEventListener("mousemove",n),document.removeEventListener("touchmove",n),document.removeEventListener("mouseup",e),document.removeEventListener("touchend",e),document.removeEventListener("touchcancel",e),t._end()};document.addEventListener("mousemove",n),document.addEventListener("touchmove",n),document.addEventListener("mouseup",a),document.addEventListener("touchend",a),document.addEventListener("touchcancel",a)}},{key:"_end",value:function(){this.value!=this.prevValue&&this.s.onfinish.call(this,this.value),this.el.className=this.el.className.replace("rs-active",""),this._togglePopup(!1),this._ensureNoElementsIntersection()}},{key:"_move",value:function(e){var t=this._getRelX(e),s=this._toValue(t);this.setValue(s)}},{key:"_moveToValue",value:function(e){e=100*this._toFraction(e),this.progressBar.style.width=this.handle.style.left=e+"%",this._moveLabel(e)}},{key:"_moveLabel",value:function(e){this.s.showCurrentValueLabel&&(this.labels.middle.style.left=e+"%"),this._ensureNoElementsIntersection()}},{key:"_ensureNoElementsIntersection",value:function(){this.s.showMinMaxLabels&&(this.s.popup&&this.popup.className.indexOf("rs-hidden")==-1&&(e.ensureNoIntersection(this.popup,this.labels.left),e.ensureNoIntersection(this.popup,this.labels.right)),this.s.showCurrentValueLabel&&this.labels.middle.className.indexOf("rs-hidden")==-1&&(e.ensureNoIntersection(this.labels.middle,this.labels.left),e.ensureNoIntersection(this.labels.middle,this.labels.right)))}},{key:"_normalize",value:function(e){e=Math.round(Math.min(Math.max(e,this.s.min),this.s.max));var t=(e-this.initialValue)%this.s.step;return t>=this.s.step/2&&(e+=this.s.step),e-=t}},{key:"_getRelX",value:function(e){var t=this.range.getBoundingClientRect(),s=(e-t.left)/t.width;return Math.min(Math.max(s,0),1)}},{key:"_toValue",value:function(e){return this.s.min+(this.s.max-this.s.min)*e}},{key:"_toFraction",value:function(e){return(e-this.s.min)/(this.s.max-this.s.min)}}],[{key:"_el",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"DIV";return document.createElement(e)}},{key:"ensureNoIntersection",value:function(t,s){s.className=s.className.replace("rs-hidden",""),t.className.indexOf("rs-hidden")==-1&&e.intersects(t,s)&&(s.className+=" rs-hidden")}},{key:"toNumber",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return e=+e,e||0===e||(e=t),e}},{key:"intersects",value:function(e,t){var s=e.getBoundingClientRect(),i=t.getBoundingClientRect();return(this._intersectsRectH(s,i)||this._intersectsRectH(i,s))&&(this._intersectsRectV(s,i)||this._intersectsRectV(i,s))}},{key:"_intersectsRectH",value:function(e,t){return e.left<=t.right&&(e.left>=t.left||e.right>=t.left)}},{key:"_intersectsRectV",value:function(e,t){return e.top<=t.bottom&&(e.top>=t.top||e.bottom>=t.top)}}]),e}(),a=Object.assign||function(e){for(var t=1;t<arguments.length;t++)for(var s in arguments[t])arguments[t].hasOwnProperty(s)&&(e[s]=arguments[t][s]);return e};"function"==typeof define&&define.amd?define(function(){return n}):"undefined"!=typeof module&&module.exports?module.exports=n:e.RangeSlider=n}(window),t.true=e}({},function(){return this}());
js/libraries/sortable.min.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ var sortable=function(){"use strict";function c(e,t,n){if(void 0===n)return e&&e.h5s&&e.h5s.data&&e.h5s.data[t];e.h5s=e.h5s||{},e.h5s.data=e.h5s.data||{},e.h5s.data[t]=n}var v=function(e,t){if(!(e instanceof NodeList||e instanceof HTMLCollection||e instanceof Array))throw new Error("You must provide a nodeList/HTMLCollection/Array of elements to be filtered.");return"string"!=typeof t?Array.from(e):Array.from(e).filter(function(e){return 1===e.nodeType&&e.matches(t)})},y=new Map,t=function(){function e(){this._config=new Map,this._placeholder=void 0,this._data=new Map}return Object.defineProperty(e.prototype,"config",{get:function(){var n={};return this._config.forEach(function(e,t){n[t]=e}),n},set:function(e){if("object"!=typeof e)throw new Error("You must provide a valid configuration object to the config setter.");var t=Object.assign({},e);this._config=new Map(Object.entries(t))},enumerable:!1,configurable:!0}),e.prototype.setConfig=function(e,t){if(!this._config.has(e))throw new Error("Trying to set invalid configuration item: "+e);this._config.set(e,t)},e.prototype.getConfig=function(e){if(!this._config.has(e))throw new Error("Invalid configuration item requested: "+e);return this._config.get(e)},Object.defineProperty(e.prototype,"placeholder",{get:function(){return this._placeholder},set:function(e){if(!(e instanceof HTMLElement)&&null!==e)throw new Error("A placeholder must be an html element or null.");this._placeholder=e},enumerable:!1,configurable:!0}),e.prototype.setData=function(e,t){if("string"!=typeof e)throw new Error("The key must be a string.");this._data.set(e,t)},e.prototype.getData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.get(e)},e.prototype.deleteData=function(e){if("string"!=typeof e)throw new Error("The key must be a string.");return this._data.delete(e)},e}(),E=function(e){if(!(e instanceof HTMLElement))throw new Error("Please provide a sortable to the store function.");return y.has(e)||y.set(e,new t),y.get(e)};function i(e,t,n){if(e instanceof Array)for(var r=0;r<e.length;++r)i(e[r],t,n);else e.addEventListener(t,n),E(e).setData("event"+t,n)}function a(e,t){if(e instanceof Array)for(var n=0;n<e.length;++n)a(e[n],t);else e.removeEventListener(t,E(e).getData("event"+t)),E(e).deleteData("event"+t)}function l(e,t,n){if(e instanceof Array)for(var r=0;r<e.length;++r)l(e[r],t,n);else e.setAttribute(t,n)}function r(e,t){if(e instanceof Array)for(var n=0;n<e.length;++n)r(e[n],t);else e.removeAttribute(t)}var w=function(e){if(!e.parentElement||0===e.getClientRects().length)throw new Error("target element must be part of the dom");var t=e.getClientRects()[0];return{left:t.left+window.pageXOffset,right:t.right+window.pageXOffset,top:t.top+window.pageYOffset,bottom:t.bottom+window.pageYOffset}},d=function(n,r){var o;return void 0===r&&(r=0),function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];clearTimeout(o),o=setTimeout(function(){n.apply(void 0,e)},r)}},b=function(e,t){if(!(e instanceof HTMLElement&&(t instanceof NodeList||t instanceof HTMLCollection||t instanceof Array)))throw new Error("You must provide an element and a list of elements.");return Array.from(t).indexOf(e)},f=function(e){if(!(e instanceof HTMLElement))throw new Error("Element is not a node element.");return null!==e.parentNode},n=function(e,t,n){if(!(e instanceof HTMLElement&&e.parentElement instanceof HTMLElement))throw new Error("target and element must be a node");e.parentElement.insertBefore(t,"before"===n?e:e.nextElementSibling)},T=function(e,t){return n(e,t,"before")},C=function(e,t){return n(e,t,"after")},o=function(t,n,e){if(void 0===n&&(n=function(e,t){return e}),void 0===e&&(e=function(e){return e}),!(t instanceof HTMLElement)||!0==!t.isSortable)throw new Error("You need to provide a sortableContainer to be serialized.");if("function"!=typeof n||"function"!=typeof e)throw new Error("You need to provide a valid serializer for items and the container.");var r=c(t,"opts").items,o=v(t.children,r),a=o.map(function(e){return{parent:t,node:e,html:e.outerHTML,index:b(e,o)}});return{container:e({node:t,itemCount:a.length}),items:a.map(function(e){return n(e,t)})}},u=function(e,t,n){var r;if(void 0===n&&(n="sortable-placeholder"),!(e instanceof HTMLElement))throw new Error("You must provide a valid element as a sortable.");if(!(t instanceof HTMLElement)&&void 0!==t)throw new Error("You must provide a valid element as a placeholder or set ot to undefined.");return void 0===t&&(["UL","OL"].includes(e.tagName)?t=document.createElement("li"):["TABLE","TBODY"].includes(e.tagName)?(t=document.createElement("tr")).innerHTML='<td colspan="100"></td>':t=document.createElement("div")),"string"==typeof n&&(r=t.classList).add.apply(r,n.split(" ")),t},L=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return"border-box"===n.getPropertyValue("box-sizing")?parseInt(n.getPropertyValue("height"),10):["height","padding-top","padding-bottom"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},x=function(e){if(!(e instanceof HTMLElement))throw new Error("You must provide a valid dom element");var n=window.getComputedStyle(e);return["width","padding-left","padding-right"].map(function(e){var t=parseInt(n.getPropertyValue(e),10);return isNaN(t)?0:t}).reduce(function(e,t){return e+t})},s=function(e,t){if(!(e instanceof Array))throw new Error("You must provide a Array of HTMLElements to be filtered.");return"string"!=typeof t?e:e.filter(function(e){return e.querySelector(t)instanceof HTMLElement||e.shadowRoot&&e.shadowRoot.querySelector(t)instanceof HTMLElement}).map(function(e){return e.querySelector(t)||e.shadowRoot&&e.shadowRoot.querySelector(t)})},p=function(e){return e.composedPath&&e.composedPath()[0]||e.target},m=function(e,t,n){return{element:e,posX:n.pageX-t.left,posY:n.pageY-t.top}},g=function(e,t,n){if(!(e instanceof Event))throw new Error("setDragImage requires a DragEvent as the first argument.");if(!(t instanceof HTMLElement))throw new Error("setDragImage requires the dragged element as the second argument.");if(n||(n=m),e.dataTransfer&&e.dataTransfer.setDragImage){var r=n(t,w(t),e);if(!(r.element instanceof HTMLElement)||"number"!=typeof r.posX||"number"!=typeof r.posY)throw new Error("The customDragImage function you provided must return and object with the properties element[string], posX[integer], posY[integer].");e.dataTransfer.effectAllowed="copyMove",e.dataTransfer.setData("text/plain",p(e).id),e.dataTransfer.setDragImage(r.element,r.posX,r.posY)}},M=function(e,t){if(!0===e.isSortable){var n=E(e).getConfig("acceptFrom");if(null!==n&&!1!==n&&"string"!=typeof n)throw new Error('HTML5Sortable: Wrong argument, "acceptFrom" must be "null", "false", or a valid selector string.');if(null!==n)return!1!==n&&0<n.split(",").filter(function(e){return 0<e.length&&t.matches(e)}).length;if(e===t)return!0;if(void 0!==E(e).getConfig("connectWith")&&null!==E(e).getConfig("connectWith"))return E(e).getConfig("connectWith")===E(t).getConfig("connectWith")}return!1},D={items:null,connectWith:null,disableIEFix:null,acceptFrom:null,copy:!1,placeholder:null,placeholderClass:"sortable-placeholder",draggingClass:"sortable-dragging",hoverClass:!1,dropTargetContainerClass:!1,debounce:0,throttleTime:100,maxItems:0,itemSerializer:void 0,containerSerializer:void 0,customDragImage:null,orientation:"vertical"};var H,I,A,S,_,Y,O,P,z,N=function(e,t){if("string"==typeof E(e).getConfig("hoverClass")){var o=E(e).getConfig("hoverClass").split(" ");!0===t?(i(e,"mousemove",function(r,o){var a=this;if(void 0===o&&(o=250),"function"!=typeof r)throw new Error("You must provide a function as the first argument for throttle.");if("number"!=typeof o)throw new Error("You must provide a number as the second argument for throttle.");var i=null;return function(){for(var e=[],t=0;t<arguments.length;t++)e[t]=arguments[t];var n=Date.now();(null===i||o<=n-i)&&(i=n,r.apply(a,e))}}(function(r){0===r.buttons&&v(e.children,E(e).getConfig("items")).forEach(function(e){var t,n;e!==r.target?(t=e.classList).remove.apply(t,o):(n=e.classList).add.apply(n,o)})},E(e).getConfig("throttleTime"))),i(e,"mouseleave",function(){v(e.children,E(e).getConfig("items")).forEach(function(e){var t;(t=e.classList).remove.apply(t,o)})})):(a(e,"mousemove"),a(e,"mouseleave"))}},h=function(e){a(e,"dragstart"),a(e,"dragend"),a(e,"dragover"),a(e,"dragenter"),a(e,"drop"),a(e,"mouseenter"),a(e,"mouseleave")},W=function(e,t){e&&a(e,"dragleave"),t&&t!==e&&a(t,"dragleave")},j=function(e,t){var n=e;return!0===E(t).getConfig("copy")&&(l(n=e.cloneNode(!0),"aria-copied","true"),e.parentElement.appendChild(n),n.style.display="none",n.oldDisplay=e.style.display),n},F=function(e){var t;(t=e).h5s&&delete t.h5s.data,r(e,"aria-dropeffect")},q=function(e){r(e,"aria-grabbed"),r(e,"aria-copied"),r(e,"draggable"),r(e,"role")};function R(e,t){if(t.composedPath)return t.composedPath().find(function(e){return e.isSortable});for(;!0!==e.isSortable;)e=e.parentElement;return e}function X(e,t){var n=c(e,"opts"),r=v(e.children,n.items).filter(function(e){return e.contains(t)||e.shadowRoot&&e.shadowRoot.contains(t)});return 0<r.length?r[0]:t}var B=function(e){var t=c(e,"opts"),n=v(e.children,t.items),r=s(n,t.handle);(l(e,"aria-dropeffect","move"),c(e,"_disabled","false"),l(r,"draggable","true"),!1===t.disableIEFix)&&("function"==typeof(document||window.document).createElement("span").dragDrop&&i(r,"mousedown",function(){if(-1!==n.indexOf(this))this.dragDrop();else{for(var e=this.parentElement;-1===n.indexOf(e);)e=e.parentElement;e.dragDrop()}}))},k=function(e){var t=c(e,"opts"),n=v(e.children,t.items),r=s(n,t.handle);c(e,"_disabled","false"),h(n),W(),a(r,"mousedown"),a(e,"dragover"),a(e,"dragenter"),a(e,"drop")};function U(e,h){var a=String(h);return h=h||{},"string"==typeof e&&(e=document.querySelectorAll(e)),e instanceof HTMLElement&&(e=[e]),e=Array.prototype.slice.call(e),/serialize/.test(a)?e.map(function(e){var t=c(e,"opts");return o(e,t.itemSerializer,t.containerSerializer)}):(e.forEach(function(s){if(/enable|disable|destroy/.test(a))return U[a](s);["connectWith","disableIEFix"].forEach(function(e){Object.prototype.hasOwnProperty.call(h,e)&&null!==h[e]&&console.warn('HTML5Sortable: You are using the deprecated configuration "'+e+'". This will be removed in an upcoming version, make sure to migrate to the new options when updating.')}),h=Object.assign({},D,E(s).config,h),E(s).config=h,c(s,"opts",h),s.isSortable=!0,k(s);var e,t=v(s.children,h.items);if(null!==h.placeholder&&void 0!==h.placeholder){var n=document.createElement(s.tagName);h.placeholder instanceof HTMLElement?n.appendChild(h.placeholder):n.innerHTML=h.placeholder,e=n.children[0]}E(s).placeholder=u(s,e,h.placeholderClass),c(s,"items",h.items),h.acceptFrom?c(s,"acceptFrom",h.acceptFrom):h.connectWith&&c(s,"connectWith",h.connectWith),B(s),l(t,"role","option"),l(t,"aria-grabbed","false"),N(s,!0),i(s,"dragstart",function(e){var t=p(e);if(!0!==t.isSortable&&(e.stopImmediatePropagation(),(!h.handle||t.matches(h.handle))&&"false"!==t.getAttribute("draggable"))){var n=R(t,e),r=X(n,t);O=v(n.children,h.items),_=O.indexOf(r),Y=b(r,n.children),S=n,g(e,r,h.customDragImage),I=L(r),A=x(r),r.classList.add(h.draggingClass),l(H=j(r,n),"aria-grabbed","true"),n.dispatchEvent(new CustomEvent("sortstart",{detail:{origin:{elementIndex:Y,index:_,container:S},item:H,originalTarget:t}}))}}),i(s,"dragenter",function(e){var n=p(e),r=R(n,e);r&&r!==P&&(z=v(r.children,c(r,"items")).filter(function(e){return e!==E(s).placeholder}),h.dropTargetContainerClass&&r.classList.add(h.dropTargetContainerClass),r.dispatchEvent(new CustomEvent("sortenter",{detail:{origin:{elementIndex:Y,index:_,container:S},destination:{container:r,itemsBeforeUpdate:z},item:H,originalTarget:n}})),i(r,"dragleave",function(e){var t=e.relatedTarget||e.fromElement;e.currentTarget.contains(t)||(h.dropTargetContainerClass&&r.classList.remove(h.dropTargetContainerClass),r.dispatchEvent(new CustomEvent("sortleave",{detail:{origin:{elementIndex:Y,index:_,container:r},item:H,originalTarget:n}})))})),P=r}),i(s,"dragend",function(e){if(H){H.classList.remove(h.draggingClass),l(H,"aria-grabbed","false"),"true"===H.getAttribute("aria-copied")&&"true"!==c(H,"dropped")&&H.remove(),H.style.display=H.oldDisplay,delete H.oldDisplay;var t=Array.from(y.values()).map(function(e){return e.placeholder}).filter(function(e){return e instanceof HTMLElement}).filter(f)[0];t&&t.remove(),s.dispatchEvent(new CustomEvent("sortstop",{detail:{origin:{elementIndex:Y,index:_,container:S},item:H}})),A=I=H=P=null}}),i(s,"drop",function(e){if(M(s,H.parentElement)){e.preventDefault(),e.stopPropagation(),c(H,"dropped","true");var t=Array.from(y.values()).map(function(e){return e.placeholder}).filter(function(e){return e instanceof HTMLElement}).filter(f)[0];C(t,H),t.remove(),s.dispatchEvent(new CustomEvent("sortstop",{detail:{origin:{elementIndex:Y,index:_,container:S},item:H}}));var n=E(s).placeholder,r=v(S.children,h.items).filter(function(e){return e!==n}),o=!0===this.isSortable?this:this.parentElement,a=v(o.children,c(o,"items")).filter(function(e){return e!==n}),i=b(H,Array.from(H.parentElement.children).filter(function(e){return e!==n})),l=b(H,a);h.dropTargetContainerClass&&o.classList.remove(h.dropTargetContainerClass),Y===i&&S===o||s.dispatchEvent(new CustomEvent("sortupdate",{detail:{origin:{elementIndex:Y,index:_,container:S,itemsBeforeUpdate:O,items:r},destination:{index:l,elementIndex:i,container:o,itemsBeforeUpdate:z,items:a},item:H}}))}});var o=d(function(t,e,n,r){if(H)if(h.forcePlaceholderSize&&(E(t).placeholder.style.height=I+"px",E(t).placeholder.style.width=A+"px"),-1<Array.from(t.children).indexOf(e)){var o=L(e),a=x(e),i=b(E(t).placeholder,e.parentElement.children),l=b(e,e.parentElement.children);if(I<o||A<a){var s=o-I,c=a-A,d=w(e).top,f=w(e).left;if(i<l&&("vertical"===h.orientation&&r<d||"horizontal"===h.orientation&&n<f))return;if(l<i&&("vertical"===h.orientation&&d+o-s<r||"horizontal"===h.orientation&&f+a-c<n))return}void 0===H.oldDisplay&&(H.oldDisplay=H.style.display),"none"!==H.style.display&&(H.style.display="none");var u=!1;try{var p=w(e).top+e.offsetHeight/2,m=w(e).left+e.offsetWidth/2;u="vertical"===h.orientation&&p<=r||"horizontal"===h.orientation&&m<=n}catch(e){u=i<l}u?C(e,E(t).placeholder):T(e,E(t).placeholder),Array.from(y.values()).filter(function(e){return void 0!==e.placeholder}).forEach(function(e){e.placeholder!==E(t).placeholder&&e.placeholder.remove()})}else{var g=Array.from(y.values()).filter(function(e){return void 0!==e.placeholder}).map(function(e){return e.placeholder});-1!==g.indexOf(e)||t!==e||v(e.children,h.items).length||(g.forEach(function(e){return e.remove()}),e.appendChild(E(t).placeholder))}},h.debounce),r=function(e){var t=e.target,n=!0===t.isSortable?t:R(t,e);if(t=X(n,t),H&&M(n,H.parentElement)&&"true"!==c(n,"_disabled")){var r=c(n,"opts");parseInt(r.maxItems)&&v(n.children,c(n,"items")).length>=parseInt(r.maxItems)&&H.parentElement!==n||(e.preventDefault(),e.stopPropagation(),e.dataTransfer.dropEffect=!0===E(n).getConfig("copy")?"copy":"move",o(n,t,e.pageX,e.pageY))}};i(t.concat(s),"dragover",r),i(t.concat(s),"dragenter",r)}),e)}return U.destroy=function(e){var t,n,r,o;n=c(t=e,"opts")||{},r=v(t.children,n.items),o=s(r,n.handle),a(t,"dragover"),a(t,"dragenter"),a(t,"dragstart"),a(t,"dragend"),a(t,"drop"),F(t),a(o,"mousedown"),h(r),q(r),W(S,P),t.isSortable=!1},U.enable=function(e){B(e)},U.disable=function(e){var t,n,r,o;n=c(t=e,"opts"),r=v(t.children,n.items),o=s(r,n.handle),l(t,"aria-dropeffect","none"),c(t,"_disabled","true"),l(o,"draggable","false"),a(o,"mousedown")},U.__testing={_data:c,_removeItemEvents:h,_removeItemData:q,_removeSortableData:F,_removeContainerEvents:W},U}();
2
+ //# sourceMappingURL=html5sortable.min.js.map
js/lottie.js ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function newLottieAnimation(x, y, json) {
2
+ const newlottie = new fabric.Lottie(json, {
3
+ left: x,
4
+ top: y,
5
+ width: 500,
6
+ height: 500,
7
+ originX: 'center',
8
+ originY: 'center',
9
+ backgroundColor: 'rgba(255,255,255,0)',
10
+ cursorWidth: 1,
11
+ stroke: '#000',
12
+ strokeUniform: true,
13
+ paintFirst: 'stroke',
14
+ strokeWidth: 0,
15
+ cursorDuration: 1,
16
+ cursorDelay: 250,
17
+ duration: duration * 1000,
18
+ assetType: 'sprite',
19
+ id: 'Sprite' + layer_count,
20
+ objectCaching: false,
21
+ strokeDashArray: false,
22
+ inGroup: false,
23
+ shadow: {
24
+ color: '#000',
25
+ offsetX: 0,
26
+ offsetY: 0,
27
+ blur: 0,
28
+ opacity: 0,
29
+ },
30
+ });
31
+ canvas.add(newlottie);
32
+ canvas.requestRenderAll();
33
+ newlottie.duration = newlottie.getDuration() * 1000;
34
+ newlottie.goToSeconds(0);
35
+ canvas.renderAll();
36
+ newLayer(newlottie);
37
+ canvas.setActiveObject(newlottie);
38
+ canvas.bringToFront(newlottie);
39
+ }
js/recorder.js ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const FPS = 30;
2
+ let frame = 0;
3
+ var chunks = [];
4
+ var stream;
5
+ var rec;
6
+ var track;
7
+
8
+ function timeout(ms) {
9
+ return new Promise((resolve) => setTimeout(resolve, ms));
10
+ }
11
+
12
+ function initRecorder() {
13
+ stream = document.getElementById('canvasrecord').captureStream(0);
14
+ track = stream.getVideoTracks()[0];
15
+
16
+ if (!track.requestFrame) {
17
+ track.requestFrame = () => stream.requestFrame();
18
+ }
19
+
20
+ rec = new MediaRecorder(stream, {
21
+ bitsPerSecond: 3200000,
22
+ });
23
+
24
+ rec.ondataavailable = function (evt) {
25
+ console.log('chunky');
26
+ chunks.push(evt.data);
27
+ };
28
+
29
+ rec.start();
30
+
31
+ console.log('Recorder has been started');
32
+
33
+ rec.onstart = function () {
34
+ rec.pause();
35
+ console.log('start!');
36
+ };
37
+ }
38
+
39
+ async function recordFrame() {
40
+ console.log(frame);
41
+
42
+ waitForEvent(rec, 'pause');
43
+
44
+ //rec.onpause = async function(e) {
45
+
46
+ // wake up the recorder
47
+ rec.resume();
48
+ recordAnimate(false, (frame / FPS) * 1000);
49
+ //animate(false, (frame/FPS)*1000)
50
+ // force write the frame
51
+ track.requestFrame();
52
+
53
+ // wait until our frame-time elapsed
54
+ await timeout(1000 / FPS);
55
+
56
+ // sleep recorder
57
+ rec.pause();
58
+ //}
59
+ }
60
+
61
+ async function exportRecording() {
62
+ rec.stop();
63
+ stream.getTracks().forEach((track) => track.stop());
64
+ await waitForEvent(rec, 'stop');
65
+ return new Blob(chunks);
66
+ }
67
+
68
+ // Record canvas
69
+ async function record() {
70
+ updateRecordCanvas();
71
+ if ($('input[name=radio]:checked').val() == 'image') {
72
+ recording = true;
73
+ paused = true;
74
+ animate(false, currenttime);
75
+ const dataURL = canvasrecord.toDataURL({
76
+ format: 'png',
77
+ });
78
+ const link = document.createElement('a');
79
+ link.download = 'image.png';
80
+ link.href = dataURL;
81
+ document.body.appendChild(link);
82
+ link.click();
83
+ document.body.removeChild(link);
84
+ recording = false;
85
+ } else {
86
+ if (!recording) {
87
+ recording = true;
88
+ paused = true;
89
+ recordAnimate(false, (frame / FPS) * 1000);
90
+ recording = true;
91
+ $('#download-real').html('Rendering...');
92
+ $('#download-real').addClass('downloading');
93
+ var fps = 60;
94
+ var aCtx = new AudioContext();
95
+ function audioTimerLoop(callback, frequency) {
96
+ var freq = frequency / 1000;
97
+ var silence = aCtx.createGain();
98
+ silence.gain.value = 0;
99
+ silence.connect(aCtx.destination);
100
+ onOSCend();
101
+ var stopped = false;
102
+ function onOSCend() {
103
+ osc = aCtx.createOscillator();
104
+ osc.onended = onOSCend;
105
+ osc.connect(silence);
106
+ osc.start(0);
107
+ osc.stop(aCtx.currentTime + freq);
108
+ callback(aCtx.currentTime);
109
+ if (stopped) {
110
+ osc.onended = function () {
111
+ return;
112
+ };
113
+ }
114
+ }
115
+ return function () {
116
+ stopped = true;
117
+ };
118
+ }
119
+ var stopAnim = audioTimerLoop(renderAnim, 1000 / fps);
120
+ var stream = document
121
+ .getElementById('canvasrecord')
122
+ .captureStream(fps);
123
+ objects.forEach(function (object) {
124
+ if (
125
+ canvasrecord.getItemById(object.id).get('assetType') &&
126
+ canvasrecord.getItemById(object.id).get('assetType') ==
127
+ 'video'
128
+ ) {
129
+ var audio = $(
130
+ canvasrecord.getItemById(object.id).getElement()
131
+ )[0];
132
+ var audioContext = new AudioContext();
133
+ var audioSource =
134
+ audioContext.createMediaElementSource(audio);
135
+ var audioDestination =
136
+ audioContext.createMediaStreamDestination();
137
+ audioSource.connect(audioDestination);
138
+ stream.addTrack(
139
+ audioDestination.stream.getAudioTracks()[0]
140
+ );
141
+ }
142
+ });
143
+ if (background_audio != false) {
144
+ var audioContext = new AudioContext();
145
+ var audioSource =
146
+ audioContext.createMediaElementSource(background_audio);
147
+ var audioDestination =
148
+ audioContext.createMediaStreamDestination();
149
+ audioSource.connect(audioDestination);
150
+ stream.addTrack(audioDestination.stream.getAudioTracks()[0]);
151
+ background_audio.currentTime = 0;
152
+ background_audio.play();
153
+ }
154
+ let chunks = [];
155
+ var recorder = new MediaRecorder(stream, {
156
+ bitsPerSecond: 3200000,
157
+ });
158
+ recorder.ondataavailable = (e) => chunks.push(e.data);
159
+ recorder.onstop = (e) => {
160
+ stopAnim();
161
+ downloadRecording(chunks);
162
+ animate(false, 0);
163
+ $('#seekbar').offset({
164
+ left:
165
+ offset_left +
166
+ $('#inner-timeline').offset().left +
167
+ currenttime / timelinetime,
168
+ });
169
+ canvas.renderAll();
170
+ console.log('Finished rendering');
171
+ };
172
+ recorder.start();
173
+
174
+ setTimeout(function () {
175
+ recorder.stop();
176
+ }, duration);
177
+
178
+ async function renderAnim(time) {
179
+ await recordAnimate(time * 1000);
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ /*
186
+
187
+ initRecorder();
188
+
189
+ //await timeout(2000)
190
+
191
+ // draw one frame at a time
192
+ while (frame++ < FPS * (duration/1000)) {
193
+ await longDraw(); // do the long drawing
194
+ await recordFrame(); // record at constant FPS
195
+ }
196
+ // now all the frames have been drawn
197
+ const recorded = await exportRecording(); // we can get our final video file
198
+ const a = document.createElement('a');
199
+ a.style.display = 'none';
200
+ a.href = URL.createObjectURL(recorded);
201
+ a.download = "test.webm";
202
+ document.body.appendChild(a);
203
+ a.click();
204
+ recording = false;
205
+ currenttime = 0;
206
+ animate(false, 0);
207
+ $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)});
208
+ canvas.renderAll();
209
+ resizeCanvas();
210
+ if (background_audio != false) {
211
+ background_audio.pause();
212
+ background_audio = new Audio(background_audio.src)
213
+ }
214
+ $("#download-real").html("Download");
215
+ $("#download-real").removeClass("downloading");
216
+ updateRecordCanvas();
217
+
218
+ // Fake long drawing operations that make real-time recording impossible
219
+ function longDraw() {
220
+ recordAnimate((frame/FPS)*1000)
221
+ return wait(Math.random() * 300)
222
+ .then(recordAnimate((frame/FPS)*1000));
223
+ }*/
224
+
225
+ /*
226
+ paused = true;
227
+ recording = true;
228
+ $("#download-real").html("Rendering...");
229
+ $("#download-real").addClass("downloading");
230
+ var fps = 60;
231
+ var aCtx = new AudioContext();
232
+ function audioTimerLoop(callback, frequency) {
233
+ var freq = frequency / 1000;
234
+ var silence = aCtx.createGain();
235
+ silence.gain.value = 0;
236
+ silence.connect(aCtx.destination);
237
+ onOSCend();
238
+ var stopped = false;
239
+ function onOSCend() {
240
+ osc = aCtx.createOscillator();
241
+ osc.onended = onOSCend;
242
+ osc.connect(silence);
243
+ osc.start(0);
244
+ osc.stop(aCtx.currentTime + freq);
245
+ callback(aCtx.currentTime);
246
+ if (stopped) {
247
+ osc.onended = function() {
248
+ return;
249
+ };
250
+ }
251
+ };
252
+ return function() {
253
+ stopped = true;
254
+ };
255
+ }
256
+ var stopAnim = audioTimerLoop(renderAnim, 1000/(fps));
257
+ var stream = document.getElementById("canvasrecord").captureStream(fps);
258
+ objects.forEach(function(object){
259
+ if (canvasrecord.getItemById(object.id).get("assetType") && canvasrecord.getItemById(object.id).get("assetType") == "video") {
260
+ var audio = $(canvasrecord.getItemById(object.id).getElement())[0];
261
+ var audioContext = new AudioContext();
262
+ var audioSource = audioContext.createMediaElementSource(audio);
263
+ var audioDestination = audioContext.createMediaStreamDestination();
264
+ audioSource.connect(audioDestination);
265
+ stream.addTrack(audioDestination.stream.getAudioTracks()[0]);
266
+ }
267
+ })
268
+ if (background_audio != false) {
269
+ var audioContext = new AudioContext();
270
+ var audioSource = audioContext.createMediaElementSource(background_audio);
271
+ var audioDestination = audioContext.createMediaStreamDestination();
272
+ audioSource.connect(audioDestination);
273
+ stream.addTrack(audioDestination.stream.getAudioTracks()[0]);
274
+ background_audio.currentTime = 0;
275
+ background_audio.play();
276
+ }
277
+ let chunks = [];
278
+ var recorder = new MediaRecorder(stream, {
279
+ bitsPerSecond : 3200000,
280
+ });
281
+ recorder.ondataavailable = e => chunks.push(e.data);
282
+ recorder.onstop = e => {
283
+ stopAnim();
284
+ downloadRecording(chunks);
285
+ animate(false, 0);
286
+ $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)});
287
+ canvas.renderAll();
288
+ console.log("Finished rendering")
289
+ }
290
+ recorder.start();
291
+
292
+ setTimeout(function() {
293
+ recorder.stop();
294
+ }, duration)
295
+
296
+ async function renderAnim(time) {
297
+ await animate(false, time*1000);
298
+ }
299
+
300
+ */
301
+
302
+ /*
303
+ $("#download-real").html("Rendering...");
304
+ $("#download-real").addClass("downloading");
305
+
306
+ // browser check
307
+ if (typeof MediaStreamTrackGenerator === undefined || typeof MediaStream === undefined || typeof VideoFrame === undefined) {
308
+ console.log('Your browser does not support the web APIs used in this demo');
309
+ return;
310
+ }
311
+
312
+ // recording setup
313
+ const fps = 60;
314
+ const generator = new MediaStreamTrackGenerator({ kind: "video" });
315
+ const writer = generator.writable.getWriter();
316
+ const stream = new MediaStream();
317
+ stream.addTrack(generator);
318
+ const recorder = new MediaRecorder(stream, { mimeType: "video/webm" });
319
+ recorder.start();
320
+
321
+ function timeout(ms) {
322
+ return new Promise(resolve => setTimeout(resolve, ms));
323
+ }
324
+
325
+ // animate stuff
326
+ console.log('rendering...')
327
+ console.log(duration);
328
+ for (let i = 0; i < (duration/1000)*fps; i++) {
329
+ animate(false, (i/fps)*1000);
330
+ const frame = new VideoFrame(document.getElementById("canvasrecord"), {
331
+ timestamp: (i / fps)*1000
332
+ });
333
+ await writer.write(frame);
334
+ await timeout(100)
335
+ console.log("frame "+(i/fps)*1000);
336
+ }
337
+ console.log('rendering done');
338
+
339
+ // stop recording and
340
+ recorder.addEventListener("dataavailable", (evt) => {
341
+ const a = document.createElement('a');
342
+ a.style.display = 'none';
343
+ a.href = URL.createObjectURL(evt.data);
344
+ a.download = "test.webm";
345
+ document.body.appendChild(a);
346
+ a.click();
347
+ recording = false;
348
+ currenttime = 0;
349
+ animate(false, 0);
350
+ $("#seekbar").offset({left:offset_left+$("#inner-timeline").offset().left+(currenttime/timelinetime)});
351
+ canvas.renderAll();
352
+ resizeCanvas();
353
+ if (background_audio != false) {
354
+ background_audio.pause();
355
+ background_audio = new Audio(background_audio.src)
356
+ }
357
+ $("#download-real").html("Download");
358
+ $("#download-real").removeClass("downloading");
359
+ updateRecordCanvas();
360
+ });
361
+ recorder.stop();
362
+ */
js/text.js ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function animateText(group, ms, play, props, cv, id) {
2
+ var starttime = p_keyframes.find((x) => x.id == id).start;
3
+ ms -= starttime;
4
+ var length = group._objects.length;
5
+ var globaldelay = 0;
6
+ for (var i = 0; i < length; i++) {
7
+ var index = i;
8
+ if (props.order == 'backward') {
9
+ index = length - i - 1;
10
+ }
11
+ let left = group.item(index).defaultLeft;
12
+ let top = group.item(index).defaultTop;
13
+ let scaleX = group.item(index).defaultScaleX;
14
+ let scaleY = group.item(index).defaultScaleY;
15
+ var delay = i * duration;
16
+ var duration = props.duration / length;
17
+ var animation = {
18
+ opacity: 0,
19
+ top: top,
20
+ left: left,
21
+ scaleX: scaleX,
22
+ scaleY: scaleY,
23
+ };
24
+ if (props.typeAnim == 'letter') {
25
+ delay = i * duration - 100;
26
+ } else if (props.typeAnim == 'word') {
27
+ if (group.item(index).text == ' ') {
28
+ globaldelay += 500;
29
+ }
30
+ delay = globaldelay;
31
+ }
32
+ if (props.preset == 'typewriter') {
33
+ delay = i * duration;
34
+ duration = 20;
35
+ } else if (props.preset == 'fade in') {
36
+ } else if (props.preset == 'slide top') {
37
+ animation.top += 20;
38
+ } else if (props.preset == 'slide bottom') {
39
+ animation.top -= 20;
40
+ } else if (props.preset == 'slide left') {
41
+ animation.left += 20;
42
+ } else if (props.preset == 'slide right') {
43
+ animation.left -= 20;
44
+ } else if (props.preset == 'scale') {
45
+ animation.scaleX = 0;
46
+ animation.scaleY = 0;
47
+ } else if (props.preset == 'shrink') {
48
+ animation.scaleX = 1.5;
49
+ animation.scaleY = 1.5;
50
+ }
51
+ if (delay < 0) {
52
+ delay = 0;
53
+ }
54
+ if (duration < 20) {
55
+ duration = 20;
56
+ }
57
+ var start = false;
58
+ var instance = anime({
59
+ targets: animation,
60
+ delay: delay,
61
+ opacity: 1,
62
+ left: left,
63
+ top: top,
64
+ scaleX: scaleX,
65
+ scaleY: scaleY,
66
+ duration: duration,
67
+ easing: props.easing,
68
+ autoplay: play,
69
+ update: function () {
70
+ if (start && play) {
71
+ group.item(index).set({
72
+ opacity: animation.opacity,
73
+ left: animation.left,
74
+ top: animation.top,
75
+ scaleX: animation.scaleX,
76
+ scaleY: animation.scaleY,
77
+ });
78
+ cv.renderAll();
79
+ }
80
+ },
81
+ changeBegin: function () {
82
+ start = true;
83
+ },
84
+ });
85
+ instance.seek(ms);
86
+ if (!play) {
87
+ group.item(index).set({
88
+ opacity: animation.opacity,
89
+ left: animation.left,
90
+ top: animation.top,
91
+ scaleX: animation.scaleX,
92
+ scaleY: animation.scaleY,
93
+ });
94
+ cv.renderAll();
95
+ }
96
+ }
97
+ }
98
+
99
+ function setText(group, props, cv) {
100
+ var length = group._objects.length;
101
+ for (var i = 0; i < length; i++) {
102
+ group.item(i).set({
103
+ fill: props.fill,
104
+ fontFamily: props.fontFamily,
105
+ });
106
+ cv.renderAll();
107
+ }
108
+ }
109
+
110
+ function renderText(string, props, x, y, cv, id, isnew, start) {
111
+ var textOffset = 0;
112
+ var group = [];
113
+ function renderLetter(letter) {
114
+ var text = new fabric.Text(letter, {
115
+ left: textOffset,
116
+ top: 0,
117
+ fill: props.fill,
118
+ fontFamily: props.fontFamily,
119
+ opacity: 1,
120
+ });
121
+ text.set({
122
+ defaultLeft: text.left,
123
+ defaultTop: text.top,
124
+ defaultScaleX: 1,
125
+ defaultScaleY: 1,
126
+ });
127
+ textOffset += text.get('width');
128
+ return text;
129
+ }
130
+ for (var i = 0; i < string.length; i++) {
131
+ group.push(renderLetter(string.charAt(i)));
132
+ }
133
+ var result = new fabric.Group(group, {
134
+ cursorWidth: 1,
135
+ stroke: '#000',
136
+ strokeUniform: true,
137
+ paintFirst: 'stroke',
138
+ strokeWidth: 0,
139
+ originX: 'center',
140
+ originY: 'center',
141
+ left: x - artboard.left,
142
+ top: y - artboard.top,
143
+ cursorDuration: 1,
144
+ cursorDelay: 250,
145
+ assetType: 'animatedText',
146
+ id: id,
147
+ strokeDashArray: false,
148
+ inGroup: false,
149
+ });
150
+ if (isnew) {
151
+ result.set({
152
+ notnew: true,
153
+ starttime: start,
154
+ });
155
+ }
156
+ result.objectCaching = false;
157
+ cv.add(result);
158
+ cv.renderAll();
159
+ newLayer(result);
160
+ result._objects.forEach(function (object, index) {
161
+ result.item(index).set({
162
+ defaultLeft: result.item(index).defaultLeft - result.width / 2,
163
+ defaultTop: result.item(index).defaultTop - result.height / 2,
164
+ });
165
+ });
166
+ cv.setActiveObject(result);
167
+ cv.bringToFront(result);
168
+ return result.id;
169
+ }
170
+
171
+ class AnimatedText {
172
+ constructor(text, props) {
173
+ this.text = text;
174
+ this.props = props;
175
+ this.id = 'Text' + layer_count;
176
+ }
177
+ render(cv) {
178
+ this.id = renderText(
179
+ this.text,
180
+ this.props,
181
+ this.props.left,
182
+ this.props.top,
183
+ cv,
184
+ this.id,
185
+ false,
186
+ 0
187
+ );
188
+ animateText(
189
+ cv.getItemById(this.id),
190
+ currenttime,
191
+ false,
192
+ this.props,
193
+ cv,
194
+ this.id
195
+ );
196
+ }
197
+ seek(ms, cv) {
198
+ animateText(
199
+ cv.getItemById(this.id),
200
+ ms,
201
+ false,
202
+ this.props,
203
+ cv,
204
+ this.id
205
+ );
206
+ }
207
+ play(cv) {
208
+ animateText(
209
+ cv.getItemById(this.id),
210
+ 0,
211
+ true,
212
+ this.props,
213
+ cv,
214
+ this.id
215
+ );
216
+ }
217
+ getObject(cv) {
218
+ return cv.getItemById(this.id);
219
+ }
220
+ setProps(newprops, cv) {
221
+ this.props = $.extend(this.props, newprops);
222
+ setText(cv.getItemById(this.id), this.props, cv);
223
+ }
224
+ setProp(newprop) {
225
+ $.extend(this.props, newprop);
226
+ }
227
+ reset(text, newprops, cv) {
228
+ var obj = cv.getItemById(this.id);
229
+ var left = obj.left;
230
+ var top = obj.top;
231
+ var scaleX = obj,
232
+ scaleX;
233
+ var scaleY = obj.scaleY;
234
+ var angle = obj.angle;
235
+ var start = p_keyframes.find((x) => x.id == this.id).start;
236
+ deleteObject(obj, false);
237
+ this.text = text;
238
+ this.props = newprops;
239
+ this.inst = renderText(
240
+ text,
241
+ this.props,
242
+ left,
243
+ top,
244
+ cv,
245
+ this.id,
246
+ true,
247
+ start
248
+ );
249
+ cv.getItemById(this.id).set({
250
+ angle: angle,
251
+ scaleX: scaleX,
252
+ scaleY: scaleY,
253
+ });
254
+ cv.renderAll();
255
+ animateText(
256
+ cv.getItemById(this.id),
257
+ currenttime,
258
+ false,
259
+ this.props,
260
+ cv,
261
+ this.id
262
+ );
263
+ animate(currenttime, false);
264
+ save();
265
+ }
266
+ assignTo(id, text, props) {
267
+ this.id = id;
268
+ }
269
+ }
js/ui.js ADDED
@@ -0,0 +1,2369 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Update panel (when selecting / de-selecting objects)
2
+ function updatePanel(selection) {
3
+ if (!selection) {
4
+ $('#align').addClass('align-off');
5
+ $('#object-specific').html(canvas_panel);
6
+ $('#preset').append("<option value='custom'>Custom</option>");
7
+ presets.forEach(function (preset) {
8
+ $('#preset').append(
9
+ "<option value='" +
10
+ preset.id +
11
+ "'>" +
12
+ preset.name +
13
+ '</option>'
14
+ );
15
+ });
16
+ $('#preset').val(activepreset);
17
+ $('#canvas-duration input').val(duration / 1000);
18
+ $('#preset').niceSelect();
19
+ updatePanelValues();
20
+ colormode = 'back';
21
+ o_fill.setColor(canvas.backgroundColor);
22
+ } else if (
23
+ selection &&
24
+ canvas.getActiveObjects().length == 1 &&
25
+ canvas.getActiveObject().get('assetType') == 'audio'
26
+ ) {
27
+ $('#object-specific').html(audio_panel);
28
+ $('#object-volume input').val(
29
+ canvas.getActiveObject().get('volume') * 200
30
+ );
31
+ } else if (
32
+ selection &&
33
+ canvas.getActiveObjects().length == 1 &&
34
+ canvas.getActiveObject().get('type') != 'group'
35
+ ) {
36
+ if (!cropping) {
37
+ updateChromaUI();
38
+ checkFilter();
39
+ }
40
+ $('#align').removeClass('align-off');
41
+ $('#object-specific').html(object_panel);
42
+ if (
43
+ canvas.getActiveObject().get('type') == 'image' &&
44
+ !canvas.getActiveObject().get('assetType')
45
+ ) {
46
+ $('#object-specific').append(image_panel);
47
+ $('#object-specific').append(image_more_panel);
48
+ } else if (
49
+ canvas.getActiveObject().get('id').indexOf('Video') >= 0
50
+ ) {
51
+ $('#object-specific').append(image_panel);
52
+ $('#object-specific').append(video_more_panel);
53
+ } else {
54
+ $('#object-specific').append(back_panel);
55
+ }
56
+ objects.forEach(function (object) {
57
+ if (object.id != canvas.getActiveObject().get('id')) {
58
+ $('#masks').append(
59
+ "<option value='" +
60
+ object.id +
61
+ "'>" +
62
+ object.id +
63
+ '</option>'
64
+ );
65
+ }
66
+ });
67
+ $('#masks').niceSelect();
68
+ var selectme = document.getElementById('select-opacity');
69
+ o_slider = new RangeSlider(selectme, {
70
+ design: '2d',
71
+ theme: 'default',
72
+ handle: 'round',
73
+ popup: null,
74
+ showMinMaxLabels: false,
75
+ unit: '%',
76
+ min: 0,
77
+ max: 100,
78
+ value: 100,
79
+ onmove: function (x) {
80
+ document
81
+ .getElementById('object-o')
82
+ .getElementsByTagName('input')[0].value = x;
83
+ canvas.getActiveObject().set({
84
+ opacity: x / 100,
85
+ });
86
+ canvas.renderAll();
87
+ },
88
+ onfinish: function (x) {
89
+ document
90
+ .getElementById('object-o')
91
+ .getElementsByTagName('input')[0].value = x;
92
+ updateObjectValues('opacity');
93
+ },
94
+ onstart: function (x) {
95
+ document
96
+ .getElementById('object-o')
97
+ .getElementsByTagName('input')[0].value = x;
98
+ },
99
+ });
100
+ if (canvas.getActiveObject().get('type') == 'rect') {
101
+ $('#object-specific').append(shape_panel);
102
+ } else if (
103
+ canvas.getActiveObject().get('type') == 'path' ||
104
+ canvas.getActiveObject().get('type') == 'circle'
105
+ ) {
106
+ $('#object-specific').append(path_panel);
107
+ } else if (canvas.getActiveObject().get('type') == 'textbox') {
108
+ $('#object-specific').append(text_panel);
109
+ selectme = document.getElementById('select-letter');
110
+ o_letter_slider = new RangeSlider(selectme, {
111
+ design: '2d',
112
+ theme: 'default',
113
+ handle: 'round',
114
+ popup: null,
115
+ showMinMaxLabels: false,
116
+ unit: '%',
117
+ min: -200,
118
+ max: 200,
119
+ value: parseFloat(
120
+ (canvas.getActiveObject().get('charSpacing') / 10).toFixed(
121
+ 2
122
+ )
123
+ ),
124
+ onmove: function (x) {
125
+ document
126
+ .getElementById('text-h')
127
+ .getElementsByTagName('input')[0].value = x;
128
+ canvas.getActiveObject().set({ charSpacing: x * 10 });
129
+ canvas.renderAll();
130
+ updatePanelValues();
131
+ },
132
+ onfinish: function (x) {
133
+ document
134
+ .getElementById('text-h')
135
+ .getElementsByTagName('input')[0].value = x;
136
+ updateObjectValues('opacity3');
137
+ },
138
+ onstart: function (x) {
139
+ document
140
+ .getElementById('text-h')
141
+ .getElementsByTagName('input')[0].value = x;
142
+ },
143
+ });
144
+ selectme = document.getElementById('select-line');
145
+ o_line_slider = new RangeSlider(selectme, {
146
+ design: '2d',
147
+ theme: 'default',
148
+ handle: 'round',
149
+ popup: null,
150
+ showMinMaxLabels: false,
151
+ unit: '%',
152
+ min: 1,
153
+ max: 500,
154
+ value: parseFloat(
155
+ (canvas.getActiveObject().get('lineHeight') * 100).toFixed(
156
+ 2
157
+ )
158
+ ),
159
+ onmove: function (x) {
160
+ document
161
+ .getElementById('text-v')
162
+ .getElementsByTagName('input')[0].value = x;
163
+ canvas
164
+ .getActiveObject()
165
+ .set({ lineHeight: parseFloat(x / 100) });
166
+ canvas.renderAll();
167
+ },
168
+ onfinish: function (x) {
169
+ document
170
+ .getElementById('text-v')
171
+ .getElementsByTagName('input')[0].value = x;
172
+ updateObjectValues('opacity3');
173
+ },
174
+ onstart: function (x) {
175
+ document
176
+ .getElementById('text-v')
177
+ .getElementsByTagName('input')[0].value = x;
178
+ },
179
+ });
180
+ updateTextValues();
181
+ }
182
+ $('#object-specific').append(stroke_panel);
183
+ $('#object-specific').append(shadow_panel);
184
+ $('#line-cap').niceSelect();
185
+ updatePanelValues();
186
+ } else if (
187
+ canvas.getActiveObjects().length > 1 ||
188
+ canvas.getActiveObject().get('type') == 'group'
189
+ ) {
190
+ $('#align').removeClass('align-off');
191
+ $('#object-specific').html(object_panel);
192
+ if (canvas.getActiveObject().get('type') == 'group') {
193
+ if (
194
+ canvas.getActiveObject().get('assetType') == 'animatedText'
195
+ ) {
196
+ $('#object-specific').append(other_panel);
197
+ $('#object-specific').append(animated_text_panel);
198
+ $('#object-specific').append(start_animation_panel);
199
+ fonts.forEach(function (font) {
200
+ $('#font-picker').append(
201
+ "<option value='" + font + "'>" + font + '</option>'
202
+ );
203
+ });
204
+ $('#font-picker').val(
205
+ animatedtext.find(
206
+ (x) => x.id == canvas.getActiveObject().id
207
+ ).props.fontFamily
208
+ );
209
+ $('#font-picker').niceSelect();
210
+ $('#text-color input').val(
211
+ convertToHex(
212
+ animatedtext.find(
213
+ (x) => x.id == canvas.getActiveObject().id
214
+ ).props.fill
215
+ )
216
+ );
217
+ $('#color-text-side').css(
218
+ 'background-color',
219
+ animatedtext.find(
220
+ (x) => x.id == canvas.getActiveObject().id
221
+ ).props.fill
222
+ );
223
+ text_animation_list.forEach(function (preset) {
224
+ $('#preset-picker').append(
225
+ "<option value='" +
226
+ preset.name +
227
+ "'>" +
228
+ preset.label +
229
+ '</option>'
230
+ );
231
+ });
232
+ $('#preset-picker').val(
233
+ animatedtext.find(
234
+ (x) => x.id == canvas.getActiveObject().id
235
+ ).props.preset
236
+ );
237
+ $('#preset-picker').niceSelect();
238
+ $('.order-toggle-item-active').removeClass(
239
+ 'order-toggle-item-active'
240
+ );
241
+ $('.order-toggle-item-active-2').removeClass(
242
+ 'order-toggle-item-active-2'
243
+ );
244
+ if (
245
+ animatedtext.find(
246
+ (x) => x.id == canvas.getActiveObject().id
247
+ ).props.order == 'backward'
248
+ ) {
249
+ $('#order-backward').addClass('order-toggle-item-active');
250
+ } else {
251
+ $('#order-forward').addClass('order-toggle-item-active');
252
+ }
253
+ if (
254
+ animatedtext.find(
255
+ (x) => x.id == canvas.getActiveObject().id
256
+ ).props.typeAnim == 'letter'
257
+ ) {
258
+ $('#type-letters').addClass('order-toggle-item-active-2');
259
+ } else {
260
+ $('#type-words').addClass('order-toggle-item-active-2');
261
+ }
262
+ $('#easing-picker').val(
263
+ animatedtext.find(
264
+ (x) => x.id == canvas.getActiveObject().id
265
+ ).props.easing
266
+ );
267
+ $('#easing-picker').niceSelect();
268
+ $('#durationinput').val(
269
+ animatedtext.find(
270
+ (x) => x.id == canvas.getActiveObject().id
271
+ ).props.duration / 1000
272
+ );
273
+ $('#masks').niceSelect();
274
+ }
275
+ /*
276
+ if (canvas.getActiveObject().isGroup) {
277
+ $("#object-specific").append(group_panel);
278
+ } else {
279
+ $("#object-specific").append(other_panel);
280
+ }
281
+ objects.forEach(function(object){
282
+ if (object.id != canvas.getActiveObject().get("id")) {
283
+ $("#masks").append("<option value='"+object.id+"'>"+object.id+"</option>");
284
+ }
285
+ });
286
+ $("#masks").niceSelect();
287
+ */
288
+ } else {
289
+ $('#object-specific').append(selection_panel);
290
+ }
291
+ var selectme = document.getElementById('select-opacity');
292
+ o_slider = new RangeSlider(selectme, {
293
+ design: '2d',
294
+ theme: 'default',
295
+ handle: 'round',
296
+ popup: null,
297
+ showMinMaxLabels: false,
298
+ unit: '%',
299
+ min: 0,
300
+ max: 100,
301
+ value: 100,
302
+ onmove: function (x) {
303
+ document
304
+ .getElementById('object-o')
305
+ .getElementsByTagName('input')[0].value = x;
306
+ canvas.getActiveObject().set({ opacity: x / 100 });
307
+ canvas.renderAll();
308
+ },
309
+ onfinish: function (x) {
310
+ document
311
+ .getElementById('object-o')
312
+ .getElementsByTagName('input')[0].value = x;
313
+ updateObjectValues('opacity');
314
+ },
315
+ onstart: function (x) {
316
+ document
317
+ .getElementById('object-o')
318
+ .getElementsByTagName('input')[0].value = x;
319
+ },
320
+ });
321
+ updatePanelValues();
322
+ }
323
+ }
324
+
325
+ function convertToHex(nonHexColorString) {
326
+ var ctx = document.createElement('canvas').getContext('2d');
327
+ ctx.fillStyle = nonHexColorString;
328
+ return ctx.fillStyle.toUpperCase();
329
+ }
330
+
331
+ function updateStrokeValues() {
332
+ const object = canvas.getActiveObject();
333
+ $('.line-join-active').removeClass('line-join-active');
334
+ if (
335
+ object.get('strokeDashArray') == false &&
336
+ object.get('strokeWidth') == 0
337
+ ) {
338
+ $('#miter').addClass('line-join-active');
339
+ $('#miter img').attr('src', 'assets/miter-active.svg');
340
+ } else if (object.get('strokeDashArray') == false) {
341
+ $('#bevel').addClass('line-join-active');
342
+ $('#bevel img').attr('src', 'assets/bevel-active.svg');
343
+ } else if (object.get('strokeDashArray') == [10, 5]) {
344
+ $('#round').addClass('line-join-active');
345
+ $('#round img').attr('src', 'assets/round-active.svg');
346
+ } else {
347
+ $('#small-dash').addClass('line-join-active');
348
+ $('#small-dash img').attr('src', 'assets/dash2-active.svg');
349
+ }
350
+ }
351
+
352
+ function toggleAnimationOrder() {
353
+ var object = canvas.getActiveObject();
354
+ $('.order-toggle-item-active').removeClass(
355
+ 'order-toggle-item-active'
356
+ );
357
+ if ($(this).attr('id') == 'order-backward') {
358
+ animatedtext
359
+ .find((x) => x.id == object.id)
360
+ .setProp({ order: 'backward' }, canvas);
361
+ } else if ($(this).attr('id') == 'order-forward') {
362
+ animatedtext
363
+ .find((x) => x.id == object.id)
364
+ .setProp({ order: 'forward' }, canvas);
365
+ }
366
+ $(this).addClass('order-toggle-item-active');
367
+ animate(currenttime, false);
368
+ save();
369
+ }
370
+ function toggleAnimationType() {
371
+ var object = canvas.getActiveObject();
372
+ $('.order-toggle-item-active-2').removeClass(
373
+ 'order-toggle-item-active-2'
374
+ );
375
+ if ($(this).attr('id') == 'type-words') {
376
+ animatedtext
377
+ .find((x) => x.id == object.id)
378
+ .setProp({ typeAnim: 'word' }, canvas);
379
+ } else if ($(this).attr('id') == 'type-letters') {
380
+ animatedtext
381
+ .find((x) => x.id == object.id)
382
+ .setProp({ typeAnim: 'letter' }, canvas);
383
+ }
384
+ $(this).addClass('order-toggle-item-active-2');
385
+ animate(currenttime, false);
386
+ save();
387
+ }
388
+ $(document).on(
389
+ 'click',
390
+ '.order-toggle-item:not(.order-toggle-item-active)',
391
+ toggleAnimationOrder
392
+ );
393
+ $(document).on(
394
+ 'click',
395
+ '.order-toggle-item-2:not(.order-toggle-item-active-2)',
396
+ toggleAnimationType
397
+ );
398
+
399
+ function updateTextValues() {
400
+ const object = canvas.getActiveObject();
401
+ fonts.forEach(function (font) {
402
+ $('#font-picker').append(
403
+ "<option value='" + font + "'>" + font + '</option>'
404
+ );
405
+ });
406
+ $('#font-picker').val(object.get('fontFamily'));
407
+ $('#font-picker').niceSelect();
408
+ $('#text-h input').val(
409
+ parseFloat((object.get('charSpacing') / 10).toFixed(2))
410
+ );
411
+ $('#text-v input').val(
412
+ parseFloat((object.get('lineHeight') * 100).toFixed(2))
413
+ );
414
+ if (object.get('textAlign') == 'left') {
415
+ $('#align-text-left').addClass('align-text-active');
416
+ $('#align-text-left img').attr(
417
+ 'src',
418
+ 'assets/align-text-left-active.svg'
419
+ );
420
+ } else if (object.get('textAlign') == 'center') {
421
+ $('#align-text-center').addClass('align-text-active');
422
+ $('#align-text-center img').attr(
423
+ 'src',
424
+ 'assets/align-text-center-active.svg'
425
+ );
426
+ } else if (object.get('textAlign') == 'right') {
427
+ $('#align-text-right').addClass('align-text-right-active');
428
+ $('#align-text-right img').attr(
429
+ 'src',
430
+ 'assets/align-text-right-active.svg'
431
+ );
432
+ } else {
433
+ $('#align-text-justify').addClass('align-text-justify-active');
434
+ $('#align-text-justify img').attr(
435
+ 'src',
436
+ 'assets/align-text-justify-active.svg'
437
+ );
438
+ }
439
+ if (
440
+ object.get('fontWeight') == 'bold' ||
441
+ object.get('fontWeight') == 700
442
+ ) {
443
+ $('#format-bold').addClass('format-text-active');
444
+ $('#format-bold img').attr('src', 'assets/bold-active.svg');
445
+ }
446
+ if (object.get('fontStyle') == 'italic') {
447
+ $('#format-italic').addClass('format-text-active');
448
+ $('#format-italic img').attr('src', 'assets/italic-active.svg');
449
+ }
450
+ if (object.get('underline') == true) {
451
+ $('#format-underline').addClass('format-text-active');
452
+ $('#format-underline img').attr(
453
+ 'src',
454
+ 'assets/underline-active.svg'
455
+ );
456
+ }
457
+ if (object.get('linethrough') == true) {
458
+ $('#format-strike').addClass('format-text-active');
459
+ $('#format-strike img').attr('src', 'assets/strike-active.svg');
460
+ }
461
+ }
462
+
463
+ // Update panel inputs based on object values
464
+ function updatePanelValues() {
465
+ if (canvas.getActiveObject()) {
466
+ if (canvas.getActiveObject().get('assetType') == 'audio') {
467
+ $('#object-volume input').val(
468
+ canvas.getActiveObject().get('volume') * 200
469
+ );
470
+ return false;
471
+ }
472
+ setting = true;
473
+ var tempstore = false;
474
+ var object = canvas.getActiveObject();
475
+ if (
476
+ canvas.getActiveObjects.length > 1 ||
477
+ object.get('type') == 'activeSelection'
478
+ ) {
479
+ object = object.toGroup();
480
+ object.set({
481
+ shadow: {
482
+ blur: 0,
483
+ color: 'black',
484
+ offsetX: 0,
485
+ offsetY: 0,
486
+ opacity: 0,
487
+ },
488
+ });
489
+ tempstore = true;
490
+ }
491
+ if (object.get('assetType') == 'animatedText') {
492
+ $('#animated-text input').val(
493
+ animatedtext.find((x) => x.id == object.id).text
494
+ );
495
+ }
496
+ if (objects.find((x) => x.id == object.get('id'))) {
497
+ if (
498
+ $(
499
+ "#masks option[value='" +
500
+ objects.find((x) => x.id == object.get('id')).mask +
501
+ "']"
502
+ ).length == 0
503
+ ) {
504
+ $('#masks').val('none');
505
+ objects.find((x) => x.id == object.get('id')).mask = 'none';
506
+ object.clipPath = null;
507
+ canvas.renderAll();
508
+ } else {
509
+ $('#masks').val(
510
+ objects.find((x) => x.id == object.get('id')).mask
511
+ );
512
+ }
513
+ $('#masks').niceSelect('update');
514
+ }
515
+ updateStrokeValues();
516
+ $('#object-x input').val(
517
+ parseFloat(
518
+ (
519
+ object.get('left') -
520
+ artboard.get('left') -
521
+ (object.get('width') * object.get('scaleX')) / 2
522
+ ).toFixed(2)
523
+ )
524
+ );
525
+ $('#object-y input').val(
526
+ parseFloat(
527
+ (
528
+ object.get('top') -
529
+ artboard.get('top') -
530
+ (object.get('height') * object.get('scaleY')) / 2
531
+ ).toFixed(2)
532
+ )
533
+ );
534
+ $('#object-w input').val(
535
+ parseFloat(
536
+ (object.get('width') * object.get('scaleX')).toFixed(2)
537
+ )
538
+ );
539
+ $('#object-h input').val(
540
+ parseFloat(
541
+ (object.get('height') * object.get('scaleY')).toFixed(2)
542
+ )
543
+ );
544
+ $('#object-r input').val(
545
+ parseFloat(object.get('angle').toFixed(2))
546
+ );
547
+ $('#object-stroke input').val(
548
+ parseFloat(object.get('strokeWidth').toFixed(2))
549
+ );
550
+ if (object.get('type') != 'group') {
551
+ $('#object-shadow-x input').val(
552
+ parseFloat(object.shadow.offsetX.toFixed(2))
553
+ );
554
+ $('#object-shadow-y input').val(
555
+ parseFloat(object.shadow.offsetY.toFixed(2))
556
+ );
557
+ $('#object-blur input').val(
558
+ parseFloat(object.shadow.blur.toFixed(2))
559
+ );
560
+ colormode = 'stroke';
561
+ o_fill.setColor(object.get('stroke'));
562
+ colormode = 'shadow';
563
+ o_fill.setColor(object.shadow.color);
564
+ }
565
+ o_slider.setValue(object.get('opacity') * 100);
566
+ if (object.get('type') == 'rect') {
567
+ $('#object-corners input').val(
568
+ parseFloat(object.get('rx').toFixed(2))
569
+ );
570
+ colormode = 'fill';
571
+ o_fill.setColor(object.get('fill'));
572
+ } else if (
573
+ object.get('type') == 'path' ||
574
+ object.get('type') == 'circle' ||
575
+ object.get('type') == 'textbox'
576
+ ) {
577
+ colormode = 'fill';
578
+ o_fill.setColor(object.get('fill'));
579
+ }
580
+ if (tempstore) {
581
+ object.toActiveSelection();
582
+ canvas.renderAll();
583
+ }
584
+ setting = false;
585
+ } else {
586
+ $('#canvas-w input').val(artboard.get('width'));
587
+ $('#canvas-h input').val(artboard.get('height'));
588
+ }
589
+ }
590
+
591
+ // Update opacity input
592
+ function updateInputs(id) {
593
+ if (canvas.getActiveObject().get('assetType') == 'audio') {
594
+ return false;
595
+ }
596
+ if ($('#object-o input').val() > 100) {
597
+ $('#object-o input').val(100);
598
+ } else if ($('#object-o input').val() < 0) {
599
+ $('#object-o input').val(0);
600
+ }
601
+ o_slider.setValue($('#object-o input').val());
602
+ if (
603
+ !isNaN(parseFloat($('#object-color-fill-opacity input').val())) &&
604
+ id == 'object-color-fill-opacity'
605
+ ) {
606
+ if ($('#object-color-fill-opacity input').val() > 100) {
607
+ $('#object-color-fill-opacity').val(100);
608
+ } else if ($('#object-color-fill-opacity input').val() < 0) {
609
+ $('#object-color-fill-opacity input').val(0);
610
+ }
611
+ colormode = 'fill';
612
+ o_fill.setColor(
613
+ 'rgba(' +
614
+ o_fill.getColor().toRGBA()[0] +
615
+ ',' +
616
+ o_fill.getColor().toRGBA()[1] +
617
+ ',' +
618
+ o_fill.getColor().toRGBA()[2] +
619
+ ',' +
620
+ $('#object-color-fill-opacity input').val() / 100 +
621
+ ')'
622
+ );
623
+ }
624
+ if (
625
+ !isNaN(
626
+ parseFloat($('#object-color-stroke-opacity input').val())
627
+ ) &&
628
+ id == 'object-color-stroke-opacity'
629
+ ) {
630
+ if ($('#object-color-stroke-opacity input').val() > 100) {
631
+ $('#object-color-stroke-opacity').val(100);
632
+ } else if ($('#object-color-stroke-opacity input').val() < 0) {
633
+ $('#object-color-stroke-opacity input').val(0);
634
+ }
635
+ colormode = 'stroke';
636
+ o_fill.setColor(
637
+ 'rgba(' +
638
+ o_fill.getColor().toRGBA()[0] +
639
+ ',' +
640
+ o_fill.getColor().toRGBA()[1] +
641
+ ',' +
642
+ o_fill.getColor().toRGBA()[2] +
643
+ ',' +
644
+ $('#object-color-stroke-opacity input').val() / 100 +
645
+ ')'
646
+ );
647
+ }
648
+ if (
649
+ !isNaN(
650
+ parseFloat($('#object-color-shadow-opacity input').val())
651
+ ) &&
652
+ id == 'object-color-shadow-opacity'
653
+ ) {
654
+ if ($('#object-color-shadow-opacity input').val() > 100) {
655
+ $('#object-color-shadow-opacity').val(100);
656
+ } else if ($('#object-color-shadow-opacity input').val() < 0) {
657
+ $('#object-color-shadow-opacity input').val(0);
658
+ }
659
+ colormode = 'shadow';
660
+ o_fill.setColor(
661
+ 'rgba(' +
662
+ o_fill.getColor().toRGBA()[0] +
663
+ ',' +
664
+ o_fill.getColor().toRGBA()[1] +
665
+ ',' +
666
+ o_fill.getColor().toRGBA()[2] +
667
+ ',' +
668
+ $('#object-color-shadow-opacity input').val() / 100 +
669
+ ')'
670
+ );
671
+ }
672
+ }
673
+
674
+ // Update object position based on panel input values
675
+ function updateObjectValues(type) {
676
+ autoSave();
677
+ if (canvas.getActiveObjects().length > 0) {
678
+ if ($(this).find('input').val() || type) {
679
+ var object = canvas.getActiveObject();
680
+ if ($(this).attr('id') == 'animated-text') {
681
+ return false;
682
+ }
683
+ if ($(this).attr('id') == 'animated-text-duration') {
684
+ var obj = p_keyframes.find((x) => x.id == object.id);
685
+ var length = obj.end - obj.start;
686
+ if ($(this).find('input').val() * 1000 > length) {
687
+ $(this)
688
+ .find('input')
689
+ .val(length / 1000);
690
+ }
691
+ animatedtext
692
+ .find((x) => x.id == object.id)
693
+ .setProp(
694
+ { duration: $(this).find('input').val() * 1000 },
695
+ canvas
696
+ );
697
+ save();
698
+ return false;
699
+ }
700
+ if ($(this).attr('id') == 'object-volume') {
701
+ newKeyframe(
702
+ 'volume',
703
+ canvas.getActiveObject(),
704
+ currenttime,
705
+ parseFloat($(this).find('input').val()) / 200,
706
+ true
707
+ );
708
+ canvas
709
+ .getActiveObject()
710
+ .set(
711
+ 'volume',
712
+ parseFloat($(this).find('input').val()) / 200
713
+ );
714
+ }
715
+ editingpanel = true;
716
+ var selection = false;
717
+ const tempselection = canvas.getActiveObjects();
718
+ const id = $(this).attr('id');
719
+ updateInputs(id);
720
+ if (tempselection.length > 1) {
721
+ object = object.toGroup();
722
+ selection = true;
723
+ }
724
+ if (objects.find((x) => x.id == object.get('id'))) {
725
+ objects.find((x) => x.id == object.get('id')).mask =
726
+ $('#masks').val();
727
+ if ($('#masks').val() == 'none') {
728
+ object.clipPath = null;
729
+ canvas.renderAll();
730
+ } else {
731
+ object.clipPath = canvas.getItemById($('#masks').val());
732
+ canvas.renderAll();
733
+ }
734
+ }
735
+ object.set({
736
+ left:
737
+ parseFloat($('#object-x input').val()) +
738
+ artboard.get('left') +
739
+ (object.get('width') * object.get('scaleX')) / 2,
740
+ top:
741
+ parseFloat($('#object-y input').val()) +
742
+ artboard.get('top') +
743
+ (object.get('height') * object.get('scaleY')) / 2,
744
+ scaleX: parseFloat(
745
+ $('#object-w input').val() / object.get('width')
746
+ ),
747
+ scaleY: parseFloat(
748
+ $('#object-h input').val() / object.get('height')
749
+ ),
750
+ angle: parseFloat($('#object-r input').val()),
751
+ opacity: parseFloat($('#object-o input').val() / 100),
752
+ strokeWidth: parseFloat($('#object-stroke input').val()),
753
+ });
754
+ if (object.get('type') != 'group') {
755
+ object.set({
756
+ shadow: {
757
+ color: object.shadow.color,
758
+ offsetX: parseFloat($('#object-shadow-x input').val()),
759
+ offsetY: parseFloat($('#object-shadow-y input').val()),
760
+ opacity: 1,
761
+ blur: parseFloat($('#object-blur input').val()),
762
+ },
763
+ });
764
+ }
765
+ canvas.renderAll();
766
+ if (tempselection.length > 1) {
767
+ object.toActiveSelection();
768
+ object = canvas.getActiveObject();
769
+ }
770
+ canvas.discardActiveObject();
771
+ tempselection.forEach(function (obj) {
772
+ keyframeChanges(obj, type, id, selection);
773
+ });
774
+ if (object) {
775
+ reselect(object);
776
+ editingpanel = false;
777
+ }
778
+ $('#' + id + ' input').focus();
779
+ save();
780
+ if (type) {
781
+ updatePanelValues();
782
+ } else if ($(this).find('input').val().length > 0) {
783
+ updatePanelValues();
784
+ }
785
+ }
786
+ } else {
787
+ if (
788
+ $(this).attr('id') == 'canvas-w' ||
789
+ $(this).attr('id') == 'canvas-h'
790
+ ) {
791
+ artboard.set({
792
+ width: parseFloat($('#canvas-w input').val()),
793
+ height: parseFloat($('#canvas-h input').val()),
794
+ });
795
+ canvas.renderAll();
796
+ resizeCanvas();
797
+ if (activepreset != 'custom') {
798
+ if (
799
+ presets.find((x) => x.id == activepreset).width !=
800
+ $('#canvas-w input').val() ||
801
+ presets.find((x) => x.id == activepreset).height !=
802
+ $('#canvas-h input').val()
803
+ ) {
804
+ activepreset = 'custom';
805
+ updatePanel();
806
+ }
807
+ }
808
+ } else if ($(this).attr('id') == 'canvas-duration') {
809
+ if (!isNaN(parseFloat($(this).find('input').val()))) {
810
+ setDuration(parseFloat($(this).find('input').val()) * 1000);
811
+ }
812
+ }
813
+ if (!isNaN(parseFloat($('#canvas-color-opacity input').val()))) {
814
+ if ($('#canvas-color-opacity input').val() > 100) {
815
+ $('#canvas-color-opacity input').val(100);
816
+ } else if ($('#canvas-color-opacity input').val() < 0) {
817
+ $('#canvas-color-opacity input').val(0);
818
+ }
819
+ colormode = 'back';
820
+ o_fill.setColor(
821
+ 'rgba(' +
822
+ o_fill.getColor().toRGBA()[0] +
823
+ ',' +
824
+ o_fill.getColor().toRGBA()[1] +
825
+ ',' +
826
+ o_fill.getColor().toRGBA()[2] +
827
+ ',' +
828
+ $('#canvas-color-opacity input').val() / 100 +
829
+ ')'
830
+ );
831
+ }
832
+ }
833
+ }
834
+ function setTextAnimation() {
835
+ var object = canvas.getActiveObject();
836
+ animatedtext
837
+ .find((x) => x.id == object.id)
838
+ .reset(
839
+ $(this).parent().find('input').val(),
840
+ animatedtext.find((x) => x.id == object.id).props,
841
+ canvas
842
+ );
843
+ }
844
+
845
+ $(document).on('input', '.property-input', updateObjectValues);
846
+ $(document).on('change', '.property-input', updateObjectValues);
847
+ $(document).on('change', '#masks', updateObjectValues);
848
+ $(document).on('click', '#animatedset', setTextAnimation);
849
+
850
+ // Toggle picker (maybe it could be condensed?)
851
+ function togglePicker() {
852
+ const object = canvas.getActiveObject();
853
+ if (!o_fill.isOpen()) {
854
+ newcolorkeyframe = true;
855
+ if ($(this).attr('id') == 'object-color-fill') {
856
+ colormode = 'fill';
857
+ o_fill.setColor(object.get('fill'));
858
+ } else if ($(this).attr('id') == 'object-color-stroke') {
859
+ colormode = 'stroke';
860
+ o_fill.setColor(object.get('stroke'));
861
+ } else if ($(this).attr('id') == 'canvas-color') {
862
+ colormode = 'back';
863
+ o_fill.setColor(canvas.backgroundColor);
864
+ } else if ($(this).attr('id') == 'chroma-color') {
865
+ colormode = 'chroma';
866
+ if (object.filters.find((x) => x.type == 'RemoveColor')) {
867
+ o_fill.setColor(
868
+ object.filters.find((x) => x.type == 'RemoveColor').color
869
+ );
870
+ } else {
871
+ o_fill.setColor('#FFF');
872
+ }
873
+ } else if ($(this).attr('id') == 'text-color') {
874
+ colormode = 'text';
875
+ o_fill.setColor(
876
+ animatedtext.find((x) => x.id == object.id).props.fill
877
+ );
878
+ } else {
879
+ colormode = 'shadow';
880
+ o_fill.setColor(object.shadow.color);
881
+ }
882
+ newcolorkeyframe = false;
883
+ o_fill.show();
884
+ } else {
885
+ o_fill.hide();
886
+ }
887
+ }
888
+ $(document).on('click', '#canvas-color', togglePicker);
889
+ $(document).on('click', '#object-color-fill', togglePicker);
890
+ $(document).on('click', '#object-color-stroke', togglePicker);
891
+ $(document).on('click', '#object-color-shadow', togglePicker);
892
+ $(document).on('click', '#chroma-color', togglePicker);
893
+ $(document).on('click', '#text-color', togglePicker);
894
+
895
+ window.onLoadImage = function (temp) {
896
+ $(temp).css('background-image', 'none');
897
+ };
898
+
899
+ // Populate shape grid on left panel
900
+ function populateGrid(type) {
901
+ if (type == 'shape-tool') {
902
+ $('#shapes-row').html('');
903
+ $('#emojis-row').html('');
904
+ shape_grid_items.forEach(function (item) {
905
+ $('#shapes-row').append(
906
+ "<div class='grid-item'><img onload='onLoadImage(this)' draggable=false src='" +
907
+ item +
908
+ "'></div>"
909
+ );
910
+ });
911
+ emoji_items.forEach(function (item) {
912
+ $('#emojis-row').append(
913
+ "<div class='grid-emoji-item'><img onload='onLoadImage(this)' draggable=false src='" +
914
+ item +
915
+ "'></div>"
916
+ );
917
+ });
918
+ } else if (type == 'image-tool') {
919
+ $('#images-grid').html('');
920
+ image_categories.forEach(function (category) {
921
+ $('#categories').append(
922
+ "<div class='category' data-name='" +
923
+ category.name +
924
+ "'><img onload='onLoadImage(this)' src='" +
925
+ category.image +
926
+ "'>" +
927
+ category.name +
928
+ '</div>'
929
+ );
930
+ });
931
+ } else if (type == 'video-tool') {
932
+ $('#images-grid').html('');
933
+ video_categories.forEach(function (category) {
934
+ $('#categories').append(
935
+ "<div class='category' data-name='" +
936
+ category.name +
937
+ "'><img onload='onLoadImage(this)' src='" +
938
+ category.image +
939
+ "'>" +
940
+ category.name +
941
+ '</div>'
942
+ );
943
+ });
944
+ } else if (type == 'images-tab') {
945
+ $('#images-grid').html('');
946
+ var flag = false;
947
+ uploaded_images
948
+ .slice()
949
+ .reverse()
950
+ .forEach(function (item) {
951
+ if (!item.hidden) {
952
+ flag = true;
953
+ $('#images-grid').append(
954
+ "<div class='image-grid-item' data-src='" +
955
+ item.src +
956
+ "' data-type='" +
957
+ item.type +
958
+ "' data-key='" +
959
+ item.key +
960
+ "'><img class='delete-media' draggable=false src='assets/more-options.svg'><img draggable=false onload='onLoadImage(this)' class='image-thing' src='" +
961
+ item.thumb +
962
+ "'</div>"
963
+ );
964
+ }
965
+ });
966
+ $('#landing').remove();
967
+ if (!flag) {
968
+ $('#upload-tabs').after(
969
+ '<div id="landing" class="upload-landing"><div id="landing-text">Your uploaded images will show up here for easy access.</div></div>'
970
+ );
971
+ }
972
+ } else if (type == 'videos-tab') {
973
+ $('#images-grid').html('');
974
+ var flag = false;
975
+ uploaded_videos
976
+ .slice()
977
+ .reverse()
978
+ .forEach(function (item) {
979
+ if (!item.hidden) {
980
+ flag = true;
981
+ $('#images-grid').append(
982
+ "<div class='video-grid-item' data-src='" +
983
+ item.src +
984
+ "' data-type='" +
985
+ item.type +
986
+ "' data-key='" +
987
+ item.key +
988
+ "'><img class='delete-media' draggable=false src='assets/more-options.svg'><img draggable=false onload='onLoadImage(this)' class='image-thing' src='" +
989
+ item.thumb +
990
+ "'></div>"
991
+ );
992
+ }
993
+ });
994
+ $('#landing').remove();
995
+ if (!flag) {
996
+ $('#upload-tabs').after(
997
+ '<div id="landing" class="upload-landing"><div id="landing-text">Your uploaded videos will show up here for easy access.</div></div>'
998
+ );
999
+ }
1000
+ } else if (type == 'audio-tool') {
1001
+ var flag = false;
1002
+ audio_items.forEach(function (item) {
1003
+ if (item.src == background_key) {
1004
+ flag = true;
1005
+ $('#audio-list').append(
1006
+ "<div class='audio-item audio-item-active' data-src='" +
1007
+ item.src +
1008
+ "'><div class='audio-preview'><img src='assets/play-button.svg'></div><img class='audio-thumb' src='" +
1009
+ item.thumb +
1010
+ "'><div class='audio-info'><div class='audio-info-title'>" +
1011
+ item.name +
1012
+ "</div><a href='" +
1013
+ item.link +
1014
+ "' target='_blank' class='audio-info-desc'>" +
1015
+ item.desc +
1016
+ "</a><div class='audio-info-duration'>" +
1017
+ item.duration +
1018
+ '</div></div></div></div>'
1019
+ );
1020
+ } else {
1021
+ $('#audio-list').append(
1022
+ "<div class='audio-item' data-src='" +
1023
+ item.src +
1024
+ "'><div class='audio-preview'><img src='assets/play-button.svg'></div><img class='audio-thumb' src='" +
1025
+ item.thumb +
1026
+ "'><div class='audio-info'><div class='audio-info-title'>" +
1027
+ item.name +
1028
+ "</div><a href='" +
1029
+ item.link +
1030
+ "' target='_blank' class='audio-info-desc'>" +
1031
+ item.desc +
1032
+ "</a><div class='audio-info-duration'>" +
1033
+ item.duration +
1034
+ '</div></div></div></div>'
1035
+ );
1036
+ }
1037
+ });
1038
+ } else if (type == 'text-tool') {
1039
+ $('#shapes-cont').append("<p class='row-title'>Animated</p>");
1040
+ $('#shapes-cont').append(
1041
+ "<div class='animated-text-grid'></div>"
1042
+ );
1043
+ text_animation_list.forEach(function (text) {
1044
+ $('.animated-text-grid').append(
1045
+ "<div class='animated-text-item noselect' data-id='" +
1046
+ text.name +
1047
+ "'><img draggable='false' class='noselect' src='" +
1048
+ text.src +
1049
+ "'></div>"
1050
+ );
1051
+ });
1052
+ $('#shapes-cont').append("<p class='row-title'>Sans Serif</p>");
1053
+ text_items.sansserif.forEach(function (text) {
1054
+ WebFont.load({
1055
+ google: {
1056
+ families: [text.fontname],
1057
+ },
1058
+ });
1059
+ $('#shapes-cont').append(
1060
+ "<div id='item-text' class='add-text noselect' data-font='" +
1061
+ text.fontname +
1062
+ "' style='font-family: " +
1063
+ text.fontname +
1064
+ ", sans-serif'>" +
1065
+ text.name +
1066
+ '</div>'
1067
+ );
1068
+ });
1069
+ $('#shapes-cont').append("<p class='row-title'>Serif</p>");
1070
+ text_items.serif.forEach(function (text) {
1071
+ WebFont.load({
1072
+ google: {
1073
+ families: [text.fontname],
1074
+ },
1075
+ });
1076
+ $('#shapes-cont').append(
1077
+ "<div id='item-text' class='add-text noselect' data-font='" +
1078
+ text.fontname +
1079
+ "' style='font-family: " +
1080
+ text.fontname +
1081
+ "'>" +
1082
+ text.name +
1083
+ '</div>'
1084
+ );
1085
+ });
1086
+ $('#shapes-cont').append("<p class='row-title'>Monospace</p>");
1087
+ text_items.monospace.forEach(function (text) {
1088
+ WebFont.load({
1089
+ google: {
1090
+ families: [text.fontname],
1091
+ },
1092
+ });
1093
+ $('#shapes-cont').append(
1094
+ "<div id='item-text' class='add-text noselect' data-font='" +
1095
+ text.fontname +
1096
+ "' style='font-family: " +
1097
+ text.fontname +
1098
+ "'>" +
1099
+ text.name +
1100
+ '</div>'
1101
+ );
1102
+ });
1103
+ $('#shapes-cont').append("<p class='row-title'>Handwriting</p>");
1104
+ text_items.handwriting.forEach(function (text) {
1105
+ WebFont.load({
1106
+ google: {
1107
+ families: [text.fontname],
1108
+ },
1109
+ });
1110
+ $('#shapes-cont').append(
1111
+ "<div id='item-text' class='add-text noselect' data-font='" +
1112
+ text.fontname +
1113
+ "' style='font-family: " +
1114
+ text.fontname +
1115
+ "'>" +
1116
+ text.name +
1117
+ '</div>'
1118
+ );
1119
+ });
1120
+ $('#shapes-cont').append("<p class='row-title'>Display</p>");
1121
+ text_items.display.forEach(function (text) {
1122
+ WebFont.load({
1123
+ google: {
1124
+ families: [text.fontname],
1125
+ },
1126
+ });
1127
+ $('#shapes-cont').append(
1128
+ "<div id='item-text' class='add-text noselect' data-font='" +
1129
+ text.fontname +
1130
+ "' style='font-family: " +
1131
+ text.fontname +
1132
+ "'>" +
1133
+ text.name +
1134
+ '</div>'
1135
+ );
1136
+ });
1137
+ }
1138
+ }
1139
+
1140
+ function scrollBottom() {
1141
+ if (
1142
+ $(this).scrollTop() + $(this).innerHeight() >=
1143
+ $(this)[0].scrollHeight - 50
1144
+ ) {
1145
+ loadMoreMedia();
1146
+ }
1147
+ if ($(this).scrollTop() > 0) {
1148
+ $('#search-fixed').addClass('search-scrolling');
1149
+ } else {
1150
+ $('.search-scrolling').removeClass('search-scrolling');
1151
+ }
1152
+ }
1153
+
1154
+ function addAnimatedText() {
1155
+ var newtext = new AnimatedText('Your text', {
1156
+ left: artboard.get('left') + artboard.get('width') / 2,
1157
+ top: artboard.get('top') + artboard.get('height') / 2,
1158
+ preset: $(this).attr('data-id'),
1159
+ typeAnim: 'letter',
1160
+ order: 'forward',
1161
+ fontFamily: 'Syne',
1162
+ duration: 1000,
1163
+ easing: 'easeInQuad',
1164
+ fill: '#FFFFFF',
1165
+ });
1166
+ animatedtext.push(newtext);
1167
+ newtext.render(canvas);
1168
+ }
1169
+
1170
+ $(document).on('click', '.animated-text-item', addAnimatedText);
1171
+
1172
+ // Switch active panel in the library
1173
+ function updateBrowser(type) {
1174
+ $('#browser').scrollTop(0);
1175
+ if (type == 'image-tool') {
1176
+ $('#browser-container').html(image_browser);
1177
+ populateGrid(type);
1178
+ $('#browser').on('scroll', scrollBottom);
1179
+ } else if (type == 'shape-tool') {
1180
+ $('#browser-container').html(shape_browser);
1181
+ populateGrid(type);
1182
+ $('#browser').on('scroll', scrollBottom);
1183
+ } else if (type == 'video-tool') {
1184
+ $('#browser-container').html(video_browser);
1185
+ populateGrid(type);
1186
+ $('#browser').on('scroll', scrollBottom);
1187
+ } else if (type == 'text-tool') {
1188
+ $('#browser-container').html(text_browser);
1189
+ populateGrid(type);
1190
+ $('#browser').on('scroll', scrollBottom);
1191
+ } else if (type == 'upload-tool') {
1192
+ $('#browser-container').html(upload_browser);
1193
+ populateGrid('images-tab');
1194
+ $('#browser').on('scroll', scrollBottom);
1195
+ } else if (type == 'audio-tool') {
1196
+ $('#browser-container').html(audio_browser);
1197
+ populateGrid(type);
1198
+ $('#browser').on('scroll', scrollBottom);
1199
+ }
1200
+ }
1201
+
1202
+ // Switch tab in the uploads depending on item being uploaded
1203
+ function updateUploadType() {
1204
+ $('.upload-tab-active').removeClass('upload-tab-active');
1205
+ $(this).addClass('upload-tab-active');
1206
+ populateGrid($(this).attr('id'));
1207
+ }
1208
+ $(document).on(
1209
+ 'click',
1210
+ '.upload-tab:not(.upload-tab-active)',
1211
+ updateUploadType
1212
+ );
1213
+
1214
+ // Switch tool
1215
+ function switchTool(e) {
1216
+ $('#browser').removeClass('collapsed');
1217
+ $('#canvas-area').removeClass('canvas-full');
1218
+ if ($(this).attr('id') == 'more-tool') {
1219
+ showMore();
1220
+ return false;
1221
+ }
1222
+ resizeCanvas();
1223
+ var act = $('.tool-active');
1224
+ if (act.attr('id') == 'image-tool') {
1225
+ act.find('img').attr('src', 'assets/image.svg');
1226
+ } else if (act.attr('id') == 'text-tool') {
1227
+ act.find('img').attr('src', 'assets/text.svg');
1228
+ } else if (act.attr('id') == 'mockup-tool') {
1229
+ act.find('img').attr('src', 'assets/mockup.svg');
1230
+ } else if (act.attr('id') == 'video-tool') {
1231
+ act.find('img').attr('src', 'assets/video.svg');
1232
+ } else if (act.attr('id') == 'shape-tool') {
1233
+ act.find('img').attr('src', 'assets/shape.svg');
1234
+ } else if (act.attr('id') == 'upload-tool') {
1235
+ act.find('img').attr('src', 'assets/uploads.svg');
1236
+ } else if (act.attr('id') == 'audio-tool') {
1237
+ act.find('img').attr('src', 'assets/audio.svg');
1238
+ }
1239
+ $('.tool-active').removeClass('tool-active');
1240
+ $(this).addClass('tool-active');
1241
+ if ($(this).attr('id') == 'image-tool') {
1242
+ $(this).find('img').attr('src', 'assets/image-active.svg');
1243
+ } else if ($(this).attr('id') == 'text-tool') {
1244
+ $(this).find('img').attr('src', 'assets/text-active.svg');
1245
+ } else if ($(this).attr('id') == 'mockup-tool') {
1246
+ $(this).find('img').attr('src', 'assets/mockup-active.svg');
1247
+ } else if ($(this).attr('id') == 'video-tool') {
1248
+ $(this).find('img').attr('src', 'assets/video-active.svg');
1249
+ } else if ($(this).attr('id') == 'shape-tool') {
1250
+ $(this).find('img').attr('src', 'assets/shape-active.svg');
1251
+ } else if ($(this).attr('id') == 'upload-tool') {
1252
+ $(this).find('img').attr('src', 'assets/uploads-active.svg');
1253
+ } else if ($(this).attr('id') == 'audio-tool') {
1254
+ $(this).find('img').attr('src', 'assets/audio-active.svg');
1255
+ }
1256
+ updateBrowser($(this).attr('id'));
1257
+ resetHeight();
1258
+ }
1259
+ $(document).on('click', '.tool:not(.tool-active)', switchTool);
1260
+
1261
+ // Replace image or video by dragging on top and holding a key
1262
+ function replaceObject(src, object) {
1263
+ var img = new Image();
1264
+ var width = object.width;
1265
+ var height = object.height;
1266
+ oldsrc = object._originalElement.currentSrc;
1267
+ oldobj = object;
1268
+ img.onload = function () {
1269
+ object.setElement(img);
1270
+ object.set('width', width);
1271
+ object.set('height', height);
1272
+ canvas.renderAll();
1273
+ };
1274
+ img.src = src;
1275
+ }
1276
+
1277
+ // Drag object from the panel
1278
+ function dragObject(e) {
1279
+ if (e.which == 3) {
1280
+ return false;
1281
+ }
1282
+ var drag = $(this).clone();
1283
+ drag.css({
1284
+ background: 'transparent',
1285
+ boxShadow: 'none',
1286
+ color: '#000',
1287
+ });
1288
+ drag.appendTo('body');
1289
+ drag.css({
1290
+ position: 'absolute',
1291
+ zIndex: 9999999,
1292
+ left: $(this).offset().left,
1293
+ top: $(this).offset().top,
1294
+ width: canvas.getZoom() * drag.width(),
1295
+ pointerEvents: 'none',
1296
+ opacity: 0,
1297
+ });
1298
+ var pageX = e.pageX;
1299
+ var pageY = e.pageY;
1300
+ var offset = drag.offset();
1301
+ var offsetx = drag.offset().left + drag.width() / 2 - e.pageX;
1302
+ var offsety = drag.offset().top + drag.height() / 2 - e.pageY;
1303
+ var replacing = false;
1304
+ draggingPanel = true;
1305
+ var move = false;
1306
+ canvas.discardActiveObject();
1307
+ canvas.renderAll();
1308
+ function dragging(e) {
1309
+ $('#bottom-area').addClass('noselect');
1310
+ $('#toolbar').addClass('noselect');
1311
+ $('#browser').addClass('noselect');
1312
+ $('#properties').addClass('noselect');
1313
+ $('#controls').addClass('noselect');
1314
+ move = true;
1315
+ var left = offset.left + (e.pageX - pageX);
1316
+ var top = offset.top + (e.pageY - pageY);
1317
+ drag.offset({ left: left, top: top });
1318
+
1319
+ if (
1320
+ overCanvas &&
1321
+ canvas.getActiveObject() &&
1322
+ !replacing &&
1323
+ canvas.getActiveObject().type == 'image' &&
1324
+ (drag.hasClass('image-grid-item') ||
1325
+ drag.hasClass('video-grid-item'))
1326
+ ) {
1327
+ if (e.ctrlKey) {
1328
+ drag.css('visibility', 'hidden');
1329
+ replaceObject(
1330
+ drag.attr('data-src'),
1331
+ canvas.getActiveObject()
1332
+ );
1333
+ replacing = true;
1334
+ } else {
1335
+ $('#replace-image').addClass('replace-active');
1336
+ }
1337
+ } else if (
1338
+ (replacing && !canvas.getActiveObject()) ||
1339
+ (replacing && !e.ctrlKey)
1340
+ ) {
1341
+ drag.css('visibility', 'visible');
1342
+ replaceObject(oldsrc, oldobj);
1343
+ replacing = false;
1344
+ canvas.discardActiveObject();
1345
+ $('#replace-image').removeClass('replace-active');
1346
+ } else {
1347
+ $('#replace-image').removeClass('replace-active');
1348
+ }
1349
+
1350
+ if (overCanvas) {
1351
+ drag.css({ opacity: 1 });
1352
+ } else {
1353
+ drag.css({ opacity: 0.5 });
1354
+ }
1355
+ }
1356
+ function released(e) {
1357
+ $('#replace-image').removeClass('replace-active');
1358
+ $('#bottom-area').removeClass('noselect');
1359
+ $('#toolbar').removeClass('noselect');
1360
+ $('#browser').removeClass('noselect');
1361
+ $('#properties').removeClass('noselect');
1362
+ $('#controls').removeClass('noselect');
1363
+ draggingPanel = false;
1364
+ $('body').off('mousemove', dragging).off('mouseup', released);
1365
+ canvasx = canvas.getPointer(e).x;
1366
+ canvasy = canvas.getPointer(e).y;
1367
+ var xpos = canvasx + offsetx - artboard.get('left');
1368
+ var ypos = canvasy + offsety - artboard.get('top');
1369
+ if (!overCanvas && move) {
1370
+ drag.remove();
1371
+ return false;
1372
+ }
1373
+ if (move && !replacing) {
1374
+ if (drag.hasClass('grid-item')) {
1375
+ newSVG(
1376
+ drag.find('img').attr('src'),
1377
+ xpos,
1378
+ ypos,
1379
+ drag.width(),
1380
+ false
1381
+ );
1382
+ } else if (drag.hasClass('image-external-grid-item')) {
1383
+ $('#load-image').addClass('loading-active');
1384
+ savePixabayImage(
1385
+ drag.attr('data-src'),
1386
+ xpos,
1387
+ ypos,
1388
+ drag.width()
1389
+ );
1390
+ } else if (drag.hasClass('video-external-grid-item')) {
1391
+ savePixabayVideo(
1392
+ drag.attr('data-src'),
1393
+ drag.find('img').attr('src'),
1394
+ xpos,
1395
+ ypos
1396
+ );
1397
+ } else if (drag.hasClass('image-grid-item')) {
1398
+ $('#load-image').addClass('loading-active');
1399
+ loadImage(
1400
+ drag.attr('data-src'),
1401
+ xpos,
1402
+ ypos,
1403
+ drag.width(),
1404
+ false
1405
+ );
1406
+ } else if (drag.hasClass('grid-emoji-item')) {
1407
+ $('#load-image').addClass('loading-active');
1408
+ loadImage(
1409
+ drag.find('img').attr('src'),
1410
+ xpos,
1411
+ ypos,
1412
+ drag.width(),
1413
+ false
1414
+ );
1415
+ } else if (drag.hasClass('add-text')) {
1416
+ if (drag.attr('id') == 'heading-text') {
1417
+ newTextbox(
1418
+ 50,
1419
+ 700,
1420
+ 'Add a heading',
1421
+ canvasx - artboard.get('left'),
1422
+ canvasy - artboard.get('top'),
1423
+ drag.width(),
1424
+ false,
1425
+ drag.attr('data-font')
1426
+ );
1427
+ } else if (drag.attr('id') == 'subheading-text') {
1428
+ newTextbox(
1429
+ 22,
1430
+ 500,
1431
+ 'Add a subheading',
1432
+ canvasx - artboard.get('left'),
1433
+ canvasy - artboard.get('top'),
1434
+ drag.width(),
1435
+ false,
1436
+ drag.attr('data-font')
1437
+ );
1438
+ } else if (drag.attr('id') == 'body-text') {
1439
+ newTextbox(
1440
+ 18,
1441
+ 400,
1442
+ 'Add body text',
1443
+ canvasx - artboard.get('left'),
1444
+ canvasy - artboard.get('top'),
1445
+ drag.width(),
1446
+ false,
1447
+ drag.attr('data-font')
1448
+ );
1449
+ } else {
1450
+ newTextbox(
1451
+ 18,
1452
+ 400,
1453
+ 'Your text',
1454
+ canvasx - artboard.get('left'),
1455
+ canvasy - artboard.get('top'),
1456
+ drag.width(),
1457
+ false,
1458
+ drag.attr('data-font')
1459
+ );
1460
+ }
1461
+ } else if (drag.hasClass('video-grid-item')) {
1462
+ $('#load-video').addClass('loading-active');
1463
+ loadVideo(drag.attr('data-src'), canvasx, canvasy);
1464
+ }
1465
+ } else if (!move && !replacing) {
1466
+ if (drag.hasClass('grid-item')) {
1467
+ newSVG(
1468
+ drag.find('img').attr('src'),
1469
+ artboard.get('left') + artboard.get('width') / 2,
1470
+ artboard.get('top') + artboard.get('height') / 2,
1471
+ 100,
1472
+ true
1473
+ );
1474
+ } else if (drag.hasClass('image-external-grid-item')) {
1475
+ savePixabayImage(
1476
+ drag.attr('data-src'),
1477
+ artboard.get('left') + artboard.get('width') / 2,
1478
+ artboard.get('top') + artboard.get('height') / 2,
1479
+ 150
1480
+ );
1481
+ } else if (drag.hasClass('video-external-grid-item')) {
1482
+ savePixabayVideo(
1483
+ drag.attr('data-src'),
1484
+ drag.find('img').attr('src'),
1485
+ artboard.get('left') + artboard.get('width') / 2,
1486
+ artboard.get('top') + artboard.get('height') / 2
1487
+ );
1488
+ } else if (drag.hasClass('image-grid-item')) {
1489
+ $('#load-image').addClass('loading-active');
1490
+ loadImage(
1491
+ drag.attr('data-src'),
1492
+ artboard.get('left') + artboard.get('width') / 2,
1493
+ artboard.get('top') + artboard.get('height') / 2,
1494
+ 150,
1495
+ true
1496
+ );
1497
+ } else if (drag.hasClass('grid-emoji-item')) {
1498
+ $('#load-image').addClass('loading-active');
1499
+ loadImage(
1500
+ drag.find('img').attr('src'),
1501
+ artboard.get('left') + artboard.get('width') / 2,
1502
+ artboard.get('top') + artboard.get('height') / 2,
1503
+ 50,
1504
+ true
1505
+ );
1506
+ } else if (drag.hasClass('add-text')) {
1507
+ if (drag.attr('id') == 'heading-text') {
1508
+ newTextbox(
1509
+ 50,
1510
+ 700,
1511
+ 'Add a heading',
1512
+ artboard.get('left') + artboard.get('width') / 2,
1513
+ artboard.get('top') + artboard.get('height') / 2,
1514
+ drag.width(),
1515
+ true,
1516
+ drag.attr('data-font')
1517
+ );
1518
+ } else if (drag.attr('id') == 'subheading-text') {
1519
+ newTextbox(
1520
+ 22,
1521
+ 500,
1522
+ 'Add a subheading',
1523
+ artboard.get('left') + artboard.get('width') / 2,
1524
+ artboard.get('top') + artboard.get('height') / 2,
1525
+ drag.width(),
1526
+ true,
1527
+ drag.attr('data-font')
1528
+ );
1529
+ } else if (drag.attr('id') == 'body-text') {
1530
+ newTextbox(
1531
+ 18,
1532
+ 400,
1533
+ 'Add body text',
1534
+ artboard.get('left') + artboard.get('width') / 2,
1535
+ artboard.get('top') + artboard.get('height') / 2,
1536
+ drag.width(),
1537
+ true,
1538
+ drag.attr('data-font')
1539
+ );
1540
+ } else {
1541
+ newTextbox(
1542
+ 18,
1543
+ 400,
1544
+ 'Your text',
1545
+ artboard.get('left') + artboard.get('width') / 2,
1546
+ artboard.get('top') + artboard.get('height') / 2,
1547
+ drag.width(),
1548
+ true,
1549
+ drag.attr('data-font')
1550
+ );
1551
+ }
1552
+ } else if (drag.hasClass('video-grid-item')) {
1553
+ $('#load-video').addClass('loading-active');
1554
+ loadVideo(
1555
+ drag.attr('data-src'),
1556
+ artboard.get('left') + artboard.get('width') / 2,
1557
+ artboard.get('top') + artboard.get('height') / 2,
1558
+ true
1559
+ );
1560
+ }
1561
+ }
1562
+ drag.remove();
1563
+ }
1564
+ $('body').on('mouseup', released).on('mousemove', dragging);
1565
+ }
1566
+ $(document).on('mousedown', '.image-grid-item', dragObject);
1567
+ $(document).on('mousedown', '.video-grid-item', dragObject);
1568
+ $(document).on('mousedown', '.grid-item', dragObject);
1569
+ $(document).on('mousedown', '.grid-emoji-item', dragObject);
1570
+ $(document).on('mousedown', '.add-text', dragObject);
1571
+ $(document).on('mousedown click mouseup', '.credit', function (e) {
1572
+ e.stopPropagation();
1573
+ });
1574
+
1575
+ // Collapse library
1576
+ function collapsePanel() {
1577
+ $('#browser').addClass('collapsed');
1578
+ $('#behind-browser').addClass('collapsed');
1579
+ $('#canvas-area').addClass('canvas-full');
1580
+ var act = $('.tool-active');
1581
+ if (act.attr('id') == 'image-tool') {
1582
+ act.find('img').attr('src', 'assets/image.svg');
1583
+ } else if (act.attr('id') == 'text-tool') {
1584
+ act.find('img').attr('src', 'assets/text.svg');
1585
+ } else if (act.attr('id') == 'mockup-tool') {
1586
+ act.find('img').attr('src', 'assets/mockup.svg');
1587
+ } else if (act.attr('id') == 'video-tool') {
1588
+ act.find('img').attr('src', 'assets/video.svg');
1589
+ } else if (act.attr('id') == 'shape-tool') {
1590
+ act.find('img').attr('src', 'assets/shape.svg');
1591
+ } else if (act.attr('id') == 'upload-tool') {
1592
+ act.find('img').attr('src', 'assets/uploads.svg');
1593
+ }
1594
+ $('.tool-active').removeClass('tool-active');
1595
+ resizeCanvas();
1596
+ }
1597
+ $(document).on('click', '#collapse', collapsePanel);
1598
+ $(document).on('click', '.tool-active', collapsePanel);
1599
+
1600
+ // Change canvas dimensions to selected preset
1601
+ function setPreset() {
1602
+ if ($(this).val() != 'custom') {
1603
+ artboard.set({
1604
+ width: presets.find((x) => x.id == $(this).val()).width,
1605
+ height: presets.find((x) => x.id == $(this).val()).height,
1606
+ });
1607
+ canvas.renderAll();
1608
+ resizeCanvas();
1609
+ }
1610
+ activepreset = $(this).val();
1611
+ updatePanel();
1612
+ save();
1613
+ }
1614
+ $(document).on('change', '#preset', setPreset);
1615
+
1616
+ function setTextPreset() {
1617
+ var object = canvas.getActiveObject();
1618
+ animatedtext
1619
+ .find((x) => x.id == object.id)
1620
+ .setProp({ preset: $(this).val() }, canvas);
1621
+ save();
1622
+ }
1623
+ function setTextEasing() {
1624
+ var object = canvas.getActiveObject();
1625
+ animatedtext
1626
+ .find((x) => x.id == object.id)
1627
+ .setProp({ easing: $(this).val() }, canvas);
1628
+ save();
1629
+ }
1630
+ $(document).on('change', '#preset-picker', setTextPreset);
1631
+ $(document).on('change', '#easing-picker', setTextEasing);
1632
+
1633
+ // Delete media from the panel
1634
+ function deleteMedia(e) {
1635
+ e.preventDefault();
1636
+ e.stopPropagation();
1637
+ var key = $(this).parent().attr('data-key');
1638
+ if (
1639
+ window.confirm(
1640
+ 'Are you sure you want to permanently delete this asset? It will also remove any instances of it in the canvas.'
1641
+ )
1642
+ ) {
1643
+ deleteAsset(key);
1644
+ }
1645
+ }
1646
+ $(document).on('mousedown', '.delete-media', deleteMedia);
1647
+
1648
+ // Save layer name
1649
+ function saveLayerName() {
1650
+ $('.name-active').prop('readonly', true);
1651
+ if ($('.name-active').val() == '') {
1652
+ $('.name-active').val('Untitled layer');
1653
+ }
1654
+ objects.find(
1655
+ (x) =>
1656
+ x.id == $('.name-active').parent().parent().attr('data-object')
1657
+ ).label = $('.name-active').val();
1658
+ save();
1659
+ $('.name-active').removeClass('name-active');
1660
+ if (window.getSelection) {
1661
+ if (window.getSelection().empty) {
1662
+ window.getSelection().empty();
1663
+ } else if (window.getSelection().removeAllRanges) {
1664
+ window.getSelection().removeAllRanges();
1665
+ }
1666
+ } else if (document.selection) {
1667
+ document.selection.empty();
1668
+ }
1669
+ editinglayer = false;
1670
+ }
1671
+ $(document).on('focusout', '.layer-custom-name', saveLayerName);
1672
+
1673
+ // Zoom to specific level
1674
+ function zoomTo() {
1675
+ var zoom;
1676
+ if ($(this).attr('data-zoom') == 'in') {
1677
+ zoom = canvas.getZoom() + 0.2;
1678
+ } else if ($(this).attr('data-zoom') == 'out') {
1679
+ zoom = canvas.getZoom() - 0.2;
1680
+ } else {
1681
+ zoom = parseInt($(this).attr('data-zoom')) / 100;
1682
+ }
1683
+ if (zoom > 20) zoom = 20;
1684
+ if (zoom < 0.01) zoom = 0.01;
1685
+ canvas.setZoom(1);
1686
+ canvas.renderAll();
1687
+ var vpw = canvas.width / zoom;
1688
+ var vph = canvas.height / zoom;
1689
+ var x = artboard.left + artboard.width / 2 - vpw / 2;
1690
+ var y = artboard.top + artboard.height / 2 - vph / 2;
1691
+ canvas.absolutePan({ x: x, y: y });
1692
+ canvas.setZoom(zoom);
1693
+ canvas.renderAll();
1694
+ $('#zoom-level span').html(
1695
+ (canvas.getZoom() * 100).toFixed(0) + '%'
1696
+ );
1697
+ }
1698
+ $(document).on('click', '.zoom-options-item', zoomTo);
1699
+
1700
+ // Add background audio (temporary)
1701
+ function addBackgroundAudio() {
1702
+ background_audio = new Audio('assets/audio.wav');
1703
+ }
1704
+
1705
+ // Hide all modals
1706
+ function hideModals() {
1707
+ $('.modal-open').removeClass('modal-open');
1708
+ }
1709
+ $('#background-overlay').on('click', hideModals);
1710
+
1711
+ // Open download modal
1712
+ function downloadModal() {
1713
+ if (!recording) {
1714
+ hideModals();
1715
+ $('#download-modal').addClass('modal-open');
1716
+ $('#background-overlay').addClass('modal-open');
1717
+ }
1718
+ }
1719
+ $('#download').on('click', downloadModal);
1720
+
1721
+ // Open import/export modal
1722
+ function importExportModal() {
1723
+ hideModals();
1724
+ $('#import-export-modal').toggleClass('modal-open');
1725
+ $('#background-overlay').toggleClass('modal-open');
1726
+ }
1727
+ $('#share').on('click', importExportModal);
1728
+
1729
+ function searchInput() {
1730
+ var value = $(this).val().toLowerCase();
1731
+ if (value == '') {
1732
+ $('#delete-search').removeClass('show-delete');
1733
+ } else {
1734
+ $('#delete-search').addClass('show-delete');
1735
+ }
1736
+ }
1737
+
1738
+ function fancyTimeFormat(duration) {
1739
+ var hrs = ~~(duration / 3600);
1740
+ var mins = ~~((duration % 3600) / 60);
1741
+ var secs = ~~duration % 60;
1742
+ var ret = '';
1743
+ if (hrs > 0) {
1744
+ ret += '' + hrs + ':' + (mins < 10 ? '0' : '');
1745
+ }
1746
+ ret += '' + mins + ':' + (secs < 10 ? '0' : '');
1747
+ ret += '' + secs;
1748
+ return ret;
1749
+ }
1750
+
1751
+ function loadMoreMedia() {
1752
+ var value = $('#browser-search input').val();
1753
+ if (value != '' && page != false) {
1754
+ page += 1;
1755
+ if ($('#image-tool').hasClass('tool-active')) {
1756
+ var URL =
1757
+ 'https://pixabay.com/api/?key=' +
1758
+ API_KEY +
1759
+ '&q=' +
1760
+ encodeURIComponent(value) +
1761
+ '&page=' +
1762
+ page;
1763
+ $.getJSON(URL, function (data) {
1764
+ if (parseInt(data.totalHits) > 0) {
1765
+ $.each(data.hits, function (i, hit) {
1766
+ $('#images-grid').append(
1767
+ "<div class='image-grid-item image-external-grid-item' data-src='" +
1768
+ hit.webformatURL +
1769
+ "'><a class='credit' href='" +
1770
+ hit.pageURL +
1771
+ "' target='_blank'>" +
1772
+ hit.user +
1773
+ "</a><img draggable=false onload='onLoadImage(this)' src='" +
1774
+ hit.webformatURL +
1775
+ "'</div>"
1776
+ );
1777
+ });
1778
+ } else {
1779
+ page = false;
1780
+ }
1781
+ });
1782
+ } else if ($('#video-tool').hasClass('tool-active')) {
1783
+ var URL =
1784
+ 'https://pixabay.com/api/videos/?key=' +
1785
+ API_KEY +
1786
+ '&q=' +
1787
+ encodeURIComponent(value) +
1788
+ '&page=' +
1789
+ page;
1790
+ $.getJSON(URL, function (data) {
1791
+ if (parseInt(data.totalHits) > 0) {
1792
+ $.each(data.hits, function (i, hit) {
1793
+ var video = hit.videos.medium.url;
1794
+ $('#images-grid').append(
1795
+ "<div class='image-grid-item video-external-grid-item' data-src='" +
1796
+ video +
1797
+ "'><a class='credit' href='" +
1798
+ hit.pageURL +
1799
+ "' target='_blank'>" +
1800
+ hit.user +
1801
+ "</a><div id='time-video'>" +
1802
+ fancyTimeFormat(hit.duration) +
1803
+ "</div><img draggable=false onload='onLoadImage(this)' src='assets/transparent.png'</div>"
1804
+ );
1805
+ createVideoThumbnail(video, 250, 0, true).then(function (
1806
+ data
1807
+ ) {
1808
+ $(".image-grid-item[data-src='" + video + "']")
1809
+ .find('img')
1810
+ .attr('src', data);
1811
+ });
1812
+ });
1813
+ } else {
1814
+ page = false;
1815
+ }
1816
+ });
1817
+ }
1818
+ }
1819
+ }
1820
+
1821
+ function search() {
1822
+ page = 1;
1823
+ var value = $('#browser-search input').val();
1824
+ if ($('#image-tool').hasClass('tool-active')) {
1825
+ var URL =
1826
+ 'https://pixabay.com/api/?key=' +
1827
+ API_KEY +
1828
+ '&q=' +
1829
+ encodeURIComponent(value) +
1830
+ '&page=' +
1831
+ page;
1832
+ $('#images-grid').html('');
1833
+ if (value != '') {
1834
+ $('#pixabay').addClass('hide-pixabay');
1835
+ $('#landing').addClass('hide-landing');
1836
+ $.getJSON(URL, function (data) {
1837
+ if (parseInt(data.totalHits) > 0) {
1838
+ $.each(data.hits, function (i, hit) {
1839
+ $('#images-grid').append(
1840
+ "<div class='image-grid-item image-external-grid-item' data-src='" +
1841
+ hit.webformatURL +
1842
+ "'><a class='credit' href='" +
1843
+ hit.pageURL +
1844
+ "' target='_blank'>" +
1845
+ hit.user +
1846
+ "</a><img draggable=false onload='onLoadImage(this)' src='" +
1847
+ hit.webformatURL +
1848
+ "'</div>"
1849
+ );
1850
+ });
1851
+ } else {
1852
+ $('#shapes-cont').html(
1853
+ "<div id='no-results'>Sorry, we couldn't find any results for &#x22;" +
1854
+ encodeURIComponent(value) +
1855
+ '&#x22;. Please try a different query.</div>'
1856
+ );
1857
+ }
1858
+ });
1859
+ } else {
1860
+ $('#pixabay').removeClass('hide-pixabay');
1861
+ $('#landing').removeClass('hide-landing');
1862
+ }
1863
+ } else if ($('#video-tool').hasClass('tool-active')) {
1864
+ var URL =
1865
+ 'https://pixabay.com/api/videos/?key=' +
1866
+ API_KEY +
1867
+ '&q=' +
1868
+ encodeURIComponent(value);
1869
+ $('#images-grid').html('');
1870
+ if (value != '') {
1871
+ $('#landing').addClass('hide-landing');
1872
+ $('#pixabay').addClass('hide-pixabay');
1873
+ $.getJSON(URL, function (data) {
1874
+ if (parseInt(data.totalHits) > 0) {
1875
+ $.each(data.hits, function (i, hit) {
1876
+ var video = hit.videos.medium.url;
1877
+ $('#images-grid').append(
1878
+ "<div class='image-grid-item video-external-grid-item' data-src='" +
1879
+ video +
1880
+ "'><a class='credit' href='" +
1881
+ hit.pageURL +
1882
+ "' target='_blank'>" +
1883
+ hit.user +
1884
+ "</a><div id='time-video'>" +
1885
+ fancyTimeFormat(hit.duration) +
1886
+ "</div><img draggable=false onload='onLoadImage(this)' src='assets/transparent.png'</div>"
1887
+ );
1888
+ //createVideoThumbnail(video, 250, 0, true).then(function(data){
1889
+ $(".image-grid-item[data-src='" + video + "']")
1890
+ .find('img')
1891
+ .attr(
1892
+ 'src',
1893
+ 'https://i.vimeocdn.com/video/' +
1894
+ hit.picture_id +
1895
+ '_640x360.jpg'
1896
+ );
1897
+ //});
1898
+ });
1899
+ } else {
1900
+ $('#shapes-cont').html(
1901
+ "<div id='no-results'>Sorry, we couldn't find any results for &#x22;" +
1902
+ encodeURIComponent(value) +
1903
+ '&#x22;. Please try a different query.</div>'
1904
+ );
1905
+ }
1906
+ });
1907
+ } else {
1908
+ $('#pixabay').removeClass('hide-pixabay');
1909
+ $('#landing').removeClass('hide-landing');
1910
+ }
1911
+ } else if ($('#shape-tool').hasClass('tool-active')) {
1912
+ if (value == '') {
1913
+ $('#shapes-cont').html(
1914
+ '<p class="row-title">Shapes</p><div class="gallery-row" id="shapes-row"></div><p class="row-title">Emojis</p><div class="gallery-row" id="emojis-row"></div>'
1915
+ );
1916
+ populateGrid('shape-tool');
1917
+ } else {
1918
+ $('.row-title').remove();
1919
+ $('.gallery-row').remove();
1920
+ $('#shapes-cont').html("<div class='gallery-row'></div>");
1921
+ var combined = shape_grid_items.concat(emoji_items);
1922
+ var flag = false;
1923
+ combined.forEach(function (item) {
1924
+ if (item.indexOf(value) > -1) {
1925
+ flag = true;
1926
+ if (item.indexOf('emoji') > -1) {
1927
+ $('.gallery-row').append(
1928
+ "<div class='grid-emoji-item'><img draggable=false src='" +
1929
+ item +
1930
+ "'></div>"
1931
+ );
1932
+ } else {
1933
+ $('.gallery-row').append(
1934
+ "<div class='grid-item'><img draggable=false src='" +
1935
+ item +
1936
+ "'></div>"
1937
+ );
1938
+ }
1939
+ }
1940
+ });
1941
+ if (!flag) {
1942
+ $('#shapes-cont').html(
1943
+ "<div id='no-results'>Sorry, we couldn't find any results for &#x22;" +
1944
+ encodeURIComponent(value) +
1945
+ '&#x22;. Please try a different query.</div>'
1946
+ );
1947
+ }
1948
+ }
1949
+ } else if ($('#text-tool').hasClass('tool-active')) {
1950
+ if (value == '') {
1951
+ $('#browser-container').html(text_browser);
1952
+ populateGrid('text-tool');
1953
+ } else {
1954
+ $('#shapes-cont').html('');
1955
+ $('.row-title').remove();
1956
+ var flag = false;
1957
+ fonts.forEach(function (font) {
1958
+ if (font.toLowerCase().indexOf(value) > -1) {
1959
+ flag = true;
1960
+ WebFont.load({
1961
+ google: {
1962
+ families: [font],
1963
+ },
1964
+ });
1965
+ $('#shapes-cont').append(
1966
+ "<div id='item-text' class='add-text noselect' data-font='" +
1967
+ font +
1968
+ "' style='font-family: " +
1969
+ font +
1970
+ "'>" +
1971
+ font +
1972
+ '</div>'
1973
+ );
1974
+ }
1975
+ });
1976
+ if (!flag) {
1977
+ $('#shapes-cont').html(
1978
+ "<div id='no-results'>Sorry, we couldn't find any results for &#x22;" +
1979
+ encodeURIComponent(value) +
1980
+ '&#x22;. Please try a different query.</div>'
1981
+ );
1982
+ }
1983
+ }
1984
+ }
1985
+ }
1986
+
1987
+ function searchCategory() {
1988
+ $('#browser-search input').val($(this).attr('data-name'));
1989
+ $('#delete-search').addClass('show-delete');
1990
+ search();
1991
+ $('#pixabay').addClass('hide-pixabay');
1992
+ }
1993
+
1994
+ function deleteSearch() {
1995
+ $('#browser-search input').val('');
1996
+ $('#delete-search').removeClass('show-delete');
1997
+ if ($('#shape-tool').hasClass('tool-active')) {
1998
+ $('#shapes-cont').html(
1999
+ '<p class="row-title">Shapes</p><div class="gallery-row" id="shapes-row"></div><p class="row-title">Emojis</p><div class="gallery-row" id="emojis-row"></div>'
2000
+ );
2001
+ populateGrid('shape-tool');
2002
+ } else if ($('#image-tool').hasClass('tool-active')) {
2003
+ $('#images-grid').html('');
2004
+ $('#landing').removeClass('hide-landing');
2005
+ $('#pixabay').removeClass('hide-pixabay');
2006
+ } else if ($('#video-tool').hasClass('tool-active')) {
2007
+ $('#images-grid').html('');
2008
+ $('#landing').removeClass('hide-landing');
2009
+ $('#pixabay').removeClass('hide-pixabay');
2010
+ } else if ($('#text-tool').hasClass('tool-active')) {
2011
+ $('#browser-container').html(text_browser);
2012
+ populateGrid('text-tool');
2013
+ }
2014
+ }
2015
+ $(document).on('click', '#delete-search', deleteSearch);
2016
+ $(document).on('input', '#browser-search input', searchInput);
2017
+ $(document).on('click', '#search-button', search);
2018
+ $(document).on('click', '.category', searchCategory);
2019
+
2020
+ function replaceAudioBackground() {
2021
+ var src = $(this).attr('data-src');
2022
+ newAudioLayer(src);
2023
+ /*
2024
+ if ($(this).hasClass("audio-item-active")) {
2025
+ background_audio = false;
2026
+ background_key = false;
2027
+ $(this).removeClass("audio-item-active");
2028
+ save();
2029
+ } else {
2030
+ var src = $(this).attr("data-src");
2031
+ if (background_audio != false) {
2032
+ $("#audio-upload-button").removeClass("remove-audio");
2033
+ $("#audio-upload-button").html('<img src="assets/upload.svg"> Upload audio');
2034
+ }
2035
+ db.collection("projects").doc({id: 1}).update({
2036
+ audiosrc: src,
2037
+ });
2038
+ background_audio = new Audio(src);
2039
+ background_audio.crossOrigin = "anonymous";
2040
+ background_key = src;
2041
+ save();
2042
+ $(this).addClass("audio-item-active");
2043
+ }
2044
+ */
2045
+ }
2046
+ $(document).on('click', '.audio-item', replaceAudioBackground);
2047
+
2048
+ function previewAudioBackground(e) {
2049
+ e.preventDefault();
2050
+ e.stopPropagation();
2051
+ var src = $(this).parent().attr('data-src');
2052
+ if ($(this).find('img').attr('src') == 'assets/play-button.svg') {
2053
+ temp_audio = new Audio(src);
2054
+ temp_audio.crossOrigin = 'anonymous';
2055
+ temp_audio.currentTime = 0;
2056
+ temp_audio.play();
2057
+ $(this).find('img').attr('src', 'assets/pause-button.svg');
2058
+ } else {
2059
+ if (temp_audio != false) {
2060
+ temp_audio.pause();
2061
+ }
2062
+ $(this).find('img').attr('src', 'assets/play-button.svg');
2063
+ }
2064
+ }
2065
+ $(document).on('click', '.audio-preview', previewAudioBackground);
2066
+
2067
+ /* Filters options */
2068
+ function checkFilter() {
2069
+ resetFilters();
2070
+ if (canvas.getActiveObject()) {
2071
+ var obj = canvas.getActiveObject();
2072
+ if (
2073
+ canvas.getActiveObjects().length == 1 &&
2074
+ (obj.type == 'image' || obj.type == 'video')
2075
+ ) {
2076
+ var value = 'none';
2077
+ if (obj.filters.length > 0) {
2078
+ obj.filters.forEach(function (filter) {
2079
+ if (
2080
+ filter.type == 'BlackWhite' ||
2081
+ filter.type == 'Invert' ||
2082
+ filter.type == 'Sepia' ||
2083
+ filter.type == 'Kodachrome' ||
2084
+ filter.type == 'Polaroid' ||
2085
+ filter.type == 'Technicolor' ||
2086
+ filter.type == 'Brownie' ||
2087
+ filter.type == 'Vintage'
2088
+ ) {
2089
+ value = filter.type;
2090
+ } else if (filter.type == 'Brightness') {
2091
+ sliders
2092
+ .find((x) => x.name == 'filter-brightness')
2093
+ .slider.setValue(filter.brightness * 100);
2094
+ } else if (filter.type == 'Contrast') {
2095
+ sliders
2096
+ .find((x) => x.name == 'filter-contrast')
2097
+ .slider.setValue(filter.contrast * 100);
2098
+ } else if (filter.type == 'Vibrance') {
2099
+ sliders
2100
+ .find((x) => x.name == 'filter-vibrance')
2101
+ .slider.setValue(filter.vibrance * 100);
2102
+ } else if (filter.type == 'Saturation') {
2103
+ sliders
2104
+ .find((x) => x.name == 'filter-saturation')
2105
+ .slider.setValue(filter.saturation * 100);
2106
+ } else if (filter.type == 'HueRotation') {
2107
+ sliders
2108
+ .find((x) => x.name == 'filter-hue')
2109
+ .slider.setValue(filter.rotation * 100);
2110
+ } else if (filter.type == 'Blur') {
2111
+ blurslider.setValue(filter.blur * 100);
2112
+ } else if (filter.type == 'Noise') {
2113
+ noiseslider.setValue(filter.noise);
2114
+ }
2115
+ $('#filters-list').val(value);
2116
+ $('#filters-list').niceSelect('update');
2117
+ });
2118
+ } else {
2119
+ $('#filters-list').val(value);
2120
+ $('#filters-list').niceSelect('update');
2121
+ }
2122
+ }
2123
+ }
2124
+ }
2125
+ function clearFilters() {
2126
+ if (canvas.getActiveObject()) {
2127
+ var obj = canvas.getActiveObject();
2128
+ obj.filters = $.grep(obj.filters, function (i) {
2129
+ return (
2130
+ i.type != 'BlackWhite' &&
2131
+ i.type != 'Invert' &&
2132
+ i.type != 'Sepia' &&
2133
+ i.type != 'Kodachrome' &&
2134
+ i.type != 'Polaroid' &&
2135
+ i.type != 'Technicolor' &&
2136
+ i.type != 'Brownie' &&
2137
+ i.type != 'Vintage'
2138
+ );
2139
+ });
2140
+ canvas.renderAll();
2141
+ }
2142
+ }
2143
+ function applyFilter(name) {
2144
+ if (canvas.getActiveObject()) {
2145
+ var obj = canvas.getActiveObject();
2146
+ if (name == 'Sepia') {
2147
+ obj.filters.push(new f.Sepia());
2148
+ } else if (name == 'Invert') {
2149
+ obj.filters.push(new f.Invert());
2150
+ } else if (name == 'BlackWhite') {
2151
+ obj.filters.push(new f.BlackWhite());
2152
+ } else if (name == 'Kodachrome') {
2153
+ obj.filters.push(new f.Kodachrome());
2154
+ } else if (name == 'Polaroid') {
2155
+ obj.filters.push(new f.Polaroid());
2156
+ } else if (name == 'Technicolor') {
2157
+ obj.filters.push(new f.Technicolor());
2158
+ } else if (name == 'Vintage') {
2159
+ obj.filters.push(new f.Vintage());
2160
+ } else if (name == 'Brownie') {
2161
+ obj.filters.push(new f.Brownie());
2162
+ }
2163
+ obj.applyFilters();
2164
+ canvas.renderAll();
2165
+ save();
2166
+ }
2167
+ }
2168
+ function updateMediaFilters() {
2169
+ var value = $(this).val();
2170
+ if (canvas.getActiveObject()) {
2171
+ clearFilters();
2172
+ applyFilter(value);
2173
+ }
2174
+ }
2175
+ $(document).on('change', '#filters select', updateMediaFilters);
2176
+
2177
+ function resetFilters() {
2178
+ if (canvas.getActiveObject()) {
2179
+ var object = canvas.getActiveObject();
2180
+ if (object.filters) {
2181
+ if (!object.filters.find((x) => x.type == 'Blur')) {
2182
+ blurslider.setValue(0);
2183
+ }
2184
+ if (!object.filters.find((x) => x.type == 'Noise')) {
2185
+ noiseslider.setValue(0);
2186
+ }
2187
+ if (object.filters.length > 0) {
2188
+ sliders.forEach(function (slider) {
2189
+ var name = '';
2190
+ if (slider.name == 'filter-hue') {
2191
+ name = 'HueRotation';
2192
+ } else if (slider.name == 'filter-brightness') {
2193
+ name = 'Brightness';
2194
+ } else if (slider.name == 'filter-vibrance') {
2195
+ name = 'Vibrance';
2196
+ } else if (slider.name == 'filter-contrast') {
2197
+ name = 'Contrast';
2198
+ } else if (slider.name == 'filter-saturation') {
2199
+ name = 'Saturation';
2200
+ }
2201
+ if (!object.filters.find((x) => x.type == name)) {
2202
+ slider.slider.setValue(0);
2203
+ }
2204
+ });
2205
+ } else {
2206
+ sliders.forEach(function (slider) {
2207
+ slider.slider.setValue(0);
2208
+ });
2209
+ }
2210
+ } else {
2211
+ sliders.forEach(function (slider) {
2212
+ slider.slider.setValue(0);
2213
+ });
2214
+ }
2215
+ }
2216
+ }
2217
+ function removeFilters() {
2218
+ sliders.forEach(function (slider) {
2219
+ slider.slider.setValue(0);
2220
+ });
2221
+ }
2222
+ $(document).on('click', '#reset-filters', removeFilters);
2223
+
2224
+ function updateChromaValues() {
2225
+ if (canvas.getActiveObject()) {
2226
+ var obj = canvas.getActiveObject();
2227
+ if ($('.status-active').attr('id') == 'status-on') {
2228
+ if (obj.filters.find((x) => x.type == 'RemoveColor')) {
2229
+ obj.filters.find((x) => x.type == 'RemoveColor').distance =
2230
+ chromaslider.getValue() / 100;
2231
+ obj.filters.find((x) => x.type == 'RemoveColor').color = $(
2232
+ '#chroma-color input'
2233
+ ).val();
2234
+ } else {
2235
+ obj.filters.push(
2236
+ new f.RemoveColor({
2237
+ distance: chromaslider.getValue() / 100,
2238
+ color: $('#chroma-color input').val(),
2239
+ })
2240
+ );
2241
+ }
2242
+ obj.applyFilters();
2243
+ canvas.renderAll();
2244
+ save();
2245
+ } else {
2246
+ if (obj.filters.find((x) => x.type == 'RemoveColor')) {
2247
+ obj.filters = $.grep(obj.filters, function (i) {
2248
+ return i.type != 'RemoveColor';
2249
+ });
2250
+ obj.applyFilters();
2251
+ canvas.renderAll();
2252
+ save();
2253
+ }
2254
+ }
2255
+ }
2256
+ }
2257
+
2258
+ function updateChromaUI() {
2259
+ if (canvas.getActiveObject()) {
2260
+ var obj = canvas.getActiveObject();
2261
+ if (obj.filters) {
2262
+ if (obj.filters.length > 0) {
2263
+ if (obj.filters.find((x) => x.type == 'RemoveColor')) {
2264
+ $('.status-active').removeClass('status-active');
2265
+ $('#status-on').addClass('status-active');
2266
+ chromaslider.setValue(
2267
+ obj.filters.find((x) => x.type == 'RemoveColor').distance
2268
+ );
2269
+ $('#chroma-color input').val(
2270
+ obj.filters.find((x) => x.type == 'RemoveColor').color
2271
+ );
2272
+ $('#color-chroma-side').css(
2273
+ 'background-color',
2274
+ obj.filters.find((x) => x.type == 'RemoveColor').color
2275
+ );
2276
+ } else {
2277
+ $('.status-active').removeClass('status-active');
2278
+ $('#status-off').addClass('status-active');
2279
+ chromaslider.setValue(1);
2280
+ $('#chroma-color input').val('#FFFFFF');
2281
+ $('#color-chroma-side').css('background-color', '#FFFFF');
2282
+ }
2283
+ }
2284
+ }
2285
+ }
2286
+ }
2287
+
2288
+ function toggleChroma() {
2289
+ if (canvas.getActiveObject()) {
2290
+ $('.status-active').removeClass('status-active');
2291
+ $(this).addClass('status-active');
2292
+ updateChromaValues();
2293
+ }
2294
+ }
2295
+
2296
+ $(document).on(
2297
+ 'click',
2298
+ '.status-trigger:not(.status-active)',
2299
+ toggleChroma
2300
+ );
2301
+
2302
+ async function getColor() {
2303
+ try {
2304
+ const selectedColor = await eyeDropper.open();
2305
+ colormode = 'chroma';
2306
+ o_fill.setColor(selectedColor.sRGBHex);
2307
+ } catch (err) {}
2308
+ }
2309
+ $(document).on('click', '.pcr-current-color', getColor);
2310
+
2311
+ function closeFilters() {
2312
+ $('.show-filters').removeClass('show-filters');
2313
+ }
2314
+
2315
+ function openFilters() {
2316
+ $('#filters-parent').addClass('show-filters');
2317
+ }
2318
+
2319
+ $(document).on('click', '#filters-button', openFilters);
2320
+ $(document).on('click', '#filters-close', closeFilters);
2321
+
2322
+ function toggleSpeed(e) {
2323
+ e.stopPropagation();
2324
+ e.preventDefault();
2325
+ $('#speed-settings').toggleClass('show-speed');
2326
+ $('#speed-arrow').toggleClass('arrow-on');
2327
+ }
2328
+ function setSpeed(e) {
2329
+ e.stopPropagation();
2330
+ e.preventDefault();
2331
+ speed = parseFloat($(this).attr('data-speed'));
2332
+ $('#speed span').html($(this).html());
2333
+ toggleSpeed(e);
2334
+ save();
2335
+ }
2336
+
2337
+ $(document).on('click', '.speed', setSpeed);
2338
+ $(document).on('click', '#speed', toggleSpeed);
2339
+
2340
+ function showMore() {
2341
+ $('#more-over').css(
2342
+ 'top',
2343
+ $('#more-tool').offset().top + 5 - $('#more-over').height() / 4
2344
+ );
2345
+ $('#more-over').addClass('more-show');
2346
+ }
2347
+ function hideMore() {
2348
+ $('#more-over').removeClass('more-show');
2349
+ }
2350
+
2351
+ function handleLottieUpload() {
2352
+ var filething = $('#filepick3').get(0).files;
2353
+ var reader = new FileReader();
2354
+ reader.onload = function (event) {
2355
+ newLottieAnimation(
2356
+ artboard.get('left') + artboard.get('width') / 2,
2357
+ artboard.get('top') + artboard.get('height') / 2,
2358
+ event.target.result
2359
+ );
2360
+ };
2361
+ reader.readAsDataURL(filething.item(0));
2362
+ }
2363
+
2364
+ $(document).on('change', '#filepick3', handleLottieUpload);
2365
+
2366
+ function uploadLottie() {
2367
+ $('#filepick3').click();
2368
+ }
2369
+ $(document).on('click', '#upload-lottie', uploadLottie);
js/webm-writer2.js ADDED
@@ -0,0 +1,1165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * A tool for presenting an ArrayBuffer as a stream for writing some simple data
3
+ * types.
4
+ *
5
+ * By Nicholas Sherlock, with updates from jimbankoski
6
+ *
7
+ * - make it work off frames with timestamps from webcodecs
8
+ * - make it write via Native File IO apis instead of FileWriter
9
+ * - remove alpha and transparency
10
+ * -
11
+ *
12
+ * Released under the WTFPLv2 https://en.wikipedia.org/wiki/WTFPL
13
+ */
14
+
15
+ 'use strict';
16
+
17
+ (function() {
18
+ /*
19
+ * Create an ArrayBuffer of the given length and present it as a writable stream
20
+ * with methods for writing data in different formats.
21
+ */
22
+ let ArrayBufferDataStream = function(length) {
23
+ this.data = new Uint8Array(length);
24
+ this.pos = 0;
25
+ };
26
+
27
+ ArrayBufferDataStream.prototype.seek = function(toOffset) {
28
+ this.pos = toOffset;
29
+ };
30
+
31
+ ArrayBufferDataStream.prototype.writeBytes = function(arr) {
32
+ for (let i = 0; i < arr.length; i++) {
33
+ this.data[this.pos++] = arr[i];
34
+ }
35
+ };
36
+
37
+ ArrayBufferDataStream.prototype.writeByte = function(b) {
38
+ this.data[this.pos++] = b;
39
+ };
40
+
41
+ // Synonym:
42
+ ArrayBufferDataStream.prototype.writeU8 =
43
+ ArrayBufferDataStream.prototype.writeByte;
44
+
45
+ ArrayBufferDataStream.prototype.writeU16BE = function(u) {
46
+ this.data[this.pos++] = u >> 8;
47
+ this.data[this.pos++] = u;
48
+ };
49
+
50
+ ArrayBufferDataStream.prototype.writeDoubleBE = function(d) {
51
+ let bytes = new Uint8Array(new Float64Array([d]).buffer);
52
+
53
+ for (let i = bytes.length - 1; i >= 0; i--) {
54
+ this.writeByte(bytes[i]);
55
+ }
56
+ };
57
+
58
+ ArrayBufferDataStream.prototype.writeFloatBE = function(d) {
59
+ let bytes = new Uint8Array(new Float32Array([d]).buffer);
60
+
61
+ for (let i = bytes.length - 1; i >= 0; i--) {
62
+ this.writeByte(bytes[i]);
63
+ }
64
+ };
65
+
66
+ /**
67
+ * Write an ASCII string to the stream
68
+ */
69
+ ArrayBufferDataStream.prototype.writeString = function(s) {
70
+ for (let i = 0; i < s.length; i++) {
71
+ this.data[this.pos++] = s.charCodeAt(i);
72
+ }
73
+ };
74
+
75
+ /**
76
+ * Write the given 32-bit integer to the stream as an EBML variable-length
77
+ * integer using the given byte width (use measureEBMLVarInt).
78
+ *
79
+ * No error checking is performed to ensure that the supplied width is correct
80
+ * for the integer.
81
+ *
82
+ * @param i Integer to be written
83
+ * @param width Number of bytes to write to the stream
84
+ */
85
+ ArrayBufferDataStream.prototype.writeEBMLVarIntWidth = function(i, width) {
86
+ switch (width) {
87
+ case 1:
88
+ this.writeU8((1 << 7) | i);
89
+ break;
90
+ case 2:
91
+ this.writeU8((1 << 6) | (i >> 8));
92
+ this.writeU8(i);
93
+ break;
94
+ case 3:
95
+ this.writeU8((1 << 5) | (i >> 16));
96
+ this.writeU8(i >> 8);
97
+ this.writeU8(i);
98
+ break;
99
+ case 4:
100
+ this.writeU8((1 << 4) | (i >> 24));
101
+ this.writeU8(i >> 16);
102
+ this.writeU8(i >> 8);
103
+ this.writeU8(i);
104
+ break;
105
+ case 5:
106
+ /*
107
+ * JavaScript converts its doubles to 32-bit integers for bitwise
108
+ * operations, so we need to do a division by 2^32 instead of a
109
+ * right-shift of 32 to retain those top 3 bits
110
+ */
111
+ this.writeU8((1 << 3) | ((i / 4294967296) & 0x7));
112
+ this.writeU8(i >> 24);
113
+ this.writeU8(i >> 16);
114
+ this.writeU8(i >> 8);
115
+ this.writeU8(i);
116
+ break;
117
+ default:
118
+ throw new Error('Bad EBML VINT size ' + width);
119
+ }
120
+ };
121
+
122
+ /**
123
+ * Return the number of bytes needed to encode the given integer as an EBML
124
+ * VINT.
125
+ */
126
+ ArrayBufferDataStream.prototype.measureEBMLVarInt = function(val) {
127
+ if (val < (1 << 7) - 1) {
128
+ /* Top bit is set, leaving 7 bits to hold the integer, but we can't store
129
+ * 127 because "all bits set to one" is a reserved value. Same thing for the
130
+ * other cases below:
131
+ */
132
+ return 1;
133
+ } else if (val < (1 << 14) - 1) {
134
+ return 2;
135
+ } else if (val < (1 << 21) - 1) {
136
+ return 3;
137
+ } else if (val < (1 << 28) - 1) {
138
+ return 4;
139
+ } else if (val < 34359738367) { // 2 ^ 35 - 1 (can address 32GB)
140
+ return 5;
141
+ } else {
142
+ throw new Error('EBML VINT size not supported ' + val);
143
+ }
144
+ };
145
+
146
+ ArrayBufferDataStream.prototype.writeEBMLVarInt = function(i) {
147
+ this.writeEBMLVarIntWidth(i, this.measureEBMLVarInt(i));
148
+ };
149
+
150
+ /**
151
+ * Write the given unsigned 32-bit integer to the stream in big-endian order
152
+ * using the given byte width. No error checking is performed to ensure that the
153
+ * supplied width is correct for the integer.
154
+ *
155
+ * Omit the width parameter to have it determined automatically for you.
156
+ *
157
+ * @param u Unsigned integer to be written
158
+ * @param width Number of bytes to write to the stream
159
+ */
160
+ ArrayBufferDataStream.prototype.writeUnsignedIntBE = function(u, width) {
161
+ if (width === undefined) {
162
+ width = this.measureUnsignedInt(u);
163
+ }
164
+
165
+ // Each case falls through:
166
+ switch (width) {
167
+ case 5:
168
+ this.writeU8(
169
+ Math.floor(u / 4294967296)); // Need to use division to access >32
170
+ // bits of floating point var
171
+ case 4:
172
+ this.writeU8(u >> 24);
173
+ case 3:
174
+ this.writeU8(u >> 16);
175
+ case 2:
176
+ this.writeU8(u >> 8);
177
+ case 1:
178
+ this.writeU8(u);
179
+ break;
180
+ default:
181
+ throw new Error('Bad UINT size ' + width);
182
+ }
183
+ };
184
+
185
+ /**
186
+ * Return the number of bytes needed to hold the non-zero bits of the given
187
+ * unsigned integer.
188
+ */
189
+ ArrayBufferDataStream.prototype.measureUnsignedInt = function(val) {
190
+ // Force to 32-bit unsigned integer
191
+ if (val < (1 << 8)) {
192
+ return 1;
193
+ } else if (val < (1 << 16)) {
194
+ return 2;
195
+ } else if (val < (1 << 24)) {
196
+ return 3;
197
+ } else if (val < 4294967296) {
198
+ return 4;
199
+ } else {
200
+ return 5;
201
+ }
202
+ };
203
+
204
+ /**
205
+ * Return a view on the portion of the buffer from the beginning to the current
206
+ * seek position as a Uint8Array.
207
+ */
208
+ ArrayBufferDataStream.prototype.getAsDataArray = function() {
209
+ if (this.pos < this.data.byteLength) {
210
+ return this.data.subarray(0, this.pos);
211
+ } else if (this.pos == this.data.byteLength) {
212
+ return this.data;
213
+ } else {
214
+ throw new Error('ArrayBufferDataStream\'s pos lies beyond end of buffer');
215
+ }
216
+ };
217
+
218
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
219
+ module.exports = ArrayBufferDataStream;
220
+ } else {
221
+ self.ArrayBufferDataStream = ArrayBufferDataStream;
222
+ }
223
+ }());
224
+ 'use strict';
225
+
226
+ /**
227
+ * Allows a series of Blob-convertible objects (ArrayBuffer, Blob, String, etc)
228
+ * to be added to a buffer. Seeking and overwriting of blobs is allowed.
229
+ *
230
+ * You can supply a FileWriter, in which case the BlobBuffer is just used as
231
+ * temporary storage before it writes it through to the disk.
232
+ *
233
+ * By Nicholas Sherlock
234
+ *
235
+ * Released under the WTFPLv2 https://en.wikipedia.org/wiki/WTFPL
236
+ */
237
+ (function() {
238
+ let BlobBuffer = function(fs) {
239
+ return function(destination) {
240
+ let buffer = [], writePromise = Promise.resolve(), fileWriter = null,
241
+ fd = null;
242
+
243
+ if (destination &&
244
+ destination.constructor.name === 'FileSystemWritableFileStream') {
245
+ fileWriter = destination;
246
+ } else if (fs && destination) {
247
+ fd = destination;
248
+ }
249
+
250
+ // Current seek offset
251
+ this.pos = 0;
252
+
253
+ // One more than the index of the highest byte ever written
254
+ this.length = 0;
255
+
256
+ // Returns a promise that converts the blob to an ArrayBuffer
257
+ function readBlobAsBuffer(blob) {
258
+ return new Promise(function(resolve, reject) {
259
+ let reader = new FileReader();
260
+
261
+ reader.addEventListener('loadend', function() {
262
+ resolve(reader.result);
263
+ });
264
+
265
+ reader.readAsArrayBuffer(blob);
266
+ });
267
+ }
268
+
269
+ function convertToUint8Array(thing) {
270
+ return new Promise(function(resolve, reject) {
271
+ if (thing instanceof Uint8Array) {
272
+ resolve(thing);
273
+ } else if (thing instanceof ArrayBuffer || ArrayBuffer.isView(thing)) {
274
+ resolve(new Uint8Array(thing));
275
+ } else if (thing instanceof Blob) {
276
+ resolve(readBlobAsBuffer(thing).then(function(buffer) {
277
+ return new Uint8Array(buffer);
278
+ }));
279
+ } else {
280
+ // Assume that Blob will know how to read this thing
281
+ resolve(readBlobAsBuffer(new Blob([thing])).then(function(buffer) {
282
+ return new Uint8Array(buffer);
283
+ }));
284
+ }
285
+ });
286
+ }
287
+
288
+ function measureData(data) {
289
+ let result = data.byteLength || data.length || data.size;
290
+
291
+ if (!Number.isInteger(result)) {
292
+ throw new Error('Failed to determine size of element');
293
+ }
294
+
295
+ return result;
296
+ }
297
+
298
+ /**
299
+ * Seek to the given absolute offset.
300
+ *
301
+ * You may not seek beyond the end of the file (this would create a hole
302
+ * and/or allow blocks to be written in non- sequential order, which isn't
303
+ * currently supported by the memory buffer backend).
304
+ */
305
+ this.seek = function(offset) {
306
+ if (offset < 0) {
307
+ throw new Error('Offset may not be negative');
308
+ }
309
+
310
+ if (isNaN(offset)) {
311
+ throw new Error('Offset may not be NaN');
312
+ }
313
+
314
+ if (offset > this.length) {
315
+ throw new Error('Seeking beyond the end of file is not allowed');
316
+ }
317
+
318
+ this.pos = offset;
319
+ };
320
+
321
+ /**
322
+ * Write the Blob-convertible data to the buffer at the current seek
323
+ * position.
324
+ *
325
+ * Note: If overwriting existing data, the write must not cross preexisting
326
+ * block boundaries (written data must be fully contained by the extent of a
327
+ * previous write).
328
+ */
329
+ this.write = function(data) {
330
+ let newEntry = {offset: this.pos, data: data, length: measureData(data)},
331
+ isAppend = newEntry.offset >= this.length;
332
+
333
+ this.pos += newEntry.length;
334
+ this.length = Math.max(this.length, this.pos);
335
+
336
+ // After previous writes complete, perform our write
337
+ writePromise = writePromise.then(async function() {
338
+ if (fd) {
339
+ return new Promise(function(resolve, reject) {
340
+ convertToUint8Array(newEntry.data).then(function(dataArray) {
341
+ let totalWritten = 0, buffer = Buffer.from(dataArray.buffer),
342
+
343
+ handleWriteComplete = function(err, written, buffer) {
344
+ totalWritten += written;
345
+
346
+ if (totalWritten >= buffer.length) {
347
+ resolve();
348
+ } else {
349
+ // We still have more to write...
350
+ fs.write(
351
+ fd, buffer, totalWritten,
352
+ buffer.length - totalWritten,
353
+ newEntry.offset + totalWritten, handleWriteComplete);
354
+ }
355
+ };
356
+
357
+ fs.write(
358
+ fd, buffer, 0, buffer.length, newEntry.offset,
359
+ handleWriteComplete);
360
+ });
361
+ });
362
+ } else if (fileWriter) {
363
+ return new Promise(function(resolve, reject) {
364
+ fileWriter.seek(newEntry.offset)
365
+ .then(() => {fileWriter.write(new Blob([newEntry.data]))})
366
+ .then(() => {resolve();
367
+ })
368
+ });
369
+ } else if (!isAppend) {
370
+ // We might be modifying a write that was already buffered in memory.
371
+
372
+ // Slow linear search to find a block we might be overwriting
373
+ for (let i = 0; i < buffer.length; i++) {
374
+ let entry = buffer[i];
375
+
376
+ // If our new entry overlaps the old one in any way...
377
+ if (!(newEntry.offset + newEntry.length <= entry.offset ||
378
+ newEntry.offset >= entry.offset + entry.length)) {
379
+ if (newEntry.offset < entry.offset ||
380
+ newEntry.offset + newEntry.length >
381
+ entry.offset + entry.length) {
382
+ throw new Error('Overwrite crosses blob boundaries');
383
+ }
384
+
385
+ if (newEntry.offset == entry.offset &&
386
+ newEntry.length == entry.length) {
387
+ // We overwrote the entire block
388
+ entry.data = newEntry.data;
389
+
390
+ // We're done
391
+ return;
392
+ } else {
393
+ return convertToUint8Array(entry.data)
394
+ .then(function(entryArray) {
395
+ entry.data = entryArray;
396
+
397
+ return convertToUint8Array(newEntry.data);
398
+ })
399
+ .then(function(newEntryArray) {
400
+ newEntry.data = newEntryArray;
401
+
402
+ entry.data.set(
403
+ newEntry.data, newEntry.offset - entry.offset);
404
+ });
405
+ }
406
+ }
407
+ }
408
+ // Else fall through to do a simple append, as we didn't overwrite any
409
+ // pre-existing blocks
410
+ }
411
+
412
+ buffer.push(newEntry);
413
+ });
414
+ };
415
+
416
+ /**
417
+ * Finish all writes to the buffer, returning a promise that signals when
418
+ * that is complete.
419
+ *
420
+ * If a FileWriter was not provided, the promise is resolved with a Blob
421
+ * that represents the completed BlobBuffer contents. You can optionally
422
+ * pass in a mimeType to be used for this blob.
423
+ *
424
+ * If a FileWriter was provided, the promise is resolved with null as the
425
+ * first argument.
426
+ */
427
+ this.complete = function(mimeType) {
428
+ if (fd || fileWriter) {
429
+ writePromise = writePromise.then(function() {
430
+ return null;
431
+ });
432
+ } else {
433
+ // After writes complete we need to merge the buffer to give to the
434
+ // caller
435
+ writePromise = writePromise.then(function() {
436
+ let result = [];
437
+
438
+ for (let i = 0; i < buffer.length; i++) {
439
+ result.push(buffer[i].data);
440
+ }
441
+
442
+ return new Blob(result, {type: mimeType});
443
+ });
444
+ }
445
+
446
+ return writePromise;
447
+ };
448
+ };
449
+ };
450
+
451
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
452
+ module.exports = BlobBuffer(require('fs'));
453
+ } else {
454
+ self.BlobBuffer = BlobBuffer(null);
455
+ }
456
+ })();
457
+ /**
458
+ * WebM video encoder for Google Chrome. This implementation is suitable for
459
+ * creating very large video files, because it can stream Blobs directly to a
460
+ * FileWriter without buffering the entire video in memory.
461
+ *
462
+ * When FileWriter is not available or not desired, it can buffer the video in
463
+ * memory as a series of Blobs which are eventually returned as one composite
464
+ * Blob.
465
+ *
466
+ * By Nicholas Sherlock.
467
+ *
468
+ * Based on the ideas from Whammy: https://github.com/antimatter15/whammy
469
+ *
470
+ * Released under the WTFPLv2 https://en.wikipedia.org/wiki/WTFPL
471
+ */
472
+
473
+ 'use strict';
474
+
475
+ (function() {
476
+ function extend(base, top) {
477
+ let target = {};
478
+
479
+ [base, top].forEach(function(obj) {
480
+ for (let prop in obj) {
481
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
482
+ target[prop] = obj[prop];
483
+ }
484
+ }
485
+ });
486
+
487
+ return target;
488
+ }
489
+
490
+ /**
491
+ * @param {String} string
492
+ * @returns {number}
493
+ */
494
+ function byteStringToUint32LE(string) {
495
+ let a = string.charCodeAt(0), b = string.charCodeAt(1),
496
+ c = string.charCodeAt(2), d = string.charCodeAt(3);
497
+
498
+ return (a | (b << 8) | (c << 16) | (d << 24)) >>> 0;
499
+ }
500
+
501
+
502
+ // Just a little utility so we can tag values as floats for the EBML encoder's
503
+ // benefit
504
+ function EBMLFloat32(value) {
505
+ this.value = value;
506
+ }
507
+
508
+ function EBMLFloat64(value) {
509
+ this.value = value;
510
+ }
511
+
512
+ /**
513
+ * Write the given EBML object to the provided ArrayBufferStream.
514
+ *
515
+ * @param buffer
516
+ * @param {Number} bufferFileOffset - The buffer's first byte is at this
517
+ * position inside the video file.
518
+ * This is used to complete offset and
519
+ * dataOffset fields in each EBML structure, indicating the file offset of the
520
+ * first byte of the EBML element and its data payload.
521
+ * @param {*} ebml
522
+ */
523
+ function writeEBML(buffer, bufferFileOffset, ebml) {
524
+ // Is the ebml an array of sibling elements?
525
+ if (Array.isArray(ebml)) {
526
+ for (let i = 0; i < ebml.length; i++) {
527
+ writeEBML(buffer, bufferFileOffset, ebml[i]);
528
+ }
529
+ // Is this some sort of raw data that we want to write directly?
530
+ } else if (typeof ebml === 'string') {
531
+ buffer.writeString(ebml);
532
+ } else if (ebml instanceof Uint8Array) {
533
+ buffer.writeBytes(ebml);
534
+ } else if (ebml.id) {
535
+ // We're writing an EBML element
536
+ ebml.offset = buffer.pos + bufferFileOffset;
537
+
538
+ buffer.writeUnsignedIntBE(ebml.id); // ID field
539
+
540
+ // Now we need to write the size field, so we must know the payload size:
541
+
542
+ if (Array.isArray(ebml.data)) {
543
+ // Writing an array of child elements. We won't try to measure the size of
544
+ // the children up-front
545
+
546
+ let sizePos, dataBegin, dataEnd;
547
+
548
+ if (ebml.size === -1) {
549
+ // Write the reserved all-one-bits marker to note that the size of this
550
+ // element is unknown/unbounded
551
+ buffer.writeByte(0xFF);
552
+ } else {
553
+ sizePos = buffer.pos;
554
+
555
+ /* Write a dummy size field to overwrite later. 4 bytes allows an
556
+ * element maximum size of 256MB, which should be plenty (we don't want
557
+ * to have to buffer that much data in memory at one time anyway!)
558
+ */
559
+ buffer.writeBytes([0, 0, 0, 0]);
560
+ }
561
+
562
+ dataBegin = buffer.pos;
563
+
564
+ ebml.dataOffset = dataBegin + bufferFileOffset;
565
+ writeEBML(buffer, bufferFileOffset, ebml.data);
566
+
567
+ if (ebml.size !== -1) {
568
+ dataEnd = buffer.pos;
569
+
570
+ ebml.size = dataEnd - dataBegin;
571
+
572
+ buffer.seek(sizePos);
573
+ buffer.writeEBMLVarIntWidth(ebml.size, 4); // Size field
574
+
575
+ buffer.seek(dataEnd);
576
+ }
577
+ } else if (typeof ebml.data === 'string') {
578
+ buffer.writeEBMLVarInt(ebml.data.length); // Size field
579
+ ebml.dataOffset = buffer.pos + bufferFileOffset;
580
+ buffer.writeString(ebml.data);
581
+ } else if (typeof ebml.data === 'number') {
582
+ // Allow the caller to explicitly choose the size if they wish by
583
+ // supplying a size field
584
+ if (!ebml.size) {
585
+ ebml.size = buffer.measureUnsignedInt(ebml.data);
586
+ }
587
+
588
+ buffer.writeEBMLVarInt(ebml.size); // Size field
589
+ ebml.dataOffset = buffer.pos + bufferFileOffset;
590
+ buffer.writeUnsignedIntBE(ebml.data, ebml.size);
591
+ } else if (ebml.data instanceof EBMLFloat64) {
592
+ buffer.writeEBMLVarInt(8); // Size field
593
+ ebml.dataOffset = buffer.pos + bufferFileOffset;
594
+ buffer.writeDoubleBE(ebml.data.value);
595
+ } else if (ebml.data instanceof EBMLFloat32) {
596
+ buffer.writeEBMLVarInt(4); // Size field
597
+ ebml.dataOffset = buffer.pos + bufferFileOffset;
598
+ buffer.writeFloatBE(ebml.data.value);
599
+ } else if (ebml.data instanceof Uint8Array) {
600
+ buffer.writeEBMLVarInt(ebml.data.byteLength); // Size field
601
+ ebml.dataOffset = buffer.pos + bufferFileOffset;
602
+ buffer.writeBytes(ebml.data);
603
+ } else {
604
+ throw new Error('Bad EBML datatype ' + typeof ebml.data);
605
+ }
606
+ } else {
607
+ throw new Error('Bad EBML datatype ' + typeof ebml.data);
608
+ }
609
+ }
610
+
611
+ /**
612
+ * @typedef {Object} Frame
613
+ * @property {string} frame - Raw VP8 frame data
614
+ * @property {Number} trackNumber - From 1 to 126 (inclusive)
615
+ * @property {Number} timecode
616
+ */
617
+
618
+ /**
619
+ * @typedef {Object} Cluster
620
+ * @property {Number} timecode - Start time for the cluster
621
+ */
622
+
623
+ /**
624
+ * @param ArrayBufferDataStream - Imported library
625
+ * @param BlobBuffer - Imported library
626
+ *
627
+ * @returns WebMWriter
628
+ *
629
+ * @constructor
630
+ */
631
+ let WebMWriter = function(ArrayBufferDataStream, BlobBuffer) {
632
+ return function(options) {
633
+ let MAX_CLUSTER_DURATION_MSEC = 5000000, DEFAULT_TRACK_NUMBER = 1,
634
+ writtenHeader = false, videoWidth = 0, videoHeight = 0,
635
+ firstTimestampEver = true, earliestTimestamp = 0,
636
+
637
+
638
+ /**
639
+ *
640
+ * @type {Frame[]}
641
+ */
642
+ clusterFrameBuffer = [], clusterStartTime = 0, clusterDuration = 0,
643
+ lastTimeCode = 0,
644
+
645
+ optionDefaults = {
646
+ fileWriter: null, // Chrome FileWriter in order to stream to a file
647
+ // instead of buffering to memory (optional)
648
+ fd: null, // Node.JS file descriptor to write to instead of buffering
649
+ // (optional)
650
+ codec: 'VP8', // Codec to write to webm file
651
+
652
+ },
653
+
654
+ seekPoints = {
655
+ Cues: {id: new Uint8Array([0x1C, 0x53, 0xBB, 0x6B]), positionEBML: null},
656
+ SegmentInfo:
657
+ {id: new Uint8Array([0x15, 0x49, 0xA9, 0x66]), positionEBML: null},
658
+ Tracks:
659
+ {id: new Uint8Array([0x16, 0x54, 0xAE, 0x6B]), positionEBML: null},
660
+ },
661
+
662
+ ebmlSegment, // Root element of the EBML document
663
+
664
+ segmentDuration = {
665
+ 'id': 0x4489, // Duration
666
+ 'data': new EBMLFloat64(0)
667
+ },
668
+
669
+ seekHead,
670
+
671
+ cues = [],
672
+
673
+ blobBuffer = new BlobBuffer(options.fileWriter || options.fd);
674
+
675
+ function fileOffsetToSegmentRelative(fileOffset) {
676
+ return fileOffset - ebmlSegment.dataOffset;
677
+ }
678
+
679
+
680
+ /**
681
+ * Create a SeekHead element with descriptors for the points in the global
682
+ * seekPoints array.
683
+ *
684
+ * 5 bytes of position values are reserved for each node, which lie at the
685
+ * offset point.positionEBML.dataOffset, to be overwritten later.
686
+ */
687
+ function createSeekHead() {
688
+ let seekPositionEBMLTemplate = {
689
+ 'id': 0x53AC, // SeekPosition
690
+ 'size': 5, // Allows for 32GB video files
691
+ 'data': 0 // We'll overwrite this when the file is complete
692
+ },
693
+
694
+ result = {
695
+ 'id': 0x114D9B74, // SeekHead
696
+ 'data': []
697
+ };
698
+
699
+ for (let name in seekPoints) {
700
+ let seekPoint = seekPoints[name];
701
+
702
+ seekPoint.positionEBML = Object.create(seekPositionEBMLTemplate);
703
+
704
+ result.data.push({
705
+ 'id': 0x4DBB, // Seek
706
+ 'data': [
707
+ {
708
+ 'id': 0x53AB, // SeekID
709
+ 'data': seekPoint.id
710
+ },
711
+ seekPoint.positionEBML
712
+ ]
713
+ });
714
+ }
715
+
716
+ return result;
717
+ }
718
+
719
+ /**
720
+ * Write the WebM file header to the stream.
721
+ */
722
+ function writeHeader() {
723
+ seekHead = createSeekHead();
724
+
725
+ let ebmlHeader = {
726
+ 'id': 0x1a45dfa3, // EBML
727
+ 'data': [
728
+ {
729
+ 'id': 0x4286, // EBMLVersion
730
+ 'data': 1
731
+ },
732
+ {
733
+ 'id': 0x42f7, // EBMLReadVersion
734
+ 'data': 1
735
+ },
736
+ {
737
+ 'id': 0x42f2, // EBMLMaxIDLength
738
+ 'data': 4
739
+ },
740
+ {
741
+ 'id': 0x42f3, // EBMLMaxSizeLength
742
+ 'data': 8
743
+ },
744
+ {
745
+ 'id': 0x4282, // DocType
746
+ 'data': 'webm'
747
+ },
748
+ {
749
+ 'id': 0x4287, // DocTypeVersion
750
+ 'data': 2
751
+ },
752
+ {
753
+ 'id': 0x4285, // DocTypeReadVersion
754
+ 'data': 2
755
+ }
756
+ ]
757
+ },
758
+
759
+ segmentInfo = {
760
+ 'id': 0x1549a966, // Info
761
+ 'data': [
762
+ {
763
+ 'id': 0x2ad7b1, // TimecodeScale
764
+ 'data': 1e6 // Times will be in microseconds (1e6 nanoseconds
765
+ // per step = 1ms)
766
+ },
767
+ {
768
+ 'id': 0x4d80, // MuxingApp
769
+ 'data': 'webm-writer-js',
770
+ },
771
+ {
772
+ 'id': 0x5741, // WritingApp
773
+ 'data': 'webm-writer-js'
774
+ },
775
+ segmentDuration // To be filled in later
776
+ ]
777
+ },
778
+
779
+ videoProperties = [
780
+ {
781
+ 'id': 0xb0, // PixelWidth
782
+ 'data': videoWidth
783
+ },
784
+ {
785
+ 'id': 0xba, // PixelHeight
786
+ 'data': videoHeight
787
+ }
788
+ ];
789
+
790
+ let tracks = {
791
+ 'id': 0x1654ae6b, // Tracks
792
+ 'data': [{
793
+ 'id': 0xae, // TrackEntry
794
+ 'data': [
795
+ {
796
+ 'id': 0xd7, // TrackNumber
797
+ 'data': DEFAULT_TRACK_NUMBER
798
+ },
799
+ {
800
+ 'id': 0x73c5, // TrackUID
801
+ 'data': DEFAULT_TRACK_NUMBER
802
+ },
803
+ {
804
+ 'id': 0x83, // TrackType
805
+ 'data': 1
806
+ },
807
+ {
808
+ 'id': 0xe0, // Video
809
+ 'data': videoProperties
810
+ },
811
+ {
812
+ 'id': 0x9c, // FlagLacing
813
+ 'data': 0
814
+ },
815
+ {
816
+ 'id': 0x22b59c, // Language
817
+ 'data': 'und'
818
+ },
819
+ {
820
+ 'id': 0xb9, // FlagEnabled
821
+ 'data': 1
822
+ },
823
+ {
824
+ 'id': 0x88, // FlagDefault
825
+ 'data': 1
826
+ },
827
+ {
828
+ 'id': 0x55aa, // FlagForced
829
+ 'data': 0
830
+ },
831
+
832
+ {
833
+ 'id': 0x86, // CodecID
834
+ 'data': 'V_' + options.codec
835
+ }, /*
836
+ (options.codec == 'VP8' ?
837
+ {
838
+ 'id': 0x63A2, // Codec private data
839
+ 'data': []
840
+ } :
841
+ {
842
+ 'id': 0x63A2, // Codec private data for vp9
843
+ 'data': [
844
+ {
845
+ 'id': 1, // vp9 Profile
846
+ 'size': 1,
847
+ 'data': 0
848
+ },
849
+ {
850
+ 'id': 2, // Feature level
851
+ 'size': 1,
852
+ 'data': 10
853
+ },
854
+ {
855
+ 'id': 3, // bitdepth level
856
+ 'size': 1,
857
+ 'data': 8
858
+ },
859
+ {
860
+ 'id': 4, // color sampling
861
+ 'size': 1,
862
+ 'data': 0
863
+ }
864
+ ]
865
+ }),
866
+ {
867
+ 'id': 0x258688, // CodecName
868
+ 'data': options.codec
869
+ },*/
870
+ ]
871
+ }]
872
+ };
873
+
874
+ ebmlSegment = {
875
+ 'id': 0x18538067, // Segment
876
+ 'size': -1, // Unbounded size
877
+ 'data': [
878
+ seekHead,
879
+ segmentInfo,
880
+ tracks,
881
+ ]
882
+ };
883
+
884
+ let bufferStream = new ArrayBufferDataStream(256);
885
+
886
+ writeEBML(bufferStream, blobBuffer.pos, [ebmlHeader, ebmlSegment]);
887
+ blobBuffer.write(bufferStream.getAsDataArray());
888
+
889
+ // Now we know where these top-level elements lie in the file:
890
+ seekPoints.SegmentInfo.positionEBML.data =
891
+ fileOffsetToSegmentRelative(segmentInfo.offset);
892
+ seekPoints.Tracks.positionEBML.data =
893
+ fileOffsetToSegmentRelative(tracks.offset);
894
+
895
+ writtenHeader = true;
896
+ }
897
+
898
+ /**
899
+ * Create a SimpleBlock element to hold the given frame.
900
+ *
901
+ * @param {Frame} frame
902
+ *
903
+ * @return A SimpleBlock EBML element.
904
+ */
905
+ function createSimpleBlockForframe(frame) {
906
+ let bufferStream = new ArrayBufferDataStream(1 + 2 + 1);
907
+
908
+ if (!(frame.trackNumber > 0 && frame.trackNumber < 127)) {
909
+ throw new Error('TrackNumber must be > 0 and < 127');
910
+ }
911
+
912
+ bufferStream.writeEBMLVarInt(
913
+ frame.trackNumber); // Always 1 byte since we limit the range of
914
+ // trackNumber
915
+ bufferStream.writeU16BE(frame.timecode);
916
+
917
+ // Flags byte
918
+ bufferStream.writeByte(
919
+ (frame.type == "key" ? 1 : 0) << 7 // frame
920
+ );
921
+
922
+ return {
923
+ 'id': 0xA3, // SimpleBlock
924
+ 'data': [bufferStream.getAsDataArray(), frame.frame]
925
+ };
926
+ }
927
+
928
+ /**
929
+ * Create a Cluster EBML node.
930
+ *
931
+ * @param {Cluster} cluster
932
+ *
933
+ * Returns an EBML element.
934
+ */
935
+ function createCluster(cluster) {
936
+ return {
937
+ 'id': 0x1f43b675,
938
+ 'data': [{
939
+ 'id': 0xe7, // Timecode
940
+ 'data': Math.round(cluster.timecode)
941
+ }]
942
+ };
943
+ }
944
+
945
+ function addCuePoint(trackIndex, clusterTime, clusterFileOffset) {
946
+ cues.push({
947
+ 'id': 0xBB, // Cue
948
+ 'data': [
949
+ {
950
+ 'id': 0xB3, // CueTime
951
+ 'data': clusterTime
952
+ },
953
+ {
954
+ 'id': 0xB7, // CueTrackPositions
955
+ 'data': [
956
+ {
957
+ 'id': 0xF7, // CueTrack
958
+ 'data': trackIndex
959
+ },
960
+ {
961
+ 'id': 0xF1, // CueClusterPosition
962
+ 'data': fileOffsetToSegmentRelative(clusterFileOffset)
963
+ }
964
+ ]
965
+ }
966
+ ]
967
+ });
968
+ }
969
+
970
+ /**
971
+ * Write a Cues element to the blobStream using the global `cues` array of
972
+ * CuePoints (use addCuePoint()). The seek entry for the Cues in the
973
+ * SeekHead is updated.
974
+ */
975
+ function writeCues() {
976
+ let ebml = {'id': 0x1C53BB6B, 'data': cues},
977
+
978
+ cuesBuffer = new ArrayBufferDataStream(
979
+ 16 +
980
+ cues.length *
981
+ 32); // Pretty crude estimate of the buffer size we'll need
982
+
983
+ writeEBML(cuesBuffer, blobBuffer.pos, ebml);
984
+ blobBuffer.write(cuesBuffer.getAsDataArray());
985
+
986
+ // Now we know where the Cues element has ended up, we can update the
987
+ // SeekHead
988
+ seekPoints.Cues.positionEBML.data =
989
+ fileOffsetToSegmentRelative(ebml.offset);
990
+ }
991
+
992
+ /**
993
+ * Flush the frames in the current clusterFrameBuffer out to the stream as a
994
+ * Cluster.
995
+ */
996
+ function flushClusterFrameBuffer() {
997
+ if (clusterFrameBuffer.length === 0) {
998
+ return;
999
+ }
1000
+
1001
+ // First work out how large of a buffer we need to hold the cluster data
1002
+ let rawImageSize = 0;
1003
+
1004
+ for (let i = 0; i < clusterFrameBuffer.length; i++) {
1005
+ rawImageSize += clusterFrameBuffer[i].frame.byteLength;
1006
+ }
1007
+
1008
+ let buffer = new ArrayBufferDataStream(
1009
+ rawImageSize +
1010
+ clusterFrameBuffer.length *
1011
+ 64), // Estimate 64 bytes per block header
1012
+
1013
+ cluster = createCluster({
1014
+ timecode: Math.round(clusterStartTime),
1015
+ });
1016
+
1017
+ for (let i = 0; i < clusterFrameBuffer.length; i++) {
1018
+ cluster.data.push(createSimpleBlockForframe(clusterFrameBuffer[i]));
1019
+ }
1020
+
1021
+ writeEBML(buffer, blobBuffer.pos, cluster);
1022
+ blobBuffer.write(buffer.getAsDataArray());
1023
+
1024
+ addCuePoint(
1025
+ DEFAULT_TRACK_NUMBER, Math.round(clusterStartTime), cluster.offset);
1026
+
1027
+ clusterFrameBuffer = [];
1028
+ clusterDuration = 0;
1029
+ }
1030
+
1031
+ function validateOptions() {
1032
+ }
1033
+
1034
+ /**
1035
+ *
1036
+ * @param {Frame} frame
1037
+ */
1038
+ function addFrameToCluster(frame) {
1039
+ frame.trackNumber = DEFAULT_TRACK_NUMBER;
1040
+ var time = frame.intime / 1000;
1041
+ if (firstTimestampEver) {
1042
+ earliestTimestamp = time;
1043
+ time = 0;
1044
+ firstTimestampEver = false;
1045
+ } else {
1046
+ time = time - earliestTimestamp;
1047
+ }
1048
+ lastTimeCode = time;
1049
+ if (clusterDuration == 0) clusterStartTime = time;
1050
+
1051
+ // Frame timecodes are relative to the start of their cluster:
1052
+ // frame.timecode = Math.round(clusterDuration);
1053
+ frame.timecode = Math.round(time - clusterStartTime);
1054
+
1055
+ clusterFrameBuffer.push(frame);
1056
+ clusterDuration = frame.timecode + 1;
1057
+
1058
+ if (clusterDuration >= MAX_CLUSTER_DURATION_MSEC) {
1059
+ flushClusterFrameBuffer();
1060
+ }
1061
+ }
1062
+
1063
+ /**
1064
+ * Rewrites the SeekHead element that was initially written to the stream
1065
+ * with the offsets of top level elements.
1066
+ *
1067
+ * Call once writing is complete (so the offset of all top level elements
1068
+ * is known).
1069
+ */
1070
+ function rewriteSeekHead() {
1071
+ let seekHeadBuffer = new ArrayBufferDataStream(seekHead.size),
1072
+ oldPos = blobBuffer.pos;
1073
+
1074
+ // Write the rewritten SeekHead element's data payload to the stream
1075
+ // (don't need to update the id or size)
1076
+ writeEBML(seekHeadBuffer, seekHead.dataOffset, seekHead.data);
1077
+
1078
+ // And write that through to the file
1079
+ blobBuffer.seek(seekHead.dataOffset);
1080
+ blobBuffer.write(seekHeadBuffer.getAsDataArray());
1081
+ blobBuffer.seek(oldPos);
1082
+ }
1083
+
1084
+ /**
1085
+ * Rewrite the Duration field of the Segment with the newly-discovered
1086
+ * video duration.
1087
+ */
1088
+ function rewriteDuration() {
1089
+ let buffer = new ArrayBufferDataStream(8), oldPos = blobBuffer.pos;
1090
+
1091
+ // Rewrite the data payload (don't need to update the id or size)
1092
+ buffer.writeDoubleBE(lastTimeCode);
1093
+
1094
+ // And write that through to the file
1095
+ blobBuffer.seek(segmentDuration.dataOffset);
1096
+ blobBuffer.write(buffer.getAsDataArray());
1097
+
1098
+ blobBuffer.seek(oldPos);
1099
+ }
1100
+
1101
+ /**
1102
+ * Add a frame to the video.
1103
+ *
1104
+ * @param {HTMLCanvasElement|String} frame - A Canvas element that
1105
+ * contains the frame, or a WebP string you obtained by calling
1106
+ * toDataUrl() on an image yourself.
1107
+ *
1108
+ */
1109
+ this.addFrame = function(frame) {
1110
+ if (!writtenHeader) {
1111
+ videoWidth = options.width;
1112
+ videoHeight = options.height;
1113
+ writeHeader();
1114
+ }
1115
+ if (frame.constructor.name == 'EncodedVideoChunk') {
1116
+ let frameData = new Uint8Array(frame.byteLength);
1117
+ frame.copyTo(frameData);
1118
+ addFrameToCluster({
1119
+ frame: frameData,
1120
+ intime: frame.timestamp,
1121
+ type: frame.type,
1122
+ });
1123
+ return;
1124
+ }
1125
+ };
1126
+
1127
+ /**
1128
+ * Finish writing the video and return a Promise to signal completion.
1129
+ *
1130
+ * If the destination device was memory (i.e. options.fileWriter was not
1131
+ * supplied), the Promise is resolved with a Blob with the contents of the
1132
+ * entire video.
1133
+ */
1134
+ this.complete = function() {
1135
+ if (!writtenHeader) {
1136
+ writeHeader();
1137
+ }
1138
+ firstTimestampEver = true;
1139
+
1140
+ flushClusterFrameBuffer();
1141
+
1142
+ writeCues();
1143
+ rewriteSeekHead();
1144
+ rewriteDuration();
1145
+
1146
+ return blobBuffer.complete('video/webm');
1147
+ };
1148
+
1149
+ this.getWrittenSize = function() {
1150
+ return blobBuffer.length;
1151
+ };
1152
+
1153
+ options = extend(optionDefaults, options || {});
1154
+ validateOptions();
1155
+ };
1156
+ };
1157
+
1158
+ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
1159
+ module.exports =
1160
+ WebMWriter(require('./ArrayBufferDataStream'), require('./BlobBuffer'));
1161
+ } else {
1162
+ self.WebMWriter =
1163
+ WebMWriter(self.ArrayBufferDataStream, self.BlobBuffer);
1164
+ }
1165
+ })();