@communitiesuk/svelte-component-library 0.1.18 → 0.2.0-alpha.2

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 (97) hide show
  1. package/README.md +30 -6
  2. package/dist/assets/css/base.css +9 -0
  3. package/dist/assets/css/code-block.css +116 -0
  4. package/dist/assets/css/components.css +47 -0
  5. package/dist/assets/css/fonts.css +19 -0
  6. package/dist/assets/css/govuk-additional.css +142 -0
  7. package/dist/assets/css/govuk-frontend.min.css +2 -2
  8. package/dist/assets/css/moduk.css +1 -0
  9. package/dist/assets/css/moj-frontend.min copy.css +4108 -0
  10. package/dist/assets/css/moj-frontend.min.css +2 -0
  11. package/dist/assets/css/moj-frontend.min.css.map +1 -0
  12. package/dist/assets/css/utilities.css +0 -0
  13. package/dist/assets/images/govuk-crest.svg +1 -1
  14. package/dist/assets/js/govuk-frontend.min.js +1 -0
  15. package/dist/assets/js/moj-frontend.min.js +1 -0
  16. package/dist/assets/rebrand/images/favicon.ico +0 -0
  17. package/dist/assets/rebrand/images/favicon.svg +1 -0
  18. package/dist/assets/rebrand/images/govuk-crest.svg +1 -0
  19. package/dist/assets/rebrand/images/govuk-icon-180.png +0 -0
  20. package/dist/assets/rebrand/images/govuk-icon-192.png +0 -0
  21. package/dist/assets/rebrand/images/govuk-icon-512.png +0 -0
  22. package/dist/assets/rebrand/images/govuk-icon-mask.svg +1 -0
  23. package/dist/assets/rebrand/images/govuk-opengraph-image.png +0 -0
  24. package/dist/assets/rebrand/manifest.json +39 -0
  25. package/dist/components/data-vis/line-chart/Line.svelte +48 -40
  26. package/dist/components/data-vis/line-chart/Line.svelte.d.ts +6 -4
  27. package/dist/components/data-vis/line-chart/LineChart.svelte +145 -36
  28. package/dist/components/data-vis/line-chart/LineChart.svelte.d.ts +25 -9
  29. package/dist/components/data-vis/line-chart/Lines.svelte +10 -23
  30. package/dist/components/data-vis/line-chart/Lines.svelte.d.ts +8 -4
  31. package/dist/components/data-vis/line-chart/Marker.svelte +31 -5
  32. package/dist/components/data-vis/line-chart/Marker.svelte.d.ts +6 -2
  33. package/dist/components/data-vis/line-chart/SeriesLabel.svelte +7 -8
  34. package/dist/components/data-vis/line-chart/SeriesLabel.svelte.d.ts +2 -2
  35. package/dist/components/data-vis/line-chart/ValueLabel.svelte +26 -34
  36. package/dist/components/data-vis/line-chart/ValueLabel.svelte.d.ts +8 -4
  37. package/dist/components/data-vis/map/Map.svelte +299 -71
  38. package/dist/components/data-vis/map/Map.svelte.d.ts +39 -12
  39. package/dist/components/data-vis/map/NonStandardControls.svelte +10 -1
  40. package/dist/components/data-vis/map/NonStandardControls.svelte.d.ts +12 -11
  41. package/dist/components/data-vis/map/Tooltip.svelte +3 -4
  42. package/dist/components/data-vis/map/Tooltip.svelte.d.ts +0 -2
  43. package/dist/components/data-vis/map/mapUtils.d.ts +2 -0
  44. package/dist/components/data-vis/map/mapUtils.js +50 -0
  45. package/dist/components/data-vis/table/Table.svelte +28 -40
  46. package/dist/components/data-vis/table/Table.svelte.d.ts +0 -2
  47. package/dist/components/layout/Breadcrumbs.svelte +10 -12
  48. package/dist/components/layout/Breadcrumbs.svelte.d.ts +1 -0
  49. package/dist/components/layout/Footer.svelte +69 -4
  50. package/dist/components/layout/Footer.svelte.d.ts +3 -0
  51. package/dist/components/layout/Header.svelte +56 -16
  52. package/dist/components/layout/Header.svelte.d.ts +1 -0
  53. package/dist/components/layout/InternalHeader.svelte +155 -150
  54. package/dist/components/layout/InternalHeader.svelte.d.ts +1 -0
  55. package/dist/components/ui/Button.svelte +78 -4
  56. package/dist/components/ui/Button.svelte.d.ts +2 -0
  57. package/dist/components/ui/CookieBanner.svelte +356 -0
  58. package/dist/components/ui/CookieBanner.svelte.d.ts +18 -0
  59. package/dist/components/ui/FilterPanel.svelte +167 -158
  60. package/dist/components/ui/FilterPanel.svelte.d.ts +2 -0
  61. package/dist/components/ui/Masthead.svelte +35 -23
  62. package/dist/components/ui/Masthead.svelte.d.ts +2 -0
  63. package/dist/components/ui/PostcodeOrAreaSearch.svelte +200 -0
  64. package/dist/components/ui/PostcodeOrAreaSearch.svelte.d.ts +37 -0
  65. package/dist/components/ui/Search.svelte +2 -2
  66. package/dist/components/ui/SearchAutocomplete.svelte +104 -14
  67. package/dist/components/ui/SearchAutocomplete.svelte.d.ts +4 -0
  68. package/dist/data/IMD2019.json +32846 -0
  69. package/dist/data/places.csv +20039 -0
  70. package/dist/data/places.json +100192 -0
  71. package/dist/data/svgFontDimensions.json +90 -0
  72. package/dist/data/testData.json +52632 -0
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.js +2 -0
  75. package/dist/package-wrapping/BaseInformation.svelte +0 -33
  76. package/dist/package-wrapping/SidebarContainer.svelte +0 -7
  77. package/dist/utils/area-search/geoConfig.d.ts +435 -0
  78. package/dist/utils/area-search/geoConfig.js +291 -0
  79. package/dist/utils/cookiesNavigation.d.ts +44 -0
  80. package/dist/utils/cookiesNavigation.js +63 -0
  81. package/dist/utils/data-transformations/convert-csv-to-json-proper.cjs +88 -0
  82. package/dist/utils/data-transformations/convert-csv-to-json-proper.d.cts +1 -0
  83. package/dist/utils/data-transformations/convertCSV.d.ts +6 -0
  84. package/dist/utils/data-transformations/convertCSV.js +40 -21
  85. package/dist/utils/text-string-conversion/textStringConversion.d.ts +6 -0
  86. package/dist/utils/text-string-conversion/textStringConversion.js +10 -0
  87. package/package.json +18 -7
  88. package/dist/components/ui/Breadcrumbs.svelte +0 -198
  89. package/dist/components/ui/Breadcrumbs.svelte.d.ts +0 -24
  90. package/dist/components/ui/Footer.svelte +0 -171
  91. package/dist/components/ui/Footer.svelte.d.ts +0 -30
  92. package/dist/components/ui/Header.svelte +0 -43
  93. package/dist/components/ui/Header.svelte.d.ts +0 -7
  94. package/dist/components/ui/ServiceNavigation.svelte +0 -143
  95. package/dist/components/ui/ServiceNavigation.svelte.d.ts +0 -13
  96. package/dist/components/ui/SideNavigation.svelte +0 -346
  97. package/dist/components/ui/SideNavigation.svelte.d.ts +0 -25
