react-design-editor 0.0.32 → 0.0.36

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