@pixldocs/canvas-renderer 0.5.101 → 0.5.102
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.cjs +390 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +390 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3682,28 +3682,33 @@ function updateCoverLayout(g) {
|
|
|
3682
3682
|
const hasCustomSvgMask = Boolean(
|
|
3683
3683
|
currentClipPath && (isSvgMaskClipPath(currentClipPath) || isLuminanceMaskClipPath(currentClipPath) || currentClipPath.__svgMask)
|
|
3684
3684
|
);
|
|
3685
|
-
|
|
3685
|
+
const hasEdgeFadeMask = Boolean(currentClipPath && currentClipPath.__edgeFadeMask);
|
|
3686
|
+
if (hasCustomSvgMask || hasEdgeFadeMask) {
|
|
3686
3687
|
if (isSvgMaskClipPath(currentClipPath)) {
|
|
3687
3688
|
syncSvgMaskClipPath(g);
|
|
3688
3689
|
} else if (currentClipPath && typeof currentClipPath.set === "function") {
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3690
|
+
if (hasEdgeFadeMask) {
|
|
3691
|
+
currentClipPath.dirty = true;
|
|
3692
|
+
} else {
|
|
3693
|
+
const baseW = Math.max(1, Number(currentClipPath.width) || frameW);
|
|
3694
|
+
const baseH = Math.max(1, Number(currentClipPath.height) || frameH);
|
|
3695
|
+
currentClipPath.set({
|
|
3696
|
+
left: 0,
|
|
3697
|
+
top: 0,
|
|
3698
|
+
originX: "center",
|
|
3699
|
+
originY: "center",
|
|
3700
|
+
scaleX: frameW / baseW,
|
|
3701
|
+
scaleY: frameH / baseH,
|
|
3702
|
+
selectable: false,
|
|
3703
|
+
evented: false,
|
|
3704
|
+
hasControls: false,
|
|
3705
|
+
hasBorders: false
|
|
3706
|
+
});
|
|
3707
|
+
currentClipPath.absolutePositioned = false;
|
|
3708
|
+
currentClipPath.excludeFromExport = true;
|
|
3709
|
+
currentClipPath.dirty = true;
|
|
3710
|
+
currentClipPath.setCoords();
|
|
3711
|
+
}
|
|
3707
3712
|
}
|
|
3708
3713
|
} else {
|
|
3709
3714
|
const needsNewClipPath = !g.clipPath || shape === "circle" && !(g.clipPath instanceof fabric__namespace.Ellipse) || shape !== "circle" && !(g.clipPath instanceof fabric__namespace.Rect);
|
|
@@ -4660,10 +4665,12 @@ function exitCropMode(g, commit = true) {
|
|
|
4660
4665
|
g.hasControls = true;
|
|
4661
4666
|
g.borderDashArray = void 0;
|
|
4662
4667
|
installCanvaMaskControls(g);
|
|
4663
|
-
g.borderColor =
|
|
4664
|
-
g.
|
|
4665
|
-
g.
|
|
4668
|
+
g.borderColor = "#4f46e5";
|
|
4669
|
+
g.borderDashArray = void 0;
|
|
4670
|
+
g.cornerColor = "#ffffff";
|
|
4671
|
+
g.cornerStrokeColor = "#4f46e5";
|
|
4666
4672
|
g.cornerStyle = "rect";
|
|
4673
|
+
g.transparentCorners = false;
|
|
4667
4674
|
g[CROP_MODE_FLAG] = false;
|
|
4668
4675
|
g.__cropZoomLastPointer = void 0;
|
|
4669
4676
|
g.__lastPointerForCrop = void 0;
|
|
@@ -6193,6 +6200,127 @@ function renderSmartElementToDataUri(type, props, width, height) {
|
|
|
6193
6200
|
if (!svg) return null;
|
|
6194
6201
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
6195
6202
|
}
|
|
6203
|
+
function hasEdgeFade(p) {
|
|
6204
|
+
if (!p) return false;
|
|
6205
|
+
const sides = [
|
|
6206
|
+
[p.fadeTopSize, p.fadeTopAmount],
|
|
6207
|
+
[p.fadeRightSize, p.fadeRightAmount],
|
|
6208
|
+
[p.fadeBottomSize, p.fadeBottomAmount],
|
|
6209
|
+
[p.fadeLeftSize, p.fadeLeftAmount]
|
|
6210
|
+
];
|
|
6211
|
+
for (const [size, amount] of sides) {
|
|
6212
|
+
const s = Number(size) || 0;
|
|
6213
|
+
const a = amount == null ? 1 : Number(amount);
|
|
6214
|
+
if (s > 0 && a < 1) return true;
|
|
6215
|
+
}
|
|
6216
|
+
return false;
|
|
6217
|
+
}
|
|
6218
|
+
function edgeFadeKey(p) {
|
|
6219
|
+
if (!hasEdgeFade(p)) return "";
|
|
6220
|
+
return [
|
|
6221
|
+
(p == null ? void 0 : p.fadeTopSize) ?? 0,
|
|
6222
|
+
(p == null ? void 0 : p.fadeTopAmount) ?? 1,
|
|
6223
|
+
(p == null ? void 0 : p.fadeRightSize) ?? 0,
|
|
6224
|
+
(p == null ? void 0 : p.fadeRightAmount) ?? 1,
|
|
6225
|
+
(p == null ? void 0 : p.fadeBottomSize) ?? 0,
|
|
6226
|
+
(p == null ? void 0 : p.fadeBottomAmount) ?? 1,
|
|
6227
|
+
(p == null ? void 0 : p.fadeLeftSize) ?? 0,
|
|
6228
|
+
(p == null ? void 0 : p.fadeLeftAmount) ?? 1,
|
|
6229
|
+
(p == null ? void 0 : p.fadeTopHardness) ?? 1,
|
|
6230
|
+
(p == null ? void 0 : p.fadeRightHardness) ?? 1,
|
|
6231
|
+
(p == null ? void 0 : p.fadeBottomHardness) ?? 1,
|
|
6232
|
+
(p == null ? void 0 : p.fadeLeftHardness) ?? 1
|
|
6233
|
+
].join("|");
|
|
6234
|
+
}
|
|
6235
|
+
function clamp01(n) {
|
|
6236
|
+
if (!Number.isFinite(n)) return 0;
|
|
6237
|
+
return Math.max(0, Math.min(1, n));
|
|
6238
|
+
}
|
|
6239
|
+
function bakeEdgeFade(source, fade) {
|
|
6240
|
+
const w = source.naturalWidth || source.width || 0;
|
|
6241
|
+
const h = source.naturalHeight || source.height || 0;
|
|
6242
|
+
const canvas = document.createElement("canvas");
|
|
6243
|
+
canvas.width = Math.max(1, w);
|
|
6244
|
+
canvas.height = Math.max(1, h);
|
|
6245
|
+
const ctx = canvas.getContext("2d");
|
|
6246
|
+
if (!ctx) return canvas;
|
|
6247
|
+
ctx.drawImage(source, 0, 0, canvas.width, canvas.height);
|
|
6248
|
+
const clampHardness = (n) => {
|
|
6249
|
+
const v = Number(n);
|
|
6250
|
+
if (!Number.isFinite(v) || v <= 0) return 1;
|
|
6251
|
+
return Math.max(0.1, Math.min(5, v));
|
|
6252
|
+
};
|
|
6253
|
+
const sides = [
|
|
6254
|
+
{ side: "top", size: clamp01(fade.fadeTopSize ?? 0), amount: clamp01(fade.fadeTopAmount ?? 1), hardness: clampHardness(fade.fadeTopHardness) },
|
|
6255
|
+
{ side: "right", size: clamp01(fade.fadeRightSize ?? 0), amount: clamp01(fade.fadeRightAmount ?? 1), hardness: clampHardness(fade.fadeRightHardness) },
|
|
6256
|
+
{ side: "bottom", size: clamp01(fade.fadeBottomSize ?? 0), amount: clamp01(fade.fadeBottomAmount ?? 1), hardness: clampHardness(fade.fadeBottomHardness) },
|
|
6257
|
+
{ side: "left", size: clamp01(fade.fadeLeftSize ?? 0), amount: clamp01(fade.fadeLeftAmount ?? 1), hardness: clampHardness(fade.fadeLeftHardness) }
|
|
6258
|
+
];
|
|
6259
|
+
for (const { side, size, amount, hardness } of sides) {
|
|
6260
|
+
if (size <= 0 || amount >= 1) continue;
|
|
6261
|
+
const mask = document.createElement("canvas");
|
|
6262
|
+
mask.width = canvas.width;
|
|
6263
|
+
mask.height = canvas.height;
|
|
6264
|
+
const mctx = mask.getContext("2d");
|
|
6265
|
+
if (!mctx) continue;
|
|
6266
|
+
mctx.fillStyle = "#000";
|
|
6267
|
+
mctx.fillRect(0, 0, mask.width, mask.height);
|
|
6268
|
+
let g;
|
|
6269
|
+
let x = 0, y = 0, rectW = mask.width, rectH = mask.height;
|
|
6270
|
+
const STOPS = 24;
|
|
6271
|
+
const innerAlpha = (t) => {
|
|
6272
|
+
const keepProgress = Math.pow(t, hardness);
|
|
6273
|
+
const erase = (1 - amount) * (1 - keepProgress);
|
|
6274
|
+
return 1 - erase;
|
|
6275
|
+
};
|
|
6276
|
+
const fillStops = (grad, reverse) => {
|
|
6277
|
+
for (let i = 0; i <= STOPS; i++) {
|
|
6278
|
+
const t = i / STOPS;
|
|
6279
|
+
const a = innerAlpha(t);
|
|
6280
|
+
grad.addColorStop(t, `rgba(0,0,0,${a})`);
|
|
6281
|
+
}
|
|
6282
|
+
};
|
|
6283
|
+
if (side === "top") {
|
|
6284
|
+
const band = Math.max(1, Math.round(mask.height * size));
|
|
6285
|
+
g = mctx.createLinearGradient(0, 0, 0, band);
|
|
6286
|
+
fillStops(g);
|
|
6287
|
+
rectH = band;
|
|
6288
|
+
} else if (side === "bottom") {
|
|
6289
|
+
const band = Math.max(1, Math.round(mask.height * size));
|
|
6290
|
+
y = mask.height - band;
|
|
6291
|
+
g = mctx.createLinearGradient(0, mask.height, 0, y);
|
|
6292
|
+
fillStops(g);
|
|
6293
|
+
rectH = band;
|
|
6294
|
+
} else if (side === "left") {
|
|
6295
|
+
const band = Math.max(1, Math.round(mask.width * size));
|
|
6296
|
+
g = mctx.createLinearGradient(0, 0, band, 0);
|
|
6297
|
+
fillStops(g);
|
|
6298
|
+
rectW = band;
|
|
6299
|
+
} else {
|
|
6300
|
+
const band = Math.max(1, Math.round(mask.width * size));
|
|
6301
|
+
x = mask.width - band;
|
|
6302
|
+
g = mctx.createLinearGradient(mask.width, 0, x, 0);
|
|
6303
|
+
fillStops(g);
|
|
6304
|
+
rectW = band;
|
|
6305
|
+
}
|
|
6306
|
+
mctx.fillStyle = g;
|
|
6307
|
+
mctx.fillRect(x, y, rectW, rectH);
|
|
6308
|
+
if (amount <= 1e-3) {
|
|
6309
|
+
const edgePx = Math.min(2, side === "top" || side === "bottom" ? rectH : rectW);
|
|
6310
|
+
mctx.fillStyle = "rgba(0,0,0,0)";
|
|
6311
|
+
mctx.globalCompositeOperation = "copy";
|
|
6312
|
+
if (side === "top") mctx.fillRect(0, 0, mask.width, edgePx);
|
|
6313
|
+
if (side === "bottom") mctx.fillRect(0, mask.height - edgePx, mask.width, edgePx);
|
|
6314
|
+
if (side === "left") mctx.fillRect(0, 0, edgePx, mask.height);
|
|
6315
|
+
if (side === "right") mctx.fillRect(mask.width - edgePx, 0, edgePx, mask.height);
|
|
6316
|
+
mctx.globalCompositeOperation = "source-over";
|
|
6317
|
+
}
|
|
6318
|
+
ctx.globalCompositeOperation = "destination-in";
|
|
6319
|
+
ctx.drawImage(mask, 0, 0);
|
|
6320
|
+
ctx.globalCompositeOperation = "source-over";
|
|
6321
|
+
}
|
|
6322
|
+
return canvas;
|
|
6323
|
+
}
|
|
6196
6324
|
function angleToCoords(angleDeg) {
|
|
6197
6325
|
const rad = angleDeg * Math.PI / 180;
|
|
6198
6326
|
const x1 = 0.5 - Math.sin(rad) * 0.5;
|
|
@@ -7702,6 +7830,10 @@ const PageCanvas = react.forwardRef(
|
|
|
7702
7830
|
fabricCanvas.on("mouse:dblclick", (e) => {
|
|
7703
7831
|
if (!isActiveRef.current || !allowEditing) return;
|
|
7704
7832
|
let target = e.target;
|
|
7833
|
+
if (!target) {
|
|
7834
|
+
const active = fabricCanvas.getActiveObject();
|
|
7835
|
+
if (active) target = active;
|
|
7836
|
+
}
|
|
7705
7837
|
if (target && target instanceof fabric__namespace.Group && target.__cropGroup) {
|
|
7706
7838
|
const ct = target.__cropData;
|
|
7707
7839
|
if ((ct == null ? void 0 : ct._img) && !isCropGroupInCropMode(target)) {
|
|
@@ -7857,7 +7989,7 @@ const PageCanvas = react.forwardRef(
|
|
|
7857
7989
|
visibilityUpdateInProgressRef.current = false;
|
|
7858
7990
|
}
|
|
7859
7991
|
doSyncRef.current = () => {
|
|
7860
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
7992
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
7861
7993
|
const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
|
|
7862
7994
|
const state = useEditorStore.getState();
|
|
7863
7995
|
const elementsToSync = elements;
|
|
@@ -8018,15 +8150,22 @@ const PageCanvas = react.forwardRef(
|
|
|
8018
8150
|
const storedImageUrl = existingObj.__imageSrc;
|
|
8019
8151
|
const currentUrlNormalized = currentImageUrl.trim();
|
|
8020
8152
|
const storedUrlNormalized = storedImageUrl ? String(storedImageUrl).trim() : "";
|
|
8021
|
-
const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
8022
|
-
const storedColorMapStr = existingObj.__svgColorMap || "";
|
|
8023
|
-
const colorMapChanged = svgColorMapStr !== storedColorMapStr;
|
|
8024
|
-
const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;
|
|
8025
|
-
const needsReload = sourceUrlChanged || colorMapChanged;
|
|
8026
8153
|
const hasUrl = currentUrlNormalized !== "";
|
|
8027
8154
|
const isCropGroup2 = existingObj instanceof fabric__namespace.Group && existingObj.__cropGroup;
|
|
8028
8155
|
const isPlaceholderGroup = isEmptyImagePlaceholderGroup(existingObj);
|
|
8029
8156
|
const isPlaceholder = isPlaceholderGroup || !(existingObj instanceof fabric__namespace.FabricImage) || existingObj instanceof fabric__namespace.Group && !isCropGroup2;
|
|
8157
|
+
const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
8158
|
+
const storedColorMapStr = existingObj.__svgColorMap || "";
|
|
8159
|
+
const colorMapChanged = svgColorMapStr !== storedColorMapStr;
|
|
8160
|
+
const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;
|
|
8161
|
+
const newFadeKey = edgeFadeKey(element);
|
|
8162
|
+
const oldFadeKey = isCropGroup2 ? existingObj.__edgeFadeInputKey || "" : existingObj.__edgeFadeKey || "";
|
|
8163
|
+
const innerImg = (_e = existingObj == null ? void 0 : existingObj.__cropData) == null ? void 0 : _e._img;
|
|
8164
|
+
const innerOldKey = isCropGroup2 ? oldFadeKey : innerImg ? innerImg.__edgeFadeKey || "" : oldFadeKey;
|
|
8165
|
+
const cropFadeRendererMissing = isCropGroup2 && Boolean(newFadeKey) && !existingObj.__edgeFadeRenderConfig;
|
|
8166
|
+
const fadeKeyChanged = newFadeKey !== oldFadeKey || newFadeKey !== innerOldKey || cropFadeRendererMissing;
|
|
8167
|
+
const needsReload = sourceUrlChanged || colorMapChanged || fadeKeyChanged && !isCropGroup2;
|
|
8168
|
+
const needsCropGroupFadeUpdate = isCropGroup2 && fadeKeyChanged;
|
|
8030
8169
|
const hadUrlBefore = storedImageUrl && String(storedImageUrl).trim() !== "";
|
|
8031
8170
|
if (!hasUrl && hadUrlBefore) {
|
|
8032
8171
|
const placeholder = isCropGroup2 ? createImagePlaceholderForGroup(element) : createImagePlaceholder(element);
|
|
@@ -8042,16 +8181,16 @@ const PageCanvas = react.forwardRef(
|
|
|
8042
8181
|
fc.requestRenderAll();
|
|
8043
8182
|
continue;
|
|
8044
8183
|
}
|
|
8045
|
-
const imageFitForReplace = element.imageFit || ((
|
|
8046
|
-
const clipShapeForReplace = element.clipShape ?? ((
|
|
8184
|
+
const imageFitForReplace = element.imageFit || ((_f = element.style) == null ? void 0 : _f.imageFit) || "cover";
|
|
8185
|
+
const clipShapeForReplace = element.clipShape ?? ((_g = element.style) == null ? void 0 : _g.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
8047
8186
|
const needCropGroupForElement = imageFitForReplace !== "fill" || clipShapeForReplace && clipShapeForReplace !== "none";
|
|
8048
8187
|
const plainImageNeedsCropGroup = hasUrl && !isCropGroup2 && existingObj instanceof fabric__namespace.FabricImage && needCropGroupForElement;
|
|
8049
|
-
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup)) {
|
|
8188
|
+
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup || needsCropGroupFadeUpdate)) {
|
|
8050
8189
|
if (needsReload && !isBeingTransformed && (!wasJustModified || sourceUrlChanged)) {
|
|
8051
8190
|
loadImageAsync(element, existingObj, fc);
|
|
8052
8191
|
} else if (plainImageNeedsCropGroup) {
|
|
8053
8192
|
loadImageAsync(element, existingObj, fc);
|
|
8054
|
-
} else if (!needsReload && isCropGroup2) {
|
|
8193
|
+
} else if ((!needsReload || needsCropGroupFadeUpdate) && isCropGroup2) {
|
|
8055
8194
|
const ct = existingObj.__cropData;
|
|
8056
8195
|
if (ct) {
|
|
8057
8196
|
const resolvedCrop = pageTree.length > 0 ? getNodeBounds(element, pageTree) : { width: typeof element.width === "number" ? element.width : 200, height: typeof element.height === "number" ? element.height : 50 };
|
|
@@ -8148,6 +8287,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8148
8287
|
}
|
|
8149
8288
|
}
|
|
8150
8289
|
updateCoverLayout(existingObj);
|
|
8290
|
+
applyEdgeFadeFrameClipPath(existingObj, element, ct.frameW, ct.frameH, ct.shape || "rect", ct.rx || 0);
|
|
8151
8291
|
if (allowEditing) {
|
|
8152
8292
|
installCanvaMaskControls(existingObj);
|
|
8153
8293
|
} else {
|
|
@@ -8457,7 +8597,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8457
8597
|
fc.add(placeholder);
|
|
8458
8598
|
fc.bringObjectToFront(placeholder);
|
|
8459
8599
|
const activeObj = fc.getActiveObject();
|
|
8460
|
-
if (activeObj && (((
|
|
8600
|
+
if (activeObj && (((_h = activeObj._ct) == null ? void 0 : _h.isCropGroup) || activeObj.__cropGroup)) {
|
|
8461
8601
|
fc.setActiveObject(activeObj);
|
|
8462
8602
|
}
|
|
8463
8603
|
placeholder.dirty = true;
|
|
@@ -8497,7 +8637,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8497
8637
|
fc.add(obj);
|
|
8498
8638
|
fc.bringObjectToFront(obj);
|
|
8499
8639
|
const activeObj = fc.getActiveObject();
|
|
8500
|
-
if (activeObj && (((
|
|
8640
|
+
if (activeObj && (((_i = activeObj._ct) == null ? void 0 : _i.isCropGroup) || activeObj.__cropGroup)) {
|
|
8501
8641
|
fc.setActiveObject(activeObj);
|
|
8502
8642
|
}
|
|
8503
8643
|
obj.dirty = true;
|
|
@@ -8531,7 +8671,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8531
8671
|
isRebuildingRef.current = false;
|
|
8532
8672
|
fc.requestRenderAll();
|
|
8533
8673
|
if (activeBeforeSync && fc.getObjects().includes(activeBeforeSync)) {
|
|
8534
|
-
const isCropGroup2 = ((
|
|
8674
|
+
const isCropGroup2 = ((_j = activeBeforeSync._ct) == null ? void 0 : _j.isCropGroup) || activeBeforeSync.__cropGroup;
|
|
8535
8675
|
if (isCropGroup2) {
|
|
8536
8676
|
fc.setActiveObject(activeBeforeSync);
|
|
8537
8677
|
fc.requestRenderAll();
|
|
@@ -8953,6 +9093,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8953
9093
|
}
|
|
8954
9094
|
}
|
|
8955
9095
|
updateCoverLayout(obj);
|
|
9096
|
+
applyEdgeFadeFrameClipPath(obj, element, elementWidth, elementHeight, ct.shape || "rect", ct.rx || 0);
|
|
8956
9097
|
obj.setCoords();
|
|
8957
9098
|
obj.dirty = true;
|
|
8958
9099
|
if (obj.clipPath) {
|
|
@@ -9536,8 +9677,131 @@ const PageCanvas = react.forwardRef(
|
|
|
9536
9677
|
obj.__lastStrokeGradientJson = "null";
|
|
9537
9678
|
}
|
|
9538
9679
|
};
|
|
9680
|
+
const clamp2 = (v, min, max) => {
|
|
9681
|
+
return Math.max(min, Math.min(max, v));
|
|
9682
|
+
};
|
|
9683
|
+
const applyEdgeFadeFrameClipPath = (group, element, frameW, frameH, shape, rxRatio) => {
|
|
9684
|
+
var _a, _b, _c;
|
|
9685
|
+
const fadeElement = element;
|
|
9686
|
+
const fadeGroup = group;
|
|
9687
|
+
const inputKey = edgeFadeKey(fadeElement);
|
|
9688
|
+
const hasFade = hasEdgeFade(fadeElement);
|
|
9689
|
+
if (!fadeGroup.__edgeFadeOriginalDrawObject) {
|
|
9690
|
+
fadeGroup.__edgeFadeOriginalDrawObject = group.drawObject;
|
|
9691
|
+
}
|
|
9692
|
+
if (hasFade) {
|
|
9693
|
+
if ((_a = group.clipPath) == null ? void 0 : _a.__edgeFadeMask) {
|
|
9694
|
+
group.clipPath = void 0;
|
|
9695
|
+
updateCoverLayout(group);
|
|
9696
|
+
}
|
|
9697
|
+
fadeGroup.__edgeFadeRenderConfig = {
|
|
9698
|
+
key: `${inputKey}|${Math.round(frameW)}|${Math.round(frameH)}|${shape}|${rxRatio}`,
|
|
9699
|
+
frameW: Math.max(1, Number(frameW) || 1),
|
|
9700
|
+
frameH: Math.max(1, Number(frameH) || 1),
|
|
9701
|
+
topSize: clamp2(Number(fadeElement.fadeTopSize) || 0, 0, 1),
|
|
9702
|
+
topAmount: clamp2(fadeElement.fadeTopAmount == null ? 1 : Number(fadeElement.fadeTopAmount), 0, 1),
|
|
9703
|
+
rightSize: clamp2(Number(fadeElement.fadeRightSize) || 0, 0, 1),
|
|
9704
|
+
rightAmount: clamp2(fadeElement.fadeRightAmount == null ? 1 : Number(fadeElement.fadeRightAmount), 0, 1),
|
|
9705
|
+
bottomSize: clamp2(Number(fadeElement.fadeBottomSize) || 0, 0, 1),
|
|
9706
|
+
bottomAmount: clamp2(fadeElement.fadeBottomAmount == null ? 1 : Number(fadeElement.fadeBottomAmount), 0, 1),
|
|
9707
|
+
leftSize: clamp2(Number(fadeElement.fadeLeftSize) || 0, 0, 1),
|
|
9708
|
+
leftAmount: clamp2(fadeElement.fadeLeftAmount == null ? 1 : Number(fadeElement.fadeLeftAmount), 0, 1),
|
|
9709
|
+
topHardness: clamp2(Number(fadeElement.fadeTopHardness) || 1, 0.1, 5),
|
|
9710
|
+
rightHardness: clamp2(Number(fadeElement.fadeRightHardness) || 1, 0.1, 5),
|
|
9711
|
+
bottomHardness: clamp2(Number(fadeElement.fadeBottomHardness) || 1, 0.1, 5),
|
|
9712
|
+
leftHardness: clamp2(Number(fadeElement.fadeLeftHardness) || 1, 0.1, 5)
|
|
9713
|
+
};
|
|
9714
|
+
const originalDrawObject = fadeGroup.__edgeFadeOriginalDrawObject ?? group.drawObject;
|
|
9715
|
+
group.drawObject = function edgeFadeDrawObject(ctx, forClipping, context) {
|
|
9716
|
+
originalDrawObject.call(this, ctx, forClipping, context);
|
|
9717
|
+
if (forClipping) return;
|
|
9718
|
+
const cfg = this.__edgeFadeRenderConfig;
|
|
9719
|
+
if (!cfg) return;
|
|
9720
|
+
const liveW = Number(this.width) || 0;
|
|
9721
|
+
const liveH = Number(this.height) || 0;
|
|
9722
|
+
const w = liveW > 0 ? liveW : cfg.frameW;
|
|
9723
|
+
const h = liveH > 0 ? liveH : cfg.frameH;
|
|
9724
|
+
const x = -w / 2;
|
|
9725
|
+
const y = -h / 2;
|
|
9726
|
+
const paintBand = (side, size, amount, hardness) => {
|
|
9727
|
+
if (size <= 0 || amount >= 1) return;
|
|
9728
|
+
ctx.save();
|
|
9729
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
9730
|
+
let gradient;
|
|
9731
|
+
const eraseAtEdge = 1 - amount;
|
|
9732
|
+
const STOPS = 24;
|
|
9733
|
+
const addStops = (g) => {
|
|
9734
|
+
for (let i = 0; i <= STOPS; i++) {
|
|
9735
|
+
const t = i / STOPS;
|
|
9736
|
+
const keepProgress = Math.pow(t, hardness);
|
|
9737
|
+
const a = eraseAtEdge * (1 - keepProgress);
|
|
9738
|
+
g.addColorStop(t, `rgba(0,0,0,${a})`);
|
|
9739
|
+
}
|
|
9740
|
+
};
|
|
9741
|
+
if (side === "top") {
|
|
9742
|
+
const band = Math.max(1, h * size);
|
|
9743
|
+
gradient = ctx.createLinearGradient(0, y, 0, y + band);
|
|
9744
|
+
addStops(gradient);
|
|
9745
|
+
ctx.fillStyle = gradient;
|
|
9746
|
+
ctx.fillRect(x, y, w, band);
|
|
9747
|
+
if (amount <= 1e-3) ctx.fillRect(x, y, w, Math.min(2, band));
|
|
9748
|
+
} else if (side === "bottom") {
|
|
9749
|
+
const band = Math.max(1, h * size);
|
|
9750
|
+
gradient = ctx.createLinearGradient(0, y + h, 0, y + h - band);
|
|
9751
|
+
addStops(gradient);
|
|
9752
|
+
ctx.fillStyle = gradient;
|
|
9753
|
+
ctx.fillRect(x, y + h - band, w, band);
|
|
9754
|
+
if (amount <= 1e-3) ctx.fillRect(x, y + h - Math.min(2, band), w, Math.min(2, band));
|
|
9755
|
+
} else if (side === "left") {
|
|
9756
|
+
const band = Math.max(1, w * size);
|
|
9757
|
+
gradient = ctx.createLinearGradient(x, 0, x + band, 0);
|
|
9758
|
+
addStops(gradient);
|
|
9759
|
+
ctx.fillStyle = gradient;
|
|
9760
|
+
ctx.fillRect(x, y, band, h);
|
|
9761
|
+
if (amount <= 1e-3) ctx.fillRect(x, y, Math.min(2, band), h);
|
|
9762
|
+
} else {
|
|
9763
|
+
const band = Math.max(1, w * size);
|
|
9764
|
+
gradient = ctx.createLinearGradient(x + w, 0, x + w - band, 0);
|
|
9765
|
+
addStops(gradient);
|
|
9766
|
+
ctx.fillStyle = gradient;
|
|
9767
|
+
ctx.fillRect(x + w - band, y, band, h);
|
|
9768
|
+
if (amount <= 1e-3) ctx.fillRect(x + w - Math.min(2, band), y, Math.min(2, band), h);
|
|
9769
|
+
}
|
|
9770
|
+
ctx.restore();
|
|
9771
|
+
};
|
|
9772
|
+
paintBand("top", cfg.topSize, cfg.topAmount, cfg.topHardness);
|
|
9773
|
+
paintBand("right", cfg.rightSize, cfg.rightAmount, cfg.rightHardness);
|
|
9774
|
+
paintBand("bottom", cfg.bottomSize, cfg.bottomAmount, cfg.bottomHardness);
|
|
9775
|
+
paintBand("left", cfg.leftSize, cfg.leftAmount, cfg.leftHardness);
|
|
9776
|
+
};
|
|
9777
|
+
group.set({ objectCaching: true, noScaleCache: false });
|
|
9778
|
+
fadeGroup.__edgeFadeKey = fadeGroup.__edgeFadeRenderConfig.key;
|
|
9779
|
+
fadeGroup.__edgeFadeInputKey = inputKey;
|
|
9780
|
+
} else {
|
|
9781
|
+
if (fadeGroup.__edgeFadeOriginalDrawObject) {
|
|
9782
|
+
group.drawObject = fadeGroup.__edgeFadeOriginalDrawObject;
|
|
9783
|
+
}
|
|
9784
|
+
delete fadeGroup.__edgeFadeRenderConfig;
|
|
9785
|
+
delete fadeGroup.__edgeFadeKey;
|
|
9786
|
+
delete fadeGroup.__edgeFadeInputKey;
|
|
9787
|
+
if ((_b = group.clipPath) == null ? void 0 : _b.__edgeFadeMask) {
|
|
9788
|
+
group.clipPath = void 0;
|
|
9789
|
+
updateCoverLayout(group);
|
|
9790
|
+
}
|
|
9791
|
+
}
|
|
9792
|
+
if (group.clipPath) {
|
|
9793
|
+
group.clipPath.dirty = true;
|
|
9794
|
+
group.clipPath.setCoords();
|
|
9795
|
+
}
|
|
9796
|
+
fadeGroup.dirty = true;
|
|
9797
|
+
const children = group.getObjects();
|
|
9798
|
+
children.forEach((child) => {
|
|
9799
|
+
child.dirty = true;
|
|
9800
|
+
});
|
|
9801
|
+
(_c = group.canvas) == null ? void 0 : _c.requestRenderAll();
|
|
9802
|
+
};
|
|
9539
9803
|
const loadImageAsync = async (element, placeholder, fc) => {
|
|
9540
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
9804
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
9541
9805
|
const imageUrl = element.src || element.imageUrl;
|
|
9542
9806
|
if (!imageUrl) return;
|
|
9543
9807
|
const elementId = element.id;
|
|
@@ -9550,7 +9814,9 @@ const PageCanvas = react.forwardRef(
|
|
|
9550
9814
|
const existingImg = ct == null ? void 0 : ct._img;
|
|
9551
9815
|
const existingSrc = placeholder.__imageSrc;
|
|
9552
9816
|
const existingSvgColorMap = placeholder.__svgColorMap || "";
|
|
9553
|
-
|
|
9817
|
+
const existingFadeKey = existingImg && existingImg.__edgeFadeKey || placeholder.__edgeFadeKey || "";
|
|
9818
|
+
const nextFadeKey = edgeFadeKey(element);
|
|
9819
|
+
if (existingImg && existingSrc === imageUrl && existingSvgColorMap === nextSvgColorMap && existingFadeKey === nextFadeKey) {
|
|
9554
9820
|
return placeholder;
|
|
9555
9821
|
}
|
|
9556
9822
|
}
|
|
@@ -9567,6 +9833,22 @@ const PageCanvas = react.forwardRef(
|
|
|
9567
9833
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
9568
9834
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
9569
9835
|
if (!isLatestRequest()) return;
|
|
9836
|
+
const imageFitForFade = element.imageFit || ((_a = element.style) == null ? void 0 : _a.imageFit) || "cover";
|
|
9837
|
+
const clipShapeForFade = element.clipShape ?? ((_b = element.style) == null ? void 0 : _b.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9838
|
+
const willUseCropGroupForFade = imageFitForFade !== "fill" || clipShapeForFade && clipShapeForFade !== "none";
|
|
9839
|
+
try {
|
|
9840
|
+
if (hasEdgeFade(element) && !willUseCropGroupForFade) {
|
|
9841
|
+
const srcEl = (_c = img.getElement) == null ? void 0 : _c.call(img);
|
|
9842
|
+
if (srcEl) {
|
|
9843
|
+
const baked = bakeEdgeFade(srcEl, element);
|
|
9844
|
+
img.setElement(baked);
|
|
9845
|
+
img.__edgeFadeKey = edgeFadeKey(element);
|
|
9846
|
+
img.dirty = true;
|
|
9847
|
+
}
|
|
9848
|
+
}
|
|
9849
|
+
} catch (e) {
|
|
9850
|
+
console.warn("[edgeFade] bake failed:", e);
|
|
9851
|
+
}
|
|
9570
9852
|
const isHidden = !element.visible;
|
|
9571
9853
|
img.set({
|
|
9572
9854
|
originX: "left",
|
|
@@ -9599,8 +9881,8 @@ const PageCanvas = react.forwardRef(
|
|
|
9599
9881
|
});
|
|
9600
9882
|
img.setCoords();
|
|
9601
9883
|
} else {
|
|
9602
|
-
const imageFit = element.imageFit || ((
|
|
9603
|
-
const clipShape = element.clipShape ?? ((
|
|
9884
|
+
const imageFit = element.imageFit || ((_d = element.style) == null ? void 0 : _d.imageFit) || "cover";
|
|
9885
|
+
const clipShape = element.clipShape ?? ((_e = element.style) == null ? void 0 : _e.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9604
9886
|
const needCropGroup2 = imageFit !== "fill" || clipShape && clipShape !== "none";
|
|
9605
9887
|
const imgNaturalWidth = img.width || 1;
|
|
9606
9888
|
const imgNaturalHeight = img.height || 1;
|
|
@@ -9627,7 +9909,7 @@ const PageCanvas = react.forwardRef(
|
|
|
9627
9909
|
if (imageFit === "fill" && !needCropGroup2) {
|
|
9628
9910
|
const finalScaleX = baseScaleX * (element.scaleX ?? 1);
|
|
9629
9911
|
const finalScaleY = baseScaleY * (element.scaleY ?? 1);
|
|
9630
|
-
const pageTreeForCreate = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
9912
|
+
const pageTreeForCreate = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_f = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _f.children) ?? [];
|
|
9631
9913
|
const createPos = pageTreeForCreate.length > 0 ? (() => {
|
|
9632
9914
|
const node = findNodeById(pageTreeForCreate, element.id);
|
|
9633
9915
|
return node ? getAbsoluteBounds(node, pageTreeForCreate) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9672,12 +9954,12 @@ const PageCanvas = react.forwardRef(
|
|
|
9672
9954
|
}
|
|
9673
9955
|
img.__imageSrc = imageUrl;
|
|
9674
9956
|
img.__svgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
9675
|
-
const imageFitFinal = element.imageFit || ((
|
|
9676
|
-
const clipShapeFinal = element.clipShape ?? ((
|
|
9957
|
+
const imageFitFinal = element.imageFit || ((_g = element.style) == null ? void 0 : _g.imageFit) || "cover";
|
|
9958
|
+
const clipShapeFinal = element.clipShape ?? ((_h = element.style) == null ? void 0 : _h.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9677
9959
|
const needCropGroup = imageFitFinal !== "fill" || clipShapeFinal && clipShapeFinal !== "none";
|
|
9678
9960
|
let finalObject = img;
|
|
9679
9961
|
if (needCropGroup) {
|
|
9680
|
-
const pageTreeForCropResolve = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
9962
|
+
const pageTreeForCropResolve = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_i = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _i.children) ?? [];
|
|
9681
9963
|
const nodeForSize = pageTreeForCropResolve.length ? findNodeById(pageTreeForCropResolve, element.id) : null;
|
|
9682
9964
|
const w = nodeForSize && isElement(nodeForSize) ? nodeForSize.width : element.width;
|
|
9683
9965
|
const h = nodeForSize && isElement(nodeForSize) ? nodeForSize.height : element.height;
|
|
@@ -9709,16 +9991,16 @@ const PageCanvas = react.forwardRef(
|
|
|
9709
9991
|
let panY = element.cropPanY ?? 0.5;
|
|
9710
9992
|
let zoom2 = element.cropZoom ?? 1;
|
|
9711
9993
|
if (existingCropGroup) {
|
|
9712
|
-
const existingImg = (
|
|
9994
|
+
const existingImg = (_j = existingCropGroup.__cropData) == null ? void 0 : _j._img;
|
|
9713
9995
|
if (existingImg) {
|
|
9714
|
-
panX = ((
|
|
9715
|
-
panY = ((
|
|
9716
|
-
zoom2 = ((
|
|
9996
|
+
panX = ((_k = existingImg._ct) == null ? void 0 : _k.panX) ?? existingImg.__panX ?? panX;
|
|
9997
|
+
panY = ((_l = existingImg._ct) == null ? void 0 : _l.panY) ?? existingImg.__panY ?? panY;
|
|
9998
|
+
zoom2 = ((_m = existingImg._ct) == null ? void 0 : _m.zoom) ?? zoom2;
|
|
9717
9999
|
}
|
|
9718
10000
|
}
|
|
9719
10001
|
const isDynamicField = dynamicFieldIds.includes(element.id);
|
|
9720
10002
|
const canBeEvented = isEditorMode || isPreviewMode && isDynamicField;
|
|
9721
|
-
const pageTreeForCrop = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
10003
|
+
const pageTreeForCrop = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_n = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _n.children) ?? [];
|
|
9722
10004
|
const createPosForCrop = pageTreeForCrop.length > 0 ? (() => {
|
|
9723
10005
|
const node = findNodeById(pageTreeForCrop, element.id);
|
|
9724
10006
|
return node ? getAbsoluteBounds(node, pageTreeForCrop) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9769,17 +10051,18 @@ const PageCanvas = react.forwardRef(
|
|
|
9769
10051
|
} else {
|
|
9770
10052
|
installCanvaMaskControls(cropGroup);
|
|
9771
10053
|
}
|
|
9772
|
-
const cropImg = (
|
|
10054
|
+
const cropImg = (_o = cropGroup.__cropData) == null ? void 0 : _o._img;
|
|
9773
10055
|
if (cropImg) {
|
|
9774
10056
|
cropImg._ct = { panX, panY, zoom: zoom2 };
|
|
9775
10057
|
updateCoverLayout(cropGroup);
|
|
9776
10058
|
}
|
|
10059
|
+
applyEdgeFadeFrameClipPath(cropGroup, element, frameW, frameH, shape, rxRatio);
|
|
9777
10060
|
setObjectData(cropGroup, element.id);
|
|
9778
10061
|
cropGroup.__imageElement = cropImg;
|
|
9779
10062
|
cropGroup.__imageSrc = imageUrl;
|
|
9780
10063
|
cropGroup.__svgColorMap = nextSvgColorMap;
|
|
9781
10064
|
if (cropImg && element.imageNaturalWidth == null) {
|
|
9782
|
-
const el = ((
|
|
10065
|
+
const el = ((_p = cropImg.getElement) == null ? void 0 : _p.call(cropImg)) ?? cropImg._element;
|
|
9783
10066
|
const orig = typeof cropImg.getOriginalSize === "function" ? cropImg.getOriginalSize() : null;
|
|
9784
10067
|
const nw = (orig == null ? void 0 : orig.width) ?? (el == null ? void 0 : el.naturalWidth) ?? cropImg.width;
|
|
9785
10068
|
const nh = (orig == null ? void 0 : orig.height) ?? (el == null ? void 0 : el.naturalHeight) ?? cropImg.height;
|
|
@@ -13940,12 +14223,69 @@ class PixldocsRenderer {
|
|
|
13940
14223
|
{ width: canvasWidth, height: canvasHeight },
|
|
13941
14224
|
{ cssOnly: false, backstoreOnly: false }
|
|
13942
14225
|
);
|
|
14226
|
+
const fadeBakeRecords = [];
|
|
14227
|
+
try {
|
|
14228
|
+
const objs = fabricInstance.getObjects().slice();
|
|
14229
|
+
for (const obj of objs) {
|
|
14230
|
+
const isFadedCropGroup = obj instanceof fabric__namespace.Group && (Boolean(obj.__edgeFadeRenderConfig) || Boolean(obj.__edgeFadeKey) || Boolean(obj.__edgeFadeInputKey));
|
|
14231
|
+
if (!isFadedCropGroup) continue;
|
|
14232
|
+
try {
|
|
14233
|
+
const baked = obj.toCanvasElement({
|
|
14234
|
+
multiplier: 2,
|
|
14235
|
+
enableRetinaScaling: false
|
|
14236
|
+
});
|
|
14237
|
+
const rect = obj.getBoundingRect();
|
|
14238
|
+
const replacement = new fabric__namespace.FabricImage(baked, {
|
|
14239
|
+
left: rect.left,
|
|
14240
|
+
top: rect.top,
|
|
14241
|
+
originX: "left",
|
|
14242
|
+
originY: "top",
|
|
14243
|
+
scaleX: rect.width / baked.width,
|
|
14244
|
+
scaleY: rect.height / baked.height,
|
|
14245
|
+
selectable: false,
|
|
14246
|
+
evented: false,
|
|
14247
|
+
objectCaching: false
|
|
14248
|
+
});
|
|
14249
|
+
const insertIndex = fabricInstance._objects.indexOf(obj);
|
|
14250
|
+
const prevExclude = obj.excludeFromExport;
|
|
14251
|
+
obj.excludeFromExport = true;
|
|
14252
|
+
if (insertIndex >= 0) {
|
|
14253
|
+
fabricInstance.insertAt(insertIndex + 1, replacement);
|
|
14254
|
+
} else {
|
|
14255
|
+
fabricInstance.add(replacement);
|
|
14256
|
+
}
|
|
14257
|
+
fadeBakeRecords.push({
|
|
14258
|
+
original: obj,
|
|
14259
|
+
replacement,
|
|
14260
|
+
prevExclude,
|
|
14261
|
+
insertIndex
|
|
14262
|
+
});
|
|
14263
|
+
} catch (bakeErr) {
|
|
14264
|
+
console.warn("[canvas-renderer][edgeFade] bake-for-svg failed:", bakeErr);
|
|
14265
|
+
}
|
|
14266
|
+
}
|
|
14267
|
+
if (fadeBakeRecords.length) {
|
|
14268
|
+
fabricInstance.renderAll();
|
|
14269
|
+
console.log(
|
|
14270
|
+
`[canvas-renderer][edgeFade] baked ${fadeBakeRecords.length} faded object(s) for SVG capture`
|
|
14271
|
+
);
|
|
14272
|
+
}
|
|
14273
|
+
} catch (e) {
|
|
14274
|
+
console.warn("[canvas-renderer][edgeFade] bake pass failed:", e);
|
|
14275
|
+
}
|
|
13943
14276
|
const rawSvgString = fabricInstance.toSVG();
|
|
13944
14277
|
const svgString = this.normalizeSvgDimensions(
|
|
13945
14278
|
rawSvgString,
|
|
13946
14279
|
canvasWidth,
|
|
13947
14280
|
canvasHeight
|
|
13948
14281
|
);
|
|
14282
|
+
for (const rec of fadeBakeRecords) {
|
|
14283
|
+
try {
|
|
14284
|
+
fabricInstance.remove(rec.replacement);
|
|
14285
|
+
rec.original.excludeFromExport = rec.prevExclude;
|
|
14286
|
+
} catch {
|
|
14287
|
+
}
|
|
14288
|
+
}
|
|
13949
14289
|
fabricInstance.enableRetinaScaling = prevRetina;
|
|
13950
14290
|
fabricInstance.setDimensions(
|
|
13951
14291
|
{ width: prevWidth, height: prevHeight },
|