@@ -2,17 +2,19 @@
2
2
  import {
3
3
  MapLibre,
4
4
  GeoJSON,
5
+ VectorTileSource,
5
6
  FillLayer,
6
7
  LineLayer,
7
8
  zoomTransition,
8
9
  Control,
9
10
  ControlButton,
10
11
  ControlGroup,
12
+ ScaleControl,
11
13
  } from "svelte-maplibre";
12
14
  import { contrastingColor } from "./colors.js";
13
15
  import { colorbrewer } from "./colorbrewer.js";
14
16
  import { hoverStateFilter } from "svelte-maplibre/filters.js";
15
- import type { LngLatLike } from "maplibre-gl";
17
+ import type { LngLatLike, LngLatBoundsLike } from "maplibre-gl";
16
18
  import type { FeatureCollection } from "geojson";
17
19
  import fullTopo from "./fullTopo.json";
18
20
  import * as topojson from "topojson-client";
@@ -22,21 +24,22 @@
22
24
  filterGeo,
23
25
  jenksBreaks,
24
26
  quantileBreaks,
27
+ createPaintObjectFromMetric,
28
+ extractVectorMetricValues,
25
29
  } from "./mapUtils.js";
26
30
  import NonStandardControls from "./NonStandardControls.svelte";
27
31
  import { replaceState } from "$app/navigation";
28
32
  import { page } from "$app/state";
29
33
  import { joinData } from "./dataJoin.js";
30
34
 
