react-design-editor 0.0.50 → 0.0.52

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