@overtone-art/canvas-editor-core 0.2.3 → 0.2.5
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/index.d.mts +43 -18
- package/dist/index.d.ts +43 -18
- package/dist/index.js +82 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -576,6 +576,7 @@ var PatternManager = class {
|
|
|
576
576
|
config,
|
|
577
577
|
originalSrc: elementToDataURL(image) ?? image.getSrc(),
|
|
578
578
|
originalClip: clip ? clip.toObject() : null,
|
|
579
|
+
originalLocks: captureLocks(image),
|
|
579
580
|
original: {
|
|
580
581
|
left: image.left ?? 0,
|
|
581
582
|
top: image.top ?? 0,
|
|
@@ -592,7 +593,7 @@ var PatternManager = class {
|
|
|
592
593
|
layer.meta.pattern.config = config;
|
|
593
594
|
}
|
|
594
595
|
try {
|
|
595
|
-
await this.renderLayer(layer
|
|
596
|
+
await this.renderLayer(layer);
|
|
596
597
|
} catch (err) {
|
|
597
598
|
if (firstEnable) delete layer.meta.pattern;
|
|
598
599
|
throw err;
|
|
@@ -600,6 +601,34 @@ var PatternManager = class {
|
|
|
600
601
|
this.history.save();
|
|
601
602
|
});
|
|
602
603
|
}
|
|
604
|
+
/**
|
|
605
|
+
* Stretch every restored pattern layer back over the full print area and
|
|
606
|
+
* re-freeze it, without re-rasterising: the baked bitmap keeps whatever size
|
|
607
|
+
* it was saved at, so it is scaled (not re-tiled) to the current canvas. Used
|
|
608
|
+
* after a state restore, where the canvas may be a different display size
|
|
609
|
+
* than when the pattern was baked — and to repair states saved while a
|
|
610
|
+
* pattern could still be dragged out of the print area.
|
|
611
|
+
*/
|
|
612
|
+
repinAll() {
|
|
613
|
+
const cw = this.canvas.getWidth();
|
|
614
|
+
const ch = this.canvas.getHeight();
|
|
615
|
+
let changed = false;
|
|
616
|
+
for (const layer of this.layers.getAll()) {
|
|
617
|
+
if (!layer.meta.pattern || layer.type !== "image") continue;
|
|
618
|
+
const image = layer.fabricObject;
|
|
619
|
+
image.set({
|
|
620
|
+
left: 0,
|
|
621
|
+
top: 0,
|
|
622
|
+
angle: 0,
|
|
623
|
+
scaleX: cw / (image.width || cw),
|
|
624
|
+
scaleY: ch / (image.height || ch)
|
|
625
|
+
});
|
|
626
|
+
applyPatternLocks(image);
|
|
627
|
+
image.setCoords();
|
|
628
|
+
changed = true;
|
|
629
|
+
}
|
|
630
|
+
if (changed) this.canvas.requestRenderAll();
|
|
631
|
+
}
|
|
603
632
|
/** Restore the original image and drop the pattern. */
|
|
604
633
|
disable(layerId) {
|
|
605
634
|
return this.enqueue(layerId, async () => {
|
|
@@ -620,6 +649,7 @@ var PatternManager = class {
|
|
|
620
649
|
angle: state.original.angle
|
|
621
650
|
});
|
|
622
651
|
image.clipPath = state.originalClip ? (await util.enlivenObjects([state.originalClip]))[0] : void 0;
|
|
652
|
+
restoreLocks(image, state.originalLocks);
|
|
623
653
|
image.setCoords();
|
|
624
654
|
delete layer.meta.pattern;
|
|
625
655
|
this.canvas.requestRenderAll();
|
|
@@ -636,13 +666,12 @@ var PatternManager = class {
|
|
|
636
666
|
);
|
|
637
667
|
return next;
|
|
638
668
|
}
|
|
639
|
-
async renderLayer(layer
|
|
669
|
+
async renderLayer(layer) {
|
|
640
670
|
const state = layer.meta.pattern;
|
|
641
671
|
if (!state) return;
|
|
642
672
|
const image = layer.fabricObject;
|
|
643
673
|
const cw = this.canvas.getWidth();
|
|
644
674
|
const ch = this.canvas.getHeight();
|
|
645
|
-
const { left, top, angle } = resolvePatternPlacement(pin, image);
|
|
646
675
|
const scale = Math.max(1, state.config.scale ?? 100) / 100;
|
|
647
676
|
const diag = Math.sqrt(cw * cw + ch * ch);
|
|
648
677
|
const minTile = Math.max(2, diag / MAX_TILES_PER_AXIS);
|
|
@@ -658,29 +687,54 @@ var PatternManager = class {
|
|
|
658
687
|
);
|
|
659
688
|
await image.setSrc(dataUrl);
|
|
660
689
|
image.set({
|
|
661
|
-
left,
|
|
662
|
-
top,
|
|
690
|
+
left: 0,
|
|
691
|
+
top: 0,
|
|
663
692
|
scaleX: 1,
|
|
664
693
|
scaleY: 1,
|
|
665
694
|
width: cw,
|
|
666
695
|
height: ch,
|
|
667
696
|
cropX: 0,
|
|
668
697
|
cropY: 0,
|
|
669
|
-
angle
|
|
698
|
+
angle: 0
|
|
670
699
|
});
|
|
671
700
|
image.clipPath = void 0;
|
|
701
|
+
applyPatternLocks(image);
|
|
672
702
|
image.setCoords();
|
|
673
703
|
this.canvas.requestRenderAll();
|
|
674
704
|
}
|
|
675
705
|
};
|
|
676
|
-
function
|
|
677
|
-
if (pin) return { left: 0, top: 0, angle: 0 };
|
|
706
|
+
function captureLocks(obj) {
|
|
678
707
|
return {
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
708
|
+
lockMovementX: obj.lockMovementX ?? false,
|
|
709
|
+
lockMovementY: obj.lockMovementY ?? false,
|
|
710
|
+
lockScalingX: obj.lockScalingX ?? false,
|
|
711
|
+
lockScalingY: obj.lockScalingY ?? false,
|
|
712
|
+
lockRotation: obj.lockRotation ?? false,
|
|
713
|
+
hasControls: obj.hasControls ?? true
|
|
682
714
|
};
|
|
683
715
|
}
|
|
716
|
+
function applyPatternLocks(obj) {
|
|
717
|
+
obj.set({
|
|
718
|
+
lockMovementX: true,
|
|
719
|
+
lockMovementY: true,
|
|
720
|
+
lockScalingX: true,
|
|
721
|
+
lockScalingY: true,
|
|
722
|
+
lockRotation: true,
|
|
723
|
+
hasControls: false
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
function restoreLocks(obj, locks) {
|
|
727
|
+
obj.set(
|
|
728
|
+
locks ?? {
|
|
729
|
+
lockMovementX: false,
|
|
730
|
+
lockMovementY: false,
|
|
731
|
+
lockScalingX: false,
|
|
732
|
+
lockScalingY: false,
|
|
733
|
+
lockRotation: false,
|
|
734
|
+
hasControls: true
|
|
735
|
+
}
|
|
736
|
+
);
|
|
737
|
+
}
|
|
684
738
|
function elementToDataURL(image) {
|
|
685
739
|
try {
|
|
686
740
|
const el = image.getElement();
|
|
@@ -749,11 +803,13 @@ function computeTilePositions(config, targetW, targetH, baseW, baseH) {
|
|
|
749
803
|
const rows = Math.ceil(diag / tileH) + 2;
|
|
750
804
|
const halfCols = Math.ceil(cols / 2);
|
|
751
805
|
const halfRows = Math.ceil(rows / 2);
|
|
806
|
+
const shiftX = tileW * (clampOffset(config.offsetX) / 100);
|
|
807
|
+
const shiftY = tileH * (clampOffset(config.offsetY) / 100);
|
|
752
808
|
const placements = [];
|
|
753
809
|
for (let j = -halfRows; j <= halfRows; j++) {
|
|
754
810
|
for (let i = -halfCols; i <= halfCols; i++) {
|
|
755
|
-
let x = i * tileW;
|
|
756
|
-
let y = j * tileH;
|
|
811
|
+
let x = i * tileW + shiftX;
|
|
812
|
+
let y = j * tileH + shiftY;
|
|
757
813
|
if (config.mode === "brick-horizontal" && mod2(j) === 1) {
|
|
758
814
|
x += tileW * (config.horizontalOffset / 100);
|
|
759
815
|
} else if (config.mode === "brick-vertical" && mod2(i) === 1) {
|
|
@@ -778,6 +834,10 @@ function drawTiles(ctx, img, config, targetW, targetH, baseW, baseH) {
|
|
|
778
834
|
}
|
|
779
835
|
ctx.restore();
|
|
780
836
|
}
|
|
837
|
+
function clampOffset(value) {
|
|
838
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 0;
|
|
839
|
+
return Math.max(-100, Math.min(100, value));
|
|
840
|
+
}
|
|
781
841
|
function mod2(n) {
|
|
782
842
|
return (n % 2 + 2) % 2;
|
|
783
843
|
}
|
|
@@ -1039,6 +1099,7 @@ var CanvasEditor = class {
|
|
|
1039
1099
|
}
|
|
1040
1100
|
async fromJSON(state) {
|
|
1041
1101
|
await deserializeEditor(this, state);
|
|
1102
|
+
this.patterns.repinAll();
|
|
1042
1103
|
}
|
|
1043
1104
|
// ─── Export ──────────────────────────────────────────
|
|
1044
1105
|
async toPNG(options) {
|
|
@@ -1233,6 +1294,8 @@ var DEFAULT_PATTERN_CONFIG = {
|
|
|
1233
1294
|
verticalSpacing: 0,
|
|
1234
1295
|
angle: 0,
|
|
1235
1296
|
horizontalOffset: 0,
|
|
1297
|
+
offsetX: 0,
|
|
1298
|
+
offsetY: 0,
|
|
1236
1299
|
rotationStepH: 0,
|
|
1237
1300
|
rotationStepV: 0
|
|
1238
1301
|
};
|
|
@@ -1247,7 +1310,9 @@ export {
|
|
|
1247
1310
|
PatternManager,
|
|
1248
1311
|
SnapManager,
|
|
1249
1312
|
UnitConverter,
|
|
1313
|
+
applyPatternLocks,
|
|
1250
1314
|
buildPatternDataURL,
|
|
1315
|
+
captureLocks,
|
|
1251
1316
|
clamp,
|
|
1252
1317
|
clearPatternImageCache,
|
|
1253
1318
|
computeTilePositions,
|
|
@@ -1257,7 +1322,7 @@ export {
|
|
|
1257
1322
|
exportPNG,
|
|
1258
1323
|
exportSVG,
|
|
1259
1324
|
generateId,
|
|
1260
|
-
|
|
1325
|
+
restoreLocks,
|
|
1261
1326
|
round2,
|
|
1262
1327
|
serializeEditor
|
|
1263
1328
|
};
|