31
- import maplibregl from "maplibre-gl";
32
- const { LngLatBounds } = maplibregl;
35
+ import maplibre from "maplibre-gl";
36
+ const { LngLatBounds } = maplibre;
33
37
 
34
- import type { LngLatBoundsLike } from "maplibre-gl";
35
38
  let {
36
39
  data,
37
- customPallet,
38
- setCustomPallet,
39
- interactive,
40
+ customPalette,
41
+ setCustomPalette = false,
42
+ interactive = true,
40
43
  cooperativeGestures = true,
41
44
  standardControls = true,
42
45
  navigationControl,
@@ -52,43 +55,74 @@
52
55
  colorPalette = "YlGnBu",
53
56
  showBorder = false,
54
57
  maxBorderWidth = 1.5,
55
- tooltip,
58
+ tooltip = true,
56
59
  clickToZoom = true,
57
- geoType,
58
- year,
59
- metric,
60
+ geoType = "ltla",
61
+ year = 2024,
62
+ metric = "Residual household waste",
60
63
  breaksType = "quantile",
61
- customBreaks,
64
+ customBreaks = [20, 40, 60, 80, 100],
62
65
  numberOfBreaks = 5,
63
66
  fillOpacity = 0.5,
64
67
  changeOpacityOnHover = true,
65
68
  hoverOpacity = 0.8,
66
69
  center = [-2.5, 53],
67
70
  zoom = 5,
68
- minZoom,
69
- maxZoom,
70
- maxBoundsCoords,
71
+ minZoom = 6,
72
+ maxZoom = 14,
73
+ maxBoundsCoords = [
74
+ [-10, 49],
75
+ [5, 60],
76
+ ],
71
77
  hash = false,
72
78
  updateHash = (u) => {
73
79
  replaceState(u, page.state);
74
80
  },
75
81
  useInitialHash = true,
76
82
  mapHeight = 200,
77
- setMaxBounds,
83
+ setMaxBounds = false,
84
+ onload,
85
+ onerror,
86
+ onclick,
87
+ ondblclick,
88
+ onmousemove,
89
+ oncontextmenu,
90
+ onmovestart,
91
+ onmoveend,
92
+ onzoomstart,
93
+ onzoom,
94
+ onzoomend,
95
+ onpitch,
96
+ onrotate,
97
+ onwheel,
98
+ ondata,
99
+ onstyleload,
100
+ onstyledata,
101
+ onidle,
102
+ geoSource = "file",
103
+ tileSource = "http://localhost:8080/{z}/{x}/{y}.pbf",
104
+ geojsonPromoteId = "areanm",
105
+ vectorMetricProperty = "Index of Multiple Deprivation (IMD) Decile",
106
+ vectorLayerName = "LSOA",
107
+ borderColor = "#003300",
108
+ labelSourceLayer = "place",
109
+ externalData = null,
110
+ showLegend = false,
78
111
  }: {
79
112
  data: object[];
80
- customPallet: object[] | undefined;
113
+ paintObject?: object;
114
+ customPalette?: object[];
81
115
  cooperativeGestures?: boolean;
82
116
  standardControls?: boolean;
83
117
  navigationControl?: boolean;
84
- navigationControlPosition?: string;
118
+ navigationControlPosition?: maplibregl.ControlPosition;
85
119
  geolocateControl?: boolean;
86
- geolocateControlPosition?: string;
120
+ geolocateControlPosition?: maplibregl.ControlPosition;
87
121
  fullscreenControl?: boolean;
88
- fullscreenControlPosition?: string;
122
+ fullscreenControlPosition?: maplibregl.ControlPosition;
89
123
  scaleControl?: boolean;
90
- scaleControlPosition?: string;
91
- scaleControlUnit?: string;
124
+ scaleControlPosition?: maplibregl.ControlPosition;
125
+ scaleControlUnit?: "imperial" | "metric" | "nautical";
92
126
  styleSheet?: string | URL | object;
93
127
  colorPalette?: string;
94
128
  showBorder?: boolean;
@@ -101,9 +135,9 @@
101
135
  breaksType?: string;
102
136
  numberOfBreaks?: number;
103
137
  fillOpacity?: number;
104
- changeOpacityOnHover: boolean;
138
+ changeOpacityOnHover?: boolean;
105
139
  hoverOpacity?: number;
106
- center?: LngLatLike | undefined;
140
+ center?: LngLatLike;
107
141
  zoom?: number;
108
142
  minZoom?: number | undefined;
109
143
  maxZoom?: number | undefined;
@@ -113,18 +147,56 @@
113
147
  updateHash?: (URL) => void;
114
148
  useInitialHash?: boolean;
115
149
  mapHeight?: number;
116
- setCustomPallet?: boolean;
150
+ setCustomPalette?: boolean;
117
151
  customBreaks?: number[];
118
- interactive: boolean;
152
+ interactive?: boolean;
153
+ showLegend: boolean;
154
+ onload?: (map: maplibregl.Map) => void;
155
+ onerror?: (error: Partial<ErrorEvent>) => void;
156
+ onclick?: (e: maplibregl.MapMouseEvent) => void;
157
+ ondblclick?: (e: maplibregl.MapMouseEvent) => void;
158
+ onmousemove?: (e: maplibregl.MapMouseEvent) => void;
159
+ oncontextmenu?: (e: maplibregl.MapMouseEvent) => void;
160
+ onmovestart?: (e: MapMoveEvent) => void;
161
+ onmoveend?: (e: MapMoveEvent) => void;
162
+ onzoomstart?: (e: maplibregl.MapLibreZoomEvent) => void;
163
+ onzoom?: (e: maplibregl.MapLibreZoomEvent) => void;
164
+ onzoomend?: (e: maplibregl.MapLibreZoomEvent) => void;
165
+ onpitch?: (
166
+ e: maplibregl.MapLibreEvent<MouseEvent | TouchEvent | undefined>,
167
+ ) => void;
168
+ onrotate?: (
169
+ e: maplibregl.MapLibreEvent<MouseEvent | TouchEvent | undefined>,
170
+ ) => void;
171
+ onwheel?: (e: maplibregl.MapWheelEvent) => void;
172
+ ondata?: (e: maplibregl.MapDataEvent) => void;
173
+ onstyleload?: (e: StyleLoadEvent) => void;
174
+ onstyledata?: (e: maplibregl.MapStyleDataEvent) => void;
175
+ onidle?: (e: maplibregl.MapLibreEvent) => void;
176
+ geoSource: "file" | "tiles" | "none";
177
+ tileSource?: string;
178
+ geojsonPromoteId?: string;
179
+ vectorMetricProperty?: string;
180
+ vectorLayerName?: string;
181
+ borderColor?: string;
182
+ labelSourceLayer?: string;
183
+ externalData?: object;
119
184
  } = $props();
