@pixldocs/canvas-renderer 0.5.18 → 0.5.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +177 -106
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +177 -106
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11844,6 +11844,83 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
11844
11844
|
});
|
|
11845
11845
|
}
|
|
11846
11846
|
}
|
|
11847
|
+
const TEXT_TYPES = /* @__PURE__ */ new Set(["textbox", "text", "i-text"]);
|
|
11848
|
+
function getTextLines(obj) {
|
|
11849
|
+
const lines = Array.isArray(obj.textLines) && obj.textLines.length ? obj.textLines : String(obj.text || "").split("\n");
|
|
11850
|
+
return lines.map((line) => Array.isArray(line) ? line.join("") : String(line ?? ""));
|
|
11851
|
+
}
|
|
11852
|
+
function measureLineWidth(obj, line) {
|
|
11853
|
+
if (typeof document === "undefined") return 0;
|
|
11854
|
+
const canvas = document.createElement("canvas");
|
|
11855
|
+
const ctx = canvas.getContext("2d");
|
|
11856
|
+
if (!ctx) return 0;
|
|
11857
|
+
const fontStyle = obj.fontStyle || "normal";
|
|
11858
|
+
const fontWeight = obj.fontWeight || 400;
|
|
11859
|
+
const fontSize = obj.fontSize || 16;
|
|
11860
|
+
const fontFamily = obj.fontFamily || "sans-serif";
|
|
11861
|
+
ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
11862
|
+
const charSpacing = Number(obj.charSpacing || 0) / 1e3 * fontSize;
|
|
11863
|
+
return ctx.measureText(line).width + Math.max(0, line.length - 1) * charSpacing;
|
|
11864
|
+
}
|
|
11865
|
+
function getFabricCanvasFromContainer(container) {
|
|
11866
|
+
const registry2 = window.__fabricCanvasRegistry;
|
|
11867
|
+
if (registry2 instanceof Map) {
|
|
11868
|
+
for (const entry of registry2.values()) {
|
|
11869
|
+
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
11870
|
+
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
11871
|
+
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
11872
|
+
if (el && container.contains(el)) return canvas;
|
|
11873
|
+
}
|
|
11874
|
+
}
|
|
11875
|
+
return null;
|
|
11876
|
+
}
|
|
11877
|
+
function stabilizeFabricTextObjects(fabricInstance) {
|
|
11878
|
+
var _a, _b, _c;
|
|
11879
|
+
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
11880
|
+
clearFabricCharCache();
|
|
11881
|
+
clearMeasurementCache();
|
|
11882
|
+
const walk = (obj) => {
|
|
11883
|
+
var _a2, _b2, _c2, _d;
|
|
11884
|
+
if (!obj) return;
|
|
11885
|
+
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
11886
|
+
if (children.length) children.forEach(walk);
|
|
11887
|
+
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (TEXT_TYPES.has(obj.type) || obj.isEditing !== void 0);
|
|
11888
|
+
if (!isTextObject) return;
|
|
11889
|
+
const saved = { width: obj.width, scaleX: obj.scaleX, scaleY: obj.scaleY };
|
|
11890
|
+
const reset = () => {
|
|
11891
|
+
var _a3;
|
|
11892
|
+
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
11893
|
+
obj.__charBounds = [];
|
|
11894
|
+
obj.__lineWidths = [];
|
|
11895
|
+
obj.__lineHeights = [];
|
|
11896
|
+
obj.__graphemeLines = [];
|
|
11897
|
+
obj._textLines = [];
|
|
11898
|
+
obj.textLines = [];
|
|
11899
|
+
obj._styleMap = null;
|
|
11900
|
+
obj.styleMap = null;
|
|
11901
|
+
obj.dirty = true;
|
|
11902
|
+
};
|
|
11903
|
+
reset();
|
|
11904
|
+
obj.initDimensions();
|
|
11905
|
+
if (saved.width != null) {
|
|
11906
|
+
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11907
|
+
reset();
|
|
11908
|
+
obj.initDimensions();
|
|
11909
|
+
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11910
|
+
}
|
|
11911
|
+
if (obj.underline || obj.linethrough) {
|
|
11912
|
+
const lineWidths = Array.isArray(obj.__lineWidths) ? obj.__lineWidths : [];
|
|
11913
|
+
obj.__lineWidths = getTextLines(obj).map((line, index) => Math.max(lineWidths[index] || 0, measureLineWidth(obj, line)));
|
|
11914
|
+
}
|
|
11915
|
+
obj.dirty = true;
|
|
11916
|
+
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
11917
|
+
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
11918
|
+
};
|
|
11919
|
+
fabricInstance.getObjects().forEach(walk);
|
|
11920
|
+
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
11921
|
+
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
11922
|
+
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
11923
|
+
}
|
|
11847
11924
|
function PixldocsPreview(props) {
|
|
11848
11925
|
const {
|
|
11849
11926
|
pageIndex = 0,
|
|
@@ -11940,6 +12017,13 @@ function PixldocsPreview(props) {
|
|
|
11940
12017
|
() => `${pageIndex}-${fontsReadyVersion}-${stabilizationPass}`,
|
|
11941
12018
|
[pageIndex, fontsReadyVersion, stabilizationPass]
|
|
11942
12019
|
);
|
|
12020
|
+
const previewWrapRef = useCallback((node) => {
|
|
12021
|
+
if (!node || !config) return;
|
|
12022
|
+
requestAnimationFrame(() => {
|
|
12023
|
+
const fabricCanvas = getFabricCanvasFromContainer(node);
|
|
12024
|
+
if (fabricCanvas) stabilizeFabricTextObjects(fabricCanvas);
|
|
12025
|
+
});
|
|
12026
|
+
}, [config, previewKey]);
|
|
11943
12027
|
useEffect(() => {
|
|
11944
12028
|
if (isResolveMode) return;
|
|
11945
12029
|
if (!config) {
|
|
@@ -11970,7 +12054,7 @@ function PixldocsPreview(props) {
|
|
|
11970
12054
|
return /* @__PURE__ */ jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
11971
12055
|
}
|
|
11972
12056
|
return /* @__PURE__ */ jsxs("div", { className, style: { ...style, position: "relative" }, children: [
|
|
11973
|
-
/* @__PURE__ */ jsx("div", { style: { visibility: canvasSettled ? "visible" : "hidden" }, children: /* @__PURE__ */ jsx(
|
|
12057
|
+
/* @__PURE__ */ jsx("div", { ref: previewWrapRef, style: { visibility: canvasSettled ? "visible" : "hidden" }, children: /* @__PURE__ */ jsx(
|
|
11974
12058
|
PreviewCanvas,
|
|
11975
12059
|
{
|
|
11976
12060
|
config,
|
|
@@ -11985,6 +12069,66 @@ function PixldocsPreview(props) {
|
|
|
11985
12069
|
!canvasSettled && /* @__PURE__ */ jsx("div", { style: { position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) })
|
|
11986
12070
|
] });
|
|
11987
12071
|
}
|
|
12072
|
+
const inlinedAssetCache = /* @__PURE__ */ new Map();
|
|
12073
|
+
function shouldInlineImageUrl(url) {
|
|
12074
|
+
if (!url || url.startsWith("data:")) return false;
|
|
12075
|
+
if (url.startsWith("blob:")) return true;
|
|
12076
|
+
if (url.startsWith("/") && !url.startsWith("//")) return true;
|
|
12077
|
+
try {
|
|
12078
|
+
const parsed = new URL(url, window.location.href);
|
|
12079
|
+
const current = new URL(window.location.href);
|
|
12080
|
+
const host = parsed.hostname.toLowerCase();
|
|
12081
|
+
return parsed.origin === current.origin || host === "localhost" || host === "127.0.0.1" || host === "0.0.0.0" || host.endsWith(".local") || /^(10\.|192\.168\.|169\.254\.)/.test(host);
|
|
12082
|
+
} catch {
|
|
12083
|
+
return false;
|
|
12084
|
+
}
|
|
12085
|
+
}
|
|
12086
|
+
async function imageUrlToDataUrl(url) {
|
|
12087
|
+
if (inlinedAssetCache.has(url)) return inlinedAssetCache.get(url) ?? null;
|
|
12088
|
+
try {
|
|
12089
|
+
const response = await fetch(url);
|
|
12090
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
12091
|
+
const blob = await response.blob();
|
|
12092
|
+
if (blob.type.includes("text/html")) throw new Error("Expected image but got text/html");
|
|
12093
|
+
const dataUrl = await new Promise((resolve, reject) => {
|
|
12094
|
+
const reader = new FileReader();
|
|
12095
|
+
reader.onloadend = () => resolve(String(reader.result || ""));
|
|
12096
|
+
reader.onerror = reject;
|
|
12097
|
+
reader.readAsDataURL(blob);
|
|
12098
|
+
});
|
|
12099
|
+
inlinedAssetCache.set(url, dataUrl);
|
|
12100
|
+
return dataUrl;
|
|
12101
|
+
} catch (error) {
|
|
12102
|
+
console.warn("[@pixldocs/canvas-renderer] Failed to inline image asset:", url, error);
|
|
12103
|
+
inlinedAssetCache.set(url, null);
|
|
12104
|
+
return null;
|
|
12105
|
+
}
|
|
12106
|
+
}
|
|
12107
|
+
async function inlineNodeAssets(node) {
|
|
12108
|
+
if (node.type === "image") {
|
|
12109
|
+
const url = typeof node.src === "string" && node.src.trim() ? node.src.trim() : typeof node.imageUrl === "string" ? node.imageUrl.trim() : "";
|
|
12110
|
+
if (shouldInlineImageUrl(url)) {
|
|
12111
|
+
const dataUrl = await imageUrlToDataUrl(url);
|
|
12112
|
+
if (dataUrl) {
|
|
12113
|
+
node.src = dataUrl;
|
|
12114
|
+
node.imageUrl = dataUrl;
|
|
12115
|
+
}
|
|
12116
|
+
}
|
|
12117
|
+
}
|
|
12118
|
+
if (Array.isArray(node.children)) {
|
|
12119
|
+
await Promise.all(node.children.map(inlineNodeAssets));
|
|
12120
|
+
}
|
|
12121
|
+
}
|
|
12122
|
+
async function inlineBrowserReachableImageAssets(config) {
|
|
12123
|
+
if (typeof window === "undefined" || typeof fetch === "undefined" || typeof FileReader === "undefined") {
|
|
12124
|
+
return config;
|
|
12125
|
+
}
|
|
12126
|
+
const cloned = JSON.parse(JSON.stringify(config));
|
|
12127
|
+
await Promise.all(
|
|
12128
|
+
(cloned.pages || []).flatMap((page) => (page.children || []).map(inlineNodeAssets))
|
|
12129
|
+
);
|
|
12130
|
+
return cloned;
|
|
12131
|
+
}
|
|
11988
12132
|
class PixldocsRenderer {
|
|
11989
12133
|
constructor(config) {
|
|
11990
12134
|
__publicField(this, "config");
|
|
@@ -11995,21 +12139,22 @@ class PixldocsRenderer {
|
|
|
11995
12139
|
* Mounts a hidden PreviewCanvas component and captures the Fabric canvas output.
|
|
11996
12140
|
*/
|
|
11997
12141
|
async render(templateConfig, options = {}) {
|
|
12142
|
+
const renderConfig = await inlineBrowserReachableImageAssets(templateConfig);
|
|
11998
12143
|
const pageIndex = options.pageIndex ?? 0;
|
|
11999
12144
|
const format = options.format ?? "png";
|
|
12000
12145
|
const quality = options.quality ?? 0.92;
|
|
12001
12146
|
const pixelRatio = options.pixelRatio ?? this.config.pixelRatio ?? 2;
|
|
12002
|
-
const canvasWidth =
|
|
12003
|
-
const canvasHeight =
|
|
12004
|
-
const page =
|
|
12147
|
+
const canvasWidth = renderConfig.canvas.width;
|
|
12148
|
+
const canvasHeight = renderConfig.canvas.height;
|
|
12149
|
+
const page = renderConfig.pages[pageIndex];
|
|
12005
12150
|
if (!page) {
|
|
12006
|
-
throw new Error(`Page index ${pageIndex} not found (template has ${
|
|
12151
|
+
throw new Error(`Page index ${pageIndex} not found (template has ${renderConfig.pages.length} pages)`);
|
|
12007
12152
|
}
|
|
12008
|
-
await ensureFontsForResolvedConfig(
|
|
12153
|
+
await ensureFontsForResolvedConfig(renderConfig);
|
|
12009
12154
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
12010
12155
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
12011
12156
|
const dataUrl = await this.renderPageViaPreviewCanvas(
|
|
12012
|
-
|
|
12157
|
+
renderConfig,
|
|
12013
12158
|
pageIndex,
|
|
12014
12159
|
pixelRatio,
|
|
12015
12160
|
format,
|
|
@@ -12061,16 +12206,17 @@ class PixldocsRenderer {
|
|
|
12061
12206
|
* This is the key building block for client-side vector PDF export.
|
|
12062
12207
|
*/
|
|
12063
12208
|
async renderPageSvg(templateConfig, pageIndex = 0) {
|
|
12064
|
-
const
|
|
12209
|
+
const renderConfig = await inlineBrowserReachableImageAssets(templateConfig);
|
|
12210
|
+
const page = renderConfig.pages[pageIndex];
|
|
12065
12211
|
if (!page) {
|
|
12066
|
-
throw new Error(`Page index ${pageIndex} not found (template has ${
|
|
12212
|
+
throw new Error(`Page index ${pageIndex} not found (template has ${renderConfig.pages.length} pages)`);
|
|
12067
12213
|
}
|
|
12068
|
-
await ensureFontsForResolvedConfig(
|
|
12214
|
+
await ensureFontsForResolvedConfig(renderConfig);
|
|
12069
12215
|
const { setPackageApiUrl: setPackageApiUrl2 } = await Promise.resolve().then(() => appApi);
|
|
12070
12216
|
setPackageApiUrl2(this.config.imageProxyUrl);
|
|
12071
|
-
const canvasWidth =
|
|
12072
|
-
const canvasHeight =
|
|
12073
|
-
return this.captureSvgViaPreviewCanvas(
|
|
12217
|
+
const canvasWidth = renderConfig.canvas.width;
|
|
12218
|
+
const canvasHeight = renderConfig.canvas.height;
|
|
12219
|
+
return this.captureSvgViaPreviewCanvas(renderConfig, pageIndex, canvasWidth, canvasHeight);
|
|
12074
12220
|
}
|
|
12075
12221
|
/**
|
|
12076
12222
|
* Render all pages and return SVG strings for each.
|
|
@@ -12418,7 +12564,7 @@ class PixldocsRenderer {
|
|
|
12418
12564
|
cleanup();
|
|
12419
12565
|
reject(new Error("Render timeout (30s)"));
|
|
12420
12566
|
}, 3e4);
|
|
12421
|
-
let
|
|
12567
|
+
let finished = false;
|
|
12422
12568
|
const cleanup = () => {
|
|
12423
12569
|
clearTimeout(timeout);
|
|
12424
12570
|
try {
|
|
@@ -12428,22 +12574,12 @@ class PixldocsRenderer {
|
|
|
12428
12574
|
container.remove();
|
|
12429
12575
|
};
|
|
12430
12576
|
const onReady = () => {
|
|
12431
|
-
if (
|
|
12432
|
-
|
|
12433
|
-
root.render(
|
|
12434
|
-
createElement(PreviewCanvas2, {
|
|
12435
|
-
config,
|
|
12436
|
-
pageIndex,
|
|
12437
|
-
zoom: pixelRatio,
|
|
12438
|
-
absoluteZoom: true,
|
|
12439
|
-
skipFontReadyWait: true,
|
|
12440
|
-
onReady
|
|
12441
|
-
})
|
|
12442
|
-
);
|
|
12443
|
-
return;
|
|
12444
|
-
}
|
|
12577
|
+
if (finished) return;
|
|
12578
|
+
finished = true;
|
|
12445
12579
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12446
12580
|
try {
|
|
12581
|
+
await this.waitForStableTextMetrics(container, config);
|
|
12582
|
+
await this.waitForCanvasScene(container, config, pageIndex, 2500, 50);
|
|
12447
12583
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12448
12584
|
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
12449
12585
|
await this.waitForCanvasImages(container, expectedImageCount);
|
|
@@ -12514,7 +12650,7 @@ class PixldocsRenderer {
|
|
|
12514
12650
|
cleanup();
|
|
12515
12651
|
reject(new Error("SVG render timeout (30s)"));
|
|
12516
12652
|
}, 3e4);
|
|
12517
|
-
let
|
|
12653
|
+
let finished = false;
|
|
12518
12654
|
const cleanup = () => {
|
|
12519
12655
|
clearTimeout(timeout);
|
|
12520
12656
|
try {
|
|
@@ -12524,23 +12660,13 @@ class PixldocsRenderer {
|
|
|
12524
12660
|
container.remove();
|
|
12525
12661
|
};
|
|
12526
12662
|
const onReady = () => {
|
|
12527
|
-
if (
|
|
12528
|
-
|
|
12529
|
-
root.render(
|
|
12530
|
-
createElement(PreviewCanvas2, {
|
|
12531
|
-
config,
|
|
12532
|
-
pageIndex,
|
|
12533
|
-
zoom: 1,
|
|
12534
|
-
absoluteZoom: true,
|
|
12535
|
-
skipFontReadyWait: true,
|
|
12536
|
-
onReady
|
|
12537
|
-
})
|
|
12538
|
-
);
|
|
12539
|
-
return;
|
|
12540
|
-
}
|
|
12663
|
+
if (finished) return;
|
|
12664
|
+
finished = true;
|
|
12541
12665
|
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12542
12666
|
var _a, _b;
|
|
12543
12667
|
try {
|
|
12668
|
+
await this.waitForStableTextMetrics(container, config);
|
|
12669
|
+
await this.waitForCanvasScene(container, config, pageIndex, 2500, 50);
|
|
12544
12670
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12545
12671
|
if (!fabricInstance) {
|
|
12546
12672
|
cleanup();
|
|
@@ -12660,16 +12786,7 @@ class PixldocsRenderer {
|
|
|
12660
12786
|
* using the global __fabricCanvasRegistry (set by PageCanvas).
|
|
12661
12787
|
*/
|
|
12662
12788
|
getFabricCanvasFromContainer(container) {
|
|
12663
|
-
|
|
12664
|
-
if (registry2 instanceof Map) {
|
|
12665
|
-
for (const entry of registry2.values()) {
|
|
12666
|
-
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
12667
|
-
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
12668
|
-
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
12669
|
-
if (el && container.contains(el)) return canvas;
|
|
12670
|
-
}
|
|
12671
|
-
}
|
|
12672
|
-
return null;
|
|
12789
|
+
return getFabricCanvasFromContainer(container);
|
|
12673
12790
|
}
|
|
12674
12791
|
async waitForStableTextMetrics(container, config) {
|
|
12675
12792
|
if (typeof document !== "undefined") {
|
|
@@ -12683,59 +12800,7 @@ class PixldocsRenderer {
|
|
|
12683
12800
|
clearFabricCharCache();
|
|
12684
12801
|
clearMeasurementCache();
|
|
12685
12802
|
};
|
|
12686
|
-
const reflowTextboxes = () =>
|
|
12687
|
-
var _a, _b, _c;
|
|
12688
|
-
const walk = (obj) => {
|
|
12689
|
-
var _a2, _b2, _c2, _d;
|
|
12690
|
-
if (!obj) return;
|
|
12691
|
-
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12692
|
-
if (children.length) children.forEach(walk);
|
|
12693
|
-
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (obj.type === "textbox" || obj.type === "text" || obj.type === "i-text" || obj.isEditing !== void 0);
|
|
12694
|
-
if (isTextObject) {
|
|
12695
|
-
const saved = {
|
|
12696
|
-
width: obj.width,
|
|
12697
|
-
scaleX: obj.scaleX,
|
|
12698
|
-
scaleY: obj.scaleY
|
|
12699
|
-
};
|
|
12700
|
-
const resetTextboxLayoutInternals = () => {
|
|
12701
|
-
var _a3;
|
|
12702
|
-
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
12703
|
-
obj.__charBounds = [];
|
|
12704
|
-
obj.__lineWidths = [];
|
|
12705
|
-
obj.__lineHeights = [];
|
|
12706
|
-
obj.__graphemeLines = [];
|
|
12707
|
-
obj._textLines = [];
|
|
12708
|
-
obj.textLines = [];
|
|
12709
|
-
obj._styleMap = null;
|
|
12710
|
-
obj.styleMap = null;
|
|
12711
|
-
obj.dirty = true;
|
|
12712
|
-
};
|
|
12713
|
-
resetTextboxLayoutInternals();
|
|
12714
|
-
obj.initDimensions();
|
|
12715
|
-
if (saved.width != null) {
|
|
12716
|
-
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, {
|
|
12717
|
-
width: saved.width,
|
|
12718
|
-
scaleX: saved.scaleX,
|
|
12719
|
-
scaleY: saved.scaleY
|
|
12720
|
-
});
|
|
12721
|
-
resetTextboxLayoutInternals();
|
|
12722
|
-
obj.initDimensions();
|
|
12723
|
-
}
|
|
12724
|
-
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, {
|
|
12725
|
-
width: saved.width,
|
|
12726
|
-
scaleX: saved.scaleX,
|
|
12727
|
-
scaleY: saved.scaleY,
|
|
12728
|
-
dirty: true
|
|
12729
|
-
});
|
|
12730
|
-
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
12731
|
-
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
12732
|
-
}
|
|
12733
|
-
};
|
|
12734
|
-
fabricInstance.getObjects().forEach(walk);
|
|
12735
|
-
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
12736
|
-
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
12737
|
-
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
12738
|
-
};
|
|
12803
|
+
const reflowTextboxes = () => stabilizeFabricTextObjects(fabricInstance);
|
|
12739
12804
|
clearTextMetricCaches();
|
|
12740
12805
|
await waitForPaint();
|
|
12741
12806
|
reflowTextboxes();
|
|
@@ -14491,6 +14556,12 @@ function convertTextDecorationsToLines(svg) {
|
|
|
14491
14556
|
} else {
|
|
14492
14557
|
textWidth = content.length * fontSize * 0.6;
|
|
14493
14558
|
}
|
|
14559
|
+
if (typeof tspan.getComputedTextLength === "function") {
|
|
14560
|
+
try {
|
|
14561
|
+
textWidth = Math.max(textWidth, tspan.getComputedTextLength());
|
|
14562
|
+
} catch {
|
|
14563
|
+
}
|
|
14564
|
+
}
|
|
14494
14565
|
const underlineY = y + fontSize * 0.15;
|
|
14495
14566
|
const thickness = Math.max(0.5, fontSize * 0.066667);
|
|
14496
14567
|
const line = doc.createElementNS("http://www.w3.org/2000/svg", "line");
|