react-design-editor 0.0.37 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/lib/Canvas.d.ts +18 -0
  2. package/lib/Canvas.js +172 -0
  3. package/lib/CanvasObject.d.ts +10 -0
  4. package/lib/CanvasObject.js +96 -0
  5. package/lib/constants/code.d.ts +19 -0
  6. package/lib/constants/code.js +22 -0
  7. package/lib/constants/defaults.d.ts +38 -0
  8. package/lib/constants/defaults.js +69 -0
  9. package/lib/constants/index.d.ts +3 -0
  10. package/lib/constants/index.js +26 -0
  11. package/lib/handlers/AlignmentHandler.d.ts +18 -0
  12. package/lib/handlers/AlignmentHandler.js +58 -0
  13. package/lib/handlers/AnimationHandler.d.ts +50 -0
  14. package/lib/handlers/AnimationHandler.js +323 -0
  15. package/lib/handlers/ChartHandler.d.ts +8 -0
  16. package/lib/handlers/ChartHandler.js +8 -0
  17. package/lib/handlers/ContextmenuHandler.d.ts +28 -0
  18. package/lib/handlers/ContextmenuHandler.js +65 -0
  19. package/lib/handlers/CropHandler.d.ts +43 -0
  20. package/lib/handlers/CropHandler.js +261 -0
  21. package/lib/handlers/CustomHandler.d.ts +7 -0
  22. package/lib/handlers/CustomHandler.js +10 -0
  23. package/lib/handlers/DrawingHandler.d.ts +28 -0
  24. package/lib/handlers/DrawingHandler.js +318 -0
  25. package/lib/handlers/ElementHandler.d.ts +80 -0
  26. package/lib/handlers/ElementHandler.js +154 -0
  27. package/lib/handlers/EventHandler.d.ts +170 -0
  28. package/lib/handlers/EventHandler.js +880 -0
  29. package/lib/handlers/FiberHandler.d.ts +6 -0
  30. package/lib/handlers/FiberHandler.js +23 -0
  31. package/lib/handlers/GridHandler.d.ts +19 -0
  32. package/lib/handlers/GridHandler.js +77 -0
  33. package/lib/handlers/GuidelineHandler.d.ts +61 -0
  34. package/lib/handlers/GuidelineHandler.js +315 -0
  35. package/lib/handlers/Handler.d.ts +622 -0
  36. package/lib/handlers/Handler.js +1638 -0
  37. package/lib/handlers/ImageHandler.d.ts +307 -0
  38. package/lib/handlers/ImageHandler.js +529 -0
  39. package/lib/handlers/InteractionHandler.d.ts +45 -0
  40. package/lib/handlers/InteractionHandler.js +164 -0
  41. package/lib/handlers/LinkHandler.d.ts +115 -0
  42. package/lib/handlers/LinkHandler.js +247 -0
  43. package/lib/handlers/NodeHandler.d.ts +50 -0
  44. package/lib/handlers/NodeHandler.js +274 -0
  45. package/lib/handlers/PortHandler.d.ts +22 -0
  46. package/lib/handlers/PortHandler.js +179 -0
  47. package/lib/handlers/ShortcutHandler.d.ts +119 -0
  48. package/lib/handlers/ShortcutHandler.js +151 -0
  49. package/lib/handlers/TooltipHandler.d.ts +33 -0
  50. package/lib/handlers/TooltipHandler.js +91 -0
  51. package/lib/handlers/TransactionHandler.d.ts +59 -0
  52. package/lib/handlers/TransactionHandler.js +137 -0
  53. package/lib/handlers/WorkareaHandler.d.ts +43 -0
  54. package/lib/handlers/WorkareaHandler.js +354 -0
  55. package/lib/handlers/ZoomHandler.d.ts +48 -0
  56. package/lib/handlers/ZoomHandler.js +143 -0
  57. package/lib/handlers/index.d.ts +23 -0
  58. package/lib/handlers/index.js +48 -0
  59. package/lib/index.d.ts +6 -0
  60. package/lib/index.js +20 -0
  61. package/lib/objects/Arrow.d.ts +2 -0
  62. package/lib/objects/Arrow.js +40 -0
  63. package/lib/objects/Chart.d.ts +10 -0
  64. package/lib/objects/Chart.js +124 -0
  65. package/lib/objects/CirclePort.d.ts +2 -0
  66. package/lib/objects/CirclePort.js +28 -0
  67. package/lib/objects/Cube.d.ts +5 -0
  68. package/lib/objects/Cube.js +71 -0
  69. package/lib/objects/CurvedLink.d.ts +2 -0
  70. package/lib/objects/CurvedLink.js +51 -0
  71. package/lib/objects/Element.d.ts +13 -0
  72. package/lib/objects/Element.js +84 -0
  73. package/lib/objects/Gif.d.ts +3 -0
  74. package/lib/objects/Gif.js +41 -0
  75. package/lib/objects/Iframe.d.ts +9 -0
  76. package/lib/objects/Iframe.js +70 -0
  77. package/lib/objects/Line.d.ts +2 -0
  78. package/lib/objects/Line.js +24 -0
  79. package/lib/objects/Link.d.ts +15 -0
  80. package/lib/objects/Link.js +106 -0
  81. package/lib/objects/Node.d.ts +59 -0
  82. package/lib/objects/Node.js +271 -0
  83. package/lib/objects/OrthogonalLink.d.ts +2 -0
  84. package/lib/objects/OrthogonalLink.js +54 -0
  85. package/lib/objects/Port.d.ts +12 -0
  86. package/lib/objects/Port.js +28 -0
  87. package/lib/objects/Svg.d.ts +8 -0
  88. package/lib/objects/Svg.js +59 -0
  89. package/lib/objects/Video.d.ts +14 -0
  90. package/lib/objects/Video.js +120 -0
  91. package/lib/objects/index.d.ts +15 -0
  92. package/lib/objects/index.js +32 -0
  93. package/lib/utils/ObjectUtil.d.ts +407 -0
  94. package/lib/utils/ObjectUtil.js +13 -0
  95. package/lib/utils/index.d.ts +1 -0
  96. package/lib/utils/index.js +13 -0
  97. package/package.json +1 -1
