@pixldocs/canvas-renderer 0.5.99 → 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 +486 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +486 -59
- 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;
|
|
@@ -5085,10 +5092,14 @@ function applyTextBackground(obj, cfg) {
|
|
|
5085
5092
|
const blur = Math.max(0, Number(shadow.blur ?? 0));
|
|
5086
5093
|
const shadowColor = String(shadow.color);
|
|
5087
5094
|
const pad = Math.max(16, Math.ceil(blur * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);
|
|
5088
|
-
const
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5095
|
+
const shadowBounds = unionBounds([
|
|
5096
|
+
...rects,
|
|
5097
|
+
computeTextVisualBounds(this, w, h)
|
|
5098
|
+
]);
|
|
5099
|
+
const bx = shadowBounds.x - pad;
|
|
5100
|
+
const by = shadowBounds.y - pad;
|
|
5101
|
+
const bw = shadowBounds.w + pad * 2;
|
|
5102
|
+
const bh = shadowBounds.h + pad * 2;
|
|
5092
5103
|
const dataAttrs = `data-blur="${blur.toFixed(3)}" data-ox="${ox.toFixed(3)}" data-oy="${oy.toFixed(3)}" data-bx="${bx.toFixed(3)}" data-by="${by.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}" data-color="${escapeXmlAttr(shadowColor)}"`;
|
|
5093
5104
|
const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
|
|
5094
5105
|
if (hasBg && (bg == null ? void 0 : bg.shadowAffectsBg) !== false) {
|
|
@@ -5150,6 +5161,51 @@ function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
|
5150
5161
|
parts.push("Z");
|
|
5151
5162
|
return parts.join(" ");
|
|
5152
5163
|
}
|
|
5164
|
+
function unionBounds(bounds) {
|
|
5165
|
+
const valid = bounds.filter((b) => Number.isFinite(b.x) && Number.isFinite(b.y) && b.w > 0 && b.h > 0);
|
|
5166
|
+
if (valid.length === 0) return { x: 0, y: 0, w: 1, h: 1 };
|
|
5167
|
+
const minX = Math.min(...valid.map((b) => b.x));
|
|
5168
|
+
const minY = Math.min(...valid.map((b) => b.y));
|
|
5169
|
+
const maxX = Math.max(...valid.map((b) => b.x + b.w));
|
|
5170
|
+
const maxY = Math.max(...valid.map((b) => b.y + b.h));
|
|
5171
|
+
return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
|
|
5172
|
+
}
|
|
5173
|
+
function computeTextVisualBounds(obj, w, h) {
|
|
5174
|
+
var _a;
|
|
5175
|
+
const lines = (obj == null ? void 0 : obj._textLines) ?? [];
|
|
5176
|
+
if (!lines || lines.length === 0) return { x: -w / 2, y: -h / 2, w, h };
|
|
5177
|
+
const rects = [];
|
|
5178
|
+
const halfW = w / 2;
|
|
5179
|
+
const halfH = h / 2;
|
|
5180
|
+
const lineHeightRatio = Math.max(0.01, Number((obj == null ? void 0 : obj.lineHeight) ?? 1) || 1);
|
|
5181
|
+
let cursorY = -halfH;
|
|
5182
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5183
|
+
let lineW = 0;
|
|
5184
|
+
let lineLeft = 0;
|
|
5185
|
+
let lineH = 0;
|
|
5186
|
+
try {
|
|
5187
|
+
lineW = obj.getLineWidth(i) || 0;
|
|
5188
|
+
} catch {
|
|
5189
|
+
lineW = 0;
|
|
5190
|
+
}
|
|
5191
|
+
try {
|
|
5192
|
+
lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
|
|
5193
|
+
} catch {
|
|
5194
|
+
lineLeft = 0;
|
|
5195
|
+
}
|
|
5196
|
+
try {
|
|
5197
|
+
lineH = obj.getHeightOfLine(i) || 0;
|
|
5198
|
+
} catch {
|
|
5199
|
+
lineH = 0;
|
|
5200
|
+
}
|
|
5201
|
+
const rawSlotH = i === lines.length - 1 ? lineH / lineHeightRatio : lineH;
|
|
5202
|
+
const usedH = cursorY + halfH;
|
|
5203
|
+
const slotH = Math.max(0, Math.min(rawSlotH, h - usedH));
|
|
5204
|
+
if (lineW > 0 && slotH > 0) rects.push({ x: -halfW + lineLeft, y: cursorY, w: lineW, h: slotH });
|
|
5205
|
+
cursorY += slotH;
|
|
5206
|
+
}
|
|
5207
|
+
return unionBounds(rects.length > 0 ? rects : [{ x: -w / 2, y: -h / 2, w, h }]);
|
|
5208
|
+
}
|
|
5153
5209
|
function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
|
|
5154
5210
|
var _a;
|
|
5155
5211
|
if (!fit) {
|
|
@@ -6144,6 +6200,127 @@ function renderSmartElementToDataUri(type, props, width, height) {
|
|
|
6144
6200
|
if (!svg) return null;
|
|
6145
6201
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
6146
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
|
+
}
|
|
6147
6324
|
function angleToCoords(angleDeg) {
|
|
6148
6325
|
const rad = angleDeg * Math.PI / 180;
|
|
6149
6326
|
const x1 = 0.5 - Math.sin(rad) * 0.5;
|
|
@@ -7653,6 +7830,10 @@ const PageCanvas = react.forwardRef(
|
|
|
7653
7830
|
fabricCanvas.on("mouse:dblclick", (e) => {
|
|
7654
7831
|
if (!isActiveRef.current || !allowEditing) return;
|
|
7655
7832
|
let target = e.target;
|
|
7833
|
+
if (!target) {
|
|
7834
|
+
const active = fabricCanvas.getActiveObject();
|
|
7835
|
+
if (active) target = active;
|
|
7836
|
+
}
|
|
7656
7837
|
if (target && target instanceof fabric__namespace.Group && target.__cropGroup) {
|
|
7657
7838
|
const ct = target.__cropData;
|
|
7658
7839
|
if ((ct == null ? void 0 : ct._img) && !isCropGroupInCropMode(target)) {
|
|
@@ -7808,7 +7989,7 @@ const PageCanvas = react.forwardRef(
|
|
|
7808
7989
|
visibilityUpdateInProgressRef.current = false;
|
|
7809
7990
|
}
|
|
7810
7991
|
doSyncRef.current = () => {
|
|
7811
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
7992
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
7812
7993
|
const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
|
|
7813
7994
|
const state = useEditorStore.getState();
|
|
7814
7995
|
const elementsToSync = elements;
|
|
@@ -7969,15 +8150,22 @@ const PageCanvas = react.forwardRef(
|
|
|
7969
8150
|
const storedImageUrl = existingObj.__imageSrc;
|
|
7970
8151
|
const currentUrlNormalized = currentImageUrl.trim();
|
|
7971
8152
|
const storedUrlNormalized = storedImageUrl ? String(storedImageUrl).trim() : "";
|
|
7972
|
-
const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
7973
|
-
const storedColorMapStr = existingObj.__svgColorMap || "";
|
|
7974
|
-
const colorMapChanged = svgColorMapStr !== storedColorMapStr;
|
|
7975
|
-
const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;
|
|
7976
|
-
const needsReload = sourceUrlChanged || colorMapChanged;
|
|
7977
8153
|
const hasUrl = currentUrlNormalized !== "";
|
|
7978
8154
|
const isCropGroup2 = existingObj instanceof fabric__namespace.Group && existingObj.__cropGroup;
|
|
7979
8155
|
const isPlaceholderGroup = isEmptyImagePlaceholderGroup(existingObj);
|
|
7980
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;
|
|
7981
8169
|
const hadUrlBefore = storedImageUrl && String(storedImageUrl).trim() !== "";
|
|
7982
8170
|
if (!hasUrl && hadUrlBefore) {
|
|
7983
8171
|
const placeholder = isCropGroup2 ? createImagePlaceholderForGroup(element) : createImagePlaceholder(element);
|
|
@@ -7993,16 +8181,16 @@ const PageCanvas = react.forwardRef(
|
|
|
7993
8181
|
fc.requestRenderAll();
|
|
7994
8182
|
continue;
|
|
7995
8183
|
}
|
|
7996
|
-
const imageFitForReplace = element.imageFit || ((
|
|
7997
|
-
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");
|
|
7998
8186
|
const needCropGroupForElement = imageFitForReplace !== "fill" || clipShapeForReplace && clipShapeForReplace !== "none";
|
|
7999
8187
|
const plainImageNeedsCropGroup = hasUrl && !isCropGroup2 && existingObj instanceof fabric__namespace.FabricImage && needCropGroupForElement;
|
|
8000
|
-
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup)) {
|
|
8188
|
+
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup || needsCropGroupFadeUpdate)) {
|
|
8001
8189
|
if (needsReload && !isBeingTransformed && (!wasJustModified || sourceUrlChanged)) {
|
|
8002
8190
|
loadImageAsync(element, existingObj, fc);
|
|
8003
8191
|
} else if (plainImageNeedsCropGroup) {
|
|
8004
8192
|
loadImageAsync(element, existingObj, fc);
|
|
8005
|
-
} else if (!needsReload && isCropGroup2) {
|
|
8193
|
+
} else if ((!needsReload || needsCropGroupFadeUpdate) && isCropGroup2) {
|
|
8006
8194
|
const ct = existingObj.__cropData;
|
|
8007
8195
|
if (ct) {
|
|
8008
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 };
|
|
@@ -8099,6 +8287,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8099
8287
|
}
|
|
8100
8288
|
}
|
|
8101
8289
|
updateCoverLayout(existingObj);
|
|
8290
|
+
applyEdgeFadeFrameClipPath(existingObj, element, ct.frameW, ct.frameH, ct.shape || "rect", ct.rx || 0);
|
|
8102
8291
|
if (allowEditing) {
|
|
8103
8292
|
installCanvaMaskControls(existingObj);
|
|
8104
8293
|
} else {
|
|
@@ -8408,7 +8597,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8408
8597
|
fc.add(placeholder);
|
|
8409
8598
|
fc.bringObjectToFront(placeholder);
|
|
8410
8599
|
const activeObj = fc.getActiveObject();
|
|
8411
|
-
if (activeObj && (((
|
|
8600
|
+
if (activeObj && (((_h = activeObj._ct) == null ? void 0 : _h.isCropGroup) || activeObj.__cropGroup)) {
|
|
8412
8601
|
fc.setActiveObject(activeObj);
|
|
8413
8602
|
}
|
|
8414
8603
|
placeholder.dirty = true;
|
|
@@ -8448,7 +8637,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8448
8637
|
fc.add(obj);
|
|
8449
8638
|
fc.bringObjectToFront(obj);
|
|
8450
8639
|
const activeObj = fc.getActiveObject();
|
|
8451
|
-
if (activeObj && (((
|
|
8640
|
+
if (activeObj && (((_i = activeObj._ct) == null ? void 0 : _i.isCropGroup) || activeObj.__cropGroup)) {
|
|
8452
8641
|
fc.setActiveObject(activeObj);
|
|
8453
8642
|
}
|
|
8454
8643
|
obj.dirty = true;
|
|
@@ -8482,7 +8671,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8482
8671
|
isRebuildingRef.current = false;
|
|
8483
8672
|
fc.requestRenderAll();
|
|
8484
8673
|
if (activeBeforeSync && fc.getObjects().includes(activeBeforeSync)) {
|
|
8485
|
-
const isCropGroup2 = ((
|
|
8674
|
+
const isCropGroup2 = ((_j = activeBeforeSync._ct) == null ? void 0 : _j.isCropGroup) || activeBeforeSync.__cropGroup;
|
|
8486
8675
|
if (isCropGroup2) {
|
|
8487
8676
|
fc.setActiveObject(activeBeforeSync);
|
|
8488
8677
|
fc.requestRenderAll();
|
|
@@ -8904,6 +9093,7 @@ const PageCanvas = react.forwardRef(
|
|
|
8904
9093
|
}
|
|
8905
9094
|
}
|
|
8906
9095
|
updateCoverLayout(obj);
|
|
9096
|
+
applyEdgeFadeFrameClipPath(obj, element, elementWidth, elementHeight, ct.shape || "rect", ct.rx || 0);
|
|
8907
9097
|
obj.setCoords();
|
|
8908
9098
|
obj.dirty = true;
|
|
8909
9099
|
if (obj.clipPath) {
|
|
@@ -9487,8 +9677,131 @@ const PageCanvas = react.forwardRef(
|
|
|
9487
9677
|
obj.__lastStrokeGradientJson = "null";
|
|
9488
9678
|
}
|
|
9489
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
|
+
};
|
|
9490
9803
|
const loadImageAsync = async (element, placeholder, fc) => {
|
|
9491
|
-
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;
|
|
9492
9805
|
const imageUrl = element.src || element.imageUrl;
|
|
9493
9806
|
if (!imageUrl) return;
|
|
9494
9807
|
const elementId = element.id;
|
|
@@ -9501,7 +9814,9 @@ const PageCanvas = react.forwardRef(
|
|
|
9501
9814
|
const existingImg = ct == null ? void 0 : ct._img;
|
|
9502
9815
|
const existingSrc = placeholder.__imageSrc;
|
|
9503
9816
|
const existingSvgColorMap = placeholder.__svgColorMap || "";
|
|
9504
|
-
|
|
9817
|
+
const existingFadeKey = existingImg && existingImg.__edgeFadeKey || placeholder.__edgeFadeKey || "";
|
|
9818
|
+
const nextFadeKey = edgeFadeKey(element);
|
|
9819
|
+
if (existingImg && existingSrc === imageUrl && existingSvgColorMap === nextSvgColorMap && existingFadeKey === nextFadeKey) {
|
|
9505
9820
|
return placeholder;
|
|
9506
9821
|
}
|
|
9507
9822
|
}
|
|
@@ -9518,6 +9833,22 @@ const PageCanvas = react.forwardRef(
|
|
|
9518
9833
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
9519
9834
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
9520
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
|
+
}
|
|
9521
9852
|
const isHidden = !element.visible;
|
|
9522
9853
|
img.set({
|
|
9523
9854
|
originX: "left",
|
|
@@ -9550,8 +9881,8 @@ const PageCanvas = react.forwardRef(
|
|
|
9550
9881
|
});
|
|
9551
9882
|
img.setCoords();
|
|
9552
9883
|
} else {
|
|
9553
|
-
const imageFit = element.imageFit || ((
|
|
9554
|
-
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");
|
|
9555
9886
|
const needCropGroup2 = imageFit !== "fill" || clipShape && clipShape !== "none";
|
|
9556
9887
|
const imgNaturalWidth = img.width || 1;
|
|
9557
9888
|
const imgNaturalHeight = img.height || 1;
|
|
@@ -9578,7 +9909,7 @@ const PageCanvas = react.forwardRef(
|
|
|
9578
9909
|
if (imageFit === "fill" && !needCropGroup2) {
|
|
9579
9910
|
const finalScaleX = baseScaleX * (element.scaleX ?? 1);
|
|
9580
9911
|
const finalScaleY = baseScaleY * (element.scaleY ?? 1);
|
|
9581
|
-
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) ?? [];
|
|
9582
9913
|
const createPos = pageTreeForCreate.length > 0 ? (() => {
|
|
9583
9914
|
const node = findNodeById(pageTreeForCreate, element.id);
|
|
9584
9915
|
return node ? getAbsoluteBounds(node, pageTreeForCreate) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9623,12 +9954,12 @@ const PageCanvas = react.forwardRef(
|
|
|
9623
9954
|
}
|
|
9624
9955
|
img.__imageSrc = imageUrl;
|
|
9625
9956
|
img.__svgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
9626
|
-
const imageFitFinal = element.imageFit || ((
|
|
9627
|
-
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");
|
|
9628
9959
|
const needCropGroup = imageFitFinal !== "fill" || clipShapeFinal && clipShapeFinal !== "none";
|
|
9629
9960
|
let finalObject = img;
|
|
9630
9961
|
if (needCropGroup) {
|
|
9631
|
-
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) ?? [];
|
|
9632
9963
|
const nodeForSize = pageTreeForCropResolve.length ? findNodeById(pageTreeForCropResolve, element.id) : null;
|
|
9633
9964
|
const w = nodeForSize && isElement(nodeForSize) ? nodeForSize.width : element.width;
|
|
9634
9965
|
const h = nodeForSize && isElement(nodeForSize) ? nodeForSize.height : element.height;
|
|
@@ -9660,16 +9991,16 @@ const PageCanvas = react.forwardRef(
|
|
|
9660
9991
|
let panY = element.cropPanY ?? 0.5;
|
|
9661
9992
|
let zoom2 = element.cropZoom ?? 1;
|
|
9662
9993
|
if (existingCropGroup) {
|
|
9663
|
-
const existingImg = (
|
|
9994
|
+
const existingImg = (_j = existingCropGroup.__cropData) == null ? void 0 : _j._img;
|
|
9664
9995
|
if (existingImg) {
|
|
9665
|
-
panX = ((
|
|
9666
|
-
panY = ((
|
|
9667
|
-
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;
|
|
9668
9999
|
}
|
|
9669
10000
|
}
|
|
9670
10001
|
const isDynamicField = dynamicFieldIds.includes(element.id);
|
|
9671
10002
|
const canBeEvented = isEditorMode || isPreviewMode && isDynamicField;
|
|
9672
|
-
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) ?? [];
|
|
9673
10004
|
const createPosForCrop = pageTreeForCrop.length > 0 ? (() => {
|
|
9674
10005
|
const node = findNodeById(pageTreeForCrop, element.id);
|
|
9675
10006
|
return node ? getAbsoluteBounds(node, pageTreeForCrop) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9720,17 +10051,18 @@ const PageCanvas = react.forwardRef(
|
|
|
9720
10051
|
} else {
|
|
9721
10052
|
installCanvaMaskControls(cropGroup);
|
|
9722
10053
|
}
|
|
9723
|
-
const cropImg = (
|
|
10054
|
+
const cropImg = (_o = cropGroup.__cropData) == null ? void 0 : _o._img;
|
|
9724
10055
|
if (cropImg) {
|
|
9725
10056
|
cropImg._ct = { panX, panY, zoom: zoom2 };
|
|
9726
10057
|
updateCoverLayout(cropGroup);
|
|
9727
10058
|
}
|
|
10059
|
+
applyEdgeFadeFrameClipPath(cropGroup, element, frameW, frameH, shape, rxRatio);
|
|
9728
10060
|
setObjectData(cropGroup, element.id);
|
|
9729
10061
|
cropGroup.__imageElement = cropImg;
|
|
9730
10062
|
cropGroup.__imageSrc = imageUrl;
|
|
9731
10063
|
cropGroup.__svgColorMap = nextSvgColorMap;
|
|
9732
10064
|
if (cropImg && element.imageNaturalWidth == null) {
|
|
9733
|
-
const el = ((
|
|
10065
|
+
const el = ((_p = cropImg.getElement) == null ? void 0 : _p.call(cropImg)) ?? cropImg._element;
|
|
9734
10066
|
const orig = typeof cropImg.getOriginalSize === "function" ? cropImg.getOriginalSize() : null;
|
|
9735
10067
|
const nw = (orig == null ? void 0 : orig.width) ?? (el == null ? void 0 : el.naturalWidth) ?? cropImg.width;
|
|
9736
10068
|
const nh = (orig == null ? void 0 : orig.height) ?? (el == null ? void 0 : el.naturalHeight) ?? cropImg.height;
|
|
@@ -13103,7 +13435,7 @@ function PixldocsPreview(props) {
|
|
|
13103
13435
|
!canvasSettled && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
13104
13436
|
] });
|
|
13105
13437
|
}
|
|
13106
|
-
const PACKAGE_VERSION = "0.5.
|
|
13438
|
+
const PACKAGE_VERSION = "0.5.101";
|
|
13107
13439
|
const roundParityValue = (value) => {
|
|
13108
13440
|
if (typeof value !== "number") return value;
|
|
13109
13441
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -13891,12 +14223,69 @@ class PixldocsRenderer {
|
|
|
13891
14223
|
{ width: canvasWidth, height: canvasHeight },
|
|
13892
14224
|
{ cssOnly: false, backstoreOnly: false }
|
|
13893
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
|
+
}
|
|
13894
14276
|
const rawSvgString = fabricInstance.toSVG();
|
|
13895
14277
|
const svgString = this.normalizeSvgDimensions(
|
|
13896
14278
|
rawSvgString,
|
|
13897
14279
|
canvasWidth,
|
|
13898
14280
|
canvasHeight
|
|
13899
14281
|
);
|
|
14282
|
+
for (const rec of fadeBakeRecords) {
|
|
14283
|
+
try {
|
|
14284
|
+
fabricInstance.remove(rec.replacement);
|
|
14285
|
+
rec.original.excludeFromExport = rec.prevExclude;
|
|
14286
|
+
} catch {
|
|
14287
|
+
}
|
|
14288
|
+
}
|
|
13900
14289
|
fabricInstance.enableRetinaScaling = prevRetina;
|
|
13901
14290
|
fabricInstance.setDimensions(
|
|
13902
14291
|
{ width: prevWidth, height: prevHeight },
|
|
@@ -15233,6 +15622,33 @@ const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradien
|
|
|
15233
15622
|
const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
15234
15623
|
const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
|
|
15235
15624
|
const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
|
|
15625
|
+
function collectFontSpecsFromMarkup(markup) {
|
|
15626
|
+
const specs = /* @__PURE__ */ new Set();
|
|
15627
|
+
const re = /<(?:text|tspan)\b[^>]*>/gi;
|
|
15628
|
+
let match;
|
|
15629
|
+
while ((match = re.exec(markup)) !== null) {
|
|
15630
|
+
const tag = match[0];
|
|
15631
|
+
const get = (attr) => {
|
|
15632
|
+
const m = tag.match(new RegExp(`\\s${attr}\\s*=\\s*"([^"]*)"`, "i"));
|
|
15633
|
+
if (m) return m[1];
|
|
15634
|
+
const styleM = tag.match(/\sstyle\s*=\s*"([^"]*)"/i);
|
|
15635
|
+
if (styleM) {
|
|
15636
|
+
const sm = styleM[1].match(new RegExp(`${attr}\\s*:\\s*([^;]+)`, "i"));
|
|
15637
|
+
if (sm) return sm[1].trim();
|
|
15638
|
+
}
|
|
15639
|
+
return null;
|
|
15640
|
+
};
|
|
15641
|
+
const family = (get("font-family") || "").split(",")[0].replace(/['"]/g, "").trim();
|
|
15642
|
+
if (!family) continue;
|
|
15643
|
+
const weight = get("font-weight") || "400";
|
|
15644
|
+
const style = get("font-style") || "normal";
|
|
15645
|
+
const size = get("font-size") || "16px";
|
|
15646
|
+
const sizePx = /[a-z%]/i.test(size) ? size : `${size}px`;
|
|
15647
|
+
const famSpec = /\s/.test(family) ? `"${family}"` : family;
|
|
15648
|
+
specs.add(`${style} ${weight} ${sizePx} ${famSpec}`);
|
|
15649
|
+
}
|
|
15650
|
+
return Array.from(specs);
|
|
15651
|
+
}
|
|
15236
15652
|
function parseColor(color) {
|
|
15237
15653
|
if (!color) return null;
|
|
15238
15654
|
const raw = color.trim().toLowerCase();
|
|
@@ -16268,7 +16684,7 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
|
|
|
16268
16684
|
}
|
|
16269
16685
|
}
|
|
16270
16686
|
async function rasterizeShadowMarkers(svg) {
|
|
16271
|
-
var _a, _b, _c, _d, _e;
|
|
16687
|
+
var _a, _b, _c, _d, _e, _f;
|
|
16272
16688
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
16273
16689
|
const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
|
|
16274
16690
|
if (markers.length === 0) return;
|
|
@@ -16293,6 +16709,17 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16293
16709
|
continue;
|
|
16294
16710
|
}
|
|
16295
16711
|
const innerXml = Array.from(marker.childNodes).map((n) => n instanceof Element ? new XMLSerializer().serializeToString(n) : "").join("");
|
|
16712
|
+
try {
|
|
16713
|
+
const fontSpecs = collectFontSpecsFromMarkup(innerXml);
|
|
16714
|
+
if (fontSpecs.length > 0 && ((_c = document.fonts) == null ? void 0 : _c.load)) {
|
|
16715
|
+
await Promise.all(
|
|
16716
|
+
fontSpecs.map(
|
|
16717
|
+
(spec) => document.fonts.load(spec).catch(() => void 0)
|
|
16718
|
+
)
|
|
16719
|
+
);
|
|
16720
|
+
}
|
|
16721
|
+
} catch {
|
|
16722
|
+
}
|
|
16296
16723
|
const scale = 2;
|
|
16297
16724
|
const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));
|
|
16298
16725
|
const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
|
|
@@ -16302,7 +16729,7 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16302
16729
|
const miniSvg = `<svg xmlns="${SVG_NS}" xmlns:xlink="${XLINK_NS}" width="${pxW}" height="${pxH}" viewBox="${bx} ${by} ${bw} ${bh}">${styleBlock}<defs><filter id="${filterId}" filterUnits="userSpaceOnUse" x="${bx}" y="${by}" width="${bw}" height="${bh}" color-interpolation-filters="sRGB"><feOffset dx="${ox}" dy="${oy}" result="offsetShadow" /><feGaussianBlur in="offsetShadow" stdDeviation="${stdDev}" /></filter></defs><g filter="url(#${filterId})">${innerXml}</g></svg>`;
|
|
16303
16730
|
const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
|
|
16304
16731
|
if (!dataUrl) {
|
|
16305
|
-
(
|
|
16732
|
+
(_d = marker.parentNode) == null ? void 0 : _d.removeChild(marker);
|
|
16306
16733
|
continue;
|
|
16307
16734
|
}
|
|
16308
16735
|
const img = svg.ownerDocument.createElementNS(SVG_NS, "image");
|
|
@@ -16314,11 +16741,11 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16314
16741
|
img.setAttribute("preserveAspectRatio", "none");
|
|
16315
16742
|
img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
|
|
16316
16743
|
img.setAttribute("href", dataUrl);
|
|
16317
|
-
(
|
|
16744
|
+
(_e = marker.parentNode) == null ? void 0 : _e.replaceChild(img, marker);
|
|
16318
16745
|
} catch (e) {
|
|
16319
16746
|
console.warn("[pdf-export] rasterizeShadowMarkers failed for one marker:", e);
|
|
16320
16747
|
try {
|
|
16321
|
-
(
|
|
16748
|
+
(_f = marker.parentNode) == null ? void 0 : _f.removeChild(marker);
|
|
16322
16749
|
} catch {
|
|
16323
16750
|
}
|
|
16324
16751
|
}
|