@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.js
CHANGED
|
@@ -3663,28 +3663,33 @@ function updateCoverLayout(g) {
|
|
|
3663
3663
|
const hasCustomSvgMask = Boolean(
|
|
3664
3664
|
currentClipPath && (isSvgMaskClipPath(currentClipPath) || isLuminanceMaskClipPath(currentClipPath) || currentClipPath.__svgMask)
|
|
3665
3665
|
);
|
|
3666
|
-
|
|
3666
|
+
const hasEdgeFadeMask = Boolean(currentClipPath && currentClipPath.__edgeFadeMask);
|
|
3667
|
+
if (hasCustomSvgMask || hasEdgeFadeMask) {
|
|
3667
3668
|
if (isSvgMaskClipPath(currentClipPath)) {
|
|
3668
3669
|
syncSvgMaskClipPath(g);
|
|
3669
3670
|
} else if (currentClipPath && typeof currentClipPath.set === "function") {
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3671
|
+
if (hasEdgeFadeMask) {
|
|
3672
|
+
currentClipPath.dirty = true;
|
|
3673
|
+
} else {
|
|
3674
|
+
const baseW = Math.max(1, Number(currentClipPath.width) || frameW);
|
|
3675
|
+
const baseH = Math.max(1, Number(currentClipPath.height) || frameH);
|
|
3676
|
+
currentClipPath.set({
|
|
3677
|
+
left: 0,
|
|
3678
|
+
top: 0,
|
|
3679
|
+
originX: "center",
|
|
3680
|
+
originY: "center",
|
|
3681
|
+
scaleX: frameW / baseW,
|
|
3682
|
+
scaleY: frameH / baseH,
|
|
3683
|
+
selectable: false,
|
|
3684
|
+
evented: false,
|
|
3685
|
+
hasControls: false,
|
|
3686
|
+
hasBorders: false
|
|
3687
|
+
});
|
|
3688
|
+
currentClipPath.absolutePositioned = false;
|
|
3689
|
+
currentClipPath.excludeFromExport = true;
|
|
3690
|
+
currentClipPath.dirty = true;
|
|
3691
|
+
currentClipPath.setCoords();
|
|
3692
|
+
}
|
|
3688
3693
|
}
|
|
3689
3694
|
} else {
|
|
3690
3695
|
const needsNewClipPath = !g.clipPath || shape === "circle" && !(g.clipPath instanceof fabric.Ellipse) || shape !== "circle" && !(g.clipPath instanceof fabric.Rect);
|
|
@@ -4641,10 +4646,12 @@ function exitCropMode(g, commit = true) {
|
|
|
4641
4646
|
g.hasControls = true;
|
|
4642
4647
|
g.borderDashArray = void 0;
|
|
4643
4648
|
installCanvaMaskControls(g);
|
|
4644
|
-
g.borderColor =
|
|
4645
|
-
g.
|
|
4646
|
-
g.
|
|
4649
|
+
g.borderColor = "#4f46e5";
|
|
4650
|
+
g.borderDashArray = void 0;
|
|
4651
|
+
g.cornerColor = "#ffffff";
|
|
4652
|
+
g.cornerStrokeColor = "#4f46e5";
|
|
4647
4653
|
g.cornerStyle = "rect";
|
|
4654
|
+
g.transparentCorners = false;
|
|
4648
4655
|
g[CROP_MODE_FLAG] = false;
|
|
4649
4656
|
g.__cropZoomLastPointer = void 0;
|
|
4650
4657
|
g.__lastPointerForCrop = void 0;
|
|
@@ -5066,10 +5073,14 @@ function applyTextBackground(obj, cfg) {
|
|
|
5066
5073
|
const blur = Math.max(0, Number(shadow.blur ?? 0));
|
|
5067
5074
|
const shadowColor = String(shadow.color);
|
|
5068
5075
|
const pad = Math.max(16, Math.ceil(blur * 4) + Math.ceil(Math.max(Math.abs(ox), Math.abs(oy))) + 8);
|
|
5069
|
-
const
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5076
|
+
const shadowBounds = unionBounds([
|
|
5077
|
+
...rects,
|
|
5078
|
+
computeTextVisualBounds(this, w, h)
|
|
5079
|
+
]);
|
|
5080
|
+
const bx = shadowBounds.x - pad;
|
|
5081
|
+
const by = shadowBounds.y - pad;
|
|
5082
|
+
const bw = shadowBounds.w + pad * 2;
|
|
5083
|
+
const bh = shadowBounds.h + pad * 2;
|
|
5073
5084
|
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)}"`;
|
|
5074
5085
|
const wrapShadow = (markup) => blur <= 0 ? `<g transform="translate(${ox.toFixed(3)} ${oy.toFixed(3)})">${markup}</g>` : `<g class="__pdShadowRaster" ${dataAttrs}>${markup}</g>`;
|
|
5075
5086
|
if (hasBg && (bg == null ? void 0 : bg.shadowAffectsBg) !== false) {
|
|
@@ -5131,6 +5142,51 @@ function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
|
5131
5142
|
parts.push("Z");
|
|
5132
5143
|
return parts.join(" ");
|
|
5133
5144
|
}
|
|
5145
|
+
function unionBounds(bounds) {
|
|
5146
|
+
const valid = bounds.filter((b) => Number.isFinite(b.x) && Number.isFinite(b.y) && b.w > 0 && b.h > 0);
|
|
5147
|
+
if (valid.length === 0) return { x: 0, y: 0, w: 1, h: 1 };
|
|
5148
|
+
const minX = Math.min(...valid.map((b) => b.x));
|
|
5149
|
+
const minY = Math.min(...valid.map((b) => b.y));
|
|
5150
|
+
const maxX = Math.max(...valid.map((b) => b.x + b.w));
|
|
5151
|
+
const maxY = Math.max(...valid.map((b) => b.y + b.h));
|
|
5152
|
+
return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
|
|
5153
|
+
}
|
|
5154
|
+
function computeTextVisualBounds(obj, w, h) {
|
|
5155
|
+
var _a;
|
|
5156
|
+
const lines = (obj == null ? void 0 : obj._textLines) ?? [];
|
|
5157
|
+
if (!lines || lines.length === 0) return { x: -w / 2, y: -h / 2, w, h };
|
|
5158
|
+
const rects = [];
|
|
5159
|
+
const halfW = w / 2;
|
|
5160
|
+
const halfH = h / 2;
|
|
5161
|
+
const lineHeightRatio = Math.max(0.01, Number((obj == null ? void 0 : obj.lineHeight) ?? 1) || 1);
|
|
5162
|
+
let cursorY = -halfH;
|
|
5163
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5164
|
+
let lineW = 0;
|
|
5165
|
+
let lineLeft = 0;
|
|
5166
|
+
let lineH = 0;
|
|
5167
|
+
try {
|
|
5168
|
+
lineW = obj.getLineWidth(i) || 0;
|
|
5169
|
+
} catch {
|
|
5170
|
+
lineW = 0;
|
|
5171
|
+
}
|
|
5172
|
+
try {
|
|
5173
|
+
lineLeft = ((_a = obj._getLineLeftOffset) == null ? void 0 : _a.call(obj, i)) ?? 0;
|
|
5174
|
+
} catch {
|
|
5175
|
+
lineLeft = 0;
|
|
5176
|
+
}
|
|
5177
|
+
try {
|
|
5178
|
+
lineH = obj.getHeightOfLine(i) || 0;
|
|
5179
|
+
} catch {
|
|
5180
|
+
lineH = 0;
|
|
5181
|
+
}
|
|
5182
|
+
const rawSlotH = i === lines.length - 1 ? lineH / lineHeightRatio : lineH;
|
|
5183
|
+
const usedH = cursorY + halfH;
|
|
5184
|
+
const slotH = Math.max(0, Math.min(rawSlotH, h - usedH));
|
|
5185
|
+
if (lineW > 0 && slotH > 0) rects.push({ x: -halfW + lineLeft, y: cursorY, w: lineW, h: slotH });
|
|
5186
|
+
cursorY += slotH;
|
|
5187
|
+
}
|
|
5188
|
+
return unionBounds(rects.length > 0 ? rects : [{ x: -w / 2, y: -h / 2, w, h }]);
|
|
5189
|
+
}
|
|
5134
5190
|
function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
|
|
5135
5191
|
var _a;
|
|
5136
5192
|
if (!fit) {
|
|
@@ -6125,6 +6181,127 @@ function renderSmartElementToDataUri(type, props, width, height) {
|
|
|
6125
6181
|
if (!svg) return null;
|
|
6126
6182
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
6127
6183
|
}
|
|
6184
|
+
function hasEdgeFade(p) {
|
|
6185
|
+
if (!p) return false;
|
|
6186
|
+
const sides = [
|
|
6187
|
+
[p.fadeTopSize, p.fadeTopAmount],
|
|
6188
|
+
[p.fadeRightSize, p.fadeRightAmount],
|
|
6189
|
+
[p.fadeBottomSize, p.fadeBottomAmount],
|
|
6190
|
+
[p.fadeLeftSize, p.fadeLeftAmount]
|
|
6191
|
+
];
|
|
6192
|
+
for (const [size, amount] of sides) {
|
|
6193
|
+
const s = Number(size) || 0;
|
|
6194
|
+
const a = amount == null ? 1 : Number(amount);
|
|
6195
|
+
if (s > 0 && a < 1) return true;
|
|
6196
|
+
}
|
|
6197
|
+
return false;
|
|
6198
|
+
}
|
|
6199
|
+
function edgeFadeKey(p) {
|
|
6200
|
+
if (!hasEdgeFade(p)) return "";
|
|
6201
|
+
return [
|
|
6202
|
+
(p == null ? void 0 : p.fadeTopSize) ?? 0,
|
|
6203
|
+
(p == null ? void 0 : p.fadeTopAmount) ?? 1,
|
|
6204
|
+
(p == null ? void 0 : p.fadeRightSize) ?? 0,
|
|
6205
|
+
(p == null ? void 0 : p.fadeRightAmount) ?? 1,
|
|
6206
|
+
(p == null ? void 0 : p.fadeBottomSize) ?? 0,
|
|
6207
|
+
(p == null ? void 0 : p.fadeBottomAmount) ?? 1,
|
|
6208
|
+
(p == null ? void 0 : p.fadeLeftSize) ?? 0,
|
|
6209
|
+
(p == null ? void 0 : p.fadeLeftAmount) ?? 1,
|
|
6210
|
+
(p == null ? void 0 : p.fadeTopHardness) ?? 1,
|
|
6211
|
+
(p == null ? void 0 : p.fadeRightHardness) ?? 1,
|
|
6212
|
+
(p == null ? void 0 : p.fadeBottomHardness) ?? 1,
|
|
6213
|
+
(p == null ? void 0 : p.fadeLeftHardness) ?? 1
|
|
6214
|
+
].join("|");
|
|
6215
|
+
}
|
|
6216
|
+
function clamp01(n) {
|
|
6217
|
+
if (!Number.isFinite(n)) return 0;
|
|
6218
|
+
return Math.max(0, Math.min(1, n));
|
|
6219
|
+
}
|
|
6220
|
+
function bakeEdgeFade(source, fade) {
|
|
6221
|
+
const w = source.naturalWidth || source.width || 0;
|
|
6222
|
+
const h = source.naturalHeight || source.height || 0;
|
|
6223
|
+
const canvas = document.createElement("canvas");
|
|
6224
|
+
canvas.width = Math.max(1, w);
|
|
6225
|
+
canvas.height = Math.max(1, h);
|
|
6226
|
+
const ctx = canvas.getContext("2d");
|
|
6227
|
+
if (!ctx) return canvas;
|
|
6228
|
+
ctx.drawImage(source, 0, 0, canvas.width, canvas.height);
|
|
6229
|
+
const clampHardness = (n) => {
|
|
6230
|
+
const v = Number(n);
|
|
6231
|
+
if (!Number.isFinite(v) || v <= 0) return 1;
|
|
6232
|
+
return Math.max(0.1, Math.min(5, v));
|
|
6233
|
+
};
|
|
6234
|
+
const sides = [
|
|
6235
|
+
{ side: "top", size: clamp01(fade.fadeTopSize ?? 0), amount: clamp01(fade.fadeTopAmount ?? 1), hardness: clampHardness(fade.fadeTopHardness) },
|
|
6236
|
+
{ side: "right", size: clamp01(fade.fadeRightSize ?? 0), amount: clamp01(fade.fadeRightAmount ?? 1), hardness: clampHardness(fade.fadeRightHardness) },
|
|
6237
|
+
{ side: "bottom", size: clamp01(fade.fadeBottomSize ?? 0), amount: clamp01(fade.fadeBottomAmount ?? 1), hardness: clampHardness(fade.fadeBottomHardness) },
|
|
6238
|
+
{ side: "left", size: clamp01(fade.fadeLeftSize ?? 0), amount: clamp01(fade.fadeLeftAmount ?? 1), hardness: clampHardness(fade.fadeLeftHardness) }
|
|
6239
|
+
];
|
|
6240
|
+
for (const { side, size, amount, hardness } of sides) {
|
|
6241
|
+
if (size <= 0 || amount >= 1) continue;
|
|
6242
|
+
const mask = document.createElement("canvas");
|
|
6243
|
+
mask.width = canvas.width;
|
|
6244
|
+
mask.height = canvas.height;
|
|
6245
|
+
const mctx = mask.getContext("2d");
|
|
6246
|
+
if (!mctx) continue;
|
|
6247
|
+
mctx.fillStyle = "#000";
|
|
6248
|
+
mctx.fillRect(0, 0, mask.width, mask.height);
|
|
6249
|
+
let g;
|
|
6250
|
+
let x = 0, y = 0, rectW = mask.width, rectH = mask.height;
|
|
6251
|
+
const STOPS = 24;
|
|
6252
|
+
const innerAlpha = (t) => {
|
|
6253
|
+
const keepProgress = Math.pow(t, hardness);
|
|
6254
|
+
const erase = (1 - amount) * (1 - keepProgress);
|
|
6255
|
+
return 1 - erase;
|
|
6256
|
+
};
|
|
6257
|
+
const fillStops = (grad, reverse) => {
|
|
6258
|
+
for (let i = 0; i <= STOPS; i++) {
|
|
6259
|
+
const t = i / STOPS;
|
|
6260
|
+
const a = innerAlpha(t);
|
|
6261
|
+
grad.addColorStop(t, `rgba(0,0,0,${a})`);
|
|
6262
|
+
}
|
|
6263
|
+
};
|
|
6264
|
+
if (side === "top") {
|
|
6265
|
+
const band = Math.max(1, Math.round(mask.height * size));
|
|
6266
|
+
g = mctx.createLinearGradient(0, 0, 0, band);
|
|
6267
|
+
fillStops(g);
|
|
6268
|
+
rectH = band;
|
|
6269
|
+
} else if (side === "bottom") {
|
|
6270
|
+
const band = Math.max(1, Math.round(mask.height * size));
|
|
6271
|
+
y = mask.height - band;
|
|
6272
|
+
g = mctx.createLinearGradient(0, mask.height, 0, y);
|
|
6273
|
+
fillStops(g);
|
|
6274
|
+
rectH = band;
|
|
6275
|
+
} else if (side === "left") {
|
|
6276
|
+
const band = Math.max(1, Math.round(mask.width * size));
|
|
6277
|
+
g = mctx.createLinearGradient(0, 0, band, 0);
|
|
6278
|
+
fillStops(g);
|
|
6279
|
+
rectW = band;
|
|
6280
|
+
} else {
|
|
6281
|
+
const band = Math.max(1, Math.round(mask.width * size));
|
|
6282
|
+
x = mask.width - band;
|
|
6283
|
+
g = mctx.createLinearGradient(mask.width, 0, x, 0);
|
|
6284
|
+
fillStops(g);
|
|
6285
|
+
rectW = band;
|
|
6286
|
+
}
|
|
6287
|
+
mctx.fillStyle = g;
|
|
6288
|
+
mctx.fillRect(x, y, rectW, rectH);
|
|
6289
|
+
if (amount <= 1e-3) {
|
|
6290
|
+
const edgePx = Math.min(2, side === "top" || side === "bottom" ? rectH : rectW);
|
|
6291
|
+
mctx.fillStyle = "rgba(0,0,0,0)";
|
|
6292
|
+
mctx.globalCompositeOperation = "copy";
|
|
6293
|
+
if (side === "top") mctx.fillRect(0, 0, mask.width, edgePx);
|
|
6294
|
+
if (side === "bottom") mctx.fillRect(0, mask.height - edgePx, mask.width, edgePx);
|
|
6295
|
+
if (side === "left") mctx.fillRect(0, 0, edgePx, mask.height);
|
|
6296
|
+
if (side === "right") mctx.fillRect(mask.width - edgePx, 0, edgePx, mask.height);
|
|
6297
|
+
mctx.globalCompositeOperation = "source-over";
|
|
6298
|
+
}
|
|
6299
|
+
ctx.globalCompositeOperation = "destination-in";
|
|
6300
|
+
ctx.drawImage(mask, 0, 0);
|
|
6301
|
+
ctx.globalCompositeOperation = "source-over";
|
|
6302
|
+
}
|
|
6303
|
+
return canvas;
|
|
6304
|
+
}
|
|
6128
6305
|
function angleToCoords(angleDeg) {
|
|
6129
6306
|
const rad = angleDeg * Math.PI / 180;
|
|
6130
6307
|
const x1 = 0.5 - Math.sin(rad) * 0.5;
|
|
@@ -7634,6 +7811,10 @@ const PageCanvas = forwardRef(
|
|
|
7634
7811
|
fabricCanvas.on("mouse:dblclick", (e) => {
|
|
7635
7812
|
if (!isActiveRef.current || !allowEditing) return;
|
|
7636
7813
|
let target = e.target;
|
|
7814
|
+
if (!target) {
|
|
7815
|
+
const active = fabricCanvas.getActiveObject();
|
|
7816
|
+
if (active) target = active;
|
|
7817
|
+
}
|
|
7637
7818
|
if (target && target instanceof fabric.Group && target.__cropGroup) {
|
|
7638
7819
|
const ct = target.__cropData;
|
|
7639
7820
|
if ((ct == null ? void 0 : ct._img) && !isCropGroupInCropMode(target)) {
|
|
@@ -7789,7 +7970,7 @@ const PageCanvas = forwardRef(
|
|
|
7789
7970
|
visibilityUpdateInProgressRef.current = false;
|
|
7790
7971
|
}
|
|
7791
7972
|
doSyncRef.current = () => {
|
|
7792
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
7973
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
7793
7974
|
const shouldSkipUpdates2 = syncLockedRef.current || editLockRef.current;
|
|
7794
7975
|
const state = useEditorStore.getState();
|
|
7795
7976
|
const elementsToSync = elements;
|
|
@@ -7950,15 +8131,22 @@ const PageCanvas = forwardRef(
|
|
|
7950
8131
|
const storedImageUrl = existingObj.__imageSrc;
|
|
7951
8132
|
const currentUrlNormalized = currentImageUrl.trim();
|
|
7952
8133
|
const storedUrlNormalized = storedImageUrl ? String(storedImageUrl).trim() : "";
|
|
7953
|
-
const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
7954
|
-
const storedColorMapStr = existingObj.__svgColorMap || "";
|
|
7955
|
-
const colorMapChanged = svgColorMapStr !== storedColorMapStr;
|
|
7956
|
-
const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;
|
|
7957
|
-
const needsReload = sourceUrlChanged || colorMapChanged;
|
|
7958
8134
|
const hasUrl = currentUrlNormalized !== "";
|
|
7959
8135
|
const isCropGroup2 = existingObj instanceof fabric.Group && existingObj.__cropGroup;
|
|
7960
8136
|
const isPlaceholderGroup = isEmptyImagePlaceholderGroup(existingObj);
|
|
7961
8137
|
const isPlaceholder = isPlaceholderGroup || !(existingObj instanceof fabric.FabricImage) || existingObj instanceof fabric.Group && !isCropGroup2;
|
|
8138
|
+
const svgColorMapStr = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
8139
|
+
const storedColorMapStr = existingObj.__svgColorMap || "";
|
|
8140
|
+
const colorMapChanged = svgColorMapStr !== storedColorMapStr;
|
|
8141
|
+
const sourceUrlChanged = currentUrlNormalized !== storedUrlNormalized;
|
|
8142
|
+
const newFadeKey = edgeFadeKey(element);
|
|
8143
|
+
const oldFadeKey = isCropGroup2 ? existingObj.__edgeFadeInputKey || "" : existingObj.__edgeFadeKey || "";
|
|
8144
|
+
const innerImg = (_e = existingObj == null ? void 0 : existingObj.__cropData) == null ? void 0 : _e._img;
|
|
8145
|
+
const innerOldKey = isCropGroup2 ? oldFadeKey : innerImg ? innerImg.__edgeFadeKey || "" : oldFadeKey;
|
|
8146
|
+
const cropFadeRendererMissing = isCropGroup2 && Boolean(newFadeKey) && !existingObj.__edgeFadeRenderConfig;
|
|
8147
|
+
const fadeKeyChanged = newFadeKey !== oldFadeKey || newFadeKey !== innerOldKey || cropFadeRendererMissing;
|
|
8148
|
+
const needsReload = sourceUrlChanged || colorMapChanged || fadeKeyChanged && !isCropGroup2;
|
|
8149
|
+
const needsCropGroupFadeUpdate = isCropGroup2 && fadeKeyChanged;
|
|
7962
8150
|
const hadUrlBefore = storedImageUrl && String(storedImageUrl).trim() !== "";
|
|
7963
8151
|
if (!hasUrl && hadUrlBefore) {
|
|
7964
8152
|
const placeholder = isCropGroup2 ? createImagePlaceholderForGroup(element) : createImagePlaceholder(element);
|
|
@@ -7974,16 +8162,16 @@ const PageCanvas = forwardRef(
|
|
|
7974
8162
|
fc.requestRenderAll();
|
|
7975
8163
|
continue;
|
|
7976
8164
|
}
|
|
7977
|
-
const imageFitForReplace = element.imageFit || ((
|
|
7978
|
-
const clipShapeForReplace = element.clipShape ?? ((
|
|
8165
|
+
const imageFitForReplace = element.imageFit || ((_f = element.style) == null ? void 0 : _f.imageFit) || "cover";
|
|
8166
|
+
const clipShapeForReplace = element.clipShape ?? ((_g = element.style) == null ? void 0 : _g.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
7979
8167
|
const needCropGroupForElement = imageFitForReplace !== "fill" || clipShapeForReplace && clipShapeForReplace !== "none";
|
|
7980
8168
|
const plainImageNeedsCropGroup = hasUrl && !isCropGroup2 && existingObj instanceof fabric.FabricImage && needCropGroupForElement;
|
|
7981
|
-
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup)) {
|
|
8169
|
+
if (hasUrl && (needsReload || isPlaceholder || plainImageNeedsCropGroup || needsCropGroupFadeUpdate)) {
|
|
7982
8170
|
if (needsReload && !isBeingTransformed && (!wasJustModified || sourceUrlChanged)) {
|
|
7983
8171
|
loadImageAsync(element, existingObj, fc);
|
|
7984
8172
|
} else if (plainImageNeedsCropGroup) {
|
|
7985
8173
|
loadImageAsync(element, existingObj, fc);
|
|
7986
|
-
} else if (!needsReload && isCropGroup2) {
|
|
8174
|
+
} else if ((!needsReload || needsCropGroupFadeUpdate) && isCropGroup2) {
|
|
7987
8175
|
const ct = existingObj.__cropData;
|
|
7988
8176
|
if (ct) {
|
|
7989
8177
|
const resolvedCrop = pageTree.length > 0 ? getNodeBounds(element, pageTree) : { width: typeof element.width === "number" ? element.width : 200, height: typeof element.height === "number" ? element.height : 50 };
|
|
@@ -8080,6 +8268,7 @@ const PageCanvas = forwardRef(
|
|
|
8080
8268
|
}
|
|
8081
8269
|
}
|
|
8082
8270
|
updateCoverLayout(existingObj);
|
|
8271
|
+
applyEdgeFadeFrameClipPath(existingObj, element, ct.frameW, ct.frameH, ct.shape || "rect", ct.rx || 0);
|
|
8083
8272
|
if (allowEditing) {
|
|
8084
8273
|
installCanvaMaskControls(existingObj);
|
|
8085
8274
|
} else {
|
|
@@ -8389,7 +8578,7 @@ const PageCanvas = forwardRef(
|
|
|
8389
8578
|
fc.add(placeholder);
|
|
8390
8579
|
fc.bringObjectToFront(placeholder);
|
|
8391
8580
|
const activeObj = fc.getActiveObject();
|
|
8392
|
-
if (activeObj && (((
|
|
8581
|
+
if (activeObj && (((_h = activeObj._ct) == null ? void 0 : _h.isCropGroup) || activeObj.__cropGroup)) {
|
|
8393
8582
|
fc.setActiveObject(activeObj);
|
|
8394
8583
|
}
|
|
8395
8584
|
placeholder.dirty = true;
|
|
@@ -8429,7 +8618,7 @@ const PageCanvas = forwardRef(
|
|
|
8429
8618
|
fc.add(obj);
|
|
8430
8619
|
fc.bringObjectToFront(obj);
|
|
8431
8620
|
const activeObj = fc.getActiveObject();
|
|
8432
|
-
if (activeObj && (((
|
|
8621
|
+
if (activeObj && (((_i = activeObj._ct) == null ? void 0 : _i.isCropGroup) || activeObj.__cropGroup)) {
|
|
8433
8622
|
fc.setActiveObject(activeObj);
|
|
8434
8623
|
}
|
|
8435
8624
|
obj.dirty = true;
|
|
@@ -8463,7 +8652,7 @@ const PageCanvas = forwardRef(
|
|
|
8463
8652
|
isRebuildingRef.current = false;
|
|
8464
8653
|
fc.requestRenderAll();
|
|
8465
8654
|
if (activeBeforeSync && fc.getObjects().includes(activeBeforeSync)) {
|
|
8466
|
-
const isCropGroup2 = ((
|
|
8655
|
+
const isCropGroup2 = ((_j = activeBeforeSync._ct) == null ? void 0 : _j.isCropGroup) || activeBeforeSync.__cropGroup;
|
|
8467
8656
|
if (isCropGroup2) {
|
|
8468
8657
|
fc.setActiveObject(activeBeforeSync);
|
|
8469
8658
|
fc.requestRenderAll();
|
|
@@ -8885,6 +9074,7 @@ const PageCanvas = forwardRef(
|
|
|
8885
9074
|
}
|
|
8886
9075
|
}
|
|
8887
9076
|
updateCoverLayout(obj);
|
|
9077
|
+
applyEdgeFadeFrameClipPath(obj, element, elementWidth, elementHeight, ct.shape || "rect", ct.rx || 0);
|
|
8888
9078
|
obj.setCoords();
|
|
8889
9079
|
obj.dirty = true;
|
|
8890
9080
|
if (obj.clipPath) {
|
|
@@ -9468,8 +9658,131 @@ const PageCanvas = forwardRef(
|
|
|
9468
9658
|
obj.__lastStrokeGradientJson = "null";
|
|
9469
9659
|
}
|
|
9470
9660
|
};
|
|
9661
|
+
const clamp2 = (v, min, max) => {
|
|
9662
|
+
return Math.max(min, Math.min(max, v));
|
|
9663
|
+
};
|
|
9664
|
+
const applyEdgeFadeFrameClipPath = (group, element, frameW, frameH, shape, rxRatio) => {
|
|
9665
|
+
var _a, _b, _c;
|
|
9666
|
+
const fadeElement = element;
|
|
9667
|
+
const fadeGroup = group;
|
|
9668
|
+
const inputKey = edgeFadeKey(fadeElement);
|
|
9669
|
+
const hasFade = hasEdgeFade(fadeElement);
|
|
9670
|
+
if (!fadeGroup.__edgeFadeOriginalDrawObject) {
|
|
9671
|
+
fadeGroup.__edgeFadeOriginalDrawObject = group.drawObject;
|
|
9672
|
+
}
|
|
9673
|
+
if (hasFade) {
|
|
9674
|
+
if ((_a = group.clipPath) == null ? void 0 : _a.__edgeFadeMask) {
|
|
9675
|
+
group.clipPath = void 0;
|
|
9676
|
+
updateCoverLayout(group);
|
|
9677
|
+
}
|
|
9678
|
+
fadeGroup.__edgeFadeRenderConfig = {
|
|
9679
|
+
key: `${inputKey}|${Math.round(frameW)}|${Math.round(frameH)}|${shape}|${rxRatio}`,
|
|
9680
|
+
frameW: Math.max(1, Number(frameW) || 1),
|
|
9681
|
+
frameH: Math.max(1, Number(frameH) || 1),
|
|
9682
|
+
topSize: clamp2(Number(fadeElement.fadeTopSize) || 0, 0, 1),
|
|
9683
|
+
topAmount: clamp2(fadeElement.fadeTopAmount == null ? 1 : Number(fadeElement.fadeTopAmount), 0, 1),
|
|
9684
|
+
rightSize: clamp2(Number(fadeElement.fadeRightSize) || 0, 0, 1),
|
|
9685
|
+
rightAmount: clamp2(fadeElement.fadeRightAmount == null ? 1 : Number(fadeElement.fadeRightAmount), 0, 1),
|
|
9686
|
+
bottomSize: clamp2(Number(fadeElement.fadeBottomSize) || 0, 0, 1),
|
|
9687
|
+
bottomAmount: clamp2(fadeElement.fadeBottomAmount == null ? 1 : Number(fadeElement.fadeBottomAmount), 0, 1),
|
|
9688
|
+
leftSize: clamp2(Number(fadeElement.fadeLeftSize) || 0, 0, 1),
|
|
9689
|
+
leftAmount: clamp2(fadeElement.fadeLeftAmount == null ? 1 : Number(fadeElement.fadeLeftAmount), 0, 1),
|
|
9690
|
+
topHardness: clamp2(Number(fadeElement.fadeTopHardness) || 1, 0.1, 5),
|
|
9691
|
+
rightHardness: clamp2(Number(fadeElement.fadeRightHardness) || 1, 0.1, 5),
|
|
9692
|
+
bottomHardness: clamp2(Number(fadeElement.fadeBottomHardness) || 1, 0.1, 5),
|
|
9693
|
+
leftHardness: clamp2(Number(fadeElement.fadeLeftHardness) || 1, 0.1, 5)
|
|
9694
|
+
};
|
|
9695
|
+
const originalDrawObject = fadeGroup.__edgeFadeOriginalDrawObject ?? group.drawObject;
|
|
9696
|
+
group.drawObject = function edgeFadeDrawObject(ctx, forClipping, context) {
|
|
9697
|
+
originalDrawObject.call(this, ctx, forClipping, context);
|
|
9698
|
+
if (forClipping) return;
|
|
9699
|
+
const cfg = this.__edgeFadeRenderConfig;
|
|
9700
|
+
if (!cfg) return;
|
|
9701
|
+
const liveW = Number(this.width) || 0;
|
|
9702
|
+
const liveH = Number(this.height) || 0;
|
|
9703
|
+
const w = liveW > 0 ? liveW : cfg.frameW;
|
|
9704
|
+
const h = liveH > 0 ? liveH : cfg.frameH;
|
|
9705
|
+
const x = -w / 2;
|
|
9706
|
+
const y = -h / 2;
|
|
9707
|
+
const paintBand = (side, size, amount, hardness) => {
|
|
9708
|
+
if (size <= 0 || amount >= 1) return;
|
|
9709
|
+
ctx.save();
|
|
9710
|
+
ctx.globalCompositeOperation = "destination-out";
|
|
9711
|
+
let gradient;
|
|
9712
|
+
const eraseAtEdge = 1 - amount;
|
|
9713
|
+
const STOPS = 24;
|
|
9714
|
+
const addStops = (g) => {
|
|
9715
|
+
for (let i = 0; i <= STOPS; i++) {
|
|
9716
|
+
const t = i / STOPS;
|
|
9717
|
+
const keepProgress = Math.pow(t, hardness);
|
|
9718
|
+
const a = eraseAtEdge * (1 - keepProgress);
|
|
9719
|
+
g.addColorStop(t, `rgba(0,0,0,${a})`);
|
|
9720
|
+
}
|
|
9721
|
+
};
|
|
9722
|
+
if (side === "top") {
|
|
9723
|
+
const band = Math.max(1, h * size);
|
|
9724
|
+
gradient = ctx.createLinearGradient(0, y, 0, y + band);
|
|
9725
|
+
addStops(gradient);
|
|
9726
|
+
ctx.fillStyle = gradient;
|
|
9727
|
+
ctx.fillRect(x, y, w, band);
|
|
9728
|
+
if (amount <= 1e-3) ctx.fillRect(x, y, w, Math.min(2, band));
|
|
9729
|
+
} else if (side === "bottom") {
|
|
9730
|
+
const band = Math.max(1, h * size);
|
|
9731
|
+
gradient = ctx.createLinearGradient(0, y + h, 0, y + h - band);
|
|
9732
|
+
addStops(gradient);
|
|
9733
|
+
ctx.fillStyle = gradient;
|
|
9734
|
+
ctx.fillRect(x, y + h - band, w, band);
|
|
9735
|
+
if (amount <= 1e-3) ctx.fillRect(x, y + h - Math.min(2, band), w, Math.min(2, band));
|
|
9736
|
+
} else if (side === "left") {
|
|
9737
|
+
const band = Math.max(1, w * size);
|
|
9738
|
+
gradient = ctx.createLinearGradient(x, 0, x + band, 0);
|
|
9739
|
+
addStops(gradient);
|
|
9740
|
+
ctx.fillStyle = gradient;
|
|
9741
|
+
ctx.fillRect(x, y, band, h);
|
|
9742
|
+
if (amount <= 1e-3) ctx.fillRect(x, y, Math.min(2, band), h);
|
|
9743
|
+
} else {
|
|
9744
|
+
const band = Math.max(1, w * size);
|
|
9745
|
+
gradient = ctx.createLinearGradient(x + w, 0, x + w - band, 0);
|
|
9746
|
+
addStops(gradient);
|
|
9747
|
+
ctx.fillStyle = gradient;
|
|
9748
|
+
ctx.fillRect(x + w - band, y, band, h);
|
|
9749
|
+
if (amount <= 1e-3) ctx.fillRect(x + w - Math.min(2, band), y, Math.min(2, band), h);
|
|
9750
|
+
}
|
|
9751
|
+
ctx.restore();
|
|
9752
|
+
};
|
|
9753
|
+
paintBand("top", cfg.topSize, cfg.topAmount, cfg.topHardness);
|
|
9754
|
+
paintBand("right", cfg.rightSize, cfg.rightAmount, cfg.rightHardness);
|
|
9755
|
+
paintBand("bottom", cfg.bottomSize, cfg.bottomAmount, cfg.bottomHardness);
|
|
9756
|
+
paintBand("left", cfg.leftSize, cfg.leftAmount, cfg.leftHardness);
|
|
9757
|
+
};
|
|
9758
|
+
group.set({ objectCaching: true, noScaleCache: false });
|
|
9759
|
+
fadeGroup.__edgeFadeKey = fadeGroup.__edgeFadeRenderConfig.key;
|
|
9760
|
+
fadeGroup.__edgeFadeInputKey = inputKey;
|
|
9761
|
+
} else {
|
|
9762
|
+
if (fadeGroup.__edgeFadeOriginalDrawObject) {
|
|
9763
|
+
group.drawObject = fadeGroup.__edgeFadeOriginalDrawObject;
|
|
9764
|
+
}
|
|
9765
|
+
delete fadeGroup.__edgeFadeRenderConfig;
|
|
9766
|
+
delete fadeGroup.__edgeFadeKey;
|
|
9767
|
+
delete fadeGroup.__edgeFadeInputKey;
|
|
9768
|
+
if ((_b = group.clipPath) == null ? void 0 : _b.__edgeFadeMask) {
|
|
9769
|
+
group.clipPath = void 0;
|
|
9770
|
+
updateCoverLayout(group);
|
|
9771
|
+
}
|
|
9772
|
+
}
|
|
9773
|
+
if (group.clipPath) {
|
|
9774
|
+
group.clipPath.dirty = true;
|
|
9775
|
+
group.clipPath.setCoords();
|
|
9776
|
+
}
|
|
9777
|
+
fadeGroup.dirty = true;
|
|
9778
|
+
const children = group.getObjects();
|
|
9779
|
+
children.forEach((child) => {
|
|
9780
|
+
child.dirty = true;
|
|
9781
|
+
});
|
|
9782
|
+
(_c = group.canvas) == null ? void 0 : _c.requestRenderAll();
|
|
9783
|
+
};
|
|
9471
9784
|
const loadImageAsync = async (element, placeholder, fc) => {
|
|
9472
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
9785
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
9473
9786
|
const imageUrl = element.src || element.imageUrl;
|
|
9474
9787
|
if (!imageUrl) return;
|
|
9475
9788
|
const elementId = element.id;
|
|
@@ -9482,7 +9795,9 @@ const PageCanvas = forwardRef(
|
|
|
9482
9795
|
const existingImg = ct == null ? void 0 : ct._img;
|
|
9483
9796
|
const existingSrc = placeholder.__imageSrc;
|
|
9484
9797
|
const existingSvgColorMap = placeholder.__svgColorMap || "";
|
|
9485
|
-
|
|
9798
|
+
const existingFadeKey = existingImg && existingImg.__edgeFadeKey || placeholder.__edgeFadeKey || "";
|
|
9799
|
+
const nextFadeKey = edgeFadeKey(element);
|
|
9800
|
+
if (existingImg && existingSrc === imageUrl && existingSvgColorMap === nextSvgColorMap && existingFadeKey === nextFadeKey) {
|
|
9486
9801
|
return placeholder;
|
|
9487
9802
|
}
|
|
9488
9803
|
}
|
|
@@ -9499,6 +9814,22 @@ const PageCanvas = forwardRef(
|
|
|
9499
9814
|
if (!fabricRef.current || !isLatestRequest()) return;
|
|
9500
9815
|
await normalizeSvgImageDimensions(img, imageUrl, element.sourceFormat);
|
|
9501
9816
|
if (!isLatestRequest()) return;
|
|
9817
|
+
const imageFitForFade = element.imageFit || ((_a = element.style) == null ? void 0 : _a.imageFit) || "cover";
|
|
9818
|
+
const clipShapeForFade = element.clipShape ?? ((_b = element.style) == null ? void 0 : _b.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9819
|
+
const willUseCropGroupForFade = imageFitForFade !== "fill" || clipShapeForFade && clipShapeForFade !== "none";
|
|
9820
|
+
try {
|
|
9821
|
+
if (hasEdgeFade(element) && !willUseCropGroupForFade) {
|
|
9822
|
+
const srcEl = (_c = img.getElement) == null ? void 0 : _c.call(img);
|
|
9823
|
+
if (srcEl) {
|
|
9824
|
+
const baked = bakeEdgeFade(srcEl, element);
|
|
9825
|
+
img.setElement(baked);
|
|
9826
|
+
img.__edgeFadeKey = edgeFadeKey(element);
|
|
9827
|
+
img.dirty = true;
|
|
9828
|
+
}
|
|
9829
|
+
}
|
|
9830
|
+
} catch (e) {
|
|
9831
|
+
console.warn("[edgeFade] bake failed:", e);
|
|
9832
|
+
}
|
|
9502
9833
|
const isHidden = !element.visible;
|
|
9503
9834
|
img.set({
|
|
9504
9835
|
originX: "left",
|
|
@@ -9531,8 +9862,8 @@ const PageCanvas = forwardRef(
|
|
|
9531
9862
|
});
|
|
9532
9863
|
img.setCoords();
|
|
9533
9864
|
} else {
|
|
9534
|
-
const imageFit = element.imageFit || ((
|
|
9535
|
-
const clipShape = element.clipShape ?? ((
|
|
9865
|
+
const imageFit = element.imageFit || ((_d = element.style) == null ? void 0 : _d.imageFit) || "cover";
|
|
9866
|
+
const clipShape = element.clipShape ?? ((_e = element.style) == null ? void 0 : _e.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9536
9867
|
const needCropGroup2 = imageFit !== "fill" || clipShape && clipShape !== "none";
|
|
9537
9868
|
const imgNaturalWidth = img.width || 1;
|
|
9538
9869
|
const imgNaturalHeight = img.height || 1;
|
|
@@ -9559,7 +9890,7 @@ const PageCanvas = forwardRef(
|
|
|
9559
9890
|
if (imageFit === "fill" && !needCropGroup2) {
|
|
9560
9891
|
const finalScaleX = baseScaleX * (element.scaleX ?? 1);
|
|
9561
9892
|
const finalScaleY = baseScaleY * (element.scaleY ?? 1);
|
|
9562
|
-
const pageTreeForCreate = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
9893
|
+
const pageTreeForCreate = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_f = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _f.children) ?? [];
|
|
9563
9894
|
const createPos = pageTreeForCreate.length > 0 ? (() => {
|
|
9564
9895
|
const node = findNodeById(pageTreeForCreate, element.id);
|
|
9565
9896
|
return node ? getAbsoluteBounds(node, pageTreeForCreate) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9604,12 +9935,12 @@ const PageCanvas = forwardRef(
|
|
|
9604
9935
|
}
|
|
9605
9936
|
img.__imageSrc = imageUrl;
|
|
9606
9937
|
img.__svgColorMap = element.svgColorMap ? JSON.stringify(element.svgColorMap) : "";
|
|
9607
|
-
const imageFitFinal = element.imageFit || ((
|
|
9608
|
-
const clipShapeFinal = element.clipShape ?? ((
|
|
9938
|
+
const imageFitFinal = element.imageFit || ((_g = element.style) == null ? void 0 : _g.imageFit) || "cover";
|
|
9939
|
+
const clipShapeFinal = element.clipShape ?? ((_h = element.style) == null ? void 0 : _h.imageFrameShape) ?? (isPreviewMode ? "rectangle" : "none");
|
|
9609
9940
|
const needCropGroup = imageFitFinal !== "fill" || clipShapeFinal && clipShapeFinal !== "none";
|
|
9610
9941
|
let finalObject = img;
|
|
9611
9942
|
if (needCropGroup) {
|
|
9612
|
-
const pageTreeForCropResolve = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
9943
|
+
const pageTreeForCropResolve = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_i = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _i.children) ?? [];
|
|
9613
9944
|
const nodeForSize = pageTreeForCropResolve.length ? findNodeById(pageTreeForCropResolve, element.id) : null;
|
|
9614
9945
|
const w = nodeForSize && isElement(nodeForSize) ? nodeForSize.width : element.width;
|
|
9615
9946
|
const h = nodeForSize && isElement(nodeForSize) ? nodeForSize.height : element.height;
|
|
@@ -9641,16 +9972,16 @@ const PageCanvas = forwardRef(
|
|
|
9641
9972
|
let panY = element.cropPanY ?? 0.5;
|
|
9642
9973
|
let zoom2 = element.cropZoom ?? 1;
|
|
9643
9974
|
if (existingCropGroup) {
|
|
9644
|
-
const existingImg = (
|
|
9975
|
+
const existingImg = (_j = existingCropGroup.__cropData) == null ? void 0 : _j._img;
|
|
9645
9976
|
if (existingImg) {
|
|
9646
|
-
panX = ((
|
|
9647
|
-
panY = ((
|
|
9648
|
-
zoom2 = ((
|
|
9977
|
+
panX = ((_k = existingImg._ct) == null ? void 0 : _k.panX) ?? existingImg.__panX ?? panX;
|
|
9978
|
+
panY = ((_l = existingImg._ct) == null ? void 0 : _l.panY) ?? existingImg.__panY ?? panY;
|
|
9979
|
+
zoom2 = ((_m = existingImg._ct) == null ? void 0 : _m.zoom) ?? zoom2;
|
|
9649
9980
|
}
|
|
9650
9981
|
}
|
|
9651
9982
|
const isDynamicField = dynamicFieldIds.includes(element.id);
|
|
9652
9983
|
const canBeEvented = isEditorMode || isPreviewMode && isDynamicField;
|
|
9653
|
-
const pageTreeForCrop = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (
|
|
9984
|
+
const pageTreeForCrop = ((pageChildren == null ? void 0 : pageChildren.length) ? pageChildren : (_n = useEditorStore.getState().canvas.pages.find((p) => p.id === pageId)) == null ? void 0 : _n.children) ?? [];
|
|
9654
9985
|
const createPosForCrop = pageTreeForCrop.length > 0 ? (() => {
|
|
9655
9986
|
const node = findNodeById(pageTreeForCrop, element.id);
|
|
9656
9987
|
return node ? getAbsoluteBounds(node, pageTreeForCrop) : { left: element.left ?? 0, top: element.top ?? 0 };
|
|
@@ -9701,17 +10032,18 @@ const PageCanvas = forwardRef(
|
|
|
9701
10032
|
} else {
|
|
9702
10033
|
installCanvaMaskControls(cropGroup);
|
|
9703
10034
|
}
|
|
9704
|
-
const cropImg = (
|
|
10035
|
+
const cropImg = (_o = cropGroup.__cropData) == null ? void 0 : _o._img;
|
|
9705
10036
|
if (cropImg) {
|
|
9706
10037
|
cropImg._ct = { panX, panY, zoom: zoom2 };
|
|
9707
10038
|
updateCoverLayout(cropGroup);
|
|
9708
10039
|
}
|
|
10040
|
+
applyEdgeFadeFrameClipPath(cropGroup, element, frameW, frameH, shape, rxRatio);
|
|
9709
10041
|
setObjectData(cropGroup, element.id);
|
|
9710
10042
|
cropGroup.__imageElement = cropImg;
|
|
9711
10043
|
cropGroup.__imageSrc = imageUrl;
|
|
9712
10044
|
cropGroup.__svgColorMap = nextSvgColorMap;
|
|
9713
10045
|
if (cropImg && element.imageNaturalWidth == null) {
|
|
9714
|
-
const el = ((
|
|
10046
|
+
const el = ((_p = cropImg.getElement) == null ? void 0 : _p.call(cropImg)) ?? cropImg._element;
|
|
9715
10047
|
const orig = typeof cropImg.getOriginalSize === "function" ? cropImg.getOriginalSize() : null;
|
|
9716
10048
|
const nw = (orig == null ? void 0 : orig.width) ?? (el == null ? void 0 : el.naturalWidth) ?? cropImg.width;
|
|
9717
10049
|
const nh = (orig == null ? void 0 : orig.height) ?? (el == null ? void 0 : el.naturalHeight) ?? cropImg.height;
|
|
@@ -13084,7 +13416,7 @@ function PixldocsPreview(props) {
|
|
|
13084
13416
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
13085
13417
|
] });
|
|
13086
13418
|
}
|
|
13087
|
-
const PACKAGE_VERSION = "0.5.
|
|
13419
|
+
const PACKAGE_VERSION = "0.5.101";
|
|
13088
13420
|
const roundParityValue = (value) => {
|
|
13089
13421
|
if (typeof value !== "number") return value;
|
|
13090
13422
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -13872,12 +14204,69 @@ class PixldocsRenderer {
|
|
|
13872
14204
|
{ width: canvasWidth, height: canvasHeight },
|
|
13873
14205
|
{ cssOnly: false, backstoreOnly: false }
|
|
13874
14206
|
);
|
|
14207
|
+
const fadeBakeRecords = [];
|
|
14208
|
+
try {
|
|
14209
|
+
const objs = fabricInstance.getObjects().slice();
|
|
14210
|
+
for (const obj of objs) {
|
|
14211
|
+
const isFadedCropGroup = obj instanceof fabric.Group && (Boolean(obj.__edgeFadeRenderConfig) || Boolean(obj.__edgeFadeKey) || Boolean(obj.__edgeFadeInputKey));
|
|
14212
|
+
if (!isFadedCropGroup) continue;
|
|
14213
|
+
try {
|
|
14214
|
+
const baked = obj.toCanvasElement({
|
|
14215
|
+
multiplier: 2,
|
|
14216
|
+
enableRetinaScaling: false
|
|
14217
|
+
});
|
|
14218
|
+
const rect = obj.getBoundingRect();
|
|
14219
|
+
const replacement = new fabric.FabricImage(baked, {
|
|
14220
|
+
left: rect.left,
|
|
14221
|
+
top: rect.top,
|
|
14222
|
+
originX: "left",
|
|
14223
|
+
originY: "top",
|
|
14224
|
+
scaleX: rect.width / baked.width,
|
|
14225
|
+
scaleY: rect.height / baked.height,
|
|
14226
|
+
selectable: false,
|
|
14227
|
+
evented: false,
|
|
14228
|
+
objectCaching: false
|
|
14229
|
+
});
|
|
14230
|
+
const insertIndex = fabricInstance._objects.indexOf(obj);
|
|
14231
|
+
const prevExclude = obj.excludeFromExport;
|
|
14232
|
+
obj.excludeFromExport = true;
|
|
14233
|
+
if (insertIndex >= 0) {
|
|
14234
|
+
fabricInstance.insertAt(insertIndex + 1, replacement);
|
|
14235
|
+
} else {
|
|
14236
|
+
fabricInstance.add(replacement);
|
|
14237
|
+
}
|
|
14238
|
+
fadeBakeRecords.push({
|
|
14239
|
+
original: obj,
|
|
14240
|
+
replacement,
|
|
14241
|
+
prevExclude,
|
|
14242
|
+
insertIndex
|
|
14243
|
+
});
|
|
14244
|
+
} catch (bakeErr) {
|
|
14245
|
+
console.warn("[canvas-renderer][edgeFade] bake-for-svg failed:", bakeErr);
|
|
14246
|
+
}
|
|
14247
|
+
}
|
|
14248
|
+
if (fadeBakeRecords.length) {
|
|
14249
|
+
fabricInstance.renderAll();
|
|
14250
|
+
console.log(
|
|
14251
|
+
`[canvas-renderer][edgeFade] baked ${fadeBakeRecords.length} faded object(s) for SVG capture`
|
|
14252
|
+
);
|
|
14253
|
+
}
|
|
14254
|
+
} catch (e) {
|
|
14255
|
+
console.warn("[canvas-renderer][edgeFade] bake pass failed:", e);
|
|
14256
|
+
}
|
|
13875
14257
|
const rawSvgString = fabricInstance.toSVG();
|
|
13876
14258
|
const svgString = this.normalizeSvgDimensions(
|
|
13877
14259
|
rawSvgString,
|
|
13878
14260
|
canvasWidth,
|
|
13879
14261
|
canvasHeight
|
|
13880
14262
|
);
|
|
14263
|
+
for (const rec of fadeBakeRecords) {
|
|
14264
|
+
try {
|
|
14265
|
+
fabricInstance.remove(rec.replacement);
|
|
14266
|
+
rec.original.excludeFromExport = rec.prevExclude;
|
|
14267
|
+
} catch {
|
|
14268
|
+
}
|
|
14269
|
+
}
|
|
13881
14270
|
fabricInstance.enableRetinaScaling = prevRetina;
|
|
13882
14271
|
fabricInstance.setDimensions(
|
|
13883
14272
|
{ width: prevWidth, height: prevHeight },
|
|
@@ -15214,6 +15603,33 @@ const GRADIENT_ATTRS_LINEAR = ["x1", "y1", "x2", "y2", "gradientUnits", "gradien
|
|
|
15214
15603
|
const GRADIENT_ATTRS_RADIAL = ["cx", "cy", "r", "fx", "fy", "gradientUnits", "gradientTransform", "spreadMethod"];
|
|
15215
15604
|
const URL_GRADIENT_RE = /^\s*url\s*\(\s*(['"]?)([^)]+?)\1\s*\)/i;
|
|
15216
15605
|
const SHADOW_RASTER_ALPHA_COMPENSATION = 0.84;
|
|
15606
|
+
function collectFontSpecsFromMarkup(markup) {
|
|
15607
|
+
const specs = /* @__PURE__ */ new Set();
|
|
15608
|
+
const re = /<(?:text|tspan)\b[^>]*>/gi;
|
|
15609
|
+
let match;
|
|
15610
|
+
while ((match = re.exec(markup)) !== null) {
|
|
15611
|
+
const tag = match[0];
|
|
15612
|
+
const get = (attr) => {
|
|
15613
|
+
const m = tag.match(new RegExp(`\\s${attr}\\s*=\\s*"([^"]*)"`, "i"));
|
|
15614
|
+
if (m) return m[1];
|
|
15615
|
+
const styleM = tag.match(/\sstyle\s*=\s*"([^"]*)"/i);
|
|
15616
|
+
if (styleM) {
|
|
15617
|
+
const sm = styleM[1].match(new RegExp(`${attr}\\s*:\\s*([^;]+)`, "i"));
|
|
15618
|
+
if (sm) return sm[1].trim();
|
|
15619
|
+
}
|
|
15620
|
+
return null;
|
|
15621
|
+
};
|
|
15622
|
+
const family = (get("font-family") || "").split(",")[0].replace(/['"]/g, "").trim();
|
|
15623
|
+
if (!family) continue;
|
|
15624
|
+
const weight = get("font-weight") || "400";
|
|
15625
|
+
const style = get("font-style") || "normal";
|
|
15626
|
+
const size = get("font-size") || "16px";
|
|
15627
|
+
const sizePx = /[a-z%]/i.test(size) ? size : `${size}px`;
|
|
15628
|
+
const famSpec = /\s/.test(family) ? `"${family}"` : family;
|
|
15629
|
+
specs.add(`${style} ${weight} ${sizePx} ${famSpec}`);
|
|
15630
|
+
}
|
|
15631
|
+
return Array.from(specs);
|
|
15632
|
+
}
|
|
15217
15633
|
function parseColor(color) {
|
|
15218
15634
|
if (!color) return null;
|
|
15219
15635
|
const raw = color.trim().toLowerCase();
|
|
@@ -16249,7 +16665,7 @@ async function convertSvgTextDecorationsToLinesString(svgStr) {
|
|
|
16249
16665
|
}
|
|
16250
16666
|
}
|
|
16251
16667
|
async function rasterizeShadowMarkers(svg) {
|
|
16252
|
-
var _a, _b, _c, _d, _e;
|
|
16668
|
+
var _a, _b, _c, _d, _e, _f;
|
|
16253
16669
|
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
16254
16670
|
const markers = Array.from(svg.querySelectorAll("g.__pdShadowRaster"));
|
|
16255
16671
|
if (markers.length === 0) return;
|
|
@@ -16274,6 +16690,17 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16274
16690
|
continue;
|
|
16275
16691
|
}
|
|
16276
16692
|
const innerXml = Array.from(marker.childNodes).map((n) => n instanceof Element ? new XMLSerializer().serializeToString(n) : "").join("");
|
|
16693
|
+
try {
|
|
16694
|
+
const fontSpecs = collectFontSpecsFromMarkup(innerXml);
|
|
16695
|
+
if (fontSpecs.length > 0 && ((_c = document.fonts) == null ? void 0 : _c.load)) {
|
|
16696
|
+
await Promise.all(
|
|
16697
|
+
fontSpecs.map(
|
|
16698
|
+
(spec) => document.fonts.load(spec).catch(() => void 0)
|
|
16699
|
+
)
|
|
16700
|
+
);
|
|
16701
|
+
}
|
|
16702
|
+
} catch {
|
|
16703
|
+
}
|
|
16277
16704
|
const scale = 2;
|
|
16278
16705
|
const pxW = Math.min(4096, Math.max(8, Math.ceil(bw * scale)));
|
|
16279
16706
|
const pxH = Math.min(4096, Math.max(8, Math.ceil(bh * scale)));
|
|
@@ -16283,7 +16710,7 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16283
16710
|
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>`;
|
|
16284
16711
|
const dataUrl = await rasterSvgToPngDataUrl(miniSvg, pxW, pxH);
|
|
16285
16712
|
if (!dataUrl) {
|
|
16286
|
-
(
|
|
16713
|
+
(_d = marker.parentNode) == null ? void 0 : _d.removeChild(marker);
|
|
16287
16714
|
continue;
|
|
16288
16715
|
}
|
|
16289
16716
|
const img = svg.ownerDocument.createElementNS(SVG_NS, "image");
|
|
@@ -16295,11 +16722,11 @@ async function rasterizeShadowMarkers(svg) {
|
|
|
16295
16722
|
img.setAttribute("preserveAspectRatio", "none");
|
|
16296
16723
|
img.setAttributeNS(XLINK_NS, "xlink:href", dataUrl);
|
|
16297
16724
|
img.setAttribute("href", dataUrl);
|
|
16298
|
-
(
|
|
16725
|
+
(_e = marker.parentNode) == null ? void 0 : _e.replaceChild(img, marker);
|
|
16299
16726
|
} catch (e) {
|
|
16300
16727
|
console.warn("[pdf-export] rasterizeShadowMarkers failed for one marker:", e);
|
|
16301
16728
|
try {
|
|
16302
|
-
(
|
|
16729
|
+
(_f = marker.parentNode) == null ? void 0 : _f.removeChild(marker);
|
|
16303
16730
|
} catch {
|
|
16304
16731
|
}
|
|
16305
16732
|
}
|