@pixldocs/canvas-renderer 0.5.204 → 0.5.206
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-pfkM2NbI.cjs → index-B1kaODSZ.cjs} +2025 -51
- package/dist/index-B1kaODSZ.cjs.map +1 -0
- package/dist/{index-BfLA9Iqt.js → index-CyxNh5Y9.js} +2025 -51
- package/dist/index-CyxNh5Y9.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -1
- package/dist/{svgTextToPath-hYM9qTeC.cjs → svgTextToPath-BT7lcwLT.cjs} +51 -6
- package/dist/svgTextToPath-BT7lcwLT.cjs.map +1 -0
- package/dist/{svgTextToPath-BoT6H7Lz.js → svgTextToPath-Bw974R9h.js} +51 -6
- package/dist/svgTextToPath-Bw974R9h.js.map +1 -0
- package/dist/{vectorPdfExport-BzQh8tO6.cjs → vectorPdfExport-C0s166DN.cjs} +38 -9
- package/dist/vectorPdfExport-C0s166DN.cjs.map +1 -0
- package/dist/{vectorPdfExport-NpBdL1eb.js → vectorPdfExport-CyNCzRhQ.js} +38 -9
- package/dist/vectorPdfExport-CyNCzRhQ.js.map +1 -0
- package/package.json +1 -1
- package/dist/index-BfLA9Iqt.js.map +0 -1
- package/dist/index-pfkM2NbI.cjs.map +0 -1
- package/dist/svgTextToPath-BoT6H7Lz.js.map +0 -1
- package/dist/svgTextToPath-hYM9qTeC.cjs.map +0 -1
- package/dist/vectorPdfExport-BzQh8tO6.cjs.map +0 -1
- package/dist/vectorPdfExport-NpBdL1eb.js.map +0 -1
|
@@ -3649,17 +3649,14 @@ async function normalizeSvgImageDimensions(fabricImage, imageUrl, sourceFormat)
|
|
|
3649
3649
|
const el = ((_a = fabricImage.getElement) == null ? void 0 : _a.call(fabricImage)) ?? fabricImage._element;
|
|
3650
3650
|
let w = 0;
|
|
3651
3651
|
let h = 0;
|
|
3652
|
-
|
|
3652
|
+
const dims = await loadSvgDimensions(imageUrl);
|
|
3653
|
+
if (dims && dims.width > 0 && dims.height > 0) {
|
|
3654
|
+
w = dims.width;
|
|
3655
|
+
h = dims.height;
|
|
3656
|
+
} else if (el && typeof el.naturalWidth === "number" && typeof el.naturalHeight === "number" && el.naturalWidth > 0 && el.naturalHeight > 0) {
|
|
3653
3657
|
w = el.naturalWidth;
|
|
3654
3658
|
h = el.naturalHeight;
|
|
3655
3659
|
}
|
|
3656
|
-
if (w <= 0 || h <= 0) {
|
|
3657
|
-
const dims = await loadSvgDimensions(imageUrl);
|
|
3658
|
-
if (dims && dims.width > 0 && dims.height > 0) {
|
|
3659
|
-
w = dims.width;
|
|
3660
|
-
h = dims.height;
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
3660
|
if (w > 0 && h > 0) {
|
|
3664
3661
|
fabricImage.set({ width: w, height: h });
|
|
3665
3662
|
fabricImage.setCoords();
|
|
@@ -5713,6 +5710,134 @@ function calculateScaleSnapGuides(scalingObj, corner, canvas, canvasWidth, canva
|
|
|
5713
5710
|
return true;
|
|
5714
5711
|
});
|
|
5715
5712
|
}
|
|
5713
|
+
const clamp01$1 = (v) => Math.max(0, Math.min(1, Number.isFinite(v) ? v : 0));
|
|
5714
|
+
function arcPath(w, sag, up) {
|
|
5715
|
+
if (sag <= 0.5) return `M 0 0 L ${w} 0`;
|
|
5716
|
+
const r = (sag * sag + w / 2 * (w / 2)) / (2 * sag);
|
|
5717
|
+
const sweep = 1;
|
|
5718
|
+
const y0 = sag;
|
|
5719
|
+
const y1 = sag;
|
|
5720
|
+
return `M 0 ${y0} A ${r.toFixed(2)} ${r.toFixed(2)} 0 0 ${sweep} ${w} ${y1}`;
|
|
5721
|
+
}
|
|
5722
|
+
function sampledPath(fn, steps = 60) {
|
|
5723
|
+
const parts = [];
|
|
5724
|
+
for (let i = 0; i <= steps; i++) {
|
|
5725
|
+
const [x, y] = fn(i / steps);
|
|
5726
|
+
parts.push(i === 0 ? `M ${x.toFixed(2)} ${y.toFixed(2)}` : `L ${x.toFixed(2)} ${y.toFixed(2)}`);
|
|
5727
|
+
}
|
|
5728
|
+
return parts.join(" ");
|
|
5729
|
+
}
|
|
5730
|
+
function resolveTextPath(cfg, width, fontSize) {
|
|
5731
|
+
if (!cfg || !cfg.preset || cfg.preset === "none") return null;
|
|
5732
|
+
const w = Math.max(1, width);
|
|
5733
|
+
const fs = Math.max(4, fontSize);
|
|
5734
|
+
const t = clamp01$1(cfg.intensity ?? 0.5);
|
|
5735
|
+
if (cfg.bezier && cfg.preset !== "circle" && cfg.preset !== "rise" && cfg.preset !== "angle") {
|
|
5736
|
+
const { p0, c0, c1, p1 } = cfg.bezier;
|
|
5737
|
+
const minX = Math.min(p0[0], c0[0], c1[0], p1[0]);
|
|
5738
|
+
const maxX = Math.max(p0[0], c0[0], c1[0], p1[0]);
|
|
5739
|
+
const minY = Math.min(p0[1], c0[1], c1[1], p1[1]);
|
|
5740
|
+
const maxY = Math.max(p0[1], c0[1], c1[1], p1[1]);
|
|
5741
|
+
return {
|
|
5742
|
+
d: `M ${p0[0]} ${p0[1]} C ${c0[0]} ${c0[1]}, ${c1[0]} ${c1[1]}, ${p1[0]} ${p1[1]}`,
|
|
5743
|
+
bbox: { width: maxX - minX, height: maxY - minY + fs * 1.4 }
|
|
5744
|
+
};
|
|
5745
|
+
}
|
|
5746
|
+
if (cfg.preset === "custom") {
|
|
5747
|
+
if (!cfg.path) return null;
|
|
5748
|
+
return { d: cfg.path, bbox: cfg.bbox ?? { width: w, height: fs * 2 } };
|
|
5749
|
+
}
|
|
5750
|
+
switch (cfg.preset) {
|
|
5751
|
+
case "arch": {
|
|
5752
|
+
const sag = t * w * 0.45;
|
|
5753
|
+
return { d: arcPath(w, sag), bbox: { width: w, height: sag + fs * 1.4 } };
|
|
5754
|
+
}
|
|
5755
|
+
case "rise":
|
|
5756
|
+
case "angle": {
|
|
5757
|
+
const ep = cfg.endpoints;
|
|
5758
|
+
const defaultDy = t * fs * 3;
|
|
5759
|
+
const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultDy;
|
|
5760
|
+
const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : 0;
|
|
5761
|
+
const lineMid = (leftY + rightY) / 2;
|
|
5762
|
+
const hasCenterHandle = ep && Number.isFinite(ep.centerY);
|
|
5763
|
+
const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : 0;
|
|
5764
|
+
const curveAmt = Math.max(-1, Math.min(1, rawCurve));
|
|
5765
|
+
const curveAmp = Math.min(w * 0.18, fs * 4);
|
|
5766
|
+
const centerY = hasCenterHandle ? ep.centerY : lineMid - curveAmt * curveAmp;
|
|
5767
|
+
if (Math.abs(centerY - lineMid) < 0.5) {
|
|
5768
|
+
const minY2 = Math.min(leftY, rightY);
|
|
5769
|
+
const maxY2 = Math.max(leftY, rightY);
|
|
5770
|
+
return {
|
|
5771
|
+
d: `M 0 ${leftY.toFixed(2)} L ${w} ${rightY.toFixed(2)}`,
|
|
5772
|
+
bbox: { width: w, height: maxY2 - minY2 + fs * 1.4 }
|
|
5773
|
+
};
|
|
5774
|
+
}
|
|
5775
|
+
const controlY = 2 * centerY - lineMid;
|
|
5776
|
+
const minY = Math.min(leftY, rightY, centerY);
|
|
5777
|
+
const maxY = Math.max(leftY, rightY, centerY);
|
|
5778
|
+
return {
|
|
5779
|
+
d: `M 0 ${leftY.toFixed(2)} Q ${(w / 2).toFixed(2)} ${controlY.toFixed(2)} ${w} ${rightY.toFixed(2)}`,
|
|
5780
|
+
bbox: { width: w, height: maxY - minY + fs * 1.4 }
|
|
5781
|
+
};
|
|
5782
|
+
}
|
|
5783
|
+
case "wave": {
|
|
5784
|
+
const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : t;
|
|
5785
|
+
const c = Math.max(-1, Math.min(1, rawCurve));
|
|
5786
|
+
const amp = c * fs * 3;
|
|
5787
|
+
const absAmp = Math.abs(amp);
|
|
5788
|
+
const d = sampledPath((u) => [u * w, absAmp - amp * Math.sin(u * Math.PI)]);
|
|
5789
|
+
return { d, bbox: { width: w, height: absAmp * 2 + fs * 1.4 } };
|
|
5790
|
+
}
|
|
5791
|
+
case "flag": {
|
|
5792
|
+
const rawCurve = Number.isFinite(cfg.curve) ? cfg.curve : t;
|
|
5793
|
+
const c = Math.max(-1, Math.min(1, rawCurve));
|
|
5794
|
+
const amp = c * fs * 2.5;
|
|
5795
|
+
const absAmp = Math.abs(amp);
|
|
5796
|
+
const d = sampledPath((u) => [u * w, absAmp + amp * Math.sin(u * Math.PI * 2)]);
|
|
5797
|
+
return { d, bbox: { width: w, height: absAmp * 2 + fs * 1.4 } };
|
|
5798
|
+
}
|
|
5799
|
+
case "circle": {
|
|
5800
|
+
const auto = Math.max(fs * 1.5, w / Math.PI);
|
|
5801
|
+
const r = Math.max(fs * 0.75, Number.isFinite(cfg.radius) && cfg.radius > 0 ? cfg.radius : auto);
|
|
5802
|
+
return {
|
|
5803
|
+
d: `M ${r} ${2 * r} A ${r} ${r} 0 1 1 ${r} 0 A ${r} ${r} 0 1 1 ${r} ${2 * r}`,
|
|
5804
|
+
bbox: { width: 2 * r, height: 2 * r + fs * 1.4 }
|
|
5805
|
+
};
|
|
5806
|
+
}
|
|
5807
|
+
default:
|
|
5808
|
+
return null;
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
function measurePath(d) {
|
|
5812
|
+
if (typeof document === "undefined") return null;
|
|
5813
|
+
const svgNS = "http://www.w3.org/2000/svg";
|
|
5814
|
+
const svg = document.createElementNS(svgNS, "svg");
|
|
5815
|
+
const path = document.createElementNS(svgNS, "path");
|
|
5816
|
+
path.setAttribute("d", d);
|
|
5817
|
+
svg.appendChild(path);
|
|
5818
|
+
return path;
|
|
5819
|
+
}
|
|
5820
|
+
function resolveTextPathAlphabeticBaselineDy(ctx, sampleText, fontSize) {
|
|
5821
|
+
const prevBaseline = ctx.textBaseline;
|
|
5822
|
+
try {
|
|
5823
|
+
ctx.textBaseline = "alphabetic";
|
|
5824
|
+
const metrics = ctx.measureText(sampleText || "M");
|
|
5825
|
+
const fontAscent = Number(metrics.fontBoundingBoxAscent);
|
|
5826
|
+
const fontDescent = Number(metrics.fontBoundingBoxDescent);
|
|
5827
|
+
if (Number.isFinite(fontAscent) && Number.isFinite(fontDescent) && fontAscent + fontDescent > 0) {
|
|
5828
|
+
return (fontAscent - fontDescent) / 2;
|
|
5829
|
+
}
|
|
5830
|
+
const actualAscent = Number(metrics.actualBoundingBoxAscent);
|
|
5831
|
+
const actualDescent = Number(metrics.actualBoundingBoxDescent);
|
|
5832
|
+
if (Number.isFinite(actualAscent) && Number.isFinite(actualDescent) && actualAscent + actualDescent > 0) {
|
|
5833
|
+
return (actualAscent - actualDescent) / 2;
|
|
5834
|
+
}
|
|
5835
|
+
} catch {
|
|
5836
|
+
} finally {
|
|
5837
|
+
ctx.textBaseline = prevBaseline;
|
|
5838
|
+
}
|
|
5839
|
+
return fontSize / 2;
|
|
5840
|
+
}
|
|
5716
5841
|
const TextboxProto = fabric__namespace.Textbox.prototype;
|
|
5717
5842
|
if (!TextboxProto.__pixldocsOrigCalcTextHeight) {
|
|
5718
5843
|
TextboxProto.__pixldocsOrigCalcTextHeight = TextboxProto.calcTextHeight;
|
|
@@ -5754,23 +5879,988 @@ const stateProps = fabric__namespace.Textbox.prototype.stateProperties;
|
|
|
5754
5879
|
if (Array.isArray(stateProps)) {
|
|
5755
5880
|
if (!stateProps.includes("minBoxHeight")) stateProps.push("minBoxHeight");
|
|
5756
5881
|
if (!stateProps.includes("verticalAlign")) stateProps.push("verticalAlign");
|
|
5882
|
+
if (!stateProps.includes("textPath")) stateProps.push("textPath");
|
|
5757
5883
|
}
|
|
5758
5884
|
const cacheProps = fabric__namespace.Textbox.prototype.cacheProperties;
|
|
5759
5885
|
if (Array.isArray(cacheProps)) {
|
|
5760
5886
|
if (!cacheProps.includes("minBoxHeight")) cacheProps.push("minBoxHeight");
|
|
5761
5887
|
if (!cacheProps.includes("verticalAlign")) cacheProps.push("verticalAlign");
|
|
5888
|
+
if (!cacheProps.includes("textPath")) cacheProps.push("textPath");
|
|
5889
|
+
}
|
|
5890
|
+
const hasActiveTextPath = (obj) => {
|
|
5891
|
+
const tp = obj.textPath;
|
|
5892
|
+
return !!tp && !!tp.preset && tp.preset !== "none";
|
|
5893
|
+
};
|
|
5894
|
+
function applyWarpFillStyle(ctx, obj) {
|
|
5895
|
+
const filler = obj.fill;
|
|
5896
|
+
if (filler && typeof filler === "object" && Array.isArray(filler.colorStops) && filler.coords) {
|
|
5897
|
+
try {
|
|
5898
|
+
const halfW = (obj.width || 0) / 2;
|
|
5899
|
+
const halfH = (obj.height || 0) / 2;
|
|
5900
|
+
const c = filler.coords || {};
|
|
5901
|
+
let live = null;
|
|
5902
|
+
if (filler.type === "radial") {
|
|
5903
|
+
live = ctx.createRadialGradient(
|
|
5904
|
+
(Number(c.x1) || 0) - halfW,
|
|
5905
|
+
(Number(c.y1) || 0) - halfH,
|
|
5906
|
+
Math.max(0, Number(c.r1) || 0),
|
|
5907
|
+
(Number(c.x2 ?? c.x1) || 0) - halfW,
|
|
5908
|
+
(Number(c.y2 ?? c.y1) || 0) - halfH,
|
|
5909
|
+
Math.max(0.1, Number(c.r2 ?? c.r) || Math.max(obj.width || 1, obj.height || 1) / 2)
|
|
5910
|
+
);
|
|
5911
|
+
} else {
|
|
5912
|
+
live = ctx.createLinearGradient(
|
|
5913
|
+
(Number(c.x1) || 0) - halfW,
|
|
5914
|
+
(Number(c.y1) || 0) - halfH,
|
|
5915
|
+
(Number(c.x2 ?? obj.width) || 0) - halfW,
|
|
5916
|
+
(Number(c.y2) || 0) - halfH
|
|
5917
|
+
);
|
|
5918
|
+
}
|
|
5919
|
+
for (const stop of filler.colorStops) {
|
|
5920
|
+
live.addColorStop(Math.max(0, Math.min(1, Number(stop.offset) || 0)), stop.color || "#000");
|
|
5921
|
+
}
|
|
5922
|
+
ctx.fillStyle = live;
|
|
5923
|
+
return { offsetX: 0, offsetY: 0 };
|
|
5924
|
+
} catch {
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
if (typeof obj.handleFiller === "function") {
|
|
5928
|
+
try {
|
|
5929
|
+
return obj.handleFiller(ctx, "fillStyle", filler || "#000") || { offsetX: 0, offsetY: 0 };
|
|
5930
|
+
} catch {
|
|
5931
|
+
}
|
|
5932
|
+
}
|
|
5933
|
+
if (filler && typeof filler.toLive === "function") {
|
|
5934
|
+
try {
|
|
5935
|
+
ctx.fillStyle = filler.toLive(ctx) || "#000";
|
|
5936
|
+
return { offsetX: 0, offsetY: 0 };
|
|
5937
|
+
} catch {
|
|
5938
|
+
}
|
|
5939
|
+
}
|
|
5940
|
+
ctx.fillStyle = typeof obj.fill === "string" ? obj.fill : "#000";
|
|
5941
|
+
return { offsetX: 0, offsetY: 0 };
|
|
5942
|
+
}
|
|
5943
|
+
function parseCssColor(input) {
|
|
5944
|
+
const fallback = [0, 0, 0, 1];
|
|
5945
|
+
if (!input) return fallback;
|
|
5946
|
+
const s = String(input).trim();
|
|
5947
|
+
if (s.startsWith("#")) {
|
|
5948
|
+
let hex = s.slice(1);
|
|
5949
|
+
if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
|
|
5950
|
+
if (hex.length === 4) hex = hex.split("").map((c) => c + c).join("");
|
|
5951
|
+
if (hex.length === 6) {
|
|
5952
|
+
const n = parseInt(hex, 16);
|
|
5953
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255, 1];
|
|
5954
|
+
}
|
|
5955
|
+
if (hex.length === 8) {
|
|
5956
|
+
const n = parseInt(hex, 16);
|
|
5957
|
+
return [n >> 24 & 255, n >> 16 & 255, n >> 8 & 255, (n & 255) / 255];
|
|
5958
|
+
}
|
|
5959
|
+
}
|
|
5960
|
+
const m = s.match(/^rgba?\s*\(\s*([\d.]+)[\s,]+([\d.]+)[\s,]+([\d.]+)(?:[\s,/]+([\d.]+%?))?\s*\)$/i);
|
|
5961
|
+
if (m) {
|
|
5962
|
+
let a = 1;
|
|
5963
|
+
if (m[4] != null) a = m[4].endsWith("%") ? parseFloat(m[4]) / 100 : parseFloat(m[4]);
|
|
5964
|
+
return [parseFloat(m[1]), parseFloat(m[2]), parseFloat(m[3]), Number.isFinite(a) ? a : 1];
|
|
5965
|
+
}
|
|
5966
|
+
try {
|
|
5967
|
+
const c = document.createElement("canvas").getContext("2d");
|
|
5968
|
+
if (c) {
|
|
5969
|
+
c.fillStyle = "#000";
|
|
5970
|
+
c.fillStyle = s;
|
|
5971
|
+
const computed = c.fillStyle;
|
|
5972
|
+
return parseCssColor(computed.startsWith("#") || computed.startsWith("rgb") ? computed : "#000");
|
|
5973
|
+
}
|
|
5974
|
+
} catch {
|
|
5975
|
+
}
|
|
5976
|
+
return fallback;
|
|
5977
|
+
}
|
|
5978
|
+
function sampleGradientColor(stops, t) {
|
|
5979
|
+
if (!stops || !stops.length) return "#000";
|
|
5980
|
+
const sorted = [...stops].sort((a, b) => (a.offset || 0) - (b.offset || 0));
|
|
5981
|
+
const u = Math.max(0, Math.min(1, t));
|
|
5982
|
+
if (u <= (sorted[0].offset || 0)) return sorted[0].color || "#000";
|
|
5983
|
+
if (u >= (sorted[sorted.length - 1].offset || 1)) return sorted[sorted.length - 1].color || "#000";
|
|
5984
|
+
for (let i = 0; i < sorted.length - 1; i++) {
|
|
5985
|
+
const a = sorted[i];
|
|
5986
|
+
const b = sorted[i + 1];
|
|
5987
|
+
const ao = a.offset || 0;
|
|
5988
|
+
const bo = b.offset || 0;
|
|
5989
|
+
if (u >= ao && u <= bo) {
|
|
5990
|
+
const span = bo - ao || 1;
|
|
5991
|
+
const k = (u - ao) / span;
|
|
5992
|
+
const ca = parseCssColor(a.color);
|
|
5993
|
+
const cb = parseCssColor(b.color);
|
|
5994
|
+
const r = Math.round(ca[0] + (cb[0] - ca[0]) * k);
|
|
5995
|
+
const g = Math.round(ca[1] + (cb[1] - ca[1]) * k);
|
|
5996
|
+
const bl = Math.round(ca[2] + (cb[2] - ca[2]) * k);
|
|
5997
|
+
const al = ca[3] + (cb[3] - ca[3]) * k;
|
|
5998
|
+
return `rgba(${r}, ${g}, ${bl}, ${al.toFixed(3)})`;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
return sorted[sorted.length - 1].color || "#000";
|
|
6002
|
+
}
|
|
6003
|
+
function getGradientStopsForFlow(obj) {
|
|
6004
|
+
const f = obj.fill;
|
|
6005
|
+
if (f && typeof f === "object" && Array.isArray(f.colorStops) && f.colorStops.length) {
|
|
6006
|
+
return f.colorStops.map((s) => ({ offset: Number(s.offset) || 0, color: s.color || "#000" }));
|
|
6007
|
+
}
|
|
6008
|
+
return null;
|
|
6009
|
+
}
|
|
6010
|
+
function localPointFromCanvas(target, x, y) {
|
|
6011
|
+
const point = new fabric__namespace.Point(x, y);
|
|
6012
|
+
try {
|
|
6013
|
+
return target.toLocalPoint(point, "left", "top");
|
|
6014
|
+
} catch {
|
|
6015
|
+
const inv = fabric__namespace.util.invertTransform(target.calcTransformMatrix());
|
|
6016
|
+
const local = fabric__namespace.util.transformPoint(point, inv);
|
|
6017
|
+
return new fabric__namespace.Point(local.x + (target.width || 0) / 2, local.y + (target.height || 0) / 2);
|
|
6018
|
+
}
|
|
6019
|
+
}
|
|
6020
|
+
function localPointFromFrozenMatrix(target, x, y, matrix) {
|
|
6021
|
+
const local = fabric__namespace.util.transformPoint(new fabric__namespace.Point(x, y), fabric__namespace.util.invertTransform(matrix));
|
|
6022
|
+
return new fabric__namespace.Point(local.x + (target.width || 0) / 2, local.y + (target.height || 0) / 2);
|
|
6023
|
+
}
|
|
6024
|
+
function vectorFromFrozenMatrix(matrix, dx, dy) {
|
|
6025
|
+
return new fabric__namespace.Point(matrix[0] * dx + matrix[2] * dy, matrix[1] * dx + matrix[3] * dy);
|
|
6026
|
+
}
|
|
6027
|
+
function scaleLocalToScreen(target, p) {
|
|
6028
|
+
var _a;
|
|
6029
|
+
const vpt = ((_a = target == null ? void 0 : target.canvas) == null ? void 0 : _a.viewportTransform) || [1, 0, 0, 1, 0, 0];
|
|
6030
|
+
const zx = Math.abs(vpt[0] || 1);
|
|
6031
|
+
const zy = Math.abs(vpt[3] || 1);
|
|
6032
|
+
const sx = Math.abs((target == null ? void 0 : target.scaleX) || 1);
|
|
6033
|
+
const sy = Math.abs((target == null ? void 0 : target.scaleY) || 1);
|
|
6034
|
+
return new fabric__namespace.Point(p.x * sx * zx, p.y * sy * zy);
|
|
6035
|
+
}
|
|
6036
|
+
function applyTextPathControls(textbox) {
|
|
6037
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
6038
|
+
const obj = textbox;
|
|
6039
|
+
if (!hasActiveTextPath(obj)) {
|
|
6040
|
+
obj.__pdTextPathHovered = false;
|
|
6041
|
+
if (obj.__pdTextPathControls) {
|
|
6042
|
+
try {
|
|
6043
|
+
const cu2 = fabric__namespace.controlsUtils;
|
|
6044
|
+
const defaults = ((_a = cu2 == null ? void 0 : cu2.createTextboxDefaultControls) == null ? void 0 : _a.call(cu2)) ?? ((_b = cu2 == null ? void 0 : cu2.createObjectDefaultControls) == null ? void 0 : _b.call(cu2));
|
|
6045
|
+
if (defaults) obj.controls = defaults;
|
|
6046
|
+
} catch {
|
|
6047
|
+
}
|
|
6048
|
+
delete obj.controls.bzP0;
|
|
6049
|
+
delete obj.controls.bzC0;
|
|
6050
|
+
delete obj.controls.bzC1;
|
|
6051
|
+
delete obj.controls.bzP1;
|
|
6052
|
+
delete obj.controls.rsL;
|
|
6053
|
+
delete obj.controls.rsR;
|
|
6054
|
+
delete obj.controls.rsC;
|
|
6055
|
+
delete obj.controls.bzMid;
|
|
6056
|
+
delete obj.controls.bzMidT0;
|
|
6057
|
+
delete obj.controls.bzMidT1;
|
|
6058
|
+
delete obj.controls.tpRot;
|
|
6059
|
+
delete obj.controls.tpPivot;
|
|
6060
|
+
(_c = obj.setControlsVisibility) == null ? void 0 : _c.call(obj, { tl: true, tr: true, bl: true, br: true, mt: true, mb: true, ml: true, mr: true, mtr: true });
|
|
6061
|
+
obj.hasBorders = true;
|
|
6062
|
+
obj.__pdTextPathControls = false;
|
|
6063
|
+
obj.setCoords();
|
|
6064
|
+
}
|
|
6065
|
+
return;
|
|
6066
|
+
}
|
|
6067
|
+
if (!obj.__pdTextPathHoverWired) {
|
|
6068
|
+
obj.on("mouseover", () => {
|
|
6069
|
+
var _a2;
|
|
6070
|
+
if (!hasActiveTextPath(obj)) return;
|
|
6071
|
+
obj.__pdTextPathHovered = true;
|
|
6072
|
+
(_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6073
|
+
});
|
|
6074
|
+
obj.on("mouseout", () => {
|
|
6075
|
+
var _a2;
|
|
6076
|
+
obj.__pdTextPathHovered = false;
|
|
6077
|
+
(_a2 = obj.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6078
|
+
});
|
|
6079
|
+
obj.__pdTextPathHoverWired = true;
|
|
6080
|
+
}
|
|
6081
|
+
obj.controls = {};
|
|
6082
|
+
const halfWOf = (t) => (t.width || 0) / 2;
|
|
6083
|
+
const halfHOf = (t) => (t.height || 0) / 2;
|
|
6084
|
+
const cu = fabric__namespace.controlsUtils;
|
|
6085
|
+
const renderRotation = (ctx, left, top) => {
|
|
6086
|
+
ctx.save();
|
|
6087
|
+
ctx.translate(left, top);
|
|
6088
|
+
ctx.shadowColor = "rgba(0,0,0,0.25)";
|
|
6089
|
+
ctx.shadowBlur = 2;
|
|
6090
|
+
ctx.shadowOffsetY = 0.5;
|
|
6091
|
+
ctx.fillStyle = "#ffffff";
|
|
6092
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6093
|
+
ctx.lineWidth = 1.5;
|
|
6094
|
+
ctx.beginPath();
|
|
6095
|
+
ctx.arc(0, 0, 6, 0, Math.PI * 2);
|
|
6096
|
+
ctx.fill();
|
|
6097
|
+
ctx.shadowColor = "transparent";
|
|
6098
|
+
ctx.stroke();
|
|
6099
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6100
|
+
ctx.lineWidth = 1.25;
|
|
6101
|
+
ctx.beginPath();
|
|
6102
|
+
ctx.arc(0, 0, 3, -Math.PI * 0.85, Math.PI * 0.75);
|
|
6103
|
+
ctx.stroke();
|
|
6104
|
+
ctx.restore();
|
|
6105
|
+
};
|
|
6106
|
+
const renderPivot = (ctx, left, top) => {
|
|
6107
|
+
ctx.save();
|
|
6108
|
+
ctx.translate(left, top);
|
|
6109
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6110
|
+
ctx.fillStyle = "#ffffff";
|
|
6111
|
+
ctx.lineWidth = 1.25;
|
|
6112
|
+
ctx.beginPath();
|
|
6113
|
+
ctx.arc(0, 0, 5, 0, Math.PI * 2);
|
|
6114
|
+
ctx.fill();
|
|
6115
|
+
ctx.stroke();
|
|
6116
|
+
ctx.beginPath();
|
|
6117
|
+
ctx.moveTo(-3.5, 0);
|
|
6118
|
+
ctx.lineTo(3.5, 0);
|
|
6119
|
+
ctx.moveTo(0, -3.5);
|
|
6120
|
+
ctx.lineTo(0, 3.5);
|
|
6121
|
+
ctx.stroke();
|
|
6122
|
+
ctx.fillStyle = "#1d9bf0";
|
|
6123
|
+
ctx.beginPath();
|
|
6124
|
+
ctx.arc(0, 0, 1.25, 0, Math.PI * 2);
|
|
6125
|
+
ctx.fill();
|
|
6126
|
+
ctx.restore();
|
|
6127
|
+
};
|
|
6128
|
+
const addRotationAndPivot = () => {
|
|
6129
|
+
var _a2, _b2;
|
|
6130
|
+
obj.controls.tpRot = new fabric__namespace.Control({
|
|
6131
|
+
x: 0,
|
|
6132
|
+
y: -0.5,
|
|
6133
|
+
offsetY: -28,
|
|
6134
|
+
cursorStyleHandler: cu == null ? void 0 : cu.rotationStyleHandler,
|
|
6135
|
+
actionHandler: cu == null ? void 0 : cu.rotationWithSnapping,
|
|
6136
|
+
actionName: "rotate",
|
|
6137
|
+
render: renderRotation,
|
|
6138
|
+
withConnection: false
|
|
6139
|
+
});
|
|
6140
|
+
obj.controls.tpPivot = new fabric__namespace.Control({
|
|
6141
|
+
x: 0,
|
|
6142
|
+
y: 0,
|
|
6143
|
+
cursorStyle: "default",
|
|
6144
|
+
actionName: "tpPivot",
|
|
6145
|
+
actionHandler: () => false,
|
|
6146
|
+
render: renderPivot
|
|
6147
|
+
});
|
|
6148
|
+
(_a2 = obj.setControlVisible) == null ? void 0 : _a2.call(obj, "tpRot", true);
|
|
6149
|
+
(_b2 = obj.setControlVisible) == null ? void 0 : _b2.call(obj, "tpPivot", true);
|
|
6150
|
+
};
|
|
6151
|
+
if (((_d = obj.textPath) == null ? void 0 : _d.preset) === "circle") {
|
|
6152
|
+
const getRadius = (target) => {
|
|
6153
|
+
const tp = target.textPath || {};
|
|
6154
|
+
const fs = target.fontSize || 16;
|
|
6155
|
+
const w = target.width || 0;
|
|
6156
|
+
const auto = Math.max(fs * 1.5, w / Math.PI);
|
|
6157
|
+
const r = tp.radius;
|
|
6158
|
+
return Math.max(fs * 0.75, Number.isFinite(r) && r > 0 ? r : auto);
|
|
6159
|
+
};
|
|
6160
|
+
const setRadius = (target, r) => {
|
|
6161
|
+
var _a2;
|
|
6162
|
+
const fs = target.fontSize || 16;
|
|
6163
|
+
const clamped = Math.max(fs * 0.75, r);
|
|
6164
|
+
if (!target.textPath) target.textPath = { preset: "circle" };
|
|
6165
|
+
target.textPath.preset = "circle";
|
|
6166
|
+
target.textPath.radius = clamped;
|
|
6167
|
+
target.dirty = true;
|
|
6168
|
+
(_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6169
|
+
};
|
|
6170
|
+
const ringPoint = (target, dir) => {
|
|
6171
|
+
const r = getRadius(target);
|
|
6172
|
+
const cx = r - halfWOf(target);
|
|
6173
|
+
const cy = r - halfHOf(target);
|
|
6174
|
+
switch (dir) {
|
|
6175
|
+
case "N":
|
|
6176
|
+
return new fabric__namespace.Point(cx, cy - r);
|
|
6177
|
+
case "E":
|
|
6178
|
+
return new fabric__namespace.Point(cx + r, cy);
|
|
6179
|
+
case "S":
|
|
6180
|
+
return new fabric__namespace.Point(cx, cy + r);
|
|
6181
|
+
case "W":
|
|
6182
|
+
return new fabric__namespace.Point(cx - r, cy);
|
|
6183
|
+
}
|
|
6184
|
+
};
|
|
6185
|
+
const positionAtRing = (dir) => (_d2, finalMatrix, target) => scaleLocalToScreen(target, ringPoint(target, dir)).transform(finalMatrix);
|
|
6186
|
+
const dragRadius = (dir) => (_e2, transform, x, y) => {
|
|
6187
|
+
const target = transform.target;
|
|
6188
|
+
const state = transform.__pdCircleRadiusDrag || (transform.__pdCircleRadiusDrag = {
|
|
6189
|
+
dir,
|
|
6190
|
+
startRadius: getRadius(target),
|
|
6191
|
+
startLeft: target.left || 0,
|
|
6192
|
+
startTop: target.top || 0,
|
|
6193
|
+
startMatrix: target.calcTransformMatrix(),
|
|
6194
|
+
startLocal: null
|
|
6195
|
+
});
|
|
6196
|
+
if (!state.startLocal) state.startLocal = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
|
|
6197
|
+
const local = localPointFromFrozenMatrix(target, x, y, state.startMatrix);
|
|
6198
|
+
const dx = local.x - state.startLocal.x;
|
|
6199
|
+
const dy = local.y - state.startLocal.y;
|
|
6200
|
+
let next = state.startRadius;
|
|
6201
|
+
if (dir === "E") next = state.startRadius + dx / 2;
|
|
6202
|
+
else if (dir === "W") next = state.startRadius - dx / 2;
|
|
6203
|
+
else if (dir === "S") next = state.startRadius + dy / 2;
|
|
6204
|
+
else next = state.startRadius - dy / 2;
|
|
6205
|
+
const fs = target.fontSize || 16;
|
|
6206
|
+
next = Math.max(fs * 0.75, next);
|
|
6207
|
+
if (dir === "W") {
|
|
6208
|
+
const appliedDx = (state.startRadius - next) * 2;
|
|
6209
|
+
const move = vectorFromFrozenMatrix(state.startMatrix, appliedDx, 0);
|
|
6210
|
+
target.set({ left: state.startLeft + move.x, top: state.startTop + move.y });
|
|
6211
|
+
} else if (dir === "N") {
|
|
6212
|
+
const appliedDy = (state.startRadius - next) * 2;
|
|
6213
|
+
const move = vectorFromFrozenMatrix(state.startMatrix, 0, appliedDy);
|
|
6214
|
+
target.set({ left: state.startLeft + move.x, top: state.startTop + move.y });
|
|
6215
|
+
}
|
|
6216
|
+
setRadius(target, next);
|
|
6217
|
+
return true;
|
|
6218
|
+
};
|
|
6219
|
+
const renderRingHandle = (ctx, left, top) => {
|
|
6220
|
+
ctx.save();
|
|
6221
|
+
ctx.translate(left, top);
|
|
6222
|
+
ctx.shadowColor = "rgba(0,0,0,0.25)";
|
|
6223
|
+
ctx.shadowBlur = 2;
|
|
6224
|
+
ctx.shadowOffsetY = 0.5;
|
|
6225
|
+
ctx.fillStyle = "#ffffff";
|
|
6226
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6227
|
+
ctx.lineWidth = 1.5;
|
|
6228
|
+
ctx.beginPath();
|
|
6229
|
+
ctx.arc(0, 0, 5.5, 0, Math.PI * 2);
|
|
6230
|
+
ctx.fill();
|
|
6231
|
+
ctx.shadowColor = "transparent";
|
|
6232
|
+
ctx.stroke();
|
|
6233
|
+
ctx.restore();
|
|
6234
|
+
};
|
|
6235
|
+
obj.controls.crN = new fabric__namespace.Control({ x: 0, y: -0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("N"), positionHandler: positionAtRing("N"), render: renderRingHandle });
|
|
6236
|
+
obj.controls.crE = new fabric__namespace.Control({ x: 0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("E"), positionHandler: positionAtRing("E"), render: renderRingHandle });
|
|
6237
|
+
obj.controls.crS = new fabric__namespace.Control({ x: 0, y: 0.5, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragRadius("S"), positionHandler: positionAtRing("S"), render: renderRingHandle });
|
|
6238
|
+
obj.controls.crW = new fabric__namespace.Control({ x: -0.5, y: 0, cursorStyle: "ew-resize", actionName: "textPath", actionHandler: dragRadius("W"), positionHandler: positionAtRing("W"), render: renderRingHandle });
|
|
6239
|
+
(_e = obj.setControlVisible) == null ? void 0 : _e.call(obj, "crN", true);
|
|
6240
|
+
(_f = obj.setControlVisible) == null ? void 0 : _f.call(obj, "crE", true);
|
|
6241
|
+
(_g = obj.setControlVisible) == null ? void 0 : _g.call(obj, "crS", true);
|
|
6242
|
+
(_h = obj.setControlVisible) == null ? void 0 : _h.call(obj, "crW", true);
|
|
6243
|
+
addRotationAndPivot();
|
|
6244
|
+
obj.hasBorders = false;
|
|
6245
|
+
obj.hasControls = true;
|
|
6246
|
+
obj.objectCaching = false;
|
|
6247
|
+
obj.__pdTextPathControls = true;
|
|
6248
|
+
obj.setCoords();
|
|
6249
|
+
return;
|
|
6250
|
+
}
|
|
6251
|
+
if (((_i = obj.textPath) == null ? void 0 : _i.preset) === "rise") {
|
|
6252
|
+
const getEndpoints = (target) => {
|
|
6253
|
+
const w = target.width || 0;
|
|
6254
|
+
const fs = target.fontSize || 16;
|
|
6255
|
+
const tp = target.textPath || {};
|
|
6256
|
+
const ep = tp.endpoints;
|
|
6257
|
+
const defaultLeftY = fs * 1.5;
|
|
6258
|
+
const defaultRightY = fs * 0.5;
|
|
6259
|
+
const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
|
|
6260
|
+
const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
|
|
6261
|
+
const lineMid = (leftY + rightY) / 2;
|
|
6262
|
+
const rawCurve = Number.isFinite(tp.curve) ? tp.curve : 0;
|
|
6263
|
+
const curveAmp = Math.min(w * 0.18, fs * 4);
|
|
6264
|
+
const centerY = ep && Number.isFinite(ep.centerY) ? ep.centerY : lineMid - Math.max(-1, Math.min(1, rawCurve)) * curveAmp;
|
|
6265
|
+
return { leftY, centerY, rightY };
|
|
6266
|
+
};
|
|
6267
|
+
const setEndpoints = (target, next) => {
|
|
6268
|
+
var _a2;
|
|
6269
|
+
target.width || 1;
|
|
6270
|
+
target.fontSize || 16;
|
|
6271
|
+
const lineMid = (next.leftY + next.rightY) / 2;
|
|
6272
|
+
const straight = { leftY: next.leftY, centerY: lineMid, rightY: next.rightY };
|
|
6273
|
+
if (!target.textPath) target.textPath = { preset: "rise" };
|
|
6274
|
+
target.textPath = {
|
|
6275
|
+
...target.textPath,
|
|
6276
|
+
preset: "rise",
|
|
6277
|
+
curve: 0,
|
|
6278
|
+
endpoints: straight
|
|
6279
|
+
};
|
|
6280
|
+
if (target.skewY) target.set("skewY", 0);
|
|
6281
|
+
target.dirty = true;
|
|
6282
|
+
(_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6283
|
+
};
|
|
6284
|
+
const positionAtAngleHandle = (key) => (_d2, finalMatrix, target) => {
|
|
6285
|
+
const ep = getEndpoints(target);
|
|
6286
|
+
const x = key === "leftY" ? 0 : key === "rightY" ? target.width || 0 : (target.width || 0) / 2;
|
|
6287
|
+
return scaleLocalToScreen(target, new fabric__namespace.Point(x - halfWOf(target), ep[key] - halfHOf(target))).transform(finalMatrix);
|
|
6288
|
+
};
|
|
6289
|
+
const dragAngleHandle = (key) => (_e2, transform, x, y) => {
|
|
6290
|
+
const target = transform.target;
|
|
6291
|
+
const local = localPointFromCanvas(target, x, y);
|
|
6292
|
+
const current = getEndpoints(target);
|
|
6293
|
+
const next = { ...current, [key]: local.y };
|
|
6294
|
+
setEndpoints(target, next);
|
|
6295
|
+
return true;
|
|
6296
|
+
};
|
|
6297
|
+
const renderAngleHandle = (ctx, left, top) => {
|
|
6298
|
+
ctx.save();
|
|
6299
|
+
ctx.translate(left, top);
|
|
6300
|
+
ctx.shadowColor = "rgba(0,0,0,0.25)";
|
|
6301
|
+
ctx.shadowBlur = 2;
|
|
6302
|
+
ctx.shadowOffsetY = 0.5;
|
|
6303
|
+
ctx.fillStyle = "#ffffff";
|
|
6304
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6305
|
+
ctx.lineWidth = 1.5;
|
|
6306
|
+
ctx.beginPath();
|
|
6307
|
+
ctx.arc(0, 0, 5.5, 0, Math.PI * 2);
|
|
6308
|
+
ctx.fill();
|
|
6309
|
+
ctx.shadowColor = "transparent";
|
|
6310
|
+
ctx.stroke();
|
|
6311
|
+
ctx.restore();
|
|
6312
|
+
};
|
|
6313
|
+
if (obj.skewY) obj.set("skewY", 0);
|
|
6314
|
+
obj.controls.rsL = new fabric__namespace.Control({ x: -0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("leftY"), positionHandler: positionAtAngleHandle("leftY"), render: renderAngleHandle });
|
|
6315
|
+
obj.controls.rsR = new fabric__namespace.Control({ x: 0.5, y: 0, cursorStyle: "ns-resize", actionName: "textPath", actionHandler: dragAngleHandle("rightY"), positionHandler: positionAtAngleHandle("rightY"), render: renderAngleHandle });
|
|
6316
|
+
(_j = obj.setControlVisible) == null ? void 0 : _j.call(obj, "rsL", true);
|
|
6317
|
+
(_k = obj.setControlVisible) == null ? void 0 : _k.call(obj, "rsR", true);
|
|
6318
|
+
addRotationAndPivot();
|
|
6319
|
+
obj.hasBorders = false;
|
|
6320
|
+
obj.hasControls = true;
|
|
6321
|
+
obj.objectCaching = false;
|
|
6322
|
+
obj.__pdTextPathControls = true;
|
|
6323
|
+
obj.setCoords();
|
|
6324
|
+
return;
|
|
6325
|
+
}
|
|
6326
|
+
const ensureBezier = (target) => {
|
|
6327
|
+
const tp = target.textPath;
|
|
6328
|
+
if (tp == null ? void 0 : tp.bezier) return tp.bezier;
|
|
6329
|
+
const resolved = resolveTextPath(tp, target.width || 0, target.fontSize || 16);
|
|
6330
|
+
const path = resolved ? measurePath(resolved.d) : null;
|
|
6331
|
+
if (!path) {
|
|
6332
|
+
const w = target.width || 0;
|
|
6333
|
+
const fs = target.fontSize || 16;
|
|
6334
|
+
const h = target.height || fs * 1.4;
|
|
6335
|
+
const cy = h / 2;
|
|
6336
|
+
const handleLen = w * 0.25;
|
|
6337
|
+
const fallback = {
|
|
6338
|
+
p0: [0, cy],
|
|
6339
|
+
c0: [handleLen, cy],
|
|
6340
|
+
c1: [w - handleLen, cy],
|
|
6341
|
+
p1: [w, cy]
|
|
6342
|
+
};
|
|
6343
|
+
target.textPath = { ...tp || { preset: "custom" }, bezier: fallback };
|
|
6344
|
+
return fallback;
|
|
6345
|
+
}
|
|
6346
|
+
const len = path.getTotalLength();
|
|
6347
|
+
const sample = (u) => {
|
|
6348
|
+
const p = path.getPointAtLength(u * len);
|
|
6349
|
+
return [p.x, p.y];
|
|
6350
|
+
};
|
|
6351
|
+
const p0 = sample(0);
|
|
6352
|
+
const a = sample(1 / 3);
|
|
6353
|
+
const b = sample(2 / 3);
|
|
6354
|
+
const p1 = sample(1);
|
|
6355
|
+
const c0 = [
|
|
6356
|
+
(-5 * p0[0] + 18 * a[0] - 9 * b[0] + 2 * p1[0]) / 6,
|
|
6357
|
+
(-5 * p0[1] + 18 * a[1] - 9 * b[1] + 2 * p1[1]) / 6
|
|
6358
|
+
];
|
|
6359
|
+
const c1 = [
|
|
6360
|
+
(2 * p0[0] - 9 * a[0] + 18 * b[0] - 5 * p1[0]) / 6,
|
|
6361
|
+
(2 * p0[1] - 9 * a[1] + 18 * b[1] - 5 * p1[1]) / 6
|
|
6362
|
+
];
|
|
6363
|
+
const solved = { p0, c0, c1, p1 };
|
|
6364
|
+
target.textPath = { ...tp || { preset: "custom" }, bezier: solved };
|
|
6365
|
+
return solved;
|
|
6366
|
+
};
|
|
6367
|
+
ensureBezier(obj);
|
|
6368
|
+
const positionAtBezier = (key) => (_d2, finalMatrix, target) => {
|
|
6369
|
+
const bz = ensureBezier(target);
|
|
6370
|
+
const [bx, by] = bz[key];
|
|
6371
|
+
return scaleLocalToScreen(target, new fabric__namespace.Point(bx - halfWOf(target), by - halfHOf(target))).transform(finalMatrix);
|
|
6372
|
+
};
|
|
6373
|
+
const bezierMidpoint = (bz) => [
|
|
6374
|
+
0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0],
|
|
6375
|
+
0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1]
|
|
6376
|
+
];
|
|
6377
|
+
const positionAtMid = (_d2, finalMatrix, target) => {
|
|
6378
|
+
const bz = ensureBezier(target);
|
|
6379
|
+
const [mx, my] = bezierMidpoint(bz);
|
|
6380
|
+
return scaleLocalToScreen(target, new fabric__namespace.Point(mx - halfWOf(target), my - halfHOf(target))).transform(finalMatrix);
|
|
6381
|
+
};
|
|
6382
|
+
const midTangentVector = (bz) => {
|
|
6383
|
+
let dx = bz.p1[0] + 3 * bz.c1[0] - 3 * bz.c0[0] - bz.p0[0];
|
|
6384
|
+
let dy = bz.p1[1] + 3 * bz.c1[1] - 3 * bz.c0[1] - bz.p0[1];
|
|
6385
|
+
const dlen = Math.hypot(dx, dy) || 1;
|
|
6386
|
+
dx /= dlen;
|
|
6387
|
+
dy /= dlen;
|
|
6388
|
+
const mx = 0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0];
|
|
6389
|
+
const my = 0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1];
|
|
6390
|
+
const projC1 = (bz.c1[0] - mx) * dx + (bz.c1[1] - my) * dy;
|
|
6391
|
+
const projC0 = (mx - bz.c0[0]) * dx + (my - bz.c0[1]) * dy;
|
|
6392
|
+
const reach = Math.max(8, (Math.abs(projC1) + Math.abs(projC0)) / 2);
|
|
6393
|
+
return { vx: dx * reach, vy: dy * reach };
|
|
6394
|
+
};
|
|
6395
|
+
const positionAtMidTangent = (side) => (_d2, finalMatrix, target) => {
|
|
6396
|
+
const bz = ensureBezier(target);
|
|
6397
|
+
const [mx, my] = bezierMidpoint(bz);
|
|
6398
|
+
const { vx, vy } = midTangentVector(bz);
|
|
6399
|
+
const px = mx + side * vx;
|
|
6400
|
+
const py = my + side * vy;
|
|
6401
|
+
return scaleLocalToScreen(target, new fabric__namespace.Point(px - halfWOf(target), py - halfHOf(target))).transform(finalMatrix);
|
|
6402
|
+
};
|
|
6403
|
+
const makeMidTangentDrag = (side) => (_e2, transform, x, y) => {
|
|
6404
|
+
var _a2;
|
|
6405
|
+
const target = transform.target;
|
|
6406
|
+
const local = localPointFromCanvas(target, x, y);
|
|
6407
|
+
const current = ensureBezier(target);
|
|
6408
|
+
const bz = {
|
|
6409
|
+
p0: [...current.p0],
|
|
6410
|
+
c0: [...current.c0],
|
|
6411
|
+
c1: [...current.c1],
|
|
6412
|
+
p1: [...current.p1]
|
|
6413
|
+
};
|
|
6414
|
+
const [mx, my] = bezierMidpoint(bz);
|
|
6415
|
+
const oldV = midTangentVector(bz);
|
|
6416
|
+
const nvx = (local.x - mx) * side;
|
|
6417
|
+
const nvy = (local.y - my) * side;
|
|
6418
|
+
const oldLen2 = oldV.vx * oldV.vx + oldV.vy * oldV.vy;
|
|
6419
|
+
if (oldLen2 < 1e-6) return true;
|
|
6420
|
+
const a = (oldV.vx * nvx + oldV.vy * nvy) / oldLen2;
|
|
6421
|
+
const b = (oldV.vx * nvy - oldV.vy * nvx) / oldLen2;
|
|
6422
|
+
const apply = (px, py) => {
|
|
6423
|
+
const rx = px - mx;
|
|
6424
|
+
const ry = py - my;
|
|
6425
|
+
return [mx + a * rx - b * ry, my + b * rx + a * ry];
|
|
6426
|
+
};
|
|
6427
|
+
bz.c0 = apply(bz.c0[0], bz.c0[1]);
|
|
6428
|
+
bz.c1 = apply(bz.c1[0], bz.c1[1]);
|
|
6429
|
+
target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
|
|
6430
|
+
target.dirty = true;
|
|
6431
|
+
(_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6432
|
+
return true;
|
|
6433
|
+
};
|
|
6434
|
+
const makeDrag = (key) => (_e2, transform, x, y) => {
|
|
6435
|
+
var _a2;
|
|
6436
|
+
const target = transform.target;
|
|
6437
|
+
const local = localPointFromCanvas(target, x, y);
|
|
6438
|
+
const current = ensureBezier(target);
|
|
6439
|
+
const bz = { p0: [...current.p0], c0: [...current.c0], c1: [...current.c1], p1: [...current.p1] };
|
|
6440
|
+
if (key === "p0" || key === "p1") {
|
|
6441
|
+
const ctrlKey = key === "p0" ? "c0" : "c1";
|
|
6442
|
+
const oldAnchor = bz[key];
|
|
6443
|
+
const oldCtrl = bz[ctrlKey];
|
|
6444
|
+
const dx = local.x - oldAnchor[0];
|
|
6445
|
+
const dy = local.y - oldAnchor[1];
|
|
6446
|
+
bz[key] = [local.x, local.y];
|
|
6447
|
+
bz[ctrlKey] = [oldCtrl[0] + dx, oldCtrl[1] + dy];
|
|
6448
|
+
} else {
|
|
6449
|
+
bz[key] = [local.x, local.y];
|
|
6450
|
+
}
|
|
6451
|
+
target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
|
|
6452
|
+
target.dirty = true;
|
|
6453
|
+
(_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6454
|
+
return true;
|
|
6455
|
+
};
|
|
6456
|
+
const makeMidDrag = () => (_e2, transform, x, y) => {
|
|
6457
|
+
var _a2;
|
|
6458
|
+
const target = transform.target;
|
|
6459
|
+
const local = localPointFromCanvas(target, x, y);
|
|
6460
|
+
const current = ensureBezier(target);
|
|
6461
|
+
const bz = {
|
|
6462
|
+
p0: [...current.p0],
|
|
6463
|
+
c0: [...current.c0],
|
|
6464
|
+
c1: [...current.c1],
|
|
6465
|
+
p1: [...current.p1]
|
|
6466
|
+
};
|
|
6467
|
+
const [mx, my] = bezierMidpoint(bz);
|
|
6468
|
+
const dx = (local.x - mx) / 0.75;
|
|
6469
|
+
const dy = (local.y - my) / 0.75;
|
|
6470
|
+
bz.c0 = [bz.c0[0] + dx, bz.c0[1] + dy];
|
|
6471
|
+
bz.c1 = [bz.c1[0] + dx, bz.c1[1] + dy];
|
|
6472
|
+
target.textPath = { ...target.textPath || { preset: "custom" }, bezier: bz };
|
|
6473
|
+
target.dirty = true;
|
|
6474
|
+
(_a2 = target.canvas) == null ? void 0 : _a2.requestRenderAll();
|
|
6475
|
+
return true;
|
|
6476
|
+
};
|
|
6477
|
+
const renderAnchor = (ctx, left, top) => {
|
|
6478
|
+
ctx.save();
|
|
6479
|
+
ctx.translate(left, top);
|
|
6480
|
+
ctx.shadowColor = "rgba(0,0,0,0.25)";
|
|
6481
|
+
ctx.shadowBlur = 2;
|
|
6482
|
+
ctx.shadowOffsetY = 0.5;
|
|
6483
|
+
ctx.fillStyle = "#ffffff";
|
|
6484
|
+
ctx.strokeStyle = "#1d9bf0";
|
|
6485
|
+
ctx.lineWidth = 1.5;
|
|
6486
|
+
ctx.beginPath();
|
|
6487
|
+
ctx.arc(0, 0, 5, 0, Math.PI * 2);
|
|
6488
|
+
ctx.fill();
|
|
6489
|
+
ctx.shadowColor = "transparent";
|
|
6490
|
+
ctx.stroke();
|
|
6491
|
+
ctx.restore();
|
|
6492
|
+
};
|
|
6493
|
+
const renderControlHandle = (ctx, left, top) => {
|
|
6494
|
+
ctx.save();
|
|
6495
|
+
ctx.translate(left, top);
|
|
6496
|
+
ctx.shadowColor = "rgba(0,0,0,0.25)";
|
|
6497
|
+
ctx.shadowBlur = 2;
|
|
6498
|
+
ctx.shadowOffsetY = 0.5;
|
|
6499
|
+
ctx.fillStyle = "#1d9bf0";
|
|
6500
|
+
ctx.strokeStyle = "#ffffff";
|
|
6501
|
+
ctx.lineWidth = 1.5;
|
|
6502
|
+
ctx.beginPath();
|
|
6503
|
+
ctx.arc(0, 0, 4, 0, Math.PI * 2);
|
|
6504
|
+
ctx.fill();
|
|
6505
|
+
ctx.shadowColor = "transparent";
|
|
6506
|
+
ctx.stroke();
|
|
6507
|
+
ctx.restore();
|
|
6508
|
+
};
|
|
6509
|
+
obj.controls.bzP0 = new fabric__namespace.Control({ x: -0.5, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("p0"), positionHandler: positionAtBezier("p0"), render: renderAnchor });
|
|
6510
|
+
obj.controls.bzP1 = new fabric__namespace.Control({ x: 0.5, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("p1"), positionHandler: positionAtBezier("p1"), render: renderAnchor });
|
|
6511
|
+
obj.controls.bzC0 = new fabric__namespace.Control({ x: -0.25, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("c0"), positionHandler: positionAtBezier("c0"), render: renderControlHandle });
|
|
6512
|
+
obj.controls.bzC1 = new fabric__namespace.Control({ x: 0.25, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeDrag("c1"), positionHandler: positionAtBezier("c1"), render: renderControlHandle });
|
|
6513
|
+
obj.controls.bzMid = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidDrag(), positionHandler: positionAtMid, render: renderAnchor });
|
|
6514
|
+
obj.controls.bzMidT0 = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(-1), positionHandler: positionAtMidTangent(-1), render: renderControlHandle });
|
|
6515
|
+
obj.controls.bzMidT1 = new fabric__namespace.Control({ x: 0, y: 0, cursorStyle: "move", actionName: "textPath", actionHandler: makeMidTangentDrag(1), positionHandler: positionAtMidTangent(1), render: renderControlHandle });
|
|
6516
|
+
(_l = obj.setControlVisible) == null ? void 0 : _l.call(obj, "bzP0", true);
|
|
6517
|
+
(_m = obj.setControlVisible) == null ? void 0 : _m.call(obj, "bzC0", true);
|
|
6518
|
+
(_n = obj.setControlVisible) == null ? void 0 : _n.call(obj, "bzC1", true);
|
|
6519
|
+
(_o = obj.setControlVisible) == null ? void 0 : _o.call(obj, "bzP1", true);
|
|
6520
|
+
(_p = obj.setControlVisible) == null ? void 0 : _p.call(obj, "bzMid", true);
|
|
6521
|
+
(_q = obj.setControlVisible) == null ? void 0 : _q.call(obj, "bzMidT0", true);
|
|
6522
|
+
(_r = obj.setControlVisible) == null ? void 0 : _r.call(obj, "bzMidT1", true);
|
|
6523
|
+
addRotationAndPivot();
|
|
6524
|
+
obj.hasBorders = false;
|
|
6525
|
+
obj.hasControls = true;
|
|
6526
|
+
obj.__pdTextPathControls = true;
|
|
6527
|
+
obj.setCoords();
|
|
6528
|
+
}
|
|
6529
|
+
function computeWarpBoundsLocal(obj) {
|
|
6530
|
+
const resolved = resolveTextPath(obj.textPath, obj.width || 0, obj.fontSize || 16);
|
|
6531
|
+
const path = resolved ? measurePath(resolved.d) : null;
|
|
6532
|
+
if (!path) return null;
|
|
6533
|
+
const len = path.getTotalLength();
|
|
6534
|
+
if (!Number.isFinite(len) || len <= 0) return null;
|
|
6535
|
+
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
6536
|
+
const steps = 96;
|
|
6537
|
+
for (let i = 0; i <= steps; i++) {
|
|
6538
|
+
const p = path.getPointAtLength(len * i / steps);
|
|
6539
|
+
if (p.x < minX) minX = p.x;
|
|
6540
|
+
if (p.x > maxX) maxX = p.x;
|
|
6541
|
+
if (p.y < minY) minY = p.y;
|
|
6542
|
+
if (p.y > maxY) maxY = p.y;
|
|
6543
|
+
}
|
|
6544
|
+
const fs = obj.fontSize || 16;
|
|
6545
|
+
const halfW = (obj.width || 0) / 2;
|
|
6546
|
+
const halfH = (obj.height || 0) / 2;
|
|
6547
|
+
return {
|
|
6548
|
+
minX: minX - fs * 0.2 - halfW,
|
|
6549
|
+
maxX: maxX + fs * 0.2 - halfW,
|
|
6550
|
+
minY: minY - fs * 1.05 - halfH,
|
|
6551
|
+
maxY: maxY + fs * 0.35 - halfH
|
|
6552
|
+
};
|
|
6553
|
+
}
|
|
6554
|
+
function computeCircleWarpBoundsLocal(obj) {
|
|
6555
|
+
var _a;
|
|
6556
|
+
if (((_a = obj.textPath) == null ? void 0 : _a.preset) !== "circle") return null;
|
|
6557
|
+
const fs = obj.fontSize || 16;
|
|
6558
|
+
const w = obj.width || 0;
|
|
6559
|
+
const auto = Math.max(fs * 1.5, w / Math.PI);
|
|
6560
|
+
const rRaw = obj.textPath.radius;
|
|
6561
|
+
const r = Math.max(fs * 0.75, Number.isFinite(rRaw) && rRaw > 0 ? rRaw : auto);
|
|
6562
|
+
const halfW = w / 2;
|
|
6563
|
+
const halfH = (obj.height || 0) / 2;
|
|
6564
|
+
const cx = r - halfW;
|
|
6565
|
+
const cy = r - halfH;
|
|
6566
|
+
return { minX: cx - r - fs * 0.2, maxX: cx + r + fs * 0.2, minY: cy - r - fs * 0.6, maxY: cy + r + fs * 0.6 };
|
|
6567
|
+
}
|
|
6568
|
+
function getTextPathHitBounds(obj) {
|
|
6569
|
+
var _a;
|
|
6570
|
+
return ((_a = obj.textPath) == null ? void 0 : _a.preset) === "circle" ? computeCircleWarpBoundsLocal(obj) : computeWarpBoundsLocal(obj);
|
|
6571
|
+
}
|
|
6572
|
+
function textPathBoundsContainScenePoint(obj, point) {
|
|
6573
|
+
const bounds = getTextPathHitBounds(obj);
|
|
6574
|
+
if (!bounds) return false;
|
|
6575
|
+
try {
|
|
6576
|
+
const inv = fabric__namespace.util.invertTransform(obj.calcTransformMatrix());
|
|
6577
|
+
const local = fabric__namespace.util.transformPoint(point, inv);
|
|
6578
|
+
return local.x >= bounds.minX && local.x <= bounds.maxX && local.y >= bounds.minY && local.y <= bounds.maxY;
|
|
6579
|
+
} catch {
|
|
6580
|
+
return false;
|
|
6581
|
+
}
|
|
6582
|
+
}
|
|
6583
|
+
function drawTextPathBounds(ctx, obj, bounds) {
|
|
6584
|
+
var _a;
|
|
6585
|
+
if (!obj.canvas) return;
|
|
6586
|
+
const retina = ((_a = obj.getCanvasRetinaScaling) == null ? void 0 : _a.call(obj)) || 1;
|
|
6587
|
+
const matrix = fabric__namespace.util.multiplyTransformMatrices(obj.canvas.viewportTransform || [1, 0, 0, 1, 0, 0], obj.calcTransformMatrix());
|
|
6588
|
+
const corners = [
|
|
6589
|
+
new fabric__namespace.Point(bounds.minX, bounds.minY),
|
|
6590
|
+
new fabric__namespace.Point(bounds.maxX, bounds.minY),
|
|
6591
|
+
new fabric__namespace.Point(bounds.maxX, bounds.maxY),
|
|
6592
|
+
new fabric__namespace.Point(bounds.minX, bounds.maxY)
|
|
6593
|
+
].map((p) => fabric__namespace.util.transformPoint(p, matrix));
|
|
6594
|
+
ctx.save();
|
|
6595
|
+
ctx.setTransform(retina, 0, 0, retina, 0, 0);
|
|
6596
|
+
ctx.strokeStyle = "rgba(29, 155, 240, 0.9)";
|
|
6597
|
+
ctx.lineWidth = 1.25;
|
|
6598
|
+
ctx.setLineDash([5, 4]);
|
|
6599
|
+
ctx.beginPath();
|
|
6600
|
+
ctx.moveTo(corners[0].x, corners[0].y);
|
|
6601
|
+
for (let i = 1; i < corners.length; i++) ctx.lineTo(corners[i].x, corners[i].y);
|
|
6602
|
+
ctx.closePath();
|
|
6603
|
+
ctx.stroke();
|
|
6604
|
+
ctx.restore();
|
|
6605
|
+
}
|
|
6606
|
+
if (typeof TextboxProto._renderControls === "function" && !TextboxProto.__pixldocsOrigRenderControls) {
|
|
6607
|
+
let drawWarpGuides = function(ctx) {
|
|
6608
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
6609
|
+
if (!this.canvas) return;
|
|
6610
|
+
const hoverBounds = getTextPathHitBounds(this);
|
|
6611
|
+
if (hoverBounds && (this.__pdTextPathHovered || ((_b = (_a = this.canvas).getActiveObject) == null ? void 0 : _b.call(_a)) === this)) {
|
|
6612
|
+
drawTextPathBounds(ctx, this, hoverBounds);
|
|
6613
|
+
}
|
|
6614
|
+
const resolved = resolveTextPath(this.textPath, this.width || 0, this.fontSize || 16);
|
|
6615
|
+
const path = resolved ? measurePath(resolved.d) : null;
|
|
6616
|
+
if (!path) return;
|
|
6617
|
+
const len = path.getTotalLength();
|
|
6618
|
+
if (!Number.isFinite(len) || len <= 0) return;
|
|
6619
|
+
const retina = ((_c = this.getCanvasRetinaScaling) == null ? void 0 : _c.call(this)) || 1;
|
|
6620
|
+
const matrix = fabric__namespace.util.multiplyTransformMatrices(
|
|
6621
|
+
this.canvas.viewportTransform || [1, 0, 0, 1, 0, 0],
|
|
6622
|
+
this.calcTransformMatrix()
|
|
6623
|
+
);
|
|
6624
|
+
const halfW = (this.width || 0) / 2;
|
|
6625
|
+
const halfH = (this.height || 0) / 2;
|
|
6626
|
+
const toScreen = (t) => {
|
|
6627
|
+
const p = path.getPointAtLength(Math.max(0, Math.min(len, len * t)));
|
|
6628
|
+
return fabric__namespace.util.transformPoint(new fabric__namespace.Point(p.x - halfW, p.y - halfH), matrix);
|
|
6629
|
+
};
|
|
6630
|
+
const toScreenXY = (x, y) => fabric__namespace.util.transformPoint(new fabric__namespace.Point(x, y), matrix);
|
|
6631
|
+
ctx.save();
|
|
6632
|
+
ctx.setTransform(retina, 0, 0, retina, 0, 0);
|
|
6633
|
+
const isCircle = ((_d = this.textPath) == null ? void 0 : _d.preset) === "circle";
|
|
6634
|
+
const isAngle = ((_e = this.textPath) == null ? void 0 : _e.preset) === "rise" || ((_f = this.textPath) == null ? void 0 : _f.preset) === "angle";
|
|
6635
|
+
ctx.strokeStyle = "rgba(29, 155, 240, 0.95)";
|
|
6636
|
+
ctx.lineWidth = 1.25;
|
|
6637
|
+
ctx.setLineDash([]);
|
|
6638
|
+
if (isAngle) {
|
|
6639
|
+
const tp = this.textPath;
|
|
6640
|
+
const w = this.width || 0;
|
|
6641
|
+
const fs = this.fontSize || 16;
|
|
6642
|
+
const ep = tp.endpoints;
|
|
6643
|
+
const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : fs * 1.5;
|
|
6644
|
+
const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : fs * 0.5;
|
|
6645
|
+
const a = toScreenXY(0 - halfW, leftY - halfH);
|
|
6646
|
+
const b = toScreenXY(w - halfW, rightY - halfH);
|
|
6647
|
+
ctx.beginPath();
|
|
6648
|
+
ctx.moveTo(a.x, a.y);
|
|
6649
|
+
ctx.lineTo(b.x, b.y);
|
|
6650
|
+
ctx.stroke();
|
|
6651
|
+
} else {
|
|
6652
|
+
ctx.beginPath();
|
|
6653
|
+
for (let i = 0; i <= 96; i++) {
|
|
6654
|
+
const p = toScreen(i / 96);
|
|
6655
|
+
if (i === 0) ctx.moveTo(p.x, p.y);
|
|
6656
|
+
else ctx.lineTo(p.x, p.y);
|
|
6657
|
+
}
|
|
6658
|
+
ctx.stroke();
|
|
6659
|
+
}
|
|
6660
|
+
if (isCircle) {
|
|
6661
|
+
const tp = this.textPath || {};
|
|
6662
|
+
const fs = this.fontSize || 16;
|
|
6663
|
+
const w = this.width || 0;
|
|
6664
|
+
const auto = Math.max(fs * 1.5, w / Math.PI);
|
|
6665
|
+
const rRaw = tp.radius;
|
|
6666
|
+
const r = Math.max(fs * 0.75, Number.isFinite(rRaw) && rRaw > 0 ? rRaw : auto);
|
|
6667
|
+
const cx = r - halfW;
|
|
6668
|
+
const cy = r - halfH;
|
|
6669
|
+
const steps = 96;
|
|
6670
|
+
ctx.beginPath();
|
|
6671
|
+
for (let i = 0; i <= steps; i++) {
|
|
6672
|
+
const a = i / steps * Math.PI * 2;
|
|
6673
|
+
const p = toScreenXY(cx + Math.cos(a) * r, cy + Math.sin(a) * r);
|
|
6674
|
+
if (i === 0) ctx.moveTo(p.x, p.y);
|
|
6675
|
+
else ctx.lineTo(p.x, p.y);
|
|
6676
|
+
}
|
|
6677
|
+
ctx.closePath();
|
|
6678
|
+
ctx.stroke();
|
|
6679
|
+
}
|
|
6680
|
+
const bz = isCircle ? null : (_g = this.textPath) == null ? void 0 : _g.bezier;
|
|
6681
|
+
if (bz) {
|
|
6682
|
+
const a = toScreenXY(bz.p0[0] - halfW, bz.p0[1] - halfH);
|
|
6683
|
+
const ah = toScreenXY(bz.c0[0] - halfW, bz.c0[1] - halfH);
|
|
6684
|
+
const b = toScreenXY(bz.p1[0] - halfW, bz.p1[1] - halfH);
|
|
6685
|
+
const bh = toScreenXY(bz.c1[0] - halfW, bz.c1[1] - halfH);
|
|
6686
|
+
ctx.strokeStyle = "rgba(29, 155, 240, 0.7)";
|
|
6687
|
+
ctx.lineWidth = 1;
|
|
6688
|
+
ctx.setLineDash([]);
|
|
6689
|
+
ctx.beginPath();
|
|
6690
|
+
ctx.moveTo(a.x, a.y);
|
|
6691
|
+
ctx.lineTo(ah.x, ah.y);
|
|
6692
|
+
ctx.moveTo(b.x, b.y);
|
|
6693
|
+
ctx.lineTo(bh.x, bh.y);
|
|
6694
|
+
ctx.stroke();
|
|
6695
|
+
const midX = 0.125 * bz.p0[0] + 0.375 * bz.c0[0] + 0.375 * bz.c1[0] + 0.125 * bz.p1[0];
|
|
6696
|
+
const midY = 0.125 * bz.p0[1] + 0.375 * bz.c0[1] + 0.375 * bz.c1[1] + 0.125 * bz.p1[1];
|
|
6697
|
+
let tdx = bz.p1[0] + 3 * bz.c1[0] - 3 * bz.c0[0] - bz.p0[0];
|
|
6698
|
+
let tdy = bz.p1[1] + 3 * bz.c1[1] - 3 * bz.c0[1] - bz.p0[1];
|
|
6699
|
+
const tlen = Math.hypot(tdx, tdy) || 1;
|
|
6700
|
+
tdx /= tlen;
|
|
6701
|
+
tdy /= tlen;
|
|
6702
|
+
const pC1 = (bz.c1[0] - midX) * tdx + (bz.c1[1] - midY) * tdy;
|
|
6703
|
+
const pC0 = (midX - bz.c0[0]) * tdx + (midY - bz.c0[1]) * tdy;
|
|
6704
|
+
const LEG = Math.max(8, (Math.abs(pC1) + Math.abs(pC0)) / 2);
|
|
6705
|
+
const m = toScreenXY(midX - halfW, midY - halfH);
|
|
6706
|
+
const t0 = toScreenXY(midX - tdx * LEG - halfW, midY - tdy * LEG - halfH);
|
|
6707
|
+
const t1 = toScreenXY(midX + tdx * LEG - halfW, midY + tdy * LEG - halfH);
|
|
6708
|
+
ctx.beginPath();
|
|
6709
|
+
ctx.moveTo(m.x, m.y);
|
|
6710
|
+
ctx.lineTo(t0.x, t0.y);
|
|
6711
|
+
ctx.moveTo(m.x, m.y);
|
|
6712
|
+
ctx.lineTo(t1.x, t1.y);
|
|
6713
|
+
ctx.stroke();
|
|
6714
|
+
}
|
|
6715
|
+
ctx.restore();
|
|
6716
|
+
};
|
|
6717
|
+
TextboxProto.__pixldocsOrigRenderControls = TextboxProto._renderControls;
|
|
6718
|
+
TextboxProto._renderControls = function(ctx, styleOverride) {
|
|
6719
|
+
if (hasActiveTextPath(this)) {
|
|
6720
|
+
const prevBorders = this.hasBorders;
|
|
6721
|
+
this.hasBorders = false;
|
|
6722
|
+
try {
|
|
6723
|
+
drawWarpGuides.call(this, ctx);
|
|
6724
|
+
TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
|
|
6725
|
+
} finally {
|
|
6726
|
+
this.hasBorders = prevBorders;
|
|
6727
|
+
}
|
|
6728
|
+
return;
|
|
6729
|
+
}
|
|
6730
|
+
TextboxProto.__pixldocsOrigRenderControls.call(this, ctx, styleOverride);
|
|
6731
|
+
if (!this.canvas) return;
|
|
6732
|
+
};
|
|
6733
|
+
}
|
|
6734
|
+
if (!TextboxProto.__pixldocsOrigRender && typeof TextboxProto._render === "function") {
|
|
6735
|
+
TextboxProto.__pixldocsOrigRender = TextboxProto._render;
|
|
6736
|
+
TextboxProto._render = function(ctx) {
|
|
6737
|
+
const tp = this.textPath;
|
|
6738
|
+
const orig = TextboxProto.__pixldocsOrigRender;
|
|
6739
|
+
if (!hasActiveTextPath(this)) {
|
|
6740
|
+
return orig.call(this, ctx);
|
|
6741
|
+
}
|
|
6742
|
+
if (tp && (tp.preset === "rise" || tp.preset === "angle")) {
|
|
6743
|
+
const w = this.width || 0;
|
|
6744
|
+
const h = this.height || 0;
|
|
6745
|
+
const fs2 = this.fontSize || 16;
|
|
6746
|
+
const ep = tp.endpoints;
|
|
6747
|
+
const defaultLeftY = fs2 * 1.5;
|
|
6748
|
+
const defaultRightY = fs2 * 0.5;
|
|
6749
|
+
const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
|
|
6750
|
+
const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
|
|
6751
|
+
const slope = w > 0 ? (rightY - leftY) / w : 0;
|
|
6752
|
+
const dy = (leftY + rightY) / 2 - h / 2;
|
|
6753
|
+
ctx.save();
|
|
6754
|
+
ctx.transform(1, slope, 0, 1, 0, dy);
|
|
6755
|
+
orig.call(this, ctx);
|
|
6756
|
+
ctx.restore();
|
|
6757
|
+
return;
|
|
6758
|
+
}
|
|
6759
|
+
const resolved = resolveTextPath(tp, this.width || 0, this.fontSize || 16);
|
|
6760
|
+
if (!resolved) return orig.call(this, ctx);
|
|
6761
|
+
const pathEl = measurePath(resolved.d);
|
|
6762
|
+
if (!pathEl) return orig.call(this, ctx);
|
|
6763
|
+
const totalLen = pathEl.getTotalLength();
|
|
6764
|
+
if (!Number.isFinite(totalLen) || totalLen <= 0) return orig.call(this, ctx);
|
|
6765
|
+
const plain = String(this.text || "").replace(/\n/g, " ");
|
|
6766
|
+
if (!plain) return;
|
|
6767
|
+
const weight = this.fontWeight || 400;
|
|
6768
|
+
const style = this.fontStyle || "normal";
|
|
6769
|
+
const family = this.fontFamily || "Open Sans";
|
|
6770
|
+
const fs = this.fontSize || 16;
|
|
6771
|
+
ctx.save();
|
|
6772
|
+
ctx.font = `${style} ${weight} ${fs}px "${family}"`;
|
|
6773
|
+
ctx.textAlign = "center";
|
|
6774
|
+
ctx.textBaseline = "alphabetic";
|
|
6775
|
+
const chars = Array.from(plain);
|
|
6776
|
+
const spacing = (this.charSpacing || 0) * fs / 1e3;
|
|
6777
|
+
const widths = chars.map((c) => ctx.measureText(c).width + spacing);
|
|
6778
|
+
const totalWidth = widths.reduce((a, b) => a + b, 0);
|
|
6779
|
+
const baselineDy = resolveTextPathAlphabeticBaselineDy(ctx, plain, fs);
|
|
6780
|
+
let cursor;
|
|
6781
|
+
if (this.textAlign === "center") cursor = Math.max(0, (totalLen - totalWidth) / 2);
|
|
6782
|
+
else if (this.textAlign === "right") cursor = Math.max(0, totalLen - totalWidth);
|
|
6783
|
+
else cursor = 0;
|
|
6784
|
+
const flowStops = getGradientStopsForFlow(this);
|
|
6785
|
+
const fillOffsets = flowStops ? { offsetX: 0, offsetY: 0 } : applyWarpFillStyle(ctx, this);
|
|
6786
|
+
const halfW = (this.width || 0) / 2;
|
|
6787
|
+
const halfH = (this.height || 0) / 2;
|
|
6788
|
+
const strokeColor = this.stroke;
|
|
6789
|
+
const strokeWidth = Number(this.strokeWidth) || 0;
|
|
6790
|
+
const hasStroke = !!strokeColor && strokeColor !== "transparent" && strokeWidth > 0;
|
|
6791
|
+
if (hasStroke) {
|
|
6792
|
+
ctx.strokeStyle = String(strokeColor);
|
|
6793
|
+
ctx.lineWidth = strokeWidth;
|
|
6794
|
+
ctx.lineJoin = "round";
|
|
6795
|
+
ctx.miterLimit = 4;
|
|
6796
|
+
}
|
|
6797
|
+
for (let i = 0; i < chars.length; i++) {
|
|
6798
|
+
const ch = chars[i];
|
|
6799
|
+
const cw = widths[i];
|
|
6800
|
+
const mid = cursor + cw / 2;
|
|
6801
|
+
cursor += cw;
|
|
6802
|
+
if (mid > totalLen) break;
|
|
6803
|
+
const p = pathEl.getPointAtLength(Math.max(0, mid));
|
|
6804
|
+
const ahead = pathEl.getPointAtLength(Math.min(totalLen, mid + 0.5));
|
|
6805
|
+
const angle = Math.atan2(ahead.y - p.y, ahead.x - p.x);
|
|
6806
|
+
if (flowStops) {
|
|
6807
|
+
const tt = chars.length > 1 ? i / (chars.length - 1) : 0;
|
|
6808
|
+
ctx.fillStyle = sampleGradientColor(flowStops, tt);
|
|
6809
|
+
}
|
|
6810
|
+
ctx.save();
|
|
6811
|
+
ctx.translate(p.x - halfW - fillOffsets.offsetX, p.y - halfH - fillOffsets.offsetY);
|
|
6812
|
+
ctx.rotate(angle);
|
|
6813
|
+
ctx.fillText(ch, 0, baselineDy);
|
|
6814
|
+
if (hasStroke) ctx.strokeText(ch, 0, baselineDy);
|
|
6815
|
+
ctx.restore();
|
|
6816
|
+
}
|
|
6817
|
+
ctx.restore();
|
|
6818
|
+
};
|
|
5762
6819
|
}
|
|
5763
6820
|
TextboxProto.__pixldocsTextboxExtended = true;
|
|
6821
|
+
const TextboxProtoHit = fabric__namespace.Textbox.prototype;
|
|
6822
|
+
if (!TextboxProtoHit.__pixldocsOrigGetCoords && typeof TextboxProtoHit.getCoords === "function") {
|
|
6823
|
+
TextboxProtoHit.__pixldocsOrigGetCoords = TextboxProtoHit.getCoords;
|
|
6824
|
+
TextboxProtoHit.getCoords = function() {
|
|
6825
|
+
if (!hasActiveTextPath(this)) return TextboxProtoHit.__pixldocsOrigGetCoords.call(this);
|
|
6826
|
+
const bounds = getTextPathHitBounds(this);
|
|
6827
|
+
if (!bounds) return TextboxProtoHit.__pixldocsOrigGetCoords.call(this);
|
|
6828
|
+
const matrix = this.calcTransformMatrix();
|
|
6829
|
+
const coords = [
|
|
6830
|
+
new fabric__namespace.Point(bounds.minX, bounds.minY),
|
|
6831
|
+
new fabric__namespace.Point(bounds.maxX, bounds.minY),
|
|
6832
|
+
new fabric__namespace.Point(bounds.maxX, bounds.maxY),
|
|
6833
|
+
new fabric__namespace.Point(bounds.minX, bounds.maxY)
|
|
6834
|
+
].map((p) => fabric__namespace.util.transformPoint(p, matrix));
|
|
6835
|
+
if (this.group) {
|
|
6836
|
+
const groupMatrix = this.group.calcTransformMatrix();
|
|
6837
|
+
return coords.map((p) => fabric__namespace.util.transformPoint(p, groupMatrix));
|
|
6838
|
+
}
|
|
6839
|
+
return coords;
|
|
6840
|
+
};
|
|
6841
|
+
}
|
|
6842
|
+
if (!TextboxProtoHit.__pixldocsOrigContainsPoint && typeof TextboxProtoHit.containsPoint === "function") {
|
|
6843
|
+
TextboxProtoHit.__pixldocsOrigContainsPoint = TextboxProtoHit.containsPoint;
|
|
6844
|
+
TextboxProtoHit.containsPoint = function(point) {
|
|
6845
|
+
const origHit = TextboxProtoHit.__pixldocsOrigContainsPoint.call(this, point);
|
|
6846
|
+
if (origHit) return true;
|
|
6847
|
+
if (!hasActiveTextPath(this)) return false;
|
|
6848
|
+
return textPathBoundsContainScenePoint(this, point);
|
|
6849
|
+
};
|
|
6850
|
+
}
|
|
5764
6851
|
const PD_BG_KEY = "__pdBg";
|
|
5765
6852
|
const PATCHED_KEY = "__pdBgPatched";
|
|
6853
|
+
const LINE_SHADOW_STROKE_WIDTH = 0.5;
|
|
5766
6854
|
function extractTextBgConfig(element) {
|
|
5767
6855
|
const legacy = Math.max(0, Number(element.textBgPadding ?? 0)) || 0;
|
|
5768
6856
|
const pick = (v) => {
|
|
5769
6857
|
const n = Number(v);
|
|
5770
6858
|
return Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
5771
6859
|
};
|
|
6860
|
+
const grad = element.textBgGradient;
|
|
5772
6861
|
return {
|
|
5773
6862
|
color: element.textBgColor,
|
|
6863
|
+
gradient: isGradientConfig(grad) && grad.stops && grad.stops.length >= 2 ? grad : void 0,
|
|
5774
6864
|
padTop: pick(element.textBgPaddingTop) ?? legacy,
|
|
5775
6865
|
padRight: pick(element.textBgPaddingRight) ?? legacy,
|
|
5776
6866
|
padBottom: pick(element.textBgPaddingBottom) ?? legacy,
|
|
@@ -5786,11 +6876,16 @@ function extractTextBgConfig(element) {
|
|
|
5786
6876
|
})(),
|
|
5787
6877
|
shadowAffectsBg: element.textShadowAffectsBg !== false,
|
|
5788
6878
|
shadowAffectsText: element.textShadowAffectsText !== false,
|
|
5789
|
-
fitToText: element.textBgFitToText === true
|
|
6879
|
+
fitToText: element.textBgFitToText === true,
|
|
6880
|
+
shadowType: element.textShadowType,
|
|
6881
|
+
shadowColor: element.textShadowColor,
|
|
6882
|
+
shadowOffsetX: Number(element.textShadowOffsetX ?? 0) || 0,
|
|
6883
|
+
shadowOffsetY: Number(element.textShadowOffsetY ?? 0) || 0
|
|
5790
6884
|
};
|
|
5791
6885
|
}
|
|
5792
6886
|
function hasTextBackground(cfg) {
|
|
5793
6887
|
if (!cfg) return false;
|
|
6888
|
+
if (cfg.gradient && cfg.gradient.stops && cfg.gradient.stops.length >= 2) return true;
|
|
5794
6889
|
const c = (cfg.color || "").toString().trim().toLowerCase();
|
|
5795
6890
|
return !!c && c !== "transparent" && c !== "none" && c !== "rgba(0,0,0,0)";
|
|
5796
6891
|
}
|
|
@@ -5800,6 +6895,8 @@ function buildTextShadow(element) {
|
|
|
5800
6895
|
const ox = Number(element.textShadowOffsetX ?? 0);
|
|
5801
6896
|
const oy = Number(element.textShadowOffsetY ?? 0);
|
|
5802
6897
|
if (!color || color === "transparent") return null;
|
|
6898
|
+
const type = element.textShadowType;
|
|
6899
|
+
if (type && type !== "drop") return null;
|
|
5803
6900
|
return new fabric__namespace.Shadow({
|
|
5804
6901
|
color: String(color),
|
|
5805
6902
|
blur: blur || 0,
|
|
@@ -5830,11 +6927,35 @@ function buildRoundedRectPath2D(ctx, x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
|
5830
6927
|
function applyTextBackground(obj, cfg) {
|
|
5831
6928
|
var _a;
|
|
5832
6929
|
obj[PD_BG_KEY] = { ...cfg };
|
|
6930
|
+
try {
|
|
6931
|
+
const hasOffset = (Number(cfg == null ? void 0 : cfg.shadowOffsetX) || 0) !== 0 || (Number(cfg == null ? void 0 : cfg.shadowOffsetY) || 0) !== 0;
|
|
6932
|
+
const isLineOrBlock = (cfg == null ? void 0 : cfg.shadowType) === "line" || (cfg == null ? void 0 : cfg.shadowType) === "block";
|
|
6933
|
+
if (isLineOrBlock && hasOffset && !!(cfg == null ? void 0 : cfg.shadowColor) && cfg.shadowColor !== "transparent") {
|
|
6934
|
+
obj.objectCaching = false;
|
|
6935
|
+
obj.dirty = true;
|
|
6936
|
+
}
|
|
6937
|
+
} catch {
|
|
6938
|
+
}
|
|
5833
6939
|
if (obj[PATCHED_KEY]) return;
|
|
5834
6940
|
obj[PATCHED_KEY] = true;
|
|
5835
6941
|
const originalRender = obj._render.bind(obj);
|
|
5836
6942
|
obj._render = function(ctx) {
|
|
5837
6943
|
const bg = this[PD_BG_KEY];
|
|
6944
|
+
const extOX = Number((bg == null ? void 0 : bg.shadowOffsetX) ?? 0) || 0;
|
|
6945
|
+
const extOY = Number((bg == null ? void 0 : bg.shadowOffsetY) ?? 0) || 0;
|
|
6946
|
+
const extDist = Math.hypot(extOX, extOY);
|
|
6947
|
+
const hasShadowColor = !!(bg == null ? void 0 : bg.shadowColor) && bg.shadowColor !== "transparent";
|
|
6948
|
+
const blockShadowActive = !!bg && bg.shadowType === "block" && hasShadowColor && extDist > 0;
|
|
6949
|
+
const lineShadowActive = !!bg && bg.shadowType === "line" && hasShadowColor && extDist > 0;
|
|
6950
|
+
let blockSteps = 0;
|
|
6951
|
+
let blockStepX = 0;
|
|
6952
|
+
let blockStepY = 0;
|
|
6953
|
+
if (blockShadowActive) {
|
|
6954
|
+
const STEP = 0.5;
|
|
6955
|
+
blockSteps = Math.min(600, Math.max(1, Math.ceil(extDist / STEP)));
|
|
6956
|
+
blockStepX = extOX / blockSteps;
|
|
6957
|
+
blockStepY = extOY / blockSteps;
|
|
6958
|
+
}
|
|
5838
6959
|
if (hasTextBackground(bg)) {
|
|
5839
6960
|
const w = this.width ?? 0;
|
|
5840
6961
|
const h = this.height ?? 0;
|
|
@@ -5852,24 +6973,172 @@ function applyTextBackground(obj, cfg) {
|
|
|
5852
6973
|
}
|
|
5853
6974
|
const op = typeof bg.opacity === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
|
|
5854
6975
|
if (op < 1) ctx.globalAlpha = (ctx.globalAlpha ?? 1) * op;
|
|
5855
|
-
|
|
5856
|
-
const
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
6976
|
+
const tpAny = this.textPath;
|
|
6977
|
+
const isShear = tpAny && (tpAny.preset === "rise" || tpAny.preset === "angle");
|
|
6978
|
+
const ribbonD = !isShear ? buildWarpRibbonD(
|
|
6979
|
+
this,
|
|
6980
|
+
pT,
|
|
6981
|
+
pR,
|
|
6982
|
+
pB,
|
|
6983
|
+
pL,
|
|
6984
|
+
bg.rxTL ?? 0,
|
|
6985
|
+
bg.rxTR ?? 0,
|
|
6986
|
+
bg.rxBR ?? 0,
|
|
6987
|
+
bg.rxBL ?? 0
|
|
6988
|
+
) : null;
|
|
6989
|
+
let bgBounds;
|
|
6990
|
+
let bgRectsForFill = null;
|
|
6991
|
+
if (ribbonD) {
|
|
6992
|
+
bgBounds = computeRibbonBoundsFor(this, pT, pR, pB, pL);
|
|
6993
|
+
} else {
|
|
6994
|
+
bgRectsForFill = computeBgRects(this, w, h, pT, pR, pB, pL, !!bg.fitToText);
|
|
6995
|
+
bgBounds = unionBounds(bgRectsForFill);
|
|
6996
|
+
}
|
|
6997
|
+
if (blockShadowActive && bg.shadowAffectsBg !== false) {
|
|
6998
|
+
ctx.save();
|
|
6999
|
+
ctx.fillStyle = bg.shadowColor;
|
|
7000
|
+
for (let i = blockSteps; i >= 1; i--) {
|
|
7001
|
+
ctx.save();
|
|
7002
|
+
ctx.translate(blockStepX * i, blockStepY * i);
|
|
7003
|
+
if (ribbonD) {
|
|
7004
|
+
try {
|
|
7005
|
+
ctx.fill(new Path2D(ribbonD));
|
|
7006
|
+
} catch {
|
|
7007
|
+
}
|
|
7008
|
+
} else {
|
|
7009
|
+
const rects = bgRectsForFill;
|
|
7010
|
+
for (const r of rects) {
|
|
7011
|
+
buildRoundedRectPath2D(
|
|
7012
|
+
ctx,
|
|
7013
|
+
r.x,
|
|
7014
|
+
r.y,
|
|
7015
|
+
r.w,
|
|
7016
|
+
r.h,
|
|
7017
|
+
bg.rxTL ?? 0,
|
|
7018
|
+
bg.rxTR ?? 0,
|
|
7019
|
+
bg.rxBR ?? 0,
|
|
7020
|
+
bg.rxBL ?? 0
|
|
7021
|
+
);
|
|
7022
|
+
ctx.fill();
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
ctx.restore();
|
|
7026
|
+
}
|
|
7027
|
+
ctx.restore();
|
|
7028
|
+
}
|
|
7029
|
+
if (lineShadowActive && bg.shadowAffectsBg !== false) {
|
|
7030
|
+
ctx.save();
|
|
7031
|
+
ctx.translate(extOX, extOY);
|
|
7032
|
+
ctx.strokeStyle = bg.shadowColor;
|
|
7033
|
+
ctx.lineWidth = 1;
|
|
7034
|
+
ctx.lineJoin = "round";
|
|
7035
|
+
if (ribbonD) {
|
|
7036
|
+
try {
|
|
7037
|
+
ctx.stroke(new Path2D(ribbonD));
|
|
7038
|
+
} catch {
|
|
7039
|
+
}
|
|
7040
|
+
} else {
|
|
7041
|
+
const rects = bgRectsForFill;
|
|
7042
|
+
for (const r of rects) {
|
|
7043
|
+
buildRoundedRectPath2D(
|
|
7044
|
+
ctx,
|
|
7045
|
+
r.x,
|
|
7046
|
+
r.y,
|
|
7047
|
+
r.w,
|
|
7048
|
+
r.h,
|
|
7049
|
+
bg.rxTL ?? 0,
|
|
7050
|
+
bg.rxTR ?? 0,
|
|
7051
|
+
bg.rxBR ?? 0,
|
|
7052
|
+
bg.rxBL ?? 0
|
|
7053
|
+
);
|
|
7054
|
+
ctx.stroke();
|
|
7055
|
+
}
|
|
7056
|
+
}
|
|
7057
|
+
ctx.restore();
|
|
7058
|
+
}
|
|
7059
|
+
ctx.fillStyle = bg.gradient ? buildCanvasGradient(ctx, bg.gradient, bgBounds.x, bgBounds.y, bgBounds.w, bgBounds.h) : bg.color || "#000";
|
|
7060
|
+
if (ribbonD) {
|
|
7061
|
+
try {
|
|
7062
|
+
const p2 = new Path2D(ribbonD);
|
|
7063
|
+
ctx.fill(p2);
|
|
7064
|
+
} catch {
|
|
7065
|
+
}
|
|
7066
|
+
} else {
|
|
7067
|
+
if (isShear) {
|
|
7068
|
+
const fs = this.fontSize || 16;
|
|
7069
|
+
const ep = tpAny.endpoints;
|
|
7070
|
+
const dL = fs * 1.5;
|
|
7071
|
+
const dR = fs * 0.5;
|
|
7072
|
+
const lY = ep && Number.isFinite(ep.leftY) ? ep.leftY : dL;
|
|
7073
|
+
const rY = ep && Number.isFinite(ep.rightY) ? ep.rightY : dR;
|
|
7074
|
+
const slope = w > 0 ? (rY - lY) / w : 0;
|
|
7075
|
+
const dy = (lY + rY) / 2 - h / 2;
|
|
7076
|
+
ctx.transform(1, slope, 0, 1, 0, dy);
|
|
7077
|
+
}
|
|
7078
|
+
const rects = bgRectsForFill;
|
|
7079
|
+
for (const r of rects) {
|
|
7080
|
+
buildRoundedRectPath2D(
|
|
7081
|
+
ctx,
|
|
7082
|
+
r.x,
|
|
7083
|
+
r.y,
|
|
7084
|
+
r.w,
|
|
7085
|
+
r.h,
|
|
7086
|
+
bg.rxTL ?? 0,
|
|
7087
|
+
bg.rxTR ?? 0,
|
|
7088
|
+
bg.rxBR ?? 0,
|
|
7089
|
+
bg.rxBL ?? 0
|
|
7090
|
+
);
|
|
7091
|
+
ctx.fill();
|
|
7092
|
+
}
|
|
5870
7093
|
}
|
|
5871
7094
|
ctx.restore();
|
|
5872
7095
|
}
|
|
7096
|
+
if (blockShadowActive && bg.shadowAffectsText !== false) {
|
|
7097
|
+
const self = this;
|
|
7098
|
+
const origFill = self.fill;
|
|
7099
|
+
const origStyles = self.styles;
|
|
7100
|
+
const origShadow = self.shadow;
|
|
7101
|
+
try {
|
|
7102
|
+
self.fill = bg.shadowColor;
|
|
7103
|
+
self.styles = {};
|
|
7104
|
+
self.shadow = null;
|
|
7105
|
+
for (let i = blockSteps; i >= 1; i--) {
|
|
7106
|
+
ctx.save();
|
|
7107
|
+
ctx.translate(blockStepX * i, blockStepY * i);
|
|
7108
|
+
originalRender(ctx);
|
|
7109
|
+
ctx.restore();
|
|
7110
|
+
}
|
|
7111
|
+
} finally {
|
|
7112
|
+
self.fill = origFill;
|
|
7113
|
+
self.styles = origStyles;
|
|
7114
|
+
self.shadow = origShadow;
|
|
7115
|
+
}
|
|
7116
|
+
}
|
|
7117
|
+
if (lineShadowActive && bg.shadowAffectsText !== false) {
|
|
7118
|
+
const self = this;
|
|
7119
|
+
const origFill = self.fill;
|
|
7120
|
+
const origStroke = self.stroke;
|
|
7121
|
+
const origStrokeWidth = self.strokeWidth;
|
|
7122
|
+
const origStyles = self.styles;
|
|
7123
|
+
const origShadow = self.shadow;
|
|
7124
|
+
try {
|
|
7125
|
+
self.fill = "transparent";
|
|
7126
|
+
self.stroke = bg.shadowColor;
|
|
7127
|
+
self.strokeWidth = LINE_SHADOW_STROKE_WIDTH;
|
|
7128
|
+
self.styles = {};
|
|
7129
|
+
self.shadow = null;
|
|
7130
|
+
ctx.save();
|
|
7131
|
+
ctx.translate(extOX, extOY);
|
|
7132
|
+
originalRender(ctx);
|
|
7133
|
+
ctx.restore();
|
|
7134
|
+
} finally {
|
|
7135
|
+
self.fill = origFill;
|
|
7136
|
+
self.stroke = origStroke;
|
|
7137
|
+
self.strokeWidth = origStrokeWidth;
|
|
7138
|
+
self.styles = origStyles;
|
|
7139
|
+
self.shadow = origShadow;
|
|
7140
|
+
}
|
|
7141
|
+
}
|
|
5873
7142
|
const suppressShadowOnText = bg && bg.shadowAffectsText === false;
|
|
5874
7143
|
if (suppressShadowOnText) {
|
|
5875
7144
|
ctx.save();
|
|
@@ -5888,19 +7157,27 @@ function applyTextBackground(obj, cfg) {
|
|
|
5888
7157
|
const out = originalToObject(propertiesToInclude);
|
|
5889
7158
|
const bg = this[PD_BG_KEY];
|
|
5890
7159
|
if (hasTextBackground(bg)) {
|
|
5891
|
-
out.__pdBg = { ...bg };
|
|
7160
|
+
out.__pdBg = { ...bg, gradient: bg.gradient ? { ...bg.gradient, stops: bg.gradient.stops.map((s) => ({ ...s })) } : void 0 };
|
|
5892
7161
|
}
|
|
5893
7162
|
return out;
|
|
5894
7163
|
};
|
|
5895
7164
|
const originalToSVG = (_a = obj.toSVG) == null ? void 0 : _a.bind(obj);
|
|
5896
7165
|
if (typeof originalToSVG === "function") {
|
|
5897
7166
|
obj.toSVG = function(reviver) {
|
|
7167
|
+
var _a2, _b;
|
|
5898
7168
|
let svg = originalToSVG(reviver);
|
|
5899
7169
|
const bg = this[PD_BG_KEY];
|
|
5900
7170
|
const shadow = this.shadow;
|
|
5901
7171
|
const hasBg = hasTextBackground(bg);
|
|
5902
7172
|
const hasShadow = !!shadow && !!shadow.color && shadow.color !== "transparent";
|
|
5903
|
-
|
|
7173
|
+
const extOX = Number((bg == null ? void 0 : bg.shadowOffsetX) ?? 0) || 0;
|
|
7174
|
+
const extOY = Number((bg == null ? void 0 : bg.shadowOffsetY) ?? 0) || 0;
|
|
7175
|
+
const extDist = Math.hypot(extOX, extOY);
|
|
7176
|
+
const hasExtShadowColor = !!(bg == null ? void 0 : bg.shadowColor) && bg.shadowColor !== "transparent";
|
|
7177
|
+
const hasBlockShadow = !!bg && bg.shadowType === "block" && hasExtShadowColor && extDist > 0;
|
|
7178
|
+
const hasLineShadow = !!bg && bg.shadowType === "line" && hasExtShadowColor && extDist > 0;
|
|
7179
|
+
if (!hasBg && !hasShadow && !hasBlockShadow && !hasLineShadow) return svg;
|
|
7180
|
+
const hasActiveTextPath2 = !!(((_a2 = this.textPath) == null ? void 0 : _a2.preset) && this.textPath.preset !== "none");
|
|
5904
7181
|
const w = this.width ?? 0;
|
|
5905
7182
|
const h = this.height ?? 0;
|
|
5906
7183
|
const pT = Math.max(0, Number((bg == null ? void 0 : bg.padTop) ?? 0));
|
|
@@ -5909,7 +7186,18 @@ function applyTextBackground(obj, cfg) {
|
|
|
5909
7186
|
const pL = Math.max(0, Number((bg == null ? void 0 : bg.padLeft) ?? 0));
|
|
5910
7187
|
const fit = !!(bg == null ? void 0 : bg.fitToText);
|
|
5911
7188
|
const rects = computeBgRects(this, w, h, pT, pR, pB, pL, fit);
|
|
5912
|
-
const
|
|
7189
|
+
const ribbonD = buildWarpRibbonD(
|
|
7190
|
+
this,
|
|
7191
|
+
pT,
|
|
7192
|
+
pR,
|
|
7193
|
+
pB,
|
|
7194
|
+
pL,
|
|
7195
|
+
(bg == null ? void 0 : bg.rxTL) ?? 0,
|
|
7196
|
+
(bg == null ? void 0 : bg.rxTR) ?? 0,
|
|
7197
|
+
(bg == null ? void 0 : bg.rxBR) ?? 0,
|
|
7198
|
+
(bg == null ? void 0 : bg.rxBL) ?? 0
|
|
7199
|
+
);
|
|
7200
|
+
const bgD = ribbonD ?? rects.map((r) => buildRoundedRectPathD(
|
|
5913
7201
|
r.x,
|
|
5914
7202
|
r.y,
|
|
5915
7203
|
r.w,
|
|
@@ -5922,7 +7210,16 @@ function applyTextBackground(obj, cfg) {
|
|
|
5922
7210
|
const bgFill = (bg == null ? void 0 : bg.color) || "";
|
|
5923
7211
|
const bgOpacity = typeof (bg == null ? void 0 : bg.opacity) === "number" ? Math.max(0, Math.min(1, bg.opacity)) : 1;
|
|
5924
7212
|
const bgOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
|
|
5925
|
-
|
|
7213
|
+
let bgGradDefs = "";
|
|
7214
|
+
let bgFillAttr = escapeXmlAttr(bgFill);
|
|
7215
|
+
if (hasBg && (bg == null ? void 0 : bg.gradient) && ((_b = bg.gradient.stops) == null ? void 0 : _b.length) >= 2) {
|
|
7216
|
+
const bounds = ribbonD ? computeRibbonBoundsFor(this, pT, pR, pB, pL) : unionBounds(rects);
|
|
7217
|
+
const gid = `__pdBgGrad_${Math.random().toString(36).slice(2, 9)}`;
|
|
7218
|
+
const def = buildSvgGradientDef(bg.gradient, gid, bounds.x, bounds.y, bounds.w, bounds.h);
|
|
7219
|
+
bgGradDefs = `<defs>${def}</defs>`;
|
|
7220
|
+
bgFillAttr = `url(#${gid})`;
|
|
7221
|
+
}
|
|
7222
|
+
const bgPath = hasBg ? `${bgGradDefs}<path class="__pdTextBgShape" d="${bgD}" fill="${bgFillAttr}"${bgOpacityAttr} />` : "";
|
|
5926
7223
|
svg = svg.replace(/style="[^"]*filter:\s*url\([^)]+\)[^"]*"/i, "");
|
|
5927
7224
|
svg = svg.replace(/<filter[\s\S]*?<\/filter>/gi, "");
|
|
5928
7225
|
let bgShadowMarker = "";
|
|
@@ -5948,14 +7245,63 @@ function applyTextBackground(obj, cfg) {
|
|
|
5948
7245
|
const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}"${shadowOpacityAttr} />`;
|
|
5949
7246
|
bgShadowMarker = wrapShadow(shadowBgPath);
|
|
5950
7247
|
}
|
|
5951
|
-
if ((bg == null ? void 0 : bg.shadowAffectsText) !== false) {
|
|
7248
|
+
if ((bg == null ? void 0 : bg.shadowAffectsText) !== false && !hasActiveTextPath2) {
|
|
5952
7249
|
const inner = extractGInnerMarkup(svg);
|
|
5953
7250
|
const recoloredText = recolorSvgFills(inner, shadowColor);
|
|
5954
7251
|
if (recoloredText) textShadowMarker = wrapShadow(recoloredText);
|
|
5955
7252
|
}
|
|
5956
7253
|
}
|
|
7254
|
+
let bgBlockShadowMarker = "";
|
|
7255
|
+
let textBlockShadowMarker = "";
|
|
7256
|
+
if (hasBlockShadow) {
|
|
7257
|
+
const STEP = 0.5;
|
|
7258
|
+
const steps = Math.min(600, Math.max(1, Math.ceil(extDist / STEP)));
|
|
7259
|
+
const stepX = extOX / steps;
|
|
7260
|
+
const stepY = extOY / steps;
|
|
7261
|
+
const shadowColor = String(bg.shadowColor);
|
|
7262
|
+
const fillObj = this.fill;
|
|
7263
|
+
const parentTextIsGradient = !!fillObj && typeof fillObj === "object" && (Array.isArray(fillObj.colorStops) || fillObj.type === "linear" || fillObj.type === "radial");
|
|
7264
|
+
const cloneOutlineAttr = parentTextIsGradient ? ' data-pd-outline-text="1"' : "";
|
|
7265
|
+
const buildCopies = (markup, cls) => {
|
|
7266
|
+
const parts = [];
|
|
7267
|
+
for (let i = steps; i >= 1; i--) {
|
|
7268
|
+
parts.push(`<g class="${cls}"${cloneOutlineAttr} transform="translate(${(stepX * i).toFixed(3)} ${(stepY * i).toFixed(3)})">${markup}</g>`);
|
|
7269
|
+
}
|
|
7270
|
+
return parts.join("");
|
|
7271
|
+
};
|
|
7272
|
+
if (hasBg && bg.shadowAffectsBg !== false) {
|
|
7273
|
+
const shadowOpacityAttr = bgOpacity < 1 ? ` fill-opacity="${bgOpacity}"` : "";
|
|
7274
|
+
const shadowBgPath = `<path d="${bgD}" fill="${escapeXmlAttr(shadowColor)}"${shadowOpacityAttr} />`;
|
|
7275
|
+
bgBlockShadowMarker = buildCopies(shadowBgPath, "__pdBgShadowClone");
|
|
7276
|
+
}
|
|
7277
|
+
if (bg.shadowAffectsText !== false) {
|
|
7278
|
+
const inner = extractGInnerMarkup(svg);
|
|
7279
|
+
const recoloredText = recolorSvgFills(inner, shadowColor);
|
|
7280
|
+
if (recoloredText) textBlockShadowMarker = buildCopies(recoloredText, "__pdTextShadowClone");
|
|
7281
|
+
}
|
|
7282
|
+
}
|
|
7283
|
+
let bgLineShadowMarker = "";
|
|
7284
|
+
let textLineShadowMarker = "";
|
|
7285
|
+
if (hasLineShadow) {
|
|
7286
|
+
const shadowColor = String(bg.shadowColor);
|
|
7287
|
+
const tx = extOX.toFixed(3);
|
|
7288
|
+
const ty = extOY.toFixed(3);
|
|
7289
|
+
const fillObjLine = this.fill;
|
|
7290
|
+
const parentTextIsGradientLine = !!fillObjLine && typeof fillObjLine === "object" && (Array.isArray(fillObjLine.colorStops) || fillObjLine.type === "linear" || fillObjLine.type === "radial");
|
|
7291
|
+
const lineOutlineAttr = parentTextIsGradientLine ? ' data-pd-outline-text="1"' : "";
|
|
7292
|
+
if (hasBg && bg.shadowAffectsBg !== false) {
|
|
7293
|
+
const outlineBg = `<path d="${bgD}" fill="none" stroke="${escapeXmlAttr(shadowColor)}" stroke-width="1" stroke-linejoin="round" />`;
|
|
7294
|
+
bgLineShadowMarker = `<g class="__pdBgShadowClone"${lineOutlineAttr} transform="translate(${tx} ${ty})">${outlineBg}</g>`;
|
|
7295
|
+
}
|
|
7296
|
+
if (bg.shadowAffectsText !== false) {
|
|
7297
|
+
const inner = extractGInnerMarkup(svg);
|
|
7298
|
+
const strokeW = LINE_SHADOW_STROKE_WIDTH;
|
|
7299
|
+
const outlined = outlineTextSvgForLineShadow(inner, shadowColor, strokeW);
|
|
7300
|
+
if (outlined) textLineShadowMarker = `<g class="__pdTextShadowClone"${lineOutlineAttr} transform="translate(${tx} ${ty})">${outlined}</g>`;
|
|
7301
|
+
}
|
|
7302
|
+
}
|
|
5957
7303
|
const openTagMatch = svg.match(/^\s*<g\b[^>]*>/);
|
|
5958
|
-
const inserted = bgShadowMarker + bgPath + textShadowMarker;
|
|
7304
|
+
const inserted = bgBlockShadowMarker + bgLineShadowMarker + bgShadowMarker + bgPath + textBlockShadowMarker + textLineShadowMarker + textShadowMarker;
|
|
5959
7305
|
const shadowBlur = hasShadow ? Math.max(0, Number(shadow.blur ?? 0)) : 0;
|
|
5960
7306
|
const decorationTags = [
|
|
5961
7307
|
shadowBlur > 0 ? 'data-pd-shadow-blur="1"' : "",
|
|
@@ -5975,7 +7321,38 @@ function recolorSvgFills(svg, color) {
|
|
|
5975
7321
|
return _recolorSvgFills(svg, color);
|
|
5976
7322
|
}
|
|
5977
7323
|
function _recolorSvgFills(svg, color) {
|
|
7324
|
+
var _a;
|
|
5978
7325
|
const safe = escapeXmlAttr(color);
|
|
7326
|
+
try {
|
|
7327
|
+
const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${svg}</svg>`;
|
|
7328
|
+
const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
|
|
7329
|
+
const root = doc.documentElement;
|
|
7330
|
+
if (root && root.nodeName !== "parsererror") {
|
|
7331
|
+
for (const g of Array.from(root.querySelectorAll("linearGradient, radialGradient, pattern"))) {
|
|
7332
|
+
try {
|
|
7333
|
+
(_a = g.parentNode) == null ? void 0 : _a.removeChild(g);
|
|
7334
|
+
} catch {
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
for (const el of Array.from(root.querySelectorAll("text, tspan, path, rect"))) {
|
|
7338
|
+
const cur = el.getAttribute("fill");
|
|
7339
|
+
if (cur && (cur.trim().toLowerCase() === "none" || cur.trim().toLowerCase() === "transparent")) continue;
|
|
7340
|
+
const style = el.getAttribute("style");
|
|
7341
|
+
if (style && /fill\s*:/i.test(style)) {
|
|
7342
|
+
const cleaned = style.replace(/(?:^|;)\s*fill\s*:[^;]*/gi, "").replace(/^;+/, "").trim();
|
|
7343
|
+
if (cleaned) el.setAttribute("style", cleaned);
|
|
7344
|
+
else el.removeAttribute("style");
|
|
7345
|
+
}
|
|
7346
|
+
el.setAttribute("fill", color);
|
|
7347
|
+
}
|
|
7348
|
+
let out2 = "";
|
|
7349
|
+
for (const child of Array.from(root.childNodes)) {
|
|
7350
|
+
out2 += new XMLSerializer().serializeToString(child);
|
|
7351
|
+
}
|
|
7352
|
+
return out2;
|
|
7353
|
+
}
|
|
7354
|
+
} catch {
|
|
7355
|
+
}
|
|
5979
7356
|
let out = svg.replace(
|
|
5980
7357
|
/(<(?:text|tspan|path|rect)\b[^>]*?\sfill=")([^"]*)("[^>]*>)/gi,
|
|
5981
7358
|
(_m, pre, val, post) => {
|
|
@@ -5991,6 +7368,11 @@ function _recolorSvgFills(svg, color) {
|
|
|
5991
7368
|
return pre + replaced + post;
|
|
5992
7369
|
}
|
|
5993
7370
|
);
|
|
7371
|
+
out = out.replace(/<(text|tspan|path)\b([^>]*)>/gi, (m, tag, attrs) => {
|
|
7372
|
+
if (/\sfill=/i.test(attrs)) return m;
|
|
7373
|
+
if (/style="[^"]*\bfill\s*:/i.test(attrs)) return m;
|
|
7374
|
+
return `<${tag}${attrs} fill="${safe}">`;
|
|
7375
|
+
});
|
|
5994
7376
|
return out;
|
|
5995
7377
|
}
|
|
5996
7378
|
function buildRoundedRectPathD(x, y, w, h, rTL, rTR, rBR, rBL) {
|
|
@@ -6129,6 +7511,239 @@ function computeBgRects(obj, w, h, pT, pR, pB, pL, fit) {
|
|
|
6129
7511
|
function escapeXmlAttr(s) {
|
|
6130
7512
|
return String(s).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
6131
7513
|
}
|
|
7514
|
+
function buildWarpRibbonD(obj, pT, pR, pB, pL, rxTL, rxTR, rxBR, rxBL) {
|
|
7515
|
+
const tp = obj == null ? void 0 : obj.textPath;
|
|
7516
|
+
if (!tp || !tp.preset || tp.preset === "none") return null;
|
|
7517
|
+
if (tp.preset === "rise" || tp.preset === "angle") return null;
|
|
7518
|
+
const w = Number(obj.width) || 0;
|
|
7519
|
+
const h = Number(obj.height) || 0;
|
|
7520
|
+
const fs = Number(obj.fontSize) || 16;
|
|
7521
|
+
const resolved = resolveTextPath(tp, w, fs);
|
|
7522
|
+
if (!resolved) return null;
|
|
7523
|
+
const pathEl = measurePath(resolved.d);
|
|
7524
|
+
if (!pathEl) return null;
|
|
7525
|
+
const len = pathEl.getTotalLength();
|
|
7526
|
+
if (!Number.isFinite(len) || len <= 0) return null;
|
|
7527
|
+
const halfW = w / 2;
|
|
7528
|
+
const halfH = h / 2;
|
|
7529
|
+
const topT = halfH + Math.max(0, pT);
|
|
7530
|
+
const botT = halfH + Math.max(0, pB);
|
|
7531
|
+
const padL = Math.max(0, pL);
|
|
7532
|
+
const padR = Math.max(0, pR);
|
|
7533
|
+
const sample = (s) => {
|
|
7534
|
+
const ss = Math.max(0, Math.min(len, s));
|
|
7535
|
+
const p = pathEl.getPointAtLength(ss);
|
|
7536
|
+
const a = pathEl.getPointAtLength(Math.min(len, ss + 0.5));
|
|
7537
|
+
const b = pathEl.getPointAtLength(Math.max(0, ss - 0.5));
|
|
7538
|
+
let tx = a.x - b.x;
|
|
7539
|
+
let ty = a.y - b.y;
|
|
7540
|
+
const tl = Math.hypot(tx, ty) || 1;
|
|
7541
|
+
tx /= tl;
|
|
7542
|
+
ty /= tl;
|
|
7543
|
+
return { px: p.x - halfW, py: p.y - halfH, tx, ty, nx: ty, ny: -tx };
|
|
7544
|
+
};
|
|
7545
|
+
const SAMPLES = 96;
|
|
7546
|
+
const topPts = [];
|
|
7547
|
+
const botPts = [];
|
|
7548
|
+
for (let i = 0; i <= SAMPLES; i++) {
|
|
7549
|
+
const s = len * i / SAMPLES;
|
|
7550
|
+
const { px, py, nx, ny } = sample(s);
|
|
7551
|
+
topPts.push([px + nx * topT, py + ny * topT]);
|
|
7552
|
+
botPts.push([px - nx * botT, py - ny * botT]);
|
|
7553
|
+
}
|
|
7554
|
+
const s0 = sample(0);
|
|
7555
|
+
const s1 = sample(len);
|
|
7556
|
+
const TL = [s0.px - s0.tx * padL + s0.nx * topT, s0.py - s0.ty * padL + s0.ny * topT];
|
|
7557
|
+
const BL = [s0.px - s0.tx * padL - s0.nx * botT, s0.py - s0.ty * padL - s0.ny * botT];
|
|
7558
|
+
const TR = [s1.px + s1.tx * padR + s1.nx * topT, s1.py + s1.ty * padR + s1.ny * topT];
|
|
7559
|
+
const BR = [s1.px + s1.tx * padR - s1.nx * botT, s1.py + s1.ty * padR - s1.ny * botT];
|
|
7560
|
+
topPts[0] = TL;
|
|
7561
|
+
topPts[topPts.length - 1] = TR;
|
|
7562
|
+
botPts[0] = BL;
|
|
7563
|
+
botPts[botPts.length - 1] = BR;
|
|
7564
|
+
const capH = topT + botT;
|
|
7565
|
+
const maxLeftR = Math.min(capH * 0.5, len * 0.5 + padL);
|
|
7566
|
+
const maxRightR = Math.min(capH * 0.5, len * 0.5 + padR);
|
|
7567
|
+
const clamp2 = (r, m) => Math.max(0, Math.min(Number(r) || 0, m));
|
|
7568
|
+
const cTL = clamp2(rxTL, maxLeftR);
|
|
7569
|
+
const cBL = clamp2(rxBL, maxLeftR);
|
|
7570
|
+
const cTR = clamp2(rxTR, maxRightR);
|
|
7571
|
+
const cBR = clamp2(rxBR, maxRightR);
|
|
7572
|
+
const dist = (a, b) => Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
7573
|
+
const inset = (from, toward, d) => {
|
|
7574
|
+
const dx = toward[0] - from[0];
|
|
7575
|
+
const dy = toward[1] - from[1];
|
|
7576
|
+
const L = Math.hypot(dx, dy) || 1;
|
|
7577
|
+
const k = Math.min(d, L) / L;
|
|
7578
|
+
return [from[0] + dx * k, from[1] + dy * k];
|
|
7579
|
+
};
|
|
7580
|
+
const walkEdge = (pts, target, fromStart) => {
|
|
7581
|
+
if (target <= 0) {
|
|
7582
|
+
const idx = fromStart ? 0 : pts.length - 1;
|
|
7583
|
+
return { pt: [pts[idx][0], pts[idx][1]], cutIdx: idx };
|
|
7584
|
+
}
|
|
7585
|
+
let acc = 0;
|
|
7586
|
+
if (fromStart) {
|
|
7587
|
+
for (let i = 1; i < pts.length; i++) {
|
|
7588
|
+
const seg = dist(pts[i - 1], pts[i]);
|
|
7589
|
+
if (acc + seg >= target) {
|
|
7590
|
+
const k = (target - acc) / (seg || 1);
|
|
7591
|
+
const pt = [
|
|
7592
|
+
pts[i - 1][0] + (pts[i][0] - pts[i - 1][0]) * k,
|
|
7593
|
+
pts[i - 1][1] + (pts[i][1] - pts[i - 1][1]) * k
|
|
7594
|
+
];
|
|
7595
|
+
return { pt, cutIdx: i - 1 };
|
|
7596
|
+
}
|
|
7597
|
+
acc += seg;
|
|
7598
|
+
}
|
|
7599
|
+
return { pt: pts[pts.length - 1], cutIdx: pts.length - 1 };
|
|
7600
|
+
}
|
|
7601
|
+
for (let i = pts.length - 2; i >= 0; i--) {
|
|
7602
|
+
const seg = dist(pts[i + 1], pts[i]);
|
|
7603
|
+
if (acc + seg >= target) {
|
|
7604
|
+
const k = (target - acc) / (seg || 1);
|
|
7605
|
+
const pt = [
|
|
7606
|
+
pts[i + 1][0] + (pts[i][0] - pts[i + 1][0]) * k,
|
|
7607
|
+
pts[i + 1][1] + (pts[i][1] - pts[i + 1][1]) * k
|
|
7608
|
+
];
|
|
7609
|
+
return { pt, cutIdx: i + 1 };
|
|
7610
|
+
}
|
|
7611
|
+
acc += seg;
|
|
7612
|
+
}
|
|
7613
|
+
return { pt: pts[0], cutIdx: 0 };
|
|
7614
|
+
};
|
|
7615
|
+
const topStart = walkEdge(topPts, cTL, true);
|
|
7616
|
+
const topEnd = walkEdge(topPts, cTR, false);
|
|
7617
|
+
const botStart = walkEdge(botPts, cBL, true);
|
|
7618
|
+
const botEnd = walkEdge(botPts, cBR, false);
|
|
7619
|
+
const insTL_top = topStart.pt;
|
|
7620
|
+
const insTR_top = topEnd.pt;
|
|
7621
|
+
const insBL_bot = botStart.pt;
|
|
7622
|
+
const insBR_bot = botEnd.pt;
|
|
7623
|
+
const insTL_cap = inset(TL, BL, cTL);
|
|
7624
|
+
const insBL_cap = inset(BL, TL, cBL);
|
|
7625
|
+
const insBR_cap = inset(BR, TR, cBR);
|
|
7626
|
+
const insTR_cap = inset(TR, BR, cTR);
|
|
7627
|
+
const fmt = (p) => `${p[0].toFixed(2)} ${p[1].toFixed(2)}`;
|
|
7628
|
+
const parts = [];
|
|
7629
|
+
parts.push(`M ${fmt(insTL_top)}`);
|
|
7630
|
+
for (let i = topStart.cutIdx + 1; i <= topEnd.cutIdx; i++) parts.push(`L ${fmt(topPts[i])}`);
|
|
7631
|
+
parts.push(`L ${fmt(insTR_top)}`);
|
|
7632
|
+
parts.push(`Q ${fmt(TR)} ${fmt(insTR_cap)}`);
|
|
7633
|
+
parts.push(`L ${fmt(insBR_cap)}`);
|
|
7634
|
+
parts.push(`Q ${fmt(BR)} ${fmt(insBR_bot)}`);
|
|
7635
|
+
for (let i = botEnd.cutIdx - 1; i >= botStart.cutIdx + 1; i--) parts.push(`L ${fmt(botPts[i])}`);
|
|
7636
|
+
parts.push(`L ${fmt(insBL_bot)}`);
|
|
7637
|
+
parts.push(`Q ${fmt(BL)} ${fmt(insBL_cap)}`);
|
|
7638
|
+
parts.push(`L ${fmt(insTL_cap)}`);
|
|
7639
|
+
parts.push(`Q ${fmt(TL)} ${fmt(insTL_top)}`);
|
|
7640
|
+
parts.push("Z");
|
|
7641
|
+
return parts.join(" ");
|
|
7642
|
+
}
|
|
7643
|
+
function computeRibbonBoundsFor(obj, pT, pR, pB, pL) {
|
|
7644
|
+
const tp = obj == null ? void 0 : obj.textPath;
|
|
7645
|
+
if (!tp || !tp.preset || tp.preset === "none") {
|
|
7646
|
+
const w2 = Number(obj.width) || 0;
|
|
7647
|
+
const h2 = Number(obj.height) || 0;
|
|
7648
|
+
return { x: -w2 / 2 - pL, y: -h2 / 2 - pT, w: w2 + pL + pR, h: h2 + pT + pB };
|
|
7649
|
+
}
|
|
7650
|
+
const w = Number(obj.width) || 0;
|
|
7651
|
+
const h = Number(obj.height) || 0;
|
|
7652
|
+
const fs = Number(obj.fontSize) || 16;
|
|
7653
|
+
const resolved = resolveTextPath(tp, w, fs);
|
|
7654
|
+
const pathEl = resolved ? measurePath(resolved.d) : null;
|
|
7655
|
+
const len = pathEl ? pathEl.getTotalLength() : 0;
|
|
7656
|
+
if (!pathEl || !Number.isFinite(len) || len <= 0) {
|
|
7657
|
+
return { x: -w / 2 - pL, y: -h / 2 - pT, w: w + pL + pR, h: h + pT + pB };
|
|
7658
|
+
}
|
|
7659
|
+
const halfW = w / 2;
|
|
7660
|
+
const halfH = h / 2;
|
|
7661
|
+
const topT = halfH + Math.max(0, pT);
|
|
7662
|
+
const botT = halfH + Math.max(0, pB);
|
|
7663
|
+
const STEPS = 48;
|
|
7664
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
7665
|
+
const ext = (x, y) => {
|
|
7666
|
+
if (x < minX) minX = x;
|
|
7667
|
+
if (y < minY) minY = y;
|
|
7668
|
+
if (x > maxX) maxX = x;
|
|
7669
|
+
if (y > maxY) maxY = y;
|
|
7670
|
+
};
|
|
7671
|
+
for (let i = 0; i <= STEPS; i++) {
|
|
7672
|
+
const s = len * i / STEPS;
|
|
7673
|
+
const p = pathEl.getPointAtLength(s);
|
|
7674
|
+
const a = pathEl.getPointAtLength(Math.min(len, s + 0.5));
|
|
7675
|
+
const b = pathEl.getPointAtLength(Math.max(0, s - 0.5));
|
|
7676
|
+
let tx = a.x - b.x;
|
|
7677
|
+
let ty = a.y - b.y;
|
|
7678
|
+
const tl = Math.hypot(tx, ty) || 1;
|
|
7679
|
+
tx /= tl;
|
|
7680
|
+
ty /= tl;
|
|
7681
|
+
const nx = ty, ny = -tx;
|
|
7682
|
+
const px = p.x - halfW, py = p.y - halfH;
|
|
7683
|
+
ext(px + nx * topT, py + ny * topT);
|
|
7684
|
+
ext(px - nx * botT, py - ny * botT);
|
|
7685
|
+
}
|
|
7686
|
+
if (pL > 0 || pR > 0) {
|
|
7687
|
+
minX -= pL;
|
|
7688
|
+
maxX += pR;
|
|
7689
|
+
}
|
|
7690
|
+
return { x: minX, y: minY, w: Math.max(1, maxX - minX), h: Math.max(1, maxY - minY) };
|
|
7691
|
+
}
|
|
7692
|
+
function normalizeStops(stops) {
|
|
7693
|
+
const out = stops.map((s) => ({ color: s.color, offset: Math.max(0, Math.min(1, Number(s.offset) || 0)) })).sort((a, b) => a.offset - b.offset);
|
|
7694
|
+
if (out.length === 0) return out;
|
|
7695
|
+
if (out[0].offset > 0) out.unshift({ color: out[0].color, offset: 0 });
|
|
7696
|
+
if (out[out.length - 1].offset < 1) out.push({ color: out[out.length - 1].color, offset: 1 });
|
|
7697
|
+
return out;
|
|
7698
|
+
}
|
|
7699
|
+
function buildCanvasGradient(ctx, g, bx, by, bw, bh) {
|
|
7700
|
+
const stops = normalizeStops(g.stops);
|
|
7701
|
+
if (stops.length === 0) return "#000";
|
|
7702
|
+
if (g.type === "radial") {
|
|
7703
|
+
const cx = bx + (g.cx ?? 0.5) * bw;
|
|
7704
|
+
const cy = by + (g.cy ?? 0.5) * bh;
|
|
7705
|
+
const r = Math.max(1, (g.r ?? 0.5) * Math.max(bw, bh));
|
|
7706
|
+
const cg2 = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);
|
|
7707
|
+
stops.forEach((s) => {
|
|
7708
|
+
try {
|
|
7709
|
+
cg2.addColorStop(s.offset, s.color);
|
|
7710
|
+
} catch {
|
|
7711
|
+
}
|
|
7712
|
+
});
|
|
7713
|
+
return cg2;
|
|
7714
|
+
}
|
|
7715
|
+
const angle = g.angle ?? 90;
|
|
7716
|
+
const rad = angle * Math.PI / 180;
|
|
7717
|
+
const x1 = bx + (0.5 - Math.sin(rad) * 0.5) * bw;
|
|
7718
|
+
const y1 = by + (0.5 + Math.cos(rad) * 0.5) * bh;
|
|
7719
|
+
const x2 = bx + (0.5 + Math.sin(rad) * 0.5) * bw;
|
|
7720
|
+
const y2 = by + (0.5 - Math.cos(rad) * 0.5) * bh;
|
|
7721
|
+
const cg = ctx.createLinearGradient(x1, y1, x2, y2);
|
|
7722
|
+
stops.forEach((s) => {
|
|
7723
|
+
try {
|
|
7724
|
+
cg.addColorStop(s.offset, s.color);
|
|
7725
|
+
} catch {
|
|
7726
|
+
}
|
|
7727
|
+
});
|
|
7728
|
+
return cg;
|
|
7729
|
+
}
|
|
7730
|
+
function buildSvgGradientDef(g, id, bx, by, bw, bh) {
|
|
7731
|
+
const stops = normalizeStops(g.stops);
|
|
7732
|
+
const stopsXml = stops.map((s) => `<stop offset="${s.offset}" stop-color="${escapeXmlAttr(s.color)}" />`).join("");
|
|
7733
|
+
if (g.type === "radial") {
|
|
7734
|
+
const cx = bx + (g.cx ?? 0.5) * bw;
|
|
7735
|
+
const cy = by + (g.cy ?? 0.5) * bh;
|
|
7736
|
+
const r = Math.max(1, (g.r ?? 0.5) * Math.max(bw, bh));
|
|
7737
|
+
return `<radialGradient id="${id}" gradientUnits="userSpaceOnUse" cx="${cx.toFixed(3)}" cy="${cy.toFixed(3)}" r="${r.toFixed(3)}" fx="${cx.toFixed(3)}" fy="${cy.toFixed(3)}">${stopsXml}</radialGradient>`;
|
|
7738
|
+
}
|
|
7739
|
+
const angle = g.angle ?? 90;
|
|
7740
|
+
const rad = angle * Math.PI / 180;
|
|
7741
|
+
const x1 = bx + (0.5 - Math.sin(rad) * 0.5) * bw;
|
|
7742
|
+
const y1 = by + (0.5 + Math.cos(rad) * 0.5) * bh;
|
|
7743
|
+
const x2 = bx + (0.5 + Math.sin(rad) * 0.5) * bw;
|
|
7744
|
+
const y2 = by + (0.5 - Math.cos(rad) * 0.5) * bh;
|
|
7745
|
+
return `<linearGradient id="${id}" gradientUnits="userSpaceOnUse" x1="${x1.toFixed(3)}" y1="${y1.toFixed(3)}" x2="${x2.toFixed(3)}" y2="${y2.toFixed(3)}">${stopsXml}</linearGradient>`;
|
|
7746
|
+
}
|
|
6132
7747
|
function extractGInnerMarkup(markup) {
|
|
6133
7748
|
const openMatch = markup.match(/^\s*<g\b[^>]*>/);
|
|
6134
7749
|
if (!openMatch) return markup;
|
|
@@ -6136,6 +7751,37 @@ function extractGInnerMarkup(markup) {
|
|
|
6136
7751
|
if (closeIdx <= openMatch[0].length) return markup;
|
|
6137
7752
|
return markup.slice(openMatch[0].length, closeIdx);
|
|
6138
7753
|
}
|
|
7754
|
+
function outlineTextSvgForLineShadow(inner, strokeColor, strokeWidth) {
|
|
7755
|
+
if (!inner) return "";
|
|
7756
|
+
try {
|
|
7757
|
+
const wrapped = `<svg xmlns="http://www.w3.org/2000/svg">${inner}</svg>`;
|
|
7758
|
+
const doc = new DOMParser().parseFromString(wrapped, "image/svg+xml");
|
|
7759
|
+
const root = doc.documentElement;
|
|
7760
|
+
if (!root || root.nodeName === "parsererror") return "";
|
|
7761
|
+
const targets = Array.from(root.querySelectorAll("text, tspan"));
|
|
7762
|
+
if (!targets.length) return "";
|
|
7763
|
+
for (const el of targets) {
|
|
7764
|
+
const style = el.getAttribute("style");
|
|
7765
|
+
if (style) {
|
|
7766
|
+
const cleaned = style.replace(/(?:^|;)\s*fill\s*:[^;]*/gi, "").replace(/(?:^|;)\s*stroke(?:-[a-z]+)?\s*:[^;]*/gi, "").replace(/^;+/, "").trim();
|
|
7767
|
+
if (cleaned) el.setAttribute("style", cleaned);
|
|
7768
|
+
else el.removeAttribute("style");
|
|
7769
|
+
}
|
|
7770
|
+
el.setAttribute("fill", "none");
|
|
7771
|
+
el.setAttribute("stroke", strokeColor);
|
|
7772
|
+
el.setAttribute("stroke-width", strokeWidth.toFixed(3));
|
|
7773
|
+
el.setAttribute("stroke-linejoin", "round");
|
|
7774
|
+
el.setAttribute("paint-order", "stroke");
|
|
7775
|
+
}
|
|
7776
|
+
let out = "";
|
|
7777
|
+
for (const child of Array.from(root.childNodes)) {
|
|
7778
|
+
out += new XMLSerializer().serializeToString(child);
|
|
7779
|
+
}
|
|
7780
|
+
return out;
|
|
7781
|
+
} catch {
|
|
7782
|
+
return "";
|
|
7783
|
+
}
|
|
7784
|
+
}
|
|
6139
7785
|
const TRIANGLE_STROKE_MITER_LIMIT = 1e6;
|
|
6140
7786
|
const toSafeNumber = (value, fallback = 0) => Number.isFinite(value) ? Math.max(0, Number(value)) : fallback;
|
|
6141
7787
|
function normalizeShapeType(shapeType) {
|
|
@@ -6764,7 +8410,8 @@ function createText(element) {
|
|
|
6764
8410
|
// same value as a fit-target, so the rendered box and the shrink target
|
|
6765
8411
|
// stay in sync (parity with the Use page / EC2 renderer).
|
|
6766
8412
|
...(element.minBoxHeight ?? 0) > 0 ? { minBoxHeight: element.minBoxHeight } : {},
|
|
6767
|
-
verticalAlign: element.verticalAlign || "top"
|
|
8413
|
+
verticalAlign: element.verticalAlign || "top",
|
|
8414
|
+
...element.textPath && element.textPath.preset && element.textPath.preset !== "none" ? { textPath: element.textPath } : {}
|
|
6768
8415
|
});
|
|
6769
8416
|
textbox.__formattingEnabled = formattingEnabled;
|
|
6770
8417
|
textbox.initDimensions();
|
|
@@ -6871,6 +8518,9 @@ function createFabricObject(element) {
|
|
|
6871
8518
|
if (element.type === "shape" || element.type === "line" || element.type === "text") {
|
|
6872
8519
|
applyInitialGradients(obj, element);
|
|
6873
8520
|
}
|
|
8521
|
+
if (element.type === "text" && obj instanceof fabric__namespace.Textbox) {
|
|
8522
|
+
applyTextPathControls(obj);
|
|
8523
|
+
}
|
|
6874
8524
|
}
|
|
6875
8525
|
return obj;
|
|
6876
8526
|
}
|
|
@@ -7057,7 +8707,7 @@ const progressDefinition = {
|
|
|
7057
8707
|
],
|
|
7058
8708
|
render: renderProgressSvg
|
|
7059
8709
|
};
|
|
7060
|
-
function escapeXml(str) {
|
|
8710
|
+
function escapeXml$1(str) {
|
|
7061
8711
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
7062
8712
|
}
|
|
7063
8713
|
function estimateTextWidth(text, fontSize, fontWeight) {
|
|
@@ -7104,7 +8754,7 @@ function renderTableSvg(props, width, height) {
|
|
|
7104
8754
|
if (text) {
|
|
7105
8755
|
const maxChars = Math.max(3, Math.floor(cellW / (fontSize * 0.55)));
|
|
7106
8756
|
const displayText = text.length > maxChars ? text.slice(0, maxChars - 1) + "…" : text;
|
|
7107
|
-
svg += `<text x="${x + cellW / 2}" y="${y + cellH / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml(displayText)}</text>`;
|
|
8757
|
+
svg += `<text x="${x + cellW / 2}" y="${y + cellH / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml$1(displayText)}</text>`;
|
|
7108
8758
|
}
|
|
7109
8759
|
}
|
|
7110
8760
|
}
|
|
@@ -7171,7 +8821,7 @@ function renderAvatarSvg(props, width, height) {
|
|
|
7171
8821
|
}
|
|
7172
8822
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">
|
|
7173
8823
|
${shapeSvg}
|
|
7174
|
-
<text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="600" fill="${textColor}">${initials}</text>
|
|
8824
|
+
<text x="${cx}" y="${cy}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="600" fill="${textColor}">${initials}</text>
|
|
7175
8825
|
</svg>`;
|
|
7176
8826
|
}
|
|
7177
8827
|
const avatarDefinition = {
|
|
@@ -7262,7 +8912,7 @@ function renderBadgeInternal(props, width, height) {
|
|
|
7262
8912
|
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${finalWidth}" height="${height}" viewBox="0 0 ${finalWidth} ${height}">
|
|
7263
8913
|
<rect x="${inset}" y="${inset}" width="${finalWidth - borderWidth}" height="${height - borderWidth}" rx="${rx}" fill="${bgColor}" stroke="${borderColor}" stroke-width="${borderWidth}"/>
|
|
7264
8914
|
${iconSvg}
|
|
7265
|
-
<text x="${textX}" y="${height / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml(displayText)}</text>
|
|
8915
|
+
<text x="${textX}" y="${height / 2}" text-anchor="middle" dominant-baseline="central" font-size="${fontSize}" font-family="${escapeXml$1(fontFamily)}" font-weight="${fontWeight}" fill="${textColor}">${escapeXml$1(displayText)}</text>
|
|
7266
8916
|
</svg>`;
|
|
7267
8917
|
return { svg, computedWidth, anchor };
|
|
7268
8918
|
}
|
|
@@ -8936,6 +10586,9 @@ const PageCanvas = react.forwardRef(
|
|
|
8936
10586
|
if (typeof baked === "number" && baked > 0) {
|
|
8937
10587
|
elementUpdate.minBoxHeight = baked;
|
|
8938
10588
|
}
|
|
10589
|
+
if (obj.textPath) {
|
|
10590
|
+
elementUpdate.textPath = obj.textPath;
|
|
10591
|
+
}
|
|
8939
10592
|
}
|
|
8940
10593
|
if (sourceElement && sourceElement.opacity !== void 0) {
|
|
8941
10594
|
elementUpdate.opacity = sourceElement.opacity;
|
|
@@ -9670,6 +11323,7 @@ const PageCanvas = react.forwardRef(
|
|
|
9670
11323
|
(existingObj.verticalAlign ?? "top") !== (element.verticalAlign ?? "top") || Math.abs((existingObj.minBoxHeight ?? 0) - (element.minBoxHeight ?? 0)) > 0.1 || // Detect text background + shadow changes so panel edits flow into Fabric.
|
|
9671
11324
|
JSON.stringify({
|
|
9672
11325
|
c: element.textBgColor ?? null,
|
|
11326
|
+
g: element.textBgGradient ?? null,
|
|
9673
11327
|
p: element.textBgPadding ?? 0,
|
|
9674
11328
|
pt: element.textBgPaddingTop ?? null,
|
|
9675
11329
|
pr: element.textBgPaddingRight ?? null,
|
|
@@ -9688,7 +11342,7 @@ const PageCanvas = react.forwardRef(
|
|
|
9688
11342
|
st: element.textShadowAffectsText !== false,
|
|
9689
11343
|
sa: element.textShadowAffectsBg !== false
|
|
9690
11344
|
}) !== (existingObj.__lastTextBgShadowJson ?? "") || // CRITICAL: Detect gradient fill/stroke changes — serialise to JSON for deep comparison
|
|
9691
|
-
JSON.stringify(element.fillGradient || null) !== (existingObj.__lastFillGradientJson ?? "null") || JSON.stringify(element.strokeGradient || null) !== (existingObj.__lastStrokeGradientJson ?? "null");
|
|
11345
|
+
JSON.stringify(element.fillGradient || null) !== (existingObj.__lastFillGradientJson ?? "null") || JSON.stringify(element.strokeGradient || null) !== (existingObj.__lastStrokeGradientJson ?? "null") || JSON.stringify(element.textPath || null) !== JSON.stringify(existingObj.textPath || null);
|
|
9692
11346
|
const forceApplyFromPanel = syncTriggeredByPanelRef.current;
|
|
9693
11347
|
const noPropsOrPositionChanged = !positionChanged && !otherPropsChanged;
|
|
9694
11348
|
if (noPropsOrPositionChanged && !forceApplyFromPanel || visibilityUpdateInProgressRef.current) {
|
|
@@ -10122,7 +11776,7 @@ const PageCanvas = react.forwardRef(
|
|
|
10122
11776
|
});
|
|
10123
11777
|
}, [selectedIds, isActive, ready, elements]);
|
|
10124
11778
|
const updateFabricObject = (obj, element, skipPositionUpdate = false) => {
|
|
10125
|
-
var _a, _b;
|
|
11779
|
+
var _a, _b, _c;
|
|
10126
11780
|
const fc = fabricRef.current;
|
|
10127
11781
|
if (fc && isTransforming(fc)) {
|
|
10128
11782
|
return;
|
|
@@ -10399,6 +12053,8 @@ const PageCanvas = react.forwardRef(
|
|
|
10399
12053
|
obj.setCoords();
|
|
10400
12054
|
}
|
|
10401
12055
|
if (!isLine) {
|
|
12056
|
+
const angleTextPathActive = isTextbox && ((_b = element.textPath) == null ? void 0 : _b.preset) === "rise";
|
|
12057
|
+
const appliedSkewY = angleTextPathActive ? 0 : element.skewY ?? 0;
|
|
10402
12058
|
let posIfNotSkipped = skipPositionUpdate ? {} : { left: fabricPos.left, top: fabricPos.top };
|
|
10403
12059
|
if (!skipPositionUpdate && obj instanceof fabric__namespace.FabricImage && obj.originX === "center") {
|
|
10404
12060
|
const vW = rW * effectiveScaleX;
|
|
@@ -10414,7 +12070,7 @@ const PageCanvas = react.forwardRef(
|
|
|
10414
12070
|
scaleY: effectiveScaleY,
|
|
10415
12071
|
angle: element.angle ?? 0,
|
|
10416
12072
|
skewX: element.skewX ?? 0,
|
|
10417
|
-
skewY:
|
|
12073
|
+
skewY: appliedSkewY
|
|
10418
12074
|
});
|
|
10419
12075
|
} else {
|
|
10420
12076
|
obj.set({
|
|
@@ -10434,7 +12090,7 @@ const PageCanvas = react.forwardRef(
|
|
|
10434
12090
|
width: rW,
|
|
10435
12091
|
angle: element.angle ?? 0,
|
|
10436
12092
|
skewX: element.skewX ?? 0,
|
|
10437
|
-
skewY:
|
|
12093
|
+
skewY: appliedSkewY,
|
|
10438
12094
|
scaleX: effectiveScaleX * baseScaleX,
|
|
10439
12095
|
scaleY: effectiveScaleY * baseScaleY
|
|
10440
12096
|
});
|
|
@@ -10566,7 +12222,9 @@ const PageCanvas = react.forwardRef(
|
|
|
10566
12222
|
dynamicMinWidth: 0,
|
|
10567
12223
|
fontSize,
|
|
10568
12224
|
fontFamily: element.fontFamily || "Open Sans",
|
|
10569
|
-
|
|
12225
|
+
// If a gradient fill is active, do not briefly overwrite it with the
|
|
12226
|
+
// stored solid fallback while applying textPath/panel updates.
|
|
12227
|
+
fill: element.fillGradient && isGradientConfig(element.fillGradient) ? obj.fill : element.fill || "#1a1a1a",
|
|
10570
12228
|
fontWeight: element.fontWeight || 400,
|
|
10571
12229
|
textAlign: element.textAlign || "left",
|
|
10572
12230
|
fontStyle: element.fontStyle || "normal",
|
|
@@ -10583,6 +12241,13 @@ const PageCanvas = react.forwardRef(
|
|
|
10583
12241
|
const minBoxH = Math.max(0, Number(element.minBoxHeight) || 0);
|
|
10584
12242
|
obj.verticalAlign = valign;
|
|
10585
12243
|
obj.minBoxHeight = minBoxH;
|
|
12244
|
+
const nextTextPath = element.textPath;
|
|
12245
|
+
if (nextTextPath && nextTextPath.preset && nextTextPath.preset !== "none") {
|
|
12246
|
+
obj.textPath = nextTextPath;
|
|
12247
|
+
} else {
|
|
12248
|
+
obj.textPath = void 0;
|
|
12249
|
+
}
|
|
12250
|
+
applyTextPathControls(obj);
|
|
10586
12251
|
if (element.formattingEnabled === true) {
|
|
10587
12252
|
obj.styles = parsedStyles || {};
|
|
10588
12253
|
} else {
|
|
@@ -10605,9 +12270,10 @@ const PageCanvas = react.forwardRef(
|
|
|
10605
12270
|
} catch {
|
|
10606
12271
|
}
|
|
10607
12272
|
obj.dirty = true;
|
|
10608
|
-
(
|
|
12273
|
+
(_c = obj.setCoords) == null ? void 0 : _c.call(obj);
|
|
10609
12274
|
obj.__lastTextBgShadowJson = JSON.stringify({
|
|
10610
12275
|
c: element.textBgColor ?? null,
|
|
12276
|
+
g: element.textBgGradient ?? null,
|
|
10611
12277
|
p: element.textBgPadding ?? 0,
|
|
10612
12278
|
pt: element.textBgPaddingTop ?? null,
|
|
10613
12279
|
pr: element.textBgPaddingRight ?? null,
|
|
@@ -10624,7 +12290,8 @@ const PageCanvas = react.forwardRef(
|
|
|
10624
12290
|
sx: element.textShadowOffsetX ?? 0,
|
|
10625
12291
|
sy: element.textShadowOffsetY ?? 0,
|
|
10626
12292
|
st: element.textShadowAffectsText !== false,
|
|
10627
|
-
sa: element.textShadowAffectsBg !== false
|
|
12293
|
+
sa: element.textShadowAffectsBg !== false,
|
|
12294
|
+
sty: element.textShadowType ?? null
|
|
10628
12295
|
});
|
|
10629
12296
|
obj.dirty = true;
|
|
10630
12297
|
} catch (err) {
|
|
@@ -11037,9 +12704,7 @@ const PageCanvas = react.forwardRef(
|
|
|
11037
12704
|
}
|
|
11038
12705
|
try {
|
|
11039
12706
|
let url = getProxiedImageUrl(imageUrl);
|
|
11040
|
-
|
|
11041
|
-
const isInlineSvgDataUrl = imageUrl.startsWith("data:image/svg+xml");
|
|
11042
|
-
if (isSvgImage(imageUrl, element.sourceFormat) && (!isInlineSvgDataUrl || hasColorOverrides)) {
|
|
12707
|
+
if (isSvgImage(imageUrl, element.sourceFormat)) {
|
|
11043
12708
|
const normalized = await getNormalizedSvgUrl(imageUrl, element.svgColorMap, element.sourceFormat);
|
|
11044
12709
|
if (!isLatestRequest()) return;
|
|
11045
12710
|
if (normalized) url = normalized;
|
|
@@ -15831,6 +17496,7 @@ async function resolveFromForm(options) {
|
|
|
15831
17496
|
} else {
|
|
15832
17497
|
inferredSections = [];
|
|
15833
17498
|
}
|
|
17499
|
+
const templateDefaultMetaSectionState = templateRow.default_data && isDefaultDataV2(templateRow.default_data) ? templateRow.default_data.sectionState : extractSectionStateCandidate(templateRow.default_data, inferredSections);
|
|
15834
17500
|
const defaultFormMetaSectionState = extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.values, inferredSections) ?? extractSectionStateCandidate(defaultForm == null ? void 0 : defaultForm.saved_data, inferredSections);
|
|
15835
17501
|
let mergedSectionState = { ...sectionState };
|
|
15836
17502
|
const templateDefaultData = templateRow.default_data;
|
|
@@ -15842,6 +17508,7 @@ async function resolveFromForm(options) {
|
|
|
15842
17508
|
}
|
|
15843
17509
|
}
|
|
15844
17510
|
}
|
|
17511
|
+
mergedSectionState = mergeRepeatableEntryMeta(mergedSectionState, templateDefaultMetaSectionState, inferredSections);
|
|
15845
17512
|
mergedSectionState = mergeRepeatableEntryMeta(mergedSectionState, defaultFormMetaSectionState, inferredSections);
|
|
15846
17513
|
const flatFormData = flattenSectionStateToFormData(mergedSectionState, inferredSections);
|
|
15847
17514
|
const dynamicFields = templateConfig.dynamicFields || [];
|
|
@@ -16804,6 +18471,312 @@ function normalizeSvgDimensions(svg, targetWidth, targetHeight) {
|
|
|
16804
18471
|
function isTextboxLike(obj) {
|
|
16805
18472
|
return !!obj && (obj instanceof fabric__namespace.Textbox || obj.type === "textbox" || Array.isArray(obj == null ? void 0 : obj._textLines) && typeof obj.getLineWidth === "function");
|
|
16806
18473
|
}
|
|
18474
|
+
function escapeXml(s) {
|
|
18475
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
18476
|
+
}
|
|
18477
|
+
function ensureFabricGradientDef(doc, obj, width, height) {
|
|
18478
|
+
const grad = obj == null ? void 0 : obj.fill;
|
|
18479
|
+
if (!grad || typeof grad !== "object" || !Array.isArray(grad.colorStops) || !grad.coords) return "";
|
|
18480
|
+
const id = `pixldocs_text_grad_${String(obj.__docuforgeId || grad.id || Math.random()).replace(/[^a-zA-Z0-9_-]/g, "_")}`;
|
|
18481
|
+
if (doc.getElementById(id)) return `url(#${id})`;
|
|
18482
|
+
const ns = "http://www.w3.org/2000/svg";
|
|
18483
|
+
let defs = doc.querySelector("defs");
|
|
18484
|
+
if (!defs) {
|
|
18485
|
+
defs = doc.createElementNS(ns, "defs");
|
|
18486
|
+
doc.documentElement.insertBefore(defs, doc.documentElement.firstChild);
|
|
18487
|
+
}
|
|
18488
|
+
const c = grad.coords || {};
|
|
18489
|
+
const el = doc.createElementNS(ns, grad.type === "radial" ? "radialGradient" : "linearGradient");
|
|
18490
|
+
el.setAttribute("id", id);
|
|
18491
|
+
el.setAttribute("gradientUnits", "userSpaceOnUse");
|
|
18492
|
+
if (grad.type === "radial") {
|
|
18493
|
+
el.setAttribute("cx", (Number(c.x2 ?? c.x1 ?? width / 2) - width / 2).toFixed(3));
|
|
18494
|
+
el.setAttribute("cy", (Number(c.y2 ?? c.y1 ?? height / 2) - height / 2).toFixed(3));
|
|
18495
|
+
el.setAttribute("fx", (Number(c.x1 ?? c.x2 ?? width / 2) - width / 2).toFixed(3));
|
|
18496
|
+
el.setAttribute("fy", (Number(c.y1 ?? c.y2 ?? height / 2) - height / 2).toFixed(3));
|
|
18497
|
+
el.setAttribute("r", Math.max(0.1, Number(c.r2 ?? c.r ?? Math.max(width, height) / 2)).toFixed(3));
|
|
18498
|
+
} else {
|
|
18499
|
+
el.setAttribute("x1", (Number(c.x1) - width / 2).toFixed(3));
|
|
18500
|
+
el.setAttribute("y1", (Number(c.y1) - height / 2).toFixed(3));
|
|
18501
|
+
el.setAttribute("x2", (Number(c.x2 ?? width) - width / 2).toFixed(3));
|
|
18502
|
+
el.setAttribute("y2", (Number(c.y2) - height / 2).toFixed(3));
|
|
18503
|
+
}
|
|
18504
|
+
for (const stop of grad.colorStops) {
|
|
18505
|
+
const stopEl = doc.createElementNS(ns, "stop");
|
|
18506
|
+
stopEl.setAttribute("offset", String(Math.max(0, Math.min(1, Number(stop.offset) || 0))));
|
|
18507
|
+
stopEl.setAttribute("stop-color", stop.color || "#000000");
|
|
18508
|
+
el.appendChild(stopEl);
|
|
18509
|
+
}
|
|
18510
|
+
defs.appendChild(el);
|
|
18511
|
+
return `url(#${id})`;
|
|
18512
|
+
}
|
|
18513
|
+
function warpTextboxSvgAlongPath(svg, obj) {
|
|
18514
|
+
var _a, _b, _c, _d, _e;
|
|
18515
|
+
const tp = obj == null ? void 0 : obj.textPath;
|
|
18516
|
+
if (!tp || !tp.preset || tp.preset === "none") return svg;
|
|
18517
|
+
if (tp.preset === "rise" || tp.preset === "angle") {
|
|
18518
|
+
const w2 = Number(obj.width) || 0;
|
|
18519
|
+
const h2 = Number(obj.height) || 0;
|
|
18520
|
+
const fs2 = Number(obj.fontSize) || 16;
|
|
18521
|
+
const ep = tp.endpoints;
|
|
18522
|
+
const defaultLeftY = fs2 * 1.5;
|
|
18523
|
+
const defaultRightY = fs2 * 0.5;
|
|
18524
|
+
const leftY = ep && Number.isFinite(ep.leftY) ? ep.leftY : defaultLeftY;
|
|
18525
|
+
const rightY = ep && Number.isFinite(ep.rightY) ? ep.rightY : defaultRightY;
|
|
18526
|
+
const slope = w2 > 0 ? (rightY - leftY) / w2 : 0;
|
|
18527
|
+
const dy = (leftY + rightY) / 2 - h2 / 2;
|
|
18528
|
+
if (Math.abs(slope) < 1e-6 && Math.abs(dy) < 1e-6) return svg;
|
|
18529
|
+
let doc2;
|
|
18530
|
+
try {
|
|
18531
|
+
doc2 = new DOMParser().parseFromString(svg, "image/svg+xml");
|
|
18532
|
+
} catch {
|
|
18533
|
+
return svg;
|
|
18534
|
+
}
|
|
18535
|
+
const textEls2 = Array.from(doc2.querySelectorAll("text"));
|
|
18536
|
+
if (!textEls2.length) return svg;
|
|
18537
|
+
const matrix = `matrix(1 ${slope.toFixed(6)} 0 1 0 ${dy.toFixed(3)})`;
|
|
18538
|
+
for (const textEl2 of textEls2) {
|
|
18539
|
+
const existing = textEl2.getAttribute("transform");
|
|
18540
|
+
textEl2.setAttribute("transform", existing ? `${matrix} ${existing}` : matrix);
|
|
18541
|
+
}
|
|
18542
|
+
const bgShapes = Array.from(doc2.querySelectorAll("path.__pdTextBgShape"));
|
|
18543
|
+
for (const bgEl of bgShapes) {
|
|
18544
|
+
const existing = bgEl.getAttribute("transform");
|
|
18545
|
+
bgEl.setAttribute("transform", existing ? `${matrix} ${existing}` : matrix);
|
|
18546
|
+
}
|
|
18547
|
+
return new XMLSerializer().serializeToString(doc2.documentElement);
|
|
18548
|
+
}
|
|
18549
|
+
const resolved = resolveTextPath(tp, Number(obj.width) || 0, Number(obj.fontSize) || 16);
|
|
18550
|
+
if (!resolved) return svg;
|
|
18551
|
+
const pathEl = measurePath(resolved.d);
|
|
18552
|
+
if (!pathEl) return svg;
|
|
18553
|
+
const totalLen = pathEl.getTotalLength();
|
|
18554
|
+
if (!Number.isFinite(totalLen) || totalLen <= 0) return svg;
|
|
18555
|
+
const plain = String(obj.text || "").replace(/\n/g, " ");
|
|
18556
|
+
if (!plain) return svg;
|
|
18557
|
+
let doc;
|
|
18558
|
+
try {
|
|
18559
|
+
doc = new DOMParser().parseFromString(svg, "image/svg+xml");
|
|
18560
|
+
} catch {
|
|
18561
|
+
return svg;
|
|
18562
|
+
}
|
|
18563
|
+
for (const marker of Array.from(doc.querySelectorAll("g.__pdShadowRaster"))) {
|
|
18564
|
+
try {
|
|
18565
|
+
(_a = marker.parentNode) == null ? void 0 : _a.removeChild(marker);
|
|
18566
|
+
} catch {
|
|
18567
|
+
}
|
|
18568
|
+
}
|
|
18569
|
+
for (const clone of Array.from(doc.querySelectorAll("g.__pdTextShadowClone"))) {
|
|
18570
|
+
try {
|
|
18571
|
+
(_b = clone.parentNode) == null ? void 0 : _b.removeChild(clone);
|
|
18572
|
+
} catch {
|
|
18573
|
+
}
|
|
18574
|
+
}
|
|
18575
|
+
const textEls = Array.from(doc.querySelectorAll("text"));
|
|
18576
|
+
if (!textEls.length) return svg;
|
|
18577
|
+
const hasFilterInChain = (el) => {
|
|
18578
|
+
let cur = el;
|
|
18579
|
+
while (cur && cur !== doc.documentElement) {
|
|
18580
|
+
if (cur.getAttribute("filter") || /filter\s*:/i.test(cur.getAttribute("style") || "")) return true;
|
|
18581
|
+
cur = cur.parentElement;
|
|
18582
|
+
}
|
|
18583
|
+
return false;
|
|
18584
|
+
};
|
|
18585
|
+
const textEl = textEls.find((el) => !hasFilterInChain(el)) || textEls[textEls.length - 1] || textEls[0];
|
|
18586
|
+
const ff = obj.fontFamily || "Open Sans";
|
|
18587
|
+
const fs = Number(obj.fontSize) || 16;
|
|
18588
|
+
const fw = obj.fontWeight ?? 400;
|
|
18589
|
+
const fst = obj.fontStyle || "normal";
|
|
18590
|
+
const readFill = (el) => {
|
|
18591
|
+
var _a2, _b2;
|
|
18592
|
+
if (!el) return "";
|
|
18593
|
+
return el.getAttribute("fill") || ((_b2 = (_a2 = (el.getAttribute("style") || "").match(/(?:^|;)\s*fill\s*:\s*([^;]+)/i)) == null ? void 0 : _a2[1]) == null ? void 0 : _b2.trim()) || "";
|
|
18594
|
+
};
|
|
18595
|
+
const w = Number(obj.width) || 0;
|
|
18596
|
+
const h = Number(obj.height) || 0;
|
|
18597
|
+
const synthesizedGradientFill = ensureFabricGradientDef(doc, obj, w, h);
|
|
18598
|
+
const fabricGradientFill = obj.fill && typeof obj.fill === "object" && obj.fill.id != null ? `url(#SVGID_${obj.fill.id})` : "";
|
|
18599
|
+
const fillAttr = synthesizedGradientFill || readFill(textEl) || readFill(textEl.querySelector("tspan")) || fabricGradientFill || (typeof obj.fill === "string" ? obj.fill : "#000");
|
|
18600
|
+
const stripFilter = (el) => {
|
|
18601
|
+
if (!el) return;
|
|
18602
|
+
el.removeAttribute("filter");
|
|
18603
|
+
const style = el.getAttribute("style");
|
|
18604
|
+
if (style && /filter\s*:/i.test(style)) {
|
|
18605
|
+
el.setAttribute("style", style.replace(/(?:^|;)\s*filter\s*:[^;]*/gi, "").replace(/^;+/, ""));
|
|
18606
|
+
}
|
|
18607
|
+
};
|
|
18608
|
+
for (const el of Array.from(doc.querySelectorAll("*"))) stripFilter(el);
|
|
18609
|
+
for (const filter of Array.from(doc.querySelectorAll("filter"))) {
|
|
18610
|
+
try {
|
|
18611
|
+
(_c = filter.parentNode) == null ? void 0 : _c.removeChild(filter);
|
|
18612
|
+
} catch {
|
|
18613
|
+
}
|
|
18614
|
+
}
|
|
18615
|
+
let shadowConfig = null;
|
|
18616
|
+
if (obj.shadow) {
|
|
18617
|
+
const sh = obj.shadow;
|
|
18618
|
+
const color = sh.color || "rgba(0,0,0,0.5)";
|
|
18619
|
+
const blur = Math.max(0, Number(sh.blur) || 0);
|
|
18620
|
+
const dx = Number(sh.offsetX) || 0;
|
|
18621
|
+
const dy = Number(sh.offsetY) || 0;
|
|
18622
|
+
shadowConfig = { color, dx, dy, blur };
|
|
18623
|
+
}
|
|
18624
|
+
const bgCfg = obj.__pdBg;
|
|
18625
|
+
const extOX = Number((bgCfg == null ? void 0 : bgCfg.shadowOffsetX) ?? 0) || 0;
|
|
18626
|
+
const extOY = Number((bgCfg == null ? void 0 : bgCfg.shadowOffsetY) ?? 0) || 0;
|
|
18627
|
+
const extDist = Math.hypot(extOX, extOY);
|
|
18628
|
+
const extColor = bgCfg == null ? void 0 : bgCfg.shadowColor;
|
|
18629
|
+
const hasExtShadowColor = !!extColor && extColor !== "transparent";
|
|
18630
|
+
const affectsText = !bgCfg || bgCfg.shadowAffectsText !== false;
|
|
18631
|
+
const blockShadowActive = !!bgCfg && bgCfg.shadowType === "block" && hasExtShadowColor && extDist > 0 && affectsText;
|
|
18632
|
+
const lineShadowActive = !!bgCfg && bgCfg.shadowType === "line" && hasExtShadowColor && extDist > 0 && affectsText;
|
|
18633
|
+
let blockSteps = 0;
|
|
18634
|
+
let blockStepX = 0;
|
|
18635
|
+
let blockStepY = 0;
|
|
18636
|
+
if (blockShadowActive) {
|
|
18637
|
+
const STEP = 1;
|
|
18638
|
+
blockSteps = Math.min(200, Math.max(1, Math.ceil(extDist / STEP)));
|
|
18639
|
+
blockStepX = extOX / blockSteps;
|
|
18640
|
+
blockStepY = extOY / blockSteps;
|
|
18641
|
+
}
|
|
18642
|
+
const flowStops = (obj == null ? void 0 : obj.fill) && typeof obj.fill === "object" && Array.isArray(obj.fill.colorStops) && obj.fill.colorStops.length ? obj.fill.colorStops.map((s) => ({ offset: Number(s.offset) || 0, color: s.color || "#000" })) : null;
|
|
18643
|
+
const gradId = (fillAttr.match(/url\(#([^)]+)\)/) || [])[1];
|
|
18644
|
+
if (gradId && w > 0 && h > 0) {
|
|
18645
|
+
const grad = doc.getElementById(gradId);
|
|
18646
|
+
if (grad && grad.getAttribute("gradientUnits") !== "userSpaceOnUse") {
|
|
18647
|
+
const tag = grad.tagName.toLowerCase();
|
|
18648
|
+
const num = (v, fallback) => {
|
|
18649
|
+
if (v == null) return fallback;
|
|
18650
|
+
const n = parseFloat(v);
|
|
18651
|
+
return Number.isFinite(n) ? n : fallback;
|
|
18652
|
+
};
|
|
18653
|
+
const mapX = (u) => -w / 2 + u * w;
|
|
18654
|
+
const mapY = (u) => -h / 2 + u * h;
|
|
18655
|
+
grad.setAttribute("gradientUnits", "userSpaceOnUse");
|
|
18656
|
+
if (tag === "lineargradient") {
|
|
18657
|
+
const x1 = num(grad.getAttribute("x1"), 0);
|
|
18658
|
+
const y1 = num(grad.getAttribute("y1"), 0);
|
|
18659
|
+
const x2 = num(grad.getAttribute("x2"), 1);
|
|
18660
|
+
const y2 = num(grad.getAttribute("y2"), 0);
|
|
18661
|
+
grad.setAttribute("x1", mapX(x1).toFixed(3));
|
|
18662
|
+
grad.setAttribute("y1", mapY(y1).toFixed(3));
|
|
18663
|
+
grad.setAttribute("x2", mapX(x2).toFixed(3));
|
|
18664
|
+
grad.setAttribute("y2", mapY(y2).toFixed(3));
|
|
18665
|
+
} else if (tag === "radialgradient") {
|
|
18666
|
+
const cx = num(grad.getAttribute("cx"), 0.5);
|
|
18667
|
+
const cy = num(grad.getAttribute("cy"), 0.5);
|
|
18668
|
+
const r = num(grad.getAttribute("r"), 0.5);
|
|
18669
|
+
const fx = num(grad.getAttribute("fx"), cx);
|
|
18670
|
+
const fy = num(grad.getAttribute("fy"), cy);
|
|
18671
|
+
grad.setAttribute("cx", mapX(cx).toFixed(3));
|
|
18672
|
+
grad.setAttribute("cy", mapY(cy).toFixed(3));
|
|
18673
|
+
grad.setAttribute("fx", mapX(fx).toFixed(3));
|
|
18674
|
+
grad.setAttribute("fy", mapY(fy).toFixed(3));
|
|
18675
|
+
grad.setAttribute("r", (r * Math.max(w, h)).toFixed(3));
|
|
18676
|
+
}
|
|
18677
|
+
}
|
|
18678
|
+
}
|
|
18679
|
+
const measure = document.createElement("canvas").getContext("2d");
|
|
18680
|
+
if (!measure) return svg;
|
|
18681
|
+
measure.font = `${fst} ${fw} ${fs}px "${ff}"`;
|
|
18682
|
+
const chars = Array.from(plain);
|
|
18683
|
+
const spacing = (Number(obj.charSpacing) || 0) * fs / 1e3;
|
|
18684
|
+
const widths = chars.map((c) => measure.measureText(c).width + spacing);
|
|
18685
|
+
const totalWidth = widths.reduce((a, b) => a + b, 0);
|
|
18686
|
+
const baselineDy = resolveTextPathAlphabeticBaselineDy(measure, plain, fs);
|
|
18687
|
+
let cursor = 0;
|
|
18688
|
+
if (obj.textAlign === "center") cursor = Math.max(0, (totalLen - totalWidth) / 2);
|
|
18689
|
+
else if (obj.textAlign === "right") cursor = Math.max(0, totalLen - totalWidth);
|
|
18690
|
+
const halfW = (Number(obj.width) || 0) / 2;
|
|
18691
|
+
const halfH = (Number(obj.height) || 0) / 2;
|
|
18692
|
+
const glyphSvg = [];
|
|
18693
|
+
const shadowSvg = [];
|
|
18694
|
+
const blockShadowSvg = [];
|
|
18695
|
+
const lineShadowSvg = [];
|
|
18696
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
18697
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
18698
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
18699
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
18700
|
+
for (let i = 0; i < chars.length; i++) {
|
|
18701
|
+
const cw = widths[i];
|
|
18702
|
+
const mid = cursor + cw / 2;
|
|
18703
|
+
cursor += cw;
|
|
18704
|
+
if (mid > totalLen) break;
|
|
18705
|
+
const p = pathEl.getPointAtLength(Math.max(0, mid));
|
|
18706
|
+
const ahead = pathEl.getPointAtLength(Math.min(totalLen, mid + 0.5));
|
|
18707
|
+
const deg = Math.atan2(ahead.y - p.y, ahead.x - p.x) * 180 / Math.PI;
|
|
18708
|
+
const x = p.x - halfW;
|
|
18709
|
+
const y = p.y - halfH;
|
|
18710
|
+
const glyphPad = Math.max(fs, cw) * 0.75;
|
|
18711
|
+
minX = Math.min(minX, x - glyphPad);
|
|
18712
|
+
minY = Math.min(minY, y - glyphPad - fs);
|
|
18713
|
+
maxX = Math.max(maxX, x + glyphPad);
|
|
18714
|
+
maxY = Math.max(maxY, y + glyphPad);
|
|
18715
|
+
const glyphFill = flowStops ? sampleGradientColor(flowStops, chars.length > 1 ? i / (chars.length - 1) : 0) : fillAttr;
|
|
18716
|
+
if (blockShadowActive) {
|
|
18717
|
+
for (let s = blockSteps; s >= 1; s--) {
|
|
18718
|
+
const bx = x + blockStepX * s;
|
|
18719
|
+
const by = y + blockStepY * s;
|
|
18720
|
+
blockShadowSvg.push(
|
|
18721
|
+
`<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(String(extColor))}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-block-shadow="true" transform="translate(${bx.toFixed(3)} ${by.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
|
|
18722
|
+
);
|
|
18723
|
+
}
|
|
18724
|
+
}
|
|
18725
|
+
if (lineShadowActive) {
|
|
18726
|
+
const lx = x + extOX;
|
|
18727
|
+
const ly = y + extOY;
|
|
18728
|
+
const lineStrokeW = LINE_SHADOW_STROKE_WIDTH;
|
|
18729
|
+
lineShadowSvg.push(
|
|
18730
|
+
`<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="none" stroke="${escapeXml(String(extColor))}" stroke-width="${lineStrokeW.toFixed(3)}" stroke-linejoin="round" paint-order="stroke" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-line-shadow="true" transform="translate(${lx.toFixed(3)} ${ly.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
|
|
18731
|
+
);
|
|
18732
|
+
}
|
|
18733
|
+
if (shadowConfig) {
|
|
18734
|
+
const sx = x + shadowConfig.dx;
|
|
18735
|
+
const sy = y + shadowConfig.dy;
|
|
18736
|
+
shadowSvg.push(
|
|
18737
|
+
`<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(shadowConfig.color)}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-shadow="true" transform="translate(${sx.toFixed(3)} ${sy.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
|
|
18738
|
+
);
|
|
18739
|
+
}
|
|
18740
|
+
glyphSvg.push(
|
|
18741
|
+
`<text font-family="${escapeXml(String(ff))}" font-size="${fs}" font-weight="${fw}" font-style="${fst}" data-source-font-family="${escapeXml(String(ff))}" data-source-font-weight="${escapeXml(String(fw))}" data-source-font-style="${escapeXml(String(fst))}" fill="${escapeXml(glyphFill)}" text-anchor="middle" y="${baselineDy.toFixed(3)}" data-pixldocs-warp-glyph="true" transform="translate(${x.toFixed(3)} ${y.toFixed(3)}) rotate(${deg.toFixed(3)})">${escapeXml(chars[i])}</text>`
|
|
18742
|
+
);
|
|
18743
|
+
}
|
|
18744
|
+
const replacement = doc.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
18745
|
+
replacement.setAttribute("data-pixldocs-warped", "true");
|
|
18746
|
+
let innerHtml = "";
|
|
18747
|
+
if (shadowConfig && shadowSvg.length) {
|
|
18748
|
+
const blur = Math.max(0, Number(shadowConfig.blur) || 0);
|
|
18749
|
+
if (blur > 0 && Number.isFinite(minX) && Number.isFinite(maxX)) {
|
|
18750
|
+
const pad = Math.max(8, blur * 3);
|
|
18751
|
+
const sMinX = minX + shadowConfig.dx - pad;
|
|
18752
|
+
const sMinY = minY + shadowConfig.dy - pad;
|
|
18753
|
+
const sMaxX = maxX + shadowConfig.dx + pad;
|
|
18754
|
+
const sMaxY = maxY + shadowConfig.dy + pad;
|
|
18755
|
+
const bw = Math.max(1, sMaxX - sMinX);
|
|
18756
|
+
const bh = Math.max(1, sMaxY - sMinY);
|
|
18757
|
+
innerHtml += `<g class="__pdShadowRaster" data-pixldocs-warp-shadow-group="true" data-blur="${blur}" data-ox="0" data-oy="0" data-bx="${sMinX.toFixed(3)}" data-by="${sMinY.toFixed(3)}" data-bw="${bw.toFixed(3)}" data-bh="${bh.toFixed(3)}">${shadowSvg.join("")}</g>`;
|
|
18758
|
+
} else {
|
|
18759
|
+
innerHtml += `<g data-pixldocs-warp-shadow-group="true">${shadowSvg.join("")}</g>`;
|
|
18760
|
+
}
|
|
18761
|
+
}
|
|
18762
|
+
if (lineShadowSvg.length) {
|
|
18763
|
+
innerHtml = `<g data-pixldocs-warp-line-shadow-group="true">${lineShadowSvg.join("")}</g>` + innerHtml;
|
|
18764
|
+
}
|
|
18765
|
+
if (blockShadowSvg.length) {
|
|
18766
|
+
innerHtml = `<g data-pixldocs-warp-block-shadow-group="true">${blockShadowSvg.join("")}</g>` + innerHtml;
|
|
18767
|
+
}
|
|
18768
|
+
innerHtml += glyphSvg.join("");
|
|
18769
|
+
replacement.innerHTML = innerHtml;
|
|
18770
|
+
(_d = textEl.parentNode) == null ? void 0 : _d.replaceChild(replacement, textEl);
|
|
18771
|
+
for (let i = 1; i < textEls.length; i++) {
|
|
18772
|
+
try {
|
|
18773
|
+
(_e = textEls[i].parentNode) == null ? void 0 : _e.removeChild(textEls[i]);
|
|
18774
|
+
} catch {
|
|
18775
|
+
}
|
|
18776
|
+
}
|
|
18777
|
+
const serialized = new XMLSerializer().serializeToString(doc.documentElement);
|
|
18778
|
+
return serialized;
|
|
18779
|
+
}
|
|
16807
18780
|
function stampFabricLineMetricsOnTextSvg(svg, obj) {
|
|
16808
18781
|
const lines = Array.isArray(obj == null ? void 0 : obj._textLines) ? obj._textLines : [];
|
|
16809
18782
|
if (!lines.length || typeof (obj == null ? void 0 : obj.getLineWidth) !== "function") return svg;
|
|
@@ -16874,6 +18847,7 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
16874
18847
|
obj.toSVG = (reviver) => {
|
|
16875
18848
|
let svg = originalToSVG(reviver);
|
|
16876
18849
|
if (isTextboxLike(obj)) svg = stampFabricLineMetricsOnTextSvg(svg, obj);
|
|
18850
|
+
if (isTextboxLike(obj)) svg = warpTextboxSvgAlongPath(svg, obj);
|
|
16877
18851
|
if (imageId) svg = stampPixldocsImageIdOnSvg(svg, imageId);
|
|
16878
18852
|
return svg;
|
|
16879
18853
|
};
|
|
@@ -16968,9 +18942,9 @@ function captureFabricCanvasSvgForPdf(fabricInstance, canvasWidth, canvasHeight)
|
|
|
16968
18942
|
}
|
|
16969
18943
|
return svgString;
|
|
16970
18944
|
}
|
|
16971
|
-
const resolvedPackageVersion = "0.5.
|
|
18945
|
+
const resolvedPackageVersion = "0.5.206";
|
|
16972
18946
|
const PACKAGE_VERSION = resolvedPackageVersion;
|
|
16973
|
-
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.
|
|
18947
|
+
const DEPLOYMENT_VERSION_MARKER = "__PIXLDOCS_CANVAS_RENDERER_VERSION__:0.5.206";
|
|
16974
18948
|
const roundParityValue = (value) => {
|
|
16975
18949
|
if (typeof value !== "number") return value;
|
|
16976
18950
|
return Number.isFinite(value) ? Number(value.toFixed(3)) : value;
|
|
@@ -17649,7 +19623,7 @@ class PixldocsRenderer {
|
|
|
17649
19623
|
await this.waitForCanvasScene(container, cloned, i);
|
|
17650
19624
|
}
|
|
17651
19625
|
console.log(`[canvas-renderer][pdf-unified] mounted ${cloned.pages.length} page(s), handing off to client exportMultiPagePdf`);
|
|
17652
|
-
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
19626
|
+
const { exportMultiPagePdf, preparePagesForExport } = await Promise.resolve().then(() => require("./vectorPdfExport-C0s166DN.cjs"));
|
|
17653
19627
|
const prepared = preparePagesForExport(
|
|
17654
19628
|
cloned.pages,
|
|
17655
19629
|
canvasWidth,
|
|
@@ -19833,7 +21807,7 @@ async function prepareLiveCanvasSvgForPdf(rawSvg, pageWidth, pageHeight, pageKey
|
|
|
19833
21807
|
if (options == null ? void 0 : options.stripPageBackground) stripRootPageBackgroundFromSvg(svgToDraw);
|
|
19834
21808
|
sanitizeSvgTreeForPdf(svgToDraw);
|
|
19835
21809
|
try {
|
|
19836
|
-
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-
|
|
21810
|
+
const { bakeTextAnchorPositionsFromLiveSvg, logTextMeasurementDiagnostic } = await Promise.resolve().then(() => require("./vectorPdfExport-C0s166DN.cjs"));
|
|
19837
21811
|
try {
|
|
19838
21812
|
await logTextMeasurementDiagnostic(svgToDraw);
|
|
19839
21813
|
} catch {
|
|
@@ -19965,7 +21939,7 @@ async function assemblePdfFromSvgs(svgResults, options = {}) {
|
|
|
19965
21939
|
);
|
|
19966
21940
|
}
|
|
19967
21941
|
try {
|
|
19968
|
-
const { prepareSvgTextForPdfMode } = await Promise.resolve().then(() => require("./svgTextToPath-
|
|
21942
|
+
const { prepareSvgTextForPdfMode } = await Promise.resolve().then(() => require("./svgTextToPath-BT7lcwLT.cjs"));
|
|
19969
21943
|
pageSvg = await prepareSvgTextForPdfMode(pageSvg, textMode, fontBaseUrl);
|
|
19970
21944
|
try {
|
|
19971
21945
|
dumpSvgTextDiagnostics(pageSvg, i, PARITY_TAG, "STAGE-1b-after-shared-text-prep");
|
|
@@ -20230,4 +22204,4 @@ exports.setAutoShrinkDebug = setAutoShrinkDebug;
|
|
|
20230
22204
|
exports.setBundledAssetPrefixes = setBundledAssetPrefixes;
|
|
20231
22205
|
exports.warmResolvedTemplateForPreview = warmResolvedTemplateForPreview;
|
|
20232
22206
|
exports.warmTemplateFromForm = warmTemplateFromForm;
|
|
20233
|
-
//# sourceMappingURL=index-
|
|
22207
|
+
//# sourceMappingURL=index-B1kaODSZ.cjs.map
|