passerelle-geo-components 0.2.0-alpha.1
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 +77 -0
- package/examples/README.md +175 -0
- package/examples/choropleth-demographique.json +90 -0
- package/examples/corpus-documentaire.json +170 -0
- package/examples/diagnostic-temporel.json +160 -0
- package/examples/heatmap-rag.json +84 -0
- package/examples/maquette-3d.json +153 -0
- package/examples/minimal.json +19 -0
- package/examples/multi-layers-narrative.json +119 -0
- package/examples/timeline-overlay-simple.json +90 -0
- package/examples/validation-terrain-zebra.json +98 -0
- package/geo-components.js +1719 -0
- package/package.json +77 -0
- package/schemas/README.md +125 -0
- package/schemas/scene_manifest.pydantic.py +1000 -0
- package/schemas/scene_manifest.schema.json +905 -0
- package/schemas/scene_manifest.zod.ts +66 -0
|
@@ -0,0 +1,905 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://nic01asfr.github.io/Passerelle/schemas/scene_manifest/0.3.1.json",
|
|
4
|
+
"title": "SceneManifest V0.3.1",
|
|
5
|
+
"description": "Contract unifie passerelle-geo-components pivot cross-projet (workspace SIG + editeur livrables + widget carto). Voir CONTRACT-V0.3.1.md pour la spec humaine complete.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"manifest_version",
|
|
9
|
+
"produced_at",
|
|
10
|
+
"provenance",
|
|
11
|
+
"title",
|
|
12
|
+
"basemap",
|
|
13
|
+
"zone",
|
|
14
|
+
"layers"
|
|
15
|
+
],
|
|
16
|
+
"additionalProperties": false,
|
|
17
|
+
"properties": {
|
|
18
|
+
"$schema": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"format": "uri",
|
|
21
|
+
"description": "Pointeur JSON Schema self-description (facultatif si absent)."
|
|
22
|
+
},
|
|
23
|
+
"manifest_version": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"pattern": "^0\\.3\\.[0-9]+$",
|
|
26
|
+
"description": "Version SemVer strict du contract. V0.3.x lit tout 0.3.y avec y ≤ x (compat descendante 2 versions mineures).",
|
|
27
|
+
"readOnly": true
|
|
28
|
+
},
|
|
29
|
+
"scene_hash": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
32
|
+
"description": "Hash SHA-256 canonique du manifest_body. Calculé UNIQUEMENT côté producteur (au snapshot dans scene_store/). Le consommateur ne recalcule jamais côté main thread. Helper computeSceneHashInWorker() disponible pour vérification offline.",
|
|
33
|
+
"readOnly": true
|
|
34
|
+
},
|
|
35
|
+
"manifest_id": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"format": "uuid",
|
|
38
|
+
"description": "UUID4 unique du manifest. Généré au publish.",
|
|
39
|
+
"readOnly": true
|
|
40
|
+
},
|
|
41
|
+
"produced_at": {
|
|
42
|
+
"type": "string",
|
|
43
|
+
"format": "date-time",
|
|
44
|
+
"description": "Timestamp ISO 8601 avec TZ. Généré au publish.",
|
|
45
|
+
"readOnly": true
|
|
46
|
+
},
|
|
47
|
+
"title": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"maxLength": 300,
|
|
50
|
+
"description": "Titre principal de la scène (affiché en header carto)."
|
|
51
|
+
},
|
|
52
|
+
"subtitle": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"maxLength": 300,
|
|
55
|
+
"description": "Sous-titre optionnel."
|
|
56
|
+
},
|
|
57
|
+
"description": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"maxLength": 2000,
|
|
60
|
+
"description": "Description longue (paragraphe intro)."
|
|
61
|
+
},
|
|
62
|
+
"source_text": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"maxLength": 500,
|
|
65
|
+
"description": "Citation datée des sources de données (BD TOPO IGN 2024, ...)."
|
|
66
|
+
},
|
|
67
|
+
"caveat": {
|
|
68
|
+
"type": "string",
|
|
69
|
+
"maxLength": 2000,
|
|
70
|
+
"description": "Disclaimer méthodologique (marge d'erreur, données pédagogiques, ...)."
|
|
71
|
+
},
|
|
72
|
+
"provenance": { "$ref": "#/$defs/Provenance" },
|
|
73
|
+
"projection": {
|
|
74
|
+
"description": "Projection cartographique. 'mercator' (défaut), 'globe' (MapLibre v5+), 'lambert93' (via adapter proj-lambert93). Enum ouverte : accepte x_<projet>_* avec fallback graceful 'mercator'.",
|
|
75
|
+
"type": "string",
|
|
76
|
+
"oneOf": [
|
|
77
|
+
{ "const": "mercator", "title": "Web Mercator EPSG:3857 (standard MapLibre)" },
|
|
78
|
+
{ "const": "globe", "title": "Projection globe (MapLibre v5+, requiert setProjection)" },
|
|
79
|
+
{ "const": "lambert93", "title": "Lambert-93 EPSG:2154 (requiert adapters/proj-lambert93.js)" },
|
|
80
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$", "title": "Extension nommée par projet" }
|
|
81
|
+
],
|
|
82
|
+
"default": "mercator"
|
|
83
|
+
},
|
|
84
|
+
"basemap": { "$ref": "#/$defs/Basemap" },
|
|
85
|
+
"basemap_switcher": {
|
|
86
|
+
"type": "array",
|
|
87
|
+
"items": { "type": "string" },
|
|
88
|
+
"description": "IDs de basemaps proposés en toggle runtime UI (opt.). Défaut : uniquement basemap.id actuel."
|
|
89
|
+
},
|
|
90
|
+
"zone": { "$ref": "#/$defs/Zone" },
|
|
91
|
+
"camera_presets": {
|
|
92
|
+
"type": "array",
|
|
93
|
+
"items": { "$ref": "#/$defs/CameraPreset" },
|
|
94
|
+
"description": "Presets caméra nommés (top, 3d, street, ...). Utilisés par API impérative flyToPreset()."
|
|
95
|
+
},
|
|
96
|
+
"terrain": { "$ref": "#/$defs/Terrain" },
|
|
97
|
+
"sky": { "$ref": "#/$defs/Sky" },
|
|
98
|
+
"layers": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": { "$ref": "#/$defs/Layer" },
|
|
101
|
+
"description": "Couches cartographiques. Ordre = ordre de rendu (z_index respecté si défini)."
|
|
102
|
+
},
|
|
103
|
+
"custom_layers": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"items": { "$ref": "#/$defs/CustomLayer" },
|
|
106
|
+
"description": "Couches custom Three.js. Trigger dimension='3d' auto (lib dérivée). Chargé uniquement si <geo-3d-scene> composition slot présent."
|
|
107
|
+
},
|
|
108
|
+
"legend": { "$ref": "#/$defs/Legend" },
|
|
109
|
+
"scalebar": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"properties": {
|
|
112
|
+
"position": { "$ref": "#/$defs/OverlayPosition" },
|
|
113
|
+
"unit": { "enum": ["metric", "imperial", "nautical"], "default": "metric" }
|
|
114
|
+
},
|
|
115
|
+
"additionalProperties": false
|
|
116
|
+
},
|
|
117
|
+
"north_arrow": {
|
|
118
|
+
"type": "object",
|
|
119
|
+
"properties": {
|
|
120
|
+
"position": { "$ref": "#/$defs/OverlayPosition" }
|
|
121
|
+
},
|
|
122
|
+
"additionalProperties": false
|
|
123
|
+
},
|
|
124
|
+
"counters": {
|
|
125
|
+
"type": "array",
|
|
126
|
+
"items": { "$ref": "#/$defs/Counter" },
|
|
127
|
+
"description": "Compteurs live bindés (nb features filtrés, %, ...)."
|
|
128
|
+
},
|
|
129
|
+
"extensions": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"description": "Extensions par-projet indexees par prefix (x_livrables, x_atlas, x_sig, x_zebra, ...). Contenu libre (additionalProperties: true).",
|
|
132
|
+
"patternProperties": {
|
|
133
|
+
"^[a-z][a-z_0-9]*$": { "type": "object", "additionalProperties": true }
|
|
134
|
+
},
|
|
135
|
+
"additionalProperties": false
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"$defs": {
|
|
139
|
+
"Provenance": {
|
|
140
|
+
"type": "object",
|
|
141
|
+
"required": ["producer", "producer_version"],
|
|
142
|
+
"properties": {
|
|
143
|
+
"producer": {
|
|
144
|
+
"description": "Producteur du manifest. Enum ouverte : accepte x_<projet>_* avec fallback graceful 'manual'.",
|
|
145
|
+
"oneOf": [
|
|
146
|
+
{ "const": "qgis-sspcloud" },
|
|
147
|
+
{ "const": "cerema-livrables" },
|
|
148
|
+
{ "const": "atlas" },
|
|
149
|
+
{ "const": "manual" },
|
|
150
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$" }
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
"producer_version": { "type": "string" },
|
|
154
|
+
"source_project": { "type": "string", "description": "Chemin projet source (ex: .qgz path)." },
|
|
155
|
+
"qgz_hash": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
|
|
156
|
+
"agent_conversation_id": { "type": "string", "description": "ID conversation LLM si issu d'un agent." },
|
|
157
|
+
"recipe_used": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"properties": {
|
|
160
|
+
"slug": { "type": "string" },
|
|
161
|
+
"version_sha": { "type": "string" }
|
|
162
|
+
},
|
|
163
|
+
"additionalProperties": false
|
|
164
|
+
},
|
|
165
|
+
"extensions": {
|
|
166
|
+
"type": "object",
|
|
167
|
+
"patternProperties": { "^[a-z][a-z_0-9]*$": { "type": "object", "additionalProperties": true } },
|
|
168
|
+
"additionalProperties": false,
|
|
169
|
+
"description": "Extensions provenance par-projet (ex: atlas.native_payload_hash pour round-trip fidèle)."
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"additionalProperties": true,
|
|
173
|
+
"readOnly": true
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
"Basemap": {
|
|
177
|
+
"type": "object",
|
|
178
|
+
"required": ["id"],
|
|
179
|
+
"properties": {
|
|
180
|
+
"id": {
|
|
181
|
+
"description": "ID du fond de carte. Enum ouverte : accepte x_<projet>_* avec fallback graceful 'osm'.",
|
|
182
|
+
"oneOf": [
|
|
183
|
+
{ "const": "osm", "title": "OpenStreetMap Positron (CartoDB CDN)" },
|
|
184
|
+
{ "const": "plan-ign-v2", "title": "Plan IGN Standard (WMTS Géoplateforme)" },
|
|
185
|
+
{ "const": "plan-ign-v2-gris", "title": "Plan IGN GRIS (neutre, recommandé fond thématique)" },
|
|
186
|
+
{ "const": "ortho-ign", "title": "Orthophoto IGN (WMTS)" },
|
|
187
|
+
{ "const": "hillshade-ign", "title": "Estompage IGN (WMTS)" },
|
|
188
|
+
{ "const": "dsfr-sobre", "title": "Fond DSFR sobre" },
|
|
189
|
+
{ "const": "etalab", "title": "Étalab" },
|
|
190
|
+
{ "const": "openfreemap-liberty", "title": "OpenFreeMap Liberty vecteur" },
|
|
191
|
+
{ "const": "openfreemap-bright", "title": "OpenFreeMap Bright" },
|
|
192
|
+
{ "const": "openfreemap-positron", "title": "OpenFreeMap Positron" },
|
|
193
|
+
{ "const": "cartodb-positron-nolabels", "title": "Positron sans labels (CartoDB CDN)" },
|
|
194
|
+
{ "const": "custom", "title": "Style JSON custom (via basemap.style)" },
|
|
195
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$", "title": "Extension nommée par projet" }
|
|
196
|
+
]
|
|
197
|
+
},
|
|
198
|
+
"style": {
|
|
199
|
+
"type": ["object", "null"],
|
|
200
|
+
"description": "Style JSON MapLibre v8 (utilisé si id='custom' ou fallback si id inconnu).",
|
|
201
|
+
"additionalProperties": true
|
|
202
|
+
},
|
|
203
|
+
"alternatives": {
|
|
204
|
+
"type": "array",
|
|
205
|
+
"items": { "type": "string" },
|
|
206
|
+
"description": "IDs alternatifs pour switcher UI runtime."
|
|
207
|
+
},
|
|
208
|
+
"toggles": {
|
|
209
|
+
"type": "object",
|
|
210
|
+
"properties": {
|
|
211
|
+
"labels": { "type": "boolean", "default": true, "description": "Toggle labels basemap (absorbé de ex-overlays)." },
|
|
212
|
+
"buildings_3d": { "type": "boolean", "default": false, "description": "Toggle fill-extrusion bâtiments natifs basemap." }
|
|
213
|
+
},
|
|
214
|
+
"additionalProperties": false
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"additionalProperties": false
|
|
218
|
+
},
|
|
219
|
+
|
|
220
|
+
"Zone": {
|
|
221
|
+
"description": "Zone d'étude / vue caméra initiale. Discriminated union sur 'kind'.",
|
|
222
|
+
"oneOf": [
|
|
223
|
+
{
|
|
224
|
+
"type": "object",
|
|
225
|
+
"required": ["kind"],
|
|
226
|
+
"properties": {
|
|
227
|
+
"kind": { "const": "manual" },
|
|
228
|
+
"bbox": { "$ref": "#/$defs/BBox" },
|
|
229
|
+
"center": { "$ref": "#/$defs/Coord" },
|
|
230
|
+
"zoom": { "type": "number", "minimum": 0, "maximum": 22 },
|
|
231
|
+
"pitch": { "type": "number", "minimum": 0, "maximum": 85 },
|
|
232
|
+
"bearing": { "type": "number", "minimum": -180, "maximum": 180 },
|
|
233
|
+
"max_pitch": { "type": "number", "minimum": 0, "maximum": 85, "default": 60 }
|
|
234
|
+
},
|
|
235
|
+
"additionalProperties": false,
|
|
236
|
+
"description": "Zone manuelle : bbox OU (center + zoom). Au moins l'un des deux requis."
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"type": "object",
|
|
240
|
+
"required": ["kind", "insee"],
|
|
241
|
+
"properties": {
|
|
242
|
+
"kind": { "enum": ["commune", "insee_arm"] },
|
|
243
|
+
"insee": {
|
|
244
|
+
"type": "string",
|
|
245
|
+
"pattern": "^[0-9AB]{5}$",
|
|
246
|
+
"description": "Code INSEE 5 chars (commune 75001-...; arrondissement 75101-75120, 13201-13216, 69381-69389)."
|
|
247
|
+
},
|
|
248
|
+
"buffer_km": { "type": "number", "minimum": 0, "maximum": 50, "description": "Rayon buffer autour de la commune (facultatif)." },
|
|
249
|
+
"pitch": { "type": "number", "minimum": 0, "maximum": 85 },
|
|
250
|
+
"bearing": { "type": "number", "minimum": -180, "maximum": 180 },
|
|
251
|
+
"max_pitch": { "type": "number", "minimum": 0, "maximum": 85, "default": 60 }
|
|
252
|
+
},
|
|
253
|
+
"additionalProperties": false,
|
|
254
|
+
"description": "Zone administrative : commune ou arrondissement municipal. Center + zoom dérivés côté renderer."
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"type": "object",
|
|
258
|
+
"required": ["kind"],
|
|
259
|
+
"properties": {
|
|
260
|
+
"kind": { "const": "auto_bounds" },
|
|
261
|
+
"pitch": { "type": "number", "minimum": 0, "maximum": 85 },
|
|
262
|
+
"bearing": { "type": "number", "minimum": -180, "maximum": 180 },
|
|
263
|
+
"max_pitch": { "type": "number", "minimum": 0, "maximum": 85, "default": 60 }
|
|
264
|
+
},
|
|
265
|
+
"additionalProperties": false,
|
|
266
|
+
"description": "Zone dérivée automatiquement de layers[].bbox unifiés."
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
"type": "object",
|
|
270
|
+
"required": ["kind"],
|
|
271
|
+
"properties": {
|
|
272
|
+
"kind": { "type": "string", "pattern": "^x_[a-z_]+$", "description": "Extension nommée par projet." }
|
|
273
|
+
},
|
|
274
|
+
"additionalProperties": true
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
"BBox": {
|
|
280
|
+
"type": "array",
|
|
281
|
+
"items": { "type": "number" },
|
|
282
|
+
"minItems": 4,
|
|
283
|
+
"maxItems": 4,
|
|
284
|
+
"description": "Bounding box [west, south, east, north] EPSG:4326 (GeoJSON RFC 7946 §5)."
|
|
285
|
+
},
|
|
286
|
+
"Coord": {
|
|
287
|
+
"type": "array",
|
|
288
|
+
"items": { "type": "number" },
|
|
289
|
+
"minItems": 2,
|
|
290
|
+
"maxItems": 2,
|
|
291
|
+
"description": "Coordonnée [longitude, latitude] EPSG:4326."
|
|
292
|
+
},
|
|
293
|
+
|
|
294
|
+
"CameraPreset": {
|
|
295
|
+
"type": "object",
|
|
296
|
+
"required": ["id", "pitch", "bearing", "zoom"],
|
|
297
|
+
"properties": {
|
|
298
|
+
"id": { "type": "string", "description": "Identifiant unique du preset (top, 3d, street, ...)." },
|
|
299
|
+
"pitch": { "type": "number", "minimum": 0, "maximum": 85 },
|
|
300
|
+
"bearing": { "type": "number", "minimum": -180, "maximum": 180 },
|
|
301
|
+
"zoom": { "type": "number", "minimum": 0, "maximum": 22 }
|
|
302
|
+
},
|
|
303
|
+
"additionalProperties": false
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
"Terrain": {
|
|
307
|
+
"type": "object",
|
|
308
|
+
"required": ["source_id"],
|
|
309
|
+
"properties": {
|
|
310
|
+
"source_id": {
|
|
311
|
+
"description": "Source DEM. Enum ouverte : accepte x_* pour custom.",
|
|
312
|
+
"oneOf": [
|
|
313
|
+
{ "const": "ign-lidar", "title": "IGN LIDAR HD (France, requiert adapter ignmnt)" },
|
|
314
|
+
{ "const": "terrarium", "title": "Terrarium AWS (mondial, sans clé)" },
|
|
315
|
+
{ "const": "custom", "title": "URL WMTS raster-dem custom (requiert custom_tiles_url)" },
|
|
316
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$" }
|
|
317
|
+
]
|
|
318
|
+
},
|
|
319
|
+
"encoding": { "enum": ["mapbox", "terrarium"], "default": "mapbox" },
|
|
320
|
+
"exaggeration": { "type": "number", "minimum": 0, "maximum": 10, "default": 1.0 },
|
|
321
|
+
"adapter": {
|
|
322
|
+
"description": "Adapter chargé à la demande (registre ADAPTERS fermé). null si source_id ne nécessite pas d'adapter.",
|
|
323
|
+
"type": ["string", "null"],
|
|
324
|
+
"enum": ["ignmnt", null]
|
|
325
|
+
},
|
|
326
|
+
"custom_tiles_url": { "type": "string", "format": "uri", "description": "URL tiles raster-dem si source_id='custom'." },
|
|
327
|
+
"hillshade": {
|
|
328
|
+
"type": ["object", "null"],
|
|
329
|
+
"properties": {
|
|
330
|
+
"opacity": { "type": "number", "minimum": 0, "maximum": 1, "default": 0.35 },
|
|
331
|
+
"blend_mode": { "enum": ["multiply", "normal", "overlay"], "default": "multiply" }
|
|
332
|
+
},
|
|
333
|
+
"additionalProperties": false,
|
|
334
|
+
"description": "Effet hillshade (absorbe l'ex overlays.hillshade)."
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
"additionalProperties": false
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
"Sky": {
|
|
341
|
+
"type": "object",
|
|
342
|
+
"properties": {
|
|
343
|
+
"enabled": { "type": "boolean", "default": true },
|
|
344
|
+
"dynamic_sun": { "type": "boolean", "default": true, "description": "Recalcul SunCalc auto selon sun_datetime + location_for_suncalc." },
|
|
345
|
+
"sun_datetime": { "type": "string", "format": "date-time" },
|
|
346
|
+
"location_for_suncalc": {
|
|
347
|
+
"type": "object",
|
|
348
|
+
"properties": {
|
|
349
|
+
"lat": { "type": "number", "minimum": -90, "maximum": 90 },
|
|
350
|
+
"lng": { "type": "number", "minimum": -180, "maximum": 180 }
|
|
351
|
+
},
|
|
352
|
+
"additionalProperties": false
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
"additionalProperties": false
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
"Layer": {
|
|
359
|
+
"type": "object",
|
|
360
|
+
"required": ["id", "name", "role", "geometry_type", "source", "style"],
|
|
361
|
+
"properties": {
|
|
362
|
+
"id": {
|
|
363
|
+
"type": "string",
|
|
364
|
+
"pattern": "^[a-z][a-z0-9_-]*$",
|
|
365
|
+
"description": "Identifiant slug unique dans le manifest."
|
|
366
|
+
},
|
|
367
|
+
"name": { "type": "string", "maxLength": 300, "description": "Nom affiché en légende." },
|
|
368
|
+
"role": {
|
|
369
|
+
"description": "Rôle sémantique. Enum ouverte + fallback 'primary'.",
|
|
370
|
+
"oneOf": [
|
|
371
|
+
{ "const": "primary", "title": "Couche métier principale (style + tooltip actifs)." },
|
|
372
|
+
{ "const": "context", "title": "Contexte territorial (opacité réduite, non interactif)." },
|
|
373
|
+
{ "const": "emprise", "title": "Contour emprise du sujet (Livrables — fill + line surlignage)." },
|
|
374
|
+
{ "const": "members", "title": "Documents/entités groupés (Livrables — 1 emprise = N docs)." },
|
|
375
|
+
{ "const": "site", "title": "Site ponctuel unique (marker prominent)." },
|
|
376
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$", "title": "Rôle métier custom (fallback: primary)." }
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
"geometry_type": {
|
|
380
|
+
"enum": ["point", "line", "polygon", "multipolygon", "raster"],
|
|
381
|
+
"description": "Type géométrie MapLibre (guide l'auto-split polygon+point si Feature Collection mixte)."
|
|
382
|
+
},
|
|
383
|
+
"source": { "$ref": "#/$defs/LayerSource" },
|
|
384
|
+
"n_features": { "type": "integer", "minimum": 0, "description": "Nombre de features (pré-calculé — obligatoire si source.type ≠ geojson)." },
|
|
385
|
+
"bbox": { "$ref": "#/$defs/BBox" },
|
|
386
|
+
"attribute_stats": {
|
|
387
|
+
"type": "object",
|
|
388
|
+
"patternProperties": {
|
|
389
|
+
"^[a-zA-Z_][a-zA-Z0-9_]*$": {
|
|
390
|
+
"type": "object",
|
|
391
|
+
"properties": {
|
|
392
|
+
"min": { "type": "number" },
|
|
393
|
+
"max": { "type": "number" },
|
|
394
|
+
"null_count": { "type": "integer" },
|
|
395
|
+
"distinct_count": { "type": "integer" },
|
|
396
|
+
"distinct_values": { "type": "array" }
|
|
397
|
+
},
|
|
398
|
+
"additionalProperties": true
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
"additionalProperties": true
|
|
402
|
+
},
|
|
403
|
+
"style": { "$ref": "#/$defs/LayerStyle" },
|
|
404
|
+
"interactions": { "$ref": "#/$defs/Interactions" },
|
|
405
|
+
"min_zoom": { "type": ["number", "null"], "minimum": 0, "maximum": 22 },
|
|
406
|
+
"max_zoom": { "type": ["number", "null"], "minimum": 0, "maximum": 22 },
|
|
407
|
+
"extensions": {
|
|
408
|
+
"type": "object",
|
|
409
|
+
"patternProperties": { "^[a-z][a-z_0-9]*$": { "type": "object", "additionalProperties": true } },
|
|
410
|
+
"additionalProperties": false
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
"additionalProperties": false
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
"LayerSource": {
|
|
417
|
+
"description": "Source de données. Discriminated union sur 'type'. Alignée MapLibre style spec (v8+).",
|
|
418
|
+
"oneOf": [
|
|
419
|
+
{
|
|
420
|
+
"type": "object",
|
|
421
|
+
"required": ["type", "data"],
|
|
422
|
+
"properties": {
|
|
423
|
+
"type": { "const": "geojson" },
|
|
424
|
+
"data": {
|
|
425
|
+
"description": "FeatureCollection inline OU URL. AUTORISÉ UNIQUEMENT si n_features ≤ 500 (500 KB) — sinon warning validation, interdit au-delà de 5 MB.",
|
|
426
|
+
"oneOf": [
|
|
427
|
+
{ "type": "string", "format": "uri" },
|
|
428
|
+
{ "type": "object", "required": ["type", "features"], "properties": { "type": { "const": "FeatureCollection" }, "features": { "type": "array" } }, "additionalProperties": true }
|
|
429
|
+
]
|
|
430
|
+
},
|
|
431
|
+
"crs": { "type": "string", "const": "EPSG:4326", "default": "EPSG:4326" }
|
|
432
|
+
},
|
|
433
|
+
"additionalProperties": true
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"type": "object",
|
|
437
|
+
"required": ["type", "path"],
|
|
438
|
+
"properties": {
|
|
439
|
+
"type": { "const": "geojson_path" },
|
|
440
|
+
"path": { "type": "string", "description": "Chemin PVC ou URL relative (résolu côté hub)." },
|
|
441
|
+
"crs": { "type": "string", "const": "EPSG:4326", "default": "EPSG:4326" }
|
|
442
|
+
},
|
|
443
|
+
"additionalProperties": true
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"type": "object",
|
|
447
|
+
"required": ["type", "url", "source_layer"],
|
|
448
|
+
"properties": {
|
|
449
|
+
"type": { "const": "vector" },
|
|
450
|
+
"url": { "type": "string", "description": "URL template MapLibre : https://.../{z}/{x}/{y}.pbf" },
|
|
451
|
+
"source_layer": { "type": "string" },
|
|
452
|
+
"min_zoom": { "type": "integer", "minimum": 0, "maximum": 22 },
|
|
453
|
+
"max_zoom": { "type": "integer", "minimum": 0, "maximum": 22 },
|
|
454
|
+
"promote_id": { "type": "string" }
|
|
455
|
+
},
|
|
456
|
+
"additionalProperties": true
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"type": "object",
|
|
460
|
+
"required": ["type", "url", "source_layer"],
|
|
461
|
+
"properties": {
|
|
462
|
+
"type": { "const": "pmtiles" },
|
|
463
|
+
"url": { "type": "string", "format": "uri", "description": "URL fichier .pmtiles (résolu via pmtiles:// protocol MapLibre)." },
|
|
464
|
+
"source_layer": { "type": "string" },
|
|
465
|
+
"promote_id": { "type": "string" }
|
|
466
|
+
},
|
|
467
|
+
"additionalProperties": true
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
"type": "object",
|
|
471
|
+
"required": ["type", "table"],
|
|
472
|
+
"properties": {
|
|
473
|
+
"type": { "const": "grist_table" },
|
|
474
|
+
"table": { "type": "string", "description": "Nom table Grist dans le doc courant." },
|
|
475
|
+
"id_field": { "type": "string", "default": "id" },
|
|
476
|
+
"sync": {
|
|
477
|
+
"enum": ["load", "reactive", "save"],
|
|
478
|
+
"default": "load",
|
|
479
|
+
"description": "load: one-shot fetch. reactive: subscribe onRecords. save: bidirectionnel."
|
|
480
|
+
}
|
|
481
|
+
},
|
|
482
|
+
"additionalProperties": true
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"type": "object",
|
|
486
|
+
"required": ["type", "url", "type_name"],
|
|
487
|
+
"properties": {
|
|
488
|
+
"type": { "const": "wfs" },
|
|
489
|
+
"url": { "type": "string", "format": "uri" },
|
|
490
|
+
"type_name": { "type": "string", "description": "WFS TypeName (ex: BATIMENT.BATIMENT)." }
|
|
491
|
+
},
|
|
492
|
+
"additionalProperties": true
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
"type": "object",
|
|
496
|
+
"required": ["type", "catalog_id"],
|
|
497
|
+
"properties": {
|
|
498
|
+
"type": { "const": "boundary_admin" },
|
|
499
|
+
"catalog_id": { "type": "string", "description": "ID catalog IGN admin (arrondissements_marseille, communes, epci, ...)." },
|
|
500
|
+
"filter": { "type": "object", "additionalProperties": true, "description": "Filtre attributaire (ex: {insee_arm: '13204'})." }
|
|
501
|
+
},
|
|
502
|
+
"additionalProperties": true
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
"type": "object",
|
|
506
|
+
"required": ["type"],
|
|
507
|
+
"properties": {
|
|
508
|
+
"type": { "type": "string", "pattern": "^x_[a-z_]+$", "description": "Extension source nommée par projet." }
|
|
509
|
+
},
|
|
510
|
+
"additionalProperties": true
|
|
511
|
+
}
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
|
|
515
|
+
"LayerStyle": {
|
|
516
|
+
"type": "object",
|
|
517
|
+
"properties": {
|
|
518
|
+
"visible": { "type": "boolean", "default": true },
|
|
519
|
+
"z_index": { "type": ["integer", "null"], "description": "Ordre d'affichage (plus élevé = au-dessus). null = ordre du tableau." },
|
|
520
|
+
"opacity": { "$ref": "#/$defs/Opacity" },
|
|
521
|
+
"classification": { "$ref": "#/$defs/Classification" },
|
|
522
|
+
"extrusion": {
|
|
523
|
+
"type": ["object", "null"],
|
|
524
|
+
"properties": {
|
|
525
|
+
"enabled": { "type": "boolean", "default": false, "description": "Active fill-extrusion 2.5D (dérive dimension='2.5d')." },
|
|
526
|
+
"height_field": { "type": "string" },
|
|
527
|
+
"base_field": { "type": ["string", "null"] },
|
|
528
|
+
"vertical_gradient": { "type": "boolean", "default": true }
|
|
529
|
+
},
|
|
530
|
+
"additionalProperties": false
|
|
531
|
+
},
|
|
532
|
+
"outline": {
|
|
533
|
+
"type": ["object", "null"],
|
|
534
|
+
"properties": {
|
|
535
|
+
"enabled": { "type": "boolean", "default": false },
|
|
536
|
+
"color": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$", "default": "#000091" },
|
|
537
|
+
"width": { "type": "number", "minimum": 0, "default": 1 }
|
|
538
|
+
},
|
|
539
|
+
"additionalProperties": false,
|
|
540
|
+
"description": "Ajoute automatiquement un layer 'line' sur la même source (absorbe workaround Livrables)."
|
|
541
|
+
},
|
|
542
|
+
"hollow_point": {
|
|
543
|
+
"type": ["object", "null"],
|
|
544
|
+
"properties": {
|
|
545
|
+
"enabled": { "type": "boolean", "default": false },
|
|
546
|
+
"stroke_color_from_field": { "type": "string" },
|
|
547
|
+
"radius": { "type": "number", "minimum": 0, "default": 7 }
|
|
548
|
+
},
|
|
549
|
+
"additionalProperties": false,
|
|
550
|
+
"description": "Point creux pour features approximatives (absorbe workaround Livrables addPoints)."
|
|
551
|
+
},
|
|
552
|
+
"maplibre_paint_override": {
|
|
553
|
+
"type": ["object", "null"],
|
|
554
|
+
"additionalProperties": true,
|
|
555
|
+
"description": "Passthrough MapLibre setPaintProperty pour props avancées non-couvertes par classification."
|
|
556
|
+
}
|
|
557
|
+
},
|
|
558
|
+
"additionalProperties": true
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
"Opacity": {
|
|
562
|
+
"description": "Opacité statique ou réactive (bindée sur événement geo:bind).",
|
|
563
|
+
"oneOf": [
|
|
564
|
+
{
|
|
565
|
+
"type": "object",
|
|
566
|
+
"required": ["kind", "value"],
|
|
567
|
+
"properties": {
|
|
568
|
+
"kind": { "const": "static" },
|
|
569
|
+
"value": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
570
|
+
},
|
|
571
|
+
"additionalProperties": false
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
"type": "object",
|
|
575
|
+
"required": ["kind", "prop", "matched", "before", "after"],
|
|
576
|
+
"properties": {
|
|
577
|
+
"kind": { "const": "reactive" },
|
|
578
|
+
"prop": { "type": "string", "description": "Event geo:bind prop (time, scenario, filter, ...)." },
|
|
579
|
+
"matched": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
580
|
+
"before": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
581
|
+
"after": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
582
|
+
"null_value": { "type": "number", "minimum": 0, "maximum": 1 }
|
|
583
|
+
},
|
|
584
|
+
"additionalProperties": false
|
|
585
|
+
}
|
|
586
|
+
]
|
|
587
|
+
},
|
|
588
|
+
|
|
589
|
+
"Classification": {
|
|
590
|
+
"type": "object",
|
|
591
|
+
"properties": {
|
|
592
|
+
"color": { "$ref": "#/$defs/ColorClassification" },
|
|
593
|
+
"size": { "$ref": "#/$defs/SizeClassification" },
|
|
594
|
+
"model": { "$ref": "#/$defs/ModelClassification" },
|
|
595
|
+
"label": {
|
|
596
|
+
"type": "object",
|
|
597
|
+
"properties": {
|
|
598
|
+
"enabled": { "type": "boolean", "default": false },
|
|
599
|
+
"field": { "type": ["string", "null"] }
|
|
600
|
+
},
|
|
601
|
+
"additionalProperties": false
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
"additionalProperties": true
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
"ColorClassification": {
|
|
608
|
+
"description": "Discriminated union sur 'mode'. Voir §4.4 CONTRACT-V0.3.1.md pour combinaisons valides.",
|
|
609
|
+
"oneOf": [
|
|
610
|
+
{
|
|
611
|
+
"type": "object",
|
|
612
|
+
"required": ["mode", "value"],
|
|
613
|
+
"properties": {
|
|
614
|
+
"mode": { "const": "single" },
|
|
615
|
+
"value": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" },
|
|
616
|
+
"default": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
|
|
617
|
+
},
|
|
618
|
+
"additionalProperties": false
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
"type": "object",
|
|
622
|
+
"required": ["mode", "field", "categories", "default"],
|
|
623
|
+
"properties": {
|
|
624
|
+
"mode": { "const": "categorized" },
|
|
625
|
+
"field": { "type": "string" },
|
|
626
|
+
"categories": {
|
|
627
|
+
"type": "array",
|
|
628
|
+
"items": {
|
|
629
|
+
"type": "object",
|
|
630
|
+
"required": ["value", "color"],
|
|
631
|
+
"properties": {
|
|
632
|
+
"value": { "type": ["string", "number", "boolean", "null"] },
|
|
633
|
+
"color": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" },
|
|
634
|
+
"count": { "type": "integer", "minimum": 0 }
|
|
635
|
+
},
|
|
636
|
+
"additionalProperties": false
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
"default": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
|
|
640
|
+
},
|
|
641
|
+
"additionalProperties": false
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
"type": "object",
|
|
645
|
+
"required": ["mode", "field", "method", "breaks", "palette", "default"],
|
|
646
|
+
"properties": {
|
|
647
|
+
"mode": { "const": "graduated" },
|
|
648
|
+
"field": { "type": "string" },
|
|
649
|
+
"method": {
|
|
650
|
+
"description": "Méthode. INPUT agent : single/categorized/manual/linear. COMPUTED producteur : + jenks/quantile/equal_interval/log/sqrt (pré-calculés en 'manual').",
|
|
651
|
+
"enum": ["linear", "log", "sqrt", "jenks", "quantile", "equal_interval", "manual"]
|
|
652
|
+
},
|
|
653
|
+
"breaks": {
|
|
654
|
+
"type": "array",
|
|
655
|
+
"items": { "type": "number" },
|
|
656
|
+
"minItems": 1,
|
|
657
|
+
"description": "Bornes intérieures. N breaks = N+1 classes."
|
|
658
|
+
},
|
|
659
|
+
"palette": { "type": "string", "description": "Nom palette (voir §4.3 CONTRACT-V0.3.1.md)." },
|
|
660
|
+
"default": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" },
|
|
661
|
+
"_compiled_expression": {
|
|
662
|
+
"description": "MapLibre expression compilée. Source de vérité rendu. readOnly (généré producteur).",
|
|
663
|
+
"type": "array",
|
|
664
|
+
"readOnly": true
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
"additionalProperties": true
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
"type": "object",
|
|
671
|
+
"required": ["mode", "expr"],
|
|
672
|
+
"properties": {
|
|
673
|
+
"mode": { "const": "expression" },
|
|
674
|
+
"expr": {
|
|
675
|
+
"type": "array",
|
|
676
|
+
"description": "MapLibre expression brute passthrough (non-portable renderers non-MapLibre)."
|
|
677
|
+
},
|
|
678
|
+
"default": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" }
|
|
679
|
+
},
|
|
680
|
+
"additionalProperties": false
|
|
681
|
+
}
|
|
682
|
+
]
|
|
683
|
+
},
|
|
684
|
+
|
|
685
|
+
"SizeClassification": {
|
|
686
|
+
"description": "Discriminated union sur 'mode' pour size (cercles proportionnels, extrusion, ...).",
|
|
687
|
+
"oneOf": [
|
|
688
|
+
{
|
|
689
|
+
"type": "object",
|
|
690
|
+
"required": ["mode", "value"],
|
|
691
|
+
"properties": {
|
|
692
|
+
"mode": { "const": "single" },
|
|
693
|
+
"value": { "type": "number", "minimum": 0 }
|
|
694
|
+
},
|
|
695
|
+
"additionalProperties": false
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
"type": "object",
|
|
699
|
+
"required": ["mode", "field", "output_range"],
|
|
700
|
+
"properties": {
|
|
701
|
+
"mode": { "const": "graduated" },
|
|
702
|
+
"field": { "type": "string" },
|
|
703
|
+
"output_range": {
|
|
704
|
+
"type": "array",
|
|
705
|
+
"items": { "type": "number", "minimum": 0 },
|
|
706
|
+
"minItems": 2,
|
|
707
|
+
"maxItems": 2
|
|
708
|
+
},
|
|
709
|
+
"method": { "enum": ["linear", "log", "sqrt"], "default": "linear" }
|
|
710
|
+
},
|
|
711
|
+
"additionalProperties": false
|
|
712
|
+
}
|
|
713
|
+
]
|
|
714
|
+
},
|
|
715
|
+
|
|
716
|
+
"ModelClassification": {
|
|
717
|
+
"description": "Discriminated union pour choix modèle 3D (Atlas).",
|
|
718
|
+
"oneOf": [
|
|
719
|
+
{
|
|
720
|
+
"type": "object",
|
|
721
|
+
"required": ["mode"],
|
|
722
|
+
"properties": {
|
|
723
|
+
"mode": { "const": "single" },
|
|
724
|
+
"value": { "type": ["string", "null"], "description": "modelId ou null." }
|
|
725
|
+
},
|
|
726
|
+
"additionalProperties": false
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
"type": "object",
|
|
730
|
+
"required": ["mode", "field", "categories", "default_model_id"],
|
|
731
|
+
"properties": {
|
|
732
|
+
"mode": { "const": "categorized" },
|
|
733
|
+
"field": { "type": "string" },
|
|
734
|
+
"categories": {
|
|
735
|
+
"type": "array",
|
|
736
|
+
"items": {
|
|
737
|
+
"type": "object",
|
|
738
|
+
"required": ["value", "model_id"],
|
|
739
|
+
"properties": {
|
|
740
|
+
"value": { "type": ["string", "number", "boolean"] },
|
|
741
|
+
"model_id": { "type": "string" }
|
|
742
|
+
},
|
|
743
|
+
"additionalProperties": false
|
|
744
|
+
}
|
|
745
|
+
},
|
|
746
|
+
"default_model_id": { "type": ["string", "null"] }
|
|
747
|
+
},
|
|
748
|
+
"additionalProperties": false
|
|
749
|
+
}
|
|
750
|
+
]
|
|
751
|
+
},
|
|
752
|
+
|
|
753
|
+
"Interactions": {
|
|
754
|
+
"type": "object",
|
|
755
|
+
"properties": {
|
|
756
|
+
"popup_template": {
|
|
757
|
+
"type": ["object", "null"],
|
|
758
|
+
"required": ["kind", "body"],
|
|
759
|
+
"properties": {
|
|
760
|
+
"kind": { "enum": ["handlebars", "html"] },
|
|
761
|
+
"body": { "type": "string", "maxLength": 4000 }
|
|
762
|
+
},
|
|
763
|
+
"additionalProperties": false
|
|
764
|
+
},
|
|
765
|
+
"tooltip_field": { "type": ["string", "null"] },
|
|
766
|
+
"hover_attributes": {
|
|
767
|
+
"type": "array",
|
|
768
|
+
"items": { "type": "string" }
|
|
769
|
+
},
|
|
770
|
+
"emits_events": {
|
|
771
|
+
"type": "boolean",
|
|
772
|
+
"default": true,
|
|
773
|
+
"description": "Si true, émet geo:feature-click/hover canoniques. Noms d'événements fixés par la lib (voir §4.5)."
|
|
774
|
+
},
|
|
775
|
+
"feature_state_selected_field": {
|
|
776
|
+
"type": ["string", "null"],
|
|
777
|
+
"description": "Attribut identifiant pour setFeatureState('selected') MapLibre (bidirectionnel Grist bridge)."
|
|
778
|
+
}
|
|
779
|
+
},
|
|
780
|
+
"additionalProperties": false
|
|
781
|
+
},
|
|
782
|
+
|
|
783
|
+
"CustomLayer": {
|
|
784
|
+
"type": "object",
|
|
785
|
+
"required": ["id", "kind", "adapter"],
|
|
786
|
+
"properties": {
|
|
787
|
+
"id": { "type": "string" },
|
|
788
|
+
"kind": {
|
|
789
|
+
"description": "Type sémantique du contenu (renderer neutre). Enum ouverte.",
|
|
790
|
+
"oneOf": [
|
|
791
|
+
{ "const": "gltf_instances", "title": "Instances de modèles GLTF (Atlas mobilier urbain)." },
|
|
792
|
+
{ "const": "custom_3d_layer", "title": "Custom layer 3D générique (SURFAC²E éditeur volumes)." },
|
|
793
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$", "title": "Extension custom layer nommée par projet." }
|
|
794
|
+
]
|
|
795
|
+
},
|
|
796
|
+
"adapter": {
|
|
797
|
+
"description": "Adapter registre ADAPTERS de la lib (chargé à la demande).",
|
|
798
|
+
"oneOf": [
|
|
799
|
+
{ "const": "geo-3d-scene", "title": "Adapter Three.js custom layer standard." },
|
|
800
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$" }
|
|
801
|
+
]
|
|
802
|
+
},
|
|
803
|
+
"source_layer_id": {
|
|
804
|
+
"type": "string",
|
|
805
|
+
"description": "Référence un layers[].id porteur des features instances (P0-K, évite instances[] inline)."
|
|
806
|
+
},
|
|
807
|
+
"params": {
|
|
808
|
+
"type": "object",
|
|
809
|
+
"additionalProperties": true,
|
|
810
|
+
"description": "Params spécifiques adapter (gltf_base_url, shadow_map, ...)."
|
|
811
|
+
},
|
|
812
|
+
"extensions": {
|
|
813
|
+
"type": "object",
|
|
814
|
+
"patternProperties": { "^[a-z][a-z_0-9]*$": { "type": "object", "additionalProperties": true } },
|
|
815
|
+
"additionalProperties": false
|
|
816
|
+
}
|
|
817
|
+
},
|
|
818
|
+
"additionalProperties": false
|
|
819
|
+
},
|
|
820
|
+
|
|
821
|
+
"Legend": {
|
|
822
|
+
"description": "Légende. Discriminated union sur 'mode'.",
|
|
823
|
+
"oneOf": [
|
|
824
|
+
{
|
|
825
|
+
"type": "object",
|
|
826
|
+
"required": ["mode", "from_layer"],
|
|
827
|
+
"properties": {
|
|
828
|
+
"mode": { "const": "auto" },
|
|
829
|
+
"from_layer": { "type": "string", "description": "layers[].id source de la classification." },
|
|
830
|
+
"position": { "$ref": "#/$defs/OverlayPosition" },
|
|
831
|
+
"format": { "$ref": "#/$defs/LegendFormat" },
|
|
832
|
+
"title": { "type": "string", "maxLength": 200 }
|
|
833
|
+
},
|
|
834
|
+
"additionalProperties": false
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
"type": "object",
|
|
838
|
+
"required": ["mode", "items"],
|
|
839
|
+
"properties": {
|
|
840
|
+
"mode": { "const": "manual" },
|
|
841
|
+
"items": {
|
|
842
|
+
"type": "array",
|
|
843
|
+
"items": {
|
|
844
|
+
"type": "object",
|
|
845
|
+
"required": ["label"],
|
|
846
|
+
"properties": {
|
|
847
|
+
"label": { "type": "string" },
|
|
848
|
+
"color": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$" },
|
|
849
|
+
"count": { "type": "integer", "minimum": 0 },
|
|
850
|
+
"size": { "type": "number", "minimum": 0 },
|
|
851
|
+
"layer": { "type": "string" }
|
|
852
|
+
},
|
|
853
|
+
"additionalProperties": false
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
"position": { "$ref": "#/$defs/OverlayPosition" },
|
|
857
|
+
"format": { "$ref": "#/$defs/LegendFormat" },
|
|
858
|
+
"title": { "type": "string", "maxLength": 200 }
|
|
859
|
+
},
|
|
860
|
+
"additionalProperties": false
|
|
861
|
+
}
|
|
862
|
+
]
|
|
863
|
+
},
|
|
864
|
+
|
|
865
|
+
"LegendFormat": {
|
|
866
|
+
"enum": ["chips", "gradient_bar", "proportional"],
|
|
867
|
+
"default": "chips"
|
|
868
|
+
},
|
|
869
|
+
|
|
870
|
+
"OverlayPosition": {
|
|
871
|
+
"enum": ["top-left", "top-right", "bottom-left", "bottom-right", "bottom", "right", "floating"],
|
|
872
|
+
"default": "bottom-left"
|
|
873
|
+
},
|
|
874
|
+
|
|
875
|
+
"Counter": {
|
|
876
|
+
"type": "object",
|
|
877
|
+
"required": ["id", "bind", "expr", "template"],
|
|
878
|
+
"properties": {
|
|
879
|
+
"id": { "type": "string" },
|
|
880
|
+
"bind": {
|
|
881
|
+
"description": "Source de mise à jour du compteur. Enum ouverte.",
|
|
882
|
+
"oneOf": [
|
|
883
|
+
{ "const": "time", "title": "Binding geo:bind prop=time (timeline)." },
|
|
884
|
+
{ "const": "scenario", "title": "Binding geo:bind prop=scenario." },
|
|
885
|
+
{ "const": "filter", "title": "Après setFilter." },
|
|
886
|
+
{ "const": "selection", "title": "Après setSelection." },
|
|
887
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$" }
|
|
888
|
+
]
|
|
889
|
+
},
|
|
890
|
+
"expr": {
|
|
891
|
+
"description": "Expression du compteur.",
|
|
892
|
+
"oneOf": [
|
|
893
|
+
{ "const": "filtered_count", "title": "Nb features actuellement rendues (après filter)." },
|
|
894
|
+
{ "const": "total", "title": "Nb features total." },
|
|
895
|
+
{ "const": "percentage", "title": "Pourcentage filtré/total." },
|
|
896
|
+
{ "type": "string", "pattern": "^x_[a-z_]+$" }
|
|
897
|
+
]
|
|
898
|
+
},
|
|
899
|
+
"template": { "type": "string", "description": "Template Handlebars avec vars {{count}}, {{total}}, {{pct}}." },
|
|
900
|
+
"position": { "$ref": "#/$defs/OverlayPosition" }
|
|
901
|
+
},
|
|
902
|
+
"additionalProperties": false
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|