@twinfinity/printing 6.1.1-beta → 6.1.2-ci.30738-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/dist/BuildInfo.js +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/layout/analyzeTemplate.d.ts +4 -4
- package/dist/layout/analyzeTemplate.d.ts.map +1 -1
- package/dist/layout/analyzeTemplate.js +18 -16
- package/dist/layout/analyzeTemplate.js.map +1 -1
- package/dist/layout/classClosure.d.ts +41 -0
- package/dist/layout/classClosure.d.ts.map +1 -0
- package/dist/layout/classClosure.js +143 -0
- package/dist/layout/classClosure.js.map +1 -0
- package/dist/layout/clipUtils.d.ts +11 -0
- package/dist/layout/clipUtils.d.ts.map +1 -1
- package/dist/layout/clipUtils.js +67 -6
- package/dist/layout/clipUtils.js.map +1 -1
- package/dist/layout/filters.d.ts +14 -8
- package/dist/layout/filters.d.ts.map +1 -1
- package/dist/layout/filters.js +28 -3
- package/dist/layout/filters.js.map +1 -1
- package/dist/layout/index.d.ts +24 -57
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +20 -337
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/itemBuilders.d.ts +11 -0
- package/dist/layout/itemBuilders.d.ts.map +1 -1
- package/dist/layout/itemBuilders.js +17 -3
- package/dist/layout/itemBuilders.js.map +1 -1
- package/dist/layout/labelsRender.d.ts.map +1 -1
- package/dist/layout/labelsRender.js +15 -27
- package/dist/layout/labelsRender.js.map +1 -1
- package/dist/layout/legendRender.d.ts +18 -6
- package/dist/layout/legendRender.d.ts.map +1 -1
- package/dist/layout/legendRender.js +49 -79
- package/dist/layout/legendRender.js.map +1 -1
- package/dist/layout/metadata.d.ts.map +1 -1
- package/dist/layout/metadata.js +26 -5
- package/dist/layout/metadata.js.map +1 -1
- package/dist/layout/model.d.ts +4 -3
- package/dist/layout/model.d.ts.map +1 -1
- package/dist/layout/model.js +17 -57
- package/dist/layout/model.js.map +1 -1
- package/dist/layout/options.d.ts +1 -2
- package/dist/layout/options.d.ts.map +1 -1
- package/dist/layout/options.js.map +1 -1
- package/dist/layout/preflight.d.ts +32 -0
- package/dist/layout/preflight.d.ts.map +1 -0
- package/dist/layout/preflight.js +69 -0
- package/dist/layout/preflight.js.map +1 -0
- package/dist/layout/qrRender.d.ts.map +1 -1
- package/dist/layout/qrRender.js +11 -10
- package/dist/layout/qrRender.js.map +1 -1
- package/dist/layout/renderDrawing.d.ts +28 -17
- package/dist/layout/renderDrawing.d.ts.map +1 -1
- package/dist/layout/renderDrawing.js +107 -88
- package/dist/layout/renderDrawing.js.map +1 -1
- package/dist/layout/renderLayout.d.ts +25 -0
- package/dist/layout/renderLayout.d.ts.map +1 -0
- package/dist/layout/renderLayout.js +315 -0
- package/dist/layout/renderLayout.js.map +1 -0
- package/dist/layout/renderTemplateSheet.d.ts +99 -0
- package/dist/layout/renderTemplateSheet.d.ts.map +1 -0
- package/dist/layout/renderTemplateSheet.js +296 -0
- package/dist/layout/renderTemplateSheet.js.map +1 -0
- package/dist/layout/renderUtils.d.ts +19 -0
- package/dist/layout/renderUtils.d.ts.map +1 -1
- package/dist/layout/renderUtils.js +47 -4
- package/dist/layout/renderUtils.js.map +1 -1
- package/dist/layout/sectionDefs.d.ts +65 -0
- package/dist/layout/sectionDefs.d.ts.map +1 -0
- package/dist/layout/sectionDefs.js +88 -0
- package/dist/layout/sectionDefs.js.map +1 -0
- package/dist/layout/slabModelView.d.ts +34 -0
- package/dist/layout/slabModelView.d.ts.map +1 -0
- package/dist/layout/slabModelView.js +175 -0
- package/dist/layout/slabModelView.js.map +1 -0
- package/dist/layout/templateVariables.d.ts +1 -1
- package/dist/layout/templateVariables.d.ts.map +1 -1
- package/dist/layout/templateVariables.js +21 -9
- package/dist/layout/templateVariables.js.map +1 -1
- package/dist/layout/types.d.ts +164 -83
- package/dist/layout/types.d.ts.map +1 -1
- package/dist/layout/types.js.map +1 -1
- package/dist/layout/validation.d.ts.map +1 -1
- package/dist/layout/validation.js +78 -33
- package/dist/layout/validation.js.map +1 -1
- package/dist/layout/viewportPrep.d.ts +8 -6
- package/dist/layout/viewportPrep.d.ts.map +1 -1
- package/dist/layout/viewportPrep.js +35 -23
- package/dist/layout/viewportPrep.js.map +1 -1
- package/dist/layout/viewportRender.d.ts +9 -7
- package/dist/layout/viewportRender.d.ts.map +1 -1
- package/dist/layout/viewportRender.js +93 -126
- package/dist/layout/viewportRender.js.map +1 -1
- package/dist/layout/viewportUtils.d.ts +20 -0
- package/dist/layout/viewportUtils.d.ts.map +1 -1
- package/dist/layout/viewportUtils.js +107 -4
- package/dist/layout/viewportUtils.js.map +1 -1
- package/dist/printToPdf.d.ts +7 -1
- package/dist/printToPdf.d.ts.map +1 -1
- package/dist/printToPdf.js +81 -14
- package/dist/printToPdf.js.map +1 -1
- package/dist/printToSvg.d.ts.map +1 -1
- package/dist/printToSvg.js +7 -3
- package/dist/printToSvg.js.map +1 -1
- package/dist/schemaUtils.d.ts +9 -0
- package/dist/schemaUtils.d.ts.map +1 -0
- package/dist/schemaUtils.js +14 -0
- package/dist/schemaUtils.js.map +1 -0
- package/dist/templates/default-template.json +30 -8
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -3
- package/src/index.ts +4 -0
- package/src/layout/analyzeTemplate.ts +21 -19
- package/src/layout/classClosure.ts +142 -0
- package/src/layout/clipUtils.ts +65 -6
- package/src/layout/filters.ts +31 -3
- package/src/layout/index.ts +61 -571
- package/src/layout/itemBuilders.ts +20 -5
- package/src/layout/labelsRender.ts +23 -40
- package/src/layout/legendRender.ts +64 -84
- package/src/layout/metadata.ts +26 -5
- package/src/layout/model.ts +21 -66
- package/src/layout/options.ts +1 -2
- package/src/layout/preflight.ts +96 -0
- package/src/layout/qrRender.ts +11 -10
- package/src/layout/renderDrawing.ts +132 -110
- package/src/layout/renderLayout.ts +483 -0
- package/src/layout/renderTemplateSheet.ts +435 -0
- package/src/layout/renderUtils.ts +53 -4
- package/src/layout/sectionDefs.ts +131 -0
- package/src/layout/slabModelView.ts +196 -0
- package/src/layout/templateVariables.ts +25 -9
- package/src/layout/types.ts +160 -70
- package/src/layout/validation.ts +98 -32
- package/src/layout/viewportPrep.ts +47 -29
- package/src/layout/viewportRender.ts +114 -141
- package/src/layout/viewportUtils.ts +118 -5
- package/src/printToPdf.ts +84 -15
- package/src/printToSvg.ts +7 -3
- package/src/schemaUtils.ts +13 -0
- package/src/templates/default-template.json +30 -8
- package/src/types.ts +12 -2
- package/templates/default-a0-landscape.json +171 -66
- package/templates/default-a0-portrait.json +159 -60
- package/templates/default-a1-landscape.json +135 -48
- package/templates/default-a1-portrait.json +123 -42
- package/templates/default-a3-landscape.json +87 -24
- package/templates/default-a3-portrait.json +99 -30
- package/templates/default-a4-landscape.json +75 -18
- package/templates/default-a4-portrait.json +75 -18
- package/templates/llm-authoring-guide.md +247 -0
- package/templates/template-schema.json +295 -120
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "twinfinity-print-template-v2",
|
|
4
4
|
"title": "Twinfinity Print Template",
|
|
5
5
|
"description": "Layout template for Twinfinity BIM section printing. Defines page size, viewports, legends, labels, and decorative elements for PDF/SVG output.",
|
|
6
|
-
"markdownDescription": "# Twinfinity Print Template\n\nLayout template for automated BIM drawing generation.\n\n## Template Structure\n\n- **`page`** — Page dimensions (A4, A3, custom)\n- **`styles`** — Named text styles (body, title, etc.)\n- **`
|
|
6
|
+
"markdownDescription": "# Twinfinity Print Template\n\nLayout template for automated BIM drawing generation.\n\n## Template Structure\n\n- **`page`** — Page dimensions (A4, A3, custom)\n- **`styles`** — Named text styles (body, title, etc.)\n- **`resources`** — Reusable images/logos\n- **`presets`** — Reusable class filters and scale lists\n- **`elements`** — All content on the page\n\n## Available Elements\n\n| Element | Purpose |\n|---------|--------|\n| `viewport` | BIM section geometry at a position/scale |\n| `text` | Static or templated text |\n| `labels` | Per-item labels (room names, etc.) |\n| `legend` | Table with item properties and colors |\n| `scaleBar` | Graphical scale indicator |\n| `qr` | QR codes for navigation/anchoring |\n| `image` | Logo or decorative image |\n| `line`, `rect`, `circle` | Basic shapes |\n| `polyline`, `polygon` | Custom vector shapes |\n| `group` | Container with transforms/clipping |\n\n## Sections\n\nEach viewport declares its own cut: `cutHeight` (+ `depth`) for horizontal plans, `planeNormal` + `planePosition` for elevations/sections. All model-space values are metres. Up to 8 viewports per template.\n\n## Filtering & Highlighting\n\n- **`includeClasses`** — Which IFC classes to render\n- **`clip`** — Crop viewport to specific areas\n- **`highlight`** — Custom stroke/fill for matching items\n- **`fills`** — Filled polygons for spaces or other classes\n\n## Template Variables\n\nUse `{{variable}}` syntax in text elements:\n- `{{viewport.<id>.scaleText}}` — e.g. \"1:100\"\n- `{{vars.<name>}}` — declared template variables\n- `{{BIP.spacename}}` — Property values in labels\n\nNumeric placeholders accept format filters: `{{BIP.area | round:1}}`, `{{BIP.area | fixed:2}}`.",
|
|
7
7
|
"type": "object",
|
|
8
8
|
"required": ["page", "elements"],
|
|
9
9
|
"additionalProperties": false,
|
|
@@ -106,11 +106,11 @@
|
|
|
106
106
|
"description": "Named text styles (body, title, etc.).",
|
|
107
107
|
"markdownDescription": "Named text styles referenced by elements.\n\n**Define reusable styles:**\n```json\n\"styles\": {\n \"body\": { \"fontFamily\": \"Arial\", \"fontSizeMm\": 3.5, \"color\": \"#000000\" },\n \"title\": { \"fontFamily\": \"Arial\", \"fontSizeMm\": 8, \"fontWeight\": \"bold\" },\n \"small\": { \"fontFamily\": \"Arial\", \"fontSizeMm\": 2.5, \"color\": \"#666666\" }\n}\n```\n\n**Reference in elements:**\n```json\n{ \"kind\": \"text\", \"textStyle\": \"body\", \"text\": \"Hello\" }\n```"
|
|
108
108
|
},
|
|
109
|
-
"
|
|
109
|
+
"resources": {
|
|
110
110
|
"type": "array",
|
|
111
|
-
"description": "Reusable
|
|
112
|
-
"markdownDescription": "Reusable
|
|
113
|
-
"items": { "$ref": "#/$defs/
|
|
111
|
+
"description": "Reusable resources (images, SVG logos) referenced by elements via resourceId.",
|
|
112
|
+
"markdownDescription": "Reusable resources (images, SVG logos, icons).\n\n**Define resources:**\n```json\n\"resources\": [\n {\n \"id\": \"logo-main\",\n \"src\": \"https://example.com/logo.svg\"\n },\n {\n \"id\": \"north-arrow\",\n \"src\": \"data:image/svg+xml;base64,...\"\n }\n]\n```\n\n**Reference in elements:**\n```json\n{ \"kind\": \"image\", \"resourceId\": \"logo-main\", \"...\" }\n{ \"northArrow\": { \"resourceId\": \"north-arrow\" } }\n```\n\n**⚠️ Remote URLs require:** `\"allowRemoteResources\": true`",
|
|
113
|
+
"items": { "$ref": "#/$defs/resource" }
|
|
114
114
|
},
|
|
115
115
|
"elements": {
|
|
116
116
|
"type": "array",
|
|
@@ -123,11 +123,59 @@
|
|
|
123
123
|
"description": "Reusable presets for class filters and scales.",
|
|
124
124
|
"markdownDescription": "Reusable presets for class filters and scales.\n\n**Define presets:**\n```json\n\"presets\": {\n \"includeClasses\": {\n \"defaultBuilding\": [\"space\", \"walls\", \"windows\", \"doors\", \"columns\", \"stairs\", \"floor\"],\n \"structureOnly\": [\"walls\", \"columns\", \"beam\", \"floor\"]\n },\n \"scales\": {\n \"default\": { \"preferredScales\": [50, 100, 200, 500, 1000] },\n \"detail\": { \"preferredScales\": [2, 5, 10, 20, 50] }\n }\n}\n```\n\n**Reference in viewports:**\n```json\n\"includeClasses\": { \"preset\": \"defaultBuilding\" },\n\"scalePreset\": \"default\"\n```"
|
|
125
125
|
},
|
|
126
|
-
"
|
|
126
|
+
"variables": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"description": "Declared template variables (parameters). Names must be simple identifiers ([A-Za-z_][A-Za-z0-9_]*) — they are referenced as {{vars.<name>}}. Values are supplied at render time via options.variables, with the declared defaults as fail-safe fallback.",
|
|
129
|
+
"markdownDescription": "Declared template variables (parameters).\n\n**Names must be simple identifiers** (`[A-Za-z_][A-Za-z0-9_]*`) — they are referenced as `{{vars.<name>}}`, so dashes/dots would collide with the placeholder syntax.\n\n**Values at render time:** `renderDrawing({ ..., options: { variables: { name: value } } })` — missing values fall back to each variable's `default`.\n\n**Example:**\n```json\n\"variables\": {\n \"title\": { \"type\": \"string\", \"default\": \"Floor plan\", \"label\": \"Title\" },\n \"showLegend\": { \"type\": \"boolean\", \"default\": true, \"label\": \"Show legend\" }\n}\n```",
|
|
130
|
+
"propertyNames": { "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
|
|
131
|
+
"additionalProperties": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"required": ["type", "default"],
|
|
134
|
+
"additionalProperties": false,
|
|
135
|
+
"properties": {
|
|
136
|
+
"type": {
|
|
137
|
+
"enum": ["string", "number", "boolean", "array"],
|
|
138
|
+
"description": "Variable type. Determines validation and UI control type."
|
|
139
|
+
},
|
|
140
|
+
"default": {
|
|
141
|
+
"description": "Default value. REQUIRED — ensures the template always works without user input. Must match the declared type."
|
|
142
|
+
},
|
|
143
|
+
"label": {
|
|
144
|
+
"type": "string",
|
|
145
|
+
"description": "Human-readable label for UI generation. Defaults to the variable name."
|
|
146
|
+
},
|
|
147
|
+
"description": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"description": "Description/help text for UI generation."
|
|
150
|
+
},
|
|
151
|
+
"format": {
|
|
152
|
+
"enum": ["color", "email", "url", "date"],
|
|
153
|
+
"description": "Semantic format hint for UI generation (string variables): color picker, email/url/date inputs."
|
|
154
|
+
},
|
|
155
|
+
"min": { "type": "number", "description": "Minimum value (number variables)." },
|
|
156
|
+
"max": { "type": "number", "description": "Maximum value (number variables)." },
|
|
157
|
+
"step": { "type": "number", "description": "Step size for UI controls (number variables)." },
|
|
158
|
+
"minLength": { "type": "number", "description": "Minimum length (string variables)." },
|
|
159
|
+
"maxLength": { "type": "number", "description": "Maximum length (string variables)." },
|
|
160
|
+
"pattern": { "type": "string", "description": "Regex the value must match (string variables)." },
|
|
161
|
+
"enum": { "type": "array", "description": "Allowed values; renders as a dropdown." },
|
|
162
|
+
"items": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"description": "Item constraints for array variables.",
|
|
165
|
+
"additionalProperties": false,
|
|
166
|
+
"properties": {
|
|
167
|
+
"type": { "enum": ["string", "number"] },
|
|
168
|
+
"enum": { "type": "array" }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"allowRemoteResources": {
|
|
127
175
|
"type": "boolean",
|
|
128
176
|
"default": false,
|
|
129
|
-
"description": "Allow fetching remote
|
|
130
|
-
"markdownDescription": "Allow fetching remote
|
|
177
|
+
"description": "Allow fetching remote resources from https:// URLs. Required for remote images/logos.",
|
|
178
|
+
"markdownDescription": "Allow fetching remote resources from `https://` URLs.\n\n**Default:** `false` (only local/data URIs allowed)\n\n**Set to `true` when:**\n- Resources use `https://` URLs\n- Loading logos from a CDN\n- Fetching remote images\n\n**Example:**\n```json\n\"allowRemoteResources\": true,\n\"resources\": [\n { \"id\": \"logo\", \"src\": \"https://example.com/logo.svg\" }\n]\n```\n\n**⚠️ Security note:** Only enable for trusted URLs."
|
|
131
179
|
}
|
|
132
180
|
},
|
|
133
181
|
|
|
@@ -265,7 +313,7 @@
|
|
|
265
313
|
"description": "Page height in millimeters.",
|
|
266
314
|
"markdownDescription": "Page height in millimeters.\n\nCommon values: `297` (A4 portrait / A3 landscape), `210` (A4 landscape), `420` (A3 portrait / A2 landscape), `594` (A1 landscape)"
|
|
267
315
|
},
|
|
268
|
-
"marginMm": { "type": "number", "default":
|
|
316
|
+
"marginMm": { "type": "number", "default": 0, "description": "Page margin in mm. Used by legend auto-placement (anchor offsets); other elements position themselves with absolute coordinates." },
|
|
269
317
|
"backgroundColor": { "$ref": "#/$defs/cssColor", "default": "#ffffff", "description": "Page background color." }
|
|
270
318
|
}
|
|
271
319
|
},
|
|
@@ -296,17 +344,18 @@
|
|
|
296
344
|
}
|
|
297
345
|
},
|
|
298
346
|
|
|
299
|
-
"
|
|
347
|
+
"resource": {
|
|
300
348
|
"type": "object",
|
|
301
|
-
"description": "A reusable
|
|
349
|
+
"description": "A reusable resource (image, SVG) that can be referenced by image elements. Needs src or content.",
|
|
302
350
|
"required": ["id"],
|
|
351
|
+
"anyOf": [{ "required": ["src"] }, { "required": ["content"] }],
|
|
303
352
|
"additionalProperties": false,
|
|
304
353
|
"properties": {
|
|
305
|
-
"id": { "type": "string", "description": "Unique
|
|
354
|
+
"id": { "type": "string", "description": "Unique resource ID, referenced by image elements via resourceId." },
|
|
306
355
|
"src": {
|
|
307
356
|
"type": "string",
|
|
308
|
-
"description": "URL or data URI for the
|
|
309
|
-
"markdownDescription": "URL or data URI for the
|
|
357
|
+
"description": "URL or data URI for the resource. Remote URLs require allowRemoteResources: true.",
|
|
358
|
+
"markdownDescription": "URL or data URI for the resource.\n\n- **Data URI**: `data:image/svg+xml;base64,PHN2Zy...` (self-contained, no network)\n- **Remote URL**: `https://example.com/logo.svg` (requires `allowRemoteResources: true`)",
|
|
310
359
|
"examples": [
|
|
311
360
|
"data:image/svg+xml;base64,PHN2Zy...",
|
|
312
361
|
"https://example.com/logo.svg"
|
|
@@ -379,7 +428,7 @@
|
|
|
379
428
|
"clipConfig": {
|
|
380
429
|
"type": "object",
|
|
381
430
|
"description": "Clip the viewport to show only the area around matching BIM items (e.g. a specific tenant's spaces).",
|
|
382
|
-
"markdownDescription": "Clip the viewport to show only the area around matching BIM items.\n\nUse `class` + `where` to select which items define the clip boundary. The viewport is cropped to the bounding box of those items, optionally expanded by `
|
|
431
|
+
"markdownDescription": "Clip the viewport to show only the area around matching BIM items.\n\nUse `class` + `where` to select which items define the clip boundary. The viewport is cropped to the bounding box of those items, optionally expanded by `expandBy`.\n\n**Example — clip to a tenant's spaces:**\n```json\n\"clip\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"expandBy\": 1.5\n}\n```",
|
|
383
432
|
"required": ["where"],
|
|
384
433
|
"additionalProperties": false,
|
|
385
434
|
"properties": {
|
|
@@ -391,34 +440,39 @@
|
|
|
391
440
|
"description": "IFC class filter (e.g. \"space\"). Only items of this class are used for the clip boundary."
|
|
392
441
|
},
|
|
393
442
|
"where": { "$ref": "#/$defs/whereCondition" },
|
|
394
|
-
"
|
|
443
|
+
"expandBy": {
|
|
395
444
|
"type": "number",
|
|
396
445
|
"default": 0,
|
|
397
446
|
"description": "Expand the clip boundary outward by this many meters. Use 0.5–1.5 to show surrounding context.",
|
|
398
|
-
"markdownDescription": "Expand the clip boundary outward by this many meters.\n\n**Purpose:** Show surrounding context (adjacent walls, neighboring rooms) while keeping the clip focused on the target area.\n\n**How it works:**\n1. The original clip polygon is calculated from matching items\n2. The polygon is expanded outward by `
|
|
447
|
+
"markdownDescription": "Expand the clip boundary outward by this many meters.\n\n**Purpose:** Show surrounding context (adjacent walls, neighboring rooms) while keeping the clip focused on the target area.\n\n**How it works:**\n1. The original clip polygon is calculated from matching items\n2. The polygon is expanded outward by `expandBy` meters (morphological dilation)\n3. Geometry **paths** are clipped to the **expanded** boundary (shows more context)\n4. Fill filtering uses the **original** (unexpanded) boundary (controlled by `matchClipFilter`)\n\n**Common values:**\n- `0.5` — Small context (0.5m around clip area)\n- `1.5` — Medium context (1.5m around clip area) **← Recommended**\n- `3.0` — Large context (3m around clip area)\n- `0` — No expansion (strict clip to exact boundary)\n\n**Example:**\nClipping to a tenant's spaces with 1.5m surrounding context:\n```json\n\"clip\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"expandBy\": 1.5\n}\n```\n\n**⚠️ Note:** When using `expandBy` with fills, set `matchClipFilter: true` on fill rules to prevent adjacent spaces from being filled."
|
|
399
448
|
},
|
|
400
449
|
"clipLabels": {
|
|
401
450
|
"type": "boolean",
|
|
402
451
|
"default": false,
|
|
403
452
|
"description": "Also clip labels to the clip boundary (hide labels outside the clip)."
|
|
404
453
|
},
|
|
405
|
-
"
|
|
454
|
+
"color": {
|
|
406
455
|
"$ref": "#/$defs/cssColor",
|
|
407
456
|
"default": "#000000",
|
|
408
|
-
"description": "Border color around the clipped area. Set to \"none\" to hide the clip border."
|
|
457
|
+
"description": "Border color around the clipped area (same vocabulary as lineStyles). Set to \"none\" to hide the clip border."
|
|
409
458
|
},
|
|
410
|
-
"
|
|
459
|
+
"widthMm": {
|
|
411
460
|
"type": "number",
|
|
412
461
|
"default": 0.5,
|
|
413
462
|
"description": "Border width in mm around the clipped area."
|
|
414
463
|
},
|
|
415
|
-
"
|
|
464
|
+
"opacity": {
|
|
416
465
|
"type": "number",
|
|
417
466
|
"default": 1,
|
|
418
467
|
"minimum": 0,
|
|
419
468
|
"maximum": 1,
|
|
420
469
|
"description": "Border opacity (0 = invisible, 1 = fully opaque)."
|
|
421
470
|
},
|
|
471
|
+
"dash": {
|
|
472
|
+
"type": "string",
|
|
473
|
+
"description": "SVG stroke-dasharray for the clip border (e.g. \"4 2\"). Omit for a solid border.",
|
|
474
|
+
"examples": ["4 2", "2 1", "6 2 1 2"]
|
|
475
|
+
},
|
|
422
476
|
"fill": {
|
|
423
477
|
"$ref": "#/$defs/cssColor",
|
|
424
478
|
"default": "none",
|
|
@@ -437,7 +491,7 @@
|
|
|
437
491
|
"highlightConfig": {
|
|
438
492
|
"type": "object",
|
|
439
493
|
"description": "Highlight matching BIM items with custom stroke/fill colors (e.g. highlight a tenant's spaces in yellow).",
|
|
440
|
-
"markdownDescription": "Highlight matching BIM items with custom stroke/fill colors.\n\nUse `class` + `where` to select which items get highlighted. Matching items are drawn with the specified stroke and fill colors.\n\n**Example — highlight tenant spaces in yellow:**\n```json\n\"highlight\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"
|
|
494
|
+
"markdownDescription": "Highlight matching BIM items with custom stroke/fill colors.\n\nUse `class` + `where` to select which items get highlighted. Matching items are drawn with the specified stroke and fill colors.\n\n**Example — highlight tenant spaces in yellow:**\n```json\n\"highlight\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"color\": \"#f00\",\n \"fill\": \"#ff0\",\n \"fillOpacity\": 1\n}\n```\n\n**Example — highlight spaces that appear in both plan and section:**\n```json\n\"highlight\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"intersectsViewport\": \"main\",\n \"color\": \"#f00\",\n \"fill\": \"#ff0\",\n \"fillOpacity\": 1\n}\n```",
|
|
441
495
|
"required": ["where"],
|
|
442
496
|
"additionalProperties": false,
|
|
443
497
|
"properties": {
|
|
@@ -454,22 +508,27 @@
|
|
|
454
508
|
"description": "Viewport ID to intersect with. Only highlights items that appear in BOTH this viewport and the referenced viewport (i.e., their geometry intersects both cutting planes).",
|
|
455
509
|
"markdownDescription": "Viewport ID to intersect with.\n\nOnly highlights items that appear in **both** this viewport and the referenced viewport. Useful for highlighting spaces at a specific level in a section view.\n\n**Example:** In a vertical section, highlight only the spaces that also appear in the plan view at Y=3:\n```json\n\"intersectsViewport\": \"plan\"\n```"
|
|
456
510
|
},
|
|
457
|
-
"
|
|
511
|
+
"color": {
|
|
458
512
|
"$ref": "#/$defs/cssColor",
|
|
459
513
|
"default": "#ff0000",
|
|
460
|
-
"description": "
|
|
514
|
+
"description": "Outline color for highlighted items (same vocabulary as lineStyles)."
|
|
461
515
|
},
|
|
462
|
-
"
|
|
516
|
+
"widthMm": {
|
|
463
517
|
"type": "number",
|
|
464
518
|
"default": 0.5,
|
|
465
|
-
"description": "
|
|
519
|
+
"description": "Outline width in mm for highlighted items."
|
|
466
520
|
},
|
|
467
|
-
"
|
|
521
|
+
"opacity": {
|
|
468
522
|
"type": "number",
|
|
469
523
|
"default": 1,
|
|
470
524
|
"minimum": 0,
|
|
471
525
|
"maximum": 1,
|
|
472
|
-
"description": "
|
|
526
|
+
"description": "Outline opacity for highlighted items."
|
|
527
|
+
},
|
|
528
|
+
"dash": {
|
|
529
|
+
"type": "string",
|
|
530
|
+
"description": "SVG stroke-dasharray for highlighted outlines (e.g. \"4 2\"). Omit for solid.",
|
|
531
|
+
"examples": ["4 2", "2 1", "6 2 1 2"]
|
|
473
532
|
},
|
|
474
533
|
"fill": {
|
|
475
534
|
"$ref": "#/$defs/cssColor",
|
|
@@ -509,18 +568,27 @@
|
|
|
509
568
|
|
|
510
569
|
"viewportLineStyles": {
|
|
511
570
|
"type": "object",
|
|
512
|
-
"description": "Per-category line styles for a viewport. Resolution order: category-specific → default → built-in defaults.",
|
|
513
|
-
"markdownDescription": "Per-category line styles for a viewport.\n\n**Resolution order:** category-specific → `default` → built-in defaults\n\n**Line categories:**\n\n| Category | Description | Typical Style |\n|----------|-------------|---------------|\n| `cutLines` | Where plane cuts geometry | Thick, solid black |\n| `visibleLines` | Visible edges below plane | Medium, solid black |\n| `hiddenLines` | Hidden behind geometry | Thin, dashed gray |\n| `
|
|
571
|
+
"description": "Per-category line styles for a viewport. Resolution order: category-specific → defaultVisibleLines/defaultHiddenLines (visibility group) → built-in category defaults → default → built-in defaults.",
|
|
572
|
+
"markdownDescription": "Per-category line styles for a viewport.\n\n**Resolution order (strongest first):** category-specific → `defaultVisibleLines`/`defaultHiddenLines` (the category's visibility group) → built-in category defaults → `default` → built-in defaults\n\n**Visibility groups:** `defaultVisibleLines` applies to `cutLines`, `visibleLines`, `silhouettesVisible`, `featureEdges`, `outlineVisible`. `defaultHiddenLines` applies to `hiddenLines`, `silhouettesHidden`, `outlineHidden`. `stairArrows` is an annotation and belongs to neither group.\n\n**Line categories:**\n\n| Category | Description | Typical Style |\n|----------|-------------|---------------|\n| `cutLines` | Where plane cuts geometry | Thick, solid black |\n| `visibleLines` | Visible edges below plane | Medium, solid black |\n| `hiddenLines` | Hidden behind geometry | Thin, dashed gray |\n| `silhouettesVisible` | Visible outline silhouettes | Medium, solid black |\n| `silhouettesHidden` | Occluded outline silhouettes | Thin, dashed gray |\n| `featureEdges` | Sharp edges (angle-based) | Thin, solid gray |\n| `stairArrows` | Direction arrows on stairs | Medium, solid black |\n| `outlineVisible` | Visible outline edges | Medium, solid black |\n| `outlineHidden` | Hidden outline edges | Thin, dashed gray |\n\n**Example — group defaults with one override:**\n```json\n\"lineStyles\": {\n \"defaultVisibleLines\": { \"widthMm\": 0.1, \"color\": \"#000000\" },\n \"defaultHiddenLines\": { \"widthMm\": 0.05, \"color\": \"#9ca3af\", \"dash\": \"2 1\" },\n \"cutLines\": { \"widthMm\": 0.2 }\n}\n```\n\n**Example — Hide specific categories:**\n```json\n\"lineStyles\": {\n \"default\": { \"widthMm\": 0.01, \"color\": \"#000000\" },\n \"hiddenLines\": { \"enabled\": false },\n \"featureEdges\": { \"enabled\": false }\n}\n```\n\n**⚠️ Performance tip:** Set `\"enabled\": false` for categories you don't need to speed up rendering.",
|
|
514
573
|
"additionalProperties": false,
|
|
515
574
|
"properties": {
|
|
516
575
|
"default": {
|
|
517
576
|
"$ref": "#/$defs/viewportLineStyle",
|
|
518
577
|
"description": "Fallback style for any category not explicitly listed."
|
|
519
578
|
},
|
|
579
|
+
"defaultVisibleLines": {
|
|
580
|
+
"$ref": "#/$defs/viewportLineStyle",
|
|
581
|
+
"description": "Group default for all visible-class categories (cutLines, visibleLines, silhouettesVisible, featureEdges, outlineVisible). Overridden by the specific category key."
|
|
582
|
+
},
|
|
583
|
+
"defaultHiddenLines": {
|
|
584
|
+
"$ref": "#/$defs/viewportLineStyle",
|
|
585
|
+
"description": "Group default for all hidden-class categories (hiddenLines, silhouettesHidden, outlineHidden). Overridden by the specific category key."
|
|
586
|
+
},
|
|
520
587
|
"cutLines": { "$ref": "#/$defs/viewportLineStyle", "description": "Lines where the section plane cuts through geometry." },
|
|
521
588
|
"visibleLines": { "$ref": "#/$defs/viewportLineStyle", "description": "Visible edges below the cut plane." },
|
|
522
589
|
"hiddenLines": { "$ref": "#/$defs/viewportLineStyle", "description": "Edges hidden behind other geometry. Typically dashed and lighter." },
|
|
523
|
-
"
|
|
590
|
+
"silhouettesVisible": { "$ref": "#/$defs/viewportLineStyle", "description": "Visible outline silhouettes of objects." },
|
|
591
|
+
"silhouettesHidden": { "$ref": "#/$defs/viewportLineStyle", "description": "Occluded outline silhouettes — dashed by default, like hiddenLines." },
|
|
524
592
|
"featureEdges": { "$ref": "#/$defs/viewportLineStyle", "description": "Sharp edges detected by angle threshold." },
|
|
525
593
|
"stairArrows": { "$ref": "#/$defs/viewportLineStyle", "description": "Directional arrows on stairs." },
|
|
526
594
|
"outlineVisible": { "$ref": "#/$defs/viewportLineStyle", "description": "Visible outline edges." },
|
|
@@ -543,10 +611,10 @@
|
|
|
543
611
|
"default": 0.25,
|
|
544
612
|
"description": "Border width in mm."
|
|
545
613
|
},
|
|
546
|
-
"
|
|
547
|
-
"type": "
|
|
548
|
-
"
|
|
549
|
-
"
|
|
614
|
+
"dash": {
|
|
615
|
+
"type": "string",
|
|
616
|
+
"description": "SVG stroke-dasharray in mm, e.g. \"4 2\".",
|
|
617
|
+
"examples": ["4 2", "2 1", "6 2 2 2"]
|
|
550
618
|
}
|
|
551
619
|
}
|
|
552
620
|
},
|
|
@@ -583,7 +651,13 @@
|
|
|
583
651
|
"description": "Text alignment within the column."
|
|
584
652
|
},
|
|
585
653
|
"minWidthMm": { "type": "number", "description": "Minimum column width in mm." },
|
|
586
|
-
"maxWidthMm": { "type": "number", "description": "Maximum column width in mm." }
|
|
654
|
+
"maxWidthMm": { "type": "number", "description": "Maximum column width in mm." },
|
|
655
|
+
"summary": {
|
|
656
|
+
"type": "boolean",
|
|
657
|
+
"default": false,
|
|
658
|
+
"description": "Include this column in the legend's summary (totals) row. Only meaningful for numerical columns.",
|
|
659
|
+
"markdownDescription": "Include this column in the legend's summary (totals) row.\n\nWhen `true`, the summary row shows the **sum** of all values in this column. Only meaningful for numerical columns.\n\nRequires the legend's `summary.enabled: true`.\n\n**Example:**\n```json\n{ \"id\": \"area\", \"label\": \"Area\", \"property\": \"BIP.area\", \"summary\": true }\n```"
|
|
660
|
+
}
|
|
587
661
|
}
|
|
588
662
|
},
|
|
589
663
|
|
|
@@ -672,7 +746,7 @@
|
|
|
672
746
|
},
|
|
673
747
|
{
|
|
674
748
|
"label": "image",
|
|
675
|
-
"description": "Image from
|
|
749
|
+
"description": "Image from a resource",
|
|
676
750
|
"body": {
|
|
677
751
|
"kind": "image",
|
|
678
752
|
"id": "${1:logo}",
|
|
@@ -680,7 +754,7 @@
|
|
|
680
754
|
"yMm": "${3:10}",
|
|
681
755
|
"widthMm": "${4:80}",
|
|
682
756
|
"heightMm": "${5:20}",
|
|
683
|
-
"
|
|
757
|
+
"resourceId": "${6:logo-main}",
|
|
684
758
|
"fit": "contain"
|
|
685
759
|
}
|
|
686
760
|
},
|
|
@@ -793,10 +867,10 @@
|
|
|
793
867
|
},
|
|
794
868
|
"align": {
|
|
795
869
|
"type": "string",
|
|
796
|
-
"enum": ["center", "topLeft"
|
|
870
|
+
"enum": ["center", "topLeft"],
|
|
797
871
|
"default": "center",
|
|
798
872
|
"description": "How the content is aligned within the viewport.",
|
|
799
|
-
"markdownDescription": "How the drawing content is aligned within the viewport.\n\n- **`center`** (default) — Center the drawing in the viewport\n - Best for: Most cases, balanced composition\n - Drawing is centered both horizontally and vertically\n\n- **`topLeft`** — Align to top-left corner\n - Best for: When you want consistent positioning\n - Drawing starts at viewport's top-left corner
|
|
873
|
+
"markdownDescription": "How the drawing content is aligned within the viewport.\n\n- **`center`** (default) — Center the drawing in the viewport\n - Best for: Most cases, balanced composition\n - Drawing is centered both horizontally and vertically\n\n- **`topLeft`** — Align to top-left corner\n - Best for: When you want consistent positioning\n - Drawing starts at viewport's top-left corner"
|
|
800
874
|
},
|
|
801
875
|
"rotationDeg": {
|
|
802
876
|
"type": "number",
|
|
@@ -808,9 +882,44 @@
|
|
|
808
882
|
"oneOf": [
|
|
809
883
|
{
|
|
810
884
|
"type": "array",
|
|
811
|
-
"items": {
|
|
812
|
-
|
|
885
|
+
"items": {
|
|
886
|
+
"oneOf": [
|
|
887
|
+
{ "$ref": "#/$defs/ifcClassName" },
|
|
888
|
+
{
|
|
889
|
+
"type": "object",
|
|
890
|
+
"required": ["class"],
|
|
891
|
+
"additionalProperties": false,
|
|
892
|
+
"properties": {
|
|
893
|
+
"class": {
|
|
894
|
+
"oneOf": [
|
|
895
|
+
{ "$ref": "#/$defs/ifcClassName" },
|
|
896
|
+
{ "type": "array", "items": { "$ref": "#/$defs/ifcClassName" } }
|
|
897
|
+
],
|
|
898
|
+
"description": "IFC class name(s) this conditional entry applies to."
|
|
899
|
+
},
|
|
900
|
+
"where": {
|
|
901
|
+
"$ref": "#/$defs/whereCondition",
|
|
902
|
+
"description": "Only include items of this class that match the condition."
|
|
903
|
+
},
|
|
904
|
+
"occludes": {
|
|
905
|
+
"type": "boolean",
|
|
906
|
+
"default": true,
|
|
907
|
+
"description": "When false, this class's geometry never hides other lines (it stays out of the occlusion computation). Use for schematic classes like pipes that must not erase the architecture behind them.",
|
|
908
|
+
"markdownDescription": "When `false`, this class's geometry never hides other lines — it stays out of the occlusion computation.\n\nUse for schematic classes like pipes that must not erase the architecture behind them. Also a major performance win for dense curved classes."
|
|
909
|
+
},
|
|
910
|
+
"classify": {
|
|
911
|
+
"type": "boolean",
|
|
912
|
+
"default": true,
|
|
913
|
+
"description": "When false, this class's own lines skip hidden-line testing and draw as-is (always visible). Big performance win for dense classes like pipes; combine with occludes:false for fully schematic linework.",
|
|
914
|
+
"markdownDescription": "When `false`, this class's own lines skip hidden-line testing and draw as-is (always visible).\n\nBig performance win for dense classes like pipes.\n\n```json\n{ \"class\": \"flow\", \"occludes\": false, \"classify\": false }\n```"
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
]
|
|
919
|
+
},
|
|
920
|
+
"description": "Class names and/or conditional { class, where } entries to include."
|
|
813
921
|
},
|
|
922
|
+
{ "$ref": "#/$defs/ifcClassName" },
|
|
814
923
|
{
|
|
815
924
|
"type": "object",
|
|
816
925
|
"required": ["preset"],
|
|
@@ -819,24 +928,26 @@
|
|
|
819
928
|
"preset": {
|
|
820
929
|
"type": "string",
|
|
821
930
|
"description": "Name of an includeClasses preset from presets.includeClasses."
|
|
931
|
+
},
|
|
932
|
+
"add": {
|
|
933
|
+
"type": "array",
|
|
934
|
+
"items": { "$ref": "#/$defs/ifcClassName" },
|
|
935
|
+
"description": "Classes to include in addition to the preset."
|
|
936
|
+
},
|
|
937
|
+
"remove": {
|
|
938
|
+
"type": "array",
|
|
939
|
+
"items": { "$ref": "#/$defs/ifcClassName" },
|
|
940
|
+
"description": "Classes to exclude from the preset."
|
|
822
941
|
}
|
|
823
942
|
}
|
|
824
943
|
}
|
|
825
944
|
],
|
|
826
|
-
"description": "Which IFC classes to render in this viewport.
|
|
945
|
+
"description": "Which IFC classes to render in this viewport. A single class, an array of classes and/or { class, where } conditions, or a preset reference (optionally with add/remove).",
|
|
827
946
|
"markdownDescription": "Which IFC classes to render in this viewport.\n\n**Option 1: Inline array** (simple, good for unique viewports)\n```json\n\"includeClasses\": [\"space\", \"walls\", \"windows\", \"doors\"]\n```\n\n**Option 2: Preset reference** (reusable, good for multiple viewports)\n```json\n\"includeClasses\": { \"preset\": \"defaultBuilding\" }\n```\nReferences `presets.includeClasses.defaultBuilding` from the top level.\n\n**Common patterns:**\n\n| Viewport Type | Typical Classes |\n|---------------|----------------|\n| **Floor plan** | `[\"space\", \"walls\", \"windows\", \"doors\", \"columns\", \"stairs\"]` |\n| **Structure only** | `[\"walls\", \"columns\", \"beam\", \"floor\"]` |\n| **Detail view** | `[\"walls\", \"windows\", \"beam\", \"columns\"]` |\n| **Section view** | `[\"space\", \"walls\", \"windows\", \"floor\", \"roof\"]` |\n| **MEP** | `[\"flow\", \"furniture\", \"walls\"]` |\n\n**⚠️ Performance tip:** Fewer classes = faster rendering. Only include what you need for the drawing.\n\n**If omitted:** All classes with geometry are included (may be slow for large models)"
|
|
828
947
|
},
|
|
829
948
|
"lineStyles": {
|
|
830
949
|
"$ref": "#/$defs/viewportLineStyles",
|
|
831
|
-
"description": "Per-category line styles.
|
|
832
|
-
},
|
|
833
|
-
"lineWidthMm": {
|
|
834
|
-
"type": "number",
|
|
835
|
-
"description": "Simple shorthand: default line width for all categories. Overridden by lineStyles."
|
|
836
|
-
},
|
|
837
|
-
"lineColor": {
|
|
838
|
-
"$ref": "#/$defs/cssColor",
|
|
839
|
-
"description": "Simple shorthand: default line color for all categories. Overridden by lineStyles."
|
|
950
|
+
"description": "Per-category line styles. Use `default` for a single style across all categories."
|
|
840
951
|
},
|
|
841
952
|
"fills": {
|
|
842
953
|
"type": "array",
|
|
@@ -849,8 +960,8 @@
|
|
|
849
960
|
"properties": {
|
|
850
961
|
"class": {
|
|
851
962
|
"oneOf": [
|
|
852
|
-
{ "
|
|
853
|
-
{ "type": "array", "items": { "
|
|
963
|
+
{ "$ref": "#/$defs/ifcClassName" },
|
|
964
|
+
{ "type": "array", "items": { "$ref": "#/$defs/ifcClassName" } }
|
|
854
965
|
],
|
|
855
966
|
"description": "IFC class filter (e.g. 'space', 'walls').",
|
|
856
967
|
"markdownDescription": "IFC class filter.\n\nCan be a single class or array of classes:\n- `\"class\": \"space\"`\n- `\"class\": [\"space\", \"walls\"]`"
|
|
@@ -875,8 +986,8 @@
|
|
|
875
986
|
"matchClipFilter": {
|
|
876
987
|
"type": "boolean",
|
|
877
988
|
"default": false,
|
|
878
|
-
"description": "Only fill items whose centroid is inside the original (unexpanded) clip polygon. Useful when
|
|
879
|
-
"markdownDescription": "Only fill items whose centroid is inside the **original** (unexpanded) clip polygon.\n\nWhen `clip.
|
|
989
|
+
"description": "Only fill items whose centroid is inside the original (unexpanded) clip polygon. Useful when expandBy reveals adjacent spaces that shouldn't be filled.",
|
|
990
|
+
"markdownDescription": "Only fill items whose centroid is inside the **original** (unexpanded) clip polygon.\n\nWhen `clip.expandBy` is used, the viewport shows geometry in an expanded area, but you may only want fills for items in the original clip area.\n\n**Example:**\n```json\n\"clip\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"expandBy\": 1.5\n},\n\"fills\": [{\n \"class\": \"space\",\n \"where\": { \"BIP.spacetype\": \"ROOM\" },\n \"fill\": \"sample\",\n \"matchClipFilter\": true\n}]\n```\n\nThis ensures only the tenant's own spaces are filled, not surrounding spaces visible due to `expandBy`."
|
|
880
991
|
}
|
|
881
992
|
}
|
|
882
993
|
}
|
|
@@ -884,31 +995,31 @@
|
|
|
884
995
|
"northArrow": {
|
|
885
996
|
"type": "object",
|
|
886
997
|
"description": "Optional north arrow overlay showing building orientation.",
|
|
887
|
-
"markdownDescription": "Optional north arrow overlay showing building orientation.\n\n**Purpose:**\nDisplays a north arrow on the viewport to indicate building orientation relative to true north.\n\n**Example:**\n```json\n\"northArrow\": {\n \"
|
|
888
|
-
"required": ["
|
|
998
|
+
"markdownDescription": "Optional north arrow overlay showing building orientation.\n\n**Purpose:**\nDisplays a north arrow on the viewport to indicate building orientation relative to true north.\n\n**Example:**\n```json\n\"northArrow\": {\n \"resourceId\": \"north-arrow-icon\",\n \"sizeMm\": 12,\n \"offsetXMm\": 8,\n \"offsetYMm\": 8,\n \"rotationDeg\": 45\n}\n```\n\n**Positioning:**\n- Arrow is anchored at the viewport's **top-right corner**\n- Positive offsets move it left (X) and down (Y) from that corner\n\n**Rotation:**\n- `rotationDeg` rotates the arrow to point north\n- Example: If building is rotated 45° from north, set `rotationDeg: 45`\n\n**Requires:**\n- Define the north arrow image in `resources`\n- Reference it via `resourceId`",
|
|
999
|
+
"required": ["resourceId"],
|
|
889
1000
|
"additionalProperties": false,
|
|
890
1001
|
"properties": {
|
|
891
|
-
"
|
|
1002
|
+
"resourceId": {
|
|
892
1003
|
"type": "string",
|
|
893
|
-
"description": "
|
|
1004
|
+
"description": "Resource ID for the north arrow image (SVG or raster).",
|
|
894
1005
|
"examples": ["north-arrow", "north-icon"]
|
|
895
1006
|
},
|
|
896
1007
|
"sizeMm": {
|
|
897
1008
|
"type": "number",
|
|
898
1009
|
"description": "Size of the north arrow in mm (width and height).",
|
|
899
|
-
"default":
|
|
1010
|
+
"default": 12,
|
|
900
1011
|
"examples": [10, 15, 20]
|
|
901
1012
|
},
|
|
902
1013
|
"offsetXMm": {
|
|
903
1014
|
"type": "number",
|
|
904
|
-
"description": "Horizontal offset from viewport's top-
|
|
905
|
-
"default":
|
|
1015
|
+
"description": "Horizontal offset (leftwards) from the viewport's top-right corner in mm.",
|
|
1016
|
+
"default": 8,
|
|
906
1017
|
"examples": [5, 10]
|
|
907
1018
|
},
|
|
908
1019
|
"offsetYMm": {
|
|
909
1020
|
"type": "number",
|
|
910
|
-
"description": "Vertical offset from viewport's top-
|
|
911
|
-
"default":
|
|
1021
|
+
"description": "Vertical offset (downwards) from the viewport's top-right corner in mm.",
|
|
1022
|
+
"default": 8,
|
|
912
1023
|
"examples": [5, 10]
|
|
913
1024
|
},
|
|
914
1025
|
"rotationDeg": {
|
|
@@ -923,14 +1034,14 @@
|
|
|
923
1034
|
"clip": { "$ref": "#/$defs/clipConfig" },
|
|
924
1035
|
"highlight": { "$ref": "#/$defs/highlightConfig" },
|
|
925
1036
|
"cutHeight": {
|
|
926
|
-
"type": "number",
|
|
927
|
-
"description": "Override cutting plane height for horizontal plans (Y coordinate). Shorthand for planeNormal=[0,1,0], planePosition=cutHeight.",
|
|
1037
|
+
"oneOf": [{ "type": "number" }, { "type": "string", "pattern": "^\\{\\{vars\\.\\w+\\}\\}$" }],
|
|
1038
|
+
"description": "Override cutting plane height for horizontal plans (Y coordinate, metres). Shorthand for planeNormal=[0,1,0], planePosition=cutHeight. May be a variable binding like '{{vars.cutHeight}}' (number variable) so users control the cut via the variables UI.",
|
|
928
1039
|
"markdownDescription": "Override cutting plane height for horizontal plans (Y coordinate).\n\n**Shorthand for:**\n```json\n\"planeNormal\": [0, 1, 0],\n\"planePosition\": <cutHeight value>\n```\n\n**Common values:**\n- `3.0` — 3 meters above origin (typical floor plan height)\n- `1.5` — 1.5 meters (lower section height)\n- `5.0` — 5 meters (upper level)\n\n**When to use:**\n- For simple horizontal floor plans at a specific elevation\n- When you don't need vertical or diagonal sections\n\n**If omitted:** Uses app default height (typically 3.0m)"
|
|
929
1040
|
},
|
|
930
1041
|
"depth": {
|
|
931
1042
|
"type": "object",
|
|
932
1043
|
"description": "Override depth above/below cutting plane. Only applicable for SLAB mode (ignored in PLANE mode).",
|
|
933
|
-
"markdownDescription": "Override depth above/below cutting plane.\n\n**⚠️ SLAB mode only** — This property is ignored in PLANE mode (vertical sections).\n\nDefines the thickness of the \"slab\" that includes geometry:\n- `above` — How far above the cutting plane to include geometry\n- `below` — How far below the cutting plane to include geometry\n\n**Example — Standard floor plan:**\n```json\n\"cutHeight\": 3.0,\n\"depth\": {\n \"above\": 1.0,\n \"below\": 2.0\n}\n```\nThis includes geometry from Y=1.0 to Y=5.0 (3.0 - 2.0 to 3.0 + 1.0).\n\n**If omitted:** Uses app default depth settings",
|
|
1044
|
+
"markdownDescription": "Override depth above/below cutting plane.\n\n**⚠️ SLAB mode only** — This property is ignored in PLANE mode (vertical sections).\n\nDefines the thickness of the \"slab\" that includes geometry:\n- `above` — How far above the cutting plane to include geometry\n- `below` — How far below the cutting plane to include geometry\n\n**Example — Standard floor plan:**\n```json\n\"cutHeight\": 3.0,\n\"depth\": {\n \"above\": 1.0,\n \"below\": 2.0\n}\n```\nThis includes geometry from Y=1.0 to Y=5.0 (3.0 - 2.0 up to 3.0 + 1.0 = 4.0).\n\n**If omitted:** Uses app default depth settings",
|
|
934
1045
|
"additionalProperties": false,
|
|
935
1046
|
"properties": {
|
|
936
1047
|
"above": {
|
|
@@ -945,6 +1056,49 @@
|
|
|
945
1056
|
}
|
|
946
1057
|
}
|
|
947
1058
|
},
|
|
1059
|
+
"stairArrows": {
|
|
1060
|
+
"type": "object",
|
|
1061
|
+
"description": "Stair-arrow geometry options for plan viewports: marker shapes and run sizing. Stroke/color/width and hiding stay under lineStyles.stairArrows. Ignored for elevations/sections.",
|
|
1062
|
+
"markdownDescription": "Stair-arrow **geometry** options for plan viewports — the shape of the generated arrows.\n\nStyling (stroke, color, width) and hiding stay under `lineStyles.stairArrows`; this object controls what gets generated.\n\n**Example — open markers per Bygghandlingar 90:**\n```json\n\"stairArrows\": {\n \"startMarker\": \"open\",\n \"arrowhead\": \"open\"\n}\n```\n\n**Ignored** for elevations/sections (they generate no stair arrows).",
|
|
1063
|
+
"additionalProperties": false,
|
|
1064
|
+
"properties": {
|
|
1065
|
+
"startMarker": {
|
|
1066
|
+
"type": "string",
|
|
1067
|
+
"enum": ["filled", "open", "none"],
|
|
1068
|
+
"default": "filled",
|
|
1069
|
+
"description": "Marker at the run's bottom end: 'filled' (solid circle), 'open' (outline circle), or 'none'."
|
|
1070
|
+
},
|
|
1071
|
+
"arrowhead": {
|
|
1072
|
+
"type": "string",
|
|
1073
|
+
"enum": ["filled", "outline", "open"],
|
|
1074
|
+
"default": "filled",
|
|
1075
|
+
"description": "Arrowhead at the run's top end: 'filled' (solid triangle), 'outline' (hollow triangle), or 'open' (two barb strokes)."
|
|
1076
|
+
},
|
|
1077
|
+
"lengthScale": {
|
|
1078
|
+
"type": "number",
|
|
1079
|
+
"minimum": 0,
|
|
1080
|
+
"description": "Fraction of the flight length the arrow occupies.",
|
|
1081
|
+
"examples": [0.6]
|
|
1082
|
+
},
|
|
1083
|
+
"minLength": {
|
|
1084
|
+
"type": "number",
|
|
1085
|
+
"minimum": 0,
|
|
1086
|
+
"description": "Minimum arrow length in metres.",
|
|
1087
|
+
"examples": [0.8]
|
|
1088
|
+
},
|
|
1089
|
+
"maxLength": {
|
|
1090
|
+
"type": "number",
|
|
1091
|
+
"minimum": 0,
|
|
1092
|
+
"description": "Maximum arrow length in metres.",
|
|
1093
|
+
"examples": [20]
|
|
1094
|
+
},
|
|
1095
|
+
"landingExtension": {
|
|
1096
|
+
"type": "number",
|
|
1097
|
+
"minimum": 0,
|
|
1098
|
+
"description": "How far the walking line extends onto a landing when the landing's own geometry can't anchor it (metres)."
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
},
|
|
948
1102
|
"planeNormal": {
|
|
949
1103
|
"type": "array",
|
|
950
1104
|
"description": "Plane normal vector [x, y, z]. Automatically normalized. Takes precedence over cutHeight.",
|
|
@@ -954,15 +1108,9 @@
|
|
|
954
1108
|
"maxItems": 3
|
|
955
1109
|
},
|
|
956
1110
|
"planePosition": {
|
|
957
|
-
"type": "number",
|
|
958
|
-
"description": "Distance from origin along the (normalized) plane normal. Required when using planeNormal.",
|
|
1111
|
+
"oneOf": [{ "type": "number" }, { "type": "string", "pattern": "^\\{\\{vars\\.\\w+\\}\\}$" }],
|
|
1112
|
+
"description": "Distance from origin along the (normalized) plane normal (metres). Required when using planeNormal. May be a variable binding like '{{vars.sectionPosition}}'.",
|
|
959
1113
|
"markdownDescription": "Distance from origin along the (normalized) plane normal.\n\n**How it works:**\nThe plane passes through the point: `normalize(planeNormal) * planePosition`\n\n**Examples:**\n\n**Vertical section at X=50:**\n```json\n\"planeNormal\": [1, 0, 0],\n\"planePosition\": 50\n```\nPlane perpendicular to X-axis, 50 meters from origin.\n\n**Vertical section at Z=30:**\n```json\n\"planeNormal\": [0, 0, 1],\n\"planePosition\": 30\n```\nPlane perpendicular to Z-axis, 30 meters from origin.\n\n**Horizontal plan at Y=3:**\n```json\n\"planeNormal\": [0, 1, 0],\n\"planePosition\": 3\n```\nSame as `\"cutHeight\": 3`.\n\n**⚠️ Must be used together with `planeNormal`**"
|
|
960
|
-
},
|
|
961
|
-
"mode": {
|
|
962
|
-
"type": "string",
|
|
963
|
-
"enum": ["slab", "plane"],
|
|
964
|
-
"description": "Section computation mode: 'slab' (horizontal plans) or 'plane' (vertical sections). Auto-detected if omitted.",
|
|
965
|
-
"markdownDescription": "Section computation mode:\n\n- **`slab`** — Optimized for horizontal floor plans. Uses `depth.above`/`depth.below` to include geometry in a thickness slab around the cutting plane. Fast and efficient for plan views.\n- **`plane`** — Arbitrary plane cuts (vertical sections, diagonal sections). Computes exact intersection with the plane. Required for non-horizontal sections.\n\n**Auto-detection (if omitted):**\n- Horizontal planes (`planeNormal` ≈ Y-axis) → `slab`\n- Vertical or diagonal planes → `plane`\n\n**⚠️ Important limitations:**\n- **Vertical sections MUST use `plane` mode** — SLAB mode only works correctly for horizontal plans\n- **Diagonal sections require `plane` mode**\n- If ANY viewport in a template requires `plane` mode, the entire export uses `plane` mode (auto-switching with console warning)\n\n**When to set explicitly:**\n- Set `\"mode\": \"plane\"` for vertical sections to be explicit\n- Set `\"mode\": \"slab\"` for horizontal plans if you want to ensure SLAB optimizations\n- Omit for auto-detection (recommended for most cases)"
|
|
966
1114
|
}
|
|
967
1115
|
}
|
|
968
1116
|
},
|
|
@@ -970,7 +1118,7 @@
|
|
|
970
1118
|
"textElement": {
|
|
971
1119
|
"type": "object",
|
|
972
1120
|
"description": "Static or template text placed at a fixed position on the page.",
|
|
973
|
-
"markdownDescription": "Static or template text placed at a fixed position on the page.\n\n**Use cases:**\n- Drawing titles\n- Scale indicators (\"Scale: 1:100\")\n- Project metadata (dates, revision numbers)\n- Fixed labels (\"PLAN\", \"SECTION A-A\")\n\n**Template variables:**\nUse `{{variable}}` syntax for dynamic content:\n\n| Variable | Output | Example |\n|----------|--------|----------|\n| `{{viewport.<id>.scaleText}}` | Scale ratio | `1:100` |\n| `{{
|
|
1121
|
+
"markdownDescription": "Static or template text placed at a fixed position on the page.\n\n**Use cases:**\n- Drawing titles\n- Scale indicators (\"Scale: 1:100\")\n- Project metadata (dates, revision numbers)\n- Fixed labels (\"PLAN\", \"SECTION A-A\")\n\n**Template variables:**\nUse `{{variable}}` syntax for dynamic content:\n\n| Variable | Output | Example |\n|----------|--------|----------|\n| `{{viewport.<id>.scaleText}}` | Scale ratio | `1:100` |\n| `{{vars.<name>}}` | Declared template variable | Any value |\n\n**Examples:**\n\n**Scale indicator:**\n```json\n{\n \"kind\": \"text\",\n \"id\": \"scale-text\",\n \"xMm\": 210,\n \"yMm\": 275,\n \"textStyle\": \"body\",\n \"align\": \"center\",\n \"text\": \"Scale: {{viewport.main.scaleText}}\"\n}\n```\nOutput: `Scale: 1:100`\n\n**Drawing title with scale:**\n```json\n{\n \"kind\": \"text\",\n \"id\": \"title\",\n \"xMm\": 10,\n \"yMm\": 15,\n \"textStyle\": \"title\",\n \"text\": \"Floor Plan 02 — {{viewport.main.scaleText}}\"\n}\n```\nOutput: `Floor Plan 02 — 1:100`\n\n**Static text:**\n```json\n{\n \"kind\": \"text\",\n \"id\": \"section-label\",\n \"xMm\": 320,\n \"yMm\": 95,\n \"textStyle\": \"body\",\n \"text\": \"SECTION A-A\"\n}\n```",
|
|
974
1122
|
"required": ["kind", "id", "xMm", "yMm", "text"],
|
|
975
1123
|
"additionalProperties": false,
|
|
976
1124
|
"properties": {
|
|
@@ -989,11 +1137,9 @@
|
|
|
989
1137
|
"description": "Text content. Use {{variable}} for template interpolation.",
|
|
990
1138
|
"examples": [
|
|
991
1139
|
"Scale: {{viewport.main.scaleText}}",
|
|
992
|
-
"Build: {{buildStamp}}",
|
|
993
1140
|
"Hyresobjekt: 2022-F2008"
|
|
994
1141
|
]
|
|
995
1142
|
},
|
|
996
|
-
"maxWidthMm": { "type": "number", "description": "Maximum text width in mm before wrapping." },
|
|
997
1143
|
"align": {
|
|
998
1144
|
"type": "string",
|
|
999
1145
|
"enum": ["left", "center", "right"],
|
|
@@ -1005,8 +1151,8 @@
|
|
|
1005
1151
|
|
|
1006
1152
|
"imageElement": {
|
|
1007
1153
|
"type": "object",
|
|
1008
|
-
"description": "An image element placed on the page. References
|
|
1009
|
-
"required": ["kind", "id", "xMm", "yMm", "widthMm", "heightMm", "
|
|
1154
|
+
"description": "An image element placed on the page. References a resource by ID.",
|
|
1155
|
+
"required": ["kind", "id", "xMm", "yMm", "widthMm", "heightMm", "resourceId"],
|
|
1010
1156
|
"additionalProperties": false,
|
|
1011
1157
|
"properties": {
|
|
1012
1158
|
"kind": { "const": "image" },
|
|
@@ -1016,7 +1162,7 @@
|
|
|
1016
1162
|
"yMm": { "type": "number", "description": "Y position on page in mm." },
|
|
1017
1163
|
"widthMm": { "type": "number", "description": "Image width in mm." },
|
|
1018
1164
|
"heightMm": { "type": "number", "description": "Image height in mm." },
|
|
1019
|
-
"
|
|
1165
|
+
"resourceId": { "type": "string", "description": "ID of a resource from the resources array." },
|
|
1020
1166
|
"fit": {
|
|
1021
1167
|
"type": "string",
|
|
1022
1168
|
"enum": ["contain", "cover", "stretch"],
|
|
@@ -1042,7 +1188,7 @@
|
|
|
1042
1188
|
"y2Mm": { "type": "number", "description": "End Y in mm." },
|
|
1043
1189
|
"stroke": { "$ref": "#/$defs/cssColor", "default": "#000", "description": "Line color." },
|
|
1044
1190
|
"strokeWidthMm": { "type": "number", "default": 0.25, "description": "Line width in mm." },
|
|
1045
|
-
"
|
|
1191
|
+
"dash": { "type": "string", "description": "SVG stroke-dasharray in mm, e.g. \"4 2\"." }
|
|
1046
1192
|
}
|
|
1047
1193
|
},
|
|
1048
1194
|
|
|
@@ -1062,7 +1208,7 @@
|
|
|
1062
1208
|
"stroke": { "$ref": "#/$defs/cssColor", "description": "Border color." },
|
|
1063
1209
|
"strokeWidthMm": { "type": "number", "description": "Border width in mm." },
|
|
1064
1210
|
"fill": { "$ref": "#/$defs/cssColor", "default": "none", "description": "Fill color. \"none\" for no fill." },
|
|
1065
|
-
"
|
|
1211
|
+
"dash": { "type": "string", "description": "SVG stroke-dasharray in mm, e.g. \"4 2\"." }
|
|
1066
1212
|
}
|
|
1067
1213
|
},
|
|
1068
1214
|
|
|
@@ -1081,7 +1227,7 @@
|
|
|
1081
1227
|
"stroke": { "$ref": "#/$defs/cssColor", "description": "Border color." },
|
|
1082
1228
|
"strokeWidthMm": { "type": "number", "description": "Border width in mm." },
|
|
1083
1229
|
"fill": { "$ref": "#/$defs/cssColor", "default": "none", "description": "Fill color." },
|
|
1084
|
-
"
|
|
1230
|
+
"dash": { "type": "string", "description": "SVG stroke-dasharray in mm, e.g. \"4 2\"." }
|
|
1085
1231
|
}
|
|
1086
1232
|
},
|
|
1087
1233
|
|
|
@@ -1107,7 +1253,7 @@
|
|
|
1107
1253
|
"points": { "type": "array", "items": { "$ref": "#/$defs/pointMm" }, "description": "Array of points in mm." },
|
|
1108
1254
|
"stroke": { "$ref": "#/$defs/cssColor", "description": "Line color." },
|
|
1109
1255
|
"strokeWidthMm": { "type": "number", "description": "Line width in mm." },
|
|
1110
|
-
"
|
|
1256
|
+
"dash": { "type": "string", "description": "SVG stroke-dasharray in mm, e.g. \"4 2\"." }
|
|
1111
1257
|
}
|
|
1112
1258
|
},
|
|
1113
1259
|
|
|
@@ -1124,7 +1270,7 @@
|
|
|
1124
1270
|
"stroke": { "$ref": "#/$defs/cssColor", "description": "Border color." },
|
|
1125
1271
|
"strokeWidthMm": { "type": "number", "description": "Border width in mm." },
|
|
1126
1272
|
"fill": { "$ref": "#/$defs/cssColor", "default": "none", "description": "Fill color." },
|
|
1127
|
-
"
|
|
1273
|
+
"dash": { "type": "string", "description": "SVG stroke-dasharray in mm, e.g. \"4 2\"." }
|
|
1128
1274
|
}
|
|
1129
1275
|
},
|
|
1130
1276
|
|
|
@@ -1225,16 +1371,11 @@
|
|
|
1225
1371
|
"description": "Label text alignment.",
|
|
1226
1372
|
"markdownDescription": "Label text alignment.\n\n- **`center`** (default) — Centered on item centroid (best for room labels)\n- **`left`** — Aligned left from centroid\n- **`right`** — Aligned right from centroid"
|
|
1227
1373
|
},
|
|
1228
|
-
"maxWidthMm": {
|
|
1229
|
-
"type": "number",
|
|
1230
|
-
"description": "Maximum label width in mm before wrapping.",
|
|
1231
|
-
"markdownDescription": "Maximum label width in mm before text wrapping.\n\n**Example:**\n```json\n\"maxWidthMm\": 30\n```\nLabels longer than 30mm will wrap to multiple lines.\n\n**If omitted:** No wrapping (single line, may overflow)"
|
|
1232
|
-
},
|
|
1233
1374
|
"matchClipFilter": {
|
|
1234
1375
|
"type": "boolean",
|
|
1235
1376
|
"default": false,
|
|
1236
1377
|
"description": "Only show labels for items inside the viewport's clip boundary (if clip is configured).",
|
|
1237
|
-
"markdownDescription": "Only show labels for items inside the viewport's clip boundary.\n\n**When to use:**\n- You have a `clip` configured on the viewport\n- You only want labels for items in the clipped area\n- You're using `
|
|
1378
|
+
"markdownDescription": "Only show labels for items inside the viewport's clip boundary.\n\n**When to use:**\n- You have a `clip` configured on the viewport\n- You only want labels for items in the clipped area\n- You're using `expandBy` and don't want labels outside the original clip\n\n**Example:**\n```json\n\"clip\": {\n \"class\": \"space\",\n \"where\": { \"BIP.hyresobjektsnummer\": \"2022-F2008\" },\n \"expandBy\": 1.5\n},\n\"labels\": {\n \"class\": \"space\",\n \"where\": { \"BIP.spacetype\": \"ROOM\" },\n \"text\": \"{{BIP.spacename}}\",\n \"matchClipFilter\": true\n}\n```\n\nLabels only appear for rooms whose centroid is in the ORIGINAL (unexpanded) clip polygon."
|
|
1238
1379
|
}
|
|
1239
1380
|
}
|
|
1240
1381
|
},
|
|
@@ -1304,41 +1445,75 @@
|
|
|
1304
1445
|
"default": 2,
|
|
1305
1446
|
"description": "Padding inside each legend cell in mm."
|
|
1306
1447
|
},
|
|
1307
|
-
"
|
|
1308
|
-
"type": "
|
|
1309
|
-
"
|
|
1310
|
-
"description": "Outer border stroke
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
"description": "Outer border color."
|
|
1316
|
-
},
|
|
1317
|
-
"gridStrokeWidthMm": {
|
|
1318
|
-
"type": "number",
|
|
1319
|
-
"default": 0.25,
|
|
1320
|
-
"description": "Internal grid line width in mm."
|
|
1321
|
-
},
|
|
1322
|
-
"gridStrokeColor": {
|
|
1323
|
-
"$ref": "#/$defs/cssColor",
|
|
1324
|
-
"default": "#000000",
|
|
1325
|
-
"description": "Internal grid line color."
|
|
1448
|
+
"border": {
|
|
1449
|
+
"type": "object",
|
|
1450
|
+
"additionalProperties": false,
|
|
1451
|
+
"description": "Outer table border — same stroke vocabulary as shape elements.",
|
|
1452
|
+
"properties": {
|
|
1453
|
+
"stroke": { "$ref": "#/$defs/cssColor", "default": "#000000", "description": "Border color." },
|
|
1454
|
+
"strokeWidthMm": { "type": "number", "default": 0.25, "description": "Border width in mm." }
|
|
1455
|
+
}
|
|
1326
1456
|
},
|
|
1327
|
-
"
|
|
1328
|
-
"type": "
|
|
1329
|
-
"
|
|
1330
|
-
"description": "
|
|
1457
|
+
"grid": {
|
|
1458
|
+
"type": "object",
|
|
1459
|
+
"additionalProperties": false,
|
|
1460
|
+
"description": "Inner grid lines between rows and columns.",
|
|
1461
|
+
"properties": {
|
|
1462
|
+
"stroke": { "$ref": "#/$defs/cssColor", "default": "#000000", "description": "Grid line color." },
|
|
1463
|
+
"strokeWidthMm": { "type": "number", "default": 0.25, "description": "Grid line width in mm." }
|
|
1464
|
+
}
|
|
1331
1465
|
},
|
|
1332
|
-
"
|
|
1333
|
-
"
|
|
1334
|
-
"
|
|
1335
|
-
"description": "
|
|
1466
|
+
"header": {
|
|
1467
|
+
"type": "object",
|
|
1468
|
+
"additionalProperties": false,
|
|
1469
|
+
"description": "Header separator line (also used above the summary row).",
|
|
1470
|
+
"properties": {
|
|
1471
|
+
"stroke": { "$ref": "#/$defs/cssColor", "default": "#000000", "description": "Separator color." },
|
|
1472
|
+
"strokeWidthMm": { "type": "number", "default": 0.65, "description": "Separator width in mm." }
|
|
1473
|
+
}
|
|
1336
1474
|
},
|
|
1337
1475
|
"columns": {
|
|
1338
1476
|
"type": "array",
|
|
1339
1477
|
"description": "Column definitions for the legend table.",
|
|
1340
1478
|
"items": { "$ref": "#/$defs/legendColumn" },
|
|
1341
1479
|
"minItems": 1
|
|
1480
|
+
},
|
|
1481
|
+
"summary": {
|
|
1482
|
+
"type": "object",
|
|
1483
|
+
"description": "Summary (totals) row at the bottom of the legend. Columns with summary: true show their sum.",
|
|
1484
|
+
"markdownDescription": "Summary (totals) row at the bottom of the legend.\n\nColumns with `summary: true` show their **sum** in this row.\n\n**Example:**\n```json\n\"summary\": { \"enabled\": true, \"label\": \"Total\" },\n\"columns\": [\n { \"id\": \"name\", \"label\": \"Room\", \"property\": \"BIP.spacename\" },\n { \"id\": \"area\", \"label\": \"Area\", \"property\": \"BIP.area\", \"summary\": true }\n]\n```",
|
|
1485
|
+
"required": ["enabled"],
|
|
1486
|
+
"additionalProperties": false,
|
|
1487
|
+
"properties": {
|
|
1488
|
+
"enabled": { "type": "boolean", "description": "Enable the summary row." },
|
|
1489
|
+
"label": {
|
|
1490
|
+
"type": "string",
|
|
1491
|
+
"default": "Total",
|
|
1492
|
+
"description": "Label shown in the first column of the summary row."
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
"groupBy": {
|
|
1497
|
+
"type": "string",
|
|
1498
|
+
"description": "Group legend rows by a property path (e.g. BIP.spacename): identical values consolidate into one row; numerical columns are summed, others take the first value.",
|
|
1499
|
+
"markdownDescription": "Group legend rows by a **property path** (short form, e.g. `BIP.spacename`).\n\nRows with identical values in the groupBy property consolidate into a single row — numerical columns are **summed** across the group; non-numerical columns take the first value.\n\n**Example:**\n```json\n\"groupBy\": \"BIP.spacename\",\n\"columns\": [\n { \"id\": \"name\", \"label\": \"Room\", \"property\": \"BIP.spacename\" },\n { \"id\": \"area\", \"label\": \"Area\", \"property\": \"BIP.area\", \"format\": { \"digits\": 2 } }\n]\n```\nGroups all rooms with the same name and sums their areas."
|
|
1500
|
+
},
|
|
1501
|
+
"assignColors": {
|
|
1502
|
+
"type": "object",
|
|
1503
|
+
"description": "Assign a distinct color to each legend row (or group) and expose them to the viewport: fill rules with fill: \"legend\" use these colors.",
|
|
1504
|
+
"markdownDescription": "Assign a distinct color to each legend row (or group when `groupBy` is set) and apply them to the referenced viewport.\n\nThe viewport uses these colors via a fill rule with `\"fill\": \"legend\"`.\n\n**Example:**\n```json\n\"assignColors\": { \"enabled\": true, \"palette\": \"auto\" },\n\"groupBy\": \"BIP.spacename\"\n```\nGenerates distinct colors per room type, applied to matching spaces in the viewport.",
|
|
1505
|
+
"required": ["enabled"],
|
|
1506
|
+
"additionalProperties": false,
|
|
1507
|
+
"properties": {
|
|
1508
|
+
"enabled": { "type": "boolean", "description": "Enable color assignment to viewport items." },
|
|
1509
|
+
"palette": {
|
|
1510
|
+
"description": "\"auto\" for generated colors, or an explicit array of CSS colors used in row order.",
|
|
1511
|
+
"oneOf": [
|
|
1512
|
+
{ "const": "auto" },
|
|
1513
|
+
{ "type": "array", "items": { "$ref": "#/$defs/cssColor" }, "minItems": 1 }
|
|
1514
|
+
]
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1342
1517
|
}
|
|
1343
1518
|
}
|
|
1344
1519
|
},
|