@pixldocs/canvas-renderer 0.5.15 → 0.5.17
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 +70 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +70 -40
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -91,8 +91,7 @@ export declare function embedFontsForConfig(pdf: jsPDF, config: any, fontBaseUrl
|
|
|
91
91
|
export declare function embedFontsInPdf(pdf: jsPDF, fontFamilies: Set<string>, fontBaseUrl: string): Promise<Set<string>>;
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
95
|
-
* and available to Fabric/Canvas before rendering.
|
|
94
|
+
* Start loading all fonts required by a fully-resolved TemplateConfig.
|
|
96
95
|
*
|
|
97
96
|
* This is the **single API** consumers (and the renderer internally) should
|
|
98
97
|
* call to guarantee font parity with EC2 `/render-from-form`.
|
|
@@ -101,8 +100,8 @@ export declare function embedFontsInPdf(pdf: jsPDF, fontFamilies: Set<string>, f
|
|
|
101
100
|
* 1. Walks ALL text nodes (including clones/repeatables) collecting
|
|
102
101
|
* fontFamily + fontWeight + fontStyle.
|
|
103
102
|
* 2. Loads each unique family via Google Fonts CSS v1 (idempotent).
|
|
104
|
-
* 3.
|
|
105
|
-
*
|
|
103
|
+
* 3. Kicks off each weight+style combo via `document.fonts.load()` without
|
|
104
|
+
* blocking render completion; late font load reflow handles final metrics.
|
|
106
105
|
*
|
|
107
106
|
* Idempotent — safe to call multiple times for the same config.
|
|
108
107
|
*/
|
|
@@ -370,6 +369,8 @@ export declare class PixldocsRenderer {
|
|
|
370
369
|
renderAllById(templateId: string, formData?: Record<string, any>, options?: Omit<RenderOptions, 'pageIndex'>): Promise<RenderResult[]>;
|
|
371
370
|
private getExpectedImageCount;
|
|
372
371
|
private waitForCanvasImages;
|
|
372
|
+
private waitForCanvasScene;
|
|
373
|
+
private waitForRelevantFonts;
|
|
373
374
|
private getNormalizedGradientStops;
|
|
374
375
|
private paintPageBackground;
|
|
375
376
|
private renderPageViaPreviewCanvas;
|
package/dist/index.js
CHANGED
|
@@ -2684,12 +2684,10 @@ const waitForFontsReady = async () => {
|
|
|
2684
2684
|
if (!document.fonts) return;
|
|
2685
2685
|
await withFontTimeout(document.fonts.ready, 2500);
|
|
2686
2686
|
};
|
|
2687
|
-
const DEFAULT_FONT_CHECK_TIMEOUT_MS = 3500;
|
|
2688
|
-
const FONT_CHECK_POLL_MS = 60;
|
|
2689
2687
|
const waitUntilFontsAvailable = async (fontFamilies, options) => {
|
|
2690
2688
|
if (!document.fonts || fontFamilies.length === 0) return;
|
|
2691
|
-
const timeoutMs =
|
|
2692
|
-
const pollMs =
|
|
2689
|
+
const timeoutMs = options == null ? void 0 : options.timeoutMs;
|
|
2690
|
+
const pollMs = options == null ? void 0 : options.pollIntervalMs;
|
|
2693
2691
|
const deadline = Date.now() + timeoutMs;
|
|
2694
2692
|
const check = () => fontFamilies.every(
|
|
2695
2693
|
(f) => document.fonts.check(`16px "${f}"`) && document.fonts.check(`bold 16px "${f}"`)
|
|
@@ -11688,18 +11686,16 @@ function normalizeFontFamily(fontStack) {
|
|
|
11688
11686
|
}
|
|
11689
11687
|
const loadedFonts = /* @__PURE__ */ new Set();
|
|
11690
11688
|
const loadingPromises = /* @__PURE__ */ new Map();
|
|
11691
|
-
|
|
11689
|
+
function withTimeout(promise, timeoutMs = 4e3) {
|
|
11692
11690
|
let timeoutId;
|
|
11693
|
-
|
|
11694
|
-
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
|
|
11698
|
-
|
|
11699
|
-
]);
|
|
11700
|
-
} finally {
|
|
11691
|
+
return Promise.race([
|
|
11692
|
+
promise,
|
|
11693
|
+
new Promise((resolve) => {
|
|
11694
|
+
timeoutId = setTimeout(resolve, timeoutMs);
|
|
11695
|
+
})
|
|
11696
|
+
]).finally(() => {
|
|
11701
11697
|
if (timeoutId) clearTimeout(timeoutId);
|
|
11702
|
-
}
|
|
11698
|
+
});
|
|
11703
11699
|
}
|
|
11704
11700
|
async function loadGoogleFontCSS(rawFontFamily) {
|
|
11705
11701
|
if (!rawFontFamily || typeof document === "undefined") return;
|
|
@@ -11721,10 +11717,6 @@ async function loadGoogleFontCSS(rawFontFamily) {
|
|
|
11721
11717
|
link.onerror = () => reject(new Error(`Failed to load font: ${fontFamily}`));
|
|
11722
11718
|
document.head.appendChild(link);
|
|
11723
11719
|
});
|
|
11724
|
-
if (document.fonts) {
|
|
11725
|
-
await withTimeout(document.fonts.load(`16px "${fontFamily}"`), 2500);
|
|
11726
|
-
await withTimeout(document.fonts.ready, 2500);
|
|
11727
|
-
}
|
|
11728
11720
|
loadedFonts.add(fontFamily);
|
|
11729
11721
|
} catch (e) {
|
|
11730
11722
|
console.warn(`[@pixldocs/canvas-renderer] Font load failed: ${fontFamily}`, e);
|
|
@@ -11836,17 +11828,15 @@ async function ensureFontsForResolvedConfig(config) {
|
|
|
11836
11828
|
if (typeof document === "undefined") return;
|
|
11837
11829
|
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
11838
11830
|
const families = new Set(descriptors.map((d) => d.family));
|
|
11839
|
-
|
|
11831
|
+
void withTimeout(Promise.all([...families].map((f) => loadGoogleFontCSS(f))), 2500);
|
|
11840
11832
|
if (document.fonts) {
|
|
11841
|
-
|
|
11833
|
+
descriptors.forEach((d) => {
|
|
11842
11834
|
const stylePrefix = d.style === "italic" ? "italic " : "";
|
|
11843
11835
|
const weightStr = String(d.weight);
|
|
11844
11836
|
const spec = `${stylePrefix}${weightStr} 16px "${d.family}"`;
|
|
11845
|
-
|
|
11837
|
+
document.fonts.load(spec).catch(() => {
|
|
11846
11838
|
});
|
|
11847
11839
|
});
|
|
11848
|
-
await withTimeout(Promise.all(loadPromises), 8e3);
|
|
11849
|
-
await withTimeout(document.fonts.ready, 2500);
|
|
11850
11840
|
}
|
|
11851
11841
|
}
|
|
11852
11842
|
function PixldocsPreview(props) {
|
|
@@ -12291,6 +12281,49 @@ class PixldocsRenderer {
|
|
|
12291
12281
|
setTimeout(check, 0);
|
|
12292
12282
|
});
|
|
12293
12283
|
}
|
|
12284
|
+
waitForCanvasScene(container, config, pageIndex, maxWaitMs = 8e3, pollMs = 50) {
|
|
12285
|
+
return new Promise((resolve) => {
|
|
12286
|
+
var _a, _b;
|
|
12287
|
+
const start = Date.now();
|
|
12288
|
+
const pageHasContent = (((_b = (_a = config.pages[pageIndex]) == null ? void 0 : _a.children) == null ? void 0 : _b.length) ?? 0) > 0;
|
|
12289
|
+
const settle = () => requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
12290
|
+
const check = () => {
|
|
12291
|
+
const fabricCanvas = this.getFabricCanvasFromContainer(container);
|
|
12292
|
+
const lowerCanvas = (fabricCanvas == null ? void 0 : fabricCanvas.lowerCanvasEl) || container.querySelector("canvas.lower-canvas, canvas");
|
|
12293
|
+
const objectCount = typeof (fabricCanvas == null ? void 0 : fabricCanvas.getObjects) === "function" ? fabricCanvas.getObjects().length : 0;
|
|
12294
|
+
const ready = !!lowerCanvas && (!pageHasContent || objectCount > 0);
|
|
12295
|
+
if (ready) {
|
|
12296
|
+
console.log(`[canvas-renderer][scene-wait] ready after ${Date.now() - start}ms (objects=${objectCount})`);
|
|
12297
|
+
settle();
|
|
12298
|
+
return;
|
|
12299
|
+
}
|
|
12300
|
+
if (Date.now() - start >= maxWaitMs) {
|
|
12301
|
+
console.warn(`[canvas-renderer][scene-wait-timeout] elapsed=${Date.now() - start}ms objects=${objectCount} pageHasContent=${pageHasContent}`);
|
|
12302
|
+
settle();
|
|
12303
|
+
return;
|
|
12304
|
+
}
|
|
12305
|
+
setTimeout(check, pollMs);
|
|
12306
|
+
};
|
|
12307
|
+
setTimeout(check, 0);
|
|
12308
|
+
});
|
|
12309
|
+
}
|
|
12310
|
+
async waitForRelevantFonts(config, maxWaitMs = 1800) {
|
|
12311
|
+
if (typeof document === "undefined" || !document.fonts) return;
|
|
12312
|
+
const descriptors = collectFontDescriptorsFromConfig(config);
|
|
12313
|
+
if (descriptors.length === 0) return;
|
|
12314
|
+
const loads = Promise.all(
|
|
12315
|
+
descriptors.map((descriptor) => {
|
|
12316
|
+
const stylePrefix = descriptor.style === "italic" ? "italic " : "";
|
|
12317
|
+
const spec = `${stylePrefix}${descriptor.weight} 16px "${descriptor.family}"`;
|
|
12318
|
+
return document.fonts.load(spec).catch(() => []);
|
|
12319
|
+
})
|
|
12320
|
+
).then(() => void 0);
|
|
12321
|
+
await Promise.race([
|
|
12322
|
+
loads,
|
|
12323
|
+
new Promise((resolve) => setTimeout(resolve, maxWaitMs))
|
|
12324
|
+
]);
|
|
12325
|
+
await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
|
|
12326
|
+
}
|
|
12294
12327
|
getNormalizedGradientStops(gradient) {
|
|
12295
12328
|
const stops = Array.isArray(gradient == null ? void 0 : gradient.stops) ? gradient.stops.map((stop) => ({
|
|
12296
12329
|
offset: Math.max(0, Math.min(1, Number((stop == null ? void 0 : stop.offset) ?? 0))),
|
|
@@ -12403,10 +12436,11 @@ class PixldocsRenderer {
|
|
|
12403
12436
|
);
|
|
12404
12437
|
return;
|
|
12405
12438
|
}
|
|
12406
|
-
|
|
12407
|
-
this.waitForCanvasImages(container, expectedImageCount).then(async () => {
|
|
12439
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12408
12440
|
try {
|
|
12409
12441
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12442
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
12443
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
12410
12444
|
await this.waitForStableTextMetrics(container, config);
|
|
12411
12445
|
const fabricCanvas = container.querySelector("canvas.upper-canvas, canvas");
|
|
12412
12446
|
const sourceCanvas = (fabricInstance == null ? void 0 : fabricInstance.lowerCanvasEl) || container.querySelector("canvas.lower-canvas") || fabricCanvas;
|
|
@@ -12497,8 +12531,7 @@ class PixldocsRenderer {
|
|
|
12497
12531
|
);
|
|
12498
12532
|
return;
|
|
12499
12533
|
}
|
|
12500
|
-
|
|
12501
|
-
this.waitForCanvasImages(container, expectedImageCount).then(async () => {
|
|
12534
|
+
this.waitForCanvasScene(container, config, pageIndex).then(async () => {
|
|
12502
12535
|
var _a, _b;
|
|
12503
12536
|
try {
|
|
12504
12537
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
@@ -12507,6 +12540,8 @@ class PixldocsRenderer {
|
|
|
12507
12540
|
reject(new Error("No Fabric canvas instance found for SVG capture"));
|
|
12508
12541
|
return;
|
|
12509
12542
|
}
|
|
12543
|
+
const expectedImageCount = this.getExpectedImageCount(config, pageIndex);
|
|
12544
|
+
await this.waitForCanvasImages(container, expectedImageCount);
|
|
12510
12545
|
await this.waitForStableTextMetrics(container, config);
|
|
12511
12546
|
const prevVPT = fabricInstance.viewportTransform ? [...fabricInstance.viewportTransform] : void 0;
|
|
12512
12547
|
const prevSvgVPT = fabricInstance.svgViewportTransformation;
|
|
@@ -12630,14 +12665,9 @@ class PixldocsRenderer {
|
|
|
12630
12665
|
return null;
|
|
12631
12666
|
}
|
|
12632
12667
|
async waitForStableTextMetrics(container, config) {
|
|
12633
|
-
var _a;
|
|
12634
12668
|
if (typeof document !== "undefined") {
|
|
12635
|
-
|
|
12636
|
-
await (
|
|
12637
|
-
const fontFamilies = [...collectFontsFromConfig(config)].filter(Boolean);
|
|
12638
|
-
if (fontFamilies.length > 0) {
|
|
12639
|
-
await waitUntilFontsAvailable(fontFamilies, { timeoutMs: 4e3, pollIntervalMs: 50 });
|
|
12640
|
-
}
|
|
12669
|
+
void ensureFontsForResolvedConfig(config);
|
|
12670
|
+
await this.waitForRelevantFonts(config);
|
|
12641
12671
|
}
|
|
12642
12672
|
const fabricInstance = this.getFabricCanvasFromContainer(container);
|
|
12643
12673
|
if (!(fabricInstance == null ? void 0 : fabricInstance.getObjects)) return;
|
|
@@ -12647,9 +12677,9 @@ class PixldocsRenderer {
|
|
|
12647
12677
|
clearMeasurementCache();
|
|
12648
12678
|
};
|
|
12649
12679
|
const reflowTextboxes = () => {
|
|
12650
|
-
var
|
|
12680
|
+
var _a, _b, _c;
|
|
12651
12681
|
const walk = (obj) => {
|
|
12652
|
-
var
|
|
12682
|
+
var _a2, _b2, _c2, _d;
|
|
12653
12683
|
if (!obj) return;
|
|
12654
12684
|
const children = Array.isArray(obj._objects) ? obj._objects : Array.isArray(obj.objects) ? obj.objects : [];
|
|
12655
12685
|
if (children.length) children.forEach(walk);
|
|
@@ -12661,8 +12691,8 @@ class PixldocsRenderer {
|
|
|
12661
12691
|
scaleY: obj.scaleY
|
|
12662
12692
|
};
|
|
12663
12693
|
const resetTextboxLayoutInternals = () => {
|
|
12664
|
-
var
|
|
12665
|
-
(
|
|
12694
|
+
var _a3;
|
|
12695
|
+
(_a3 = obj._clearCache) == null ? void 0 : _a3.call(obj);
|
|
12666
12696
|
obj.__charBounds = [];
|
|
12667
12697
|
obj.__lineWidths = [];
|
|
12668
12698
|
obj.__lineHeights = [];
|
|
@@ -12676,7 +12706,7 @@ class PixldocsRenderer {
|
|
|
12676
12706
|
resetTextboxLayoutInternals();
|
|
12677
12707
|
obj.initDimensions();
|
|
12678
12708
|
if (saved.width != null) {
|
|
12679
|
-
(
|
|
12709
|
+
(_a2 = obj.set) == null ? void 0 : _a2.call(obj, {
|
|
12680
12710
|
width: saved.width,
|
|
12681
12711
|
scaleX: saved.scaleX,
|
|
12682
12712
|
scaleY: saved.scaleY
|
|
@@ -12695,7 +12725,7 @@ class PixldocsRenderer {
|
|
|
12695
12725
|
}
|
|
12696
12726
|
};
|
|
12697
12727
|
fabricInstance.getObjects().forEach(walk);
|
|
12698
|
-
(
|
|
12728
|
+
(_a = fabricInstance.calcOffset) == null ? void 0 : _a.call(fabricInstance);
|
|
12699
12729
|
(_b = fabricInstance.renderAll) == null ? void 0 : _b.call(fabricInstance);
|
|
12700
12730
|
(_c = fabricInstance.requestRenderAll) == null ? void 0 : _c.call(fabricInstance);
|
|
12701
12731
|
};
|