@pixldocs/canvas-renderer 0.5.19 → 0.5.21
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 +99 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +99 -66
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -11863,6 +11863,89 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
11863
11863
|
});
|
|
11864
11864
|
}
|
|
11865
11865
|
}
|
|
11866
|
+
const TEXT_TYPES = /* @__PURE__ */ new Set(["textbox", "text", "i-text"]);
|
|
11867
|
+
function getTextLines(obj) {
|
|
11868
|
+
const lines = Array.isArray(obj.textLines) && obj.textLines.length ? obj.textLines : String(obj.text || "").split("\n");
|
|
11869
|
+
return lines.map((line) => Array.isArray(line) ? line.join("") : String(line ?? ""));
|
|
11870
|
+
}
|
|
11871
|
+
function measureLineWidth(obj, line) {
|
|
11872
|
+
if (typeof document === "undefined") return 0;
|
|
11873
|
+
const canvas = document.createElement("canvas");
|
|
11874
|
+
const ctx = canvas.getContext("2d");
|
|
11875
|
+
if (!ctx) return 0;
|
|
11876
|
+
const fontStyle = obj.fontStyle || "normal";
|
|
11877
|
+
const fontWeight = obj.fontWeight || 400;
|
|
11878
|
+
const fontSize = obj.fontSize || 16;
|
|
11879
|
+
const fontFamily = obj.fontFamily || "sans-serif";
|
|
11880
|
+
ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
|
|
11881
|
+
const charSpacing = Number(obj.charSpacing || 0) / 1e3 * fontSize;
|
|
11882
|
+
return ctx.measureText(line).width + Math.max(0, line.length - 1) * charSpacing;
|
|
11883
|
+
}
|
|
11884
|
+
function getDecorationPadding(obj) {
|
|
11885
|
+
var _a;
|
|
11886
|
+
const strokeWidth = Number(obj.strokeWidth || 0);
|
|
11887
|
+
const shadowBlur = Number(((_a = obj.shadow) == null ? void 0 : _a.blur) || 0);
|
|
11888
|
+
return Math.max(0, strokeWidth) + Math.max(0, shadowBlur * 0.25);
|
|
11889
|
+
}
|
|
11890
|
+
function getFabricCanvasFromContainer(container) {
|
|
11891
|
+
const registry2 = window.__fabricCanvasRegistry;
|
|
11892
|
+
if (registry2 instanceof Map) {
|
|
11893
|
+
for (const entry of registry2.values()) {
|
|
11894
|
+
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
11895
|
+
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
11896
|
+
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
11897
|
+
if (el && container.contains(el)) return canvas;
|
|
11898
|
+
}
|
|
11899
|
+
}
|
|
11900
|
+
return null;
|
|
11901
|
+
}
|
|
11902
|
+
function stabilizeFabricTextObjects(fabricInstance) {
|
|
11903
|
+
var _a, _b, _c;
|
|
11904
|
+
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
11905
|
+
clearFabricCharCache();
|
|
11906
|
+
clearMeasurementCache();
|
|
11907
|
+
const walk = (obj) => {
|
|
11908
|
+
var _a2, _b2, _c2, _d;
|
|
11909
|
+
if (!obj) return;
|
|
11910
|
+
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
11911
|
+
if (children.length) children.forEach(walk);
|
|
11912
|
+
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (TEXT_TYPES.has(obj.type) || obj.isEditing !== void 0);
|
|
11913
|
+
if (!isTextObject) return;
|
|
11914
|
+
const saved = { width: obj.width, scaleX: obj.scaleX, scaleY: obj.scaleY };
|
|
11915
|
+
const reset = () => {
|
|
11916
|
+
var _a3;
|
|
11917
|
+
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
11918
|
+
obj.__charBounds = [];
|
|
11919
|
+
obj.__lineWidths = [];
|
|
11920
|
+
obj.__lineHeights = [];
|
|
11921
|
+
obj.__graphemeLines = [];
|
|
11922
|
+
obj._textLines = [];
|
|
11923
|
+
obj.textLines = [];
|
|
11924
|
+
obj._styleMap = null;
|
|
11925
|
+
obj.styleMap = null;
|
|
11926
|
+
obj.dirty = true;
|
|
11927
|
+
};
|
|
11928
|
+
reset();
|
|
11929
|
+
obj.initDimensions();
|
|
11930
|
+
if (saved.width != null) {
|
|
11931
|
+
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11932
|
+
reset();
|
|
11933
|
+
obj.initDimensions();
|
|
11934
|
+
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, { width: saved.width, scaleX: saved.scaleX, scaleY: saved.scaleY });
|
|
11935
|
+
}
|
|
11936
|
+
if (obj.underline || obj.linethrough) {
|
|
11937
|
+
const decorationPadding = getDecorationPadding(obj);
|
|
11938
|
+
obj.__lineWidths = getTextLines(obj).map((line) => Math.max(0, measureLineWidth(obj, line) + decorationPadding));
|
|
11939
|
+
}
|
|
11940
|
+
obj.dirty = true;
|
|
11941
|
+
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
11942
|
+
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
11943
|
+
};
|
|
11944
|
+
fabricInstance.getObjects().forEach(walk);
|
|
11945
|
+
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
11946
|
+
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
11947
|
+
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
11948
|
+
}
|
|
11866
11949
|
function PixldocsPreview(props) {
|
|
11867
11950
|
const {
|
|
11868
11951
|
pageIndex = 0,
|
|
@@ -11959,6 +12042,13 @@ function PixldocsPreview(props) {
|
|
|
11959
12042
|
() => `${pageIndex}-${fontsReadyVersion}-${stabilizationPass}`,
|
|
11960
12043
|
[pageIndex, fontsReadyVersion, stabilizationPass]
|
|
11961
12044
|
);
|
|
12045
|
+
const previewWrapRef = react.useCallback((node) => {
|
|
12046
|
+
if (!node || !config) return;
|
|
12047
|
+
requestAnimationFrame(() => {
|
|
12048
|
+
const fabricCanvas = getFabricCanvasFromContainer(node);
|
|
12049
|
+
if (fabricCanvas) stabilizeFabricTextObjects(fabricCanvas);
|
|
12050
|
+
});
|
|
12051
|
+
}, [config, previewKey]);
|
|
11962
12052
|
react.useEffect(() => {
|
|
11963
12053
|
if (isResolveMode) return;
|
|
11964
12054
|
if (!config) {
|
|
@@ -11989,7 +12079,7 @@ function PixldocsPreview(props) {
|
|
|
11989
12079
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...style, display: "flex", alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { color: "#888", fontSize: 14 }, children: "Loading preview..." }) });
|
|
11990
12080
|
}
|
|
11991
12081
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...style, position: "relative" }, children: [
|
|
11992
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { visibility: canvasSettled ? "visible" : "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
12082
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: previewWrapRef, style: { visibility: canvasSettled ? "visible" : "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11993
12083
|
PreviewCanvas,
|
|
11994
12084
|
{
|
|
11995
12085
|
config,
|
|
@@ -12556,7 +12646,6 @@ class PixldocsRenderer {
|
|
|
12556
12646
|
pageIndex,
|
|
12557
12647
|
zoom: pixelRatio,
|
|
12558
12648
|
absoluteZoom: true,
|
|
12559
|
-
skipFontReadyWait: true,
|
|
12560
12649
|
onReady
|
|
12561
12650
|
})
|
|
12562
12651
|
);
|
|
@@ -12660,7 +12749,6 @@ class PixldocsRenderer {
|
|
|
12660
12749
|
zoom: 1,
|
|
12661
12750
|
// 1:1 — no UI scaling for SVG capture
|
|
12662
12751
|
absoluteZoom: true,
|
|
12663
|
-
skipFontReadyWait: true,
|
|
12664
12752
|
onReady
|
|
12665
12753
|
})
|
|
12666
12754
|
);
|
|
@@ -12721,16 +12809,7 @@ class PixldocsRenderer {
|
|
|
12721
12809
|
* using the global __fabricCanvasRegistry (set by PageCanvas).
|
|
12722
12810
|
*/
|
|
12723
12811
|
getFabricCanvasFromContainer(container) {
|
|
12724
|
-
|
|
12725
|
-
if (registry2 instanceof Map) {
|
|
12726
|
-
for (const entry of registry2.values()) {
|
|
12727
|
-
const canvas = (entry == null ? void 0 : entry.canvas) || entry;
|
|
12728
|
-
if (!canvas || typeof canvas.toSVG !== "function") continue;
|
|
12729
|
-
const el = canvas.lowerCanvasEl || canvas.upperCanvasEl;
|
|
12730
|
-
if (el && container.contains(el)) return canvas;
|
|
12731
|
-
}
|
|
12732
|
-
}
|
|
12733
|
-
return null;
|
|
12812
|
+
return getFabricCanvasFromContainer(container);
|
|
12734
12813
|
}
|
|
12735
12814
|
async waitForStableTextMetrics(container, config) {
|
|
12736
12815
|
if (typeof document !== "undefined") {
|
|
@@ -12744,59 +12823,7 @@ class PixldocsRenderer {
|
|
|
12744
12823
|
clearFabricCharCache();
|
|
12745
12824
|
clearMeasurementCache();
|
|
12746
12825
|
};
|
|
12747
|
-
const reflowTextboxes = () =>
|
|
12748
|
-
var _a, _b, _c;
|
|
12749
|
-
const walk = (obj) => {
|
|
12750
|
-
var _a2, _b2, _c2, _d;
|
|
12751
|
-
if (!obj) return;
|
|
12752
|
-
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12753
|
-
if (children.length) children.forEach(walk);
|
|
12754
|
-
const isTextObject = typeof obj.text === "string" && typeof obj.initDimensions === "function" && (obj.type === "textbox" || obj.type === "text" || obj.type === "i-text" || obj.isEditing !== void 0);
|
|
12755
|
-
if (isTextObject) {
|
|
12756
|
-
const saved = {
|
|
12757
|
-
width: obj.width,
|
|
12758
|
-
scaleX: obj.scaleX,
|
|
12759
|
-
scaleY: obj.scaleY
|
|
12760
|
-
};
|
|
12761
|
-
const resetTextboxLayoutInternals = () => {
|
|
12762
|
-
var _a3;
|
|
12763
|
-
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
12764
|
-
obj.__charBounds = [];
|
|
12765
|
-
obj.__lineWidths = [];
|
|
12766
|
-
obj.__lineHeights = [];
|
|
12767
|
-
obj.__graphemeLines = [];
|
|
12768
|
-
obj._textLines = [];
|
|
12769
|
-
obj.textLines = [];
|
|
12770
|
-
obj._styleMap = null;
|
|
12771
|
-
obj.styleMap = null;
|
|
12772
|
-
obj.dirty = true;
|
|
12773
|
-
};
|
|
12774
|
-
resetTextboxLayoutInternals();
|
|
12775
|
-
obj.initDimensions();
|
|
12776
|
-
if (saved.width != null) {
|
|
12777
|
-
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, {
|
|
12778
|
-
width: saved.width,
|
|
12779
|
-
scaleX: saved.scaleX,
|
|
12780
|
-
scaleY: saved.scaleY
|
|
12781
|
-
});
|
|
12782
|
-
resetTextboxLayoutInternals();
|
|
12783
|
-
obj.initDimensions();
|
|
12784
|
-
}
|
|
12785
|
-
(_b2 = obj.set) == null ? void 0 : _b2.call(obj, {
|
|
12786
|
-
width: saved.width,
|
|
12787
|
-
scaleX: saved.scaleX,
|
|
12788
|
-
scaleY: saved.scaleY,
|
|
12789
|
-
dirty: true
|
|
12790
|
-
});
|
|
12791
|
-
(_c2 = obj._clearCache) == null ? void 0 : _c2.call(obj);
|
|
12792
|
-
(_d = obj.setCoords) == null ? void 0 : _d.call(obj);
|
|
12793
|
-
}
|
|
12794
|
-
};
|
|
12795
|
-
fabricInstance.getObjects().forEach(walk);
|
|
12796
|
-
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
12797
|
-
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
12798
|
-
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
12799
|
-
};
|
|
12826
|
+
const reflowTextboxes = () => stabilizeFabricTextObjects(fabricInstance);
|
|
12800
12827
|
clearTextMetricCaches();
|
|
12801
12828
|
await waitForPaint();
|
|
12802
12829
|
reflowTextboxes();
|
|
@@ -14552,6 +14579,12 @@ function convertTextDecorationsToLines(svg) {
|
|
|
14552
14579
|
} else {
|
|
14553
14580
|
textWidth = content.length * fontSize * 0.6;
|
|
14554
14581
|
}
|
|
14582
|
+
if (typeof tspan.getComputedTextLength === "function") {
|
|
14583
|
+
try {
|
|
14584
|
+
textWidth = Math.max(textWidth, tspan.getComputedTextLength());
|
|
14585
|
+
} catch {
|
|
14586
|
+
}
|
|
14587
|
+
}
|
|
14555
14588
|
const underlineY = y + fontSize * 0.15;
|
|
14556
14589
|
const thickness = Math.max(0.5, fontSize * 0.066667);
|
|
14557
14590
|
const line = doc.createElementNS("http://www.w3.org/2000/svg", "line");
|