@defra/interactive-map 0.0.31-alpha → 0.0.33-alpha

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.
Files changed (131) hide show
  1. package/README.md +2 -2
  2. package/assets/images/bright-ofm-thumb.jpg +0 -0
  3. package/assets/images/dark-ofm-thumb.jpg +0 -0
  4. package/assets/images/road-ofm-thumb.jpg +0 -0
  5. package/assets/templates/add-polygons.njk +143 -0
  6. package/assets/templates/add-symbols.njk +119 -0
  7. package/assets/templates/{map.njk → basic-map.njk} +9 -17
  8. package/assets/templates/button-map.njk +56 -0
  9. package/assets/templates/draw-tools.njk +161 -0
  10. package/assets/templates/marker-panel.njk +91 -0
  11. package/assets/templates/place-marker.njk +104 -0
  12. package/assets/templates/search-control.njk +98 -0
  13. package/assets/templates/select-feature.njk +101 -0
  14. package/assets/templates/style-switcher.njk +87 -0
  15. package/assets/templates/toggle-marker-label.njk +74 -0
  16. package/dist/css/index.css +1 -1
  17. package/dist/esm/im-core.js +1 -1
  18. package/dist/esm/im-shell.js +1 -1
  19. package/dist/umd/im-core.js +1 -1
  20. package/dist/umd/index.js +1 -1
  21. package/docs/api/map-style-config.md +27 -3
  22. package/docs/api.md +55 -0
  23. package/docs/assets/css/docusaurus.scss +22 -6
  24. package/docs/assets/images/add-polygons.jpg +0 -0
  25. package/docs/assets/images/add-symbols.jpg +0 -0
  26. package/docs/assets/images/hero.png +0 -0
  27. package/docs/assets/images/place-marker.jpg +0 -0
  28. package/docs/assets/images/screenshot.jpg +0 -0
  29. package/docs/examples/add-marker-with-panel.mdx +1 -1
  30. package/docs/examples/add-polygons.mdx +225 -0
  31. package/docs/examples/add-symbols.mdx +177 -0
  32. package/docs/examples/{draw.mdx → draw-tools.mdx} +2 -2
  33. package/docs/examples/index.mdx +38 -2
  34. package/docs/examples/place-marker.mdx +151 -0
  35. package/docs/plugins/datasets.md +144 -96
  36. package/docs/plugins/interact.md +1 -4
  37. package/docusaurus.config.cjs +5 -2
  38. package/govuk-prototype-kit.config.json +52 -2
  39. package/package.json +1 -1
  40. package/plugins/beta/datasets/dist/css/index.css +1 -2
  41. package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
  42. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
  43. package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
  44. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
  45. package/plugins/beta/datasets/dist/umd/index.js +1 -1
  46. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +27 -9
  47. package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +46 -4
  48. package/plugins/beta/datasets/src/api/setFeatureVisibility.js +10 -1
  49. package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +48 -6
  50. package/plugins/beta/datasets/src/components/LayersMenu/Layers.module.scss +12 -12
  51. package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +11 -6
  52. package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +49 -0
  53. package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +8 -1
  54. package/plugins/beta/datasets/src/reducers/pluginState.js +1 -1
  55. package/plugins/beta/datasets/src/registry/dataset.js +7 -3
  56. package/plugins/beta/datasets/src/registry/dataset.test.js +14 -0
  57. package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +1 -1
  58. package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
  59. package/plugins/beta/draw-es/src/api/addFeature.js +12 -3
  60. package/plugins/beta/draw-es/src/events.js +8 -3
  61. package/plugins/beta/draw-es/src/events.test.js +2 -0
  62. package/plugins/beta/draw-es/src/graphic.js +26 -2
  63. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
  64. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
  65. package/plugins/beta/draw-ml/src/DrawInit.jsx +19 -0
  66. package/plugins/beta/draw-ml/src/api/newLine.js +1 -0
  67. package/plugins/beta/draw-ml/src/api/newPolygon.js +1 -0
  68. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +52 -37
  69. package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +1 -1
  70. package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +5 -4
  71. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +53 -21
  72. package/plugins/beta/draw-ol/dist/esm/DrawMode.js +1 -1
  73. package/plugins/beta/draw-ol/dist/esm/EditMode.js +1 -1
  74. package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
  75. package/plugins/beta/draw-ol/src/core/OLDrawManager.js +3 -0
  76. package/plugins/beta/draw-ol/src/draw/DrawMode.js +57 -49
  77. package/plugins/beta/draw-ol/src/draw/drawInput.js +76 -32
  78. package/plugins/beta/draw-ol/src/edit/EditMode.js +4 -4
  79. package/plugins/beta/draw-ol/src/edit/keyboardHandler.js +4 -2
  80. package/plugins/beta/draw-ol/src/manifest.js +5 -1
  81. package/plugins/beta/draw-ol/src/reducer.js +1 -1
  82. package/plugins/beta/draw-ol/src/snap/snapEngine.js +75 -31
  83. package/plugins/beta/draw-ol/src/snap/snapGeometry.js +23 -46
  84. package/plugins/beta/draw-ol/src/snap/snapInteraction.js +30 -29
  85. package/plugins/beta/draw-ol/src/snap/snapManager.js +10 -1
  86. package/plugins/beta/draw-ol/src/utils/geometryHelpers.js +9 -3
  87. package/plugins/beta/draw-ol/src/utils/olCoords.js +2 -2
  88. package/plugins/beta/draw-ol/src/utils/spatial.js +4 -8
  89. package/plugins/beta/map-styles/src/mapStyles.scss +41 -41
  90. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  91. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  92. package/plugins/interact/dist/umd/index.js +1 -1
  93. package/plugins/interact/src/InteractInit.jsx +1 -3
  94. package/plugins/interact/src/InteractInit.test.js +0 -2
  95. package/plugins/interact/src/events.test.js +1 -1
  96. package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -10
  97. package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +5 -10
  98. package/plugins/interact/src/hooks/useHighlightSync.js +1 -10
  99. package/plugins/interact/src/hooks/useHighlightSync.test.js +2 -21
  100. package/plugins/interact/src/hooks/useInteractionHandlers.js +5 -11
  101. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -25
  102. package/plugins/interact/src/reducer.js +4 -22
  103. package/plugins/interact/src/reducer.test.js +11 -39
  104. package/plugins/search/dist/css/index.css +5 -2
  105. package/plugins/search/src/components/Form/Form.module.scss +5 -2
  106. package/plugins/search/src/search.scss +4 -4
  107. package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
  108. package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
  109. package/providers/beta/openlayers/dist/umd/index.js +1 -1
  110. package/providers/beta/openlayers/src/utils/tileLayers.js +29 -2
  111. package/providers/beta/openlayers/src/utils/tileLayers.test.js +53 -1
  112. package/src/App/components/CrossHair/CrossHair.module.scss +8 -8
  113. package/src/App/components/MapButton/MapButton.jsx +14 -10
  114. package/src/App/components/MapButton/MapButton.module.scss +1 -1
  115. package/src/App/components/MapButton/MapButton.test.jsx +1 -1
  116. package/src/App/components/PopupMenu/PopupMenu.test.jsx +79 -0
  117. package/src/App/components/PopupMenu/usePopupMenu.js +61 -12
  118. package/src/App/hooks/useLayoutMeasurements.js +10 -2
  119. package/src/App/hooks/useResizeObserver.js +4 -2
  120. package/src/InteractiveMap/InteractiveMap.js +4 -4
  121. package/src/InteractiveMap/InteractiveMap.test.js +3 -3
  122. package/src/InteractiveMap/behaviourController.js +3 -1
  123. package/src/InteractiveMap/behaviourController.test.js +6 -3
  124. package/src/InteractiveMap/domStateManager.js +2 -0
  125. package/src/config/events.js +21 -3
  126. package/src/types.js +12 -3
  127. package/src/utils/findNextTabStop.js +3 -3
  128. package/src/utils/findNextTabStop.test.js +25 -1
  129. package/webpack.dev.mjs +1 -0
  130. package/docs/assets/images/screens-blue.jpg +0 -0
  131. package/docs/assets/images/screens-white.jpg +0 -0
