@twinfinity/printing 6.0.1-ci.28952-beta → 6.0.2-beta
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/README.md +3 -3
- package/dist/BuildInfo.js +3 -3
- package/dist/BuildInfo.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/layout/analyzeTemplate.js.map +1 -1
- package/dist/layout/clipUtils.js.map +1 -1
- package/dist/layout/colorConstants.js.map +1 -1
- package/dist/layout/elementKinds.js.map +1 -1
- package/dist/layout/exportDrawing.js.map +1 -1
- package/dist/layout/filters.js.map +1 -1
- package/dist/layout/geometryConstants.js.map +1 -1
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/itemBuilders.js.map +1 -1
- package/dist/layout/labelsRender.js.map +1 -1
- package/dist/layout/legendConstants.js.map +1 -1
- package/dist/layout/legendRender.js.map +1 -1
- package/dist/layout/legendRows.js.map +1 -1
- package/dist/layout/legendUtils.js.map +1 -1
- package/dist/layout/metadata.js.map +1 -1
- package/dist/layout/model.js.map +1 -1
- package/dist/layout/options.js.map +1 -1
- package/dist/layout/presets.js.map +1 -1
- package/dist/layout/qrRender.js.map +1 -1
- package/dist/layout/renderDrawing.js.map +1 -1
- package/dist/layout/renderUtils.js.map +1 -1
- package/dist/layout/sectionValidation.js.map +1 -1
- package/dist/layout/templateVariables.js.map +1 -1
- package/dist/layout/typeGuards.js.map +1 -1
- package/dist/layout/types.js.map +1 -1
- package/dist/layout/utils.js.map +1 -1
- package/dist/layout/validation.js.map +1 -1
- package/dist/layout/validationHelpers.js.map +1 -1
- package/dist/layout/validationUtils.js.map +1 -1
- package/dist/layout/viewportPrep.js.map +1 -1
- package/dist/layout/viewportRender.js.map +1 -1
- package/dist/layout/viewportUtils.js.map +1 -1
- package/dist/layout/warnings.js.map +1 -1
- package/dist/printToPdf.js.map +1 -1
- package/dist/printToSvg.js.map +1 -1
- package/dist/sections.js.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/src/BuildInfo.ts +41 -41
- package/src/index.ts +10 -10
- package/src/layout/analyzeTemplate.ts +218 -218
- package/src/layout/clipUtils.ts +193 -193
- package/src/layout/colorConstants.ts +16 -16
- package/src/layout/elementKinds.ts +35 -35
- package/src/layout/exportDrawing.ts +206 -206
- package/src/layout/filters.ts +80 -80
- package/src/layout/geometryConstants.ts +11 -11
- package/src/layout/index.ts +671 -671
- package/src/layout/itemBuilders.ts +159 -159
- package/src/layout/labelsRender.ts +170 -170
- package/src/layout/legendConstants.ts +11 -11
- package/src/layout/legendRender.ts +543 -543
- package/src/layout/legendRows.ts +62 -62
- package/src/layout/legendUtils.ts +144 -144
- package/src/layout/metadata.ts +210 -210
- package/src/layout/model.ts +372 -372
- package/src/layout/options.ts +17 -17
- package/src/layout/presets.ts +51 -51
- package/src/layout/qrRender.ts +126 -126
- package/src/layout/qrcode.d.ts +2 -2
- package/src/layout/renderDrawing.ts +710 -710
- package/src/layout/renderUtils.ts +138 -138
- package/src/layout/sectionValidation.ts +2 -2
- package/src/layout/templateVariables.ts +317 -317
- package/src/layout/typeGuards.ts +9 -9
- package/src/layout/types.ts +835 -835
- package/src/layout/utils.ts +85 -85
- package/src/layout/validation.ts +392 -392
- package/src/layout/validationHelpers.ts +59 -59
- package/src/layout/validationUtils.ts +6 -6
- package/src/layout/viewportPrep.ts +351 -351
- package/src/layout/viewportRender.ts +442 -442
- package/src/layout/viewportUtils.ts +50 -50
- package/src/layout/warnings.ts +3 -3
- package/src/printToPdf.ts +108 -108
- package/src/printToSvg.ts +188 -188
- package/src/sections.ts +1019 -1019
- package/src/types.ts +49 -49
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import { uniquePositiveDenoms } from './utils';
|
|
2
|
-
import { ComputedViewportScale, SvgModelView, ViewportElement } from './types';
|
|
3
|
-
|
|
4
|
-
export const rotateBounds = (width: number, height: number, rotationDeg: number): { width: number; height: number } => {
|
|
5
|
-
if (!rotationDeg) return { width, height };
|
|
6
|
-
const rad = (rotationDeg * Math.PI) / 180;
|
|
7
|
-
const cos = Math.cos(rad);
|
|
8
|
-
const sin = Math.sin(rad);
|
|
9
|
-
const rotatedWidth = Math.abs(width * cos) + Math.abs(height * sin);
|
|
10
|
-
const rotatedHeight = Math.abs(width * sin) + Math.abs(height * cos);
|
|
11
|
-
return { width: rotatedWidth, height: rotatedHeight };
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export const pickScale = (
|
|
15
|
-
viewport: ViewportElement,
|
|
16
|
-
model: SvgModelView,
|
|
17
|
-
preferred: number[],
|
|
18
|
-
scalePresets: Record<string, { preferredScales?: number[] }>
|
|
19
|
-
): ComputedViewportScale => {
|
|
20
|
-
const scalePresetName = viewport.scalePreset;
|
|
21
|
-
const scalePreset = scalePresetName && scalePresets[scalePresetName] ? scalePresets[scalePresetName] : null;
|
|
22
|
-
const denoms =
|
|
23
|
-
viewport.scaleMode === 'fixed' && viewport.fixedScaleDenom
|
|
24
|
-
? [viewport.fixedScaleDenom]
|
|
25
|
-
: uniquePositiveDenoms(viewport.preferredScales ?? scalePreset?.preferredScales ?? preferred);
|
|
26
|
-
|
|
27
|
-
const rotationDeg = viewport.rotationDeg ?? 0;
|
|
28
|
-
let selectedDenom = denoms[denoms.length - 1];
|
|
29
|
-
let selectedMmPerModel = 1000 / selectedDenom;
|
|
30
|
-
let fits = false;
|
|
31
|
-
|
|
32
|
-
for (const denom of denoms) {
|
|
33
|
-
const mmPerModel = 1000 / denom;
|
|
34
|
-
const widthMm = model.widthModel * mmPerModel;
|
|
35
|
-
const heightMm = model.heightModel * mmPerModel;
|
|
36
|
-
const rotated = rotateBounds(widthMm, heightMm, rotationDeg);
|
|
37
|
-
if (rotated.width <= viewport.widthMm && rotated.height <= viewport.heightMm) {
|
|
38
|
-
selectedDenom = denom;
|
|
39
|
-
selectedMmPerModel = mmPerModel;
|
|
40
|
-
fits = true;
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
denom: selectedDenom,
|
|
47
|
-
mmPerModelUnit: selectedMmPerModel,
|
|
48
|
-
fits
|
|
49
|
-
};
|
|
50
|
-
};
|
|
1
|
+
import { uniquePositiveDenoms } from './utils';
|
|
2
|
+
import { ComputedViewportScale, SvgModelView, ViewportElement } from './types';
|
|
3
|
+
|
|
4
|
+
export const rotateBounds = (width: number, height: number, rotationDeg: number): { width: number; height: number } => {
|
|
5
|
+
if (!rotationDeg) return { width, height };
|
|
6
|
+
const rad = (rotationDeg * Math.PI) / 180;
|
|
7
|
+
const cos = Math.cos(rad);
|
|
8
|
+
const sin = Math.sin(rad);
|
|
9
|
+
const rotatedWidth = Math.abs(width * cos) + Math.abs(height * sin);
|
|
10
|
+
const rotatedHeight = Math.abs(width * sin) + Math.abs(height * cos);
|
|
11
|
+
return { width: rotatedWidth, height: rotatedHeight };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const pickScale = (
|
|
15
|
+
viewport: ViewportElement,
|
|
16
|
+
model: SvgModelView,
|
|
17
|
+
preferred: number[],
|
|
18
|
+
scalePresets: Record<string, { preferredScales?: number[] }>
|
|
19
|
+
): ComputedViewportScale => {
|
|
20
|
+
const scalePresetName = viewport.scalePreset;
|
|
21
|
+
const scalePreset = scalePresetName && scalePresets[scalePresetName] ? scalePresets[scalePresetName] : null;
|
|
22
|
+
const denoms =
|
|
23
|
+
viewport.scaleMode === 'fixed' && viewport.fixedScaleDenom
|
|
24
|
+
? [viewport.fixedScaleDenom]
|
|
25
|
+
: uniquePositiveDenoms(viewport.preferredScales ?? scalePreset?.preferredScales ?? preferred);
|
|
26
|
+
|
|
27
|
+
const rotationDeg = viewport.rotationDeg ?? 0;
|
|
28
|
+
let selectedDenom = denoms[denoms.length - 1];
|
|
29
|
+
let selectedMmPerModel = 1000 / selectedDenom;
|
|
30
|
+
let fits = false;
|
|
31
|
+
|
|
32
|
+
for (const denom of denoms) {
|
|
33
|
+
const mmPerModel = 1000 / denom;
|
|
34
|
+
const widthMm = model.widthModel * mmPerModel;
|
|
35
|
+
const heightMm = model.heightModel * mmPerModel;
|
|
36
|
+
const rotated = rotateBounds(widthMm, heightMm, rotationDeg);
|
|
37
|
+
if (rotated.width <= viewport.widthMm && rotated.height <= viewport.heightMm) {
|
|
38
|
+
selectedDenom = denom;
|
|
39
|
+
selectedMmPerModel = mmPerModel;
|
|
40
|
+
fits = true;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
denom: selectedDenom,
|
|
47
|
+
mmPerModelUnit: selectedMmPerModel,
|
|
48
|
+
fits
|
|
49
|
+
};
|
|
50
|
+
};
|
package/src/layout/warnings.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export const pushWarning = (warnings: string[], message: string): void => {
|
|
2
|
-
warnings.push(message);
|
|
3
|
-
};
|
|
1
|
+
export const pushWarning = (warnings: string[], message: string): void => {
|
|
2
|
+
warnings.push(message);
|
|
3
|
+
};
|
package/src/printToPdf.ts
CHANGED
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PDF export via jsPDF + svg2pdf.js
|
|
3
|
-
*
|
|
4
|
-
* These are optional peer dependencies. Functions will throw at runtime if not installed.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export interface PrintToPdfOptions {
|
|
8
|
-
svgMarkup: string;
|
|
9
|
-
fileName?: string;
|
|
10
|
-
pageFormat?: 'a0' | 'a1' | 'a2' | 'a3' | 'a4';
|
|
11
|
-
orientation?: 'portrait' | 'landscape';
|
|
12
|
-
marginMm?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Export an SVG string to a PDF file.
|
|
17
|
-
* Requires jspdf and svg2pdf.js as peer dependencies.
|
|
18
|
-
*/
|
|
19
|
-
export async function printToPdf(options: PrintToPdfOptions): Promise<Blob> {
|
|
20
|
-
// Dynamic imports for optional peer dependencies (installed by consumer, not this package)
|
|
21
|
-
let jspdfModule: any;
|
|
22
|
-
try {
|
|
23
|
-
// @ts-expect-error — optional peer dependency resolved at runtime
|
|
24
|
-
jspdfModule = await import('jspdf');
|
|
25
|
-
} catch {
|
|
26
|
-
throw new Error('jspdf is required for PDF export. Install it: bun add jspdf');
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
// @ts-expect-error — optional peer dependency resolved at runtime
|
|
30
|
-
await import('svg2pdf.js');
|
|
31
|
-
} catch {
|
|
32
|
-
throw new Error('svg2pdf.js is required for PDF export. Install it: bun add svg2pdf.js');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const { jsPDF } = jspdfModule;
|
|
36
|
-
const format = options.pageFormat ?? 'a3';
|
|
37
|
-
const orientation = options.orientation ?? 'landscape';
|
|
38
|
-
const margin = options.marginMm ?? 10;
|
|
39
|
-
|
|
40
|
-
const doc = new jsPDF({ format, orientation, unit: 'mm' });
|
|
41
|
-
const pageWidth = doc.internal.pageSize.getWidth();
|
|
42
|
-
const pageHeight = doc.internal.pageSize.getHeight();
|
|
43
|
-
|
|
44
|
-
const parser = new DOMParser();
|
|
45
|
-
const svgDoc = parser.parseFromString(options.svgMarkup, 'image/svg+xml');
|
|
46
|
-
const svgElement = svgDoc.documentElement;
|
|
47
|
-
|
|
48
|
-
await doc.svg(svgElement, {
|
|
49
|
-
x: margin,
|
|
50
|
-
y: margin,
|
|
51
|
-
width: pageWidth - margin * 2,
|
|
52
|
-
height: pageHeight - margin * 2
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const blob = doc.output('blob');
|
|
56
|
-
|
|
57
|
-
if (options.fileName) {
|
|
58
|
-
doc.save(options.fileName);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return blob;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Export an SVG string directly as a downloadable SVG file.
|
|
66
|
-
*/
|
|
67
|
-
export function printToSvgFile(svgMarkup: string, fileName: string): void {
|
|
68
|
-
const blob = new Blob([svgMarkup], { type: 'image/svg+xml' });
|
|
69
|
-
const url = URL.createObjectURL(blob);
|
|
70
|
-
const link = document.createElement('a');
|
|
71
|
-
link.href = url;
|
|
72
|
-
link.download = fileName;
|
|
73
|
-
link.click();
|
|
74
|
-
URL.revokeObjectURL(url);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Compatibility wrappers for print-layout module
|
|
78
|
-
export interface ExportSectionToPdfOptions {
|
|
79
|
-
svgMarkup: string;
|
|
80
|
-
fileName: string;
|
|
81
|
-
pageSizeMm?: { width: number; height: number };
|
|
82
|
-
openInNewTab?: boolean;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export async function exportSectionToPdf(options: ExportSectionToPdfOptions): Promise<void> {
|
|
86
|
-
await printToPdf({
|
|
87
|
-
svgMarkup: options.svgMarkup,
|
|
88
|
-
fileName: options.fileName
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface ExportSectionToSvgOptions {
|
|
93
|
-
svgMarkup: string;
|
|
94
|
-
fileName: string;
|
|
95
|
-
openInNewTab?: boolean;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function exportSectionToSvg(options: ExportSectionToSvgOptions): void {
|
|
99
|
-
if (options.openInNewTab) {
|
|
100
|
-
const blob = new Blob([options.svgMarkup], { type: 'image/svg+xml' });
|
|
101
|
-
const url = URL.createObjectURL(blob);
|
|
102
|
-
window.open(url, '_blank');
|
|
103
|
-
// Revoke after a delay to allow the new tab to load the blob
|
|
104
|
-
setTimeout(() => URL.revokeObjectURL(url), 60_000);
|
|
105
|
-
} else {
|
|
106
|
-
printToSvgFile(options.svgMarkup, options.fileName);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* PDF export via jsPDF + svg2pdf.js
|
|
3
|
+
*
|
|
4
|
+
* These are optional peer dependencies. Functions will throw at runtime if not installed.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface PrintToPdfOptions {
|
|
8
|
+
svgMarkup: string;
|
|
9
|
+
fileName?: string;
|
|
10
|
+
pageFormat?: 'a0' | 'a1' | 'a2' | 'a3' | 'a4';
|
|
11
|
+
orientation?: 'portrait' | 'landscape';
|
|
12
|
+
marginMm?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Export an SVG string to a PDF file.
|
|
17
|
+
* Requires jspdf and svg2pdf.js as peer dependencies.
|
|
18
|
+
*/
|
|
19
|
+
export async function printToPdf(options: PrintToPdfOptions): Promise<Blob> {
|
|
20
|
+
// Dynamic imports for optional peer dependencies (installed by consumer, not this package)
|
|
21
|
+
let jspdfModule: any;
|
|
22
|
+
try {
|
|
23
|
+
// @ts-expect-error — optional peer dependency resolved at runtime
|
|
24
|
+
jspdfModule = await import('jspdf');
|
|
25
|
+
} catch {
|
|
26
|
+
throw new Error('jspdf is required for PDF export. Install it: bun add jspdf');
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
// @ts-expect-error — optional peer dependency resolved at runtime
|
|
30
|
+
await import('svg2pdf.js');
|
|
31
|
+
} catch {
|
|
32
|
+
throw new Error('svg2pdf.js is required for PDF export. Install it: bun add svg2pdf.js');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const { jsPDF } = jspdfModule;
|
|
36
|
+
const format = options.pageFormat ?? 'a3';
|
|
37
|
+
const orientation = options.orientation ?? 'landscape';
|
|
38
|
+
const margin = options.marginMm ?? 10;
|
|
39
|
+
|
|
40
|
+
const doc = new jsPDF({ format, orientation, unit: 'mm' });
|
|
41
|
+
const pageWidth = doc.internal.pageSize.getWidth();
|
|
42
|
+
const pageHeight = doc.internal.pageSize.getHeight();
|
|
43
|
+
|
|
44
|
+
const parser = new DOMParser();
|
|
45
|
+
const svgDoc = parser.parseFromString(options.svgMarkup, 'image/svg+xml');
|
|
46
|
+
const svgElement = svgDoc.documentElement;
|
|
47
|
+
|
|
48
|
+
await doc.svg(svgElement, {
|
|
49
|
+
x: margin,
|
|
50
|
+
y: margin,
|
|
51
|
+
width: pageWidth - margin * 2,
|
|
52
|
+
height: pageHeight - margin * 2
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const blob = doc.output('blob');
|
|
56
|
+
|
|
57
|
+
if (options.fileName) {
|
|
58
|
+
doc.save(options.fileName);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return blob;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Export an SVG string directly as a downloadable SVG file.
|
|
66
|
+
*/
|
|
67
|
+
export function printToSvgFile(svgMarkup: string, fileName: string): void {
|
|
68
|
+
const blob = new Blob([svgMarkup], { type: 'image/svg+xml' });
|
|
69
|
+
const url = URL.createObjectURL(blob);
|
|
70
|
+
const link = document.createElement('a');
|
|
71
|
+
link.href = url;
|
|
72
|
+
link.download = fileName;
|
|
73
|
+
link.click();
|
|
74
|
+
URL.revokeObjectURL(url);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Compatibility wrappers for print-layout module
|
|
78
|
+
export interface ExportSectionToPdfOptions {
|
|
79
|
+
svgMarkup: string;
|
|
80
|
+
fileName: string;
|
|
81
|
+
pageSizeMm?: { width: number; height: number };
|
|
82
|
+
openInNewTab?: boolean;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export async function exportSectionToPdf(options: ExportSectionToPdfOptions): Promise<void> {
|
|
86
|
+
await printToPdf({
|
|
87
|
+
svgMarkup: options.svgMarkup,
|
|
88
|
+
fileName: options.fileName
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface ExportSectionToSvgOptions {
|
|
93
|
+
svgMarkup: string;
|
|
94
|
+
fileName: string;
|
|
95
|
+
openInNewTab?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function exportSectionToSvg(options: ExportSectionToSvgOptions): void {
|
|
99
|
+
if (options.openInNewTab) {
|
|
100
|
+
const blob = new Blob([options.svgMarkup], { type: 'image/svg+xml' });
|
|
101
|
+
const url = URL.createObjectURL(blob);
|
|
102
|
+
window.open(url, '_blank');
|
|
103
|
+
// Revoke after a delay to allow the new tab to load the blob
|
|
104
|
+
setTimeout(() => URL.revokeObjectURL(url), 60_000);
|
|
105
|
+
} else {
|
|
106
|
+
printToSvgFile(options.svgMarkup, options.fileName);
|
|
107
|
+
}
|
|
108
|
+
}
|