react-design-editor 0.0.37 → 0.0.41

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