@@ -129,15 +129,61 @@ Human-readable name shown in the LayersMenu panel and Key panel.
129
129
 
130
130
  **Type:** `string | GeoJSON.FeatureCollection`
131
131
 
132
- GeoJSON source. Provide a URL string for remote data, or a GeoJSON object for inline data. Use alongside `transformRequest` to add authentication or append bbox parameters to the request.
132
+ GeoJSON source. Provide a URL string for remote data, or a `FeatureCollection` object for inline data.
133
+
134
+ For data that needs authentication headers or viewport-based filtering, use `dynamicGeoJSON` instead.
135
+
136
+ ---
137
+
138
+ ### `dynamicGeoJSON`
139
+
140
+ **Type:** `Object`
141
+
142
+ Enables dynamic, bbox-aware GeoJSON fetching — the plugin calls your API as the map pans and zooms, loading features for the current viewport and evicting distant ones. Configure this instead of `geojson` when your data is too large to load all at once.
143
+
144
+ | Property | Type | Description |
145
+ |----------|------|-------------|
146
+ | `url` | `string` | **Required.** Base URL for the GeoJSON API endpoint |
147
+ | `idProperty` | `string` | **Required.** Property name that uniquely identifies each feature. Used for deduplication across viewport fetches |
148
+ | `transformRequest` | `Function` | Called before each fetch. Return a URL string or `{ url, headers }` object to add auth headers or modify the URL |
149
+ | `maxFeatures` | `number` | Optional. Cap on features held in memory across all viewport fetches. Older out-of-viewport features are evicted when exceeded |
150
+
151
+ **`transformRequest` signature:** `transformRequest(url, { bbox, zoom, dataset })`
152
+
153
+ | Argument | Type | Description |
154
+ |----------|------|-------------|
155
+ | `url` | `string` | The base URL |
156
+ | `bbox` | `number[]` | Current viewport bounds as `[west, south, east, north]` |
157
+ | `zoom` | `number` | Current map zoom level |
158
+ | `dataset` | `Object` | The full dataset configuration |
159
+
160
+ ```js
161
+ {
162
+ id: 'land-parcels',
163
+ dynamicGeoJSON: {
164
+ url: 'https://example.com/api/parcels',
165
+ idProperty: 'parcel_id',
166
+ transformRequest: (url, { bbox }) => {
167
+ const separator = url.includes('?') ? '&' : '?'
168
+ return {
169
+ url: `${url}${separator}bbox=${bbox.join(',')}`,
170
+ headers: { Authorization: `Bearer ${getToken()}` }
171
+ }
172
+ },
173
+ maxFeatures: 50000
174
+ },
175
+ minZoom: 10,
176
+ style: { stroke: '#d4351c', strokeWidth: 2 }
177
+ }
178
+ ```
133
179
 
134
180
  ---
135
181
 
136
182
  ### `tiles`
137
183
 
138
- **Type:** `string[]`
184
+ **Type:** `string | string[]`
139
185
 
140
- Array of vector tile URL templates (e.g. `https://example.com/tiles/{z}/{x}/{y}`). When set, the dataset uses a vector tile source instead of GeoJSON.
186
+ Vector tile URL template or array of templates (e.g. `'https://example.com/tiles/{z}/{x}/{y}'`). When set, the dataset uses a vector tile source instead of GeoJSON.
141
187
 
142
188
  ---
143
189
 
@@ -149,55 +195,44 @@ The layer name within the vector tile source to render. Required when using `til
149
195
 
150
196
  ---
151
197
 
152
- ### `transformRequest`
153
-
154
- **Type:** `Function`
155
-
156
- A function called before each fetch to transform the request. Its primary purpose is to attach authentication credentials — API keys, OAuth tokens, or other headers. It also receives the current viewport context so you can append bbox or zoom parameters to the URL if your API supports spatial filtering.
198
+ ### `idProperty`
157
199
 
158
- The plugin handles all dynamic fetching concerns (viewport tracking, debouncing, deduplication, caching, request cancellation) — `transformRequest` only needs to return the final URL and any headers.
200
+ **Type:** `string`
159
201
 
160
- **Signature:** `transformRequest(url, { bbox, zoom, dataset })`
202
+ Property name used to uniquely identify features in a static `geojson` source. When set, the plugin promotes this property to the MapLibre feature ID (`promoteId`) so that feature IDs are stable and derived from your data rather than auto-generated.
161
203
 
162
- | Argument | Type | Description |
163
- |----------|------|-------------|
164
- | `url` | `string` | The base URL from `geojson` |
165
- | `bbox` | `number[]` | Current viewport bounds as `[west, south, east, north]` |
166
- | `zoom` | `number` | Current map zoom level |
167
- | `dataset` | `Object` | The full dataset configuration |
204
+ Required for `setFeatureVisibility` to work correctly — the IDs you pass must match the values of this property in your data.
168
205
 
169
- Return either a plain URL string or an object `{ url, headers }`. The object form is needed when attaching auth headers.
206
+ > [!NOTE]
207
+ > For `dynamicGeoJSON` sources, set `idProperty` inside the `dynamicGeoJSON` object, not here.
170
208
 
171
209
  ```js
