@sjvair/monitor-map 4.2.0 → 5.0.0-beta.0

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 (265) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -126
  3. package/dist/lib/MonitorDetailPanel.svelte +23 -20
  4. package/dist/lib/MonitorMapLayout.svelte +147 -77
  5. package/dist/lib/abort.d.ts +16 -0
  6. package/dist/lib/abort.js +51 -0
  7. package/dist/lib/components/DataBox.svelte +4 -1
  8. package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
  9. package/dist/lib/config.svelte.d.ts +7 -0
  10. package/dist/lib/config.svelte.js +10 -0
  11. package/dist/lib/core.d.ts +2 -2
  12. package/dist/lib/core.js +2 -1
  13. package/dist/lib/data-chart/DataChart.svelte +54 -24
  14. package/dist/lib/data-chart/DateRange.d.ts +13 -4
  15. package/dist/lib/data-chart/DateRange.js +50 -14
  16. package/dist/lib/data-chart/chart-utils.js +5 -7
  17. package/dist/lib/data-chart/level-colors.d.ts +3 -4
  18. package/dist/lib/data-chart/level-colors.js +7 -4
  19. package/dist/lib/data-chart/pacific-time.d.ts +9 -0
  20. package/dist/lib/data-chart/pacific-time.js +25 -0
  21. package/dist/lib/data-chart/requests.d.ts +2 -1
  22. package/dist/lib/data-chart/requests.js +5 -2
  23. package/dist/lib/data-chart/tooltip.js +2 -2
  24. package/{src/lib/ev-stations/components/EvStationTooltip.svelte → dist/lib/ev-stations/EvPopup.svelte} +6 -5
  25. package/dist/lib/ev-stations/EvPopup.svelte.d.ts +7 -0
  26. package/dist/lib/ev-stations/ev-plugin.svelte.d.ts +14 -0
  27. package/dist/lib/ev-stations/ev-plugin.svelte.js +71 -0
  28. package/dist/lib/ev-stations/ev-station-icons.d.ts +1 -4
  29. package/dist/lib/ev-stations/ev-station-icons.js +1 -13
  30. package/dist/lib/ev-stations/ev-stations.d.ts +7 -0
  31. package/dist/lib/ev-stations/ev-stations.js +53 -0
  32. package/dist/lib/ev-stations/ev-store.svelte.d.ts +21 -0
  33. package/dist/lib/ev-stations/ev-store.svelte.js +83 -0
  34. package/dist/lib/ev-stations/station-popup.svelte.d.ts +14 -0
  35. package/dist/lib/ev-stations/station-popup.svelte.js +54 -0
  36. package/dist/lib/ev-stations/types.d.ts +0 -29
  37. package/dist/lib/ev-stations/zip-codes.d.ts +11 -0
  38. package/dist/lib/ev-stations/zip-codes.js +28 -16
  39. package/dist/lib/index.d.ts +8 -56
  40. package/dist/lib/index.js +7 -46
  41. package/dist/lib/legend/Legend.svelte +18 -19
  42. package/dist/lib/legend/Legend.svelte.d.ts +2 -2
  43. package/dist/lib/levels.d.ts +7 -0
  44. package/dist/lib/levels.js +19 -0
  45. package/dist/lib/map/MapShell.svelte +17 -24
  46. package/dist/lib/map/MapShell.svelte.d.ts +4 -4
  47. package/dist/lib/map/basemaps.d.ts +25 -0
  48. package/dist/lib/map/basemaps.js +66 -0
  49. package/dist/lib/map/live-map.svelte.d.ts +3 -0
  50. package/dist/lib/map/live-map.svelte.js +22 -0
  51. package/dist/lib/map/sync-plugins.svelte.d.ts +19 -0
  52. package/dist/lib/map/sync-plugins.svelte.js +52 -0
  53. package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +82 -82
  54. package/dist/lib/monitors/filtered-source.svelte.d.ts +9 -0
  55. package/dist/lib/monitors/filtered-source.svelte.js +28 -0
  56. package/dist/lib/monitors/monitor-details.svelte.js +11 -3
  57. package/dist/lib/monitors/monitors.svelte.d.ts +29 -26
  58. package/dist/lib/monitors/monitors.svelte.js +35 -126
  59. package/dist/lib/monitors/retry-load.d.ts +8 -0
  60. package/dist/lib/monitors/retry-load.js +11 -0
  61. package/dist/lib/monitors/subscriptions.d.ts +3 -0
  62. package/dist/lib/monitors/subscriptions.js +9 -0
  63. package/dist/lib/monitors/types.d.ts +1 -41
  64. package/dist/lib/options/map-option-defaults.d.ts +25 -36
  65. package/dist/lib/options/map-option-defaults.js +12 -30
  66. package/dist/lib/options/map-options.svelte.d.ts +13 -0
  67. package/dist/lib/options/map-options.svelte.js +26 -0
  68. package/dist/lib/options/menus/LayersMenu.svelte +8 -20
  69. package/dist/lib/options/menus/LayersMenu.svelte.d.ts +17 -2
  70. package/dist/lib/options/menus/MonitorsMenu.svelte +34 -18
  71. package/dist/lib/options/menus/OverlaysMenu.svelte +2 -2
  72. package/dist/lib/options/menus/PollutantMenu.svelte +4 -9
  73. package/dist/lib/options/menus/SettingsMenu.svelte +32 -25
  74. package/dist/lib/options/menus/SettingsMenu.svelte.d.ts +5 -16
  75. package/dist/lib/options/plugin-order.d.ts +8 -0
  76. package/dist/lib/options/plugin-order.js +36 -0
  77. package/dist/lib/options/pollutant-param.d.ts +7 -5
  78. package/dist/lib/options/pollutant-param.js +9 -5
  79. package/dist/lib/options/row-icons.d.ts +8 -0
  80. package/dist/lib/options/row-icons.js +15 -0
  81. package/dist/lib/options/rows/MarkerIcon.svelte +5 -5
  82. package/dist/lib/options/rows/MarkerIcon.svelte.d.ts +1 -2
  83. package/dist/lib/search/Search.svelte +20 -33
  84. package/dist/lib/search/Search.svelte.d.ts +5 -1
  85. package/dist/lib/search/search-pin.svelte.d.ts +11 -0
  86. package/dist/lib/search/search-pin.svelte.js +28 -0
  87. package/dist/lib/search/service.d.ts +7 -2
  88. package/dist/lib/search/service.js +17 -10
  89. package/dist/lib/stores.svelte.d.ts +8 -0
  90. package/dist/lib/stores.svelte.js +9 -0
  91. package/dist/lib/wind/wind-plugin.d.ts +11 -0
  92. package/dist/lib/wind/wind-plugin.js +25 -0
  93. package/package.json +12 -10
  94. package/src/lib/MonitorDetailPanel.svelte +23 -20
  95. package/src/lib/MonitorMapLayout.svelte +147 -77
  96. package/src/lib/abort.ts +59 -0
  97. package/src/lib/components/DataBox.svelte +4 -1
  98. package/src/lib/config.svelte.ts +16 -0
  99. package/src/lib/core.ts +2 -2
  100. package/src/lib/data-chart/DataChart.svelte +54 -24
  101. package/src/lib/data-chart/DateRange.ts +58 -15
  102. package/src/lib/data-chart/chart-utils.ts +6 -7
  103. package/src/lib/data-chart/level-colors.ts +8 -9
  104. package/src/lib/data-chart/pacific-time.ts +31 -0
  105. package/src/lib/data-chart/requests.ts +14 -7
  106. package/src/lib/data-chart/tooltip.ts +2 -2
  107. package/{dist/lib/ev-stations/components/EvStationTooltip.svelte → src/lib/ev-stations/EvPopup.svelte} +6 -5
  108. package/src/lib/ev-stations/ev-plugin.svelte.ts +86 -0
  109. package/src/lib/ev-stations/ev-station-icons.ts +1 -17
  110. package/src/lib/ev-stations/ev-stations.ts +72 -0
  111. package/src/lib/ev-stations/ev-store.svelte.ts +117 -0
  112. package/src/lib/ev-stations/station-popup.svelte.ts +64 -0
  113. package/src/lib/ev-stations/types.ts +0 -34
  114. package/src/lib/ev-stations/zip-codes.ts +29 -16
  115. package/src/lib/index.ts +8 -99
  116. package/src/lib/legend/Legend.svelte +18 -19
  117. package/src/lib/levels.ts +24 -0
  118. package/src/lib/map/MapShell.svelte +17 -24
  119. package/src/lib/map/basemaps.ts +76 -0
  120. package/src/lib/map/live-map.svelte.ts +24 -0
  121. package/src/lib/map/sync-plugins.svelte.ts +69 -0
  122. package/src/lib/monitors/components/MonitorSubscriptionManager.svelte +82 -82
  123. package/src/lib/monitors/filtered-source.svelte.ts +38 -0
  124. package/src/lib/monitors/monitor-details.svelte.ts +12 -3
  125. package/src/lib/monitors/monitors.svelte.ts +62 -153
  126. package/src/lib/monitors/retry-load.ts +14 -0
  127. package/src/lib/monitors/subscriptions.ts +17 -0
  128. package/src/lib/monitors/types.ts +1 -47
  129. package/src/lib/options/map-option-defaults.ts +30 -53
  130. package/src/lib/options/map-options.svelte.ts +30 -0
  131. package/src/lib/options/menus/LayersMenu.svelte +8 -20
  132. package/src/lib/options/menus/MonitorsMenu.svelte +34 -18
  133. package/src/lib/options/menus/OverlaysMenu.svelte +2 -2
  134. package/src/lib/options/menus/PollutantMenu.svelte +4 -9
  135. package/src/lib/options/menus/SettingsMenu.svelte +32 -25
  136. package/src/lib/options/plugin-order.ts +38 -0
  137. package/src/lib/options/pollutant-param.ts +14 -9
  138. package/src/lib/options/row-icons.ts +17 -0
  139. package/src/lib/options/rows/MarkerIcon.svelte +5 -5
  140. package/src/lib/search/Search.svelte +20 -33
  141. package/src/lib/search/search-pin.svelte.ts +35 -0
  142. package/src/lib/search/service.ts +34 -15
  143. package/src/lib/stores.svelte.ts +15 -0
  144. package/src/lib/wind/wind-plugin.ts +33 -0
  145. package/dist/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  146. package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +0 -7
  147. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +0 -7
  148. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +0 -18
  149. package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +0 -21
  150. package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +0 -113
  151. package/dist/lib/collocation-sites/collocations.svelte.d.ts +0 -9
  152. package/dist/lib/collocation-sites/collocations.svelte.js +0 -17
  153. package/dist/lib/collocation-sites/types.d.ts +0 -8
  154. package/dist/lib/collocation-sites/types.js +0 -1
  155. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  156. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +0 -7
  157. package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +0 -7
  158. package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +0 -19
  159. package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +0 -131
  160. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +0 -31
  161. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +0 -226
  162. package/dist/lib/ev-stations/ev-stations.svelte.d.ts +0 -9
  163. package/dist/lib/ev-stations/ev-stations.svelte.js +0 -55
  164. package/dist/lib/hms/hms-fire-icon-manager.d.ts +0 -13
  165. package/dist/lib/hms/hms-fire-icon-manager.js +0 -39
  166. package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +0 -23
  167. package/dist/lib/hms/hms-fire-map-integration.svelte.js +0 -94
  168. package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +0 -39
  169. package/dist/lib/hms/hms-smoke-map-integration.svelte.js +0 -87
  170. package/dist/lib/hms/hms.svelte.d.ts +0 -19
  171. package/dist/lib/hms/hms.svelte.js +0 -227
  172. package/dist/lib/legend/LegendBar.svelte +0 -45
  173. package/dist/lib/legend/LegendBar.svelte.d.ts +0 -7
  174. package/dist/lib/legend/legend-data.d.ts +0 -40
  175. package/dist/lib/legend/legend-data.js +0 -65
  176. package/dist/lib/map/Map.svelte +0 -13
  177. package/dist/lib/map/Map.svelte.d.ts +0 -8
  178. package/dist/lib/map/basemap.d.ts +0 -14
  179. package/dist/lib/map/basemap.js +0 -10
  180. package/dist/lib/map/icons.d.ts +0 -7
  181. package/dist/lib/map/icons.js +0 -33
  182. package/dist/lib/map/integrations/base-layer-seperator.d.ts +0 -9
  183. package/dist/lib/map/integrations/base-layer-seperator.js +0 -11
  184. package/dist/lib/map/integrations/click-manager.d.ts +0 -14
  185. package/dist/lib/map/integrations/click-manager.js +0 -52
  186. package/dist/lib/map/integrations/integrations-manager.d.ts +0 -8
  187. package/dist/lib/map/integrations/integrations-manager.js +0 -20
  188. package/dist/lib/map/integrations/map-display-option.svelte.d.ts +0 -7
  189. package/dist/lib/map/integrations/map-display-option.svelte.js +0 -10
  190. package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +0 -32
  191. package/dist/lib/map/integrations/map-geojson-integration.svelte.js +0 -60
  192. package/dist/lib/map/integrations/map-icon-manager.d.ts +0 -15
  193. package/dist/lib/map/integrations/map-icon-manager.js +0 -52
  194. package/dist/lib/map/integrations/map-integration.svelte.d.ts +0 -6
  195. package/dist/lib/map/integrations/map-integration.svelte.js +0 -2
  196. package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +0 -11
  197. package/dist/lib/map/integrations/map-layer-integration.svelte.js +0 -40
  198. package/dist/lib/map/integrations/tooltip.svelte.d.ts +0 -36
  199. package/dist/lib/map/integrations/tooltip.svelte.js +0 -131
  200. package/dist/lib/map/integrations/types.d.ts +0 -14
  201. package/dist/lib/map/integrations/types.js +0 -1
  202. package/dist/lib/map/map-manager.svelte.d.ts +0 -20
  203. package/dist/lib/map/map-manager.svelte.js +0 -63
  204. package/dist/lib/map/map-style-state.svelte.d.ts +0 -23
  205. package/dist/lib/map/map-style-state.svelte.js +0 -86
  206. package/dist/lib/map/utils.d.ts +0 -7
  207. package/dist/lib/map/utils.js +0 -36
  208. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  209. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +0 -7
  210. package/dist/lib/monitors/components/MonitorTooltip.svelte +0 -61
  211. package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +0 -7
  212. package/dist/lib/monitors/monitor-utils.d.ts +0 -4
  213. package/dist/lib/monitors/monitor-utils.js +0 -41
  214. package/dist/lib/monitors/monitors-cluster-renderer.d.ts +0 -33
  215. package/dist/lib/monitors/monitors-cluster-renderer.js +0 -221
  216. package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +0 -15
  217. package/dist/lib/monitors/monitors-icon-manager.svelte.js +0 -78
  218. package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +0 -43
  219. package/dist/lib/monitors/monitors-map-integration.svelte.js +0 -301
  220. package/dist/lib/options/reset-map-options.d.ts +0 -2
  221. package/dist/lib/options/reset-map-options.js +0 -24
  222. package/dist/lib/reactivity.svelte.d.ts +0 -0
  223. package/dist/lib/reactivity.svelte.js +0 -83
  224. package/dist/lib/wind/wind.svelte.d.ts +0 -10
  225. package/dist/lib/wind/wind.svelte.js +0 -13
  226. package/src/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  227. package/src/lib/collocation-sites/collocations-icon-manager.svelte.ts +0 -21
  228. package/src/lib/collocation-sites/collocations-map-integration.svelte.ts +0 -136
  229. package/src/lib/collocation-sites/collocations.svelte.ts +0 -24
  230. package/src/lib/collocation-sites/types.ts +0 -10
  231. package/src/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  232. package/src/lib/ev-stations/ev-stations-cluster-renderer.ts +0 -162
  233. package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +0 -248
  234. package/src/lib/ev-stations/ev-stations.svelte.ts +0 -79
  235. package/src/lib/hms/hms-fire-icon-manager.ts +0 -48
  236. package/src/lib/hms/hms-fire-map-integration.svelte.ts +0 -109
  237. package/src/lib/hms/hms-smoke-map-integration.svelte.ts +0 -105
  238. package/src/lib/hms/hms.svelte.ts +0 -264
  239. package/src/lib/legend/LegendBar.svelte +0 -45
  240. package/src/lib/legend/legend-data.ts +0 -101
  241. package/src/lib/map/Map.svelte +0 -13
  242. package/src/lib/map/basemap.ts +0 -24
  243. package/src/lib/map/icons.ts +0 -42
  244. package/src/lib/map/integrations/base-layer-seperator.ts +0 -17
  245. package/src/lib/map/integrations/click-manager.ts +0 -64
  246. package/src/lib/map/integrations/integrations-manager.ts +0 -25
  247. package/src/lib/map/integrations/map-display-option.svelte.ts +0 -13
  248. package/src/lib/map/integrations/map-geojson-integration.svelte.ts +0 -77
  249. package/src/lib/map/integrations/map-icon-manager.ts +0 -67
  250. package/src/lib/map/integrations/map-integration.svelte.ts +0 -8
  251. package/src/lib/map/integrations/map-layer-integration.svelte.ts +0 -49
  252. package/src/lib/map/integrations/tooltip.svelte.ts +0 -153
  253. package/src/lib/map/integrations/types.ts +0 -24
  254. package/src/lib/map/map-manager.svelte.ts +0 -83
  255. package/src/lib/map/map-style-state.svelte.ts +0 -94
  256. package/src/lib/map/utils.ts +0 -53
  257. package/src/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  258. package/src/lib/monitors/components/MonitorTooltip.svelte +0 -61
  259. package/src/lib/monitors/monitor-utils.ts +0 -57
  260. package/src/lib/monitors/monitors-cluster-renderer.ts +0 -285
  261. package/src/lib/monitors/monitors-icon-manager.svelte.ts +0 -98
  262. package/src/lib/monitors/monitors-map-integration.svelte.ts +0 -318
  263. package/src/lib/options/reset-map-options.ts +0 -28
  264. package/src/lib/reactivity.svelte.ts +0 -82
  265. package/src/lib/wind/wind.svelte.ts +0 -20
