@leapfrog/interactive-canvas 2.0.25-beta-7 → 2.0.25-beta-9
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.
|
@@ -232,12 +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
235
|
canvas.getObjectsInternal().forEach((object) => {
|
|
238
236
|
var _a;
|
|
239
237
|
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
238
|
if (canvasObj && (((_a = canvasObj.isPinToBottom) === null || _a === void 0 ? void 0 : _a.call(canvasObj)) || object.top > currentDimensions.heightPx * 0.5)) {
|
|
242
239
|
object.setCoords();
|
|
243
240
|
}
|
|
@@ -274,7 +271,6 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
274
271
|
this.dimensionsLayoutScheduled = false;
|
|
275
272
|
}
|
|
276
273
|
onCanvasDimensionsChange() {
|
|
277
|
-
// Batch dimension changes to avoid redundant layout passes
|
|
278
274
|
if (this.dimensionsLayoutScheduled) {
|
|
279
275
|
return;
|
|
280
276
|
}
|
|
@@ -314,9 +310,7 @@ class StackObjectsLayoutFunction {
|
|
|
314
310
|
const footerObjects = objects[0];
|
|
315
311
|
const bodyObjects = objects[1];
|
|
316
312
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
317
|
-
//canvas.redraw();
|
|
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
|
|
313
|
+
// canvas.redraw();
|
|
320
314
|
//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
315
|
this.applyWidths(allObjects, bodyWidth);
|
|
322
316
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -403,6 +397,7 @@ class StackObjectsLayoutFunction {
|
|
|
403
397
|
object.setPosition({
|
|
404
398
|
width: actualWidth
|
|
405
399
|
});
|
|
400
|
+
//object.updateDimensions();
|
|
406
401
|
_(objects).forEach((object) => {
|
|
407
402
|
if (object.getType() !== ObjectType.VERTICAL_RULE) {
|
|
408
403
|
object.updateDimensions();
|
|
@@ -522,12 +517,10 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
522
517
|
this.stackAndRedraw();
|
|
523
518
|
}
|
|
524
519
|
stackAndRedraw() {
|
|
525
|
-
// Batch multiple layout requests into a single pass
|
|
526
520
|
if (this.layoutBatchScheduled) {
|
|
527
521
|
return;
|
|
528
522
|
}
|
|
529
523
|
this.layoutBatchScheduled = true;
|
|
530
|
-
// Use microtask to batch synchronous calls, but still execute before next frame
|
|
531
524
|
Promise.resolve().then(() => {
|
|
532
525
|
this.stackObjects.execute(this.canvas);
|
|
533
526
|
this.repositionCutoffs.execute(this.canvas);
|
|
@@ -1814,19 +1807,43 @@ var ObjectType;
|
|
|
1814
1807
|
class Text extends AbstractCanvasObject {
|
|
1815
1808
|
constructor(canvas, fabricObject, persistedField) {
|
|
1816
1809
|
super(ObjectType.TEXT, canvas, fabricObject, persistedField);
|
|
1817
|
-
//private notifyCanvasTimeout: NodeJS.Timeout | null = null;
|
|
1818
1810
|
this.notifyCanvasTimeout = null;
|
|
1819
|
-
this.NOTIFY_DELAY_MS = 150;
|
|
1811
|
+
this.NOTIFY_DELAY_MS = 150;
|
|
1820
1812
|
this.canvas = canvas;
|
|
1821
1813
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1822
1814
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1823
1815
|
this.text$ = new BehaviorSubject(this.fabricObject.text);
|
|
1824
1816
|
this.data.userText = this.fabricObject.text;
|
|
1825
1817
|
this.textSelection$ = new BehaviorSubject(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
1826
|
-
|
|
1827
|
-
this.fabricObject.set({
|
|
1818
|
+
//this.fabricObject.set({strokeWidth: 0});
|
|
1819
|
+
this.fabricObject.set({
|
|
1820
|
+
strokeWidth: 0,
|
|
1821
|
+
perPixelTargetFind: false // Disable per-pixel detection for this object
|
|
1822
|
+
});
|
|
1828
1823
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1829
1824
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
1825
|
+
this.fabricObject.containsPoint.bind(this.fabricObject);
|
|
1826
|
+
this.fabricObject.containsPoint = function (point) {
|
|
1827
|
+
const coords = this.getCoords();
|
|
1828
|
+
if (coords.length !== 4)
|
|
1829
|
+
return false;
|
|
1830
|
+
let inside = false;
|
|
1831
|
+
for (let i = 0, j = coords.length - 1; i < coords.length; j = i++) {
|
|
1832
|
+
const xi = coords[i].x, yi = coords[i].y;
|
|
1833
|
+
const xj = coords[j].x, yj = coords[j].y;
|
|
1834
|
+
const intersect = ((yi > point.y) !== (yj > point.y))
|
|
1835
|
+
&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
|
|
1836
|
+
if (intersect)
|
|
1837
|
+
inside = !inside;
|
|
1838
|
+
}
|
|
1839
|
+
return inside;
|
|
1840
|
+
};
|
|
1841
|
+
this.fabricObject.on("mousedown", (e) => {
|
|
1842
|
+
var _a;
|
|
1843
|
+
if (!this.fabricObject.isEditing) {
|
|
1844
|
+
(_a = e.e) === null || _a === void 0 ? void 0 : _a.preventDefault();
|
|
1845
|
+
}
|
|
1846
|
+
});
|
|
1830
1847
|
this.applyBulletListMonkeyPatches();
|
|
1831
1848
|
}
|
|
1832
1849
|
/**
|
|
@@ -2546,9 +2563,16 @@ class Text extends AbstractCanvasObject {
|
|
|
2546
2563
|
const profile = this.canvas.getProfile();
|
|
2547
2564
|
const allowManualPositioning = !this.canvas.getLayoutManager().isEnforcedPositioning;
|
|
2548
2565
|
this.fabricObject.set({
|
|
2566
|
+
lockMovementX: false,
|
|
2567
|
+
lockMovementY: false,
|
|
2549
2568
|
lockScalingY: true,
|
|
2550
2569
|
lockScalingX: this.isPinToBottom(),
|
|
2551
|
-
lockScalingFlip: true
|
|
2570
|
+
lockScalingFlip: true,
|
|
2571
|
+
lockRotation: true,
|
|
2572
|
+
selectable: true,
|
|
2573
|
+
editable: false, // Only enable on double-click
|
|
2574
|
+
hoverCursor: "move", // Show move cursor by default
|
|
2575
|
+
moveCursor: "move",
|
|
2552
2576
|
});
|
|
2553
2577
|
this.fabricObject.setControlsVisibility({
|
|
2554
2578
|
tl: false,
|
|
@@ -2558,59 +2582,49 @@ class Text extends AbstractCanvasObject {
|
|
|
2558
2582
|
ml: allowManualPositioning && profile.allowScale && !this.isPinToBottom(),
|
|
2559
2583
|
mt: false,
|
|
2560
2584
|
mr: allowManualPositioning && profile.allowScale && !this.isPinToBottom(),
|
|
2561
|
-
mb: false
|
|
2585
|
+
mb: false,
|
|
2586
|
+
mtr: false
|
|
2562
2587
|
});
|
|
2563
2588
|
this.redraw();
|
|
2564
2589
|
}
|
|
2565
2590
|
onTextChange() {
|
|
2566
|
-
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2567
2591
|
this.data.userText = this.fabricObject.text;
|
|
2568
2592
|
this.text$.next(this.fabricObject.text);
|
|
2569
|
-
// Only check width bounds if text is close to canvas edge (performance optimization)
|
|
2570
2593
|
const currentLeft = this.fabricObject.left || 0;
|
|
2571
2594
|
const canvasWidth = this.canvas.getDimensions().widthPx;
|
|
2572
2595
|
// Skip expensive getBoundingBox if object is clearly within bounds
|
|
2573
2596
|
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
2597
|
if (this.getBoundingBox().width > canvasWidth) {
|
|
2576
2598
|
this.fabricObject.set({ left: 0, width: canvasWidth });
|
|
2577
2599
|
this.redraw();
|
|
2578
2600
|
}
|
|
2579
2601
|
}
|
|
2580
|
-
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2581
2602
|
}
|
|
2582
2603
|
onDelete() {
|
|
2583
2604
|
this.removeBullets();
|
|
2584
2605
|
}
|
|
2585
2606
|
onSelectionChange() {
|
|
2586
|
-
console.log(`start of onSelectionChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2587
2607
|
this.updateTextSelection(false);
|
|
2588
2608
|
}
|
|
2589
2609
|
hasTextSelection() {
|
|
2590
2610
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2591
2611
|
}
|
|
2592
2612
|
updateTextSelection(notifyCanvas = true) {
|
|
2593
|
-
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2594
2613
|
if (this.canvas.headless)
|
|
2595
2614
|
return;
|
|
2596
2615
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2597
2616
|
if (notifyCanvas) {
|
|
2598
|
-
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2599
2617
|
this.notifyCanvasOfTextChanges();
|
|
2600
2618
|
}
|
|
2601
2619
|
}
|
|
2602
2620
|
notifyCanvasOfTextChanges() {
|
|
2603
|
-
console.log(`start of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2604
2621
|
if (this.notifyCanvasTimeout) {
|
|
2605
|
-
console.log(`inside timeout if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2606
2622
|
clearTimeout(this.notifyCanvasTimeout);
|
|
2607
2623
|
}
|
|
2608
2624
|
this.notifyCanvasTimeout = setTimeout(() => {
|
|
2609
|
-
console.log(`start of setTimeout in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2610
2625
|
this.canvas.notifyTextChanged();
|
|
2611
2626
|
this.notifyCanvasTimeout = null;
|
|
2612
2627
|
}, this.NOTIFY_DELAY_MS);
|
|
2613
|
-
console.log(`end of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2614
2628
|
}
|
|
2615
2629
|
}
|
|
2616
2630
|
Text.NEW_LINE = "\n";
|
|
@@ -2618,7 +2632,6 @@ class TextSelection {
|
|
|
2618
2632
|
constructor(fabricObject, fontLibrary) {
|
|
2619
2633
|
this.fabricObject = fabricObject;
|
|
2620
2634
|
this.fontLibrary = fontLibrary;
|
|
2621
|
-
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2622
2635
|
this.start = this.fabricObject.selectionStart;
|
|
2623
2636
|
this.end = this.fabricObject.selectionEnd;
|
|
2624
2637
|
this.length = this.end - this.start;
|
|
@@ -2800,7 +2813,7 @@ class AbstractInteractiveCanvas {
|
|
|
2800
2813
|
this.fabricCanvas.stateful = true;
|
|
2801
2814
|
this.fabricCanvas.preserveObjectStacking = true;
|
|
2802
2815
|
this.fabricCanvas.perPixelTargetFind = true;
|
|
2803
|
-
this.fabricCanvas.targetFindTolerance =
|
|
2816
|
+
this.fabricCanvas.targetFindTolerance = 4;
|
|
2804
2817
|
this.setBackgroundColor("#FFFFFF");
|
|
2805
2818
|
}
|
|
2806
2819
|
/**
|
|
@@ -3194,7 +3207,12 @@ class AbstractInteractiveCanvas {
|
|
|
3194
3207
|
charSpacing: profile.defaultCharacterSpacing,
|
|
3195
3208
|
perPixelTargetFind: false,
|
|
3196
3209
|
targetFindTolerance: 4,
|
|
3197
|
-
splitByGrapheme: true
|
|
3210
|
+
splitByGrapheme: true,
|
|
3211
|
+
editable: false, // Only enable on double-click
|
|
3212
|
+
editingBorderColor: '#2196F3',
|
|
3213
|
+
padding: 0,
|
|
3214
|
+
cornerSize: 8,
|
|
3215
|
+
touchCornerSize: 12
|
|
3198
3216
|
};
|
|
3199
3217
|
const fabricTextbox = new this.fabric.Textbox("Text goes here", textOptions);
|
|
3200
3218
|
this.fabricCanvas.add(fabricTextbox);
|
|
@@ -3643,12 +3661,10 @@ class AbstractInteractiveCanvas {
|
|
|
3643
3661
|
* Redraw the canvas.
|
|
3644
3662
|
*/
|
|
3645
3663
|
redraw() {
|
|
3646
|
-
//this.fabricCanvas.requestRenderAll();
|
|
3647
3664
|
if (this.redrawScheduled) {
|
|
3648
|
-
return;
|
|
3665
|
+
return;
|
|
3649
3666
|
}
|
|
3650
3667
|
this.redrawScheduled = true;
|
|
3651
|
-
// Use requestAnimationFrame for smoother rendering and automatic batching
|
|
3652
3668
|
requestAnimationFrame(() => {
|
|
3653
3669
|
this.fabricCanvas.requestRenderAll();
|
|
3654
3670
|
this.redrawScheduled = false;
|
|
@@ -3778,6 +3794,7 @@ class AbstractInteractiveCanvas {
|
|
|
3778
3794
|
* Update the actual dimensions of the canvas by multiplying the requested dimensions by the current zoom factor.
|
|
3779
3795
|
*/
|
|
3780
3796
|
updateCanvasDimensions(dims, zoom) {
|
|
3797
|
+
const oldWidth = this.fabricCanvas.getWidth();
|
|
3781
3798
|
const width = dims.widthPx * zoom;
|
|
3782
3799
|
const height = dims.heightPx * zoom;
|
|
3783
3800
|
this.fabricCanvas.setZoom(zoom);
|
|
@@ -3785,6 +3802,34 @@ class AbstractInteractiveCanvas {
|
|
|
3785
3802
|
width,
|
|
3786
3803
|
height
|
|
3787
3804
|
});
|
|
3805
|
+
const scaleFactor = width / oldWidth;
|
|
3806
|
+
const objects = this.fabricCanvas.getObjects();
|
|
3807
|
+
objects.forEach((obj) => {
|
|
3808
|
+
obj.set({
|
|
3809
|
+
left: obj.left * scaleFactor,
|
|
3810
|
+
});
|
|
3811
|
+
if (obj.type === "textbox" || obj.type === "text") {
|
|
3812
|
+
obj.set({
|
|
3813
|
+
scaleX: 1,
|
|
3814
|
+
scaleY: 1,
|
|
3815
|
+
width: obj.width * scaleFactor,
|
|
3816
|
+
});
|
|
3817
|
+
}
|
|
3818
|
+
else if (obj.type === "border" || obj.type === "rect") {
|
|
3819
|
+
obj.set({
|
|
3820
|
+
width: obj.width * scaleFactor,
|
|
3821
|
+
scaleX: 1,
|
|
3822
|
+
strokeUniform: true,
|
|
3823
|
+
});
|
|
3824
|
+
}
|
|
3825
|
+
else {
|
|
3826
|
+
obj.set({
|
|
3827
|
+
scaleX: obj.scaleX * scaleFactor,
|
|
3828
|
+
});
|
|
3829
|
+
}
|
|
3830
|
+
obj.setCoords();
|
|
3831
|
+
});
|
|
3832
|
+
this.fabricCanvas.requestRenderAll();
|
|
3788
3833
|
}
|
|
3789
3834
|
onProfileChanged(profile) {
|
|
3790
3835
|
this.setMultiSelect(profile.allowMultiSelect);
|
|
@@ -3939,8 +3984,18 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3939
3984
|
this.fabricCanvas.on("selection:created", (event) => this.onFabricSelectionChanged(event));
|
|
3940
3985
|
this.fabricCanvas.on("selection:cleared", (event) => this.onFabricSelectionChanged(event));
|
|
3941
3986
|
this.fabricCanvas.on("text:editing:entered", () => this.onTextEditing());
|
|
3942
|
-
this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3987
|
+
//this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
3988
|
+
this.fabricCanvas.on("text:editing:exited", (event) => {
|
|
3989
|
+
this.onTextEditing();
|
|
3990
|
+
const target = event.target;
|
|
3991
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
3992
|
+
target.set({ editable: false, hoverCursor: 'move' });
|
|
3993
|
+
}
|
|
3994
|
+
});
|
|
3943
3995
|
this.fabricCanvas.on("text:changed", () => this.onTextChange());
|
|
3996
|
+
// Handle double-click on textbox to enter editing mode
|
|
3997
|
+
// @ts-ignore
|
|
3998
|
+
this.fabricCanvas.on("mouse:dblclick", (event) => this.onDoubleClick(event));
|
|
3944
3999
|
}
|
|
3945
4000
|
/**
|
|
3946
4001
|
* @override
|
|
@@ -3968,7 +4023,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3968
4023
|
});
|
|
3969
4024
|
}
|
|
3970
4025
|
onFabricSelectionChanged(event) {
|
|
3971
|
-
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3972
4026
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3973
4027
|
const selection = new SelectionData(selected);
|
|
3974
4028
|
if (event) {
|
|
@@ -3979,7 +4033,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3979
4033
|
}
|
|
3980
4034
|
enterTextSelectionModeIfRequired() {
|
|
3981
4035
|
var _a, _b;
|
|
3982
|
-
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3983
4036
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
3984
4037
|
return;
|
|
3985
4038
|
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 +4041,20 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3988
4041
|
text.enterEditing();
|
|
3989
4042
|
}
|
|
3990
4043
|
onTextEditing() {
|
|
3991
|
-
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3992
4044
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3993
4045
|
this.selection$.next(new SelectionData(selected));
|
|
3994
4046
|
}
|
|
4047
|
+
onDoubleClick(event) {
|
|
4048
|
+
const target = event.target;
|
|
4049
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
4050
|
+
if (!target.isEditing) {
|
|
4051
|
+
target.set({ editable: true, hoverCursor: 'text' });
|
|
4052
|
+
// target.enterEditing();
|
|
4053
|
+
// target.hiddenTextarea?.focus();
|
|
4054
|
+
this.enterTextSelectionModeIfRequired();
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
3995
4058
|
}
|
|
3996
4059
|
|
|
3997
4060
|
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,12 +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
256
|
canvas.getObjectsInternal().forEach((object) => {
|
|
259
257
|
var _a;
|
|
260
258
|
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
259
|
if (canvasObj && (((_a = canvasObj.isPinToBottom) === null || _a === void 0 ? void 0 : _a.call(canvasObj)) || object.top > currentDimensions.heightPx * 0.5)) {
|
|
263
260
|
object.setCoords();
|
|
264
261
|
}
|
|
@@ -295,7 +292,6 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
295
292
|
this.dimensionsLayoutScheduled = false;
|
|
296
293
|
}
|
|
297
294
|
onCanvasDimensionsChange() {
|
|
298
|
-
// Batch dimension changes to avoid redundant layout passes
|
|
299
295
|
if (this.dimensionsLayoutScheduled) {
|
|
300
296
|
return;
|
|
301
297
|
}
|
|
@@ -335,9 +331,7 @@ class StackObjectsLayoutFunction {
|
|
|
335
331
|
const footerObjects = objects[0];
|
|
336
332
|
const bodyObjects = objects[1];
|
|
337
333
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
338
|
-
//canvas.redraw();
|
|
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
|
|
334
|
+
// canvas.redraw();
|
|
341
335
|
//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
336
|
this.applyWidths(allObjects, bodyWidth);
|
|
343
337
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -424,6 +418,7 @@ class StackObjectsLayoutFunction {
|
|
|
424
418
|
object.setPosition({
|
|
425
419
|
width: actualWidth
|
|
426
420
|
});
|
|
421
|
+
//object.updateDimensions();
|
|
427
422
|
_(objects).forEach((object) => {
|
|
428
423
|
if (object.getType() !== exports.ObjectType.VERTICAL_RULE) {
|
|
429
424
|
object.updateDimensions();
|
|
@@ -543,12 +538,10 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
543
538
|
this.stackAndRedraw();
|
|
544
539
|
}
|
|
545
540
|
stackAndRedraw() {
|
|
546
|
-
// Batch multiple layout requests into a single pass
|
|
547
541
|
if (this.layoutBatchScheduled) {
|
|
548
542
|
return;
|
|
549
543
|
}
|
|
550
544
|
this.layoutBatchScheduled = true;
|
|
551
|
-
// Use microtask to batch synchronous calls, but still execute before next frame
|
|
552
545
|
Promise.resolve().then(() => {
|
|
553
546
|
this.stackObjects.execute(this.canvas);
|
|
554
547
|
this.repositionCutoffs.execute(this.canvas);
|
|
@@ -1835,19 +1828,43 @@ exports.ObjectType = void 0;
|
|
|
1835
1828
|
class Text extends AbstractCanvasObject {
|
|
1836
1829
|
constructor(canvas, fabricObject, persistedField) {
|
|
1837
1830
|
super(exports.ObjectType.TEXT, canvas, fabricObject, persistedField);
|
|
1838
|
-
//private notifyCanvasTimeout: NodeJS.Timeout | null = null;
|
|
1839
1831
|
this.notifyCanvasTimeout = null;
|
|
1840
|
-
this.NOTIFY_DELAY_MS = 150;
|
|
1832
|
+
this.NOTIFY_DELAY_MS = 150;
|
|
1841
1833
|
this.canvas = canvas;
|
|
1842
1834
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1843
1835
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1844
1836
|
this.text$ = new rxjs.BehaviorSubject(this.fabricObject.text);
|
|
1845
1837
|
this.data.userText = this.fabricObject.text;
|
|
1846
1838
|
this.textSelection$ = new rxjs.BehaviorSubject(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
1847
|
-
|
|
1848
|
-
this.fabricObject.set({
|
|
1839
|
+
//this.fabricObject.set({strokeWidth: 0});
|
|
1840
|
+
this.fabricObject.set({
|
|
1841
|
+
strokeWidth: 0,
|
|
1842
|
+
perPixelTargetFind: false // Disable per-pixel detection for this object
|
|
1843
|
+
});
|
|
1849
1844
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1850
1845
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
1846
|
+
this.fabricObject.containsPoint.bind(this.fabricObject);
|
|
1847
|
+
this.fabricObject.containsPoint = function (point) {
|
|
1848
|
+
const coords = this.getCoords();
|
|
1849
|
+
if (coords.length !== 4)
|
|
1850
|
+
return false;
|
|
1851
|
+
let inside = false;
|
|
1852
|
+
for (let i = 0, j = coords.length - 1; i < coords.length; j = i++) {
|
|
1853
|
+
const xi = coords[i].x, yi = coords[i].y;
|
|
1854
|
+
const xj = coords[j].x, yj = coords[j].y;
|
|
1855
|
+
const intersect = ((yi > point.y) !== (yj > point.y))
|
|
1856
|
+
&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
|
|
1857
|
+
if (intersect)
|
|
1858
|
+
inside = !inside;
|
|
1859
|
+
}
|
|
1860
|
+
return inside;
|
|
1861
|
+
};
|
|
1862
|
+
this.fabricObject.on("mousedown", (e) => {
|
|
1863
|
+
var _a;
|
|
1864
|
+
if (!this.fabricObject.isEditing) {
|
|
1865
|
+
(_a = e.e) === null || _a === void 0 ? void 0 : _a.preventDefault();
|
|
1866
|
+
}
|
|
1867
|
+
});
|
|
1851
1868
|
this.applyBulletListMonkeyPatches();
|
|
1852
1869
|
}
|
|
1853
1870
|
/**
|
|
@@ -2567,9 +2584,16 @@ class Text extends AbstractCanvasObject {
|
|
|
2567
2584
|
const profile = this.canvas.getProfile();
|
|
2568
2585
|
const allowManualPositioning = !this.canvas.getLayoutManager().isEnforcedPositioning;
|
|
2569
2586
|
this.fabricObject.set({
|
|
2587
|
+
lockMovementX: false,
|
|
2588
|
+
lockMovementY: false,
|
|
2570
2589
|
lockScalingY: true,
|
|
2571
2590
|
lockScalingX: this.isPinToBottom(),
|
|
2572
|
-
lockScalingFlip: true
|
|
2591
|
+
lockScalingFlip: true,
|
|
2592
|
+
lockRotation: true,
|
|
2593
|
+
selectable: true,
|
|
2594
|
+
editable: false, // Only enable on double-click
|
|
2595
|
+
hoverCursor: "move", // Show move cursor by default
|
|
2596
|
+
moveCursor: "move",
|
|
2573
2597
|
});
|
|
2574
2598
|
this.fabricObject.setControlsVisibility({
|
|
2575
2599
|
tl: false,
|
|
@@ -2579,59 +2603,49 @@ class Text extends AbstractCanvasObject {
|
|
|
2579
2603
|
ml: allowManualPositioning && profile.allowScale && !this.isPinToBottom(),
|
|
2580
2604
|
mt: false,
|
|
2581
2605
|
mr: allowManualPositioning && profile.allowScale && !this.isPinToBottom(),
|
|
2582
|
-
mb: false
|
|
2606
|
+
mb: false,
|
|
2607
|
+
mtr: false
|
|
2583
2608
|
});
|
|
2584
2609
|
this.redraw();
|
|
2585
2610
|
}
|
|
2586
2611
|
onTextChange() {
|
|
2587
|
-
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2588
2612
|
this.data.userText = this.fabricObject.text;
|
|
2589
2613
|
this.text$.next(this.fabricObject.text);
|
|
2590
|
-
// Only check width bounds if text is close to canvas edge (performance optimization)
|
|
2591
2614
|
const currentLeft = this.fabricObject.left || 0;
|
|
2592
2615
|
const canvasWidth = this.canvas.getDimensions().widthPx;
|
|
2593
2616
|
// Skip expensive getBoundingBox if object is clearly within bounds
|
|
2594
2617
|
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
2618
|
if (this.getBoundingBox().width > canvasWidth) {
|
|
2597
2619
|
this.fabricObject.set({ left: 0, width: canvasWidth });
|
|
2598
2620
|
this.redraw();
|
|
2599
2621
|
}
|
|
2600
2622
|
}
|
|
2601
|
-
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2602
2623
|
}
|
|
2603
2624
|
onDelete() {
|
|
2604
2625
|
this.removeBullets();
|
|
2605
2626
|
}
|
|
2606
2627
|
onSelectionChange() {
|
|
2607
|
-
console.log(`start of onSelectionChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2608
2628
|
this.updateTextSelection(false);
|
|
2609
2629
|
}
|
|
2610
2630
|
hasTextSelection() {
|
|
2611
2631
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2612
2632
|
}
|
|
2613
2633
|
updateTextSelection(notifyCanvas = true) {
|
|
2614
|
-
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2615
2634
|
if (this.canvas.headless)
|
|
2616
2635
|
return;
|
|
2617
2636
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2618
2637
|
if (notifyCanvas) {
|
|
2619
|
-
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2620
2638
|
this.notifyCanvasOfTextChanges();
|
|
2621
2639
|
}
|
|
2622
2640
|
}
|
|
2623
2641
|
notifyCanvasOfTextChanges() {
|
|
2624
|
-
console.log(`start of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2625
2642
|
if (this.notifyCanvasTimeout) {
|
|
2626
|
-
console.log(`inside timeout if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2627
2643
|
clearTimeout(this.notifyCanvasTimeout);
|
|
2628
2644
|
}
|
|
2629
2645
|
this.notifyCanvasTimeout = setTimeout(() => {
|
|
2630
|
-
console.log(`start of setTimeout in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2631
2646
|
this.canvas.notifyTextChanged();
|
|
2632
2647
|
this.notifyCanvasTimeout = null;
|
|
2633
2648
|
}, this.NOTIFY_DELAY_MS);
|
|
2634
|
-
console.log(`end of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2635
2649
|
}
|
|
2636
2650
|
}
|
|
2637
2651
|
Text.NEW_LINE = "\n";
|
|
@@ -2639,7 +2653,6 @@ class TextSelection {
|
|
|
2639
2653
|
constructor(fabricObject, fontLibrary) {
|
|
2640
2654
|
this.fabricObject = fabricObject;
|
|
2641
2655
|
this.fontLibrary = fontLibrary;
|
|
2642
|
-
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2643
2656
|
this.start = this.fabricObject.selectionStart;
|
|
2644
2657
|
this.end = this.fabricObject.selectionEnd;
|
|
2645
2658
|
this.length = this.end - this.start;
|
|
@@ -2821,7 +2834,7 @@ class AbstractInteractiveCanvas {
|
|
|
2821
2834
|
this.fabricCanvas.stateful = true;
|
|
2822
2835
|
this.fabricCanvas.preserveObjectStacking = true;
|
|
2823
2836
|
this.fabricCanvas.perPixelTargetFind = true;
|
|
2824
|
-
this.fabricCanvas.targetFindTolerance =
|
|
2837
|
+
this.fabricCanvas.targetFindTolerance = 4;
|
|
2825
2838
|
this.setBackgroundColor("#FFFFFF");
|
|
2826
2839
|
}
|
|
2827
2840
|
/**
|
|
@@ -3215,7 +3228,12 @@ class AbstractInteractiveCanvas {
|
|
|
3215
3228
|
charSpacing: profile.defaultCharacterSpacing,
|
|
3216
3229
|
perPixelTargetFind: false,
|
|
3217
3230
|
targetFindTolerance: 4,
|
|
3218
|
-
splitByGrapheme: true
|
|
3231
|
+
splitByGrapheme: true,
|
|
3232
|
+
editable: false, // Only enable on double-click
|
|
3233
|
+
editingBorderColor: '#2196F3',
|
|
3234
|
+
padding: 0,
|
|
3235
|
+
cornerSize: 8,
|
|
3236
|
+
touchCornerSize: 12
|
|
3219
3237
|
};
|
|
3220
3238
|
const fabricTextbox = new this.fabric.Textbox("Text goes here", textOptions);
|
|
3221
3239
|
this.fabricCanvas.add(fabricTextbox);
|
|
@@ -3664,12 +3682,10 @@ class AbstractInteractiveCanvas {
|
|
|
3664
3682
|
* Redraw the canvas.
|
|
3665
3683
|
*/
|
|
3666
3684
|
redraw() {
|
|
3667
|
-
//this.fabricCanvas.requestRenderAll();
|
|
3668
3685
|
if (this.redrawScheduled) {
|
|
3669
|
-
return;
|
|
3686
|
+
return;
|
|
3670
3687
|
}
|
|
3671
3688
|
this.redrawScheduled = true;
|
|
3672
|
-
// Use requestAnimationFrame for smoother rendering and automatic batching
|
|
3673
3689
|
requestAnimationFrame(() => {
|
|
3674
3690
|
this.fabricCanvas.requestRenderAll();
|
|
3675
3691
|
this.redrawScheduled = false;
|
|
@@ -3799,6 +3815,7 @@ class AbstractInteractiveCanvas {
|
|
|
3799
3815
|
* Update the actual dimensions of the canvas by multiplying the requested dimensions by the current zoom factor.
|
|
3800
3816
|
*/
|
|
3801
3817
|
updateCanvasDimensions(dims, zoom) {
|
|
3818
|
+
const oldWidth = this.fabricCanvas.getWidth();
|
|
3802
3819
|
const width = dims.widthPx * zoom;
|
|
3803
3820
|
const height = dims.heightPx * zoom;
|
|
3804
3821
|
this.fabricCanvas.setZoom(zoom);
|
|
@@ -3806,6 +3823,34 @@ class AbstractInteractiveCanvas {
|
|
|
3806
3823
|
width,
|
|
3807
3824
|
height
|
|
3808
3825
|
});
|
|
3826
|
+
const scaleFactor = width / oldWidth;
|
|
3827
|
+
const objects = this.fabricCanvas.getObjects();
|
|
3828
|
+
objects.forEach((obj) => {
|
|
3829
|
+
obj.set({
|
|
3830
|
+
left: obj.left * scaleFactor,
|
|
3831
|
+
});
|
|
3832
|
+
if (obj.type === "textbox" || obj.type === "text") {
|
|
3833
|
+
obj.set({
|
|
3834
|
+
scaleX: 1,
|
|
3835
|
+
scaleY: 1,
|
|
3836
|
+
width: obj.width * scaleFactor,
|
|
3837
|
+
});
|
|
3838
|
+
}
|
|
3839
|
+
else if (obj.type === "border" || obj.type === "rect") {
|
|
3840
|
+
obj.set({
|
|
3841
|
+
width: obj.width * scaleFactor,
|
|
3842
|
+
scaleX: 1,
|
|
3843
|
+
strokeUniform: true,
|
|
3844
|
+
});
|
|
3845
|
+
}
|
|
3846
|
+
else {
|
|
3847
|
+
obj.set({
|
|
3848
|
+
scaleX: obj.scaleX * scaleFactor,
|
|
3849
|
+
});
|
|
3850
|
+
}
|
|
3851
|
+
obj.setCoords();
|
|
3852
|
+
});
|
|
3853
|
+
this.fabricCanvas.requestRenderAll();
|
|
3809
3854
|
}
|
|
3810
3855
|
onProfileChanged(profile) {
|
|
3811
3856
|
this.setMultiSelect(profile.allowMultiSelect);
|
|
@@ -3960,8 +4005,18 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3960
4005
|
this.fabricCanvas.on("selection:created", (event) => this.onFabricSelectionChanged(event));
|
|
3961
4006
|
this.fabricCanvas.on("selection:cleared", (event) => this.onFabricSelectionChanged(event));
|
|
3962
4007
|
this.fabricCanvas.on("text:editing:entered", () => this.onTextEditing());
|
|
3963
|
-
this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
4008
|
+
//this.fabricCanvas.on("text:editing:exited", () => this.onTextEditing());
|
|
4009
|
+
this.fabricCanvas.on("text:editing:exited", (event) => {
|
|
4010
|
+
this.onTextEditing();
|
|
4011
|
+
const target = event.target;
|
|
4012
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
4013
|
+
target.set({ editable: false, hoverCursor: 'move' });
|
|
4014
|
+
}
|
|
4015
|
+
});
|
|
3964
4016
|
this.fabricCanvas.on("text:changed", () => this.onTextChange());
|
|
4017
|
+
// Handle double-click on textbox to enter editing mode
|
|
4018
|
+
// @ts-ignore
|
|
4019
|
+
this.fabricCanvas.on("mouse:dblclick", (event) => this.onDoubleClick(event));
|
|
3965
4020
|
}
|
|
3966
4021
|
/**
|
|
3967
4022
|
* @override
|
|
@@ -3989,7 +4044,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3989
4044
|
});
|
|
3990
4045
|
}
|
|
3991
4046
|
onFabricSelectionChanged(event) {
|
|
3992
|
-
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3993
4047
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3994
4048
|
const selection = new SelectionData(selected);
|
|
3995
4049
|
if (event) {
|
|
@@ -4000,7 +4054,6 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
4000
4054
|
}
|
|
4001
4055
|
enterTextSelectionModeIfRequired() {
|
|
4002
4056
|
var _a, _b;
|
|
4003
|
-
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
4004
4057
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
4005
4058
|
return;
|
|
4006
4059
|
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 +4062,20 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
4009
4062
|
text.enterEditing();
|
|
4010
4063
|
}
|
|
4011
4064
|
onTextEditing() {
|
|
4012
|
-
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
4013
4065
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
4014
4066
|
this.selection$.next(new SelectionData(selected));
|
|
4015
4067
|
}
|
|
4068
|
+
onDoubleClick(event) {
|
|
4069
|
+
const target = event.target;
|
|
4070
|
+
if (target && (target.type === 'textbox' || target.type === 'i-text')) {
|
|
4071
|
+
if (!target.isEditing) {
|
|
4072
|
+
target.set({ editable: true, hoverCursor: 'text' });
|
|
4073
|
+
// target.enterEditing();
|
|
4074
|
+
// target.hiddenTextarea?.focus();
|
|
4075
|
+
this.enterTextSelectionModeIfRequired();
|
|
4076
|
+
}
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4016
4079
|
}
|
|
4017
4080
|
|
|
4018
4081
|
exports.AbstractCanvasObject = AbstractCanvasObject;
|