120
185
 
186
+ const tileSourceId = "lsoas";
187
+ const promoteProperty = "LSOA21NM";
188
+
121
189
  let styleLookup = {
122
190
  "Carto-light":
123
191
  "https://basemaps.cartocdn.com/gl/positron-gl-style/style.json",
124
192
  "Carto-dark":
125
193
  "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json",
126
194
  };
127
- let style = $derived(styleLookup[styleSheet] ?? styleSheet);
195
+ let style = $derived(
196
+ typeof styleSheet == "string"
197
+ ? (styleLookup[styleSheet] ?? styleSheet)
198
+ : styleSheet,
199
+ );
128
200
 
129
201
  let breakCount = $derived(
130
202
  breaksType == "custom" ? customBreaks.length : numberOfBreaks,
@@ -147,13 +219,18 @@
147
219
  let filteredGeoJsonData = $derived(filterGeo(geojsonData, year));
148
220
 
149
221
  let fillColors: string[] = $derived(
150
- setCustomPallet == true
151
- ? customPallet
222
+ setCustomPalette == true
223
+ ? customPalette
152
224
  : colorbrewer[colorPalette][breakCount],
153
225
  );
154
226
 
155
- let borderColor = "#003300";
227
+ let tooFewColors = $derived(fillColors.length < breakCount);
156
228
 
229
+ $effect(() => {
230
+ if (tooFewColors) {
231
+ console.warn("Too few colours for the number of breaks");
232
+ }
233
+ });
157
234
  let map: maplibregl.Map | undefined = $state();
158
235
 
159
236
  let loaded = $state(false);
@@ -202,7 +279,28 @@
202
279
  map?.cooperativeGestures.disable();
203
280
  }
204
281
 
282
+ if (interactive) {
283
+ map?.scrollZoom.enable();
284
+ map?.boxZoom.enable();
285
+ map?.dragRotate.enable();
286
+ map?.dragPan.enable();
287
+ map?.keyboard.enable();
288
+ map?.doubleClickZoom.enable();
289
+ map?.touchZoomRotate.enable();
290
+ } else {
291
+ map?.scrollZoom.disable();
292
+ map?.boxZoom.disable();
293
+ map?.dragRotate.disable();
294
+ map?.dragPan.disable();
295
+ map?.keyboard.disable();
296
+ map?.doubleClickZoom.disable();
297
+ map?.touchZoomRotate.disable();
298
+ }
299
+
205
300
  map?.setMaxBounds(bounds);