@@ -1,131 +0,0 @@
1
- import { mapManager } from "../map/map-manager.svelte.js";
2
- import { mountPopup } from "../map/utils";
3
- import { clickManager } from "../map/integrations/click-manager";
4
- import { EV_STATION_LEVELS } from "./ev-station-icons";
5
- import EvStationClusterTooltip from "./components/EvStationClusterTooltip.svelte";
6
- function clusterTooltip(evt) {
7
- const feature = evt.features?.[0];
8
- if (!feature)
9
- return;
10
- return mountPopup(EvStationClusterTooltip, { feature }, evt.lngLat);
11
- }
12
- export class EvStationsClusterRenderer {
13
- ctx;
14
- _levels = [];
15
- constructor(ctx) {
16
- this.ctx = ctx;
17
- }
18
- apply(stationClickHandler) {
19
- if (!mapManager.map)
20
- return;
21
- for (const level of Object.keys(EV_STATION_LEVELS)) {
22
- const sourceId = `${this.ctx.referenceId}-${level}`;
23
- const features = this.ctx.featuresByLevel[level] ?? [];
24
- const { bg } = EV_STATION_LEVELS[level];
25
- const clusterBg = bg.replace("rgb(", "rgba(").replace(")", ", 0.6)");
26
- mapManager.map.addSource(sourceId, {
27
- type: "geojson",
28
- promoteId: "id",
29
- data: { type: "FeatureCollection", features },
30
- cluster: true,
31
- clusterRadius: 40,
32
- clusterMaxZoom: 9
33
- });
34
- mapManager.map.addLayer({
35
- id: `${sourceId}-cluster-circle`,
36
- type: "circle",
37
- source: sourceId,
38
- filter: ["has", "point_count"],
39
- paint: {
40
- "circle-color": clusterBg,
41
- "circle-radius": ["step", ["get", "point_count"], 15, 10, 20, 25, 25]
42
- }
43
- }, this.ctx.beforeLayer);
44
- mapManager.map.addLayer({
45
- id: `${sourceId}-cluster-label`,
46
- type: "symbol",
47
- source: sourceId,
48
- filter: ["has", "point_count"],
49
- layout: {
50
- "text-field": ["get", "point_count_abbreviated"],
51
- "text-size": 12,
52
- "text-allow-overlap": true,
53
- "text-ignore-placement": true
54
- },
55
- paint: { "text-color": "#ffffff" }
56
- }, this.ctx.beforeLayer);
57
- mapManager.map.addLayer({
58
- id: `${sourceId}-unclustered`,
59
- type: "symbol",
60
- source: sourceId,
61
- filter: ["!", ["has", "point_count"]],
62
- layout: {
63
- "icon-image": `ev-station-${level}`,
64
- "icon-allow-overlap": true,
65
- "icon-ignore-placement": true,
66
- "icon-size": 1
67
- },
68
- paint: {}
69
- }, this.ctx.beforeLayer);
70
- const circleLayerId = `${sourceId}-cluster-circle`;
71
- const unclusteredLayerId = `${sourceId}-unclustered`;
72
- if (!this.ctx.tooltipManager.has(circleLayerId)) {
73
- this.ctx.tooltipManager.register(circleLayerId, clusterTooltip);
74
- }
75
- clickManager.register([circleLayerId], this.makeClusterClickHandler(sourceId));
76
- clickManager.register([unclusteredLayerId], stationClickHandler);
77
- this._levels.push(level);
78
- }
79
- }
80
- remove() {
81
- if (!mapManager.map)
82
- return;
83
- for (const level of this._levels) {
84
- const sourceId = `${this.ctx.referenceId}-${level}`;
85
- const layerIds = [
86
- `${sourceId}-cluster-circle`,
87
- `${sourceId}-cluster-label`,
88
- `${sourceId}-unclustered`
89
- ];
90
- for (const layerId of layerIds) {
91
- clickManager.unregister([layerId]);
92
- if (mapManager.map.getLayer(layerId)) {
93
- mapManager.map.removeLayer(layerId);
94
- }
95
- }
96
- if (mapManager.map.getSource(sourceId)) {
97
- mapManager.map.removeSource(sourceId);
98
- }
99
- }
100
- this._levels = [];
101
- }
102
- get unclusteredLayerIds() {
103
- return this._levels.map((level) => `${this.ctx.referenceId}-${level}-unclustered`);
104
- }
105
- syncFeatures() {
106
- if (!mapManager.map)
107
- return;
108
- for (const level of this._levels) {
109
- const sourceId = `${this.ctx.referenceId}-${level}`;
110
- mapManager.setDataSource(sourceId, this.ctx.featuresByLevel[level] ?? []);
111
- }
112
- }
113
- makeClusterClickHandler(sourceId) {
114
- return async (features) => {
115
- try {
116
- const feature = features[0];
117
- if (!feature?.properties?.cluster_id)
118
- return;
119
- const source = mapManager.map?.getSource(sourceId);
120
- if (!source)
121
- return;
122
- const zoom = await source.getClusterExpansionZoom(feature.properties.cluster_id);
123
- const coords = feature.geometry.coordinates;
124
- mapManager.map?.easeTo({ center: coords, zoom });
125
- }
126
- catch (err) {
127
- console.error("EvStations: cluster expansion zoom failed", err);
128
- }
129
- };
130
- }
131
- }
@@ -1,31 +0,0 @@
1
- import type { FilterSpecification, Map as MaptilerMap } from "@maptiler/sdk";
2
- import { MapIconLayerIntegration } from "../map/integrations/map-geojson-integration.svelte";
3
- import { MapDisplayOption } from "../map/integrations/map-display-option.svelte";
4
- import { TooltipManager } from "../map/integrations/tooltip.svelte";
5
- import { EvStationIconManager } from "./ev-station-icons";
6
- import { type EvStationsClusterContext } from "./ev-stations-cluster-renderer";
7
- import type { EvStationMapFeature, EvStationMarkerProperties } from "./types";
8
- declare class EvStationsMapIntegration extends MapIconLayerIntegration<EvStationMarkerProperties> implements EvStationsClusterContext {
9
- referenceId: string;
10
- enabled: boolean;
11
- clustered: boolean;
12
- icons: EvStationIconManager;
13
- tooltipManager: TooltipManager;
14
- private renderer;
15
- private currentPopup;
16
- displayOptions: {
17
- lvl2: MapDisplayOption;
18
- lvl3: MapDisplayOption;
19
- };
20
- features: Array<EvStationMapFeature>;
21
- featuresByLevel: Record<string, EvStationMapFeature[]>;
22
- filters: FilterSpecification;
23
- private handleStationClick;
24
- get mapLayer(): Parameters<MaptilerMap["addLayer"]>[0];
25
- get mapSource(): Parameters<MaptilerMap["addSource"]>[1];
26
- constructor();
27
- apply(): void;
28
- remove(): void;
29
- }
30
- export declare const evStationsMapIntegration: EvStationsMapIntegration;
31
- export type { EvStationsMapIntegration };
@@ -1,226 +0,0 @@
1
- import { untrack } from "svelte";
2
- import { mapManager } from "../map/map-manager.svelte.js";
3
- import { clickManager } from "../map/integrations/click-manager";
4
- import { MapIconLayerIntegration } from "../map/integrations/map-geojson-integration.svelte";
5
- import { MapDisplayOption } from "../map/integrations/map-display-option.svelte";
6
- import { TooltipManager } from "../map/integrations/tooltip.svelte";
7
- import { mountClickPopup } from "../map/utils";
8
- import { evStationsManager } from "./ev-stations.svelte";
9
- import { EvStationIconManager } from "./ev-station-icons";
10
- import { EvStationsClusterRenderer } from "./ev-stations-cluster-renderer";
11
- import EvStationTooltip from "./components/EvStationTooltip.svelte";
12
- class EvStationsMapIntegration extends MapIconLayerIntegration {
13
- referenceId = "ev-stations";
14
- enabled = $state(false);
15
- clustered = $state(true);
16
- icons = new EvStationIconManager();
17
- tooltipManager = new TooltipManager();
18
- renderer = new EvStationsClusterRenderer(this);
19
- currentPopup = null;
20
- displayOptions = $derived.by(() => ({
21
- lvl2: new MapDisplayOption("Level 2", true, this.icons.get("ev-station-lvl2")),
22
- lvl3: new MapDisplayOption("Level 3", true, this.icons.get("ev-station-lvl3"))
23
- }));
24
- features = $derived.by(() => {
25
- const result = [];
26
- if (evStationsManager.lvl2Stations) {
27
- for (const station of evStationsManager.lvl2Stations) {
28
- result.push(toFeature(station, "lvl2"));
29
- }
30
- }
31
- if (evStationsManager.lvl3Stations) {
32
- for (const station of evStationsManager.lvl3Stations) {
33
- result.push(toFeature(station, "lvl3"));
34
- }
35
- }
36
- return result;
37
- });
38
- featuresByLevel = $derived.by(() => {
39
- const byLevel = {};
40
- for (const feature of this.features) {
41
- const level = feature.properties.level;
42
- if (level === "lvl2" && !this.displayOptions.lvl2.value)
43
- continue;
44
- if (level === "lvl3" && !this.displayOptions.lvl3.value)
45
- continue;
46
- const arr = byLevel[level] ?? [];
47
- arr.push(feature);
48
- byLevel[level] = arr;
49
- }
50
- return byLevel;
51
- });
52
- filters = $derived.by(() => {
53
- const levels = [];
54
- if (this.displayOptions.lvl2.value)
55
- levels.push("lvl2");
56
- if (this.displayOptions.lvl3.value)
57
- levels.push("lvl3");
58
- if (levels.length === 0)
59
- return ["==", ["get", "level"], "none"];
60
- if (levels.length === 2)
61
- return ["boolean", true];
62
- return ["==", ["get", "level"], levels[0]];
63
- });
64
- handleStationClick = (features, evt) => {
65
- this.currentPopup?.remove();
66
- const feature = features[0];
67
- if (!feature)
68
- return;
69
- this.currentPopup = mountClickPopup(EvStationTooltip, { feature }, evt.lngLat);
70
- this.currentPopup.addTo(mapManager.map);
71
- };
72
- get mapLayer() {
73
- return {
74
- id: this.referenceId,
75
- type: "symbol",
76
- source: this.referenceId,
77
- filter: this.filters,
78
- layout: {
79
- "icon-allow-overlap": true,
80
- "icon-ignore-placement": true,
81
- "icon-image": ["get", "icon"],
82
- "icon-size": 1
83
- },
84
- paint: {}
85
- };
86
- }
87
- get mapSource() {
88
- return {
89
- type: "geojson",
90
- promoteId: "id",
91
- data: {
92
- type: "FeatureCollection",
93
- features: this.features
94
- }
95
- };
96
- }
97
- constructor() {
98
- super();
99
- $effect.root(() => {
100
- // Lazy-fetch level data only once the integration is enabled and the level is on
101
- $effect(() => {
102
- if (this.enabled &&
103
- this.displayOptions.lvl2.value &&
104
- evStationsManager.lvl2Stations === undefined) {
105
- evStationsManager.loadLvl2Stations();
106
- }
107
- });
108
- $effect(() => {
109
- if (this.enabled &&
110
- this.displayOptions.lvl3.value &&
111
- evStationsManager.lvl3Stations === undefined) {
112
- evStationsManager.loadLvl3Stations();
113
- }
114
- });
115
- // Every effect below early-returns while disabled so a data refresh can't re-add the layer.
116
- // `enabled` is read untracked: the base class's own effect already applies/removes on
117
- // enabled changes, and tracking it here would apply twice. The guard comes after each
118
- // effect's tracked reads so its dependencies are always collected; returning before
119
- // reading anything would leave the effect permanently dead.
120
- // Push filter changes to the unclustered layer
121
- $effect(() => {
122
- const filter = this.filters;
123
- if (!mapManager.map || this.clustered)
124
- return;
125
- if (!untrack(() => this.enabled))
126
- return;
127
- if (mapManager.map.getLayer(this.referenceId)) {
128
- mapManager.map.setFilter(this.referenceId, filter);
129
- }
130
- });
131
- // Sync unclustered source when features change
132
- $effect(() => {
133
- const features = this.features;
134
- if (!mapManager.map || this.clustered)
135
- return;
136
- if (!untrack(() => this.enabled))
137
- return;
138
- mapManager.setDataSource(this.referenceId, features);
139
- });
140
- // Sync clustered sources when featuresByLevel changes
141
- $effect(() => {
142
- void this.featuresByLevel;
143
- if (!mapManager.map || !this.clustered)
144
- return;
145
- if (!untrack(() => this.enabled))
146
- return;
147
- this.renderer.syncFeatures();
148
- });
149
- // Re-apply when clustered mode switches or data first arrives
150
- $effect(() => {
151
- void this.clustered;
152
- const hasFeatures = Object.keys(this.featuresByLevel).length > 0;
153
- if (!untrack(() => mapManager.map) || !hasFeatures)
154
- return;
155
- if (!untrack(() => this.enabled))
156
- return;
157
- untrack(() => this.apply());
158
- });
159
- });
160
- }
161
- apply() {
162
- if (!mapManager.map)
163
- return;
164
- if (this.clustered) {
165
- if (mapManager.map.getLayer(this.referenceId))
166
- mapManager.map.removeLayer(this.referenceId);
167
- if (mapManager.map.getSource(this.referenceId))
168
- mapManager.map.removeSource(this.referenceId);
169
- clickManager.unregister([this.referenceId]);
170
- this.tooltipManager.disable();
171
- this.renderer.remove();
172
- // Clustering may be toggled again before the icons arrive; only the latest apply runs.
173
- this.supersedePending();
174
- this.whenIconsLoad(() => {
175
- this.renderer.apply(this.handleStationClick);
176
- this.tooltipManager.enable();
177
- });
178
- }
179
- else {
180
- this.renderer.remove();
181
- this.tooltipManager.disable();
182
- clickManager.unregister([this.referenceId]);
183
- super.apply();
184
- this.whenIconsLoad(() => {
185
- clickManager.register([this.referenceId], this.handleStationClick);
186
- this.tooltipManager.enable();
187
- });
188
- }
189
- }
190
- remove() {
191
- clickManager.unregister([this.referenceId]);
192
- clickManager.unregister(this.renderer.unclusteredLayerIds);
193
- this.renderer.remove();
194
- this.currentPopup?.remove();
195
- this.currentPopup = null;
196
- super.remove();
197
- }
198
- }
199
- function toFeature(station, level) {
200
- return {
201
- type: "Feature",
202
- properties: {
203
- icon: `ev-station-${level}`,
204
- id: station.id,
205
- level,
206
- station_name: station.station_name ?? "",
207
- facility_type: station.facility_type ?? "",
208
- ev_network: station.ev_network ?? "",
209
- station_phone: station.station_phone ?? "",
210
- street_address: station.street_address ?? "",
211
- city: station.city ?? "",
212
- state: station.state ?? "",
213
- zip: station.zip ?? "",
214
- access_days_time: station.access_days_time ?? "",
215
- access_detail_code: station.access_detail_code ?? "",
216
- cards_accepted: station.cards_accepted ?? null,
217
- ev_pricing: station.ev_pricing ?? "",
218
- ev_connector_types: JSON.stringify(station.ev_connector_types ?? [])
219
- },
220
- geometry: {
221
- type: "Point",
222
- coordinates: [station.longitude, station.latitude]
223
- }
224
- };
225
- }
226
- export const evStationsMapIntegration = new EvStationsMapIntegration();
@@ -1,9 +0,0 @@
1
- import type { EvStation } from "./types";
2
- declare class EvStationsManager {
3
- lvl2Stations: Array<EvStation> | undefined;
4
- lvl3Stations: Array<EvStation> | undefined;
5
- loadLvl3Stations(): Promise<void>;
6
- loadLvl2Stations(): Promise<void>;
7
- }
8
- export declare const evStationsManager: EvStationsManager;
9
- export type { EvStationsManager };
@@ -1,55 +0,0 @@
1
- import { accessDetailCodeTypes, creditCardTypes, evConnectorTypes, evNetworkTypes, facilityTypes } from "./data-maps";
2
- import * as ZipCodes from "./zip-codes";
3
- class EvStationsManager {
4
- lvl2Stations = $state();
5
- lvl3Stations = $state();
6
- async loadLvl3Stations() {
7
- this.lvl3Stations = await fetchEvStations("dc_fast");
8
- }
9
- async loadLvl2Stations() {
10
- this.lvl2Stations = await fetchEvStations("2");
11
- }
12
- }
13
- const zipCodes = Object.values(ZipCodes)
14
- .reduce((prev, curr) => prev.concat(curr))
15
- .join(",");
16
- async function fetchEvStations(chargingLevel) {
17
- const url = new URL(`https://developer.nlr.gov/api/alt-fuel-stations/v1.json`);
18
- url.searchParams.set("fuel_type", "ELEC");
19
- url.searchParams.set("state", "CA");
20
- url.searchParams.set("status", "E");
21
- url.searchParams.set("access", "public");
22
- url.searchParams.set("ev_charging_level", chargingLevel);
23
- url.searchParams.set("zip", zipCodes);
24
- url.searchParams.set("api_key", import.meta.env.VITE_NREL_KEY);
25
- return await fetch(url)
26
- .then(async (res) => await res.json())
27
- .then((data) => {
28
- const fuelStations = data.fuel_stations;
29
- return (fuelStations
30
- .map((station) => {
31
- if (station.access_detail_code) {
32
- station.access_detail_code = accessDetailCodeTypes.get(station.access_detail_code);
33
- }
34
- if (station.cards_accepted) {
35
- station.cards_accepted = station.cards_accepted
36
- .split(" ")
37
- .map((c) => creditCardTypes.get(c))
38
- .join(", ");
39
- }
40
- if (station.ev_connector_types && station.ev_connector_types.length) {
41
- station.ev_connector_types = station.ev_connector_types.map((t) => evConnectorTypes.get(t));
42
- }
43
- if (station.ev_network) {
44
- station.ev_network = evNetworkTypes.get(station.ev_network);
45
- }
46
- if (station.facility_type) {
47
- station.facility_type = facilityTypes.get(station.facility_type);
48
- }
49
- return station;
50
- })
51
- // remove stations with invalid coordinates
52
- .filter((station) => station.id !== 226154));
53
- });
54
- }
55
- export const evStationsManager = new EvStationsManager();
@@ -1,13 +0,0 @@
1
- import { MapIconManager } from "../map/integrations/map-icon-manager";
2
- import type { LegendCategory } from "../legend/legend-data";
3
- export type FRPTier = "sm" | "md" | "lg" | "xl" | "xxl";
4
- export declare const FRP_TIERS: Record<FRPTier, {
5
- color: string;
6
- size: number;
7
- }>;
8
- /** Fire legend blocks (MW), in tier order, using the same colors as the map icons. */
9
- export declare const FIRE_LEGEND_CATEGORIES: Array<LegendCategory>;
10
- export declare function getTierIconId(frp: number): string;
11
- export declare class HMSFireIconManager extends MapIconManager {
12
- constructor();
13
- }
@@ -1,39 +0,0 @@
1
- import { asDataURI, fireIcon } from "../map/icons";
2
- import { MapIconManager } from "../map/integrations/map-icon-manager";
3
- export const FRP_TIERS = {
4
- sm: { color: "#FFD700", size: 20 },
5
- md: { color: "#FF8C00", size: 24 },
6
- lg: { color: "#FF4500", size: 28 },
7
- xl: { color: "#DC143C", size: 32 },
8
- xxl: { color: "#8B0000", size: 36 }
9
- };
10
- const FRP_TIER_LABELS = {
11
- sm: "<10",
12
- md: "10-49",
13
- lg: "50-149",
14
- xl: "150-349",
15
- xxl: "≥350"
16
- };
17
- /** Fire legend blocks (MW), in tier order, using the same colors as the map icons. */
18
- export const FIRE_LEGEND_CATEGORIES = Object.keys(FRP_TIERS).map((tier) => ({ color: FRP_TIERS[tier].color, label: FRP_TIER_LABELS[tier] }));
19
- export function getTierIconId(frp) {
20
- if (frp < 10)
21
- return "hms-fire-sm";
22
- if (frp < 50)
23
- return "hms-fire-md";
24
- if (frp < 150)
25
- return "hms-fire-lg";
26
- if (frp < 350)
27
- return "hms-fire-xl";
28
- return "hms-fire-xxl";
29
- }
30
- export class HMSFireIconManager extends MapIconManager {
31
- constructor() {
32
- super();
33
- for (const [tier, { color, size }] of Object.entries(FRP_TIERS)) {
34
- const img = new Image(size, size);
35
- img.src = asDataURI(fireIcon(color, size));
36
- this.register(`hms-fire-${tier}`, img);
37
- }
38
- }
39
- }
@@ -1,23 +0,0 @@
1
- import type { Map as MaptilerMap } from "@maptiler/sdk";
2
- import type { Feature } from "geojson";
3
- import type { Point } from "geojson";
4
- import { MapIconLayerIntegration } from "../map/integrations/map-geojson-integration.svelte";
5
- import { HMSFireIconManager } from "./hms-fire-icon-manager";
6
- type FireProperties = Record<string, unknown>;
7
- declare class HMSFireMapIntegration extends MapIconLayerIntegration<FireProperties> {
8
- referenceId: string;
9
- enabled: boolean;
10
- icons: HMSFireIconManager;
11
- private zoomedIn;
12
- get features(): Array<Feature<Point, FireProperties>>;
13
- get mapLayer(): Parameters<MaptilerMap["addLayer"]>[0];
14
- get mapSource(): Parameters<MaptilerMap["addSource"]>[1];
15
- private get groupFeatures();
16
- private get hotspotFeatures();
17
- private onZoom;
18
- constructor();
19
- apply(): void;
20
- remove(): void;
21
- }
22
- export declare const hmsFireMapIntegration: HMSFireMapIntegration;
23
- export type { HMSFireMapIntegration };
@@ -1,94 +0,0 @@
1
- import { mapManager } from "../map/map-manager.svelte.js";
2
- import { MapIconLayerIntegration } from "../map/integrations/map-geojson-integration.svelte";
3
- import { hmsManager } from "./hms.svelte";
4
- import { HMSFireIconManager, getTierIconId } from "./hms-fire-icon-manager";
5
- const ZOOM_THRESHOLD = 10;
6
- class HMSFireMapIntegration extends MapIconLayerIntegration {
7
- referenceId = "hms-fire";
8
- enabled = $state(true);
9
- icons = new HMSFireIconManager();
10
- zoomedIn = $state(false);
11
- get features() {
12
- return this.zoomedIn ? this.hotspotFeatures : this.groupFeatures;
13
- }
14
- get mapLayer() {
15
- return {
16
- id: this.referenceId,
17
- type: "symbol",
18
- source: this.referenceId,
19
- layout: {
20
- "icon-image": ["get", "icon"],
21
- "icon-allow-overlap": true,
22
- "icon-ignore-placement": true
23
- },
24
- paint: {}
25
- };
26
- }
27
- get mapSource() {
28
- return {
29
- type: "geojson",
30
- promoteId: "id",
31
- data: { type: "FeatureCollection", features: this.features }
32
- };
33
- }
34
- get groupFeatures() {
35
- return (hmsManager.fireGroups ?? []).map((g) => ({
36
- type: "Feature",
37
- properties: {
38
- id: g.id,
39
- icon: getTierIconId(g.avgFrp),
40
- avgFrp: g.avgFrp,
41
- count: g.count
42
- },
43
- geometry: { type: "Point", coordinates: g.coordinates }
44
- }));
45
- }
46
- get hotspotFeatures() {
47
- return (hmsManager.fire ?? []).map((d) => ({
48
- type: "Feature",
49
- properties: {
50
- id: d.id,
51
- icon: getTierIconId(d.frp),
52
- frp: d.frp
53
- },
54
- geometry: d.geometry
55
- }));
56
- }
57
- onZoom = () => {
58
- if (!mapManager.map)
59
- return;
60
- this.zoomedIn = mapManager.map.getZoom() >= ZOOM_THRESHOLD;
61
- };
62
- constructor() {
63
- super();
64
- $effect.root(() => {
65
- $effect(() => {
66
- const features = this.features;
67
- if (!mapManager.map || !this.enabled)
68
- return;
69
- mapManager.setDataSource(this.referenceId, features);
70
- });
71
- });
72
- }
73
- apply() {
74
- if (!mapManager.map)
75
- return;
76
- this.icons
77
- .loadIcons()
78
- .then(() => {
79
- if (!mapManager.map || !this.enabled || mapManager.styleLoading)
80
- return;
81
- this.remove();
82
- this.zoomedIn = mapManager.map.getZoom() >= ZOOM_THRESHOLD;
83
- mapManager.map.addSource(this.referenceId, this.mapSource);
84
- mapManager.map.addLayer(this.mapLayer, this.beforeLayer);
85
- mapManager.map.on("zoom", this.onZoom);
86
- })
87
- .catch(console.error);
88
- }
89
- remove() {
90
- mapManager.map?.off("zoom", this.onZoom);
91
- super.remove();
92
- }
93
- }
94
- export const hmsFireMapIntegration = new HMSFireMapIntegration();
@@ -1,39 +0,0 @@
1
- import type { Map as MaptilerMap } from "@maptiler/sdk";
2
- import type { Feature, MultiPolygon } from "geojson";
3
- import type { HMSSmokeGeoJSON } from "@sjvair/sdk/hms";
4
- import { MapGeoJSONIntegration } from "../map/integrations/map-geojson-integration.svelte";
5
- import type { SmokeDensityStyle } from "../legend/legend-data";
6
- /** Smoke fill styles, shared by the map layer and the legend so they can't drift apart. */
7
- export declare const SMOKE_DENSITY_STYLES: {
8
- light: {
9
- label: string;
10
- color: string;
11
- opacity: number;
12
- };
13
- medium: {
14
- label: string;
15
- color: string;
16
- opacity: number;
17
- };
18
- heavy: {
19
- label: string;
20
- color: string;
21
- opacity: number;
22
- };
23
- };
24
- export declare const SMOKE_LEGEND: Array<SmokeDensityStyle>;
25
- type SmokeProperties = {
26
- id: string;
27
- density: HMSSmokeGeoJSON["density"];
28
- };
29
- declare class HMSSmokeMapIntegration extends MapGeoJSONIntegration<SmokeProperties> {
30
- referenceId: string;
31
- enabled: boolean;
32
- get features(): Array<Feature<MultiPolygon, SmokeProperties>>;
33
- get mapLayer(): Parameters<MaptilerMap["addLayer"]>[0];
34
- get mapSource(): Parameters<MaptilerMap["addSource"]>[1];
35
- constructor();
36
- apply(): void;
37
- }
38
- export declare const hmsSmokeMapIntegration: HMSSmokeMapIntegration;
39
- export type { HMSSmokeMapIntegration };