@sjvair/monitor-map 4.3.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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -138
  3. package/dist/lib/MonitorDetailPanel.svelte +23 -20
  4. package/dist/lib/MonitorMapLayout.svelte +147 -77
  5. package/dist/lib/components/DataBox.svelte +4 -1
  6. package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
  7. package/dist/lib/config.svelte.d.ts +7 -0
  8. package/dist/lib/config.svelte.js +10 -0
  9. package/dist/lib/core.d.ts +2 -2
  10. package/dist/lib/core.js +2 -1
  11. package/dist/lib/data-chart/DataChart.svelte +40 -25
  12. package/dist/lib/data-chart/DateRange.d.ts +13 -4
  13. package/dist/lib/data-chart/DateRange.js +50 -14
  14. package/dist/lib/data-chart/chart-utils.js +5 -7
  15. package/dist/lib/data-chart/level-colors.d.ts +3 -4
  16. package/dist/lib/data-chart/level-colors.js +7 -4
  17. package/dist/lib/data-chart/pacific-time.d.ts +9 -0
  18. package/dist/lib/data-chart/pacific-time.js +25 -0
  19. package/dist/lib/data-chart/tooltip.js +2 -2
  20. package/{src/lib/ev-stations/components/EvStationTooltip.svelte → dist/lib/ev-stations/EvPopup.svelte} +6 -5
  21. package/dist/lib/ev-stations/EvPopup.svelte.d.ts +7 -0
  22. package/dist/lib/ev-stations/ev-plugin.svelte.d.ts +14 -0
  23. package/dist/lib/ev-stations/ev-plugin.svelte.js +71 -0
  24. package/dist/lib/ev-stations/ev-station-icons.d.ts +1 -4
  25. package/dist/lib/ev-stations/ev-station-icons.js +1 -13
  26. package/dist/lib/ev-stations/ev-stations.d.ts +7 -0
  27. package/dist/lib/ev-stations/ev-stations.js +53 -0
  28. package/dist/lib/ev-stations/ev-store.svelte.d.ts +21 -0
  29. package/dist/lib/ev-stations/ev-store.svelte.js +83 -0
  30. package/dist/lib/ev-stations/station-popup.svelte.d.ts +14 -0
  31. package/dist/lib/ev-stations/station-popup.svelte.js +54 -0
  32. package/dist/lib/ev-stations/types.d.ts +0 -29
  33. package/dist/lib/ev-stations/zip-codes.d.ts +11 -0
  34. package/dist/lib/ev-stations/zip-codes.js +28 -16
  35. package/dist/lib/index.d.ts +8 -56
  36. package/dist/lib/index.js +7 -46
  37. package/dist/lib/legend/Legend.svelte +18 -19
  38. package/dist/lib/legend/Legend.svelte.d.ts +2 -2
  39. package/dist/lib/levels.d.ts +7 -0
  40. package/dist/lib/levels.js +19 -0
  41. package/dist/lib/map/MapShell.svelte +17 -24
  42. package/dist/lib/map/MapShell.svelte.d.ts +4 -4
  43. package/dist/lib/map/basemaps.d.ts +25 -0
  44. package/dist/lib/map/basemaps.js +66 -0
  45. package/dist/lib/map/live-map.svelte.d.ts +3 -0
  46. package/dist/lib/map/live-map.svelte.js +22 -0
  47. package/dist/lib/map/sync-plugins.svelte.d.ts +19 -0
  48. package/dist/lib/map/sync-plugins.svelte.js +52 -0
  49. package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
  50. package/dist/lib/monitors/filtered-source.svelte.d.ts +9 -0
  51. package/dist/lib/monitors/filtered-source.svelte.js +28 -0
  52. package/dist/lib/monitors/monitors.svelte.d.ts +25 -35
  53. package/dist/lib/monitors/monitors.svelte.js +35 -218
  54. package/dist/lib/monitors/retry-load.d.ts +8 -0
  55. package/dist/lib/monitors/retry-load.js +11 -0
  56. package/dist/lib/monitors/types.d.ts +1 -41
  57. package/dist/lib/options/map-option-defaults.d.ts +25 -36
  58. package/dist/lib/options/map-option-defaults.js +12 -30
  59. package/dist/lib/options/map-options.svelte.d.ts +13 -0
  60. package/dist/lib/options/map-options.svelte.js +26 -0
  61. package/dist/lib/options/menus/LayersMenu.svelte +8 -20
  62. package/dist/lib/options/menus/LayersMenu.svelte.d.ts +17 -2
  63. package/dist/lib/options/menus/MonitorsMenu.svelte +34 -18
  64. package/dist/lib/options/menus/OverlaysMenu.svelte +2 -2
  65. package/dist/lib/options/menus/PollutantMenu.svelte +4 -9
  66. package/dist/lib/options/menus/SettingsMenu.svelte +32 -25
  67. package/dist/lib/options/menus/SettingsMenu.svelte.d.ts +5 -16
  68. package/dist/lib/options/plugin-order.d.ts +8 -0
  69. package/dist/lib/options/plugin-order.js +36 -0
  70. package/dist/lib/options/pollutant-param.d.ts +7 -5
  71. package/dist/lib/options/pollutant-param.js +9 -5
  72. package/dist/lib/options/row-icons.d.ts +8 -0
  73. package/dist/lib/options/row-icons.js +15 -0
  74. package/dist/lib/options/rows/MarkerIcon.svelte +5 -5
  75. package/dist/lib/options/rows/MarkerIcon.svelte.d.ts +1 -2
  76. package/dist/lib/search/Search.svelte +20 -33
  77. package/dist/lib/search/Search.svelte.d.ts +5 -1
  78. package/dist/lib/search/search-pin.svelte.d.ts +11 -0
  79. package/dist/lib/search/search-pin.svelte.js +28 -0
  80. package/dist/lib/search/service.d.ts +7 -2
  81. package/dist/lib/search/service.js +17 -10
  82. package/dist/lib/stores.svelte.d.ts +8 -0
  83. package/dist/lib/stores.svelte.js +9 -0
  84. package/dist/lib/wind/wind-plugin.d.ts +11 -0
  85. package/dist/lib/wind/wind-plugin.js +25 -0
  86. package/package.json +12 -10
  87. package/src/lib/MonitorDetailPanel.svelte +23 -20
  88. package/src/lib/MonitorMapLayout.svelte +147 -77
  89. package/src/lib/components/DataBox.svelte +4 -1
  90. package/src/lib/config.svelte.ts +16 -0
  91. package/src/lib/core.ts +2 -2
  92. package/src/lib/data-chart/DataChart.svelte +40 -25
  93. package/src/lib/data-chart/DateRange.ts +58 -15
  94. package/src/lib/data-chart/chart-utils.ts +6 -7
  95. package/src/lib/data-chart/level-colors.ts +8 -9
  96. package/src/lib/data-chart/pacific-time.ts +31 -0
  97. package/src/lib/data-chart/tooltip.ts +2 -2
  98. package/{dist/lib/ev-stations/components/EvStationTooltip.svelte → src/lib/ev-stations/EvPopup.svelte} +6 -5
  99. package/src/lib/ev-stations/ev-plugin.svelte.ts +86 -0
  100. package/src/lib/ev-stations/ev-station-icons.ts +1 -17
  101. package/src/lib/ev-stations/ev-stations.ts +72 -0
  102. package/src/lib/ev-stations/ev-store.svelte.ts +117 -0
  103. package/src/lib/ev-stations/station-popup.svelte.ts +64 -0
  104. package/src/lib/ev-stations/types.ts +0 -34
  105. package/src/lib/ev-stations/zip-codes.ts +29 -16
  106. package/src/lib/index.ts +8 -99
  107. package/src/lib/legend/Legend.svelte +18 -19
  108. package/src/lib/levels.ts +24 -0
  109. package/src/lib/map/MapShell.svelte +17 -24
  110. package/src/lib/map/basemaps.ts +76 -0
  111. package/src/lib/map/live-map.svelte.ts +24 -0
  112. package/src/lib/map/sync-plugins.svelte.ts +69 -0
  113. package/src/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
  114. package/src/lib/monitors/filtered-source.svelte.ts +38 -0
  115. package/src/lib/monitors/monitors.svelte.ts +58 -261
  116. package/src/lib/monitors/retry-load.ts +14 -0
  117. package/src/lib/monitors/types.ts +1 -47
  118. package/src/lib/options/map-option-defaults.ts +30 -53
  119. package/src/lib/options/map-options.svelte.ts +30 -0
  120. package/src/lib/options/menus/LayersMenu.svelte +8 -20
  121. package/src/lib/options/menus/MonitorsMenu.svelte +34 -18
  122. package/src/lib/options/menus/OverlaysMenu.svelte +2 -2
  123. package/src/lib/options/menus/PollutantMenu.svelte +4 -9
  124. package/src/lib/options/menus/SettingsMenu.svelte +32 -25
  125. package/src/lib/options/plugin-order.ts +38 -0
  126. package/src/lib/options/pollutant-param.ts +14 -9
  127. package/src/lib/options/row-icons.ts +17 -0
  128. package/src/lib/options/rows/MarkerIcon.svelte +5 -5
  129. package/src/lib/search/Search.svelte +20 -33
  130. package/src/lib/search/search-pin.svelte.ts +35 -0
  131. package/src/lib/search/service.ts +34 -15
  132. package/src/lib/stores.svelte.ts +15 -0
  133. package/src/lib/wind/wind-plugin.ts +33 -0
  134. package/dist/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  135. package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +0 -7
  136. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +0 -7
  137. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +0 -18
  138. package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +0 -21
  139. package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +0 -113
  140. package/dist/lib/collocation-sites/collocations.svelte.d.ts +0 -10
  141. package/dist/lib/collocation-sites/collocations.svelte.js +0 -21
  142. package/dist/lib/collocation-sites/types.d.ts +0 -8
  143. package/dist/lib/collocation-sites/types.js +0 -1
  144. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  145. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +0 -7
  146. package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +0 -7
  147. package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +0 -19
  148. package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +0 -131
  149. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +0 -31
  150. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +0 -226
  151. package/dist/lib/ev-stations/ev-stations.svelte.d.ts +0 -10
  152. package/dist/lib/ev-stations/ev-stations.svelte.js +0 -57
  153. package/dist/lib/hms/hms-fire-icon-manager.d.ts +0 -13
  154. package/dist/lib/hms/hms-fire-icon-manager.js +0 -39
  155. package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +0 -23
  156. package/dist/lib/hms/hms-fire-map-integration.svelte.js +0 -94
  157. package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +0 -39
  158. package/dist/lib/hms/hms-smoke-map-integration.svelte.js +0 -87
  159. package/dist/lib/hms/hms.svelte.d.ts +0 -20
  160. package/dist/lib/hms/hms.svelte.js +0 -237
  161. package/dist/lib/legend/LegendBar.svelte +0 -45
  162. package/dist/lib/legend/LegendBar.svelte.d.ts +0 -7
  163. package/dist/lib/legend/legend-data.d.ts +0 -40
  164. package/dist/lib/legend/legend-data.js +0 -65
  165. package/dist/lib/map/Map.svelte +0 -13
  166. package/dist/lib/map/Map.svelte.d.ts +0 -8
  167. package/dist/lib/map/basemap.d.ts +0 -14
  168. package/dist/lib/map/basemap.js +0 -10
  169. package/dist/lib/map/icons.d.ts +0 -7
  170. package/dist/lib/map/icons.js +0 -33
  171. package/dist/lib/map/integrations/base-layer-seperator.d.ts +0 -9
  172. package/dist/lib/map/integrations/base-layer-seperator.js +0 -11
  173. package/dist/lib/map/integrations/click-manager.d.ts +0 -14
  174. package/dist/lib/map/integrations/click-manager.js +0 -52
  175. package/dist/lib/map/integrations/integrations-manager.d.ts +0 -8
  176. package/dist/lib/map/integrations/integrations-manager.js +0 -20
  177. package/dist/lib/map/integrations/map-display-option.svelte.d.ts +0 -7
  178. package/dist/lib/map/integrations/map-display-option.svelte.js +0 -10
  179. package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +0 -32
  180. package/dist/lib/map/integrations/map-geojson-integration.svelte.js +0 -60
  181. package/dist/lib/map/integrations/map-icon-manager.d.ts +0 -15
  182. package/dist/lib/map/integrations/map-icon-manager.js +0 -52
  183. package/dist/lib/map/integrations/map-integration.svelte.d.ts +0 -6
  184. package/dist/lib/map/integrations/map-integration.svelte.js +0 -2
  185. package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +0 -11
  186. package/dist/lib/map/integrations/map-layer-integration.svelte.js +0 -40
  187. package/dist/lib/map/integrations/tooltip.svelte.d.ts +0 -36
  188. package/dist/lib/map/integrations/tooltip.svelte.js +0 -131
  189. package/dist/lib/map/integrations/types.d.ts +0 -14
  190. package/dist/lib/map/integrations/types.js +0 -1
  191. package/dist/lib/map/map-manager.svelte.d.ts +0 -20
  192. package/dist/lib/map/map-manager.svelte.js +0 -63
  193. package/dist/lib/map/map-style-state.svelte.d.ts +0 -23
  194. package/dist/lib/map/map-style-state.svelte.js +0 -86
  195. package/dist/lib/map/utils.d.ts +0 -7
  196. package/dist/lib/map/utils.js +0 -36
  197. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  198. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +0 -7
  199. package/dist/lib/monitors/components/MonitorTooltip.svelte +0 -61
  200. package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +0 -7
  201. package/dist/lib/monitors/monitor-utils.d.ts +0 -4
  202. package/dist/lib/monitors/monitor-utils.js +0 -41
  203. package/dist/lib/monitors/monitors-cluster-renderer.d.ts +0 -33
  204. package/dist/lib/monitors/monitors-cluster-renderer.js +0 -221
  205. package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +0 -15
  206. package/dist/lib/monitors/monitors-icon-manager.svelte.js +0 -78
  207. package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +0 -43
  208. package/dist/lib/monitors/monitors-map-integration.svelte.js +0 -301
  209. package/dist/lib/options/reset-map-options.d.ts +0 -2
  210. package/dist/lib/options/reset-map-options.js +0 -24
  211. package/dist/lib/reactivity.svelte.d.ts +0 -0
  212. package/dist/lib/reactivity.svelte.js +0 -83
  213. package/dist/lib/wind/wind.svelte.d.ts +0 -10
  214. package/dist/lib/wind/wind.svelte.js +0 -13
  215. package/src/lib/collocation-sites/CollocationTooltip.svelte +0 -98
  216. package/src/lib/collocation-sites/collocations-icon-manager.svelte.ts +0 -21
  217. package/src/lib/collocation-sites/collocations-map-integration.svelte.ts +0 -136
  218. package/src/lib/collocation-sites/collocations.svelte.ts +0 -27
  219. package/src/lib/collocation-sites/types.ts +0 -10
  220. package/src/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
  221. package/src/lib/ev-stations/ev-stations-cluster-renderer.ts +0 -162
  222. package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +0 -248
  223. package/src/lib/ev-stations/ev-stations.svelte.ts +0 -84
  224. package/src/lib/hms/hms-fire-icon-manager.ts +0 -48
  225. package/src/lib/hms/hms-fire-map-integration.svelte.ts +0 -109
  226. package/src/lib/hms/hms-smoke-map-integration.svelte.ts +0 -105
  227. package/src/lib/hms/hms.svelte.ts +0 -270
  228. package/src/lib/legend/LegendBar.svelte +0 -45
  229. package/src/lib/legend/legend-data.ts +0 -101
  230. package/src/lib/map/Map.svelte +0 -13
  231. package/src/lib/map/basemap.ts +0 -24
  232. package/src/lib/map/icons.ts +0 -42
  233. package/src/lib/map/integrations/base-layer-seperator.ts +0 -17
  234. package/src/lib/map/integrations/click-manager.ts +0 -64
  235. package/src/lib/map/integrations/integrations-manager.ts +0 -25
  236. package/src/lib/map/integrations/map-display-option.svelte.ts +0 -13
  237. package/src/lib/map/integrations/map-geojson-integration.svelte.ts +0 -77
  238. package/src/lib/map/integrations/map-icon-manager.ts +0 -67
  239. package/src/lib/map/integrations/map-integration.svelte.ts +0 -8
  240. package/src/lib/map/integrations/map-layer-integration.svelte.ts +0 -49
  241. package/src/lib/map/integrations/tooltip.svelte.ts +0 -153
  242. package/src/lib/map/integrations/types.ts +0 -24
  243. package/src/lib/map/map-manager.svelte.ts +0 -83
  244. package/src/lib/map/map-style-state.svelte.ts +0 -94
  245. package/src/lib/map/utils.ts +0 -53
  246. package/src/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
  247. package/src/lib/monitors/components/MonitorTooltip.svelte +0 -61
  248. package/src/lib/monitors/monitor-utils.ts +0 -57
  249. package/src/lib/monitors/monitors-cluster-renderer.ts +0 -285
  250. package/src/lib/monitors/monitors-icon-manager.svelte.ts +0 -98
  251. package/src/lib/monitors/monitors-map-integration.svelte.ts +0 -318
  252. package/src/lib/options/reset-map-options.ts +0 -28
  253. package/src/lib/reactivity.svelte.ts +0 -82
  254. package/src/lib/wind/wind.svelte.ts +0 -20
