@leapfrog/interactive-canvas 2.0.25-beta-5 → 2.0.25-beta-7
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 +1 -0
- package/dist/interactive-canvas.es.js +94 -20
- package/dist/interactive-canvas.js +94 -20
- package/dist/layout/advanced-layout-manager.d.ts +1 -0
- package/dist/layout/standard-layout-manager.d.ts +1 -0
- package/dist/object/impl/text.d.ts +2 -0
- package/package.json +1 -1
|
@@ -340,6 +340,7 @@ export declare abstract class AbstractInteractiveCanvas implements IInteractiveC
|
|
|
340
340
|
* @inheritDoc
|
|
341
341
|
*/
|
|
342
342
|
cloneObject(sourceObject: FabricObject, objectData: CanvasObjectData): Promise<void>;
|
|
343
|
+
private redrawScheduled;
|
|
343
344
|
/**
|
|
344
345
|
* Redraw the canvas.
|
|
345
346
|
*/
|
|
@@ -232,9 +232,18 @@ 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
|
-
|
|
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();
|
|
236
246
|
}
|
|
237
|
-
canvas.redraw();
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
249
|
|
|
@@ -262,13 +271,22 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
262
271
|
this.repositionCutoffs = new RepositionCutoffsLayoutFunction();
|
|
263
272
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
264
273
|
this.resizeCanvas = new ResizeCanvasLayoutFunction();
|
|
274
|
+
this.dimensionsLayoutScheduled = false;
|
|
265
275
|
}
|
|
266
276
|
onCanvasDimensionsChange() {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.
|
|
277
|
+
// Batch dimension changes to avoid redundant layout passes
|
|
278
|
+
if (this.dimensionsLayoutScheduled) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.dimensionsLayoutScheduled = true;
|
|
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
|
+
});
|
|
272
290
|
}
|
|
273
291
|
onTextChange() {
|
|
274
292
|
this.resizeCanvas.execute(this.canvas);
|
|
@@ -296,7 +314,9 @@ class StackObjectsLayoutFunction {
|
|
|
296
314
|
const footerObjects = objects[0];
|
|
297
315
|
const bodyObjects = objects[1];
|
|
298
316
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
299
|
-
canvas.redraw();
|
|
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
|
|
300
320
|
//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.
|
|
301
321
|
this.applyWidths(allObjects, bodyWidth);
|
|
302
322
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -383,7 +403,11 @@ class StackObjectsLayoutFunction {
|
|
|
383
403
|
object.setPosition({
|
|
384
404
|
width: actualWidth
|
|
385
405
|
});
|
|
386
|
-
|
|
406
|
+
_(objects).forEach((object) => {
|
|
407
|
+
if (object.getType() !== ObjectType.VERTICAL_RULE) {
|
|
408
|
+
object.updateDimensions();
|
|
409
|
+
}
|
|
410
|
+
});
|
|
387
411
|
});
|
|
388
412
|
}
|
|
389
413
|
adjustCanvasSize(canvas, requiredHeight) {
|
|
@@ -456,6 +480,7 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
456
480
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
457
481
|
this.stackObjects = new StackObjectsLayoutFunction();
|
|
458
482
|
this.updateObjectDimensions = new UpdateObjectDimensionsLayoutFunction();
|
|
483
|
+
this.layoutBatchScheduled = false;
|
|
459
484
|
}
|
|
460
485
|
/**
|
|
461
486
|
* @override
|
|
@@ -497,12 +522,21 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
497
522
|
this.stackAndRedraw();
|
|
498
523
|
}
|
|
499
524
|
stackAndRedraw() {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
this.
|
|
505
|
-
|
|
525
|
+
// Batch multiple layout requests into a single pass
|
|
526
|
+
if (this.layoutBatchScheduled) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
this.layoutBatchScheduled = true;
|
|
530
|
+
// Use microtask to batch synchronous calls, but still execute before next frame
|
|
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
|
+
});
|
|
506
540
|
}
|
|
507
541
|
}
|
|
508
542
|
|
|
@@ -1780,12 +1814,16 @@ var ObjectType;
|
|
|
1780
1814
|
class Text extends AbstractCanvasObject {
|
|
1781
1815
|
constructor(canvas, fabricObject, persistedField) {
|
|
1782
1816
|
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
|
|
1783
1820
|
this.canvas = canvas;
|
|
1784
1821
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1785
1822
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1786
1823
|
this.text$ = new BehaviorSubject(this.fabricObject.text);
|
|
1787
1824
|
this.data.userText = this.fabricObject.text;
|
|
1788
1825
|
this.textSelection$ = new BehaviorSubject(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
1826
|
+
console.log(`inside constructor in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
1789
1827
|
this.fabricObject.set({ strokeWidth: 0 });
|
|
1790
1828
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1791
1829
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
@@ -2525,32 +2563,54 @@ class Text extends AbstractCanvasObject {
|
|
|
2525
2563
|
this.redraw();
|
|
2526
2564
|
}
|
|
2527
2565
|
onTextChange() {
|
|
2566
|
+
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2528
2567
|
this.data.userText = this.fabricObject.text;
|
|
2529
2568
|
this.text$.next(this.fabricObject.text);
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2569
|
+
// Only check width bounds if text is close to canvas edge (performance optimization)
|
|
2570
|
+
const currentLeft = this.fabricObject.left || 0;
|
|
2571
|
+
const canvasWidth = this.canvas.getDimensions().widthPx;
|
|
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
|
+
}
|
|
2533
2579
|
}
|
|
2580
|
+
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2534
2581
|
}
|
|
2535
2582
|
onDelete() {
|
|
2536
2583
|
this.removeBullets();
|
|
2537
2584
|
}
|
|
2538
2585
|
onSelectionChange() {
|
|
2586
|
+
console.log(`start of onSelectionChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2539
2587
|
this.updateTextSelection(false);
|
|
2540
2588
|
}
|
|
2541
2589
|
hasTextSelection() {
|
|
2542
2590
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2543
2591
|
}
|
|
2544
2592
|
updateTextSelection(notifyCanvas = true) {
|
|
2593
|
+
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2545
2594
|
if (this.canvas.headless)
|
|
2546
2595
|
return;
|
|
2547
2596
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2548
2597
|
if (notifyCanvas) {
|
|
2598
|
+
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2549
2599
|
this.notifyCanvasOfTextChanges();
|
|
2550
2600
|
}
|
|
2551
2601
|
}
|
|
2552
2602
|
notifyCanvasOfTextChanges() {
|
|
2553
|
-
|
|
2603
|
+
console.log(`start of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
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()}`);
|
|
2554
2614
|
}
|
|
2555
2615
|
}
|
|
2556
2616
|
Text.NEW_LINE = "\n";
|
|
@@ -2558,6 +2618,7 @@ class TextSelection {
|
|
|
2558
2618
|
constructor(fabricObject, fontLibrary) {
|
|
2559
2619
|
this.fabricObject = fabricObject;
|
|
2560
2620
|
this.fontLibrary = fontLibrary;
|
|
2621
|
+
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2561
2622
|
this.start = this.fabricObject.selectionStart;
|
|
2562
2623
|
this.end = this.fabricObject.selectionEnd;
|
|
2563
2624
|
this.length = this.end - this.start;
|
|
@@ -2716,6 +2777,7 @@ class AbstractInteractiveCanvas {
|
|
|
2716
2777
|
this.devicePixelRatio = devicePixelRatio;
|
|
2717
2778
|
this.fontLibrary = new FontLibrary();
|
|
2718
2779
|
this.dimensionChangeRejections$ = new Subject();
|
|
2780
|
+
this.redrawScheduled = false;
|
|
2719
2781
|
this.IMAGE_CAPTURE_COEFFICIENT = this.calculateImageCaptureCoefficient();
|
|
2720
2782
|
/**
|
|
2721
2783
|
* Fabric defaults to only 2 decimal places when saving, which causes havoc on the scaling of large images.
|
|
@@ -3581,7 +3643,16 @@ class AbstractInteractiveCanvas {
|
|
|
3581
3643
|
* Redraw the canvas.
|
|
3582
3644
|
*/
|
|
3583
3645
|
redraw() {
|
|
3584
|
-
this.fabricCanvas.requestRenderAll();
|
|
3646
|
+
//this.fabricCanvas.requestRenderAll();
|
|
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
|
+
});
|
|
3585
3656
|
}
|
|
3586
3657
|
syncObjectList() {
|
|
3587
3658
|
const newObjectList = _(this.fabricCanvas.getObjects())
|
|
@@ -3897,6 +3968,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3897
3968
|
});
|
|
3898
3969
|
}
|
|
3899
3970
|
onFabricSelectionChanged(event) {
|
|
3971
|
+
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3900
3972
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3901
3973
|
const selection = new SelectionData(selected);
|
|
3902
3974
|
if (event) {
|
|
@@ -3907,6 +3979,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3907
3979
|
}
|
|
3908
3980
|
enterTextSelectionModeIfRequired() {
|
|
3909
3981
|
var _a, _b;
|
|
3982
|
+
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3910
3983
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
3911
3984
|
return;
|
|
3912
3985
|
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)
|
|
@@ -3915,6 +3988,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3915
3988
|
text.enterEditing();
|
|
3916
3989
|
}
|
|
3917
3990
|
onTextEditing() {
|
|
3991
|
+
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3918
3992
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3919
3993
|
this.selection$.next(new SelectionData(selected));
|
|
3920
3994
|
}
|
|
@@ -253,9 +253,18 @@ 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
|
-
|
|
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();
|
|
257
267
|
}
|
|
258
|
-
canvas.redraw();
|
|
259
268
|
}
|
|
260
269
|
}
|
|
261
270
|
|
|
@@ -283,13 +292,22 @@ class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
283
292
|
this.repositionCutoffs = new RepositionCutoffsLayoutFunction();
|
|
284
293
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
285
294
|
this.resizeCanvas = new ResizeCanvasLayoutFunction();
|
|
295
|
+
this.dimensionsLayoutScheduled = false;
|
|
286
296
|
}
|
|
287
297
|
onCanvasDimensionsChange() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
this.
|
|
298
|
+
// Batch dimension changes to avoid redundant layout passes
|
|
299
|
+
if (this.dimensionsLayoutScheduled) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.dimensionsLayoutScheduled = true;
|
|
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
|
+
});
|
|
293
311
|
}
|
|
294
312
|
onTextChange() {
|
|
295
313
|
this.resizeCanvas.execute(this.canvas);
|
|
@@ -317,7 +335,9 @@ class StackObjectsLayoutFunction {
|
|
|
317
335
|
const footerObjects = objects[0];
|
|
318
336
|
const bodyObjects = objects[1];
|
|
319
337
|
const bodyWidth = canvasDimensions.widthPx - canvasMargin.right - canvasMargin.left;
|
|
320
|
-
canvas.redraw();
|
|
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
|
|
321
341
|
//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.
|
|
322
342
|
this.applyWidths(allObjects, bodyWidth);
|
|
323
343
|
const bodyRows = this.getRows(bodyObjects);
|
|
@@ -404,7 +424,11 @@ class StackObjectsLayoutFunction {
|
|
|
404
424
|
object.setPosition({
|
|
405
425
|
width: actualWidth
|
|
406
426
|
});
|
|
407
|
-
|
|
427
|
+
_(objects).forEach((object) => {
|
|
428
|
+
if (object.getType() !== exports.ObjectType.VERTICAL_RULE) {
|
|
429
|
+
object.updateDimensions();
|
|
430
|
+
}
|
|
431
|
+
});
|
|
408
432
|
});
|
|
409
433
|
}
|
|
410
434
|
adjustCanvasSize(canvas, requiredHeight) {
|
|
@@ -477,6 +501,7 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
477
501
|
this.repositionBackgrounds = new RepositionBackgroundsLayoutFunction();
|
|
478
502
|
this.stackObjects = new StackObjectsLayoutFunction();
|
|
479
503
|
this.updateObjectDimensions = new UpdateObjectDimensionsLayoutFunction();
|
|
504
|
+
this.layoutBatchScheduled = false;
|
|
480
505
|
}
|
|
481
506
|
/**
|
|
482
507
|
* @override
|
|
@@ -518,12 +543,21 @@ class StandardLayoutManager extends AbstractLayoutManager {
|
|
|
518
543
|
this.stackAndRedraw();
|
|
519
544
|
}
|
|
520
545
|
stackAndRedraw() {
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
this.
|
|
526
|
-
|
|
546
|
+
// Batch multiple layout requests into a single pass
|
|
547
|
+
if (this.layoutBatchScheduled) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
this.layoutBatchScheduled = true;
|
|
551
|
+
// Use microtask to batch synchronous calls, but still execute before next frame
|
|
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
|
+
});
|
|
527
561
|
}
|
|
528
562
|
}
|
|
529
563
|
|
|
@@ -1801,12 +1835,16 @@ exports.ObjectType = void 0;
|
|
|
1801
1835
|
class Text extends AbstractCanvasObject {
|
|
1802
1836
|
constructor(canvas, fabricObject, persistedField) {
|
|
1803
1837
|
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
|
|
1804
1841
|
this.canvas = canvas;
|
|
1805
1842
|
this.fontLibrary = canvas.getFontLibrary();
|
|
1806
1843
|
this.baseComponentHeight = this.fabricObject.height;
|
|
1807
1844
|
this.text$ = new rxjs.BehaviorSubject(this.fabricObject.text);
|
|
1808
1845
|
this.data.userText = this.fabricObject.text;
|
|
1809
1846
|
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()}`);
|
|
1810
1848
|
this.fabricObject.set({ strokeWidth: 0 });
|
|
1811
1849
|
this.fabricObject.on("changed", () => this.onTextChange());
|
|
1812
1850
|
this.fabricObject.on("selection:changed", () => this.onSelectionChange());
|
|
@@ -2546,32 +2584,54 @@ class Text extends AbstractCanvasObject {
|
|
|
2546
2584
|
this.redraw();
|
|
2547
2585
|
}
|
|
2548
2586
|
onTextChange() {
|
|
2587
|
+
console.log(`inside onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2549
2588
|
this.data.userText = this.fabricObject.text;
|
|
2550
2589
|
this.text$.next(this.fabricObject.text);
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2590
|
+
// Only check width bounds if text is close to canvas edge (performance optimization)
|
|
2591
|
+
const currentLeft = this.fabricObject.left || 0;
|
|
2592
|
+
const canvasWidth = this.canvas.getDimensions().widthPx;
|
|
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
|
+
}
|
|
2554
2600
|
}
|
|
2601
|
+
console.log(`end of onTextChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2555
2602
|
}
|
|
2556
2603
|
onDelete() {
|
|
2557
2604
|
this.removeBullets();
|
|
2558
2605
|
}
|
|
2559
2606
|
onSelectionChange() {
|
|
2607
|
+
console.log(`start of onSelectionChange in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2560
2608
|
this.updateTextSelection(false);
|
|
2561
2609
|
}
|
|
2562
2610
|
hasTextSelection() {
|
|
2563
2611
|
return this.canvas.getSelection().isText && this.textSelection$.value.length > 0;
|
|
2564
2612
|
}
|
|
2565
2613
|
updateTextSelection(notifyCanvas = true) {
|
|
2614
|
+
console.log(`start of updateTextSelection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2566
2615
|
if (this.canvas.headless)
|
|
2567
2616
|
return;
|
|
2568
2617
|
this.textSelection$.next(new TextSelection(this.fabricObject, this.fontLibrary));
|
|
2569
2618
|
if (notifyCanvas) {
|
|
2619
|
+
console.log(`inside if in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2570
2620
|
this.notifyCanvasOfTextChanges();
|
|
2571
2621
|
}
|
|
2572
2622
|
}
|
|
2573
2623
|
notifyCanvasOfTextChanges() {
|
|
2574
|
-
|
|
2624
|
+
console.log(`start of notifyCanvasOfTextChanges in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
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()}`);
|
|
2575
2635
|
}
|
|
2576
2636
|
}
|
|
2577
2637
|
Text.NEW_LINE = "\n";
|
|
@@ -2579,6 +2639,7 @@ class TextSelection {
|
|
|
2579
2639
|
constructor(fabricObject, fontLibrary) {
|
|
2580
2640
|
this.fabricObject = fabricObject;
|
|
2581
2641
|
this.fontLibrary = fontLibrary;
|
|
2642
|
+
console.log(`constructor of textselection in text.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
2582
2643
|
this.start = this.fabricObject.selectionStart;
|
|
2583
2644
|
this.end = this.fabricObject.selectionEnd;
|
|
2584
2645
|
this.length = this.end - this.start;
|
|
@@ -2737,6 +2798,7 @@ class AbstractInteractiveCanvas {
|
|
|
2737
2798
|
this.devicePixelRatio = devicePixelRatio;
|
|
2738
2799
|
this.fontLibrary = new FontLibrary();
|
|
2739
2800
|
this.dimensionChangeRejections$ = new rxjs.Subject();
|
|
2801
|
+
this.redrawScheduled = false;
|
|
2740
2802
|
this.IMAGE_CAPTURE_COEFFICIENT = this.calculateImageCaptureCoefficient();
|
|
2741
2803
|
/**
|
|
2742
2804
|
* Fabric defaults to only 2 decimal places when saving, which causes havoc on the scaling of large images.
|
|
@@ -3602,7 +3664,16 @@ class AbstractInteractiveCanvas {
|
|
|
3602
3664
|
* Redraw the canvas.
|
|
3603
3665
|
*/
|
|
3604
3666
|
redraw() {
|
|
3605
|
-
this.fabricCanvas.requestRenderAll();
|
|
3667
|
+
//this.fabricCanvas.requestRenderAll();
|
|
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
|
+
});
|
|
3606
3677
|
}
|
|
3607
3678
|
syncObjectList() {
|
|
3608
3679
|
const newObjectList = _(this.fabricCanvas.getObjects())
|
|
@@ -3918,6 +3989,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3918
3989
|
});
|
|
3919
3990
|
}
|
|
3920
3991
|
onFabricSelectionChanged(event) {
|
|
3992
|
+
console.log(`start of onfabricselectionchange in ic.ts - ${MouseEvent}- ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3921
3993
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3922
3994
|
const selection = new SelectionData(selected);
|
|
3923
3995
|
if (event) {
|
|
@@ -3928,6 +4000,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3928
4000
|
}
|
|
3929
4001
|
enterTextSelectionModeIfRequired() {
|
|
3930
4002
|
var _a, _b;
|
|
4003
|
+
console.log(`start of enterTextSelectionModeIfRequired in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3931
4004
|
if (!this.profile$.value.enterTextEditImmediatelyOnSelect && !this.layoutManager$.value.enterTextEditImmediatelyOnSelect)
|
|
3932
4005
|
return;
|
|
3933
4006
|
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)
|
|
@@ -3936,6 +4009,7 @@ class InteractiveCanvas extends AbstractInteractiveCanvas {
|
|
|
3936
4009
|
text.enterEditing();
|
|
3937
4010
|
}
|
|
3938
4011
|
onTextEditing() {
|
|
4012
|
+
console.log(`start of onTextEditing in IC.ts - ${new Date().toLocaleString()}-${new Date().getMilliseconds()}`);
|
|
3939
4013
|
const selected = this.getFieldsByCanvasObject(this.fabricCanvas.getActiveObjects());
|
|
3940
4014
|
this.selection$.next(new SelectionData(selected));
|
|
3941
4015
|
}
|
|
@@ -9,6 +9,7 @@ export declare class AdvancedLayoutManager extends AbstractLayoutManager {
|
|
|
9
9
|
private repositionCutoffs;
|
|
10
10
|
private repositionBackgrounds;
|
|
11
11
|
private resizeCanvas;
|
|
12
|
+
private dimensionsLayoutScheduled;
|
|
12
13
|
constructor(canvas: IInteractiveCanvas);
|
|
13
14
|
onCanvasDimensionsChange(): void;
|
|
14
15
|
onTextChange(): void;
|
|
@@ -63,6 +63,8 @@ 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;
|
|
66
68
|
constructor(canvas: IInteractiveCanvas, fabricObject: fabric.Textbox, persistedField?: CanvasObjectData);
|
|
67
69
|
/**
|
|
68
70
|
* @override
|