@leapfrog/interactive-canvas 2.0.25-beta-7 → 2.0.25-beta-8
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.
- package/dist/abstract-interactive-canvas.d.ts +0 -1
- package/dist/interactive-canvas.d.ts +1 -0
- package/dist/interactive-canvas.es.js +80 -102
- package/dist/interactive-canvas.js +80 -102
- package/dist/layout/advanced-layout-manager.d.ts +0 -1
- package/dist/layout/standard-layout-manager.d.ts +0 -1
- package/dist/object/impl/text.d.ts +0 -2
- package/package.json +1 -1
|
@@ -340,7 +340,6 @@ export declare abstract class AbstractInteractiveCanvas implements IInteractiveC
|
|
|
340
340
|
* @inheritDoc
|
|
341
341
|
*/
|
|
342
342
|
cloneObject(sourceObject: FabricObject, objectData: CanvasObjectData): Promise<void>;
|
|
343
|
-
private redrawScheduled;
|
|
344
343
|
/**
|
|
345
344
|
* Redraw the canvas.
|
|
346
345
|
*/
|
|
@@ -232,18 +232,9 @@ class ResizeCanvasLayoutFunction {
|
|
|
232
232
|
const targetHeight = increase.withSize(increase.width, baseDimensions.height + increase.height);
|
|
233
233
|
if (currentDimensions.height !== targetHeight.height) {
|
|
234
234
|
canvas.setDimensions(targetHeight);
|
|
235
|
-
// Only update coords for objects affected by height change (pinned to bottom, etc.)
|
|
236
|
-
// This is much faster than updating all objects on slow machines
|
|
237
|
-
canvas.getObjectsInternal().forEach((object) => {
|
|
238
|
-
var _a;
|
|
239
|
-
const canvasObj = canvas.getObjectsByTypeInternal(object.type).find(o => o.getId() === object.getId());
|
|
240
|
-
// Only update coords for objects that are positioned relative to canvas bottom or that might be affected
|
|
241
|
-
if (canvasObj && (((_a = canvasObj.isPinToBottom) === null || _a === void 0 ? void 0 : _a.call(canvasObj)) || object.top > currentDimensions.heightPx * 0.5)) {
|
|
242
|
-
object.setCoords();
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
canvas.redraw();
|
|
246
235
|
}
|
|
236
|
+
canvas.getObjectsInternal().forEach((object) => object.setCoords());
|
|
237
|
+
canvas.redraw();
|
|
247
238
|
}
|
|
248
239
|
}
|
|
249
240
|
|
|
@@ -271,22 +262,13 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
271
262
|
this.repositionCutoffs = new RepositionCutoffsLayoutFunction();
|
|
272
263
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
273
264
|
this.resizeCanvas = new ResizeCanvasLayoutFunction();
|
|
274
|
-
this.dimensionsLayoutScheduled = false;
|
|
275
265
|
}
|
|
276
266
|
onCanvasDimensionsChange() {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.
|
|
282
|
-
Promise.resolve().then(() => {
|
|
283
|
-
this.pinToBottom.execute(this.canvas);
|
|
284
|
-
this.repositionCutoffs.execute(this.canvas);
|
|
285
|
-
this.repositionBorders.execute(this.canvas);
|
|
286
|
-
this.repositionBackgrounds.execute(this.canvas);
|
|
287
|
-
this.redrawAll.execute(this.canvas);
|
|
288
|
-
this.dimensionsLayoutScheduled = false;
|
|
289
|
-
});
|
|
267
|
+
this.pinToBottom.execute(this.canvas);
|
|
268
|
+
this.repositionCutoffs.execute(this.canvas);
|
|
269
|
+
this.repositionBorders.execute(this.canvas);
|
|
270
|
+
this.repositionBackgrounds.execute(this.canvas);
|
|
271
|
+
this.redrawAll.execute(this.canvas);
|
|
290
272
|
}
|
|
291
273
|
onTextChange() {
|
|
292
274
|
this.resizeCanvas.execute(this.canvas);
|
|
@@ -314,9 +296,7 @@ class StackObjectsLayoutFunction {
|
|
|
314
296
|
const footerObjects = objects[0];
|
|
315
297
|
const bodyObjects = objects[1];
|
|
316
298
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
317
|
-
|
|
318
|
-
// No need to redraw here - it will be called by the layout manager after all layout functions complete
|
|
319
|
-
// This reduces redundant render passes significantly
|
|
299
|
+
canvas.redraw();
|
|
320
300
|
//Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
|
|
321
301
|
this.applyWidths(allObjects, bodyWidth);
|
|
322
302
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -403,11 +383,7 @@ class StackObjectsLayoutFunction {
|
|
|
403
383
|
object.setPosition({
|
|
404
384
|
width: actualWidth
|
|
405
385
|
});
|
|
406
|
-
|
|
407
|
-
if (object.getType() !== ObjectType.VERTICAL_RULE) {
|
|
408
|
-
object.updateDimensions();
|
|
409
|
-
}
|
|
410
|
-
});
|
|
386
|
+
object.updateDimensions();
|
|
411
387
|
});
|
|
412
388
|
}
|
|
413
389
|
adjustCanvasSize(canvas, requiredHeight) {
|
|
@@ -480,7 +456,6 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
480
456
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
481
457
|
this.stackObjects = new StackObjectsLayoutFunction();
|
|
482
458
|
this.updateObjectDimensions = new UpdateObjectDimensionsLayoutFunction();
|
|
483
|
-
this.layoutBatchScheduled = false;
|
|
484
459
|
}
|
|
485
460
|
/**
|
|
486
461
|
* @override
|
|
@@ -522,21 +497,12 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
522
497
|
this.stackAndRedraw();
|
|
523
498
|
}
|
|
524
499
|
stackAndRedraw() {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
this.
|
|
530
|
-
|
|
531
|
-
Promise.resolve().then(() => {
|
|
532
|
-
this.stackObjects.execute(this.canvas);
|
|
533
|
-
this.repositionCutoffs.execute(this.canvas);
|
|
534
|
-
this.repositionBorders.execute(this.canvas);
|
|
535
|
-
this.repositionBackgrounds.execute(this.canvas);
|
|
536
|
-
this.updateObjectDimensions.execute(this.canvas);
|
|
537
|
-
this.redrawAll.execute(this.canvas);
|
|
538
|
-
this.layoutBatchScheduled = false;
|
|
539
|
-
});
|
|
500
|
+
this.stackObjects.execute(this.canvas);
|
|
501
|
+
this.repositionCutoffs.execute(this.canvas);
|
|
502
|
+
this.repositionBorders.execute(this.canvas);
|
|
503
|
+
this.repositionBackgrounds.execute(this.canvas);
|
|
504
|
+
this.updateObjectDimensions.execute(this.canvas);
|
|
505
|
+
this.redrawAll.execute(this.canvas);
|
|
540
506
|
}
|
|
541
507
|
}
|
|
542
508
|
|
|
@@ -1814,16 +1780,12 @@ var ObjectType;
|
|
|
1814
1780
|
class Text extends AbstractCanvasObject {
|
|
1815
1781
|
constructor(canvas, fabricObject, persistedField) {
|
|
1816
1782
|
super(ObjectType.TEXT, canvas, fabricObject, persistedField);
|
|
1817
|
-
//private notifyCanvasTimeout: NodeJS.Timeout | null = null;
|
|
1818
|
-
this.notifyCanvasTimeout = null;
|
|
1819
|
-
this.NOTIFY_DELAY_MS = 150; // Debounce canvas notifications
|
|
1820
1783
|
this.canvas = canvas;
|
|
1821
1784
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1822
1785
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1823
1786
|
this.text$ = new BehaviorSubject(this.fabricObject.text);
|
|
1824
1787
|
this.data.userText = this.fabricObject.text;
|
|
1825
1788
|
this.textSelection$ = new BehaviorSubject(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
1826
|
-
console.log(`inside constructor in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
1827
1789
|
this.fabricObject.set({ strokeWidth: 0 });
|
|
1828
1790
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1829
1791
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
@@ -2563,54 +2525,30 @@ class Text extends AbstractCanvasObject {
|
|
|
2563
2525
|
this.redraw();
|
|
2564
2526
|
}
|
|
2565
2527
|
onTextChange() {
|
|
2566
|
-
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2567
2528
|
this.data.userText = this.fabricObject.text;
|
|
2568
2529
|
this.text$.next(this.fabricObject.text);
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
// Skip expensive getBoundingBox if object is clearly within bounds
|
|
2573
|
-
if (currentLeft + (this.fabricObject.width || 0) > canvasWidth * 0.9) {
|
|
2574
|
-
console.log(`inside if onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2575
|
-
if (this.getBoundingBox().width > canvasWidth) {
|
|
2576
|
-
this.fabricObject.set({ left: 0, width: canvasWidth });
|
|
2577
|
-
this.redraw();
|
|
2578
|
-
}
|
|
2530
|
+
if (this.getBoundingBox().width > this.canvas.getDimensions().widthPx) {
|
|
2531
|
+
this.fabricObject.set({ left: 0, width: this.canvas.getDimensions().widthPx });
|
|
2532
|
+
this.redraw();
|
|
2579
2533
|
}
|
|
2580
|
-
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2581
2534
|
}
|
|
2582
2535
|
onDelete() {
|
|
2583
2536
|
this.removeBullets();
|
|
2584
2537
|
}
|
|
2585
2538
|
onSelectionChange() {
|
|
2586
|
-
|
|
2587
|
-
this.updateTextSelection(false);
|
|
2539
|
+
this.updateTextSelection();
|
|
2588
2540
|
}
|
|
2589
2541
|
hasTextSelection() {
|
|
2590
2542
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2591
2543
|
}
|
|
2592
|
-
updateTextSelection(
|
|
2593
|
-
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2544
|
+
updateTextSelection() {
|
|
2594
2545
|
if (this.canvas.headless)
|
|
2595
2546
|
return;
|
|
2596
2547
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2597
|
-
|
|
2598
|
-
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2599
|
-
this.notifyCanvasOfTextChanges();
|
|
2600
|
-
}
|
|
2548
|
+
this.notifyCanvasOfTextChanges();
|
|
2601
2549
|
}
|
|
2602
2550
|
notifyCanvasOfTextChanges() {
|
|
2603
|
-
|
|
2604
|
-
if (this.notifyCanvasTimeout) {
|
|
2605
|
-
console.log(`inside timeout if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2606
|
-
clearTimeout(this.notifyCanvasTimeout);
|
|
2607
|
-
}
|
|
2608
|
-
this.notifyCanvasTimeout = setTimeout(() => {
|
|
2609
|
-
console.log(`start of setTimeout in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2610
|
-
this.canvas.notifyTextChanged();
|
|
2611
|
-
this.notifyCanvasTimeout = null;
|
|
2612
|
-
}, this.NOTIFY_DELAY_MS);
|
|
2613
|
-
console.log(`end of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2551
|
+
this.canvas.notifyTextChanged();
|
|
2614
2552
|
}
|
|
2615
2553
|
}
|
|
2616
2554
|
Text.NEW_LINE = "\n";
|
|
@@ -2618,7 +2556,6 @@ class TextSelection {
|
|
|
2618
2556
|
constructor(fabricObject, fontLibrary) {
|
|
2619
2557
|
this.fabricObject = fabricObject;
|
|
2620
2558
|
this.fontLibrary = fontLibrary;
|
|
2621
|
-
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2622
2559
|
this.start = this.fabricObject.selectionStart;
|
|
2623
2560
|
this.end = this.fabricObject.selectionEnd;
|
|
2624
2561
|
this.length = this.end - this.start;
|
|
@@ -2777,7 +2714,6 @@ class AbstractInteractiveCanvas {
|
|
|
2777
2714
|
this.devicePixelRatio = devicePixelRatio;
|
|
2778
2715
|
this.fontLibrary = new FontLibrary();
|
|
2779
2716
|
this.dimensionChangeRejections$ = new Subject();
|
|
2780
|
-
this.redrawScheduled = false;
|
|
2781
2717
|
this.IMAGE_CAPTURE_COEFFICIENT = this.calculateImageCaptureCoefficient();
|
|
2782
2718
|
/**
|
|
2783
2719
|
* Fabric defaults to only 2 decimal places when saving, which causes havoc on the scaling of large images.
|
|
@@ -2800,7 +2736,7 @@ class AbstractInteractiveCanvas {
|
|
|
2800
2736
|
this.fabricCanvas.stateful = true;
|
|
2801
2737
|
this.fabricCanvas.preserveObjectStacking = true;
|
|
2802
2738
|
this.fabricCanvas.perPixelTargetFind = true;
|
|
2803
|
-
this.fabricCanvas.targetFindTolerance =
|
|
2739
|
+
this.fabricCanvas.targetFindTolerance = 4;
|
|
2804
2740
|
this.setBackgroundColor("#FFFFFF");
|
|
2805
2741
|
}
|
|
2806
2742
|
/**
|
|
@@ -3194,7 +3130,11 @@ class AbstractInteractiveCanvas {
|
|
|
3194
3130
|
charSpacing: profile.defaultCharacterSpacing,
|
|
3195
3131
|
perPixelTargetFind: false,
|
|
3196
3132
|
targetFindTolerance: 4,
|
|
3197
|
-
splitByGrapheme: true
|
|
3133
|
+
splitByGrapheme: true,
|
|
3134
|
+
editable: false, // Only enable on double-click
|
|
3135
|
+
padding: 0,
|
|
3136
|
+
cornerSize: 8,
|
|
3137
|
+
touchCornerSize: 12
|
|
3198
3138
|
};
|
|
3199
3139
|
const fabricTextbox = new this.fabric.Textbox("Text goes here", textOptions);
|
|
3200
3140
|
this.fabricCanvas.add(fabricTextbox);
|
|
@@ -3643,16 +3583,7 @@ class AbstractInteractiveCanvas {
|
|
|
3643
3583
|
* Redraw the canvas.
|
|
3644
3584
|
*/
|
|
3645
3585
|
redraw() {
|
|
3646
|
-
|
|
3647
|
-
if (this.redrawScheduled) {
|
|
3648
|
-
return; // Already scheduled, don't schedule again
|
|
3649
|
-
}
|
|
3650
|
-
this.redrawScheduled = true;
|
|
3651
|
-
// Use requestAnimationFrame for smoother rendering and automatic batching
|
|
3652
|
-
requestAnimationFrame(() => {
|
|
3653
|
-
this.fabricCanvas.requestRenderAll();
|
|
3654
|
-
this.redrawScheduled = false;
|
|
3655
|
-
});
|
|
3586
|
+
this.fabricCanvas.requestRenderAll();
|
|
3656
3587
|
}
|
|
3657
3588
|
syncObjectList() {
|
|
3658
3589
|
const newObjectList = _(this.fabricCanvas.getObjects())
|
|
@@ -3778,6 +3709,7 @@ class AbstractInteractiveCanvas {
|
|
|
3778
3709
|
* Update the actual dimensions of the canvas by multiplying the requested dimensions by the current zoom factor.
|
|
3779
3710
|
*/
|
|
3780
3711
|
updateCanvasDimensions(dims, zoom) {
|
|
3712
|
+
const oldWidth = this.fabricCanvas.getWidth();
|
|
3781
3713
|
const width = dims.widthPx * zoom;
|
|
3782
3714
|
const height = dims.heightPx * zoom;
|
|
3783
3715
|
this.fabricCanvas.setZoom(zoom);
|
|
@@ -3785,6 +3717,34 @@ class AbstractInteractiveCanvas {
|
|
|
3785
3717
|
width,
|
|
3786
3718
|
height
|
|
3787
3719
|
});
|
|
3720
|
+
const scaleFactor = width / oldWidth;
|
|
3721
|
+
const objects = this.fabricCanvas.getObjects();
|
|
3722
|
+
objects.forEach((obj) => {
|
|
3723
|
+
obj.set({
|
|
3724
|
+
left: obj.left * scaleFactor,
|
|
3725
|
+
});
|
|
3726
|
+
if (obj.type === "textbox" || obj.type === "text") {
|
|
3727
|
+
obj.set({
|
|
3728
|
+
scaleX: 1,
|
|
3729
|
+
scaleY: 1,
|
|
3730
|
+
width: obj.width * scaleFactor,
|
|
3731
|
+
});
|
|
3732
|
+
}
|
|
3733
|
+
else if (obj.type === "border" || obj.type === "rect") {
|
|
3734
|
+
obj.set({
|
|
3735
|
+
width: obj.width * scaleFactor,
|
|
3736
|
+
scaleX: 1,
|
|
3737
|
+
strokeUniform: true,
|
|
3738
|
+
});
|
|
3739
|
+
}
|
|
3740
|
+
else {
|
|
3741
|
+
obj.set({
|
|
3742
|
+
scaleX: obj.scaleX * scaleFactor,
|
|
3743
|
+
});
|
|
3744
|
+
}
|
|
3745
|
+
obj.setCoords();
|
|
3746
|
+
});
|
|
3747
|
+
this.fabricCanvas.requestRenderAll();
|
|
3788
3748
|
}
|
|
3789
3749
|
onProfileChanged(profile) {
|
|
3790
3750
|
this.setMultiSelect(profile.allowMultiSelect);
|
|
@@ -3939,8 +3899,18 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3939
3899
|
this.fabricCanvas.on("selection:created", (event) => this.onFabricSelectionChanged(event));
|
|
3940
3900
|
this.fabricCanvas.on("selection:cleared", (event) => this.onFabricSelectionChanged(event));
|
|
3941
3901
|
this.fabricCanvas.on("text:editing:entered", () => this.onTextEditing());
|
|
3942
|
-
this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3902
|
+
//this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3903
|
+
this.fabricCanvas.on("text:editing:exited", (event) => {
|
|
3904
|
+
this.onTextEditing();
|
|
3905
|
+
const target = event.target;
|
|
3906
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
3907
|
+
target.set({ editable: false, hoverCursor: 'move' });
|
|
3908
|
+
}
|
|
3909
|
+
});
|
|
3943
3910
|
this.fabricCanvas.on("text:changed", () => this.onTextChange());
|
|
3911
|
+
// Handle double-click on textbox to enter editing mode
|
|
3912
|
+
// @ts-ignore
|
|
3913
|
+
this.fabricCanvas.on("mouse:dblclick", (event) => this.onDoubleClick(event));
|
|
3944
3914
|
}
|
|
3945
3915
|
/**
|
|
3946
3916
|
* @override
|
|
@@ -3968,7 +3938,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3968
3938
|
});
|
|
3969
3939
|
}
|
|
3970
3940
|
onFabricSelectionChanged(event) {
|
|
3971
|
-
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3972
3941
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3973
3942
|
const selection = new SelectionData(selected);
|
|
3974
3943
|
if (event) {
|
|
@@ -3979,7 +3948,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3979
3948
|
}
|
|
3980
3949
|
enterTextSelectionModeIfRequired() {
|
|
3981
3950
|
var _a, _b;
|
|
3982
|
-
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3983
3951
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
3984
3952
|
return;
|
|
3985
3953
|
if (((_b = (_a = this.selection$.value) === null || _a === void 0 ? void 0 : _a.objects[0]) === null || _b === void 0 ? void 0 : _b.getType()) !== ObjectType.TEXT)
|
|
@@ -3988,10 +3956,20 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3988
3956
|
text.enterEditing();
|
|
3989
3957
|
}
|
|
3990
3958
|
onTextEditing() {
|
|
3991
|
-
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3992
3959
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3993
3960
|
this.selection$.next(new SelectionData(selected));
|
|
3994
3961
|
}
|
|
3962
|
+
onDoubleClick(event) {
|
|
3963
|
+
const target = event.target;
|
|
3964
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
3965
|
+
if (!target.isEditing) {
|
|
3966
|
+
target.set({ editable: true, hoverCursor: 'text' });
|
|
3967
|
+
// target.enterEditing();
|
|
3968
|
+
// target.hiddenTextarea?.focus();
|
|
3969
|
+
this.enterTextSelectionModeIfRequired();
|
|
3970
|
+
}
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3995
3973
|
}
|
|
3996
3974
|
|
|
3997
3975
|
export { AbstractCanvasObject, AbstractInteractiveCanvas, AbstractLayoutManager, AdvancedLayoutManager, BackgroundImage, Border, CanvasObjectData, Cutoff, DefaultCanvasProfile, Font, FontLibrary, HeadlessInteractiveCanvas, HorizontalRule, Image, ImageType, InteractiveCanvas, LayoutManager, MillimeterDimensions, ObjectType, PixelCanvasDimensions, Print6ColCanvasDimensions, Print8ColCanvasDimensions, Rectangle, RichText, SelectionData, StandardLayoutManager, Text, UNKNOWN_FONT, UnknownFont, VerticalRule, isMutableBackgroundColor, isMutableColor, isMutableImage, isMutablePosition, isMutableStroke, isMutableText, isMutableTextStyle };
|
|
@@ -253,18 +253,9 @@ class ResizeCanvasLayoutFunction {
|
|
|
253
253
|
const targetHeight = increase.withSize(increase.width, baseDimensions.height + increase.height);
|
|
254
254
|
if (currentDimensions.height !== targetHeight.height) {
|
|
255
255
|
canvas.setDimensions(targetHeight);
|
|
256
|
-
// Only update coords for objects affected by height change (pinned to bottom, etc.)
|
|
257
|
-
// This is much faster than updating all objects on slow machines
|
|
258
|
-
canvas.getObjectsInternal().forEach((object) => {
|
|
259
|
-
var _a;
|
|
260
|
-
const canvasObj = canvas.getObjectsByTypeInternal(object.type).find(o => o.getId() === object.getId());
|
|
261
|
-
// Only update coords for objects that are positioned relative to canvas bottom or that might be affected
|
|
262
|
-
if (canvasObj && (((_a = canvasObj.isPinToBottom) === null || _a === void 0 ? void 0 : _a.call(canvasObj)) || object.top > currentDimensions.heightPx * 0.5)) {
|
|
263
|
-
object.setCoords();
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
canvas.redraw();
|
|
267
256
|
}
|
|
257
|
+
canvas.getObjectsInternal().forEach((object) => object.setCoords());
|
|
258
|
+
canvas.redraw();
|
|
268
259
|
}
|
|
269
260
|
}
|
|
270
261
|
|
|
@@ -292,22 +283,13 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
292
283
|
this.repositionCutoffs = new RepositionCutoffsLayoutFunction();
|
|
293
284
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
294
285
|
this.resizeCanvas = new ResizeCanvasLayoutFunction();
|
|
295
|
-
this.dimensionsLayoutScheduled = false;
|
|
296
286
|
}
|
|
297
287
|
onCanvasDimensionsChange() {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
this.
|
|
303
|
-
Promise.resolve().then(() => {
|
|
304
|
-
this.pinToBottom.execute(this.canvas);
|
|
305
|
-
this.repositionCutoffs.execute(this.canvas);
|
|
306
|
-
this.repositionBorders.execute(this.canvas);
|
|
307
|
-
this.repositionBackgrounds.execute(this.canvas);
|
|
308
|
-
this.redrawAll.execute(this.canvas);
|
|
309
|
-
this.dimensionsLayoutScheduled = false;
|
|
310
|
-
});
|
|
288
|
+
this.pinToBottom.execute(this.canvas);
|
|
289
|
+
this.repositionCutoffs.execute(this.canvas);
|
|
290
|
+
this.repositionBorders.execute(this.canvas);
|
|
291
|
+
this.repositionBackgrounds.execute(this.canvas);
|
|
292
|
+
this.redrawAll.execute(this.canvas);
|
|
311
293
|
}
|
|
312
294
|
onTextChange() {
|
|
313
295
|
this.resizeCanvas.execute(this.canvas);
|
|
@@ -335,9 +317,7 @@ class StackObjectsLayoutFunction {
|
|
|
335
317
|
const footerObjects = objects[0];
|
|
336
318
|
const bodyObjects = objects[1];
|
|
337
319
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
338
|
-
|
|
339
|
-
// No need to redraw here - it will be called by the layout manager after all layout functions complete
|
|
340
|
-
// This reduces redundant render passes significantly
|
|
320
|
+
canvas.redraw();
|
|
341
321
|
//Make one pass and set the widths of all elements. This will force objects with dynamic heights (like text) to take on their necessary height before trying to lay them out.
|
|
342
322
|
this.applyWidths(allObjects, bodyWidth);
|
|
343
323
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -424,11 +404,7 @@ class StackObjectsLayoutFunction {
|
|
|
424
404
|
object.setPosition({
|
|
425
405
|
width: actualWidth
|
|
426
406
|
});
|
|
427
|
-
|
|
428
|
-
if (object.getType() !== exports.ObjectType.VERTICAL_RULE) {
|
|
429
|
-
object.updateDimensions();
|
|
430
|
-
}
|
|
431
|
-
});
|
|
407
|
+
object.updateDimensions();
|
|
432
408
|
});
|
|
433
409
|
}
|
|
434
410
|
adjustCanvasSize(canvas, requiredHeight) {
|
|
@@ -501,7 +477,6 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
501
477
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
502
478
|
this.stackObjects = new StackObjectsLayoutFunction();
|
|
503
479
|
this.updateObjectDimensions = new UpdateObjectDimensionsLayoutFunction();
|
|
504
|
-
this.layoutBatchScheduled = false;
|
|
505
480
|
}
|
|
506
481
|
/**
|
|
507
482
|
* @override
|
|
@@ -543,21 +518,12 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
543
518
|
this.stackAndRedraw();
|
|
544
519
|
}
|
|
545
520
|
stackAndRedraw() {
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
this.
|
|
551
|
-
|
|
552
|
-
Promise.resolve().then(() => {
|
|
553
|
-
this.stackObjects.execute(this.canvas);
|
|
554
|
-
this.repositionCutoffs.execute(this.canvas);
|
|
555
|
-
this.repositionBorders.execute(this.canvas);
|
|
556
|
-
this.repositionBackgrounds.execute(this.canvas);
|
|
557
|
-
this.updateObjectDimensions.execute(this.canvas);
|
|
558
|
-
this.redrawAll.execute(this.canvas);
|
|
559
|
-
this.layoutBatchScheduled = false;
|
|
560
|
-
});
|
|
521
|
+
this.stackObjects.execute(this.canvas);
|
|
522
|
+
this.repositionCutoffs.execute(this.canvas);
|
|
523
|
+
this.repositionBorders.execute(this.canvas);
|
|
524
|
+
this.repositionBackgrounds.execute(this.canvas);
|
|
525
|
+
this.updateObjectDimensions.execute(this.canvas);
|
|
526
|
+
this.redrawAll.execute(this.canvas);
|
|
561
527
|
}
|
|
562
528
|
}
|
|
563
529
|
|
|
@@ -1835,16 +1801,12 @@ exports.ObjectType = void 0;
|
|
|
1835
1801
|
class Text extends AbstractCanvasObject {
|
|
1836
1802
|
constructor(canvas, fabricObject, persistedField) {
|
|
1837
1803
|
super(exports.ObjectType.TEXT, canvas, fabricObject, persistedField);
|
|
1838
|
-
//private notifyCanvasTimeout: NodeJS.Timeout | null = null;
|
|
1839
|
-
this.notifyCanvasTimeout = null;
|
|
1840
|
-
this.NOTIFY_DELAY_MS = 150; // Debounce canvas notifications
|
|
1841
1804
|
this.canvas = canvas;
|
|
1842
1805
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1843
1806
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1844
1807
|
this.text$ = new rxjs.BehaviorSubject(this.fabricObject.text);
|
|
1845
1808
|
this.data.userText = this.fabricObject.text;
|
|
1846
1809
|
this.textSelection$ = new rxjs.BehaviorSubject(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
1847
|
-
console.log(`inside constructor in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
1848
1810
|
this.fabricObject.set({ strokeWidth: 0 });
|
|
1849
1811
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1850
1812
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
@@ -2584,54 +2546,30 @@ class Text extends AbstractCanvasObject {
|
|
|
2584
2546
|
this.redraw();
|
|
2585
2547
|
}
|
|
2586
2548
|
onTextChange() {
|
|
2587
|
-
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2588
2549
|
this.data.userText = this.fabricObject.text;
|
|
2589
2550
|
this.text$.next(this.fabricObject.text);
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
// Skip expensive getBoundingBox if object is clearly within bounds
|
|
2594
|
-
if (currentLeft + (this.fabricObject.width || 0) > canvasWidth * 0.9) {
|
|
2595
|
-
console.log(`inside if onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2596
|
-
if (this.getBoundingBox().width > canvasWidth) {
|
|
2597
|
-
this.fabricObject.set({ left: 0, width: canvasWidth });
|
|
2598
|
-
this.redraw();
|
|
2599
|
-
}
|
|
2551
|
+
if (this.getBoundingBox().width > this.canvas.getDimensions().widthPx) {
|
|
2552
|
+
this.fabricObject.set({ left: 0, width: this.canvas.getDimensions().widthPx });
|
|
2553
|
+
this.redraw();
|
|
2600
2554
|
}
|
|
2601
|
-
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2602
2555
|
}
|
|
2603
2556
|
onDelete() {
|
|
2604
2557
|
this.removeBullets();
|
|
2605
2558
|
}
|
|
2606
2559
|
onSelectionChange() {
|
|
2607
|
-
|
|
2608
|
-
this.updateTextSelection(false);
|
|
2560
|
+
this.updateTextSelection();
|
|
2609
2561
|
}
|
|
2610
2562
|
hasTextSelection() {
|
|
2611
2563
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2612
2564
|
}
|
|
2613
|
-
updateTextSelection(
|
|
2614
|
-
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2565
|
+
updateTextSelection() {
|
|
2615
2566
|
if (this.canvas.headless)
|
|
2616
2567
|
return;
|
|
2617
2568
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2618
|
-
|
|
2619
|
-
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2620
|
-
this.notifyCanvasOfTextChanges();
|
|
2621
|
-
}
|
|
2569
|
+
this.notifyCanvasOfTextChanges();
|
|
2622
2570
|
}
|
|
2623
2571
|
notifyCanvasOfTextChanges() {
|
|
2624
|
-
|
|
2625
|
-
if (this.notifyCanvasTimeout) {
|
|
2626
|
-
console.log(`inside timeout if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2627
|
-
clearTimeout(this.notifyCanvasTimeout);
|
|
2628
|
-
}
|
|
2629
|
-
this.notifyCanvasTimeout = setTimeout(() => {
|
|
2630
|
-
console.log(`start of setTimeout in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2631
|
-
this.canvas.notifyTextChanged();
|
|
2632
|
-
this.notifyCanvasTimeout = null;
|
|
2633
|
-
}, this.NOTIFY_DELAY_MS);
|
|
2634
|
-
console.log(`end of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2572
|
+
this.canvas.notifyTextChanged();
|
|
2635
2573
|
}
|
|
2636
2574
|
}
|
|
2637
2575
|
Text.NEW_LINE = "\n";
|
|
@@ -2639,7 +2577,6 @@ class TextSelection {
|
|
|
2639
2577
|
constructor(fabricObject, fontLibrary) {
|
|
2640
2578
|
this.fabricObject = fabricObject;
|
|
2641
2579
|
this.fontLibrary = fontLibrary;
|
|
2642
|
-
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2643
2580
|
this.start = this.fabricObject.selectionStart;
|
|
2644
2581
|
this.end = this.fabricObject.selectionEnd;
|
|
2645
2582
|
this.length = this.end - this.start;
|
|
@@ -2798,7 +2735,6 @@ class AbstractInteractiveCanvas {
|
|
|
2798
2735
|
this.devicePixelRatio = devicePixelRatio;
|
|
2799
2736
|
this.fontLibrary = new FontLibrary();
|
|
2800
2737
|
this.dimensionChangeRejections$ = new rxjs.Subject();
|
|
2801
|
-
this.redrawScheduled = false;
|
|
2802
2738
|
this.IMAGE_CAPTURE_COEFFICIENT = this.calculateImageCaptureCoefficient();
|
|
2803
2739
|
/**
|
|
2804
2740
|
* Fabric defaults to only 2 decimal places when saving, which causes havoc on the scaling of large images.
|
|
@@ -2821,7 +2757,7 @@ class AbstractInteractiveCanvas {
|
|
|
2821
2757
|
this.fabricCanvas.stateful = true;
|
|
2822
2758
|
this.fabricCanvas.preserveObjectStacking = true;
|
|
2823
2759
|
this.fabricCanvas.perPixelTargetFind = true;
|
|
2824
|
-
this.fabricCanvas.targetFindTolerance =
|
|
2760
|
+
this.fabricCanvas.targetFindTolerance = 4;
|
|
2825
2761
|
this.setBackgroundColor("#FFFFFF");
|
|
2826
2762
|
}
|
|
2827
2763
|
/**
|
|
@@ -3215,7 +3151,11 @@ class AbstractInteractiveCanvas {
|
|
|
3215
3151
|
charSpacing: profile.defaultCharacterSpacing,
|
|
3216
3152
|
perPixelTargetFind: false,
|
|
3217
3153
|
targetFindTolerance: 4,
|
|
3218
|
-
splitByGrapheme: true
|
|
3154
|
+
splitByGrapheme: true,
|
|
3155
|
+
editable: false, // Only enable on double-click
|
|
3156
|
+
padding: 0,
|
|
3157
|
+
cornerSize: 8,
|
|
3158
|
+
touchCornerSize: 12
|
|
3219
3159
|
};
|
|
3220
3160
|
const fabricTextbox = new this.fabric.Textbox("Text goes here", textOptions);
|
|
3221
3161
|
this.fabricCanvas.add(fabricTextbox);
|
|
@@ -3664,16 +3604,7 @@ class AbstractInteractiveCanvas {
|
|
|
3664
3604
|
* Redraw the canvas.
|
|
3665
3605
|
*/
|
|
3666
3606
|
redraw() {
|
|
3667
|
-
|
|
3668
|
-
if (this.redrawScheduled) {
|
|
3669
|
-
return; // Already scheduled, don't schedule again
|
|
3670
|
-
}
|
|
3671
|
-
this.redrawScheduled = true;
|
|
3672
|
-
// Use requestAnimationFrame for smoother rendering and automatic batching
|
|
3673
|
-
requestAnimationFrame(() => {
|
|
3674
|
-
this.fabricCanvas.requestRenderAll();
|
|
3675
|
-
this.redrawScheduled = false;
|
|
3676
|
-
});
|
|
3607
|
+
this.fabricCanvas.requestRenderAll();
|
|
3677
3608
|
}
|
|
3678
3609
|
syncObjectList() {
|
|
3679
3610
|
const newObjectList = _(this.fabricCanvas.getObjects())
|
|
@@ -3799,6 +3730,7 @@ class AbstractInteractiveCanvas {
|
|
|
3799
3730
|
* Update the actual dimensions of the canvas by multiplying the requested dimensions by the current zoom factor.
|
|
3800
3731
|
*/
|
|
3801
3732
|
updateCanvasDimensions(dims, zoom) {
|
|
3733
|
+
const oldWidth = this.fabricCanvas.getWidth();
|
|
3802
3734
|
const width = dims.widthPx * zoom;
|
|
3803
3735
|
const height = dims.heightPx * zoom;
|
|
3804
3736
|
this.fabricCanvas.setZoom(zoom);
|
|
@@ -3806,6 +3738,34 @@ class AbstractInteractiveCanvas {
|
|
|
3806
3738
|
width,
|
|
3807
3739
|
height
|
|
3808
3740
|
});
|
|
3741
|
+
const scaleFactor = width / oldWidth;
|
|
3742
|
+
const objects = this.fabricCanvas.getObjects();
|
|
3743
|
+
objects.forEach((obj) => {
|
|
3744
|
+
obj.set({
|
|
3745
|
+
left: obj.left * scaleFactor,
|
|
3746
|
+
});
|
|
3747
|
+
if (obj.type === "textbox" || obj.type === "text") {
|
|
3748
|
+
obj.set({
|
|
3749
|
+
scaleX: 1,
|
|
3750
|
+
scaleY: 1,
|
|
3751
|
+
width: obj.width * scaleFactor,
|
|
3752
|
+
});
|
|
3753
|
+
}
|
|
3754
|
+
else if (obj.type === "border" || obj.type === "rect") {
|
|
3755
|
+
obj.set({
|
|
3756
|
+
width: obj.width * scaleFactor,
|
|
3757
|
+
scaleX: 1,
|
|
3758
|
+
strokeUniform: true,
|
|
3759
|
+
});
|
|
3760
|
+
}
|
|
3761
|
+
else {
|
|
3762
|
+
obj.set({
|
|
3763
|
+
scaleX: obj.scaleX * scaleFactor,
|
|
3764
|
+
});
|
|
3765
|
+
}
|
|
3766
|
+
obj.setCoords();
|
|
3767
|
+
});
|
|
3768
|
+
this.fabricCanvas.requestRenderAll();
|
|
3809
3769
|
}
|
|
3810
3770
|
onProfileChanged(profile) {
|
|
3811
3771
|
this.setMultiSelect(profile.allowMultiSelect);
|
|
@@ -3960,8 +3920,18 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3960
3920
|
this.fabricCanvas.on("selection:created", (event) => this.onFabricSelectionChanged(event));
|
|
3961
3921
|
this.fabricCanvas.on("selection:cleared", (event) => this.onFabricSelectionChanged(event));
|
|
3962
3922
|
this.fabricCanvas.on("text:editing:entered", () => this.onTextEditing());
|
|
3963
|
-
this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3923
|
+
//this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3924
|
+
this.fabricCanvas.on("text:editing:exited", (event) => {
|
|
3925
|
+
this.onTextEditing();
|
|
3926
|
+
const target = event.target;
|
|
3927
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
3928
|
+
target.set({ editable: false, hoverCursor: 'move' });
|
|
3929
|
+
}
|
|
3930
|
+
});
|
|
3964
3931
|
this.fabricCanvas.on("text:changed", () => this.onTextChange());
|
|
3932
|
+
// Handle double-click on textbox to enter editing mode
|
|
3933
|
+
// @ts-ignore
|
|
3934
|
+
this.fabricCanvas.on("mouse:dblclick", (event) => this.onDoubleClick(event));
|
|
3965
3935
|
}
|
|
3966
3936
|
/**
|
|
3967
3937
|
* @override
|
|
@@ -3989,7 +3959,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3989
3959
|
});
|
|
3990
3960
|
}
|
|
3991
3961
|
onFabricSelectionChanged(event) {
|
|
3992
|
-
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3993
3962
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3994
3963
|
const selection = new SelectionData(selected);
|
|
3995
3964
|
if (event) {
|
|
@@ -4000,7 +3969,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
4000
3969
|
}
|
|
4001
3970
|
enterTextSelectionModeIfRequired() {
|
|
4002
3971
|
var _a, _b;
|
|
4003
|
-
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
4004
3972
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
4005
3973
|
return;
|
|
4006
3974
|
if (((_b = (_a = this.selection$.value) === null || _a === void 0 ? void 0 : _a.objects[0]) === null || _b === void 0 ? void 0 : _b.getType()) !== exports.ObjectType.TEXT)
|
|
@@ -4009,10 +3977,20 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
4009
3977
|
text.enterEditing();
|
|
4010
3978
|
}
|
|
4011
3979
|
onTextEditing() {
|
|
4012
|
-
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
4013
3980
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
4014
3981
|
this.selection$.next(new SelectionData(selected));
|
|
4015
3982
|
}
|
|
3983
|
+
onDoubleClick(event) {
|
|
3984
|
+
const target = event.target;
|
|
3985
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
3986
|
+
if (!target.isEditing) {
|
|
3987
|
+
target.set({ editable: true, hoverCursor: 'text' });
|
|
3988
|
+
// target.enterEditing();
|
|
3989
|
+
// target.hiddenTextarea?.focus();
|
|
3990
|
+
this.enterTextSelectionModeIfRequired();
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
}
|
|
4016
3994
|
}
|
|
4017
3995
|
|
|
4018
3996
|
exports.AbstractCanvasObject = AbstractCanvasObject;
|
|
@@ -9,7 +9,6 @@ export declare class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
9
9
|
private repositionCutoffs;
|
|
10
10
|
private repositionBackgrounds;
|
|
11
11
|
private resizeCanvas;
|
|
12
|
-
private dimensionsLayoutScheduled;
|
|
13
12
|
constructor(canvas: IInteractiveCanvas);
|
|
14
13
|
onCanvasDimensionsChange(): void;
|
|
15
14
|
onTextChange(): void;
|
|
@@ -63,8 +63,6 @@ export declare class Text extends AbstractCanvasObject<ExtendedFabricTextbox> im
|
|
|
63
63
|
private readonly text$;
|
|
64
64
|
private readonly textSelection$;
|
|
65
65
|
static readonly NEW_LINE: string;
|
|
66
|
-
private notifyCanvasTimeout;
|
|
67
|
-
private readonly NOTIFY_DELAY_MS;
|
|
68
66
|
constructor(canvas: IInteractiveCanvas, fabricObject: fabric.Textbox, persistedField?: CanvasObjectData);
|
|
69
67
|
/**
|
|
70
68
|
* @override
|