@twinfinity/printing 5.0.3-ci.28538-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 +208 -0
- package/dist/BuildInfo.d.ts +25 -0
- package/dist/BuildInfo.d.ts.map +1 -0
- package/dist/BuildInfo.js +15 -0
- package/dist/BuildInfo.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/analyzeTemplate.d.ts +29 -0
- package/dist/layout/analyzeTemplate.d.ts.map +1 -0
- package/dist/layout/analyzeTemplate.js +168 -0
- package/dist/layout/analyzeTemplate.js.map +1 -0
- package/dist/layout/clipUtils.d.ts +18 -0
- package/dist/layout/clipUtils.d.ts.map +1 -0
- package/dist/layout/clipUtils.js +165 -0
- package/dist/layout/clipUtils.js.map +1 -0
- package/dist/layout/colorConstants.d.ts +11 -0
- package/dist/layout/colorConstants.d.ts.map +1 -0
- package/dist/layout/colorConstants.js +14 -0
- package/dist/layout/colorConstants.js.map +1 -0
- package/dist/layout/elementKinds.d.ts +21 -0
- package/dist/layout/elementKinds.d.ts.map +1 -0
- package/dist/layout/elementKinds.js +17 -0
- package/dist/layout/elementKinds.js.map +1 -0
- package/dist/layout/exportDrawing.d.ts +143 -0
- package/dist/layout/exportDrawing.d.ts.map +1 -0
- package/dist/layout/exportDrawing.js +146 -0
- package/dist/layout/exportDrawing.js.map +1 -0
- package/dist/layout/filters.d.ts +33 -0
- package/dist/layout/filters.d.ts.map +1 -0
- package/dist/layout/filters.js +77 -0
- package/dist/layout/filters.js.map +1 -0
- package/dist/layout/geometryConstants.d.ts +8 -0
- package/dist/layout/geometryConstants.d.ts.map +1 -0
- package/dist/layout/geometryConstants.js +10 -0
- package/dist/layout/geometryConstants.js.map +1 -0
- package/dist/layout/index.d.ts +86 -0
- package/dist/layout/index.d.ts.map +1 -0
- package/dist/layout/index.js +363 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/layout/itemBuilders.d.ts +29 -0
- package/dist/layout/itemBuilders.d.ts.map +1 -0
- package/dist/layout/itemBuilders.js +135 -0
- package/dist/layout/itemBuilders.js.map +1 -0
- package/dist/layout/labelsRender.d.ts +29 -0
- package/dist/layout/labelsRender.d.ts.map +1 -0
- package/dist/layout/labelsRender.js +109 -0
- package/dist/layout/labelsRender.js.map +1 -0
- package/dist/layout/legendConstants.d.ts +12 -0
- package/dist/layout/legendConstants.d.ts.map +1 -0
- package/dist/layout/legendConstants.js +12 -0
- package/dist/layout/legendConstants.js.map +1 -0
- package/dist/layout/legendRender.d.ts +13 -0
- package/dist/layout/legendRender.d.ts.map +1 -0
- package/dist/layout/legendRender.js +424 -0
- package/dist/layout/legendRender.js.map +1 -0
- package/dist/layout/legendRows.d.ts +26 -0
- package/dist/layout/legendRows.d.ts.map +1 -0
- package/dist/layout/legendRows.js +45 -0
- package/dist/layout/legendRows.js.map +1 -0
- package/dist/layout/legendUtils.d.ts +21 -0
- package/dist/layout/legendUtils.d.ts.map +1 -0
- package/dist/layout/legendUtils.js +110 -0
- package/dist/layout/legendUtils.js.map +1 -0
- package/dist/layout/metadata.d.ts +43 -0
- package/dist/layout/metadata.d.ts.map +1 -0
- package/dist/layout/metadata.js +191 -0
- package/dist/layout/metadata.js.map +1 -0
- package/dist/layout/model.d.ts +15 -0
- package/dist/layout/model.d.ts.map +1 -0
- package/dist/layout/model.js +310 -0
- package/dist/layout/model.js.map +1 -0
- package/dist/layout/options.d.ts +17 -0
- package/dist/layout/options.d.ts.map +1 -0
- package/dist/layout/options.js +2 -0
- package/dist/layout/options.js.map +1 -0
- package/dist/layout/presets.d.ts +23 -0
- package/dist/layout/presets.d.ts.map +1 -0
- package/dist/layout/presets.js +41 -0
- package/dist/layout/presets.js.map +1 -0
- package/dist/layout/qrRender.d.ts +13 -0
- package/dist/layout/qrRender.d.ts.map +1 -0
- package/dist/layout/qrRender.js +97 -0
- package/dist/layout/qrRender.js.map +1 -0
- package/dist/layout/renderDrawing.d.ts +62 -0
- package/dist/layout/renderDrawing.d.ts.map +1 -0
- package/dist/layout/renderDrawing.js +555 -0
- package/dist/layout/renderDrawing.js.map +1 -0
- package/dist/layout/renderUtils.d.ts +36 -0
- package/dist/layout/renderUtils.d.ts.map +1 -0
- package/dist/layout/renderUtils.js +117 -0
- package/dist/layout/renderUtils.js.map +1 -0
- package/dist/layout/sectionValidation.d.ts +3 -0
- package/dist/layout/sectionValidation.d.ts.map +1 -0
- package/dist/layout/sectionValidation.js +2 -0
- package/dist/layout/sectionValidation.js.map +1 -0
- package/dist/layout/templateVariables.d.ts +137 -0
- package/dist/layout/templateVariables.d.ts.map +1 -0
- package/dist/layout/templateVariables.js +295 -0
- package/dist/layout/templateVariables.js.map +1 -0
- package/dist/layout/typeGuards.d.ts +5 -0
- package/dist/layout/typeGuards.d.ts.map +1 -0
- package/dist/layout/typeGuards.js +9 -0
- package/dist/layout/typeGuards.js.map +1 -0
- package/dist/layout/types.d.ts +816 -0
- package/dist/layout/types.d.ts.map +1 -0
- package/dist/layout/types.js +2 -0
- package/dist/layout/types.js.map +1 -0
- package/dist/layout/utils.d.ts +9 -0
- package/dist/layout/utils.d.ts.map +1 -0
- package/dist/layout/utils.js +84 -0
- package/dist/layout/utils.js.map +1 -0
- package/dist/layout/validation.d.ts +7 -0
- package/dist/layout/validation.d.ts.map +1 -0
- package/dist/layout/validation.js +352 -0
- package/dist/layout/validation.js.map +1 -0
- package/dist/layout/validationHelpers.d.ts +15 -0
- package/dist/layout/validationHelpers.d.ts.map +1 -0
- package/dist/layout/validationHelpers.js +43 -0
- package/dist/layout/validationHelpers.js.map +1 -0
- package/dist/layout/validationUtils.d.ts +5 -0
- package/dist/layout/validationUtils.d.ts.map +1 -0
- package/dist/layout/validationUtils.js +5 -0
- package/dist/layout/validationUtils.js.map +1 -0
- package/dist/layout/viewportPrep.d.ts +47 -0
- package/dist/layout/viewportPrep.d.ts.map +1 -0
- package/dist/layout/viewportPrep.js +275 -0
- package/dist/layout/viewportPrep.js.map +1 -0
- package/dist/layout/viewportRender.d.ts +42 -0
- package/dist/layout/viewportRender.d.ts.map +1 -0
- package/dist/layout/viewportRender.js +337 -0
- package/dist/layout/viewportRender.js.map +1 -0
- package/dist/layout/viewportUtils.d.ts +9 -0
- package/dist/layout/viewportUtils.d.ts.map +1 -0
- package/dist/layout/viewportUtils.js +40 -0
- package/dist/layout/viewportUtils.js.map +1 -0
- package/dist/layout/warnings.d.ts +2 -0
- package/dist/layout/warnings.d.ts.map +1 -0
- package/dist/layout/warnings.js +4 -0
- package/dist/layout/warnings.js.map +1 -0
- package/dist/printToPdf.d.ts +38 -0
- package/dist/printToPdf.d.ts.map +1 -0
- package/dist/printToPdf.js +79 -0
- package/dist/printToPdf.js.map +1 -0
- package/dist/printToSvg.d.ts +11 -0
- package/dist/printToSvg.d.ts.map +1 -0
- package/dist/printToSvg.js +168 -0
- package/dist/printToSvg.js.map +1 -0
- package/dist/sections.d.ts +118 -0
- package/dist/sections.d.ts.map +1 -0
- package/dist/sections.js +839 -0
- package/dist/sections.js.map +1 -0
- package/dist/templates/default-template.json +137 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
- package/src/BuildInfo.ts +41 -0
- package/src/index.ts +10 -0
- package/src/layout/analyzeTemplate.ts +218 -0
- package/src/layout/clipUtils.ts +193 -0
- package/src/layout/colorConstants.ts +16 -0
- package/src/layout/elementKinds.ts +35 -0
- package/src/layout/exportDrawing.ts +206 -0
- package/src/layout/filters.ts +80 -0
- package/src/layout/geometryConstants.ts +11 -0
- package/src/layout/index.ts +671 -0
- package/src/layout/itemBuilders.ts +159 -0
- package/src/layout/labelsRender.ts +170 -0
- package/src/layout/legendConstants.ts +11 -0
- package/src/layout/legendRender.ts +543 -0
- package/src/layout/legendRows.ts +62 -0
- package/src/layout/legendUtils.ts +144 -0
- package/src/layout/metadata.ts +210 -0
- package/src/layout/model.ts +372 -0
- package/src/layout/options.ts +17 -0
- package/src/layout/presets.ts +51 -0
- package/src/layout/qrRender.ts +126 -0
- package/src/layout/qrcode.d.ts +2 -0
- package/src/layout/renderDrawing.ts +710 -0
- package/src/layout/renderUtils.ts +138 -0
- package/src/layout/sectionValidation.ts +2 -0
- package/src/layout/templateVariables.ts +317 -0
- package/src/layout/typeGuards.ts +9 -0
- package/src/layout/types.ts +835 -0
- package/src/layout/utils.ts +85 -0
- package/src/layout/validation.ts +392 -0
- package/src/layout/validationHelpers.ts +59 -0
- package/src/layout/validationUtils.ts +6 -0
- package/src/layout/viewportPrep.ts +351 -0
- package/src/layout/viewportRender.ts +442 -0
- package/src/layout/viewportUtils.ts +50 -0
- package/src/layout/warnings.ts +3 -0
- package/src/printToPdf.ts +108 -0
- package/src/printToSvg.ts +188 -0
- package/src/sections.ts +1019 -0
- package/src/templates/default-template.json +137 -0
- package/src/types.ts +49 -0
- package/templates/default-a0-landscape.json +209 -0
- package/templates/default-a0-portrait.json +195 -0
- package/templates/default-a1-landscape.json +167 -0
- package/templates/default-a1-portrait.json +153 -0
- package/templates/default-a3-landscape.json +111 -0
- package/templates/default-a3-portrait.json +125 -0
- package/templates/default-a4-landscape.json +97 -0
- package/templates/default-a4-portrait.json +97 -0
- package/templates/template-schema.json +1395 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legendUtils.d.ts","sourceRoot":"/","sources":["layout/legendUtils.ts"],"names":[],"mappings":"AAOA,KAAK,YAAY,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,GAAG,SAAS,CAAC;AAa/F,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CA0BtG;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,MAAM,CAgC5E;AAED,wBAAgB,yBAAyB,CACrC,YAAY,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAC3E,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,EAAE,EAC5B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACnB;IAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqBhD;AAED,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,YAAY,MAAM,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAgB1G,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { LEGEND_TEXT_WIDTH_FACTOR, LEGEND_MIN_CONTENT_WIDTH_EM, LEGEND_TEXT_Y_OFFSET_FACTOR, PX_PER_MM } from './legendConstants';
|
|
2
|
+
import { RGB_MAX, RED_SHIFT, GREEN_SHIFT, HASH_COLOR_MODULO, HASH_GREEN_SHIFT, HASH_BLUE_SHIFT, RGB_MIN } from './colorConstants';
|
|
3
|
+
import { isRecord, getProp } from './typeGuards';
|
|
4
|
+
export function parseLegendColor(value, fallbackKey) {
|
|
5
|
+
if (Array.isArray(value) && (value.length === 3 || value.length === 4)) {
|
|
6
|
+
const [r, g, b, a = RGB_MAX] = value.map((v) => Number(v) || 0);
|
|
7
|
+
return [clampColor(r), clampColor(g), clampColor(b), clampColor(a)];
|
|
8
|
+
}
|
|
9
|
+
if (typeof value === 'string') {
|
|
10
|
+
const hex = value.trim();
|
|
11
|
+
const match = /^#?([a-fA-F0-9]{6})([a-fA-F0-9]{2})?$/.exec(hex);
|
|
12
|
+
if (match) {
|
|
13
|
+
const intVal = parseInt(match[1], 16);
|
|
14
|
+
const aHex = match[2];
|
|
15
|
+
return [
|
|
16
|
+
(intVal >> RED_SHIFT) & 0xff,
|
|
17
|
+
(intVal >> GREEN_SHIFT) & 0xff,
|
|
18
|
+
intVal & 0xff,
|
|
19
|
+
aHex ? parseInt(aHex, 16) : RGB_MAX
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const hash = Math.abs(hashCode(fallbackKey || ''));
|
|
24
|
+
return [
|
|
25
|
+
hash % HASH_COLOR_MODULO,
|
|
26
|
+
(hash >> HASH_GREEN_SHIFT) % HASH_COLOR_MODULO,
|
|
27
|
+
(hash >> HASH_BLUE_SHIFT) % HASH_COLOR_MODULO,
|
|
28
|
+
RGB_MAX
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
export function formatLegendValue(value, fmt) {
|
|
32
|
+
if (fmt === undefined || fmt === null || fmt === 'string') {
|
|
33
|
+
return value === undefined || value === null ? '' : String(value);
|
|
34
|
+
}
|
|
35
|
+
if (typeof fmt === 'string') {
|
|
36
|
+
const fixedMatch = /^fixed\((\d+)(?:,\s*([^)]*))?\)$/i.exec(fmt);
|
|
37
|
+
if (fixedMatch) {
|
|
38
|
+
const digits = parseInt(fixedMatch[1], 10);
|
|
39
|
+
const suffix = fixedMatch[2] || '';
|
|
40
|
+
const num = Number(value);
|
|
41
|
+
if (Number.isFinite(num)) {
|
|
42
|
+
return `${num.toFixed(digits)}${suffix ? ` ${suffix.trim()}` : ''}`.trim();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return String(value ?? '');
|
|
46
|
+
}
|
|
47
|
+
if (isRecord(fmt)) {
|
|
48
|
+
const digits = getProp(fmt, 'digits');
|
|
49
|
+
const prefix = getProp(fmt, 'prefix');
|
|
50
|
+
const suffix = getProp(fmt, 'suffix');
|
|
51
|
+
const num = Number(value);
|
|
52
|
+
if (Number.isFinite(num) && typeof digits === 'number') {
|
|
53
|
+
const prefixStr = typeof prefix === 'string' ? prefix : '';
|
|
54
|
+
const suffixStr = typeof suffix === 'string' ? suffix : '';
|
|
55
|
+
return `${prefixStr}${num.toFixed(digits)}${suffixStr}`;
|
|
56
|
+
}
|
|
57
|
+
return String(value ?? '');
|
|
58
|
+
}
|
|
59
|
+
return String(value ?? '');
|
|
60
|
+
}
|
|
61
|
+
export function computeLegendColumnWidths(columnLabels, rows, fontSizeMm, cellPaddingMm, swatchWidthMm, fontFamily) {
|
|
62
|
+
const columnCount = Math.min(6, Math.max(2, columnLabels.length + 1));
|
|
63
|
+
const colWidthsMm = new Array(columnCount).fill(0);
|
|
64
|
+
colWidthsMm[0] = swatchWidthMm;
|
|
65
|
+
const measureTextWidthMm = createLegendTextMeasurer(fontFamily, fontSizeMm);
|
|
66
|
+
for (let c = 1; c < columnCount; c++) {
|
|
67
|
+
const colIdx = c - 1;
|
|
68
|
+
const col = columnLabels[colIdx];
|
|
69
|
+
const minWidth = col.minWidthMm ?? fontSizeMm * LEGEND_MIN_CONTENT_WIDTH_EM;
|
|
70
|
+
const maxWidth = col.maxWidthMm ?? Number.POSITIVE_INFINITY;
|
|
71
|
+
let maxWidthMeasured = measureTextWidthMm(col.label ?? '');
|
|
72
|
+
rows.forEach((row) => {
|
|
73
|
+
const text = row.values[colIdx] ?? '';
|
|
74
|
+
maxWidthMeasured = Math.max(maxWidthMeasured, measureTextWidthMm(text));
|
|
75
|
+
});
|
|
76
|
+
const contentWidth = Math.max(minWidth, Math.min(maxWidth, maxWidthMeasured + cellPaddingMm * 2));
|
|
77
|
+
colWidthsMm[c] = contentWidth;
|
|
78
|
+
}
|
|
79
|
+
return { colWidthsMm, columnCount };
|
|
80
|
+
}
|
|
81
|
+
export function computeLegendTextYOffset(fontSizeMm) {
|
|
82
|
+
return fontSizeMm * LEGEND_TEXT_Y_OFFSET_FACTOR;
|
|
83
|
+
}
|
|
84
|
+
export const createLegendTextMeasurer = (fontFamily, fontSizeMm) => {
|
|
85
|
+
if (typeof document !== 'undefined') {
|
|
86
|
+
const canvas = document.createElement('canvas');
|
|
87
|
+
canvas.width = 1024;
|
|
88
|
+
canvas.height = 64;
|
|
89
|
+
const canvasCtx = canvas.getContext('2d');
|
|
90
|
+
if (canvasCtx) {
|
|
91
|
+
canvasCtx.font = `${fontSizeMm * PX_PER_MM}px ${fontFamily}`;
|
|
92
|
+
const measureTextWidthMm = (text) => {
|
|
93
|
+
const metrics = canvasCtx.measureText(text);
|
|
94
|
+
return metrics.width / PX_PER_MM;
|
|
95
|
+
};
|
|
96
|
+
return measureTextWidthMm;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return (text) => text.length * fontSizeMm * LEGEND_TEXT_WIDTH_FACTOR;
|
|
100
|
+
};
|
|
101
|
+
const clampColor = (value) => Math.max(RGB_MIN, Math.min(RGB_MAX, Math.round(value)));
|
|
102
|
+
const hashCode = (str) => {
|
|
103
|
+
let hash = 0;
|
|
104
|
+
for (let i = 0; i < str.length; i++) {
|
|
105
|
+
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
106
|
+
hash |= 0;
|
|
107
|
+
}
|
|
108
|
+
return hash;
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=legendUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legendUtils.js","sourceRoot":"/","sources":["layout/legendUtils.ts"],"names":[],"mappings":"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","sourcesContent":["import {\r\n LEGEND_TEXT_WIDTH_FACTOR,\r\n LEGEND_MIN_CONTENT_WIDTH_EM,\r\n LEGEND_TEXT_Y_OFFSET_FACTOR,\r\n PX_PER_MM\r\n} from './legendConstants';\r\n// v2 format: { digits?: number; prefix?: string; suffix?: string } or undefined\r\ntype LegendFormat = { digits?: number; prefix?: string; suffix?: string } | string | undefined;\r\nimport {\r\n RGB_MAX,\r\n RED_SHIFT,\r\n GREEN_SHIFT,\r\n HASH_COLOR_MODULO,\r\n HASH_GREEN_SHIFT,\r\n HASH_BLUE_SHIFT,\r\n RGB_MIN\r\n} from './colorConstants';\r\n\r\nimport { isRecord, getProp } from './typeGuards';\r\n\r\nexport function parseLegendColor(value: unknown, fallbackKey: string): [number, number, number, number] {\r\n if (Array.isArray(value) && (value.length === 3 || value.length === 4)) {\r\n const [r, g, b, a = RGB_MAX] = value.map((v) => Number(v) || 0);\r\n return [clampColor(r), clampColor(g), clampColor(b), clampColor(a)];\r\n }\r\n if (typeof value === 'string') {\r\n const hex = value.trim();\r\n const match = /^#?([a-fA-F0-9]{6})([a-fA-F0-9]{2})?$/.exec(hex);\r\n if (match) {\r\n const intVal = parseInt(match[1], 16);\r\n const aHex = match[2];\r\n return [\r\n (intVal >> RED_SHIFT) & 0xff,\r\n (intVal >> GREEN_SHIFT) & 0xff,\r\n intVal & 0xff,\r\n aHex ? parseInt(aHex, 16) : RGB_MAX\r\n ];\r\n }\r\n }\r\n const hash = Math.abs(hashCode(fallbackKey || ''));\r\n return [\r\n hash % HASH_COLOR_MODULO,\r\n (hash >> HASH_GREEN_SHIFT) % HASH_COLOR_MODULO,\r\n (hash >> HASH_BLUE_SHIFT) % HASH_COLOR_MODULO,\r\n RGB_MAX\r\n ];\r\n}\r\n\r\nexport function formatLegendValue(value: unknown, fmt?: LegendFormat): string {\r\n if (fmt === undefined || fmt === null || fmt === 'string') {\r\n return value === undefined || value === null ? '' : String(value);\r\n }\r\n\r\n if (typeof fmt === 'string') {\r\n const fixedMatch = /^fixed\\((\\d+)(?:,\\s*([^)]*))?\\)$/i.exec(fmt);\r\n if (fixedMatch) {\r\n const digits = parseInt(fixedMatch[1], 10);\r\n const suffix = fixedMatch[2] || '';\r\n const num = Number(value);\r\n if (Number.isFinite(num)) {\r\n return `${num.toFixed(digits)}${suffix ? ` ${suffix.trim()}` : ''}`.trim();\r\n }\r\n }\r\n return String(value ?? '');\r\n }\r\n\r\n if (isRecord(fmt)) {\r\n const digits = getProp(fmt, 'digits');\r\n const prefix = getProp(fmt, 'prefix');\r\n const suffix = getProp(fmt, 'suffix');\r\n const num = Number(value);\r\n if (Number.isFinite(num) && typeof digits === 'number') {\r\n const prefixStr = typeof prefix === 'string' ? prefix : '';\r\n const suffixStr = typeof suffix === 'string' ? suffix : '';\r\n return `${prefixStr}${num.toFixed(digits)}${suffixStr}`;\r\n }\r\n return String(value ?? '');\r\n }\r\n\r\n return String(value ?? '');\r\n}\r\n\r\nexport function computeLegendColumnWidths(\r\n columnLabels: { label: string; minWidthMm?: number; maxWidthMm?: number }[],\r\n rows: { values: string[] }[],\r\n fontSizeMm: number,\r\n cellPaddingMm: number,\r\n swatchWidthMm: number,\r\n fontFamily: string\r\n): { colWidthsMm: number[]; columnCount: number } {\r\n const columnCount = Math.min(6, Math.max(2, columnLabels.length + 1));\r\n const colWidthsMm: number[] = new Array(columnCount).fill(0);\r\n colWidthsMm[0] = swatchWidthMm;\r\n const measureTextWidthMm = createLegendTextMeasurer(fontFamily, fontSizeMm);\r\n\r\n for (let c = 1; c < columnCount; c++) {\r\n const colIdx = c - 1;\r\n const col = columnLabels[colIdx];\r\n const minWidth = col.minWidthMm ?? fontSizeMm * LEGEND_MIN_CONTENT_WIDTH_EM;\r\n const maxWidth = col.maxWidthMm ?? Number.POSITIVE_INFINITY;\r\n let maxWidthMeasured = measureTextWidthMm(col.label ?? '');\r\n rows.forEach((row) => {\r\n const text = row.values[colIdx] ?? '';\r\n maxWidthMeasured = Math.max(maxWidthMeasured, measureTextWidthMm(text));\r\n });\r\n const contentWidth = Math.max(minWidth, Math.min(maxWidth, maxWidthMeasured + cellPaddingMm * 2));\r\n colWidthsMm[c] = contentWidth;\r\n }\r\n\r\n return { colWidthsMm, columnCount };\r\n}\r\n\r\nexport function computeLegendTextYOffset(fontSizeMm: number): number {\r\n return fontSizeMm * LEGEND_TEXT_Y_OFFSET_FACTOR;\r\n}\r\n\r\nexport const createLegendTextMeasurer = (fontFamily: string, fontSizeMm: number): ((text: string) => number) => {\r\n if (typeof document !== 'undefined') {\r\n const canvas = document.createElement('canvas');\r\n canvas.width = 1024;\r\n canvas.height = 64;\r\n const canvasCtx = canvas.getContext('2d');\r\n if (canvasCtx) {\r\n canvasCtx.font = `${fontSizeMm * PX_PER_MM}px ${fontFamily}`;\r\n const measureTextWidthMm = (text: string): number => {\r\n const metrics = canvasCtx.measureText(text);\r\n return metrics.width / PX_PER_MM;\r\n };\r\n return measureTextWidthMm;\r\n }\r\n }\r\n return (text: string): number => text.length * fontSizeMm * LEGEND_TEXT_WIDTH_FACTOR;\r\n};\r\n\r\nconst clampColor = (value: number): number => Math.max(RGB_MIN, Math.min(RGB_MAX, Math.round(value)));\r\n\r\nconst hashCode = (str: string): number => {\r\n let hash = 0;\r\n for (let i = 0; i < str.length; i++) {\r\n hash = (hash << 5) - hash + str.charCodeAt(i);\r\n hash |= 0;\r\n }\r\n return hash;\r\n};\r\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { LayoutTemplate, ResolvedIncludeFilter } from './types';
|
|
2
|
+
export interface ModelMetadataEntry {
|
|
3
|
+
productId?: string;
|
|
4
|
+
ifcClass?: string;
|
|
5
|
+
ifcClassId?: string;
|
|
6
|
+
properties?: unknown;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
export type ModelMetadata = Record<string, ModelMetadataEntry>;
|
|
10
|
+
/** Resolve the IFC class name from a BIM product object's `.class` property. */
|
|
11
|
+
export declare const resolveIfcClassName: (product: unknown) => string | null;
|
|
12
|
+
/** Resolve the predefined IFC class ID (e.g. "USERDEFINED") from `.class.id`. */
|
|
13
|
+
export declare const resolveIfcClassId: (product: unknown) => string | null;
|
|
14
|
+
export declare const normalizePropertySets: (product: unknown) => Record<string, Record<string, {
|
|
15
|
+
value: unknown;
|
|
16
|
+
unit?: string;
|
|
17
|
+
type?: string;
|
|
18
|
+
}>>;
|
|
19
|
+
export declare const buildMetadataMap: (entries: unknown[]) => ModelMetadata;
|
|
20
|
+
export declare const resolveMeta: (meta: unknown, metadataById?: ModelMetadata) => unknown;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve includeClasses config to an array of filters.
|
|
23
|
+
*
|
|
24
|
+
* Supports:
|
|
25
|
+
* - String arrays: ["space", "walls"]
|
|
26
|
+
* - Filter objects: [{ class: "space", where: { "BIP.spacetype": "ROOM" } }]
|
|
27
|
+
* - Preset references: { preset: "defaultBuilding" }
|
|
28
|
+
* - Mixed arrays: ["walls", { class: "space", where: {...} }]
|
|
29
|
+
*
|
|
30
|
+
* @returns Array of filters (strings or class+where objects), or null if no filters
|
|
31
|
+
*/
|
|
32
|
+
export declare const resolveIncludeClasses: (includeClasses: unknown, currentIncludePresets: Record<string, string[]>) => ResolvedIncludeFilter[] | null;
|
|
33
|
+
/**
|
|
34
|
+
* Resolve allowed class names from template/viewport includeClasses config.
|
|
35
|
+
*
|
|
36
|
+
* Extracts only string filters (class names), ignoring filter objects with where conditions.
|
|
37
|
+
* Used for backward compatibility and simple class-based filtering.
|
|
38
|
+
*
|
|
39
|
+
* @returns Set of normalized class names, or null if no filters
|
|
40
|
+
*/
|
|
41
|
+
export declare const resolveAllowedClasses: (layoutTemplate: LayoutTemplate, viewportId?: string) => Set<string> | null;
|
|
42
|
+
export declare const getPathValue: (obj: unknown, path: string) => unknown;
|
|
43
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"/","sources":["layout/metadata.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAkB,MAAM,SAAS,CAAC;AAErF,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAK/D,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,GAAI,SAAS,OAAO,KAAG,MAAM,GAAG,IAI/D,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,iBAAiB,GAAI,SAAS,OAAO,KAAG,MAAM,GAAG,IAK7D,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAC9B,SAAS,OAAO,KACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAkCjF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,SAAS,OAAO,EAAE,KAAG,aAmBrD,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,MAAM,OAAO,EAAE,eAAe,aAAa,KAAG,OAezE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,GAC9B,gBAAgB,OAAO,EACvB,uBAAuB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,KAChD,qBAAqB,EAAE,GAAG,IAkD5B,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,GAAI,gBAAgB,cAAc,EAAE,mBAAmB,KAAG,GAAG,CAAC,MAAM,CAAC,GAAG,IA0BzG,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,KAAK,OAAO,EAAE,MAAM,MAAM,KAAG,OAAoC,CAAC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { getPathValue as getValueByPath } from './renderUtils';
|
|
2
|
+
import { isRecord, getProp } from './typeGuards';
|
|
3
|
+
import { normalizeClass } from './filters';
|
|
4
|
+
/** Resolve the IFC class name from a BIM product object's `.class` property. */
|
|
5
|
+
export const resolveIfcClassName = (product) => {
|
|
6
|
+
const classObj = getProp(product, 'class');
|
|
7
|
+
if (!classObj)
|
|
8
|
+
return null;
|
|
9
|
+
return normalizeClass(getProp(classObj, 'name') ?? getProp(classObj, 'type') ?? getProp(classObj, 'id'));
|
|
10
|
+
};
|
|
11
|
+
/** Resolve the predefined IFC class ID (e.g. "USERDEFINED") from `.class.id`. */
|
|
12
|
+
export const resolveIfcClassId = (product) => {
|
|
13
|
+
const classObj = getProp(product, 'class');
|
|
14
|
+
if (!classObj)
|
|
15
|
+
return null;
|
|
16
|
+
const id = getProp(classObj, 'id');
|
|
17
|
+
return typeof id === 'string' ? id : null;
|
|
18
|
+
};
|
|
19
|
+
export const normalizePropertySets = (product) => {
|
|
20
|
+
const properties = getProp(product, 'properties');
|
|
21
|
+
// BIM products may have properties at various paths:
|
|
22
|
+
// - product.properties.data (Twinfinity standard)
|
|
23
|
+
// - product.properties.propertySets (BIM API)
|
|
24
|
+
// - product.propertySets (direct)
|
|
25
|
+
// - product.properties (fallback)
|
|
26
|
+
// New T8 API: product.propertySets → Record<string, T8PropertySet>
|
|
27
|
+
// where T8PropertySet.properties → Record<string, T8Property { value, type, unit }>
|
|
28
|
+
// Legacy: product.properties.data / product.properties.sets → Record<string, Record<string, unknown>>
|
|
29
|
+
const raw = getProp(product, 'propertySets') ??
|
|
30
|
+
getProp(properties, 'data') ??
|
|
31
|
+
getProp(properties, 'sets') ??
|
|
32
|
+
properties ??
|
|
33
|
+
{};
|
|
34
|
+
const propertySets = {};
|
|
35
|
+
if (!isRecord(raw))
|
|
36
|
+
return propertySets;
|
|
37
|
+
Object.entries(raw).forEach(([setName, setValue]) => {
|
|
38
|
+
if (!isRecord(setValue))
|
|
39
|
+
return;
|
|
40
|
+
// T8PropertySet has a .properties sub-record with T8Property entries
|
|
41
|
+
const innerProps = getProp(setValue, 'properties');
|
|
42
|
+
const source = isRecord(innerProps) ? innerProps : setValue;
|
|
43
|
+
const props = {};
|
|
44
|
+
Object.entries(source).forEach(([propName, propVal]) => {
|
|
45
|
+
if (isRecord(propVal) && 'value' in propVal) {
|
|
46
|
+
props[propName] = propVal;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
props[propName] = { value: propVal };
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
propertySets[setName] = props;
|
|
53
|
+
});
|
|
54
|
+
return propertySets;
|
|
55
|
+
};
|
|
56
|
+
export const buildMetadataMap = (entries) => {
|
|
57
|
+
const out = {};
|
|
58
|
+
if (!Array.isArray(entries))
|
|
59
|
+
return out;
|
|
60
|
+
entries.forEach((entry) => {
|
|
61
|
+
const product = getProp(entry, 'product') ?? entry;
|
|
62
|
+
const gid = getProp(product, 'gid') ?? getProp(product, 'id') ?? null;
|
|
63
|
+
if (!gid)
|
|
64
|
+
return;
|
|
65
|
+
const propertySets = normalizePropertySets(product);
|
|
66
|
+
const ifcClass = resolveIfcClassName(product) ?? undefined;
|
|
67
|
+
const ifcClassId = resolveIfcClassId(product) ?? undefined;
|
|
68
|
+
out[String(gid)] = {
|
|
69
|
+
productId: String(gid),
|
|
70
|
+
ifcClass,
|
|
71
|
+
ifcClassId,
|
|
72
|
+
properties: propertySets,
|
|
73
|
+
propertySets
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
return out;
|
|
77
|
+
};
|
|
78
|
+
export const resolveMeta = (meta, metadataById) => {
|
|
79
|
+
const productId = getProp(meta, 'productId') ?? getProp(meta, 'gid') ?? getProp(meta, 'id');
|
|
80
|
+
const base = productId && metadataById ? metadataById[String(productId)] : undefined;
|
|
81
|
+
if (!base) {
|
|
82
|
+
return meta;
|
|
83
|
+
}
|
|
84
|
+
const baseProps = getProp(base, 'properties');
|
|
85
|
+
const metaProps = getProp(meta, 'properties');
|
|
86
|
+
const mergedProps = baseProps || metaProps
|
|
87
|
+
? { ...(isRecord(baseProps) ? baseProps : {}), ...(isRecord(metaProps) ? metaProps : {}) }
|
|
88
|
+
: undefined;
|
|
89
|
+
return mergedProps
|
|
90
|
+
? { ...base, ...(isRecord(meta) ? meta : {}), productId, properties: mergedProps }
|
|
91
|
+
: { ...base, ...(isRecord(meta) ? meta : {}), productId };
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Resolve includeClasses config to an array of filters.
|
|
95
|
+
*
|
|
96
|
+
* Supports:
|
|
97
|
+
* - String arrays: ["space", "walls"]
|
|
98
|
+
* - Filter objects: [{ class: "space", where: { "BIP.spacetype": "ROOM" } }]
|
|
99
|
+
* - Preset references: { preset: "defaultBuilding" }
|
|
100
|
+
* - Mixed arrays: ["walls", { class: "space", where: {...} }]
|
|
101
|
+
*
|
|
102
|
+
* @returns Array of filters (strings or class+where objects), or null if no filters
|
|
103
|
+
*/
|
|
104
|
+
export const resolveIncludeClasses = (includeClasses, currentIncludePresets) => {
|
|
105
|
+
if (!includeClasses)
|
|
106
|
+
return null;
|
|
107
|
+
// Handle array of filters (strings or objects)
|
|
108
|
+
if (Array.isArray(includeClasses)) {
|
|
109
|
+
const result = [];
|
|
110
|
+
for (const item of includeClasses) {
|
|
111
|
+
if (typeof item === 'string' && item.length > 0) {
|
|
112
|
+
result.push(item);
|
|
113
|
+
}
|
|
114
|
+
else if (isRecord(item)) {
|
|
115
|
+
const cls = getProp(item, 'class');
|
|
116
|
+
const where = getProp(item, 'where');
|
|
117
|
+
// Must have either class or where (or both)
|
|
118
|
+
if (cls !== undefined || (where && isRecord(where))) {
|
|
119
|
+
result.push({ class: cls, where: where });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return result.length > 0 ? result : null;
|
|
124
|
+
}
|
|
125
|
+
// Handle preset reference or filter object
|
|
126
|
+
if (isRecord(includeClasses)) {
|
|
127
|
+
const preset = getProp(includeClasses, 'preset');
|
|
128
|
+
const cls = getProp(includeClasses, 'class');
|
|
129
|
+
const where = getProp(includeClasses, 'where');
|
|
130
|
+
// Preset reference: { preset: "name" }
|
|
131
|
+
if (typeof preset === 'string') {
|
|
132
|
+
const presetName = preset;
|
|
133
|
+
const base = currentIncludePresets[presetName] ?? [];
|
|
134
|
+
const addProp = getProp(includeClasses, 'add');
|
|
135
|
+
const removeProp = getProp(includeClasses, 'remove');
|
|
136
|
+
const add = Array.isArray(addProp) ? addProp : [];
|
|
137
|
+
const remove = Array.isArray(removeProp) ? removeProp : [];
|
|
138
|
+
const set = new Set();
|
|
139
|
+
base.forEach((c) => set.add(c));
|
|
140
|
+
add.forEach((c) => typeof c === 'string' && set.add(c));
|
|
141
|
+
remove.forEach((c) => typeof c === 'string' && set.delete(c));
|
|
142
|
+
const strings = Array.from(set).filter((c) => typeof c === 'string' && c.length > 0);
|
|
143
|
+
return strings.length > 0 ? strings : null;
|
|
144
|
+
}
|
|
145
|
+
// Filter object: { class: "space", where: {...} }
|
|
146
|
+
if (cls !== undefined || (where && isRecord(where))) {
|
|
147
|
+
return [{ class: cls, where: where }];
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return null;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Resolve allowed class names from template/viewport includeClasses config.
|
|
154
|
+
*
|
|
155
|
+
* Extracts only string filters (class names), ignoring filter objects with where conditions.
|
|
156
|
+
* Used for backward compatibility and simple class-based filtering.
|
|
157
|
+
*
|
|
158
|
+
* @returns Set of normalized class names, or null if no filters
|
|
159
|
+
*/
|
|
160
|
+
export const resolveAllowedClasses = (layoutTemplate, viewportId = 'main') => {
|
|
161
|
+
if (!layoutTemplate)
|
|
162
|
+
return null;
|
|
163
|
+
const presets = layoutTemplate.presets?.includeClasses ?? {};
|
|
164
|
+
const templateClasses = resolveIncludeClasses(getProp(layoutTemplate, 'includeClasses'), presets);
|
|
165
|
+
const elements = layoutTemplate.elements;
|
|
166
|
+
const viewportEl = Array.isArray(elements)
|
|
167
|
+
? elements.find((el) => isRecord(el) && getProp(el, 'kind') === 'viewport' && getProp(el, 'id') === viewportId)
|
|
168
|
+
: undefined;
|
|
169
|
+
const viewportClasses = resolveIncludeClasses(getProp(viewportEl, 'includeClasses'), presets);
|
|
170
|
+
const resolved = viewportClasses ?? templateClasses;
|
|
171
|
+
if (!resolved || !resolved.length) {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
// Extract only string filters (class names)
|
|
175
|
+
const classNames = new Set();
|
|
176
|
+
for (const filter of resolved) {
|
|
177
|
+
if (typeof filter === 'string') {
|
|
178
|
+
classNames.add(filter);
|
|
179
|
+
}
|
|
180
|
+
else if (isRecord(filter) && filter.class) {
|
|
181
|
+
const classes = Array.isArray(filter.class) ? filter.class : [filter.class];
|
|
182
|
+
for (const c of classes) {
|
|
183
|
+
if (typeof c === 'string')
|
|
184
|
+
classNames.add(c);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return classNames.size > 0 ? classNames : null;
|
|
189
|
+
};
|
|
190
|
+
export const getPathValue = (obj, path) => getValueByPath(obj, path);
|
|
191
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"/","sources":["layout/metadata.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPathValue as getValueByPath } from './renderUtils';\r\nimport type { LayoutTemplate, ResolvedIncludeFilter, WhereCondition } from './types';\r\n\r\nexport interface ModelMetadataEntry {\r\n productId?: string;\r\n ifcClass?: string;\r\n ifcClassId?: string;\r\n properties?: unknown;\r\n [key: string]: unknown;\r\n}\r\n\r\nexport type ModelMetadata = Record<string, ModelMetadataEntry>;\r\n\r\nimport { isRecord, getProp } from './typeGuards';\r\nimport { normalizeClass } from './filters';\r\n\r\n/** Resolve the IFC class name from a BIM product object's `.class` property. */\r\nexport const resolveIfcClassName = (product: unknown): string | null => {\r\n const classObj = getProp(product, 'class');\r\n if (!classObj) return null;\r\n return normalizeClass(getProp(classObj, 'name') ?? getProp(classObj, 'type') ?? getProp(classObj, 'id'));\r\n};\r\n\r\n/** Resolve the predefined IFC class ID (e.g. \"USERDEFINED\") from `.class.id`. */\r\nexport const resolveIfcClassId = (product: unknown): string | null => {\r\n const classObj = getProp(product, 'class');\r\n if (!classObj) return null;\r\n const id = getProp(classObj, 'id');\r\n return typeof id === 'string' ? id : null;\r\n};\r\n\r\nexport const normalizePropertySets = (\r\n product: unknown\r\n): Record<string, Record<string, { value: unknown; unit?: string; type?: string }>> => {\r\n const properties = getProp(product, 'properties');\r\n // BIM products may have properties at various paths:\r\n // - product.properties.data (Twinfinity standard)\r\n // - product.properties.propertySets (BIM API)\r\n // - product.propertySets (direct)\r\n // - product.properties (fallback)\r\n // New T8 API: product.propertySets → Record<string, T8PropertySet>\r\n // where T8PropertySet.properties → Record<string, T8Property { value, type, unit }>\r\n // Legacy: product.properties.data / product.properties.sets → Record<string, Record<string, unknown>>\r\n const raw =\r\n getProp(product, 'propertySets') ??\r\n getProp(properties, 'data') ??\r\n getProp(properties, 'sets') ??\r\n properties ??\r\n {};\r\n const propertySets: Record<string, Record<string, { value: unknown; unit?: string; type?: string }>> = {};\r\n if (!isRecord(raw)) return propertySets;\r\n Object.entries(raw).forEach(([setName, setValue]) => {\r\n if (!isRecord(setValue)) return;\r\n // T8PropertySet has a .properties sub-record with T8Property entries\r\n const innerProps = getProp(setValue, 'properties');\r\n const source = isRecord(innerProps) ? innerProps : setValue;\r\n const props: Record<string, { value: unknown; unit?: string; type?: string }> = {};\r\n Object.entries(source).forEach(([propName, propVal]) => {\r\n if (isRecord(propVal) && 'value' in propVal) {\r\n props[propName] = propVal as { value: unknown; unit?: string; type?: string };\r\n } else {\r\n props[propName] = { value: propVal };\r\n }\r\n });\r\n propertySets[setName] = props;\r\n });\r\n return propertySets;\r\n};\r\n\r\nexport const buildMetadataMap = (entries: unknown[]): ModelMetadata => {\r\n const out: ModelMetadata = {};\r\n if (!Array.isArray(entries)) return out;\r\n entries.forEach((entry) => {\r\n const product = getProp(entry, 'product') ?? entry;\r\n const gid = getProp(product, 'gid') ?? getProp(product, 'id') ?? null;\r\n if (!gid) return;\r\n const propertySets = normalizePropertySets(product);\r\n const ifcClass = resolveIfcClassName(product) ?? undefined;\r\n const ifcClassId = resolveIfcClassId(product) ?? undefined;\r\n out[String(gid)] = {\r\n productId: String(gid),\r\n ifcClass,\r\n ifcClassId,\r\n properties: propertySets,\r\n propertySets\r\n };\r\n });\r\n return out;\r\n};\r\n\r\nexport const resolveMeta = (meta: unknown, metadataById?: ModelMetadata): unknown => {\r\n const productId = getProp(meta, 'productId') ?? getProp(meta, 'gid') ?? getProp(meta, 'id');\r\n const base = productId && metadataById ? metadataById[String(productId)] : undefined;\r\n if (!base) {\r\n return meta;\r\n }\r\n const baseProps = getProp(base, 'properties');\r\n const metaProps = getProp(meta, 'properties');\r\n const mergedProps =\r\n baseProps || metaProps\r\n ? { ...(isRecord(baseProps) ? baseProps : {}), ...(isRecord(metaProps) ? metaProps : {}) }\r\n : undefined;\r\n return mergedProps\r\n ? { ...base, ...(isRecord(meta) ? meta : {}), productId, properties: mergedProps }\r\n : { ...base, ...(isRecord(meta) ? meta : {}), productId };\r\n};\r\n\r\n/**\r\n * Resolve includeClasses config to an array of filters.\r\n *\r\n * Supports:\r\n * - String arrays: [\"space\", \"walls\"]\r\n * - Filter objects: [{ class: \"space\", where: { \"BIP.spacetype\": \"ROOM\" } }]\r\n * - Preset references: { preset: \"defaultBuilding\" }\r\n * - Mixed arrays: [\"walls\", { class: \"space\", where: {...} }]\r\n *\r\n * @returns Array of filters (strings or class+where objects), or null if no filters\r\n */\r\nexport const resolveIncludeClasses = (\r\n includeClasses: unknown,\r\n currentIncludePresets: Record<string, string[]>\r\n): ResolvedIncludeFilter[] | null => {\r\n if (!includeClasses) return null;\r\n\r\n // Handle array of filters (strings or objects)\r\n if (Array.isArray(includeClasses)) {\r\n const result: ResolvedIncludeFilter[] = [];\r\n for (const item of includeClasses) {\r\n if (typeof item === 'string' && item.length > 0) {\r\n result.push(item);\r\n } else if (isRecord(item)) {\r\n const cls = getProp(item, 'class');\r\n const where = getProp(item, 'where');\r\n // Must have either class or where (or both)\r\n if (cls !== undefined || (where && isRecord(where))) {\r\n result.push({ class: cls as string | string[] | undefined, where: where as WhereCondition });\r\n }\r\n }\r\n }\r\n return result.length > 0 ? result : null;\r\n }\r\n\r\n // Handle preset reference or filter object\r\n if (isRecord(includeClasses)) {\r\n const preset = getProp(includeClasses, 'preset');\r\n const cls = getProp(includeClasses, 'class');\r\n const where = getProp(includeClasses, 'where');\r\n\r\n // Preset reference: { preset: \"name\" }\r\n if (typeof preset === 'string') {\r\n const presetName = preset;\r\n const base = currentIncludePresets[presetName] ?? [];\r\n const addProp = getProp(includeClasses, 'add');\r\n const removeProp = getProp(includeClasses, 'remove');\r\n const add = Array.isArray(addProp) ? addProp : [];\r\n const remove = Array.isArray(removeProp) ? removeProp : [];\r\n const set = new Set<string>();\r\n base.forEach((c: string) => set.add(c));\r\n add.forEach((c: unknown) => typeof c === 'string' && set.add(c));\r\n remove.forEach((c: unknown) => typeof c === 'string' && set.delete(c));\r\n const strings = Array.from(set).filter((c) => typeof c === 'string' && c.length > 0);\r\n return strings.length > 0 ? strings : null;\r\n }\r\n\r\n // Filter object: { class: \"space\", where: {...} }\r\n if (cls !== undefined || (where && isRecord(where))) {\r\n return [{ class: cls as string | string[] | undefined, where: where as WhereCondition }];\r\n }\r\n }\r\n\r\n return null;\r\n};\r\n\r\n/**\r\n * Resolve allowed class names from template/viewport includeClasses config.\r\n *\r\n * Extracts only string filters (class names), ignoring filter objects with where conditions.\r\n * Used for backward compatibility and simple class-based filtering.\r\n *\r\n * @returns Set of normalized class names, or null if no filters\r\n */\r\nexport const resolveAllowedClasses = (layoutTemplate: LayoutTemplate, viewportId = 'main'): Set<string> | null => {\r\n if (!layoutTemplate) return null;\r\n const presets = layoutTemplate.presets?.includeClasses ?? {};\r\n const templateClasses = resolveIncludeClasses(getProp(layoutTemplate, 'includeClasses'), presets);\r\n const elements = layoutTemplate.elements;\r\n const viewportEl = Array.isArray(elements)\r\n ? elements.find((el) => isRecord(el) && getProp(el, 'kind') === 'viewport' && getProp(el, 'id') === viewportId)\r\n : undefined;\r\n const viewportClasses = resolveIncludeClasses(getProp(viewportEl, 'includeClasses'), presets);\r\n const resolved = viewportClasses ?? templateClasses;\r\n if (!resolved || !resolved.length) {\r\n return null;\r\n }\r\n // Extract only string filters (class names)\r\n const classNames = new Set<string>();\r\n for (const filter of resolved) {\r\n if (typeof filter === 'string') {\r\n classNames.add(filter);\r\n } else if (isRecord(filter) && filter.class) {\r\n const classes = Array.isArray(filter.class) ? filter.class : [filter.class];\r\n for (const c of classes) {\r\n if (typeof c === 'string') classNames.add(c);\r\n }\r\n }\r\n }\r\n return classNames.size > 0 ? classNames : null;\r\n};\r\n\r\nexport const getPathValue = (obj: unknown, path: string): unknown => getValueByPath(obj, path);\r\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SectionPath, SectionLabel } from '@twinfinity/geometry';
|
|
2
|
+
import type { SvgModelView, ViewportElement, LabelStyle } from './types';
|
|
3
|
+
import type { ModelMetadata } from './metadata';
|
|
4
|
+
export declare const buildModelViewFromRaw: (rawPaths: SectionPath[] | undefined, rawLabels: SectionLabel[] | undefined, transform: SvgModelView["transform"] | undefined, geometryTransform?: string, labelStyle?: LabelStyle) => SvgModelView | null;
|
|
5
|
+
export declare const filterModelForViewport: (model: SvgModelView, vp: ViewportElement, metadataById?: ModelMetadata, includePresets?: Record<string, string[]>, allowedGids?: Set<string> | null, highlight?: {
|
|
6
|
+
gids: Set<string> | null;
|
|
7
|
+
styles?: {
|
|
8
|
+
stroke?: string;
|
|
9
|
+
strokeWidthMm?: number;
|
|
10
|
+
strokeOpacity?: number;
|
|
11
|
+
fill?: string;
|
|
12
|
+
fillOpacity?: number;
|
|
13
|
+
};
|
|
14
|
+
}, filterClasses?: Set<string> | null) => SvgModelView;
|
|
15
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"/","sources":["layout/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,UAAU,EAAyB,MAAM,SAAS,CAAC;AAChG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAQhD,eAAO,MAAM,qBAAqB,GAC9B,UAAU,WAAW,EAAE,GAAG,SAAS,EACnC,WAAW,YAAY,EAAE,GAAG,SAAS,EACrC,WAAW,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,EAChD,oBAAoB,MAAM,EAC1B,aAAa,UAAU,KACxB,YAAY,GAAG,IAkDjB,CAAC;AAwFF,eAAO,MAAM,sBAAsB,GAC/B,OAAO,YAAY,EACnB,IAAI,eAAe,EACnB,eAAe,aAAa,EAC5B,iBAAiB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EACzC,cAAc,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EAChC,YAAY;IACR,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACzB,MAAM,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACL,EACD,gBAAgB,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,KACnC,YAwMF,CAAC"}
|