172
- // Auth headers only (no bbox filtering)
173
- transformRequest: (url) => ({
174
- url,
175
- headers: { Authorization: `Bearer ${getToken()}` }
176
- })
177
-
178
- // Append bbox to URL for server-side spatial filtering
179
- transformRequest: (url, { bbox }) => {
180
- const separator = url.includes('?') ? '&' : '?'
181
- return { url: `${url}${separator}bbox=${bbox.join(',')}` }
182
- }
183
-
184
- // Both — auth + bbox
185
- transformRequest: (url, { bbox }) => {
186
- const separator = url.includes('?') ? '&' : '?'
187
- return {
188
- url: `${url}${separator}bbox=${bbox.join(',')}`,
189
- headers: { Authorization: `Bearer ${getToken()}` }
190
- }
210
+ // Features have { properties: { parcel_id: 'ABC123', ... } }
211
+ {
212
+ id: 'my-parcels',
213
+ geojson: 'https://example.com/api/parcels',
214
+ idProperty: 'parcel_id'
191
215
  }
192
216
  ```
193
217
 
194
218
  ---
195
219
 
196
- ### `idProperty`
220
+ ### `generateIds`
197
221
 
198
- **Type:** `string`
222
+ **Type:** `boolean`
199
223
 
200
- Property name used to uniquely identify features. Required alongside `transformRequest` to enable dynamic bbox-based fetching the plugin uses it internally to deduplicate features across successive viewport fetches.
224
+ When `true`, MapLibre auto-generates integer IDs for GeoJSON features by their array index position (0-based). Use this when your features have no natural unique ID property and you need `setFeatureVisibility` to work.
225
+
226
+ > [!NOTE]
227
+ > Auto-generated IDs are positional and reset on every `setData` call. If your data changes between calls, the same integer ID may refer to a different feature. Prefer `idProperty` whenever your data has a stable unique field.
228
+
229
+ ```js
230
+ {
231
+ id: 'my-parcels',
232
+ geojson: 'https://example.com/api/parcels',
233
+ generateIds: true
234
+ }
235
+ ```
201
236
 
202
237
  ---
203
238
 
@@ -231,18 +266,10 @@ Maximum zoom level at which the dataset is visible.
231
266
 
232
267
  ---
233
268
 
234
- ### `maxFeatures`
235
-
236
- **Type:** `number`
237
-
238
- Only applies to dynamic sources (those using `transformRequest`). Caps the number of features held in memory across all viewport fetches — older out-of-viewport features are evicted when the limit is exceeded. Omit for small or bounded datasets; set it when users are likely to pan extensively over a large dataset.
239
-
240
- ---
241
-
242
- ### `visibility`
269
+ ### `visible`
243
270
 
244
- **Type:** `'visible' | 'hidden'`
245
- **Default:** `'visible'`
271
+ **Type:** `boolean`
272
+ **Default:** `true`
246
273
 
247
274
  Initial visibility of the dataset.
248
275
 
@@ -253,7 +280,7 @@ Initial visibility of the dataset.
253
280
  **Type:** `boolean`
254
281
  **Default:** `false`
255
282
 
256
- When `true`, the dataset appears in the Key panel with its style symbol and label.
283
+ When `true`, the dataset appears in the Key panel with its style symbol and label. Sublayers inherit this value — set `showInKey: false` on an individual sublayer to opt it out.
257
284
 
258
285
  ---
259
286
 
@@ -262,7 +289,7 @@ When `true`, the dataset appears in the Key panel with its style symbol and labe
262
289
  **Type:** `boolean`
263
290
  **Default:** `false`
264
291
 
265
- When `true`, the dataset appears in the LayersMenu panel and can be toggled on and off by the user.
292
+ When `true`, the dataset appears in the LayersMenu panel and can be toggled on and off by the user. Sublayers inherit this value — set `showInMenu: false` on an individual sublayer to opt it out.
266
293
 
267
294
  ---
268
295
 
@@ -367,7 +394,7 @@ style: {
367
394
 
368
395
  Array of sublayer rules that partition the dataset into visually distinct groups based on feature filters. Each sublayer is rendered as a separate map layer.
369
396
 
370
- Sublayers inherit the parent dataset's style and only override what they specify in their own `style` object. For polygon/line datasets, fill precedence is (highest to lowest): sublayer `fillPattern` sublayer `fill` parent `fillPattern` → parent `fill`. For symbol datasets, each symbol property is inherited individually from the parent unless the sublayer sets it explicitly.
397
+ Sublayer styles merge over the parent's the sublayer wins on any property it sets. Rendering type is driven by the merged result: `symbol` > `fillPattern`/`fill` > `stroke`.
371
398
 
372
399
  #### `Sublayer` properties
373
400
 
@@ -377,70 +404,71 @@ Sublayers inherit the parent dataset's style and only override what they specify
377
404
  | `label` | `string` | Human-readable name shown in the LayersMenu and Key panels |
378
405
  | `filter` | `FilterExpression` | MapLibre filter expression to match features for this sublayer |
379
406
  | `style` | `Object` | Style overrides. Accepts the same properties as the dataset `style` object |
380
- | `showInKey` | `boolean` | Shows this sublayer in the Key panel. Inherits from dataset if not set |
381
- | `showInMenu` | `boolean` | Shows this sublayer in the LayersMenu panel. **Default:** `false` |
407
+ | `showInKey` | `boolean` | Shows this sublayer in the Key panel. Inherits from the dataset when not set; explicit `false` overrides a dataset-level `true` |
408
+ | `showInMenu` | `boolean` | Shows this sublayer in the LayersMenu panel. Inherits from the dataset when not set; explicit `false` overrides a dataset-level `true` |
382
409
 
383
410
  **Polygon/line example:**
384
411
 
385
412
  ```js
386
- sublayers: [
387
- {
388
- id: 'active',
389
- label: 'Active parcels',
390
- filter: ['==', ['get', 'status'], 'active'],
391
- showInMenu: true,
392
- style: {
393
- stroke: '#00703c',
394
- fill: 'rgba(0,112,60,0.1)',
395
- symbolDescription: 'Green outline'
396
- }
397
- },
398
- {
399
- id: 'inactive',
400
- label: 'Inactive parcels',
401
- filter: ['==', ['get', 'status'], 'inactive'],
402
- showInMenu: true,
403
- style: {
404
- stroke: '#d4351c',
405
- fillPattern: 'diagonal-cross-hatch',
406
- fillPatternForegroundColor: '#d4351c'
413
+ {
414
+ id: 'field-parcels',
415
+ label: 'Field parcels',
416
+ geojson: parcelsData,
417
+ showInKey: true,
418
+ showInMenu: true,
419
+ sublayers: [
420
+ {
421
+ id: 'active',
422
+ label: 'Active parcels',
423
+ filter: ['==', ['get', 'status'], 'active'],
424
+ style: {
425
+ stroke: '#00703c',
426
+ fill: 'rgba(0,112,60,0.1)',
427
+ symbolDescription: 'Green outline'
428
+ }
429
+ },
430
+ {
431
+ id: 'inactive',
432
+ label: 'Inactive parcels',
433
+ filter: ['==', ['get', 'status'], 'inactive'],
434
+ style: {
435
+ stroke: '#d4351c',
436
+ fillPattern: 'diagonal-cross-hatch',
437
+ fillPatternForegroundColor: '#d4351c'
438
+ }
407
439
  }
408
- }
409
- ]
440
+ ]
441
+ }
410
442
  ```
411
443
 
412
444
  **Symbol (point) example — scheduled monuments by type:**
413
445
 
414
- When the parent dataset has `symbol` set, each sublayer can override individual symbol properties to represent different categories. Properties not set on the sublayer are inherited from the parent.
446
+ Here the parent defines the shared symbol shape; each sublayer only overrides what differs.
415
447
 
416
448
  ```js
417
449
  {
418
450
  id: 'scheduled-monuments',
419
451
  geojson: scheduledMonumentsData,
452
+ showInKey: true,
453
+ showInMenu: true,
420
454
  style: { symbol: 'square' },
421
455
  sublayers: [
422
456
  {
423
457
  id: 'prehistoric',
424
458
  label: 'Prehistoric sites',
425
459
  filter: ['==', ['get', 'type'], 'prehistoric'],
426
- showInKey: true,
427
- showInMenu: true,
428
460
  style: { symbolBackgroundColor: '#0f7a52' }
429
461
  },
430
462
  {
431
463
  id: 'roman',
432
464
  label: 'Roman sites',
433
465
  filter: ['==', ['get', 'type'], 'roman'],
434
- showInKey: true,
435
- showInMenu: true,
436
466
  style: { symbolBackgroundColor: '#54319f' }
437
467
  },
438
468
  {
439
469
  id: 'medieval',
440
470
  label: 'Medieval sites',
441
471
  filter: ['==', ['get', 'type'], 'medieval'],
442
- showInKey: true,
443
- showInMenu: true,
444
472
  style: { symbolBackgroundColor: '#ca357c' }
445
473
  }
446
474
  ]
@@ -520,26 +548,26 @@ datasetsPlugin.setDatasetVisibility(false, { datasetId: 'my-parcels', sublayerId
520
548
 
521
549
  ### `setFeatureVisibility(visible, featureIds, scope)`
522
550
 
523
- Show or hide specific features within a dataset without removing them from the source.
551
+ Show or hide specific features within a dataset without removing them from the source. The feature IDs you pass are matched against the dataset's `idProperty` value, or against the native feature `id` when `idProperty` is not set.
552
+
553
+ > [!NOTE]
554
+ > The dataset must have `idProperty` or `generateIds: true` configured for feature matching to work. A console warning is emitted if neither is set.
524
555
 
525
556
  | Argument | Type | Description |
526
557
  |----------|------|-------------|
527
558
  | `visible` | `boolean` | `true` to show, `false` to hide |
528
- | `featureIds` | `(string \| number)[]` | IDs of the features to target |
559
+ | `featureIds` | `(string \| number)[]` | IDs of the features to target — must match the `idProperty` values in your data |
529
560
  | `scope.datasetId` | `string` | ID of the dataset |
530
- | `scope.idProperty` | `string \| null` | Property name to match features on. Pass `null` to match against the top-level `feature.id` |
531
561
 
532
562
  ```js
533
- // Hide by a feature property
534
- datasetsPlugin.setFeatureVisibility(false, [123, 456], {
535
- datasetId: 'my-parcels',
536
- idProperty: 'parcel_id'
563
+ // Dataset configured with idProperty: 'parcel_id'
564
+ datasetsPlugin.setFeatureVisibility(false, ['ABC123', 'DEF456'], {
565
+ datasetId: 'my-parcels'
537
566
  })
538
567
 
539
- // Show using feature.id
540
- datasetsPlugin.setFeatureVisibility(true, [123, 456], {
541
- datasetId: 'my-parcels',
542
- idProperty: null
568
+ // Show previously hidden features
569
+ datasetsPlugin.setFeatureVisibility(true, ['ABC123'], {
570
+ datasetId: 'my-parcels'
543
571
  })
544
572
  ```
545
573
 
@@ -661,6 +689,26 @@ datasetsPlugin.setData(
661
689
 
662
690
  ---
663
691
 
692
+ ### `setGlobals(values)`
693
+
694
+ Set global state that applies across all datasets. Currently supports `opacityMode`.
695
+
696
+ | Argument | Type | Description |
697
+ |----------|------|-------------|
698
+ | `values.opacityMode` | `'dataset' \| 'global' \| 'multiply'` | Controls how opacity values are combined when both a global opacity and a per-dataset opacity are set |
699
+
700
+ | Mode | Behaviour |
701
+ |------|-----------|
702
+ | `'dataset'` | Each dataset uses its own `style.opacity` only. Global opacity is ignored |
703
+ | `'global'` | All datasets use the global opacity, ignoring per-dataset values |
704
+ | `'multiply'` | Effective opacity is `globalOpacity × datasetOpacity` |
705
+
706
+ ```js
707
+ datasetsPlugin.setGlobals({ opacityMode: 'multiply' })
708
+ ```
709
+
710
+ ---
711
+
664
712
  ## Events
665
713
 
666
714
  Subscribe to events using `interactiveMap.on()`.
@@ -295,7 +295,6 @@ Emitted when the user confirms their selection (clicks "Done").
295
295
 
296
296
  // If features were selected:
297
297
  selectedFeatures: [...],
298
- selectionBounds: [west, south, east, north],
299
298
 
300
299
  // If markers were selected:
301
300
  selectedMarkers: ['...']
@@ -340,10 +339,9 @@ Emitted whenever the selected features or selected markers change.
340
339
  ```js
341
340
  {
342
341
  selectedFeatures: [
343
- { featureId: '...', layerId: '...', properties: {...}, geometry: {...} }
342
+ { featureId: '...', layerId: '...', idProperty: '...', properties: {...} }
344
343
  ],
345
344
  selectedMarkers: ['...'], // array of selected marker IDs
346
- selectionBounds: [west, south, east, north] | null,
347
345
  contiguous: boolean // true when 2+ features are selected and all form a single contiguous group
348
346
  }
349
347
  ```
@@ -351,7 +349,6 @@ Emitted whenever the selected features or selected markers change.
351
349
  ```js
352
350
  interactiveMap.on('interact:selectionchange', (e) => {
353
351
  console.log('Selected features:', e.selectedFeatures)
354
- console.log('Bounds:', e.selectionBounds)
355
352
  })
356
353
  ```
357
354
 
@@ -91,12 +91,15 @@ const config = {
91
91
  sidebar: [
92
92
  { text: 'Basic map', href: '/examples/basic-map' },
93
93
  { text: 'Button-triggered map', href: '/examples/button-map' },
94
- { text: 'Add a marker with a panel', href: '/examples/add-marker-with-panel' },
94
+ { text: 'Map with marker and panel', href: '/examples/add-marker-with-panel' },
95
95
  { text: 'Toggle marker label', href: '/examples/toggle-marker-label' },
96
+ { text: 'Place a marker to continue', href: '/examples/place-marker' },
96
97
  { text: 'Add a search control', href: '/examples/search-control' },
97
98
  { text: 'Select a feature', href: '/examples/select-feature' },
98
99
  { text: 'Change map style', href: '/examples/style-switcher' },
99
- { text: 'Draw tools', href: '/examples/draw' },
100
+ { text: 'Draw tools', href: '/examples/draw-tools' },
101
+ { text: 'Add symbols', href: '/examples/add-symbols' },
102
+ { text: 'Add polygons', href: '/examples/add-polygons' },
100
103
  ],
101
104
  },
102
105
  {
@@ -1,8 +1,58 @@
1
1
  {
2
2
  "templates": [
3
3
  {
4
- "name": "Map page",
5
- "path": "/assets/templates/map.njk",
4
+ "name": "Basic map",
5
+ "path": "/assets/templates/basic-map.njk",
6
+ "type": "nunjucks"
7
+ },
8
+ {
9
+ "name": "Map with marker and panel",
10
+ "path": "/assets/templates/marker-panel.njk",
11
+ "type": "nunjucks"
12
+ },
13
+ {
14
+ "name": "Button-triggered map",
15
+ "path": "/assets/templates/button-map.njk",
16
+ "type": "nunjucks"
17
+ },
18
+ {
19
+ "name": "Toggle marker label",
20
+ "path": "/assets/templates/toggle-marker-label.njk",
21
+ "type": "nunjucks"
22
+ },
23
+ {
24
+ "name": "Place a marker to continue",
25
+ "path": "/assets/templates/place-marker.njk",
26
+ "type": "nunjucks"
27
+ },
28
+ {
29
+ "name": "Add a search control",
30
+ "path": "/assets/templates/search-control.njk",
31
+ "type": "nunjucks"
32
+ },
33
+ {
34
+ "name": "Select a feature",
35
+ "path": "/assets/templates/select-feature.njk",
36
+ "type": "nunjucks"
37
+ },
38
+ {
39
+ "name": "Change map style",
40
+ "path": "/assets/templates/style-switcher.njk",
41
+ "type": "nunjucks"
42
+ },
43
+ {
44
+ "name": "Draw tools",
45
+ "path": "/assets/templates/draw-tools.njk",
46
+ "type": "nunjucks"
47
+ },
48
+ {
49
+ "name": "Add symbols",
50
+ "path": "/assets/templates/add-symbols.njk",
51
+ "type": "nunjucks"
52
+ },
53
+ {
54
+ "name": "Add polygons",
55
+ "path": "/assets/templates/add-polygons.njk",
6
56
  "type": "nunjucks"
7
57
  }
8
58
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra/interactive-map",
3
- "version": "0.0.31-alpha",
3
+ "version": "0.0.33-alpha",
4
4
  "description": "An accessible map component",
5
5
  "repository": {
6
6
  "type": "git",
@@ -93,8 +93,7 @@
93
93
  .im-c-datasets-layers-group .im-c-datasets-layers__item:not(:last-child) {
94
94
  margin-bottom: 0;
95
95
  }
96
-
97
- .im-c-datasets-layers__item-label {
96
+ .im-c-datasets-layers__item .im-c-datasets-layers__item-label {
98
97
  width: 100%;
99
98
  max-width: none;
100
99
  align-items: start;
@@ -1 +1 @@
1
- import t from"@babel/runtime/helpers/asyncToGenerator";import e from"@babel/runtime/helpers/defineProperty";import{g as r,a,D as i,h as s,d as o}from"./im-datasets-plugin.js";import"preact/compat";import"preact/jsx-runtime";function l(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),r.push.apply(r,a)}return r}var y=(t,r,i)=>{var{hasStroke:s,strokeLayerId:o}=r;if(s&&!t.getLayer(o)){var y=function(t){for(var r=1;r<arguments.length;r++){var a=null!=arguments[r]?arguments[r]:{};r%2?l(Object(a),!0).forEach(function(r){e(t,r,a[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(a)):l(Object(a)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(a,e))})}return t}({"line-color":a(r.style.stroke,i),"line-width":r.style.strokeWidth||1,"line-opacity":r.opacity},r.style.strokeDashArray?{"line-dasharray":r.style.strokeDashArray}:{}),n=r.getStrokeSource(y);t.addLayer(n)}},n=(t,e,i,s,o,l)=>{var h,{sourceId:d,source:p}=e;p&&!t.getSource(d)&&t.addSource(d,p);var c=i.id;return((t,e,a,i,s)=>{var{hasSymbol:o,symbolLayerId:l}=e;if(o&&i&&l&&!t.getLayer(l)){var y=i.getSymbolDef(e.style);if(y){var n=i.getSymbolImageId(e.style,a,!1,s);if(n){var h=r(e.style,y);t.addLayer(e.getSymbolSource(n,h,y))}}}})(t,e,i,s,l),function(t,e,r,i){var s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,{hasFill:o,fillLayerId:l}=e;if(o&&l&&!t.getLayer(l)){var y=i.getPatternImageId(e.style,r,s),n=y?{"fill-pattern":y,"fill-opacity":e.opacity}:{"fill-color":a(e.style.fill,r),"fill-opacity":e.opacity};t.addLayer(e.getFillSource(n))}}(t,e,c,o,l),y(t,e,c),null!==(h=e.sublayers)&&void 0!==h&&h.length?(e.sublayers.forEach(e=>{n(t,e,i,s,o,l)}),d):e.isSublayer?void 0:d},h=t=>{var[e,r]=t,a=(t=>t<=.25?"left":t>=.75?"right":"")(e),i=(t=>t<=.25?"top":t>=.75?"bottom":"")(r);return i+(a&&i?"-":"")+a||"center"};function d(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),r.push.apply(r,a)}return r}function p(t){for(var r=1;r<arguments.length;r++){var a=null!=arguments[r]?arguments[r]:{};r%2?d(Object(a),!0).forEach(function(r){e(t,r,a[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(a)):d(Object(a)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(a,e))})}return t}class c extends i{get visibility(){return this.visible?"visible":"none"}get fillLayerId(){return this.hasSublayers||this.hasSymbol?null:this.hasFill?this.id:null}get strokeLayerId(){return this.hasSublayers||this.hasSymbol?null:this.hasStroke?this.hasFill?"".concat(this.id,"-stroke"):this.id:null}get symbolLayerId(){return this.hasSublayers?null:this.hasSymbol?this.id:null}get layerIds(){return this.hasSublayers?this.sublayers.flatMap(t=>t.layerIds).filter(Boolean):[this.symbolLayerId,this.fillLayerId,this.strokeLayerId].filter(Boolean)}getLayersWithValue(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=[];if(!1===e||this[e]){var a=[this.symbolLayerId,this.fillLayerId,this.strokeLayerId].filter(Boolean);if(a.length){var i=this[t];r.push({layerIds:a,[t]:i})}}return this.hasSublayers&&this.sublayers.forEach(a=>{(!1===e||a[e])&&r.push(a.getLayersWithValue(t)[0])}),r}getLayersWithVisibility(){return this.getLayersWithValue("visibility")}getLayersWithOpacity(){return this.getLayersWithValue("opacity")}getLayersWithFilters(){return this.getLayersWithValue("filter","hasHiddenFeatures")}get sourceId(){if(this.isSublayer)return this.parent.sourceId;if(this.hasDynamicGeoJSON)return this.dynamicGeoJSON.sourceId;if(this.tiles){var t=Array.isArray(this.tiles)?this.tiles.join(","):this.tiles;return"tiles-".concat(s(t))}return this.geojson?"string"==typeof this.geojson?"geojson-".concat(s(this.geojson)):"geojson-".concat(this.id):"source-".concat(this.id)}get source(){return this.hasDynamicGeoJSON?this.dynamicGeoJSON.source:this.tiles?{type:"vector",tiles:this.tiles,minzoom:this.minZoom||0,maxzoom:this.maxZoom||22}:this.geojson?{type:"geojson",data:this.geojson,generateId:!0}:null}getSymbolSource(t,e,r){return p({id:this.symbolLayerId,type:"symbol",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility,"icon-image":t,"icon-anchor":h(e||(null==r?void 0:r.anchor)||[.5,.5]),"icon-allow-overlap":!0}},this.filter?{filter:this.filter}:{})}getFillSource(t){return p({id:this.fillLayerId,type:"fill",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility},paint:t},this.filter?{filter:this.filter}:{})}getStrokeSource(t){return p({id:this.strokeLayerId,type:"line",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility},paint:t},this.filter?{filter:this.filter}:{})}get _hiddenFeaturesIdExpression(){return this.hasDynamicGeoJSON?this.dynamicGeoJSON.hiddenFeaturesIdExpression:["to-string",["id"]]}get _hiddenFeaturesFilter(){var t,e=null===(t=this.hiddenFeatures)||void 0===t?void 0:t.filter(t=>-1!==t);return null!=e&&e.length?["!",["in",this._hiddenFeaturesIdExpression,["literal",e.map(String)]]]:null}get filter(){var t,e=["all"];null!==(t=this.parent)&&void 0!==t&&t.filter&&e.push(this.parent.filter),this._datasetDefinition.filter&&e.push(this._datasetDefinition.filter);var r=this._hiddenFeaturesFilter;return r&&e.push(r),1===e.length?null:e.length>2?e:e[1]}}class u{constructor(t,e,r){this._mapProvider=t,this._map=t.map,this._symbolRegistry=e,this._patternRegistry=r,this._datasetSourceMap=new Map,window._datasetSourceMap=this._datasetSourceMap,this._symbolLayerIds=new Set}createDataset(t){return new c(t)}init(e){var r=this;return t(function*(){var{patternConfigs:t,symbolConfigs:a}=o.getPatternAndSymbolConfigs();yield r.addPatternsAndSymbolsToMap(t,a,e),r._symbolLayerIds.clear(),o.forEachDataset(t=>r._addLayers(t,e)),yield new Promise(t=>r._map.once("idle",t))})()}removeLayer(t){this._map.getLayer(t)&&this._map.removeLayer(t),this._symbolLayerIds.delete(t)}addPatternsAndSymbolsToMap(e,r,a){var i=this;return t(function*(){var t=a.id;return Promise.all([i._mapProvider.addPatternsToMap(e,t,i._patternRegistry),i._mapProvider.addSymbolsToMap(r,a,i._symbolRegistry)])})()}destroy(){var t=new Set;o.forEachDataset(e=>{var r=e.sourceId;this._getLayersUsingSource(r).forEach(t=>this.removeLayer(t)),!t.has(r)&&this._map.getSource(r)&&(this._map.removeSource(r),t.add(r))}),this._datasetSourceMap.clear()}onMapStyleChange(e,r){var a=this;return t(function*(){yield new Promise(t=>a._map.once("idle",t));var{patternConfigs:t,symbolConfigs:i}=o.getPatternAndSymbolConfigs();yield a.addPatternsAndSymbolsToMap(t,i,e),a._symbolLayerIds.clear(),o.forEachDataset(t=>{a._addLayers(t,e),a._applyFeatureFilter(t)}),r.forEach(t=>t.reapply())})()}onMapSizeChange(e){var r=this;return t(function*(){var{patternConfigs:t,symbolConfigs:a}=o.getPatternAndSymbolConfigs();yield r.addPatternsAndSymbolsToMap(t,a,e),o.forEach(t=>{var{fillLayerId:a,symbolLayerId:i}=t;if(i&&r._symbolLayerIds.has(i)&&r._map.getLayer(i)){var s=r._symbolRegistry.getSymbolImageId(t.style,e,!1,r._pixelRatio);s&&r._map.setLayoutProperty(i,"icon-image",s)}else if(a&&r._map.getLayer(a)){var o=r._patternRegistry.getPatternImageId(t.style,e.id,r._pixelRatio);o&&r._map.setPaintProperty(a,"fill-pattern",o)}})})()}addDataset(e,r){var a=this;return t(function*(){var t=o.getDataset(e);yield a.addPatternsAndSymbolsToMap(t.patternConfigs,t.symbolConfigs,r),a._addLayers(t,r)})()}removeDataset(t){var e=o.getDataset(t);if(e){var{sourceId:r,layerIds:a}=e;a.forEach(t=>this.removeLayer(t));var i=o.topLevelDatasets().filter(e=>e.id!==t&&e.sourceId===r).length>0;!i&&this._map.getSource(r)&&this._map.removeSource(r),this._datasetSourceMap.delete(t)}}applyFeatureFilter(t){var e=o.getDataset(t);e&&this._applyFeatureFilter(e)}applyStyle(e,r){var a=this;return t(function*(){var t=o.getDataset(e);t.layerIds.forEach(t=>a.removeLayer(t)),yield a.addPatternsAndSymbolsToMap(t.patternConfigs,t.symbolConfigs,r),a._addLayers(t,r)})()}applyDatasetOpacity(t){var e=o.getDataset(t);e&&this._applyRegistryDatasetOpacity(e)}_applyRegistryDatasetOpacity(t){t.getLayersWithOpacity().forEach(t=>{var{layerIds:e,opacity:r}=t;e.forEach(t=>this._setPaintOpacity(t,r))})}applyGlobalOpacity(){o.forEachDataset(t=>this._applyRegistryDatasetOpacity(t))}setData(t,e){var r=this._datasetSourceMap.get(t);if(r){var a=this._map.getSource(r);a&&"function"==typeof a.setData&&a.setData(e)}}get _pixelRatio(){return this._mapProvider.map.getPixelRatio()}_addLayers(t,e){var r=n(this._map,t,e,this._symbolRegistry,this._patternRegistry,this._pixelRatio);this._datasetSourceMap.set(t.id,r),this._maintainSymbolOrdering(t)}_getFirstSymbolLayerId(){var t,e=this._map.getStyle();if(null==e||!e.layers)return null;var r=e.layers.find(t=>this._symbolLayerIds.has(t.id));return null!==(t=null==r?void 0:r.id)&&void 0!==t?t:null}_maintainSymbolOrdering(t){var e=(t=t.isSublayer?t.parent:t).layerIds.filter(t=>t&&this._map.getLayer(t));e.forEach(t=>{var e;"symbol"===(null===(e=this._map.getLayer(t))||void 0===e?void 0:e.type)?this._symbolLayerIds.add(t):this._symbolLayerIds.delete(t)});var r=this._getFirstSymbolLayerId();r&&e.forEach(t=>{this._symbolLayerIds.has(t)||this._map.moveLayer(t,r)})}applyDatasetVisibility(t){var e=o.getDataset(t);e&&this._applyRegistryDatasetVisibility(e)}_applyRegistryDatasetVisibility(t){t.getLayersWithVisibility().forEach(t=>{var{layerIds:e,visibility:r}=t;e.forEach(t=>{this._map.getLayer(t)&&this._map.setLayoutProperty(t,"visibility",r)})})}applyGlobalVisibility(){o.forEachDataset(t=>this._applyRegistryDatasetVisibility(t))}_applyFeatureFilter(t){t.getLayersWithFilters().forEach(t=>{var{layerIds:e,filter:r}=t;e.forEach(t=>{this._map.getLayer(t)&&this._map.setFilter(t,r)})})}_setPaintOpacity(t,e){var r=this._map.getLayer(t);if(r){var a={line:"line-opacity",symbol:"icon-opacity"}[r.type]||"fill-opacity";this._map.setPaintProperty(t,a,e)}}_getLayersUsingSource(t){var e=this._map.getStyle();return null!=e&&e.layers?e.layers.filter(e=>e.source===t).map(t=>t.id):[]}}export{u as default};
1
+ import t from"@babel/runtime/helpers/asyncToGenerator";import e from"@babel/runtime/helpers/defineProperty";import{g as r,a as i,D as a,h as s,l as o,d as l}from"./im-datasets-plugin.js";import"preact/compat";import"preact/jsx-runtime";function y(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),r.push.apply(r,i)}return r}var n=(t,r,a)=>{var{hasStroke:s,strokeLayerId:o}=r;if(s&&!t.getLayer(o)){var l=function(t){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?y(Object(i),!0).forEach(function(r){e(t,r,i[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):y(Object(i)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))})}return t}({"line-color":i(r.style.stroke,a),"line-width":r.style.strokeWidth||1,"line-opacity":r.opacity},r.style.strokeDashArray?{"line-dasharray":r.style.strokeDashArray}:{}),n=r.getStrokeSource(l);t.addLayer(n)}},h=(t,e,a,s,o,l)=>{var y,{sourceId:d,source:p}=e;p&&!t.getSource(d)&&t.addSource(d,p);var u=a.id;return((t,e,i,a,s)=>{var{hasSymbol:o,symbolLayerId:l}=e;if(o&&a&&l&&!t.getLayer(l)){var y=a.getSymbolDef(e.style);if(y){var n=a.getSymbolImageId(e.style,i,!1,s);if(n){var h=r(e.style,y);t.addLayer(e.getSymbolSource(n,h,y))}}}})(t,e,a,s,l),function(t,e,r,a){var s=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,{hasFill:o,fillLayerId:l}=e;if(o&&l&&!t.getLayer(l)){var y=a.getPatternImageId(e.style,r,s),n=y?{"fill-pattern":y,"fill-opacity":e.opacity}:{"fill-color":i(e.style.fill,r),"fill-opacity":e.opacity};t.addLayer(e.getFillSource(n))}}(t,e,u,o,l),n(t,e,u),null!==(y=e.sublayers)&&void 0!==y&&y.length?(e.sublayers.forEach(e=>{h(t,e,a,s,o,l)}),d):e.isSublayer?void 0:d},d=t=>{var[e,r]=t,i=(t=>t<=.25?"left":t>=.75?"right":"")(e),a=(t=>t<=.25?"top":t>=.75?"bottom":"")(r);return a+(i&&a?"-":"")+i||"center"};function p(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),r.push.apply(r,i)}return r}function u(t){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?p(Object(i),!0).forEach(function(r){e(t,r,i[r])}):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(i)):p(Object(i)).forEach(function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(i,e))})}return t}class c extends a{get visibility(){return this.visible?"visible":"none"}get fillLayerId(){return this.hasSublayers||this.hasSymbol?null:this.hasFill?this.id:null}get strokeLayerId(){return this.hasSublayers||this.hasSymbol?null:this.hasStroke?this.hasFill?"".concat(this.id,"-stroke"):this.id:null}get symbolLayerId(){return this.hasSublayers?null:this.hasSymbol?this.id:null}get layerIds(){return this.hasSublayers?this.sublayers.flatMap(t=>t.layerIds).filter(Boolean):[this.symbolLayerId,this.fillLayerId,this.strokeLayerId].filter(Boolean)}getLayersWithValue(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],r=[];if(!1===e||this[e]){var i=[this.symbolLayerId,this.fillLayerId,this.strokeLayerId].filter(Boolean);if(i.length){var a=this[t];r.push({layerIds:i,[t]:a})}}return this.hasSublayers&&this.sublayers.forEach(i=>{(!1===e||i[e])&&r.push(i.getLayersWithValue(t)[0])}),r}getLayersWithVisibility(){return this.getLayersWithValue("visibility")}getLayersWithOpacity(){return this.getLayersWithValue("opacity")}getLayersWithFilters(){return this.getLayersWithValue("filter","hasHiddenFeatures")}get sourceId(){if(this.isSublayer)return this.parent.sourceId;if(this.hasDynamicGeoJSON)return this.dynamicGeoJSON.sourceId;if(this.tiles){var t=Array.isArray(this.tiles)?this.tiles.join(","):this.tiles;return"tiles-".concat(s(t))}return this.geojson?"string"==typeof this.geojson?"geojson-".concat(s(this.geojson)):"geojson-".concat(this.id):"source-".concat(this.id)}_geojsonIdStrategy(){var t;return this.idProperty?{promoteId:this.idProperty}:this.generateIds?{generateId:!0}:(null!==(t=this.geojson)&&void 0!==t&&null!==(t=t.features)&&void 0!==t&&t.some(t=>"string"==typeof t.id)&&o.warn('Dataset "'.concat(this.id,'" has GeoJSON features with string native IDs. MapLibre only surfaces integer native feature IDs through queryRenderedFeatures. Use idProperty to promote a string property instead.')),{})}get source(){if(this.hasDynamicGeoJSON)return this.dynamicGeoJSON.source;if(this.tiles){var t={type:"vector",tiles:this.tiles,minzoom:this.minZoom||0,maxzoom:this.maxZoom||22};return this.idProperty&&this.sourceLayer&&(t.promoteId={[this.sourceLayer]:this.idProperty}),t}return this.geojson?u({type:"geojson",data:this.geojson},this._geojsonIdStrategy()):null}getSymbolSource(t,e,r){return u({id:this.symbolLayerId,type:"symbol",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility,"icon-image":t,"icon-anchor":d(e||(null==r?void 0:r.anchor)||[.5,.5]),"icon-allow-overlap":!0}},this.filter?{filter:this.filter}:{})}getFillSource(t){return u({id:this.fillLayerId,type:"fill",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility},paint:t},this.filter?{filter:this.filter}:{})}getStrokeSource(t){return u({id:this.strokeLayerId,type:"line",source:this.sourceId,"source-layer":this.sourceLayer,minzoom:this.minZoom,maxzoom:this.maxZoom,layout:{visibility:this.visibility},paint:t},this.filter?{filter:this.filter}:{})}get _hiddenFeaturesIdExpression(){return this.hasDynamicGeoJSON?this.dynamicGeoJSON.hiddenFeaturesIdExpression:this.idProperty?["to-string",["get",this.idProperty]]:["to-string",["id"]]}get _hiddenFeaturesFilter(){var t,e=null===(t=this.hiddenFeatures)||void 0===t?void 0:t.filter(t=>-1!==t);return null!=e&&e.length?["!",["in",this._hiddenFeaturesIdExpression,["literal",e.map(String)]]]:null}get filter(){var t,e=["all"];null!==(t=this.parent)&&void 0!==t&&t.filter&&e.push(this.parent.filter),this._datasetDefinition.filter&&e.push(this._datasetDefinition.filter);var r=this._hiddenFeaturesFilter;return r&&e.push(r),1===e.length?null:e.length>2?e:e[1]}}class m{constructor(t,e,r){this._mapProvider=t,this._map=t.map,this._symbolRegistry=e,this._patternRegistry=r,this._datasetSourceMap=new Map,window._datasetSourceMap=this._datasetSourceMap,this._symbolLayerIds=new Set}createDataset(t){return new c(t)}init(e){var r=this;return t(function*(){var{patternConfigs:t,symbolConfigs:i}=l.getPatternAndSymbolConfigs();yield r.addPatternsAndSymbolsToMap(t,i,e),r._symbolLayerIds.clear(),l.forEachDataset(t=>r._addLayers(t,e)),yield new Promise(t=>r._map.once("idle",t))})()}removeLayer(t){this._map.getLayer(t)&&this._map.removeLayer(t),this._symbolLayerIds.delete(t)}addPatternsAndSymbolsToMap(e,r,i){var a=this;return t(function*(){var t=i.id;return Promise.all([a._mapProvider.addPatternsToMap(e,t,a._patternRegistry),a._mapProvider.addSymbolsToMap(r,i,a._symbolRegistry)])})()}destroy(){var t=new Set;l.forEachDataset(e=>{var r=e.sourceId;this._getLayersUsingSource(r).forEach(t=>this.removeLayer(t)),!t.has(r)&&this._map.getSource(r)&&(this._map.removeSource(r),t.add(r))}),this._datasetSourceMap.clear()}onMapStyleChange(e,r){var i=this;return t(function*(){yield new Promise(t=>i._map.once("idle",t));var{patternConfigs:t,symbolConfigs:a}=l.getPatternAndSymbolConfigs();yield i.addPatternsAndSymbolsToMap(t,a,e),i._symbolLayerIds.clear(),l.forEachDataset(t=>{i._addLayers(t,e),i._applyFeatureFilter(t)}),r.forEach(t=>t.reapply())})()}onMapSizeChange(e){var r=this;return t(function*(){var{patternConfigs:t,symbolConfigs:i}=l.getPatternAndSymbolConfigs();yield r.addPatternsAndSymbolsToMap(t,i,e),l.forEach(t=>{var{fillLayerId:i,symbolLayerId:a}=t;if(a&&r._symbolLayerIds.has(a)&&r._map.getLayer(a)){var s=r._symbolRegistry.getSymbolImageId(t.style,e,!1,r._pixelRatio);s&&r._map.setLayoutProperty(a,"icon-image",s)}else if(i&&r._map.getLayer(i)){var o=r._patternRegistry.getPatternImageId(t.style,e.id,r._pixelRatio);o&&r._map.setPaintProperty(i,"fill-pattern",o)}})})()}addDataset(e,r){var i=this;return t(function*(){var t=l.getDataset(e);yield i.addPatternsAndSymbolsToMap(t.patternConfigs,t.symbolConfigs,r),i._addLayers(t,r)})()}removeDataset(t){var e=l.getDataset(t);if(e){var{sourceId:r,layerIds:i}=e;i.forEach(t=>this.removeLayer(t));var a=l.topLevelDatasets().filter(e=>e.id!==t&&e.sourceId===r).length>0;!a&&this._map.getSource(r)&&this._map.removeSource(r),this._datasetSourceMap.delete(t)}}applyFeatureFilter(t){var e=l.getDataset(t);e&&this._applyFeatureFilter(e)}applyStyle(e,r){var i=this;return t(function*(){var t=l.getDataset(e);t.layerIds.forEach(t=>i.removeLayer(t)),yield i.addPatternsAndSymbolsToMap(t.patternConfigs,t.symbolConfigs,r),i._addLayers(t,r)})()}applyDatasetOpacity(t){var e=l.getDataset(t);e&&this._applyRegistryDatasetOpacity(e)}_applyRegistryDatasetOpacity(t){t.getLayersWithOpacity().forEach(t=>{var{layerIds:e,opacity:r}=t;e.forEach(t=>this._setPaintOpacity(t,r))})}applyGlobalOpacity(){l.forEachDataset(t=>this._applyRegistryDatasetOpacity(t))}setData(t,e){var r=this._datasetSourceMap.get(t);if(r){var i=this._map.getSource(r);i&&"function"==typeof i.setData&&i.setData(e)}}get _pixelRatio(){return this._mapProvider.map.getPixelRatio()}_addLayers(t,e){var r=h(this._map,t,e,this._symbolRegistry,this._patternRegistry,this._pixelRatio);this._datasetSourceMap.set(t.id,r),this._maintainSymbolOrdering(t)}_getFirstSymbolLayerId(){var t,e=this._map.getStyle();if(null==e||!e.layers)return null;var r=e.layers.find(t=>this._symbolLayerIds.has(t.id));return null!==(t=null==r?void 0:r.id)&&void 0!==t?t:null}_maintainSymbolOrdering(t){var e=(t=t.isSublayer?t.parent:t).layerIds.filter(t=>t&&this._map.getLayer(t));e.forEach(t=>{var e;"symbol"===(null===(e=this._map.getLayer(t))||void 0===e?void 0:e.type)?this._symbolLayerIds.add(t):this._symbolLayerIds.delete(t)});var r=this._getFirstSymbolLayerId();r&&e.forEach(t=>{this._symbolLayerIds.has(t)||this._map.moveLayer(t,r)})}applyDatasetVisibility(t){var e=l.getDataset(t);e&&this._applyRegistryDatasetVisibility(e)}_applyRegistryDatasetVisibility(t){t.getLayersWithVisibility().forEach(t=>{var{layerIds:e,visibility:r}=t;e.forEach(t=>{this._map.getLayer(t)&&this._map.setLayoutProperty(t,"visibility",r)})})}applyGlobalVisibility(){l.forEachDataset(t=>this._applyRegistryDatasetVisibility(t))}_applyFeatureFilter(t){t.getLayersWithFilters().forEach(t=>{var{layerIds:e,filter:r}=t;e.forEach(t=>{this._map.getLayer(t)&&this._map.setFilter(t,r)})})}_setPaintOpacity(t,e){var r=this._map.getLayer(t);if(r){var i={line:"line-opacity",symbol:"icon-opacity"}[r.type]||"fill-opacity";this._map.setPaintProperty(t,i,e)}}_getLayersUsingSource(t){var e=this._map.getStyle();return null!=e&&e.layers?e.layers.filter(e=>e.source===t).map(t=>t.id):[]}}export{m as default};