@@ -0,0 +1,1638 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const fabric_1 = require("fabric");
7
+ const lodash_1 = require("lodash");
8
+ const uuidv4_1 = require("uuidv4");
9
+ const warning_1 = __importDefault(require("warning"));
10
+ const _1 = require(".");
11
+ const CanvasObject_1 = __importDefault(require("../CanvasObject"));
12
+ const constants_1 = require("../constants");
13
+ /**
14
+ * Main handler for Canvas
15
+ * @class Handler
16
+ * @implements {HandlerOptions}
17
+ */
18
+ class Handler {
19
+ constructor(options) {
20
+ this.propertiesToInclude = constants_1.defaults.propertiesToInclude;
21
+ this.workareaOption = constants_1.defaults.workareaOption;
22
+ this.canvasOption = constants_1.defaults.canvasOption;
23
+ this.gridOption = constants_1.defaults.gridOption;
24
+ this.objectOption = constants_1.defaults.objectOption;
25
+ this.guidelineOption = constants_1.defaults.guidelineOption;
26
+ this.keyEvent = constants_1.defaults.keyEvent;
27
+ this.activeSelectionOption = constants_1.defaults.activeSelectionOption;
28
+ this.fabricObjects = CanvasObject_1.default;
29
+ this.handlers = {};
30
+ this.objectMap = {};
31
+ this.zoom = 1;
32
+ this.isCut = false;
33
+ this.isRequsetAnimFrame = false;
34
+ /**
35
+ * Init class fields
36
+ * @param {HandlerOptions} options
37
+ */
38
+ this.initOption = (options) => {
39
+ this.id = options.id;
40
+ this.canvas = options.canvas;
41
+ this.container = options.container;
42
+ this.editable = options.editable;
43
+ this.interactionMode = options.interactionMode;
44
+ this.minZoom = options.minZoom;
45
+ this.maxZoom = options.maxZoom;
46
+ this.zoomEnabled = options.zoomEnabled;
47
+ this.width = options.width;
48
+ this.height = options.height;
49
+ this.objects = [];
50
+ this.setPropertiesToInclude(options.propertiesToInclude);
51
+ this.setWorkareaOption(options.workareaOption);
52
+ this.setCanvasOption(options.canvasOption);
53
+ this.setGridOption(options.gridOption);
54
+ this.setObjectOption(options.objectOption);
55
+ this.setFabricObjects(options.fabricObjects);
56
+ this.setGuidelineOption(options.guidelineOption);
57
+ this.setActiveSelectionOption(options.activeSelectionOption);
58
+ this.setKeyEvent(options.keyEvent);
59
+ };
60
+ /**
61
+ * Initialize callback
62
+ * @param {HandlerOptions} options
63
+ */
64
+ this.initCallback = (options) => {
65
+ this.onAdd = options.onAdd;
66
+ this.onTooltip = options.onTooltip;
67
+ this.onZoom = options.onZoom;
68
+ this.onContext = options.onContext;
69
+ this.onClick = options.onClick;
70
+ this.onModified = options.onModified;
71
+ this.onDblClick = options.onDblClick;
72
+ this.onSelect = options.onSelect;
73
+ this.onRemove = options.onRemove;
74
+ this.onTransaction = options.onTransaction;
75
+ this.onInteraction = options.onInteraction;
76
+ this.onLoad = options.onLoad;
77
+ };
78
+ /**
79
+ * Initialize handlers
80
+ *
81
+ */
82
+ this.initHandler = () => {
83
+ this.workareaHandler = new _1.WorkareaHandler(this);
84
+ this.imageHandler = new _1.ImageHandler(this);
85
+ this.chartHandler = new _1.ChartHandler(this);
86
+ this.elementHandler = new _1.ElementHandler(this);
87
+ this.cropHandler = new _1.CropHandler(this);
88
+ this.animationHandler = new _1.AnimationHandler(this);
89
+ this.contextmenuHandler = new _1.ContextmenuHandler(this);
90
+ this.tooltipHandler = new _1.TooltipHandler(this);
91
+ this.zoomHandler = new _1.ZoomHandler(this);
92
+ this.interactionHandler = new _1.InteractionHandler(this);
93
+ this.transactionHandler = new _1.TransactionHandler(this);
94
+ this.gridHandler = new _1.GridHandler(this);
95
+ this.portHandler = new _1.PortHandler(this);
96
+ this.linkHandler = new _1.LinkHandler(this);
97
+ this.nodeHandler = new _1.NodeHandler(this);
98
+ this.alignmentHandler = new _1.AlignmentHandler(this);
99
+ this.guidelineHandler = new _1.GuidelineHandler(this);
100
+ this.eventHandler = new _1.EventHandler(this);
101
+ this.drawingHandler = new _1.DrawingHandler(this);
102
+ this.shortcutHandler = new _1.ShortcutHandler(this);
103
+ };
104
+ /**
105
+ * Get primary object
106
+ * @returns {FabricObject[]}
107
+ */
108
+ this.getObjects = () => {
109
+ const objects = this.canvas.getObjects().filter((obj) => {
110
+ if (obj.id === 'workarea') {
111
+ return false;
112
+ }
113
+ else if (obj.id === 'grid') {
114
+ return false;
115
+ }
116
+ else if (obj.superType === 'port') {
117
+ return false;
118
+ }
119
+ else if (!obj.id) {
120
+ return false;
121
+ }
122
+ return true;
123
+ });
124
+ if (objects.length) {
125
+ objects.forEach(obj => (this.objectMap[obj.id] = obj));
126
+ }
127
+ else {
128
+ this.objectMap = {};
129
+ }
130
+ return objects;
131
+ };
132
+ /**
133
+ * Set key pair
134
+ * @param {keyof FabricObject} key
135
+ * @param {*} value
136
+ * @returns
137
+ */
138
+ this.set = (key, value) => {
139
+ const activeObject = this.canvas.getActiveObject();
140
+ if (!activeObject) {
141
+ return;
142
+ }
143
+ if ((activeObject.type === 'svg' && key === 'fill') || key === 'stroke') {
144
+ activeObject._objects.forEach(obj => obj.set(key, value));
145
+ }
146
+ else {
147
+ activeObject.set(key, value);
148
+ activeObject.setCoords();
149
+ }
150
+ this.canvas.requestRenderAll();
151
+ const { id, superType, type, player, width, height } = activeObject;
152
+ if (superType === 'element') {
153
+ if (key === 'visible') {
154
+ if (value) {
155
+ activeObject.element.style.display = 'block';
156
+ }
157
+ else {
158
+ activeObject.element.style.display = 'none';
159
+ }
160
+ }
161
+ const el = this.elementHandler.findById(id);
162
+ // update the element
163
+ this.elementHandler.setScaleOrAngle(el, activeObject);
164
+ this.elementHandler.setSize(el, activeObject);
165
+ this.elementHandler.setPosition(el, activeObject);
166
+ if (type === 'video' && player) {
167
+ player.setPlayerSize(width, height);
168
+ }
169
+ }
170
+ const { onModified } = this;
171
+ if (onModified) {
172
+ onModified(activeObject);
173
+ }
174
+ };
175
+ /**
176
+ * Set option
177
+ * @param {Partial<FabricObject>} option
178
+ * @returns
179
+ */
180
+ this.setObject = (option) => {
181
+ const activeObject = this.canvas.getActiveObject();
182
+ if (!activeObject) {
183
+ return;
184
+ }
185
+ Object.keys(option).forEach(key => {
186
+ if (option[key] !== activeObject[key]) {
187
+ activeObject.set(key, option[key]);
188
+ activeObject.setCoords();
189
+ }
190
+ });
191
+ this.canvas.requestRenderAll();
192
+ const { id, superType, type, player, width, height } = activeObject;
193
+ if (superType === 'element') {
194
+ if ('visible' in option) {
195
+ if (option.visible) {
196
+ activeObject.element.style.display = 'block';
197
+ }
198
+ else {
199
+ activeObject.element.style.display = 'none';
200
+ }
201
+ }
202
+ const el = this.elementHandler.findById(id);
203
+ // update the element
204
+ this.elementHandler.setScaleOrAngle(el, activeObject);
205
+ this.elementHandler.setSize(el, activeObject);
206
+ this.elementHandler.setPosition(el, activeObject);
207
+ if (type === 'video' && player) {
208
+ player.setPlayerSize(width, height);
209
+ }
210
+ }
211
+ const { onModified } = this;
212
+ if (onModified) {
213
+ onModified(activeObject);
214
+ }
215
+ };
216
+ /**
217
+ * Set key pair by object
218
+ * @param {FabricObject} obj
219
+ * @param {string} key
220
+ * @param {*} value
221
+ * @returns
222
+ */
223
+ this.setByObject = (obj, key, value) => {
224
+ if (!obj) {
225
+ return;
226
+ }
227
+ obj.set(key, value);
228
+ obj.setCoords();
229
+ this.canvas.renderAll();
230
+ const { id, superType, type, player, width, height } = obj;
231
+ if (superType === 'element') {
232
+ if (key === 'visible') {
233
+ if (value) {
234
+ obj.element.style.display = 'block';
235
+ }
236
+ else {
237
+ obj.element.style.display = 'none';
238
+ }
239
+ }
240
+ const el = this.elementHandler.findById(id);
241
+ // update the element
242
+ this.elementHandler.setScaleOrAngle(el, obj);
243
+ this.elementHandler.setSize(el, obj);
244
+ this.elementHandler.setPosition(el, obj);
245
+ if (type === 'video' && player) {
246
+ player.setPlayerSize(width, height);
247
+ }
248
+ }
249
+ const { onModified } = this;
250
+ if (onModified) {
251
+ onModified(obj);
252
+ }
253
+ };
254
+ /**
255
+ * Set key pair by id
256
+ * @param {string} id
257
+ * @param {string} key
258
+ * @param {*} value
259
+ */
260
+ this.setById = (id, key, value) => {
261
+ const findObject = this.findById(id);
262
+ this.setByObject(findObject, key, value);
263
+ };
264
+ /**
265
+ * Set partial by object
266
+ * @param {FabricObject} obj
267
+ * @param {FabricObjectOption} option
268
+ * @returns
269
+ */
270
+ this.setByPartial = (obj, option) => {
271
+ if (!obj) {
272
+ return;
273
+ }
274
+ obj.set(option);
275
+ obj.setCoords();
276
+ this.canvas.renderAll();
277
+ const { id, superType, type, player, width, height } = obj;
278
+ if (superType === 'element') {
279
+ if ('visible' in option) {
280
+ if (option.visible) {
281
+ obj.element.style.display = 'block';
282
+ }
283
+ else {
284
+ obj.element.style.display = 'none';
285
+ }
286
+ }
287
+ const el = this.elementHandler.findById(id);
288
+ // update the element
289
+ this.elementHandler.setScaleOrAngle(el, obj);
290
+ this.elementHandler.setSize(el, obj);
291
+ this.elementHandler.setPosition(el, obj);
292
+ if (type === 'video' && player) {
293
+ player.setPlayerSize(width, height);
294
+ }
295
+ }
296
+ };
297
+ /**
298
+ * Set shadow
299
+ * @param {fabric.Shadow} option
300
+ * @returns
301
+ */
302
+ this.setShadow = (option) => {
303
+ const activeObject = this.canvas.getActiveObject();
304
+ if (!activeObject) {
305
+ return;
306
+ }
307
+ activeObject.set('shadow', new fabric_1.fabric.Shadow(option));
308
+ this.canvas.requestRenderAll();
309
+ const { onModified } = this;
310
+ if (onModified) {
311
+ onModified(activeObject);
312
+ }
313
+ };
314
+ /**
315
+ * Set the image
316
+ * @param {FabricImage} obj
317
+ * @param {(File | string)} [source]
318
+ * @returns
319
+ */
320
+ this.setImage = (obj, source) => {
321
+ if (!source) {
322
+ this.loadImage(obj, null);
323
+ obj.set('file', null);
324
+ obj.set('src', null);
325
+ return;
326
+ }
327
+ if (source instanceof File) {
328
+ const reader = new FileReader();
329
+ reader.onload = () => {
330
+ this.loadImage(obj, reader.result);
331
+ obj.set('file', source);
332
+ obj.set('src', null);
333
+ };
334
+ reader.readAsDataURL(source);
335
+ }
336
+ else {
337
+ this.loadImage(obj, source);
338
+ obj.set('file', null);
339
+ obj.set('src', source);
340
+ }
341
+ };
342
+ /**
343
+ * Set image by id
344
+ * @param {string} id
345
+ * @param {*} source
346
+ */
347
+ this.setImageById = (id, source) => {
348
+ const findObject = this.findById(id);
349
+ this.setImage(findObject, source);
350
+ };
351
+ /**
352
+ * Set visible
353
+ * @param {boolean} [visible]
354
+ * @returns
355
+ */
356
+ this.setVisible = (visible) => {
357
+ const activeObject = this.canvas.getActiveObject();
358
+ if (!activeObject) {
359
+ return;
360
+ }
361
+ if (activeObject.superType === 'element') {
362
+ if (visible) {
363
+ activeObject.element.style.display = 'block';
364
+ }
365
+ else {
366
+ activeObject.element.style.display = 'none';
367
+ }
368
+ }
369
+ activeObject.set({
370
+ visible,
371
+ });
372
+ this.canvas.renderAll();
373
+ };
374
+ /**
375
+ * Set the position on Object
376
+ *
377
+ * @param {FabricObject} obj
378
+ * @param {boolean} [centered]
379
+ */
380
+ this.centerObject = (obj, centered) => {
381
+ if (centered) {
382
+ this.canvas.centerObject(obj);
383
+ obj.setCoords();
384
+ }
385
+ else {
386
+ this.setByPartial(obj, {
387
+ left: obj.left / this.canvas.getZoom() -
388
+ obj.width / 2 -
389
+ this.canvas.viewportTransform[4] / this.canvas.getZoom(),
390
+ top: obj.top / this.canvas.getZoom() -
391
+ obj.height / 2 -
392
+ this.canvas.viewportTransform[5] / this.canvas.getZoom(),
393
+ });
394
+ }
395
+ };
396
+ /**
397
+ * Add object
398
+ * @param {FabricObjectOption} obj
399
+ * @param {boolean} [centered=true]
400
+ * @param {boolean} [loaded=false]
401
+ * @returns
402
+ */
403
+ this.add = (obj, centered = true, loaded = false) => {
404
+ const { editable, onAdd, gridOption, objectOption } = this;
405
+ const option = {
406
+ hasControls: editable,
407
+ hasBorders: editable,
408
+ selectable: editable,
409
+ lockMovementX: !editable,
410
+ lockMovementY: !editable,
411
+ hoverCursor: !editable ? 'pointer' : 'move',
412
+ };
413
+ if (obj.type === 'i-text') {
414
+ option.editable = false;
415
+ }
416
+ else {
417
+ option.editable = editable;
418
+ }
419
+ if (editable && this.workarea.layout === 'fullscreen') {
420
+ option.scaleX = this.workarea.scaleX;
421
+ option.scaleY = this.workarea.scaleY;
422
+ }
423
+ const newOption = Object.assign({}, objectOption, obj, {
424
+ container: this.container.id,
425
+ editable,
426
+ }, option);
427
+ // Individually create canvas object
428
+ if (obj.superType === 'link') {
429
+ return this.linkHandler.create(newOption, loaded);
430
+ }
431
+ let createdObj;
432
+ // Create canvas object
433
+ if (obj.type === 'image') {
434
+ createdObj = this.addImage(newOption);
435
+ }
436
+ else if (obj.type === 'group') {
437
+ // TODO...
438
+ // Group add function needs to be fixed
439
+ const objects = this.addGroup(newOption, centered, loaded);
440
+ const groupOption = Object.assign({}, newOption, { objects, name: 'New Group' });
441
+ createdObj = this.fabricObjects[obj.type].create(groupOption);
442
+ }
443
+ else {
444
+ createdObj = this.fabricObjects[obj.type].create(newOption);
445
+ }
446
+ this.canvas.add(createdObj);
447
+ this.objects = this.getObjects();
448
+ if (!editable && !(obj.superType === 'element')) {
449
+ createdObj.on('mousedown', this.eventHandler.object.mousedown);
450
+ }
451
+ if (createdObj.dblclick) {
452
+ createdObj.on('mousedblclick', this.eventHandler.object.mousedblclick);
453
+ }
454
+ if (this.objects.some(object => object.type === 'gif')) {
455
+ this.startRequestAnimFrame();
456
+ }
457
+ else {
458
+ this.stopRequestAnimFrame();
459
+ }
460
+ if (obj.superType !== 'drawing' && obj.superType !== 'link' && editable && !loaded) {
461
+ this.centerObject(createdObj, centered);
462
+ }
463
+ if (createdObj.superType === 'node') {
464
+ this.portHandler.create(createdObj);
465
+ if (createdObj.iconButton) {
466
+ this.canvas.add(createdObj.iconButton);
467
+ }
468
+ }
469
+ if (!editable && createdObj.animation && createdObj.animation.autoplay) {
470
+ this.animationHandler.play(createdObj.id);
471
+ }
472
+ if (createdObj.superType === 'node') {
473
+ createdObj.set('shadow', {
474
+ color: createdObj.stroke,
475
+ });
476
+ }
477
+ if (gridOption.enabled) {
478
+ this.gridHandler.setCoords(createdObj);
479
+ }
480
+ if (!this.transactionHandler.active && !loaded) {
481
+ this.transactionHandler.save('add');
482
+ }
483
+ if (onAdd && editable && !loaded) {
484
+ onAdd(createdObj);
485
+ }
486
+ return createdObj;
487
+ };
488
+ /**
489
+ * Add group object
490
+ *
491
+ * @param {FabricGroup} obj
492
+ * @param {boolean} [centered=true]
493
+ * @param {boolean} [loaded=false]
494
+ * @returns
495
+ */
496
+ this.addGroup = (obj, centered = true, loaded = false) => {
497
+ return obj.objects.map(child => {
498
+ return this.add(child, centered, loaded);
499
+ });
500
+ };
501
+ /**
502
+ * Add iamge object
503
+ * @param {FabricImage} obj
504
+ * @returns
505
+ */
506
+ this.addImage = (obj) => {
507
+ const { objectOption } = this;
508
+ const { filters = [], ...otherOption } = obj;
509
+ const image = new Image();
510
+ if (obj.src) {
511
+ image.src = obj.src;
512
+ }
513
+ const createdObj = new fabric_1.fabric.Image(image, {
514
+ ...objectOption,
515
+ ...otherOption,
516
+ });
517
+ createdObj.set({
518
+ filters: this.imageHandler.createFilters(filters),
519
+ });
520
+ this.setImage(createdObj, obj.src || obj.file);
521
+ return createdObj;
522
+ };
523
+ /**
524
+ * Remove object
525
+ * @param {FabricObject} target
526
+ * @returns {any}
527
+ */
528
+ this.remove = (target) => {
529
+ const activeObject = target || this.canvas.getActiveObject();
530
+ if (this.prevTarget && this.prevTarget.superType === 'link') {
531
+ this.linkHandler.remove(this.prevTarget);
532
+ if (!this.transactionHandler.active) {
533
+ this.transactionHandler.save('remove');
534
+ }
535
+ return;
536
+ }
537
+ if (!activeObject) {
538
+ return;
539
+ }
540
+ if (typeof activeObject.deletable !== 'undefined' && !activeObject.deletable) {
541
+ return;
542
+ }
543
+ if (activeObject.type !== 'activeSelection') {
544
+ this.canvas.discardActiveObject();
545
+ if (activeObject.superType === 'element') {
546
+ this.elementHandler.removeById(activeObject.id);
547
+ }
548
+ if (activeObject.superType === 'link') {
549
+ this.linkHandler.remove(activeObject);
550
+ }
551
+ else if (activeObject.superType === 'node') {
552
+ if (activeObject.toPort) {
553
+ if (activeObject.toPort.links.length) {
554
+ activeObject.toPort.links.forEach((link) => {
555
+ this.linkHandler.remove(link, 'from');
556
+ });
557
+ }
558
+ this.canvas.remove(activeObject.toPort);
559
+ }
560
+ if (activeObject.fromPort && activeObject.fromPort.length) {
561
+ activeObject.fromPort.forEach((port) => {
562
+ if (port.links.length) {
563
+ port.links.forEach((link) => {
564
+ this.linkHandler.remove(link, 'to');
565
+ });
566
+ }
567
+ this.canvas.remove(port);
568
+ });
569
+ }
570
+ }
571
+ this.canvas.remove(activeObject);
572
+ }
573
+ else {
574
+ const { _objects: activeObjects } = activeObject;
575
+ const existDeleted = activeObjects.some((obj) => typeof obj.deletable !== 'undefined' && !obj.deletable);
576
+ if (existDeleted) {
577
+ return;
578
+ }
579
+ this.canvas.discardActiveObject();
580
+ activeObjects.forEach((obj) => {
581
+ if (obj.superType === 'element') {
582
+ this.elementHandler.removeById(obj.id);
583
+ }
584
+ else if (obj.superType === 'node') {
585
+ if (obj.toPort) {
586
+ if (obj.toPort.links.length) {
587
+ obj.toPort.links.forEach((link) => {
588
+ this.linkHandler.remove(link, 'from');
589
+ });
590
+ }
591
+ this.canvas.remove(obj.toPort);
592
+ }
593
+ if (obj.fromPort && obj.fromPort.length) {
594
+ obj.fromPort.forEach((port) => {
595
+ if (port.links.length) {
596
+ port.links.forEach((link) => {
597
+ this.linkHandler.remove(link, 'to');
598
+ });
599
+ }
600
+ this.canvas.remove(port);
601
+ });
602
+ }
603
+ }
604
+ this.canvas.remove(obj);
605
+ });
606
+ }
607
+ if (!this.transactionHandler.active) {
608
+ this.transactionHandler.save('remove');
609
+ }
610
+ this.objects = this.getObjects();
611
+ const { onRemove } = this;
612
+ if (onRemove) {
613
+ onRemove(activeObject);
614
+ }
615
+ };
616
+ /**
617
+ * Remove object by id
618
+ * @param {string} id
619
+ */
620
+ this.removeById = (id) => {
621
+ const findObject = this.findById(id);
622
+ if (findObject) {
623
+ this.remove(findObject);
624
+ }
625
+ };
626
+ /**
627
+ * Delete at origin object list
628
+ * @param {string} id
629
+ */
630
+ this.removeOriginById = (id) => {
631
+ const object = this.findOriginByIdWithIndex(id);
632
+ if (object.index > 0) {
633
+ this.objects.splice(object.index, 1);
634
+ }
635
+ };
636
+ /**
637
+ * Duplicate object
638
+ * @returns
639
+ */
640
+ this.duplicate = () => {
641
+ const { onAdd, propertiesToInclude, gridOption: { grid = 10 }, } = this;
642
+ const activeObject = this.canvas.getActiveObject();
643
+ if (!activeObject) {
644
+ return;
645
+ }
646
+ if (typeof activeObject.cloneable !== 'undefined' && !activeObject.cloneable) {
647
+ return;
648
+ }
649
+ activeObject.clone((clonedObj) => {
650
+ this.canvas.discardActiveObject();
651
+ clonedObj.set({
652
+ left: clonedObj.left + grid,
653
+ top: clonedObj.top + grid,
654
+ evented: true,
655
+ });
656
+ if (clonedObj.type === 'activeSelection') {
657
+ const activeSelection = clonedObj;
658
+ activeSelection.canvas = this.canvas;
659
+ activeSelection.forEachObject((obj) => {
660
+ obj.set('id', uuidv4_1.uuid());
661
+ if (obj.superType === 'node') {
662
+ obj.set('shadow', {
663
+ color: obj.stroke,
664
+ });
665
+ }
666
+ this.canvas.add(obj);
667
+ this.objects = this.getObjects();
668
+ if (obj.dblclick) {
669
+ obj.on('mousedblclick', this.eventHandler.object.mousedblclick);
670
+ }
671
+ });
672
+ if (onAdd) {
673
+ onAdd(activeSelection);
674
+ }
675
+ activeSelection.setCoords();
676
+ }
677
+ else {
678
+ if (activeObject.id === clonedObj.id) {
679
+ clonedObj.set('id', uuidv4_1.uuid());
680
+ }
681
+ if (clonedObj.superType === 'node') {
682
+ clonedObj.set('shadow', {
683
+ color: clonedObj.stroke,
684
+ });
685
+ }
686
+ this.canvas.add(clonedObj);
687
+ this.objects = this.getObjects();
688
+ if (clonedObj.dblclick) {
689
+ clonedObj.on('mousedblclick', this.eventHandler.object.mousedblclick);
690
+ }
691
+ if (onAdd) {
692
+ onAdd(clonedObj);
693
+ }
694
+ }
695
+ this.canvas.setActiveObject(clonedObj);
696
+ this.portHandler.create(clonedObj);
697
+ this.canvas.requestRenderAll();
698
+ }, propertiesToInclude);
699
+ };
700
+ /**
701
+ * Duplicate object by id
702
+ * @param {string} id
703
+ * @returns
704
+ */
705
+ this.duplicateById = (id) => {
706
+ const { onAdd, propertiesToInclude, gridOption: { grid = 10 }, } = this;
707
+ const findObject = this.findById(id);
708
+ if (findObject) {
709
+ if (typeof findObject.cloneable !== 'undefined' && !findObject.cloneable) {
710
+ return false;
711
+ }
712
+ findObject.clone((cloned) => {
713
+ cloned.set({
714
+ left: cloned.left + grid,
715
+ top: cloned.top + grid,
716
+ id: uuidv4_1.uuid(),
717
+ evented: true,
718
+ });
719
+ this.canvas.add(cloned);
720
+ this.objects = this.getObjects();
721
+ if (onAdd) {
722
+ onAdd(cloned);
723
+ }
724
+ if (cloned.dblclick) {
725
+ cloned.on('mousedblclick', this.eventHandler.object.mousedblclick);
726
+ }
727
+ this.canvas.setActiveObject(cloned);
728
+ this.portHandler.create(cloned);
729
+ this.canvas.requestRenderAll();
730
+ }, propertiesToInclude);
731
+ }
732
+ return true;
733
+ };
734
+ /**
735
+ * Cut object
736
+ *
737
+ */
738
+ this.cut = () => {
739
+ this.copy();
740
+ this.remove();
741
+ this.isCut = true;
742
+ };
743
+ /**
744
+ * Copy to clipboard
745
+ *
746
+ * @param {*} value
747
+ */
748
+ this.copyToClipboard = (value) => {
749
+ const textarea = document.createElement('textarea');
750
+ document.body.appendChild(textarea);
751
+ textarea.value = value;
752
+ textarea.select();
753
+ document.execCommand('copy');
754
+ document.body.removeChild(textarea);
755
+ this.canvas.wrapperEl.focus();
756
+ };
757
+ /**
758
+ * Copy object
759
+ *
760
+ * @returns
761
+ */
762
+ this.copy = () => {
763
+ const { propertiesToInclude } = this;
764
+ const activeObject = this.canvas.getActiveObject();
765
+ if (activeObject && activeObject.superType === 'link') {
766
+ return false;
767
+ }
768
+ if (activeObject) {
769
+ if (typeof activeObject.cloneable !== 'undefined' && !activeObject.cloneable) {
770
+ return false;
771
+ }
772
+ if (activeObject.type === 'activeSelection') {
773
+ const activeSelection = activeObject;
774
+ if (activeSelection.getObjects().some((obj) => obj.superType === 'node')) {
775
+ if (this.keyEvent.clipboard) {
776
+ const links = [];
777
+ const objects = activeSelection.getObjects().map((obj, index) => {
778
+ if (typeof obj.cloneable !== 'undefined' && !obj.cloneable) {
779
+ return null;
780
+ }
781
+ if (obj.fromPort.length) {
782
+ obj.fromPort.forEach((port) => {
783
+ if (port.links.length) {
784
+ port.links.forEach((link) => {
785
+ const linkTarget = {
786
+ fromNodeIndex: index,
787
+ fromPortId: port.id,
788
+ type: 'curvedLink',
789
+ superType: 'link',
790
+ };
791
+ const findIndex = activeSelection
792
+ .getObjects()
793
+ .findIndex((compObj) => compObj.id === link.toNode.id);
794
+ if (findIndex >= 0) {
795
+ linkTarget.toNodeIndex = findIndex;
796
+ links.push(linkTarget);
797
+ }
798
+ });
799
+ }
800
+ });
801
+ }
802
+ return {
803
+ name: obj.name,
804
+ description: obj.description,
805
+ superType: obj.superType,
806
+ type: obj.type,
807
+ nodeClazz: obj.nodeClazz,
808
+ configuration: obj.configuration,
809
+ properties: {
810
+ left: activeObject.left + activeObject.width / 2 + obj.left || 0,
811
+ top: activeObject.top + activeObject.height / 2 + obj.top || 0,
812
+ iconName: obj.descriptor.icon,
813
+ },
814
+ };
815
+ });
816
+ this.copyToClipboard(JSON.stringify(objects.concat(links), null, '\t'));
817
+ return true;
818
+ }
819
+ this.clipboard = activeObject;
820
+ return true;
821
+ }
822
+ }
823
+ activeObject.clone((cloned) => {
824
+ if (this.keyEvent.clipboard) {
825
+ if (cloned.superType === 'node') {
826
+ const node = {
827
+ name: cloned.name,
828
+ description: cloned.description,
829
+ superType: cloned.superType,
830
+ type: cloned.type,
831
+ nodeClazz: cloned.nodeClazz,
832
+ configuration: cloned.configuration,
833
+ properties: {
834
+ left: cloned.left || 0,
835
+ top: cloned.top || 0,
836
+ iconName: cloned.descriptor.icon,
837
+ },
838
+ };
839
+ const objects = [node];
840
+ this.copyToClipboard(JSON.stringify(objects, null, '\t'));
841
+ }
842
+ else {
843
+ this.copyToClipboard(JSON.stringify(cloned.toObject(propertiesToInclude), null, '\t'));
844
+ }
845
+ }
846
+ else {
847
+ this.clipboard = cloned;
848
+ }
849
+ }, propertiesToInclude);
850
+ }
851
+ return true;
852
+ };
853
+ /**
854
+ * Paste object
855
+ *
856
+ * @returns
857
+ */
858
+ this.paste = () => {
859
+ const { onAdd, propertiesToInclude, gridOption: { grid = 10 }, clipboard, isCut, } = this;
860
+ const padding = isCut ? 0 : grid;
861
+ if (!clipboard) {
862
+ return false;
863
+ }
864
+ if (typeof clipboard.cloneable !== 'undefined' && !clipboard.cloneable) {
865
+ return false;
866
+ }
867
+ this.isCut = false;
868
+ if (clipboard.type === 'activeSelection') {
869
+ if (clipboard.getObjects().some((obj) => obj.superType === 'node')) {
870
+ this.canvas.discardActiveObject();
871
+ const objects = [];
872
+ const linkObjects = [];
873
+ clipboard.getObjects().forEach((obj) => {
874
+ if (typeof obj.cloneable !== 'undefined' && !obj.cloneable) {
875
+ return;
876
+ }
877
+ const clonedObj = obj.duplicate();
878
+ if (clonedObj.type === 'SwitchNode') {
879
+ clonedObj.set({
880
+ left: obj.left + padding + padding,
881
+ top: obj.top + padding,
882
+ });
883
+ }
884
+ else {
885
+ clonedObj.set({
886
+ left: obj.left + padding,
887
+ top: obj.top + padding,
888
+ });
889
+ }
890
+ if (obj.fromPort.length) {
891
+ obj.fromPort.forEach((port) => {
892
+ if (port.links.length) {
893
+ port.links.forEach((link) => {
894
+ const linkTarget = {
895
+ fromNode: clonedObj.id,
896
+ fromPort: port.id,
897
+ };
898
+ const findIndex = clipboard
899
+ .getObjects()
900
+ .findIndex((compObj) => compObj.id === link.toNode.id);
901
+ if (findIndex >= 0) {
902
+ linkTarget.toNodeIndex = findIndex;
903
+ linkObjects.push(linkTarget);
904
+ }
905
+ });
906
+ }
907
+ });
908
+ }
909
+ if (clonedObj.dblclick) {
910
+ clonedObj.on('mousedblclick', this.eventHandler.object.mousedblclick);
911
+ }
912
+ this.canvas.add(clonedObj);
913
+ this.objects = this.getObjects();
914
+ this.portHandler.create(clonedObj);
915
+ objects.push(clonedObj);
916
+ });
917
+ if (linkObjects.length) {
918
+ linkObjects.forEach((linkObject) => {
919
+ const { fromNode, fromPort, toNodeIndex } = linkObject;
920
+ const toNode = objects[toNodeIndex];
921
+ const link = {
922
+ type: 'curvedLink',
923
+ fromNodeId: fromNode,
924
+ fromPortId: fromPort,
925
+ toNodeId: toNode.id,
926
+ toPortId: toNode.toPort.id,
927
+ };
928
+ this.linkHandler.create(link);
929
+ });
930
+ }
931
+ const activeSelection = new fabric_1.fabric.ActiveSelection(objects, {
932
+ canvas: this.canvas,
933
+ ...this.activeSelectionOption,
934
+ });
935
+ if (isCut) {
936
+ this.clipboard = null;
937
+ }
938
+ else {
939
+ this.clipboard = activeSelection;
940
+ }
941
+ if (!this.transactionHandler.active) {
942
+ this.transactionHandler.save('paste');
943
+ }
944
+ this.canvas.setActiveObject(activeSelection);
945
+ this.canvas.renderAll();
946
+ return true;
947
+ }
948
+ }
949
+ clipboard.clone((clonedObj) => {
950
+ this.canvas.discardActiveObject();
951
+ clonedObj.set({
952
+ left: clonedObj.left + padding,
953
+ top: clonedObj.top + padding,
954
+ id: isCut ? clipboard.id : uuidv4_1.uuid(),
955
+ evented: true,
956
+ });
957
+ if (clonedObj.type === 'activeSelection') {
958
+ clonedObj.canvas = this.canvas;
959
+ clonedObj.forEachObject((obj) => {
960
+ obj.set('id', isCut ? obj.id : uuidv4_1.uuid());
961
+ this.canvas.add(obj);
962
+ if (obj.dblclick) {
963
+ obj.on('mousedblclick', this.eventHandler.object.mousedblclick);
964
+ }
965
+ });
966
+ }
967
+ else {
968
+ if (clonedObj.superType === 'node') {
969
+ clonedObj = clonedObj.duplicate();
970
+ }
971
+ this.canvas.add(clonedObj);
972
+ if (clonedObj.dblclick) {
973
+ clonedObj.on('mousedblclick', this.eventHandler.object.mousedblclick);
974
+ }
975
+ }
976
+ const newClipboard = clipboard.set({
977
+ top: clonedObj.top,
978
+ left: clonedObj.left,
979
+ });
980
+ if (isCut) {
981
+ this.clipboard = null;
982
+ }
983
+ else {
984
+ this.clipboard = newClipboard;
985
+ }
986
+ if (clonedObj.superType === 'node') {
987
+ this.portHandler.create(clonedObj);
988
+ }
989
+ if (!this.transactionHandler.active) {
990
+ this.transactionHandler.save('paste');
991
+ }
992
+ // TODO...
993
+ // After toGroup svg elements not rendered.
994
+ this.objects = this.getObjects();
995
+ if (onAdd) {
996
+ onAdd(clonedObj);
997
+ }
998
+ clonedObj.setCoords();
999
+ this.canvas.setActiveObject(clonedObj);
1000
+ this.canvas.requestRenderAll();
1001
+ }, propertiesToInclude);
1002
+ return true;
1003
+ };
1004
+ /**
1005
+ * Load the image
1006
+ * @param {FabricImage} obj
1007
+ * @param {string} src
1008
+ */
1009
+ this.loadImage = (obj, src) => {
1010
+ let url = src;
1011
+ if (!url) {
1012
+ url = './images/sample/transparentBg.png';
1013
+ }
1014
+ fabric_1.fabric.util.loadImage(url, source => {
1015
+ if (obj.type !== 'image') {
1016
+ obj.set('fill', new fabric_1.fabric.Pattern({
1017
+ source,
1018
+ repeat: 'repeat',
1019
+ }));
1020
+ obj.setCoords();
1021
+ this.canvas.renderAll();
1022
+ return;
1023
+ }
1024
+ obj.setElement(source);
1025
+ obj.setCoords();
1026
+ this.canvas.renderAll();
1027
+ });
1028
+ };
1029
+ /**
1030
+ * Find object by object
1031
+ * @param {FabricObject} obj
1032
+ */
1033
+ this.find = (obj) => this.findById(obj.id);
1034
+ /**
1035
+ * Find object by id
1036
+ * @param {string} id
1037
+ * @returns {(FabricObject | null)}
1038
+ */
1039
+ this.findById = (id) => {
1040
+ let findObject;
1041
+ const exist = this.objects.some(obj => {
1042
+ if (obj.id === id) {
1043
+ findObject = obj;
1044
+ return true;
1045
+ }
1046
+ return false;
1047
+ });
1048
+ if (!exist) {
1049
+ warning_1.default(true, 'Not found object by id.');
1050
+ return null;
1051
+ }
1052
+ return findObject;
1053
+ };
1054
+ /**
1055
+ * Find object in origin list
1056
+ * @param {string} id
1057
+ * @returns
1058
+ */
1059
+ this.findOriginById = (id) => {
1060
+ let findObject;
1061
+ const exist = this.objects.some(obj => {
1062
+ if (obj.id === id) {
1063
+ findObject = obj;
1064
+ return true;
1065
+ }
1066
+ return false;
1067
+ });
1068
+ if (!exist) {
1069
+ console.warn('Not found object by id.');
1070
+ return null;
1071
+ }
1072
+ return findObject;
1073
+ };
1074
+ /**
1075
+ * Return origin object list
1076
+ * @param {string} id
1077
+ * @returns
1078
+ */
1079
+ this.findOriginByIdWithIndex = (id) => {
1080
+ let findObject;
1081
+ let index = -1;
1082
+ const exist = this.objects.some((obj, i) => {
1083
+ if (obj.id === id) {
1084
+ findObject = obj;
1085
+ index = i;
1086
+ return true;
1087
+ }
1088
+ return false;
1089
+ });
1090
+ if (!exist) {
1091
+ console.warn('Not found object by id.');
1092
+ return {};
1093
+ }
1094
+ return {
1095
+ object: findObject,
1096
+ index,
1097
+ };
1098
+ };
1099
+ /**
1100
+ * Select object
1101
+ * @param {FabricObject} obj
1102
+ * @param {boolean} [find]
1103
+ */
1104
+ this.select = (obj, find) => {
1105
+ let findObject = obj;
1106
+ if (find) {
1107
+ findObject = this.find(obj);
1108
+ }
1109
+ if (findObject) {
1110
+ this.canvas.discardActiveObject();
1111
+ this.canvas.setActiveObject(findObject);
1112
+ this.canvas.requestRenderAll();
1113
+ }
1114
+ };
1115
+ /**
1116
+ * Select by id
1117
+ * @param {string} id
1118
+ */
1119
+ this.selectById = (id) => {
1120
+ const findObject = this.findById(id);
1121
+ if (findObject) {
1122
+ this.canvas.discardActiveObject();
1123
+ this.canvas.setActiveObject(findObject);
1124
+ this.canvas.requestRenderAll();
1125
+ }
1126
+ };
1127
+ /**
1128
+ * Select all
1129
+ * @returns
1130
+ */
1131
+ this.selectAll = () => {
1132
+ this.canvas.discardActiveObject();
1133
+ const filteredObjects = this.canvas.getObjects().filter((obj) => {
1134
+ if (obj.id === 'workarea') {
1135
+ return false;
1136
+ }
1137
+ else if (!obj.evented) {
1138
+ return false;
1139
+ }
1140
+ else if (obj.superType === 'link') {
1141
+ return false;
1142
+ }
1143
+ else if (obj.superType === 'port') {
1144
+ return false;
1145
+ }
1146
+ else if (obj.superType === 'element') {
1147
+ return false;
1148
+ }
1149
+ else if (obj.locked) {
1150
+ return false;
1151
+ }
1152
+ return true;
1153
+ });
1154
+ if (!filteredObjects.length) {
1155
+ return;
1156
+ }
1157
+ if (filteredObjects.length === 1) {
1158
+ this.canvas.setActiveObject(filteredObjects[0]);
1159
+ this.canvas.renderAll();
1160
+ return;
1161
+ }
1162
+ const activeSelection = new fabric_1.fabric.ActiveSelection(filteredObjects, {
1163
+ canvas: this.canvas,
1164
+ ...this.activeSelectionOption,
1165
+ });
1166
+ this.canvas.setActiveObject(activeSelection);
1167
+ this.canvas.renderAll();
1168
+ };
1169
+ /**
1170
+ * Save origin width, height
1171
+ * @param {FabricObject} obj
1172
+ * @param {number} width
1173
+ * @param {number} height
1174
+ */
1175
+ this.originScaleToResize = (obj, width, height) => {
1176
+ if (obj.id === 'workarea') {
1177
+ this.setByPartial(obj, {
1178
+ workareaWidth: obj.width,
1179
+ workareaHeight: obj.height,
1180
+ });
1181
+ }
1182
+ this.setByPartial(obj, {
1183
+ scaleX: width / obj.width,
1184
+ scaleY: height / obj.height,
1185
+ });
1186
+ };
1187
+ /**
1188
+ * When set the width, height, Adjust the size
1189
+ * @param {number} width
1190
+ * @param {number} height
1191
+ */
1192
+ this.scaleToResize = (width, height) => {
1193
+ const activeObject = this.canvas.getActiveObject();
1194
+ const { id } = activeObject;
1195
+ const obj = {
1196
+ id,
1197
+ scaleX: width / activeObject.width,
1198
+ scaleY: height / activeObject.height,
1199
+ };
1200
+ this.setObject(obj);
1201
+ activeObject.setCoords();
1202
+ this.canvas.requestRenderAll();
1203
+ };
1204
+ /**
1205
+ * Import json
1206
+ * @param {*} json
1207
+ * @param {(canvas: FabricCanvas) => void} [callback]
1208
+ */
1209
+ this.importJSON = async (json, callback) => {
1210
+ if (typeof json === 'string') {
1211
+ json = JSON.parse(json);
1212
+ }
1213
+ let prevLeft = 0;
1214
+ let prevTop = 0;
1215
+ this.canvas.setBackgroundColor(this.canvasOption.backgroundColor, this.canvas.renderAll.bind(this.canvas));
1216
+ const workareaExist = json.filter((obj) => obj.id === 'workarea');
1217
+ if (!this.workarea) {
1218
+ this.workareaHandler.initialize();
1219
+ }
1220
+ if (!workareaExist.length) {
1221
+ this.canvas.centerObject(this.workarea);
1222
+ this.workarea.setCoords();
1223
+ prevLeft = this.workarea.left;
1224
+ prevTop = this.workarea.top;
1225
+ }
1226
+ else {
1227
+ const workarea = workareaExist[0];
1228
+ prevLeft = workarea.left;
1229
+ prevTop = workarea.top;
1230
+ this.workarea.set(workarea);
1231
+ await this.workareaHandler.setImage(workarea.src, true);
1232
+ this.workarea.setCoords();
1233
+ }
1234
+ json.forEach((obj) => {
1235
+ if (obj.id === 'workarea') {
1236
+ return;
1237
+ }
1238
+ const canvasWidth = this.canvas.getWidth();
1239
+ const canvasHeight = this.canvas.getHeight();
1240
+ const { width, height, scaleX, scaleY, layout, left, top } = this.workarea;
1241
+ if (layout === 'fullscreen') {
1242
+ const leftRatio = canvasWidth / (width * scaleX);
1243
+ const topRatio = canvasHeight / (height * scaleY);
1244
+ obj.left *= leftRatio;
1245
+ obj.top *= topRatio;
1246
+ obj.scaleX *= leftRatio;
1247
+ obj.scaleY *= topRatio;
1248
+ }
1249
+ else {
1250
+ const diffLeft = left - prevLeft;
1251
+ const diffTop = top - prevTop;
1252
+ obj.left += diffLeft;
1253
+ obj.top += diffTop;
1254
+ }
1255
+ if (obj.superType === 'element') {
1256
+ obj.id = uuidv4_1.uuid();
1257
+ }
1258
+ this.add(obj, false, true);
1259
+ this.canvas.renderAll();
1260
+ });
1261
+ this.objects = this.getObjects();
1262
+ if (callback) {
1263
+ callback(this.canvas);
1264
+ }
1265
+ return Promise.resolve(this.canvas);
1266
+ };
1267
+ /**
1268
+ * Export json
1269
+ */
1270
+ this.exportJSON = () => this.canvas.toObject(this.propertiesToInclude).objects;
1271
+ /**
1272
+ * Active selection to group
1273
+ * @returns
1274
+ */
1275
+ this.toGroup = (target) => {
1276
+ const activeObject = target || this.canvas.getActiveObject();
1277
+ if (!activeObject) {
1278
+ return null;
1279
+ }
1280
+ if (activeObject.type !== 'activeSelection') {
1281
+ return null;
1282
+ }
1283
+ const group = activeObject.toGroup();
1284
+ group.set({
1285
+ id: uuidv4_1.uuid(),
1286
+ name: 'New group',
1287
+ type: 'group',
1288
+ ...this.objectOption,
1289
+ });
1290
+ this.objects = this.getObjects();
1291
+ if (!this.transactionHandler.active) {
1292
+ this.transactionHandler.save('group');
1293
+ }
1294
+ if (this.onSelect) {
1295
+ this.onSelect(group);
1296
+ }
1297
+ this.canvas.renderAll();
1298
+ return group;
1299
+ };
1300
+ /**
1301
+ * Group to active selection
1302
+ * @returns
1303
+ */
1304
+ this.toActiveSelection = (target) => {
1305
+ const activeObject = target || this.canvas.getActiveObject();
1306
+ if (!activeObject) {
1307
+ return;
1308
+ }
1309
+ if (activeObject.type !== 'group') {
1310
+ return;
1311
+ }
1312
+ const activeSelection = activeObject.toActiveSelection();
1313
+ this.objects = this.getObjects();
1314
+ if (!this.transactionHandler.active) {
1315
+ this.transactionHandler.save('ungroup');
1316
+ }
1317
+ if (this.onSelect) {
1318
+ this.onSelect(activeSelection);
1319
+ }
1320
+ this.canvas.renderAll();
1321
+ return activeSelection;
1322
+ };
1323
+ /**
1324
+ * Bring forward
1325
+ */
1326
+ this.bringForward = () => {
1327
+ const activeObject = this.canvas.getActiveObject();
1328
+ if (activeObject) {
1329
+ this.canvas.bringForward(activeObject);
1330
+ if (!this.transactionHandler.active) {
1331
+ this.transactionHandler.save('bringForward');
1332
+ }
1333
+ const { onModified } = this;
1334
+ if (onModified) {
1335
+ onModified(activeObject);
1336
+ }
1337
+ }
1338
+ };
1339
+ /**
1340
+ * Bring to front
1341
+ */
1342
+ this.bringToFront = () => {
1343
+ const activeObject = this.canvas.getActiveObject();
1344
+ if (activeObject) {
1345
+ this.canvas.bringToFront(activeObject);
1346
+ if (!this.transactionHandler.active) {
1347
+ this.transactionHandler.save('bringToFront');
1348
+ }
1349
+ const { onModified } = this;
1350
+ if (onModified) {
1351
+ onModified(activeObject);
1352
+ }
1353
+ }
1354
+ };
1355
+ /**
1356
+ * Send backwards
1357
+ * @returns
1358
+ */
1359
+ this.sendBackwards = () => {
1360
+ const activeObject = this.canvas.getActiveObject();
1361
+ if (activeObject) {
1362
+ const firstObject = this.canvas.getObjects()[1];
1363
+ if (firstObject.id === activeObject.id) {
1364
+ return;
1365
+ }
1366
+ if (!this.transactionHandler.active) {
1367
+ this.transactionHandler.save('sendBackwards');
1368
+ }
1369
+ this.canvas.sendBackwards(activeObject);
1370
+ const { onModified } = this;
1371
+ if (onModified) {
1372
+ onModified(activeObject);
1373
+ }
1374
+ }
1375
+ };
1376
+ /**
1377
+ * Send to back
1378
+ */
1379
+ this.sendToBack = () => {
1380
+ const activeObject = this.canvas.getActiveObject();
1381
+ if (activeObject) {
1382
+ this.canvas.sendToBack(activeObject);
1383
+ this.canvas.sendToBack(this.canvas.getObjects()[1]);
1384
+ if (!this.transactionHandler.active) {
1385
+ this.transactionHandler.save('sendToBack');
1386
+ }
1387
+ const { onModified } = this;
1388
+ if (onModified) {
1389
+ onModified(activeObject);
1390
+ }
1391
+ }
1392
+ };
1393
+ /**
1394
+ * Clear canvas
1395
+ * @param {boolean} [includeWorkarea=false]
1396
+ */
1397
+ this.clear = (includeWorkarea = false) => {
1398
+ const ids = this.canvas.getObjects().reduce((prev, curr) => {
1399
+ if (curr.superType === 'element') {
1400
+ prev.push(curr.id);
1401
+ return prev;
1402
+ }
1403
+ return prev;
1404
+ }, []);
1405
+ this.elementHandler.removeByIds(ids);
1406
+ if (includeWorkarea) {
1407
+ this.canvas.clear();
1408
+ this.workarea = null;
1409
+ }
1410
+ else {
1411
+ this.canvas.discardActiveObject();
1412
+ this.canvas.getObjects().forEach((obj) => {
1413
+ if (obj.id === 'grid' || obj.id === 'workarea') {
1414
+ return;
1415
+ }
1416
+ this.canvas.remove(obj);
1417
+ });
1418
+ }
1419
+ this.objects = this.getObjects();
1420
+ this.canvas.renderAll();
1421
+ };
1422
+ /**
1423
+ * Start request animation frame
1424
+ */
1425
+ this.startRequestAnimFrame = () => {
1426
+ if (!this.isRequsetAnimFrame) {
1427
+ this.isRequsetAnimFrame = true;
1428
+ const render = () => {
1429
+ this.canvas.renderAll();
1430
+ this.requestFrame = fabric_1.fabric.util.requestAnimFrame(render);
1431
+ };
1432
+ fabric_1.fabric.util.requestAnimFrame(render);
1433
+ }
1434
+ };
1435
+ /**
1436
+ * Stop request animation frame
1437
+ */
1438
+ this.stopRequestAnimFrame = () => {
1439
+ this.isRequsetAnimFrame = false;
1440
+ const cancelRequestAnimFrame = (() => window.cancelAnimationFrame ||
1441
+ // || window.webkitCancelRequestAnimationFrame
1442
+ // || window.mozCancelRequestAnimationFrame
1443
+ // || window.oCancelRequestAnimationFrame
1444
+ // || window.msCancelRequestAnimationFrame
1445
+ clearTimeout)();
1446
+ cancelRequestAnimFrame(this.requestFrame);
1447
+ };
1448
+ /**
1449
+ * Save target object as image
1450
+ * @param {FabricObject} targetObject
1451
+ * @param {string} [option={ name: 'New Image', format: 'png', quality: 1 }]
1452
+ */
1453
+ this.saveImage = (targetObject, option = { name: 'New Image', format: 'png', quality: 1 }) => {
1454
+ let dataUrl;
1455
+ let target = targetObject;
1456
+ if (target) {
1457
+ dataUrl = target.toDataURL(option);
1458
+ }
1459
+ else {
1460
+ target = this.canvas.getActiveObject();
1461
+ if (target) {
1462
+ dataUrl = target.toDataURL(option);
1463
+ }
1464
+ }
1465
+ if (dataUrl) {
1466
+ const anchorEl = document.createElement('a');
1467
+ anchorEl.href = dataUrl;
1468
+ anchorEl.download = `${option.name}.png`;
1469
+ document.body.appendChild(anchorEl); // required for firefox
1470
+ anchorEl.click();
1471
+ anchorEl.remove();
1472
+ }
1473
+ };
1474
+ /**
1475
+ * Save canvas as image
1476
+ * @param {string} [option={ name: 'New Image', format: 'png', quality: 1 }]
1477
+ */
1478
+ this.saveCanvasImage = (option = { name: 'New Image', format: 'png', quality: 1 }) => {
1479
+ const dataUrl = this.canvas.toDataURL(option);
1480
+ if (dataUrl) {
1481
+ const anchorEl = document.createElement('a');
1482
+ anchorEl.href = dataUrl;
1483
+ anchorEl.download = `${option.name}.png`;
1484
+ document.body.appendChild(anchorEl); // required for firefox
1485
+ anchorEl.click();
1486
+ anchorEl.remove();
1487
+ }
1488
+ };
1489
+ /**
1490
+ * Sets "angle" of an instance with centered rotation
1491
+ *
1492
+ * @param {number} angle
1493
+ */
1494
+ this.rotate = (angle) => {
1495
+ const activeObject = this.canvas.getActiveObject();
1496
+ if (activeObject) {
1497
+ this.set('rotation', angle);
1498
+ activeObject.rotate(angle);
1499
+ this.canvas.requestRenderAll();
1500
+ }
1501
+ };
1502
+ /**
1503
+ * Destroy canvas
1504
+ *
1505
+ */
1506
+ this.destroy = () => {
1507
+ this.eventHandler.destroy();
1508
+ this.guidelineHandler.destroy();
1509
+ this.contextmenuHandler.destory();
1510
+ this.tooltipHandler.destroy();
1511
+ this.clear(true);
1512
+ };
1513
+ /**
1514
+ * Set canvas option
1515
+ *
1516
+ * @param {CanvasOption} canvasOption
1517
+ */
1518
+ this.setCanvasOption = (canvasOption) => {
1519
+ this.canvasOption = Object.assign({}, this.canvasOption, canvasOption);
1520
+ this.canvas.setBackgroundColor(canvasOption.backgroundColor, this.canvas.renderAll.bind(this.canvas));
1521
+ if (typeof canvasOption.width !== 'undefined' && typeof canvasOption.height !== 'undefined') {
1522
+ if (this.eventHandler) {
1523
+ this.eventHandler.resize(canvasOption.width, canvasOption.height);
1524
+ }
1525
+ else {
1526
+ this.canvas.setWidth(canvasOption.width).setHeight(canvasOption.height);
1527
+ }
1528
+ }
1529
+ if (typeof canvasOption.selection !== 'undefined') {
1530
+ this.canvas.selection = canvasOption.selection;
1531
+ }
1532
+ if (typeof canvasOption.hoverCursor !== 'undefined') {
1533
+ this.canvas.hoverCursor = canvasOption.hoverCursor;
1534
+ }
1535
+ if (typeof canvasOption.defaultCursor !== 'undefined') {
1536
+ this.canvas.defaultCursor = canvasOption.defaultCursor;
1537
+ }
1538
+ if (typeof canvasOption.preserveObjectStacking !== 'undefined') {
1539
+ this.canvas.preserveObjectStacking = canvasOption.preserveObjectStacking;
1540
+ }
1541
+ };
1542
+ /**
1543
+ * Set keyboard event
1544
+ *
1545
+ * @param {KeyEvent} keyEvent
1546
+ */
1547
+ this.setKeyEvent = (keyEvent) => {
1548
+ this.keyEvent = Object.assign({}, this.keyEvent, keyEvent);
1549
+ };
1550
+ /**
1551
+ * Set fabric objects
1552
+ *
1553
+ * @param {FabricObjects} fabricObjects
1554
+ */
1555
+ this.setFabricObjects = (fabricObjects) => {
1556
+ this.fabricObjects = Object.assign({}, this.fabricObjects, fabricObjects);
1557
+ };
1558
+ /**
1559
+ * Set workarea option
1560
+ *
1561
+ * @param {WorkareaOption} workareaOption
1562
+ */
1563
+ this.setWorkareaOption = (workareaOption) => {
1564
+ this.workareaOption = Object.assign({}, this.workareaOption, workareaOption);
1565
+ if (this.workarea) {
1566
+ this.workarea.set({
1567
+ ...workareaOption,
1568
+ });
1569
+ }
1570
+ };
1571
+ /**
1572
+ * Set guideline option
1573
+ *
1574
+ * @param {GuidelineOption} guidelineOption
1575
+ */
1576
+ this.setGuidelineOption = (guidelineOption) => {
1577
+ this.guidelineOption = Object.assign({}, this.guidelineOption, guidelineOption);
1578
+ if (this.guidelineHandler) {
1579
+ this.guidelineHandler.initialize();
1580
+ }
1581
+ };
1582
+ /**
1583
+ * Set grid option
1584
+ *
1585
+ * @param {GridOption} gridOption
1586
+ */
1587
+ this.setGridOption = (gridOption) => {
1588
+ this.gridOption = Object.assign({}, this.gridOption, gridOption);
1589
+ };
1590
+ /**
1591
+ * Set object option
1592
+ *
1593
+ * @param {FabricObjectOption} objectOption
1594
+ */
1595
+ this.setObjectOption = (objectOption) => {
1596
+ this.objectOption = Object.assign({}, this.objectOption, objectOption);
1597
+ };
1598
+ /**
1599
+ * Set activeSelection option
1600
+ *
1601
+ * @param {Partial<FabricObjectOption<fabric.ActiveSelection>>} activeSelectionOption
1602
+ */
1603
+ this.setActiveSelectionOption = (activeSelectionOption) => {
1604
+ this.activeSelectionOption = Object.assign({}, this.activeSelectionOption, activeSelectionOption);
1605
+ };
1606
+ /**
1607
+ * Set propertiesToInclude
1608
+ *
1609
+ * @param {string[]} propertiesToInclude
1610
+ */
1611
+ this.setPropertiesToInclude = (propertiesToInclude) => {
1612
+ this.propertiesToInclude = lodash_1.union(propertiesToInclude, this.propertiesToInclude);
1613
+ };
1614
+ /**
1615
+ * Register custom handler
1616
+ *
1617
+ * @param {string} name
1618
+ * @param {typeof CustomHandler} handler
1619
+ */
1620
+ this.registerHandler = (name, handler) => {
1621
+ this.handlers[name] = new handler(this);
1622
+ return this.handlers[name];
1623
+ };
1624
+ this.initialize(options);
1625
+ }
1626
+ /**
1627
+ * Initialize handler
1628
+ *
1629
+ * @author salgum1114
1630
+ * @param {HandlerOptions} options
1631
+ */
1632
+ initialize(options) {
1633
+ this.initOption(options);
1634
+ this.initCallback(options);
1635
+ this.initHandler();
1636
+ }
1637
+ }
1638
+ exports.default = Handler;