@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,170 +1,170 @@
|
|
|
1
|
-
import { LabelsElement, LayoutData } from './types';
|
|
2
|
-
import { matchesV2Filter } from './filters';
|
|
3
|
-
import { pointInPolygon } from './clipUtils';
|
|
4
|
-
import { getPathValue, resolvePath, escapeAttr, escapeText } from './renderUtils';
|
|
5
|
-
|
|
6
|
-
import { isRecord, getProp } from './typeGuards';
|
|
7
|
-
|
|
8
|
-
export interface ViewportRenderInfo {
|
|
9
|
-
mmPerModel: number;
|
|
10
|
-
contentWidthMm: number;
|
|
11
|
-
contentHeightMm: number;
|
|
12
|
-
offsetX: number;
|
|
13
|
-
offsetY: number;
|
|
14
|
-
rotationDeg: number;
|
|
15
|
-
transform: {
|
|
16
|
-
viewMinX: number;
|
|
17
|
-
viewMaxX: number;
|
|
18
|
-
viewMinZ: number;
|
|
19
|
-
viewMaxZ: number;
|
|
20
|
-
viewWidth: number;
|
|
21
|
-
viewHeight: number;
|
|
22
|
-
};
|
|
23
|
-
centerX: number;
|
|
24
|
-
centerY: number;
|
|
25
|
-
centerModelX: number;
|
|
26
|
-
centerModelY: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const renderLabels = (
|
|
30
|
-
labelElements: LabelsElement[],
|
|
31
|
-
data: LayoutData,
|
|
32
|
-
viewportRenderInfo: Record<string, ViewportRenderInfo>,
|
|
33
|
-
viewportClipLabels: Record<string, boolean>,
|
|
34
|
-
viewportClipPolygonsLocal: Record<string, Array<Array<{ x: number; y: number }>>>,
|
|
35
|
-
viewportClipPolygonsWorld: Record<string, Array<Array<{ x: number; z: number }>>>,
|
|
36
|
-
styles: Record<string, unknown>,
|
|
37
|
-
dataWithViewport: unknown,
|
|
38
|
-
warnings: string[]
|
|
39
|
-
): string[] => {
|
|
40
|
-
const parts: string[] = [];
|
|
41
|
-
|
|
42
|
-
for (const dl of labelElements) {
|
|
43
|
-
const vpInfo = viewportRenderInfo[dl.viewport];
|
|
44
|
-
if (!vpInfo) {
|
|
45
|
-
warnings.push(`Labels '${dl.id}' missing viewport '${dl.viewport}'.`);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
if (vpInfo.rotationDeg !== 0) {
|
|
49
|
-
warnings.push(`Labels '${dl.id}' skipped because rotation is not supported.`);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
if (!vpInfo.transform) {
|
|
53
|
-
warnings.push(`Labels '${dl.id}' skipped because model transform is missing.`);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
// Items come from the bound viewport's data
|
|
57
|
-
const items = getPathValue(data, `viewports.${dl.viewport}.items`);
|
|
58
|
-
if (!Array.isArray(items) || !items.length) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
// Filter by class + where
|
|
62
|
-
let filteredItems =
|
|
63
|
-
dl.class || dl.where ? items.filter((item) => matchesV2Filter(item, dl.class, dl.where)) : items;
|
|
64
|
-
|
|
65
|
-
console.log(`[Labels ${dl.id}] Total items:`, items.length, 'After class+where filter:', filteredItems.length);
|
|
66
|
-
|
|
67
|
-
// If matchClipFilter is true, filter by spatial position inside clip polygon
|
|
68
|
-
if (dl.matchClipFilter && viewportClipPolygonsWorld[dl.viewport]?.length) {
|
|
69
|
-
const clipPolygons = viewportClipPolygonsWorld[dl.viewport];
|
|
70
|
-
console.log(`[Labels ${dl.id}] Applying matchClipFilter (spatial) with ${clipPolygons.length} polygons`);
|
|
71
|
-
const beforeClipFilter = filteredItems.length;
|
|
72
|
-
filteredItems = filteredItems.filter((item) => {
|
|
73
|
-
const ix = getProp(item, 'x');
|
|
74
|
-
const iz = getProp(item, 'z');
|
|
75
|
-
if (!Number.isFinite(ix) || !Number.isFinite(iz)) return false;
|
|
76
|
-
return clipPolygons.some((poly) => {
|
|
77
|
-
// pointInPolygon expects y coordinate, but we use z for world space
|
|
78
|
-
const polyWith2D = poly.map((p) => ({ x: p.x, y: p.z }));
|
|
79
|
-
return pointInPolygon(polyWith2D, ix as number, iz as number);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
console.log(
|
|
83
|
-
`[Labels ${dl.id}] After matchClipFilter (spatial):`,
|
|
84
|
-
filteredItems.length,
|
|
85
|
-
'(was:',
|
|
86
|
-
beforeClipFilter,
|
|
87
|
-
')'
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
// Debug: log first few items to see their properties
|
|
91
|
-
if (filteredItems.length === 0 && beforeClipFilter > 0) {
|
|
92
|
-
console.log('[Labels] Sample item that was filtered out:', items[0]);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (!filteredItems.length) {
|
|
97
|
-
console.log(`[Labels ${dl.id}] No items left after filtering, skipping.`);
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
const styleName = dl.textStyle;
|
|
101
|
-
const style = styleName && isRecord(styles) ? getProp(styles, styleName) : undefined;
|
|
102
|
-
if (!isRecord(style)) {
|
|
103
|
-
warnings.push(`Labels '${dl.id}' missing textStyle '${styleName ?? '(none)'}'.`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
const anchor = dl.align === 'center' ? 'middle' : dl.align === 'right' ? 'end' : 'start';
|
|
107
|
-
const t = vpInfo.transform;
|
|
108
|
-
|
|
109
|
-
let renderedCount = 0;
|
|
110
|
-
let spatiallyFilteredCount = 0;
|
|
111
|
-
|
|
112
|
-
filteredItems.forEach((item) => {
|
|
113
|
-
// Hardcoded x/z for BIM floor plane convention
|
|
114
|
-
const xVal = getProp(item, 'x');
|
|
115
|
-
const yVal = getProp(item, 'z');
|
|
116
|
-
if (!Number.isFinite(xVal as number) || !Number.isFinite(yVal as number)) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const viewX = (xVal as number) - t.viewMinX;
|
|
120
|
-
const viewY = t.viewMaxZ - (yVal as number);
|
|
121
|
-
const centerModelX = vpInfo.centerModelX;
|
|
122
|
-
const centerModelY = vpInfo.centerModelY;
|
|
123
|
-
const xMm = vpInfo.centerX + (viewX - centerModelX) * vpInfo.mmPerModel;
|
|
124
|
-
const yMm = vpInfo.centerY + (viewY - centerModelY) * vpInfo.mmPerModel;
|
|
125
|
-
|
|
126
|
-
if (viewportClipLabels[dl.viewport] && viewportClipPolygonsLocal[dl.viewport]?.length) {
|
|
127
|
-
const inside = viewportClipPolygonsLocal[dl.viewport].some((poly) =>
|
|
128
|
-
pointInPolygon(poly, viewX, viewY)
|
|
129
|
-
);
|
|
130
|
-
if (!inside) {
|
|
131
|
-
spatiallyFilteredCount++;
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
renderedCount++;
|
|
137
|
-
|
|
138
|
-
const text = escapeText(
|
|
139
|
-
dl.text && typeof dl.text === 'string'
|
|
140
|
-
? dl.text.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_m, path) => {
|
|
141
|
-
const val = resolvePath(item, path) ?? getPathValue(dataWithViewport, path);
|
|
142
|
-
return val === undefined || val === null || typeof val === 'object' ? '' : String(val);
|
|
143
|
-
})
|
|
144
|
-
: ''
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
const fontFamily = getProp(style, 'fontFamily');
|
|
148
|
-
const fontSizeMm = getProp(style, 'fontSizeMm');
|
|
149
|
-
const fontWeight = getProp(style, 'fontWeight');
|
|
150
|
-
const color = getProp(style, 'color');
|
|
151
|
-
const letterSpacingMm = getProp(style, 'letterSpacingMm');
|
|
152
|
-
const lineHeightMm = getProp(style, 'lineHeightMm');
|
|
153
|
-
|
|
154
|
-
parts.push(
|
|
155
|
-
`<text x="${xMm}" y="${yMm}" font-family="${escapeAttr(String(fontFamily))}" font-size="${fontSizeMm}"` +
|
|
156
|
-
(fontWeight ? ` font-weight="${escapeAttr(String(fontWeight))}"` : '') +
|
|
157
|
-
(color ? ` fill="${escapeAttr(String(color))}"` : '') +
|
|
158
|
-
(letterSpacingMm !== undefined ? ` letter-spacing="${letterSpacingMm}"` : '') +
|
|
159
|
-
(lineHeightMm !== undefined ? ` line-height="${lineHeightMm}"` : '') +
|
|
160
|
-
` text-anchor="${anchor}">${text}</text>`
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
console.log(
|
|
165
|
-
`[Labels ${dl.id}] Rendered ${renderedCount} labels. Spatially filtered out: ${spatiallyFilteredCount}`
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return parts;
|
|
170
|
-
};
|
|
1
|
+
import { LabelsElement, LayoutData } from './types';
|
|
2
|
+
import { matchesV2Filter } from './filters';
|
|
3
|
+
import { pointInPolygon } from './clipUtils';
|
|
4
|
+
import { getPathValue, resolvePath, escapeAttr, escapeText } from './renderUtils';
|
|
5
|
+
|
|
6
|
+
import { isRecord, getProp } from './typeGuards';
|
|
7
|
+
|
|
8
|
+
export interface ViewportRenderInfo {
|
|
9
|
+
mmPerModel: number;
|
|
10
|
+
contentWidthMm: number;
|
|
11
|
+
contentHeightMm: number;
|
|
12
|
+
offsetX: number;
|
|
13
|
+
offsetY: number;
|
|
14
|
+
rotationDeg: number;
|
|
15
|
+
transform: {
|
|
16
|
+
viewMinX: number;
|
|
17
|
+
viewMaxX: number;
|
|
18
|
+
viewMinZ: number;
|
|
19
|
+
viewMaxZ: number;
|
|
20
|
+
viewWidth: number;
|
|
21
|
+
viewHeight: number;
|
|
22
|
+
};
|
|
23
|
+
centerX: number;
|
|
24
|
+
centerY: number;
|
|
25
|
+
centerModelX: number;
|
|
26
|
+
centerModelY: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const renderLabels = (
|
|
30
|
+
labelElements: LabelsElement[],
|
|
31
|
+
data: LayoutData,
|
|
32
|
+
viewportRenderInfo: Record<string, ViewportRenderInfo>,
|
|
33
|
+
viewportClipLabels: Record<string, boolean>,
|
|
34
|
+
viewportClipPolygonsLocal: Record<string, Array<Array<{ x: number; y: number }>>>,
|
|
35
|
+
viewportClipPolygonsWorld: Record<string, Array<Array<{ x: number; z: number }>>>,
|
|
36
|
+
styles: Record<string, unknown>,
|
|
37
|
+
dataWithViewport: unknown,
|
|
38
|
+
warnings: string[]
|
|
39
|
+
): string[] => {
|
|
40
|
+
const parts: string[] = [];
|
|
41
|
+
|
|
42
|
+
for (const dl of labelElements) {
|
|
43
|
+
const vpInfo = viewportRenderInfo[dl.viewport];
|
|
44
|
+
if (!vpInfo) {
|
|
45
|
+
warnings.push(`Labels '${dl.id}' missing viewport '${dl.viewport}'.`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (vpInfo.rotationDeg !== 0) {
|
|
49
|
+
warnings.push(`Labels '${dl.id}' skipped because rotation is not supported.`);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (!vpInfo.transform) {
|
|
53
|
+
warnings.push(`Labels '${dl.id}' skipped because model transform is missing.`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
// Items come from the bound viewport's data
|
|
57
|
+
const items = getPathValue(data, `viewports.${dl.viewport}.items`);
|
|
58
|
+
if (!Array.isArray(items) || !items.length) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
// Filter by class + where
|
|
62
|
+
let filteredItems =
|
|
63
|
+
dl.class || dl.where ? items.filter((item) => matchesV2Filter(item, dl.class, dl.where)) : items;
|
|
64
|
+
|
|
65
|
+
console.log(`[Labels ${dl.id}] Total items:`, items.length, 'After class+where filter:', filteredItems.length);
|
|
66
|
+
|
|
67
|
+
// If matchClipFilter is true, filter by spatial position inside clip polygon
|
|
68
|
+
if (dl.matchClipFilter && viewportClipPolygonsWorld[dl.viewport]?.length) {
|
|
69
|
+
const clipPolygons = viewportClipPolygonsWorld[dl.viewport];
|
|
70
|
+
console.log(`[Labels ${dl.id}] Applying matchClipFilter (spatial) with ${clipPolygons.length} polygons`);
|
|
71
|
+
const beforeClipFilter = filteredItems.length;
|
|
72
|
+
filteredItems = filteredItems.filter((item) => {
|
|
73
|
+
const ix = getProp(item, 'x');
|
|
74
|
+
const iz = getProp(item, 'z');
|
|
75
|
+
if (!Number.isFinite(ix) || !Number.isFinite(iz)) return false;
|
|
76
|
+
return clipPolygons.some((poly) => {
|
|
77
|
+
// pointInPolygon expects y coordinate, but we use z for world space
|
|
78
|
+
const polyWith2D = poly.map((p) => ({ x: p.x, y: p.z }));
|
|
79
|
+
return pointInPolygon(polyWith2D, ix as number, iz as number);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
console.log(
|
|
83
|
+
`[Labels ${dl.id}] After matchClipFilter (spatial):`,
|
|
84
|
+
filteredItems.length,
|
|
85
|
+
'(was:',
|
|
86
|
+
beforeClipFilter,
|
|
87
|
+
')'
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Debug: log first few items to see their properties
|
|
91
|
+
if (filteredItems.length === 0 && beforeClipFilter > 0) {
|
|
92
|
+
console.log('[Labels] Sample item that was filtered out:', items[0]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!filteredItems.length) {
|
|
97
|
+
console.log(`[Labels ${dl.id}] No items left after filtering, skipping.`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const styleName = dl.textStyle;
|
|
101
|
+
const style = styleName && isRecord(styles) ? getProp(styles, styleName) : undefined;
|
|
102
|
+
if (!isRecord(style)) {
|
|
103
|
+
warnings.push(`Labels '${dl.id}' missing textStyle '${styleName ?? '(none)'}'.`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const anchor = dl.align === 'center' ? 'middle' : dl.align === 'right' ? 'end' : 'start';
|
|
107
|
+
const t = vpInfo.transform;
|
|
108
|
+
|
|
109
|
+
let renderedCount = 0;
|
|
110
|
+
let spatiallyFilteredCount = 0;
|
|
111
|
+
|
|
112
|
+
filteredItems.forEach((item) => {
|
|
113
|
+
// Hardcoded x/z for BIM floor plane convention
|
|
114
|
+
const xVal = getProp(item, 'x');
|
|
115
|
+
const yVal = getProp(item, 'z');
|
|
116
|
+
if (!Number.isFinite(xVal as number) || !Number.isFinite(yVal as number)) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const viewX = (xVal as number) - t.viewMinX;
|
|
120
|
+
const viewY = t.viewMaxZ - (yVal as number);
|
|
121
|
+
const centerModelX = vpInfo.centerModelX;
|
|
122
|
+
const centerModelY = vpInfo.centerModelY;
|
|
123
|
+
const xMm = vpInfo.centerX + (viewX - centerModelX) * vpInfo.mmPerModel;
|
|
124
|
+
const yMm = vpInfo.centerY + (viewY - centerModelY) * vpInfo.mmPerModel;
|
|
125
|
+
|
|
126
|
+
if (viewportClipLabels[dl.viewport] && viewportClipPolygonsLocal[dl.viewport]?.length) {
|
|
127
|
+
const inside = viewportClipPolygonsLocal[dl.viewport].some((poly) =>
|
|
128
|
+
pointInPolygon(poly, viewX, viewY)
|
|
129
|
+
);
|
|
130
|
+
if (!inside) {
|
|
131
|
+
spatiallyFilteredCount++;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
renderedCount++;
|
|
137
|
+
|
|
138
|
+
const text = escapeText(
|
|
139
|
+
dl.text && typeof dl.text === 'string'
|
|
140
|
+
? dl.text.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_m, path) => {
|
|
141
|
+
const val = resolvePath(item, path) ?? getPathValue(dataWithViewport, path);
|
|
142
|
+
return val === undefined || val === null || typeof val === 'object' ? '' : String(val);
|
|
143
|
+
})
|
|
144
|
+
: ''
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
const fontFamily = getProp(style, 'fontFamily');
|
|
148
|
+
const fontSizeMm = getProp(style, 'fontSizeMm');
|
|
149
|
+
const fontWeight = getProp(style, 'fontWeight');
|
|
150
|
+
const color = getProp(style, 'color');
|
|
151
|
+
const letterSpacingMm = getProp(style, 'letterSpacingMm');
|
|
152
|
+
const lineHeightMm = getProp(style, 'lineHeightMm');
|
|
153
|
+
|
|
154
|
+
parts.push(
|
|
155
|
+
`<text x="${xMm}" y="${yMm}" font-family="${escapeAttr(String(fontFamily))}" font-size="${fontSizeMm}"` +
|
|
156
|
+
(fontWeight ? ` font-weight="${escapeAttr(String(fontWeight))}"` : '') +
|
|
157
|
+
(color ? ` fill="${escapeAttr(String(color))}"` : '') +
|
|
158
|
+
(letterSpacingMm !== undefined ? ` letter-spacing="${letterSpacingMm}"` : '') +
|
|
159
|
+
(lineHeightMm !== undefined ? ` line-height="${lineHeightMm}"` : '') +
|
|
160
|
+
` text-anchor="${anchor}">${text}</text>`
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
console.log(
|
|
165
|
+
`[Labels ${dl.id}] Rendered ${renderedCount} labels. Spatially filtered out: ${spatiallyFilteredCount}`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return parts;
|
|
170
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export const PX_PER_MM = 96 / 25.4;
|
|
2
|
-
export const DEFAULT_LEGEND_SWATCH_WIDTH_MM = 8;
|
|
3
|
-
export const DEFAULT_LEGEND_CELL_PADDING_MM = 2;
|
|
4
|
-
export const DEFAULT_LEGEND_BORDER_WIDTH_MM = 0.25;
|
|
5
|
-
export const DEFAULT_LEGEND_GRID_WIDTH_MM = 0.25;
|
|
6
|
-
export const DEFAULT_LEGEND_HEADER_WIDTH_MM = 0.65;
|
|
7
|
-
export const DEFAULT_LEGEND_OFFSET_MM = 5;
|
|
8
|
-
export const LEGEND_TEXT_WIDTH_FACTOR = 0.7;
|
|
9
|
-
export const LEGEND_MIN_CONTENT_WIDTH_EM = 4;
|
|
10
|
-
export const LEGEND_TEXT_Y_OFFSET_FACTOR = 0.3;
|
|
11
|
-
export const MAX_LEGEND_ROWS = 200;
|
|
1
|
+
export const PX_PER_MM = 96 / 25.4;
|
|
2
|
+
export const DEFAULT_LEGEND_SWATCH_WIDTH_MM = 8;
|
|
3
|
+
export const DEFAULT_LEGEND_CELL_PADDING_MM = 2;
|
|
4
|
+
export const DEFAULT_LEGEND_BORDER_WIDTH_MM = 0.25;
|
|
5
|
+
export const DEFAULT_LEGEND_GRID_WIDTH_MM = 0.25;
|
|
6
|
+
export const DEFAULT_LEGEND_HEADER_WIDTH_MM = 0.65;
|
|
7
|
+
export const DEFAULT_LEGEND_OFFSET_MM = 5;
|
|
8
|
+
export const LEGEND_TEXT_WIDTH_FACTOR = 0.7;
|
|
9
|
+
export const LEGEND_MIN_CONTENT_WIDTH_EM = 4;
|
|
10
|
+
export const LEGEND_TEXT_Y_OFFSET_FACTOR = 0.3;
|
|
11
|
+
export const MAX_LEGEND_ROWS = 200;
|