301
+
302
+ map?.setMaxZoom(maxZoom);
303
+ map?.setMinZoom(minZoom);
206
304
  });
207
305
 
208
306
  let vals = $derived(
@@ -216,6 +314,16 @@
216
314
  ? quantileBreaks(vals, breakCount)
217
315
  : customBreaks,
218
316
  );
317
+ let vectorPaintObject = $derived(
318
+ externalData != null
319
+ ? createPaintObjectFromMetric(metric, breaks, fillColors, fillOpacity)
320
+ : createPaintObjectFromMetric(
321
+ vectorMetricProperty,
322
+ breaks,
323
+ fillColors,
324
+ fillOpacity,
325
+ ),
326
+ );
219
327
 
220
328
  let dataWithColor = $derived(
221
329
  filteredMapData.map((d) => {
@@ -226,6 +334,23 @@
226
334
  }),
227
335
  );
228
336
 
337
+ let legendItems = $derived([
338
+ ...breaks
339
+ .map((b, i) => {
340
+ const from = b;
341
+ const to = breaks[i + 1];
342
+ return {
343
+ color: fillColors[i],
344
+ label: to ? `${from} – ${to}` : `${from}+`,
345
+ };
346
+ })
347
+ .slice(0, fillColors.length),
348
+ {
349
+ color: "lightgrey",
350
+ label: "No data",
351
+ },
352
+ ]);
353
+
229
354
  let merged = $derived(joinData(filteredGeoJsonData, dataWithColor));
230
355
 
231
356
  let hoveredArea = $state();
@@ -283,24 +408,43 @@
283
408
  : zoom;
284
409
 
285
410
  let bounds = $derived(
286
- setMaxBounds ? convertToLngLatBounds(maxBoundsCoords) : undefined,
411
+ setMaxBounds
412
+ ? maxBoundsCoords
413
+ ? convertToLngLatBounds(maxBoundsCoords)
414
+ : undefined
415
+ : undefined,
287
416
  );
288
417
  </script>
289
418
 
290
- <div style="height: {mapHeight}px;">
419
+ <div style="position: relative; height: {mapHeight}px;">
291
420
  <MapLibre
292
421
  bind:map
293
422
  bind:loaded
294
423
  {style}
295
424
  {center}
296
425
  {zoom}
297
- {maxZoom}
298
- {minZoom}
299
426
  standardControls={interactive && standardControls}
300
427
  {hash}
301
428
  {updateHash}
302
- {interactive}
303
429
  class="map"
430
+ {onload}
431
+ {onidle}
432
+ {onerror}
433
+ {onclick}
434
+ {ondblclick}
435
+ {onmousemove}
436
+ {oncontextmenu}
437
+ {onmovestart}
438
+ {onmoveend}
439
+ {onzoomstart}
440
+ {onzoom}
441
+ {onzoomend}
442
+ {onpitch}
443
+ {onrotate}
444
+ {onwheel}
445
+ {ondata}
446
+ {onstyleload}
447
+ {onstyledata}
304
448
  >