@@ -1,301 +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 { monitorsManager } from "./monitors.svelte";
6
- import { getIconId, MonitorsIconManager } from "./monitors-icon-manager.svelte";
7
- import { TooltipManager } from "../map/integrations/tooltip.svelte";
8
- import { MapDisplayOption } from "../map/integrations/map-display-option.svelte";
9
- import { getCurrentLevel, getOrder } from "./monitor-utils";
10
- import { MonitorsClusterRenderer, monitorTooltip } from "./monitors-cluster-renderer";
11
- const filters = {
12
- monitor(deviceType) {
13
- return ["==", ["get", "type"], deviceType];
14
- }
15
- };
16
- class MonitorsMapIntegration extends MapIconLayerIntegration {
17
- dataSource;
18
- referenceId = "monitors";
19
- enabled = $state(true);
20
- clustered = $state(true);
21
- icons;
22
- tooltipManager = new TooltipManager();
23
- renderer = new MonitorsClusterRenderer(this);
24
- displayOptions = $derived.by(() => ({
25
- airnow: new MapDisplayOption("AirNow", true, this.icons.get("outside-display-triangle")),
26
- aqlite: new MapDisplayOption("AQLite", true, this.icons.get("outside-display-triangle")),
27
- aqview: new MapDisplayOption("AQview", true, this.icons.get("outside-display-triangle")),
28
- bam1022: new MapDisplayOption("SJVAir", true, this.icons.get("outside-display-triangle")),
29
- airgradient: new MapDisplayOption("AirGradient", true, this.icons.get("outside-display-circle")),
30
- purpleair: new MapDisplayOption("PurpleAir", true, this.icons.get("outside-display-circle")),
31
- vozbox: new MapDisplayOption("VOZbox", true, this.icons.get("outside-display-circle")),
32
- inactive: new MapDisplayOption("Inactive", false, this.icons.get("outside-default-circle")),
33
- inside: new MapDisplayOption("Inside", false, this.icons.get("inside-display-circle"))
34
- }));
35
- /** Set by the app to handle navigation when a monitor is clicked. Receives the monitor ID. */
36
- onMonitorClick = null;
37
- selectedMonitorId = $state(null);
38
- handleMonitorClick = (features) => {
39
- if (!this.onMonitorClick)
40
- return;
41
- const sorted = [...features].sort((a, b) => (b.properties?.order ?? 0) - (a.properties?.order ?? 0));
42
- const top = sorted[0];
43
- if (!top?.properties?.id)
44
- return;
45
- this.selectedMonitorId = top.properties.id;
46
- this.onMonitorClick(this.selectedMonitorId);
47
- if (top.geometry.type !== "Point")
48
- return;
49
- const coords = top.geometry.coordinates;
50
- mapManager.map?.easeTo({
51
- center: coords,
52
- zoom: Math.max(mapManager.map.getZoom(), 12)
53
- });
54
- };
55
- features = $derived.by(() => {
56
- if (!this.dataSource.meta || !this.dataSource.latest || !this.dataSource.pollutant) {
57
- return [];
58
- }
59
- const levels = this.dataSource.meta.entryType(this.dataSource.pollutant).asIter.levels;
60
- return Array.from(this.dataSource.latest.values().map((m) => {
61
- const feature = {
62
- type: "Feature",
63
- properties: {
64
- icon: "outside-default-square",
65
- id: m.id,
66
- is_active: m.is_active,
67
- is_sjvair: m.is_sjvair,
68
- location: m.location,
69
- name: m.name,
70
- order: getOrder(m),
71
- type: m.type,
72
- value: m.latest.value
73
- },
74
- geometry: m.position
75
- };
76
- if (levels) {
77
- const level = getCurrentLevel(m.latest.value, levels);
78
- if (level) {
79
- feature.properties.icon = getIconId(m, level);
80
- }
81
- }
82
- return feature;
83
- }));
84
- });
85
- filters = $derived.by(() => {
86
- const monitorFilters = ["any"];
87
- const locationFilters = [
88
- "any",
89
- ["==", ["get", "location"], "outside"]
90
- ];
91
- const statusFilters = ["any", ["==", ["get", "is_active"], true]];
92
- if (this.displayOptions.airnow.value)
93
- monitorFilters.push(filters.monitor("airnow"));
94
- if (this.displayOptions.aqlite.value)
95
- monitorFilters.push(filters.monitor("aqlite"));
96
- if (this.displayOptions.aqview.value)
97
- monitorFilters.push(filters.monitor("aqview"));
98
- if (this.displayOptions.bam1022.value)
99
- monitorFilters.push(filters.monitor("bam1022"));
100
- if (this.displayOptions.airgradient.value)
101
- monitorFilters.push(filters.monitor("airgradient"));
102
- if (this.displayOptions.purpleair.value)
103
- monitorFilters.push(filters.monitor("purpleair"));
104
- if (this.displayOptions.vozbox.value)
105
- monitorFilters.push(filters.monitor("vozbox"));
106
- if (this.displayOptions.inside.value)
107
- locationFilters.push(["==", ["get", "location"], "inside"]);
108
- if (this.displayOptions.inactive.value)
109
- statusFilters.push(["==", ["get", "is_active"], false]);
110
- return ["all", monitorFilters, locationFilters, statusFilters];
111
- });
112
- // Groups features by monitor type for per-type cluster sources, applying display option
113
- // filters so cluster aggregates only include visible monitors.
114
- featuresByType = $derived.by(() => {
115
- const opts = this.displayOptions;
116
- const byType = {};
117
- for (const feat of this.features) {
118
- const p = feat.properties;
119
- if (!p.is_active && !opts.inactive.value)
120
- continue;
121
- if (p.location === "inside" && !opts.inside.value)
122
- continue;
123
- const typeVisible = {
124
- airnow: opts.airnow.value,
125
- aqlite: opts.aqlite.value,
126
- aqview: opts.aqview.value,
127
- bam1022: opts.bam1022.value,
128
- airgradient: opts.airgradient.value,
129
- purpleair: opts.purpleair.value,
130
- vozbox: opts.vozbox.value
131
- };
132
- if (!(typeVisible[p.type] ?? true))
133
- continue;
134
- const arr = byType[p.type] ?? [];
135
- arr.push(feat);
136
- byType[p.type] = arr;
137
- }
138
- return byType;
139
- });
140
- clusterIconThresholds = $derived.by(() => {
141
- if (!this.dataSource.meta || !this.dataSource.pollutant)
142
- return [];
143
- return this.dataSource.meta.entryType(this.dataSource.pollutant).asIter.levels ?? [];
144
- });
145
- get mapLayer() {
146
- return {
147
- id: this.referenceId,
148
- type: "symbol",
149
- source: this.referenceId,
150
- filter: this.filters,
151
- layout: {
152
- "symbol-sort-key": ["coalesce", ["get", "order"], 0],
153
- "icon-allow-overlap": true,
154
- "icon-ignore-placement": true,
155
- "icon-image": ["get", "icon"],
156
- "icon-size": 1
157
- },
158
- paint: {}
159
- };
160
- }
161
- get mapSource() {
162
- return {
163
- type: "geojson",
164
- promoteId: "id",
165
- data: {
166
- type: "FeatureCollection",
167
- features: this.features
168
- }
169
- };
170
- }
171
- constructor(dataSource = monitorsManager) {
172
- super();
173
- this.dataSource = dataSource;
174
- this.icons = new MonitorsIconManager(dataSource);
175
- $effect.root(() => {
176
- // Every effect below early-returns while disabled (Pollutant = None) so a data refresh
177
- // can't re-add the layer. `enabled` is read untracked: the base class's own effect
178
- // already applies/removes on enabled changes, and tracking it here would apply twice.
179
- // The guard comes after each effect's tracked reads so its dependencies are always
180
- // collected; returning before reading anything would leave the effect permanently dead.
181
- // Push filter changes to the active layer(s) imperatively
182
- $effect(() => {
183
- const filter = this.filters;
184
- const clustered = this.clustered;
185
- if (!mapManager.map)
186
- return;
187
- if (!untrack(() => this.enabled))
188
- return;
189
- if (clustered) {
190
- this.renderer.syncFilter();
191
- }
192
- else {
193
- if (mapManager.map.getLayer(this.referenceId)) {
194
- mapManager.map.setFilter(this.referenceId, filter);
195
- }
196
- }
197
- });
198
- // Sync unclustered source data when features change
199
- $effect(() => {
200
- const features = this.features;
201
- if (!mapManager.map || this.clustered)
202
- return;
203
- if (!untrack(() => this.enabled))
204
- return;
205
- mapManager.setDataSource(this.referenceId, features);
206
- });
207
- // Keep cluster source data in sync when features or display options change
208
- $effect(() => {
209
- void this.featuresByType;
210
- if (!mapManager.map || !this.clustered)
211
- return;
212
- if (!untrack(() => this.enabled))
213
- return;
214
- this.renderer.syncFeatures();
215
- });
216
- // Push updated icon expressions to cluster layers when the pollutant changes
217
- $effect(() => {
218
- const thresholds = this.clusterIconThresholds;
219
- if (!mapManager.map || !this.clustered || !thresholds.length)
220
- return;
221
- if (!untrack(() => this.enabled))
222
- return;
223
- this.renderer.syncThresholds();
224
- });
225
- // Re-apply when clustered mode switches or when data first arrives (cold load).
226
- // featuresByType is tracked so this fires once data is available; untrack on apply()
227
- // prevents reactive reads inside it from leaking into this effect's dependency graph.
228
- $effect(() => {
229
- void this.clustered;
230
- const hasFeatures = Object.keys(this.featuresByType).length > 0;
231
- if (!untrack(() => mapManager.map) || !hasFeatures)
232
- return;
233
- if (!untrack(() => this.enabled))
234
- return;
235
- untrack(() => this.apply());
236
- });
237
- // Sync selected icon scale via feature state
238
- $effect(() => {
239
- void this.selectedMonitorId;
240
- if (!mapManager.map)
241
- return;
242
- untrack(() => this.applySelectedState());
243
- });
244
- });
245
- }
246
- apply() {
247
- if (!mapManager.map)
248
- return;
249
- if (!this.tooltipManager.has(this.referenceId)) {
250
- this.tooltipManager.register(this.referenceId, monitorTooltip);
251
- }
252
- if (this.clustered) {
253
- if (mapManager.map.getLayer(this.referenceId))
254
- mapManager.map.removeLayer(this.referenceId);
255
- if (mapManager.map.getSource(this.referenceId))
256
- mapManager.map.removeSource(this.referenceId);
257
- clickManager.unregister([this.referenceId]);
258
- this.tooltipManager.disable();
259
- this.renderer.remove();
260
- // Clustering may be toggled again before the icons arrive; only the latest apply runs.
261
- this.supersedePending();
262
- this.whenIconsLoad(() => {
263
- this.renderer.apply(this.handleMonitorClick);
264
- this.tooltipManager.enable();
265
- this.applySelectedState();
266
- });
267
- }
268
- else {
269
- this.tooltipManager.disable();
270
- this.renderer.remove();
271
- this.tooltipManager.enable();
272
- clickManager.unregister([this.referenceId]);
273
- super.apply();
274
- this.whenIconsLoad(() => {
275
- clickManager.register([this.referenceId], this.handleMonitorClick);
276
- this.applySelectedState();
277
- });
278
- }
279
- }
280
- remove() {
281
- this.tooltipManager.disable();
282
- clickManager.unregister([this.referenceId]);
283
- this.renderer.remove();
284
- super.remove();
285
- }
286
- applySelectedState() {
287
- if (!mapManager.map)
288
- return;
289
- const layerIds = this.clustered ? this.renderer.unclusteredLayerIds : [this.referenceId];
290
- const iconSize = this.selectedMonitorId
291
- ? ["match", ["get", "id"], this.selectedMonitorId, 1.3, 1]
292
- : 1;
293
- for (const layerId of layerIds) {
294
- if (!mapManager.map.getLayer(layerId))
295
- continue;
296
- mapManager.map.setLayoutProperty(layerId, "icon-size", iconSize);
297
- }
298
- }
299
- }
300
- export const monitorsMapIntegration = new MonitorsMapIntegration();
301
- export { MonitorsMapIntegration };
@@ -1,2 +0,0 @@
1
- /** "Reset Map Options": restores every map option to its default. */
2
- export declare function resetMapOptions(): void;
@@ -1,24 +0,0 @@
1
- import { monitorsManager } from "../monitors/monitors.svelte";
2
- import { monitorsMapIntegration } from "../monitors/monitors-map-integration.svelte";
3
- import { collocationSitesMapIntegration } from "../collocation-sites/collocations-map-integration.svelte";
4
- import { hmsFireMapIntegration } from "../hms/hms-fire-map-integration.svelte";
5
- import { hmsSmokeMapIntegration } from "../hms/hms-smoke-map-integration.svelte";
6
- import { evStationsMapIntegration } from "../ev-stations/ev-stations-map-integration.svelte";
7
- import { windMapIntegration } from "../wind/wind.svelte";
8
- import { mapStyleState } from "../map/map-style-state.svelte.js";
9
- import { applyMapOptionDefaults } from "./map-option-defaults";
10
- /** "Reset Map Options": restores every map option to its default. */
11
- export function resetMapOptions() {
12
- applyMapOptionDefaults({
13
- manager: monitorsManager,
14
- integration: monitorsMapIntegration,
15
- collocationSites: collocationSitesMapIntegration,
16
- hmsFire: hmsFireMapIntegration,
17
- hmsSmoke: hmsSmokeMapIntegration,
18
- evStations: evStationsMapIntegration,
19
- wind: windMapIntegration,
20
- // The basemap reset may start loading a new style; integrations skip the style while
21
- // mapManager.styleLoading is set and the refresh on "style.load" re-applies them.
22
- mapStyle: mapStyleState
23
- }, monitorsManager.meta?.default_pollutant ?? null);
24
- }
File without changes
@@ -1,83 +0,0 @@
1
- "use strict";
2
- //class ReactiveState<T> {
3
- // private internalValue?: T = $state();
4
- //
5
- // constructor(initialValue?: T) {
6
- // this.internalValue = initialValue;
7
- // }
8
- // get value(): T | undefined {
9
- // return this.internalValue;
10
- // }
11
- //
12
- // set value(newValue: T) {
13
- // // Perform any validation or side effects here
14
- // this.internalValue = newValue; // Update the reactive state
15
- // }
16
- //}
17
- //
18
- //class ShallowReactiveState<T> {
19
- // private internalValue?: T = $state.raw();
20
- //
21
- // constructor(initialValue?: T) {
22
- // this.internalValue = initialValue;
23
- // }
24
- // get value(): T | undefined {
25
- // return this.internalValue;
26
- // }
27
- //
28
- // set value(newValue: T) {
29
- // // Perform any validation or side effects here
30
- // this.internalValue = newValue; // Update the reactive state
31
- // }
32
- //}
33
- //
34
- //
35
- //class DerivedReactiveState<T> {
36
- // private internalValue?: T;
37
- //
38
- // constructor(expression: () => T) {
39
- // this.internalValue = $derived.by(expression);
40
- // }
41
- // get value(): T | undefined {
42
- // return this.internalValue;
43
- // }
44
- // set value(newValue: T) {
45
- // this.internalValue = newValue;
46
- // }
47
- //}
48
- //
49
- //export function Derived<V>(value: () => V) {
50
- // let ref: DerivedReactiveState<V> = new DerivedReactiveState<V>(value);
51
- // return function <V, T = unknown>(
52
- // _target: ClassAccessorDecoratorTarget<T, V>,
53
- // _ctx: ClassAccessorDecoratorContext,
54
- // ): ClassAccessorDecoratorResult<T, V> {
55
- //
56
- // return {
57
- // get() {
58
- // return ref.value as V;
59
- // },
60
- // };
61
- // }
62
- //}
63
- //export function Reactive(shallow?: boolean) {
64
- // return function <V, T = unknown>(
65
- // _target: ClassAccessorDecoratorTarget<T, V>,
66
- // _ctx: ClassAccessorDecoratorContext,
67
- // ): ClassAccessorDecoratorResult<T, V> {
68
- // let ref = shallow ? new ShallowReactiveState<V>() : new ReactiveState<V>();
69
- //
70
- // return {
71
- // get(): V {
72
- // return ref.value as V;
73
- // },
74
- // set(newValue): void {
75
- // ref.value = newValue;
76
- // },
77
- // init(initialValue: V): V {
78
- // ref.value = initialValue;
79
- // return ref.value as V;
80
- // }
81
- // };
82
- // };
83
- //}
@@ -1,10 +0,0 @@
1
- import { Map as MaptilerMap } from "@maptiler/sdk";
2
- import { MapLayerIntegration } from "../map/integrations/map-layer-integration.svelte";
3
- declare class WindMapIntegration extends MapLayerIntegration {
4
- referenceId: string;
5
- beforeLayer: string;
6
- enabled: boolean;
7
- mapLayer: Parameters<MaptilerMap["addLayer"]>[0];
8
- }
9
- export declare const windMapIntegration: WindMapIntegration;
10
- export type { WindMapIntegration };
@@ -1,13 +0,0 @@
1
- import { WindLayer } from "@maptiler/weather";
2
- import { baseLayerSeperator } from "../map/integrations/base-layer-seperator";
3
- import { MapLayerIntegration } from "../map/integrations/map-layer-integration.svelte";
4
- class WindMapIntegration extends MapLayerIntegration {
5
- referenceId = "MapTiler Wind";
6
- beforeLayer = baseLayerSeperator.referenceId;
7
- enabled = $state(false);
8
- mapLayer = new WindLayer({
9
- id: this.referenceId,
10
- opacity: 0.5
11
- });
12
- }
13
- export const windMapIntegration = new WindMapIntegration();
@@ -1,98 +0,0 @@
1
- <script lang="ts">
2
- import { format, formatDistanceToNow } from "date-fns";
3
- import DataBox from "$lib/components/DataBox.svelte";
4
- import type { CollocationSiteMapFeature } from "./types";
5
- import { monitorsManager } from "$lib/monitors/monitors.svelte";
6
- import { getCurrentLevel } from "$lib/monitors/monitor-utils";
7
- import type { MonitorLatest, SJVAirEntryLevel } from "@sjvair/sdk";
8
-
9
- interface CollocationTooltipProps {
10
- feature: CollocationSiteMapFeature;
11
- }
12
-
13
- const { feature }: CollocationTooltipProps = $props();
14
-
15
- const data = $derived.by(() => {
16
- const collocated = monitorsManager.latest?.get(feature.properties.colocated_id);
17
- const reference = monitorsManager.latest?.get(feature.properties.reference_id);
18
-
19
- return {
20
- collocated: getMonitorData(collocated),
21
- reference: getMonitorData(reference)
22
- };
23
- });
24
-
25
- function getMonitorData(monitor: MonitorLatest | undefined) {
26
- if (!monitor || !("value" in monitor.latest) || !monitorsManager.meta) return;
27
-
28
- const entryType = monitorsManager.meta.entryType(monitor.latest.entry_type);
29
- const level: SJVAirEntryLevel | undefined = getCurrentLevel(
30
- monitor.latest.value,
31
- entryType.asIter.levels!
32
- );
33
-
34
- const updateDuration = monitorsManager.meta.monitorType(monitor.type).expected_interval;
35
-
36
- return {
37
- color: level?.color ?? "",
38
- header: entryType.label,
39
- date: {
40
- formatted: format(monitor.latest.timestamp, "h:mm:aaa EEEE MMM dd, yyyy"),
41
- diference: formatDistanceToNow(monitor.latest.timestamp, {
42
- addSuffix: true,
43
- includeSeconds: true
44
- })
45
- },
46
- monitorName: monitor.name,
47
- subheading: `(${updateDuration} avg)`,
48
- value: Math.round(parseInt(monitor.latest.value, 10)).toString()
49
- };
50
- }
51
- </script>
52
-
53
- {#if data}
54
- <div class="flex flex-col gap-4">
55
- {#if data.reference}
56
- <div class="flex gap-2">
57
- <DataBox
58
- color={data.reference.color}
59
- header={data.reference.header}
60
- subheading={data.reference.subheading}
61
- value={data.reference.value}
62
- />
63
- <div class="flex flex-col">
64
- <p class="leading-none">{data.reference.date.formatted}</p>
65
- <h1 class="text-lg font-bold underline">{data.reference.monitorName}</h1>
66
- <p class="leading-none">Reference monitor</p>
67
- <div class="mt-auto">
68
- <p class="text-base leading-none">Last updated</p>
69
- <p class="text-base leading-none">{data.reference.date.diference}</p>
70
- </div>
71
- </div>
72
- </div>
73
- {:else}
74
- <h1>Reference monitor disabled</h1>
75
- {/if}
76
- {#if data.collocated}
77
- <div class="flex flex-row-reverse gap-2">
78
- <DataBox
79
- color={data.collocated.color}
80
- header={data.collocated.header}
81
- subheading={data.collocated.subheading}
82
- value={data.collocated.value}
83
- />
84
- <div class="flex flex-col">
85
- <p class="leading-none">{data.collocated.date.formatted}</p>
86
- <h1 class="text-lg font-bold underline">{data.collocated.monitorName}</h1>
87
- <p class="leading-none">Collocated monitor</p>
88
- <div class="mt-auto">
89
- <p class="text-base leading-none">Last updated</p>
90
- <p class="text-base leading-none">{data.collocated.date.diference}</p>
91
- </div>
92
- </div>
93
- </div>
94
- {:else}
95
- <h1>Collocated monitor disabled</h1>
96
- {/if}
97
- </div>
98
- {/if}
@@ -1,21 +0,0 @@
1
- import { CROSSHAIR_ICON_SIZE, withCrosshair } from "$lib/map/icons";
2
- import { MonitorShapeIconManager } from "$lib/monitors/monitors-icon-manager.svelte";
3
-
4
- const COLLOCATION_ICON_PREFIX = "collocation";
5
- const CROSSHAIR_COLOR = "#4A5FC6";
6
-
7
- export function getCollocationIconId(baseIconId: string): string {
8
- return `${COLLOCATION_ICON_PREFIX}-${baseIconId}`;
9
- }
10
-
11
- export class CollocationIconManager extends MonitorShapeIconManager {
12
- protected get idPrefix(): string {
13
- return COLLOCATION_ICON_PREFIX;
14
- }
15
- protected get iconSize(): number {
16
- return CROSSHAIR_ICON_SIZE;
17
- }
18
- protected transformSvg(svg: string): string {
19
- return withCrosshair(svg, CROSSHAIR_COLOR);
20
- }
21
- }