react-design-editor 0.0.49 → 0.0.51

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