305
449
  {#if interactive && !standardControls}
306
450
  <NonStandardControls
@@ -329,64 +473,148 @@
329
473
  </button>
330
474
  </ControlGroup>
331
475
  </Control>
476
+ {:else if !interactive}
477
+ <ScaleControl position={scaleControlPosition} unit={scaleControlUnit} />
332
478
  {/if}
333
-
334
- <GeoJSON id="areas" data={merged} promoteId="areanm">
335
- <FillLayer
336
- paint={{
337
- "fill-color": ["coalesce", ["get", "color"], "lightgrey"],
338
- "fill-opacity": changeOpacityOnHover
339
- ? hoverStateFilter(fillOpacity, hoverOpacity)
340
- : fillOpacity,
341
- }}
342
- beforeLayerType="symbol"
343
- manageHoverState={interactive}
344
- onclick={interactive ? (e) => zoomToArea(e) : null}
345
- onmousemove={interactive
346
- ? (e) => {
347
- hoveredArea = e.features[0].id;
348
- hoveredAreaData = e.features[0].properties.metric;
349
- currentMousePosition = e.event.point;
350
- }
351
- : null}
352
- onmouseleave={interactive
353
- ? () => {
354
- hoveredArea = null;
355
- hoveredAreaData = null;
356
- }
357
- : null}
358
- />
359
- {#if showBorder}
360
- <LineLayer
361
- layout={{ "line-cap": "round", "line-join": "round" }}
479
+ {#if geoSource == "file"}
480
+ <GeoJSON id="areas" data={merged} promoteId={geojsonPromoteId}>
481
+ <FillLayer
482
+ id="main-fill-layer"
362
483
  paint={{
363
- "line-color": hoverStateFilter(borderColor, "orange"),
364
- "line-width": zoomTransition(3, 0, 12, maxBorderWidth),
484
+ "fill-color": ["coalesce", ["get", "color"], "lightgrey"],
485
+ "fill-opacity": changeOpacityOnHover
486
+ ? hoverStateFilter(fillOpacity, hoverOpacity)
487
+ : fillOpacity,
365
488
  }}
366
489
  beforeLayerType="symbol"
490
+ manageHoverState={interactive}
491
+ onclick={interactive ? (e) => zoomToArea(e) : undefined}
492
+ onmousemove={interactive
493
+ ? (e) => {
494
+ hoveredArea = e.features[0].id;
495
+ hoveredAreaData = e.features[0].properties.metric;
496
+ currentMousePosition = e.event.point;
497
+ }
498
+ : undefined}
499
+ onmouseleave={interactive
500
+ ? () => {
501
+ hoveredArea = null;
502
+ hoveredAreaData = null;
503
+ }
504
+ : undefined}
367
505
  />
368
- {/if}
369
- </GeoJSON>
506
+ {#if showBorder}
507
+ <LineLayer
508
+ id="border-layer"
509
+ layout={{ "line-cap": "round", "line-join": "round" }}
510
+ paint={{
511
+ "line-color": hoverStateFilter(borderColor, "orange"),
512
+ "line-width": zoomTransition(3, 0, 12, maxBorderWidth),
513
+ }}
514
+ beforeLayerType="symbol"
515
+ />
516
+ {/if}
517
+ </GeoJSON>
518
+ {:else if geoSource == "tiles"}
519
+ <VectorTileSource
520
+ id={tileSourceId}
521
+ promoteId={promoteProperty}
522
+ tiles={[tileSource]}
523
+ >
524
+ <FillLayer
525
+ paint={vectorPaintObject}
526
+ sourceLayer={vectorLayerName}
527
+ onclick={interactive ? zoomToArea : undefined}
528
+ onmousemove={interactive
529
+ ? (e) => {
530
+ if (e.features?.[0]) {
531
+ hoveredArea = e.features[0].id;
532
+ hoveredAreaData =
533
+ e.features[0].properties[vectorMetricProperty];
534
+ currentMousePosition = e.event.point;
535
+ }
536
+ }
537
+ : undefined}
538
+ onmouseleave={interactive
539
+ ? () => {
540
+ hoveredArea = null;
541
+ hoveredAreaData = null;
542
+ }
543
+ : undefined}
544
+ />
545
+ {#if showBorder}
546
+ <LineLayer
547
+ layout={{ "line-cap": "round", "line-join": "round" }}
548
+ paint={{
549
+ "line-color": hoverStateFilter(borderColor, "orange"),
550
+ "line-width": zoomTransition(
551
+ minZoom ?? 3,
552
+ 0,
553
+ maxZoom ?? 14,
554
+ maxBorderWidth,
555
+ ),
556
+ }}
557
+ beforeLayerType="symbol"
558
+ sourceLayer={vectorLayerName}
559
+ />
560
+ {/if}
561
+ </VectorTileSource>
562
+ {:else}
563
+ <p>No data</p>
564
+ {/if}
370
565
 
566
+ <!-- Important note: sourceLayer must match `-l` value from tippecanoe -->
371
567
  {#if interactive && tooltip}
372
568
  <Tooltip
373
569
  {currentMousePosition}
374
570
  {hoveredArea}
375
571
  {hoveredAreaData}
376
- {year}
377
- {metric}
572
+ metric={geoSource == "tiles" ? vectorMetricProperty : metric}
378
573
  />
379
574
  {/if}
380
575
  </MapLibre>
381
576
  </div>
577
+ {#if showLegend}
578
+ <div class="legend">
579
+ {#each legendItems as item}
580
+ <div class="legend-item">
581
+ <div class="legend-color" style="background-color: {item.color};"></div>
582
+ <span>{item.label}</span>
583
+ </div>
584
+ {/each}
585
+ </div>
586
+ {/if}
382
587
 
383
588
  <style>
384
589
  :global(.maplibregl-ctrl-group button.reset-button) {
385
590
  /* margin: 10px; */
386
591
  width: -moz-fit-content;
387
592
  width: fit-content;
388
- padding: 0px 10px;
593
+ padding: 5px 10px;
389
594
  font-size: 16px;
390
595
  height: 100%;
391
596
  }
597
+ .legend {
598
+ position: absolute;
599
+ bottom: 20px;
600
+ left: 10px;
601
+ background: white;
602
+ padding: 10px;
603
+ border-radius: 4px;
604
+ font-size: 12px;
605
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
606
+ }
607
+
608
+ .legend-item {
609
+ display: flex;
610
+ align-items: center;
611
+ margin-bottom: 4px;
612
+ }
613
+
614
+ .legend-color {
615
+ width: 20px;
616
+ height: 20px;
617
+ margin-right: 8px;
618
+ border: 1px solid #ccc;
619
+ }
392
620
  </style>
@@ -1,19 +1,19 @@
1
- import type { LngLatLike } from "maplibre-gl";
2
- import type { LngLatBoundsLike } from "maplibre-gl";
1
+ import type { LngLatLike, LngLatBoundsLike } from "maplibre-gl";
3
2
  type $$ComponentProps = {
4
3
  data: object[];
5
- customPallet: object[] | undefined;
4
+ paintObject?: object;
5
+ customPalette?: object[];
6
6
  cooperativeGestures?: boolean;
7
7
  standardControls?: boolean;
8
8
  navigationControl?: boolean;
9
- navigationControlPosition?: string;
9
+ navigationControlPosition?: maplibregl.ControlPosition;
10
10
  geolocateControl?: boolean;
11
- geolocateControlPosition?: string;
11
+ geolocateControlPosition?: maplibregl.ControlPosition;
12
12
  fullscreenControl?: boolean;
13
- fullscreenControlPosition?: string;
13
+ fullscreenControlPosition?: maplibregl.ControlPosition;
14
14
  scaleControl?: boolean;
15
- scaleControlPosition?: string;
16
- scaleControlUnit?: string;
15
+ scaleControlPosition?: maplibregl.ControlPosition;
16
+ scaleControlUnit?: "imperial" | "metric" | "nautical";
17
17
  styleSheet?: string | URL | object;
18
18
  colorPalette?: string;
19
19
  showBorder?: boolean;
@@ -26,9 +26,9 @@ type $$ComponentProps = {
26
26
  breaksType?: string;
27
27
  numberOfBreaks?: number;
28
28
  fillOpacity?: number;
29
- changeOpacityOnHover: boolean;
29
+ changeOpacityOnHover?: boolean;
30
30
  hoverOpacity?: number;
31
- center?: LngLatLike | undefined;
31
+ center?: LngLatLike;
32
32
  zoom?: number;
33
33
  minZoom?: number | undefined;
34
34
  maxZoom?: number | undefined;
@@ -38,9 +38,36 @@ type $$ComponentProps = {
38
38
  updateHash?: (URL: any) => void;
39
39
  useInitialHash?: boolean;
40
40
  mapHeight?: number;
41
- setCustomPallet?: boolean;
41
+ setCustomPalette?: boolean;
42
42
  customBreaks?: number[];
43
- interactive: boolean;
43
+ interactive?: boolean;
44
+ showLegend: boolean;
45
+ onload?: (map: maplibregl.Map) => void;
46
+ onerror?: (error: Partial<ErrorEvent>) => void;
47
+ onclick?: (e: maplibregl.MapMouseEvent) => void;
48
+ ondblclick?: (e: maplibregl.MapMouseEvent) => void;
49
+ onmousemove?: (e: maplibregl.MapMouseEvent) => void;
50
+ oncontextmenu?: (e: maplibregl.MapMouseEvent) => void;
51
+ onmovestart?: (e: MapMoveEvent) => void;
52
+ onmoveend?: (e: MapMoveEvent) => void;
53
+ onzoomstart?: (e: maplibregl.MapLibreZoomEvent) => void;
54
+ onzoom?: (e: maplibregl.MapLibreZoomEvent) => void;
55
+ onzoomend?: (e: maplibregl.MapLibreZoomEvent) => void;
56
+ onpitch?: (e: maplibregl.MapLibreEvent<MouseEvent | TouchEvent | undefined>) => void;
57
+ onrotate?: (e: maplibregl.MapLibreEvent<MouseEvent | TouchEvent | undefined>) => void;
58
+ onwheel?: (e: maplibregl.MapWheelEvent) => void;
59
+ ondata?: (e: maplibregl.MapDataEvent) => void;
60
+ onstyleload?: (e: StyleLoadEvent) => void;
61
+ onstyledata?: (e: maplibregl.MapStyleDataEvent) => void;
62
+ onidle?: (e: maplibregl.MapLibreEvent) => void;
63
+ geoSource: "file" | "tiles" | "none";
64
+ tileSource?: string;
65
+ geojsonPromoteId?: string;
66
+ vectorMetricProperty?: string;
67
+ vectorLayerName?: string;
68
+ borderColor?: string;
69
+ labelSourceLayer?: string;
70
+ externalData?: object;
44
71
  };
45
72
  declare const Map: import("svelte").Component<$$ComponentProps, {}, "">;
46
73
  type Map = ReturnType<typeof Map>;
@@ -1,5 +1,4 @@
1
1
  <script lang="ts">
2
- //@ts-nocheck
3
2
  import {
4
3
  FullscreenControl,
5
4
  GeolocateControl,
@@ -17,6 +16,16 @@
17
16
  scaleControl,
18
17
  scaleControlPosition = "bottom-left",
19
18
  scaleControlUnit = "metric",
19
+ }: {
20
+ navigationControl?: boolean;
21
+ navigationControlPosition?: maplibregl.ControlPosition;
22
+ geolocateControl?: boolean;
23
+ geolocateControlPosition?: maplibregl.ControlPosition;
24
+ fullscreenControl?: boolean;
25
+ fullscreenControlPosition?: maplibregl.ControlPosition;
26
+ scaleControl?: boolean;
27
+ scaleControlPosition?: maplibregl.ControlPosition;
28
+ scaleControlUnit?: "imperial" | "metric" | "nautical";
20
29
  } = $props();
21
30
  </script>
22
31
 
@@ -1,13 +1,14 @@
1
- declare const NonStandardControls: import("svelte").Component<{
2
- navigationControl: any;
3
- navigationControlPosition?: string;
4
- geolocateControl: any;
5
- geolocateControlPosition?: string;
6
- fullscreenControl: any;
7
- fullscreenControlPosition?: string;
8
- scaleControl: any;
9
- scaleControlPosition?: string;
10
- scaleControlUnit?: string;
11
- }, {}, "">;
1
+ type $$ComponentProps = {
2
+ navigationControl?: boolean;
3
+ navigationControlPosition?: maplibregl.ControlPosition;
4
+ geolocateControl?: boolean;
5
+ geolocateControlPosition?: maplibregl.ControlPosition;
6
+ fullscreenControl?: boolean;
7
+ fullscreenControlPosition?: maplibregl.ControlPosition;
8
+ scaleControl?: boolean;
9
+ scaleControlPosition?: maplibregl.ControlPosition;
10
+ scaleControlUnit?: "imperial" | "metric" | "nautical";
11
+ };
12
+ declare const NonStandardControls: import("svelte").Component<$$ComponentProps, {}, "">;
12
13
  type NonStandardControls = ReturnType<typeof NonStandardControls>;
13
14
  export default NonStandardControls;
@@ -1,8 +1,8 @@
1
1
  <script>
2
- let { currentMousePosition, hoveredArea, hoveredAreaData, year, metric } =
3
- $props();
2
+ let { currentMousePosition, hoveredArea, hoveredAreaData, metric } = $props();
4
3
  let tooltipHeight = $state();
5
4
  let tooltipWidth = $state();
5
+
6
6
  // $inspect(tooltipHeight, tooltipWidth, currentMousePosition);
7
7
  </script>
8
8
 
@@ -15,8 +15,7 @@
15
15
  >
16
16
  <p>{hoveredArea}</p>
17
17
  <p class="detail">
18
- {year}
19
- {metric}: {isNaN(hoveredAreaData) ? "No data" : hoveredAreaData}
18
+ {metric}: {hoveredAreaData ?? "No data"}
20
19
  </p>
21
20
  </div>
22
21
  {/if}
@@ -7,13 +7,11 @@ declare const Tooltip: import("svelte").Component<{
7
7
  currentMousePosition: any;
8
8
  hoveredArea: any;
9
9
  hoveredAreaData: any;
10
- year: any;
11
10
  metric: any;
12
11
  }, {}, "">;
13
12
  type $$ComponentProps = {
14
13
  currentMousePosition: any;
15
14
  hoveredArea: any;
16
15
  hoveredAreaData: any;
17
- year: any;
18
16
  metric: any;
19
17
  };