@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.
- package/LICENSE +21 -0
- package/README.md +59 -138
- package/dist/lib/MonitorDetailPanel.svelte +23 -20
- package/dist/lib/MonitorMapLayout.svelte +147 -77
- package/dist/lib/components/DataBox.svelte +4 -1
- package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
- package/dist/lib/config.svelte.d.ts +7 -0
- package/dist/lib/config.svelte.js +10 -0
- package/dist/lib/core.d.ts +2 -2
- package/dist/lib/core.js +2 -1
- package/dist/lib/data-chart/DataChart.svelte +40 -25
- package/dist/lib/data-chart/DateRange.d.ts +13 -4
- package/dist/lib/data-chart/DateRange.js +50 -14
- package/dist/lib/data-chart/chart-utils.js +5 -7
- package/dist/lib/data-chart/level-colors.d.ts +3 -4
- package/dist/lib/data-chart/level-colors.js +7 -4
- package/dist/lib/data-chart/pacific-time.d.ts +9 -0
- package/dist/lib/data-chart/pacific-time.js +25 -0
- package/dist/lib/data-chart/tooltip.js +2 -2
- package/{src/lib/ev-stations/components/EvStationTooltip.svelte → dist/lib/ev-stations/EvPopup.svelte} +6 -5
- package/dist/lib/ev-stations/EvPopup.svelte.d.ts +7 -0
- package/dist/lib/ev-stations/ev-plugin.svelte.d.ts +14 -0
- package/dist/lib/ev-stations/ev-plugin.svelte.js +71 -0
- package/dist/lib/ev-stations/ev-station-icons.d.ts +1 -4
- package/dist/lib/ev-stations/ev-station-icons.js +1 -13
- package/dist/lib/ev-stations/ev-stations.d.ts +7 -0
- package/dist/lib/ev-stations/ev-stations.js +53 -0
- package/dist/lib/ev-stations/ev-store.svelte.d.ts +21 -0
- package/dist/lib/ev-stations/ev-store.svelte.js +83 -0
- package/dist/lib/ev-stations/station-popup.svelte.d.ts +14 -0
- package/dist/lib/ev-stations/station-popup.svelte.js +54 -0
- package/dist/lib/ev-stations/types.d.ts +0 -29
- package/dist/lib/ev-stations/zip-codes.d.ts +11 -0
- package/dist/lib/ev-stations/zip-codes.js +28 -16
- package/dist/lib/index.d.ts +8 -56
- package/dist/lib/index.js +7 -46
- package/dist/lib/legend/Legend.svelte +18 -19
- package/dist/lib/legend/Legend.svelte.d.ts +2 -2
- package/dist/lib/levels.d.ts +7 -0
- package/dist/lib/levels.js +19 -0
- package/dist/lib/map/MapShell.svelte +17 -24
- package/dist/lib/map/MapShell.svelte.d.ts +4 -4
- package/dist/lib/map/basemaps.d.ts +25 -0
- package/dist/lib/map/basemaps.js +66 -0
- package/dist/lib/map/live-map.svelte.d.ts +3 -0
- package/dist/lib/map/live-map.svelte.js +22 -0
- package/dist/lib/map/sync-plugins.svelte.d.ts +19 -0
- package/dist/lib/map/sync-plugins.svelte.js +52 -0
- package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
- package/dist/lib/monitors/filtered-source.svelte.d.ts +9 -0
- package/dist/lib/monitors/filtered-source.svelte.js +28 -0
- package/dist/lib/monitors/monitors.svelte.d.ts +25 -35
- package/dist/lib/monitors/monitors.svelte.js +35 -218
- package/dist/lib/monitors/retry-load.d.ts +8 -0
- package/dist/lib/monitors/retry-load.js +11 -0
- package/dist/lib/monitors/types.d.ts +1 -41
- package/dist/lib/options/map-option-defaults.d.ts +25 -36
- package/dist/lib/options/map-option-defaults.js +12 -30
- package/dist/lib/options/map-options.svelte.d.ts +13 -0
- package/dist/lib/options/map-options.svelte.js +26 -0
- package/dist/lib/options/menus/LayersMenu.svelte +8 -20
- package/dist/lib/options/menus/LayersMenu.svelte.d.ts +17 -2
- package/dist/lib/options/menus/MonitorsMenu.svelte +34 -18
- package/dist/lib/options/menus/OverlaysMenu.svelte +2 -2
- package/dist/lib/options/menus/PollutantMenu.svelte +4 -9
- package/dist/lib/options/menus/SettingsMenu.svelte +32 -25
- package/dist/lib/options/menus/SettingsMenu.svelte.d.ts +5 -16
- package/dist/lib/options/plugin-order.d.ts +8 -0
- package/dist/lib/options/plugin-order.js +36 -0
- package/dist/lib/options/pollutant-param.d.ts +7 -5
- package/dist/lib/options/pollutant-param.js +9 -5
- package/dist/lib/options/row-icons.d.ts +8 -0
- package/dist/lib/options/row-icons.js +15 -0
- package/dist/lib/options/rows/MarkerIcon.svelte +5 -5
- package/dist/lib/options/rows/MarkerIcon.svelte.d.ts +1 -2
- package/dist/lib/search/Search.svelte +20 -33
- package/dist/lib/search/Search.svelte.d.ts +5 -1
- package/dist/lib/search/search-pin.svelte.d.ts +11 -0
- package/dist/lib/search/search-pin.svelte.js +28 -0
- package/dist/lib/search/service.d.ts +7 -2
- package/dist/lib/search/service.js +17 -10
- package/dist/lib/stores.svelte.d.ts +8 -0
- package/dist/lib/stores.svelte.js +9 -0
- package/dist/lib/wind/wind-plugin.d.ts +11 -0
- package/dist/lib/wind/wind-plugin.js +25 -0
- package/package.json +12 -10
- package/src/lib/MonitorDetailPanel.svelte +23 -20
- package/src/lib/MonitorMapLayout.svelte +147 -77
- package/src/lib/components/DataBox.svelte +4 -1
- package/src/lib/config.svelte.ts +16 -0
- package/src/lib/core.ts +2 -2
- package/src/lib/data-chart/DataChart.svelte +40 -25
- package/src/lib/data-chart/DateRange.ts +58 -15
- package/src/lib/data-chart/chart-utils.ts +6 -7
- package/src/lib/data-chart/level-colors.ts +8 -9
- package/src/lib/data-chart/pacific-time.ts +31 -0
- package/src/lib/data-chart/tooltip.ts +2 -2
- package/{dist/lib/ev-stations/components/EvStationTooltip.svelte → src/lib/ev-stations/EvPopup.svelte} +6 -5
- package/src/lib/ev-stations/ev-plugin.svelte.ts +86 -0
- package/src/lib/ev-stations/ev-station-icons.ts +1 -17
- package/src/lib/ev-stations/ev-stations.ts +72 -0
- package/src/lib/ev-stations/ev-store.svelte.ts +117 -0
- package/src/lib/ev-stations/station-popup.svelte.ts +64 -0
- package/src/lib/ev-stations/types.ts +0 -34
- package/src/lib/ev-stations/zip-codes.ts +29 -16
- package/src/lib/index.ts +8 -99
- package/src/lib/legend/Legend.svelte +18 -19
- package/src/lib/levels.ts +24 -0
- package/src/lib/map/MapShell.svelte +17 -24
- package/src/lib/map/basemaps.ts +76 -0
- package/src/lib/map/live-map.svelte.ts +24 -0
- package/src/lib/map/sync-plugins.svelte.ts +69 -0
- package/src/lib/monitors/components/MonitorSubscriptionManager.svelte +66 -61
- package/src/lib/monitors/filtered-source.svelte.ts +38 -0
- package/src/lib/monitors/monitors.svelte.ts +58 -261
- package/src/lib/monitors/retry-load.ts +14 -0
- package/src/lib/monitors/types.ts +1 -47
- package/src/lib/options/map-option-defaults.ts +30 -53
- package/src/lib/options/map-options.svelte.ts +30 -0
- package/src/lib/options/menus/LayersMenu.svelte +8 -20
- package/src/lib/options/menus/MonitorsMenu.svelte +34 -18
- package/src/lib/options/menus/OverlaysMenu.svelte +2 -2
- package/src/lib/options/menus/PollutantMenu.svelte +4 -9
- package/src/lib/options/menus/SettingsMenu.svelte +32 -25
- package/src/lib/options/plugin-order.ts +38 -0
- package/src/lib/options/pollutant-param.ts +14 -9
- package/src/lib/options/row-icons.ts +17 -0
- package/src/lib/options/rows/MarkerIcon.svelte +5 -5
- package/src/lib/search/Search.svelte +20 -33
- package/src/lib/search/search-pin.svelte.ts +35 -0
- package/src/lib/search/service.ts +34 -15
- package/src/lib/stores.svelte.ts +15 -0
- package/src/lib/wind/wind-plugin.ts +33 -0
- package/dist/lib/collocation-sites/CollocationTooltip.svelte +0 -98
- package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +0 -7
- package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +0 -7
- package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +0 -18
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +0 -21
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +0 -113
- package/dist/lib/collocation-sites/collocations.svelte.d.ts +0 -10
- package/dist/lib/collocation-sites/collocations.svelte.js +0 -21
- package/dist/lib/collocation-sites/types.d.ts +0 -8
- package/dist/lib/collocation-sites/types.js +0 -1
- package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
- package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +0 -7
- package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +0 -7
- package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +0 -19
- package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +0 -131
- package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +0 -31
- package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +0 -226
- package/dist/lib/ev-stations/ev-stations.svelte.d.ts +0 -10
- package/dist/lib/ev-stations/ev-stations.svelte.js +0 -57
- package/dist/lib/hms/hms-fire-icon-manager.d.ts +0 -13
- package/dist/lib/hms/hms-fire-icon-manager.js +0 -39
- package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +0 -23
- package/dist/lib/hms/hms-fire-map-integration.svelte.js +0 -94
- package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +0 -39
- package/dist/lib/hms/hms-smoke-map-integration.svelte.js +0 -87
- package/dist/lib/hms/hms.svelte.d.ts +0 -20
- package/dist/lib/hms/hms.svelte.js +0 -237
- package/dist/lib/legend/LegendBar.svelte +0 -45
- package/dist/lib/legend/LegendBar.svelte.d.ts +0 -7
- package/dist/lib/legend/legend-data.d.ts +0 -40
- package/dist/lib/legend/legend-data.js +0 -65
- package/dist/lib/map/Map.svelte +0 -13
- package/dist/lib/map/Map.svelte.d.ts +0 -8
- package/dist/lib/map/basemap.d.ts +0 -14
- package/dist/lib/map/basemap.js +0 -10
- package/dist/lib/map/icons.d.ts +0 -7
- package/dist/lib/map/icons.js +0 -33
- package/dist/lib/map/integrations/base-layer-seperator.d.ts +0 -9
- package/dist/lib/map/integrations/base-layer-seperator.js +0 -11
- package/dist/lib/map/integrations/click-manager.d.ts +0 -14
- package/dist/lib/map/integrations/click-manager.js +0 -52
- package/dist/lib/map/integrations/integrations-manager.d.ts +0 -8
- package/dist/lib/map/integrations/integrations-manager.js +0 -20
- package/dist/lib/map/integrations/map-display-option.svelte.d.ts +0 -7
- package/dist/lib/map/integrations/map-display-option.svelte.js +0 -10
- package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +0 -32
- package/dist/lib/map/integrations/map-geojson-integration.svelte.js +0 -60
- package/dist/lib/map/integrations/map-icon-manager.d.ts +0 -15
- package/dist/lib/map/integrations/map-icon-manager.js +0 -52
- package/dist/lib/map/integrations/map-integration.svelte.d.ts +0 -6
- package/dist/lib/map/integrations/map-integration.svelte.js +0 -2
- package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +0 -11
- package/dist/lib/map/integrations/map-layer-integration.svelte.js +0 -40
- package/dist/lib/map/integrations/tooltip.svelte.d.ts +0 -36
- package/dist/lib/map/integrations/tooltip.svelte.js +0 -131
- package/dist/lib/map/integrations/types.d.ts +0 -14
- package/dist/lib/map/integrations/types.js +0 -1
- package/dist/lib/map/map-manager.svelte.d.ts +0 -20
- package/dist/lib/map/map-manager.svelte.js +0 -63
- package/dist/lib/map/map-style-state.svelte.d.ts +0 -23
- package/dist/lib/map/map-style-state.svelte.js +0 -86
- package/dist/lib/map/utils.d.ts +0 -7
- package/dist/lib/map/utils.js +0 -36
- package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
- package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +0 -7
- package/dist/lib/monitors/components/MonitorTooltip.svelte +0 -61
- package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +0 -7
- package/dist/lib/monitors/monitor-utils.d.ts +0 -4
- package/dist/lib/monitors/monitor-utils.js +0 -41
- package/dist/lib/monitors/monitors-cluster-renderer.d.ts +0 -33
- package/dist/lib/monitors/monitors-cluster-renderer.js +0 -221
- package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +0 -15
- package/dist/lib/monitors/monitors-icon-manager.svelte.js +0 -78
- package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +0 -43
- package/dist/lib/monitors/monitors-map-integration.svelte.js +0 -301
- package/dist/lib/options/reset-map-options.d.ts +0 -2
- package/dist/lib/options/reset-map-options.js +0 -24
- package/dist/lib/reactivity.svelte.d.ts +0 -0
- package/dist/lib/reactivity.svelte.js +0 -83
- package/dist/lib/wind/wind.svelte.d.ts +0 -10
- package/dist/lib/wind/wind.svelte.js +0 -13
- package/src/lib/collocation-sites/CollocationTooltip.svelte +0 -98
- package/src/lib/collocation-sites/collocations-icon-manager.svelte.ts +0 -21
- package/src/lib/collocation-sites/collocations-map-integration.svelte.ts +0 -136
- package/src/lib/collocation-sites/collocations.svelte.ts +0 -27
- package/src/lib/collocation-sites/types.ts +0 -10
- package/src/lib/ev-stations/components/EvStationClusterTooltip.svelte +0 -16
- package/src/lib/ev-stations/ev-stations-cluster-renderer.ts +0 -162
- package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +0 -248
- package/src/lib/ev-stations/ev-stations.svelte.ts +0 -84
- package/src/lib/hms/hms-fire-icon-manager.ts +0 -48
- package/src/lib/hms/hms-fire-map-integration.svelte.ts +0 -109
- package/src/lib/hms/hms-smoke-map-integration.svelte.ts +0 -105
- package/src/lib/hms/hms.svelte.ts +0 -270
- package/src/lib/legend/LegendBar.svelte +0 -45
- package/src/lib/legend/legend-data.ts +0 -101
- package/src/lib/map/Map.svelte +0 -13
- package/src/lib/map/basemap.ts +0 -24
- package/src/lib/map/icons.ts +0 -42
- package/src/lib/map/integrations/base-layer-seperator.ts +0 -17
- package/src/lib/map/integrations/click-manager.ts +0 -64
- package/src/lib/map/integrations/integrations-manager.ts +0 -25
- package/src/lib/map/integrations/map-display-option.svelte.ts +0 -13
- package/src/lib/map/integrations/map-geojson-integration.svelte.ts +0 -77
- package/src/lib/map/integrations/map-icon-manager.ts +0 -67
- package/src/lib/map/integrations/map-integration.svelte.ts +0 -8
- package/src/lib/map/integrations/map-layer-integration.svelte.ts +0 -49
- package/src/lib/map/integrations/tooltip.svelte.ts +0 -153
- package/src/lib/map/integrations/types.ts +0 -24
- package/src/lib/map/map-manager.svelte.ts +0 -83
- package/src/lib/map/map-style-state.svelte.ts +0 -94
- package/src/lib/map/utils.ts +0 -53
- package/src/lib/monitors/components/MonitorClusterTooltip.svelte +0 -112
- package/src/lib/monitors/components/MonitorTooltip.svelte +0 -61
- package/src/lib/monitors/monitor-utils.ts +0 -57
- package/src/lib/monitors/monitors-cluster-renderer.ts +0 -285
- package/src/lib/monitors/monitors-icon-manager.svelte.ts +0 -98
- package/src/lib/monitors/monitors-map-integration.svelte.ts +0 -318
- package/src/lib/options/reset-map-options.ts +0 -28
- package/src/lib/reactivity.svelte.ts +0 -82
- package/src/lib/wind/wind.svelte.ts +0 -20
|
@@ -1,17 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
getMonitorsMeta,
|
|
5
|
-
type MonitorData,
|
|
6
|
-
type MonitorLatestType,
|
|
7
|
-
type MonitorsMeta,
|
|
8
|
-
type SJVAirEntryLevel
|
|
9
|
-
} from "@sjvair/sdk";
|
|
10
|
-
import { XMap } from "@tstk/builtin-extensions";
|
|
11
|
-
import { Interval } from "@tstk/utils";
|
|
12
|
-
import { untrack } from "svelte";
|
|
13
|
-
import { anySignal, untilAborted, type SignalOptions } from "$lib/abort";
|
|
14
|
-
import type { MonitorsDataSource, MonitorsPollutant } from "./types";
|
|
1
|
+
import type { MonitorData, MonitorsMeta } from "@sjvair/sdk";
|
|
2
|
+
import type { MonitorsStore } from "@sjvair/map-sdk/stores";
|
|
3
|
+
import { monitorsStore } from "../stores.svelte.js";
|
|
15
4
|
|
|
16
5
|
export interface MonitorsInitOptions {
|
|
17
6
|
/**
|
|
@@ -22,261 +11,69 @@ export interface MonitorsInitOptions {
|
|
|
22
11
|
/**
|
|
23
12
|
* Stops waiting: the returned promise rejects with the signal's reason. The shared run keeps
|
|
24
13
|
* going for the other calls waiting on it, and is cancelled only when every call waiting on it
|
|
25
|
-
* passed a signal and all of those aborted.
|
|
26
|
-
* recorded. Ignored once initialized.
|
|
14
|
+
* passed a signal and all of those aborted. Ignored once initialized.
|
|
27
15
|
*/
|
|
28
16
|
signal?: AbortSignal;
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
class MonitorsManager implements MonitorsDataSource {
|
|
43
|
-
autoUpdate: Interval = new Interval(async () => await this.update(), 2 * 60 * 1000);
|
|
44
|
-
initialized: boolean = $state(false);
|
|
45
|
-
|
|
46
|
-
latest: XMap<string, MonitorLatestType<"pm25" | "o3">> | null = $state(null);
|
|
47
|
-
list: Array<MonitorData> | null = $state(null);
|
|
48
|
-
|
|
49
|
-
meta: MonitorsMeta | null = $state(null);
|
|
50
|
-
|
|
51
|
-
pollutant: "pm25" | "o3" | null = $state(null);
|
|
52
|
-
|
|
53
|
-
levels: Array<SJVAirEntryLevel> | null = $derived(
|
|
54
|
-
this.meta?.entryType(this.pollutant ?? this.meta.default_pollutant).asIter.levels || null
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
#initRun: InitRun | null = null;
|
|
58
|
-
#requestedPollutant: MonitorsPollutant | null = null;
|
|
59
|
-
#requestedAutoUpdate = false;
|
|
60
|
-
#updateController: AbortController | null = null;
|
|
61
|
-
|
|
62
|
-
constructor() {
|
|
63
|
-
// Refetch monitors when the pollutant changes after the initial load, wherever the change
|
|
64
|
-
// comes from (Pollutant menu, URL sync, a host's own UI). Clearing first blanks the markers
|
|
65
|
-
// instead of briefly coloring them with the previous pollutant's readings.
|
|
66
|
-
let fetchedPollutant: string | null = null;
|
|
67
|
-
$effect.root(() => {
|
|
68
|
-
$effect(() => {
|
|
69
|
-
const pollutant = this.pollutant;
|
|
70
|
-
if (!this.initialized) return;
|
|
71
|
-
if (fetchedPollutant !== null && fetchedPollutant !== pollutant) {
|
|
72
|
-
untrack(() => {
|
|
73
|
-
this.list = [];
|
|
74
|
-
this.latest = null;
|
|
75
|
-
this.update();
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
fetchedPollutant = pollutant;
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Safe to call from several places: overlapping calls share one run, and a failed run can
|
|
85
|
-
* be retried. An explicit "pm25"/"o3" wins over a call without one, whichever came first;
|
|
86
|
-
* between two explicit values the most recent wins. Polling starts when the run finishes
|
|
87
|
-
* unless every call sharing it passed `autoUpdate: false`. A no-op once initialized, so it
|
|
88
|
-
* never restarts polling either: that is `resumeAutoUpdate()`.
|
|
89
|
-
*/
|
|
90
|
-
init(urlPollutant?: string | number | boolean, options: MonitorsInitOptions = {}): Promise<void> {
|
|
91
|
-
if (this.initialized) return Promise.resolve();
|
|
92
|
-
|
|
93
|
-
const { signal } = options;
|
|
94
|
-
// Nothing is recorded or started for a call that is already cancelled.
|
|
95
|
-
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
96
|
-
|
|
97
|
-
if (options.autoUpdate !== false) this.#requestedAutoUpdate = true;
|
|
98
|
-
|
|
99
|
-
if (urlPollutant === "pm25" || urlPollutant === "o3") {
|
|
100
|
-
this.#requestedPollutant = urlPollutant;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const run = (this.#initRun ??= this.#startInitRun());
|
|
104
|
-
|
|
105
|
-
if (!signal) {
|
|
106
|
-
run.unsignalled = true;
|
|
107
|
-
return run.promise;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
run.signalled++;
|
|
111
|
-
const onAbort = () => {
|
|
112
|
-
run.aborted++;
|
|
113
|
-
if (!run.unsignalled && run.aborted === run.signalled) this.#abortInitRun(run);
|
|
114
|
-
};
|
|
115
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
116
|
-
const cleanup = () => signal.removeEventListener("abort", onAbort);
|
|
117
|
-
run.promise.then(cleanup, cleanup);
|
|
118
|
-
|
|
119
|
-
return untilAborted(run.promise, signal);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
#startInitRun(): InitRun {
|
|
123
|
-
const controller = new AbortController();
|
|
124
|
-
const run: InitRun = {
|
|
125
|
-
promise: this.#runInit(controller.signal).finally(() => {
|
|
126
|
-
if (this.#initRun === run) this.#clearInitRun();
|
|
127
|
-
}),
|
|
128
|
-
controller,
|
|
129
|
-
signalled: 0,
|
|
130
|
-
aborted: 0,
|
|
131
|
-
unsignalled: false
|
|
132
|
-
};
|
|
133
|
-
return run;
|
|
134
|
-
}
|
|
135
|
-
|
|
19
|
+
/**
|
|
20
|
+
* The live monitors data, as hosts have used it since 4.x: a thin view over map-sdk's monitors
|
|
21
|
+
* store, which owns the data, the shared init and the polling.
|
|
22
|
+
*/
|
|
23
|
+
export interface MonitorsManager {
|
|
24
|
+
/** Loads the monitors. Only "pm25" and "o3" pass through; anything else means the default. */
|
|
25
|
+
init(pollutant?: unknown, options?: MonitorsInitOptions): Promise<void>;
|
|
26
|
+
readonly initialized: boolean;
|
|
27
|
+
readonly meta: MonitorsMeta | null;
|
|
136
28
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
29
|
+
* Every monitor, or null until initialized. The same array between reads until the store's
|
|
30
|
+
* monitors are replaced.
|
|
139
31
|
*/
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
this.#requestedAutoUpdate = false;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async #runInit(signal: AbortSignal): Promise<void> {
|
|
153
|
-
// The pollutant the latest readings were requested for.
|
|
154
|
-
let fetchedPollutant = this.#requestedPollutant;
|
|
155
|
-
|
|
156
|
-
const metaRequest = getMonitorsMeta({ signal });
|
|
157
|
-
const listAndMeta = Promise.all([getMonitorsList({ signal }), metaRequest]).then(
|
|
158
|
-
([list, meta]) => {
|
|
159
|
-
if (signal.aborted) throw signal.reason;
|
|
160
|
-
this.list = list;
|
|
161
|
-
this.meta = meta;
|
|
162
|
-
return meta;
|
|
163
|
-
}
|
|
164
|
-
);
|
|
165
|
-
// The latest readings only need the pollutant, so they never wait for the list. An explicit
|
|
166
|
-
// pollutant may still arrive before meta does, in which case the default is never fetched.
|
|
167
|
-
const latestRequest = fetchedPollutant
|
|
168
|
-
? getMonitorsLatestMap(fetchedPollutant, signal)
|
|
169
|
-
: metaRequest.then((meta) => {
|
|
170
|
-
const pollutant = this.#requestedPollutant ?? meta.default_pollutant;
|
|
171
|
-
fetchedPollutant = pollutant;
|
|
172
|
-
return getMonitorsLatestMap(pollutant, signal);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
// One Promise.all so a failure in either never leaves the other unhandled.
|
|
176
|
-
const [meta, firstLatest] = await Promise.all([listAndMeta, latestRequest]);
|
|
177
|
-
let latest = firstLatest;
|
|
178
|
-
|
|
179
|
-
// An explicit pollutant may have arrived while the requests above were in flight.
|
|
180
|
-
let wanted = this.#requestedPollutant ?? meta.default_pollutant;
|
|
181
|
-
while (wanted !== fetchedPollutant) {
|
|
182
|
-
latest = await getMonitorsLatestMap(wanted, signal);
|
|
183
|
-
fetchedPollutant = wanted;
|
|
184
|
-
wanted = this.#requestedPollutant ?? meta.default_pollutant;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Cancelled while a request that ignores the signal was settling: leave state to the next run.
|
|
188
|
-
if (signal.aborted) throw signal.reason;
|
|
189
|
-
|
|
190
|
-
this.pollutant = fetchedPollutant;
|
|
191
|
-
this.latest = latest;
|
|
192
|
-
if (this.#requestedAutoUpdate) this.autoUpdate.start();
|
|
193
|
-
this.initialized = true;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Starts polling when it is not running: after something stopped it (MonitorMapLayout stops
|
|
198
|
-
* it on destroy) or after an init that opted out of it. Refreshes first since the data may
|
|
199
|
-
* be stale. A no-op before init or while polling.
|
|
200
|
-
*/
|
|
201
|
-
resumeAutoUpdate(): void {
|
|
202
|
-
if (!this.initialized || this.autoUpdate.isActive) return;
|
|
203
|
-
|
|
204
|
-
this.update().catch(console.error);
|
|
205
|
-
this.autoUpdate.start();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Refreshes the list and the latest readings. Starting an update aborts the previous
|
|
210
|
-
* in-flight one, which then resolves without touching state. Pass `signal` to cancel from the
|
|
211
|
-
* outside: that rejects with the signal's reason.
|
|
212
|
-
*/
|
|
213
|
-
async update(options: SignalOptions = {}): Promise<void> {
|
|
214
|
-
if (!this.initialized) return;
|
|
215
|
-
|
|
216
|
-
// Nothing has started yet, so an in-flight update is left alone.
|
|
217
|
-
if (options.signal?.aborted) throw options.signal.reason;
|
|
218
|
-
|
|
219
|
-
const supersededInFlight = this.#updateController !== null;
|
|
220
|
-
this.#updateController?.abort();
|
|
221
|
-
const controller = new AbortController();
|
|
222
|
-
this.#updateController = controller;
|
|
223
|
-
const combined = anySignal(controller.signal, options.signal);
|
|
224
|
-
|
|
225
|
-
// The caller cancelled this update. If it is still the latest and it cut off an update that
|
|
226
|
-
// was in flight, that update's data is lost too, so refresh again without a signal.
|
|
227
|
-
const callerAborted = (signal: AbortSignal) => {
|
|
228
|
-
if (supersededInFlight && this.#updateController === controller) {
|
|
229
|
-
this.update().catch(console.error);
|
|
230
|
-
}
|
|
231
|
-
return signal.reason;
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
// Set once callerAborted has run, so the catch below does not run it a second time.
|
|
235
|
-
let abortedError: unknown;
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
const pollutant = this.pollutant;
|
|
239
|
-
const [list, latest] = await Promise.all([
|
|
240
|
-
getMonitorsList({ signal: combined.signal }),
|
|
241
|
-
getMonitorsLatestMap(pollutant || this.meta?.default_pollutant || "pm25", combined.signal)
|
|
242
|
-
]);
|
|
243
|
-
|
|
244
|
-
// Superseded or cancelled while the requests were settling.
|
|
245
|
-
if (options.signal?.aborted) throw (abortedError = callerAborted(options.signal));
|
|
246
|
-
if (controller.signal.aborted) return;
|
|
247
|
-
|
|
248
|
-
// The pollutant changed while this was in flight: these readings belong to the previous
|
|
249
|
-
// one, and the change has already started its own update.
|
|
250
|
-
if (this.pollutant !== pollutant) return;
|
|
251
|
-
|
|
252
|
-
this.list = list;
|
|
253
|
-
this.latest = latest;
|
|
254
|
-
} catch (error) {
|
|
255
|
-
// The caller's own abort rejects with its reason. A superseded update resolves quietly.
|
|
256
|
-
if (options.signal?.aborted)
|
|
257
|
-
throw error === abortedError ? error : callerAborted(options.signal);
|
|
258
|
-
if (controller.signal.aborted) return;
|
|
259
|
-
throw error;
|
|
260
|
-
} finally {
|
|
261
|
-
combined.dispose();
|
|
262
|
-
if (this.#updateController === controller) this.#updateController = null;
|
|
263
|
-
}
|
|
264
|
-
}
|
|
32
|
+
readonly list: MonitorData[] | null;
|
|
33
|
+
/** The pollutant the readings are for, or null before init. */
|
|
34
|
+
readonly pollutant: string | null;
|
|
35
|
+
setPollutant(pollutant: "pm25" | "o3"): void;
|
|
36
|
+
update(options?: { signal?: AbortSignal }): Promise<void>;
|
|
37
|
+
resumeAutoUpdate(): void;
|
|
38
|
+
pauseAutoUpdate(): void;
|
|
39
|
+
/** The store underneath, for map-sdk plugins and stores. */
|
|
40
|
+
readonly store: MonitorsStore;
|
|
265
41
|
}
|
|
266
42
|
|
|
267
|
-
|
|
268
|
-
pollutant
|
|
269
|
-
|
|
270
|
-
): Promise<XMap<string, MonitorLatestType<"pm25" | "o3">>> {
|
|
271
|
-
const monitors = await getMonitors(pollutant, undefined, { signal });
|
|
272
|
-
const latest = new XMap<string, MonitorLatestType<"pm25" | "o3">>();
|
|
273
|
-
|
|
274
|
-
for (const monitor of monitors) {
|
|
275
|
-
latest.set(monitor.id, monitor);
|
|
276
|
-
}
|
|
43
|
+
function initPollutant(pollutant: unknown): "pm25" | "o3" | undefined {
|
|
44
|
+
return pollutant === "pm25" || pollutant === "o3" ? pollutant : undefined;
|
|
45
|
+
}
|
|
277
46
|
|
|
278
|
-
|
|
47
|
+
export function createMonitorsManager(store: MonitorsStore): MonitorsManager {
|
|
48
|
+
// The list built from `store.monitors`, which the store replaces rather than mutates.
|
|
49
|
+
let listFrom: MonitorsStore["monitors"] | null = null;
|
|
50
|
+
let list: MonitorData[] = [];
|
|
51
|
+
return {
|
|
52
|
+
init: (pollutant, options) => store.init(initPollutant(pollutant), options),
|
|
53
|
+
get initialized() {
|
|
54
|
+
return store.initialized;
|
|
55
|
+
},
|
|
56
|
+
get meta() {
|
|
57
|
+
return store.meta;
|
|
58
|
+
},
|
|
59
|
+
get list() {
|
|
60
|
+
if (!store.initialized) return null;
|
|
61
|
+
const monitors = store.monitors;
|
|
62
|
+
if (monitors !== listFrom) {
|
|
63
|
+
listFrom = monitors;
|
|
64
|
+
list = [...monitors.values()];
|
|
65
|
+
}
|
|
66
|
+
return list;
|
|
67
|
+
},
|
|
68
|
+
get pollutant() {
|
|
69
|
+
return store.entryType;
|
|
70
|
+
},
|
|
71
|
+
setPollutant: (pollutant) => store.entryTypeFor(pollutant),
|
|
72
|
+
update: (options) => store.update(options),
|
|
73
|
+
resumeAutoUpdate: () => store.resumeAutoUpdate(),
|
|
74
|
+
pauseAutoUpdate: () => store.pauseAutoUpdate(),
|
|
75
|
+
store
|
|
76
|
+
};
|
|
279
77
|
}
|
|
280
78
|
|
|
281
|
-
export const monitorsManager =
|
|
282
|
-
export type { MonitorsManager };
|
|
79
|
+
export const monitorsManager: MonitorsManager = createMonitorsManager(monitorsStore);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { monitorsStore } from "$lib/stores.svelte.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Retries a failed initial monitors load through the store's own `status.retry()`, which repeats
|
|
5
|
+
* the failed `init()` call. When the status is not an error (nothing to retry), runs `fallback`.
|
|
6
|
+
*/
|
|
7
|
+
export function retryMonitorsLoad(
|
|
8
|
+
store: { dataSource: Pick<typeof monitorsStore.dataSource, "status"> },
|
|
9
|
+
fallback: () => void
|
|
10
|
+
) {
|
|
11
|
+
const { status } = store.dataSource;
|
|
12
|
+
if (status.state === "error") status.retry();
|
|
13
|
+
else fallback();
|
|
14
|
+
}
|
|
@@ -1,48 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import type { MonitorLatestType, MonitorsMeta, MonitorType, SJVAirEntryLevel } from "@sjvair/sdk";
|
|
3
|
-
import type { MapGeoJSONFeature } from "@maptiler/sdk";
|
|
4
|
-
import type { XMap } from "@tstk/builtin-extensions";
|
|
5
|
-
|
|
6
|
-
export type MonitorMapFeature = Feature<Geometry, MonitorMarkerProperties>;
|
|
7
|
-
|
|
8
|
-
export interface MonitorClusterMapFeature extends MapGeoJSONFeature {
|
|
9
|
-
properties: MonitorClusterMarkerProperties;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface MonitorMarkerProperties {
|
|
13
|
-
icon: string;
|
|
14
|
-
id: string;
|
|
15
|
-
is_active: boolean;
|
|
16
|
-
is_sjvair?: boolean;
|
|
17
|
-
location: string;
|
|
18
|
-
name: string;
|
|
19
|
-
order: number;
|
|
20
|
-
type: MonitorType;
|
|
21
|
-
value: string;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface MonitorClusterMarkerProperties {
|
|
25
|
-
cluster: true;
|
|
26
|
-
cluster_id: number;
|
|
27
|
-
point_count: number;
|
|
28
|
-
point_count_abbreviated: string | number;
|
|
29
|
-
sumValues: number;
|
|
30
|
-
countValues: number;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** The pollutants monitorsMapIntegration/monitorsIconManager can render. */
|
|
1
|
+
/** The pollutants the map can show. */
|
|
34
2
|
export type MonitorsPollutant = "pm25" | "o3";
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* The reactive data a monitors map display needs: which monitors exist, their
|
|
38
|
-
* per-monitor "latest" value for the active pollutant, and the entry-level metadata
|
|
39
|
-
* used to color icons. `monitorsManager` (live, auto-polling) is the default
|
|
40
|
-
* implementation; a host app can supply its own (e.g. one backed by historical
|
|
41
|
-
* summaries instead of live readings) to reuse the map rendering with different data.
|
|
42
|
-
*/
|
|
43
|
-
export interface MonitorsDataSource {
|
|
44
|
-
readonly meta: MonitorsMeta | null;
|
|
45
|
-
readonly pollutant: MonitorsPollutant | null;
|
|
46
|
-
readonly latest: XMap<string, MonitorLatestType<MonitorsPollutant>> | null;
|
|
47
|
-
readonly levels: Array<SJVAirEntryLevel> | null;
|
|
48
|
-
}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/** The map options the toolbar edits; `mapOptions` holds the live copy. */
|
|
2
|
+
export interface MapOptions {
|
|
3
|
+
/** False for the Pollutant menu's "None": no monitors (or collocation sites) on the map. */
|
|
4
|
+
monitorsOn: boolean;
|
|
5
|
+
/** Which monitor types draw, keyed by server type; a type with no key never draws. */
|
|
6
|
+
monitorTypes: Record<string, boolean>;
|
|
7
|
+
inactive: boolean;
|
|
8
|
+
inside: boolean;
|
|
9
|
+
/** Monitors' and EV chargers' clustering. */
|
|
10
|
+
clustered: boolean;
|
|
11
|
+
collocationSites: boolean;
|
|
12
|
+
/** HMS smoke and fire together. */
|
|
13
|
+
fireAndSmoke: boolean;
|
|
14
|
+
evStations: boolean;
|
|
15
|
+
evLevels: { lvl2: boolean; lvl3: boolean };
|
|
16
|
+
wind: boolean;
|
|
17
|
+
}
|
|
3
18
|
|
|
4
|
-
/**
|
|
5
|
-
* Defaults restored by "Reset Map Options". Keep in sync with the constructor defaults in each
|
|
6
|
-
* integration (monitors/EV display options, `enabled`, `clustered`) so a reset matches a fresh load.
|
|
7
|
-
*/
|
|
19
|
+
/** Defaults restored by "Reset Map Options"; a fresh load starts at them too. */
|
|
8
20
|
export const MAP_OPTION_DEFAULTS = {
|
|
9
21
|
monitorTypes: {
|
|
10
22
|
airnow: true,
|
|
@@ -13,59 +25,24 @@ export const MAP_OPTION_DEFAULTS = {
|
|
|
13
25
|
bam1022: true,
|
|
14
26
|
airgradient: true,
|
|
15
27
|
purpleair: true,
|
|
16
|
-
vozbox: true
|
|
17
|
-
inactive: false,
|
|
18
|
-
inside: false
|
|
28
|
+
vozbox: true
|
|
19
29
|
},
|
|
30
|
+
inactive: false,
|
|
31
|
+
inside: false,
|
|
20
32
|
clustered: true,
|
|
21
33
|
collocationSites: false,
|
|
22
34
|
fireAndSmoke: true,
|
|
23
35
|
evStations: false,
|
|
24
36
|
evLevels: { lvl2: true, lvl3: true },
|
|
25
37
|
wind: false
|
|
26
|
-
} as const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
} as const satisfies Omit<MapOptions, "monitorsOn">;
|
|
39
|
+
|
|
40
|
+
/** A fresh copy of the defaults, with monitors on. */
|
|
41
|
+
export function defaultMapOptions(): MapOptions {
|
|
42
|
+
return {
|
|
43
|
+
...MAP_OPTION_DEFAULTS,
|
|
44
|
+
monitorsOn: true,
|
|
45
|
+
monitorTypes: { ...MAP_OPTION_DEFAULTS.monitorTypes },
|
|
46
|
+
evLevels: { ...MAP_OPTION_DEFAULTS.evLevels }
|
|
35
47
|
};
|
|
36
|
-
collocationSites: Toggle;
|
|
37
|
-
hmsFire: Toggle;
|
|
38
|
-
hmsSmoke: Toggle;
|
|
39
|
-
evStations: Toggle & { clustered: boolean; displayOptions: { lvl2: Option; lvl3: Option } };
|
|
40
|
-
wind: Toggle;
|
|
41
|
-
mapStyle: { reset(): void };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function applyMapOptionDefaults(
|
|
45
|
-
targets: MapOptionTargets,
|
|
46
|
-
defaultPollutant: MonitorsPollutant | null
|
|
47
|
-
): void {
|
|
48
|
-
if (defaultPollutant) {
|
|
49
|
-
applyPollutantSelection(defaultPollutant, targets);
|
|
50
|
-
} else {
|
|
51
|
-
targets.integration.enabled = true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
for (const [key, value] of Object.entries(MAP_OPTION_DEFAULTS.monitorTypes)) {
|
|
55
|
-
const option = targets.integration.displayOptions[key];
|
|
56
|
-
if (option) option.value = value;
|
|
57
|
-
}
|
|
58
|
-
targets.integration.clustered = MAP_OPTION_DEFAULTS.clustered;
|
|
59
|
-
|
|
60
|
-
targets.collocationSites.enabled = MAP_OPTION_DEFAULTS.collocationSites;
|
|
61
|
-
targets.hmsFire.enabled = MAP_OPTION_DEFAULTS.fireAndSmoke;
|
|
62
|
-
targets.hmsSmoke.enabled = MAP_OPTION_DEFAULTS.fireAndSmoke;
|
|
63
|
-
|
|
64
|
-
targets.evStations.enabled = MAP_OPTION_DEFAULTS.evStations;
|
|
65
|
-
targets.evStations.clustered = MAP_OPTION_DEFAULTS.clustered;
|
|
66
|
-
targets.evStations.displayOptions.lvl2.value = MAP_OPTION_DEFAULTS.evLevels.lvl2;
|
|
67
|
-
targets.evStations.displayOptions.lvl3.value = MAP_OPTION_DEFAULTS.evLevels.lvl3;
|
|
68
|
-
|
|
69
|
-
targets.wind.enabled = MAP_OPTION_DEFAULTS.wind;
|
|
70
|
-
targets.mapStyle.reset();
|
|
71
48
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { monitorsManager } from "../monitors/monitors.svelte.js";
|
|
2
|
+
import type { MonitorsPollutant } from "../monitors/types";
|
|
3
|
+
import { defaultMapOptions, MAP_OPTION_DEFAULTS, type MapOptions } from "./map-option-defaults";
|
|
4
|
+
|
|
5
|
+
export type { MapOptions } from "./map-option-defaults";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The toolbar's map options. Module-level, so they survive the layout remounting (as the 4.x
|
|
9
|
+
* integrations' state did); the layout turns them into map-sdk plugins.
|
|
10
|
+
*/
|
|
11
|
+
export const mapOptions: MapOptions = $state(defaultMapOptions());
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* "Reset Map Options": every option back to its default, monitors on, and the pollutant back to
|
|
15
|
+
* `defaultPollutant` (the server's default; null before the meta loads leaves it as it is).
|
|
16
|
+
*/
|
|
17
|
+
export function resetMapOptions(defaultPollutant: MonitorsPollutant | null): void {
|
|
18
|
+
if (defaultPollutant) monitorsManager.setPollutant(defaultPollutant);
|
|
19
|
+
mapOptions.monitorsOn = true;
|
|
20
|
+
Object.assign(mapOptions.monitorTypes, MAP_OPTION_DEFAULTS.monitorTypes);
|
|
21
|
+
mapOptions.inactive = MAP_OPTION_DEFAULTS.inactive;
|
|
22
|
+
mapOptions.inside = MAP_OPTION_DEFAULTS.inside;
|
|
23
|
+
mapOptions.clustered = MAP_OPTION_DEFAULTS.clustered;
|
|
24
|
+
mapOptions.collocationSites = MAP_OPTION_DEFAULTS.collocationSites;
|
|
25
|
+
mapOptions.fireAndSmoke = MAP_OPTION_DEFAULTS.fireAndSmoke;
|
|
26
|
+
mapOptions.evStations = MAP_OPTION_DEFAULTS.evStations;
|
|
27
|
+
mapOptions.evLevels.lvl2 = MAP_OPTION_DEFAULTS.evLevels.lvl2;
|
|
28
|
+
mapOptions.evLevels.lvl3 = MAP_OPTION_DEFAULTS.evLevels.lvl3;
|
|
29
|
+
mapOptions.wind = MAP_OPTION_DEFAULTS.wind;
|
|
30
|
+
}
|
|
@@ -4,43 +4,31 @@
|
|
|
4
4
|
import CheckboxRow from "../rows/CheckboxRow.svelte";
|
|
5
5
|
import SubmenuRow from "../rows/SubmenuRow.svelte";
|
|
6
6
|
import MarkerIcon from "../rows/MarkerIcon.svelte";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { evStationsMapIntegration } from "$lib/ev-stations/ev-stations-map-integration.svelte";
|
|
10
|
-
|
|
11
|
-
const levels = $derived(evStationsMapIntegration.displayOptions);
|
|
7
|
+
import { mapOptions } from "../map-options.svelte.js";
|
|
8
|
+
import { ROW_ICONS } from "../row-icons";
|
|
12
9
|
</script>
|
|
13
10
|
|
|
14
11
|
<OptionsMenu id="layers" label="Layers">
|
|
15
12
|
{#snippet icon()}
|
|
16
13
|
<LayersIcon size={20} color="#708090" />
|
|
17
14
|
{/snippet}
|
|
18
|
-
<CheckboxRow
|
|
19
|
-
label="Fire & Smoke"
|
|
20
|
-
bind:checked={
|
|
21
|
-
() => hmsFireMapIntegration.enabled && hmsSmokeMapIntegration.enabled,
|
|
22
|
-
(value) => {
|
|
23
|
-
hmsFireMapIntegration.enabled = value;
|
|
24
|
-
hmsSmokeMapIntegration.enabled = value;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
>
|
|
15
|
+
<CheckboxRow label="Fire & Smoke" bind:checked={mapOptions.fireAndSmoke}>
|
|
28
16
|
{#snippet icon()}
|
|
29
17
|
<FlameIcon size={18} color="#ff4500" />
|
|
30
18
|
{/snippet}
|
|
31
19
|
</CheckboxRow>
|
|
32
|
-
<SubmenuRow label="EV Chargers" bind:checked={
|
|
20
|
+
<SubmenuRow label="EV Chargers" bind:checked={mapOptions.evStations}>
|
|
33
21
|
{#snippet icon()}
|
|
34
22
|
<EvChargerIcon size={18} color="#708090" />
|
|
35
23
|
{/snippet}
|
|
36
|
-
<CheckboxRow label="Level 2" bind:checked={
|
|
24
|
+
<CheckboxRow label="Level 2" bind:checked={mapOptions.evLevels.lvl2}>
|
|
37
25
|
{#snippet icon()}
|
|
38
|
-
<MarkerIcon
|
|
26
|
+
<MarkerIcon svg={ROW_ICONS.evLevel2} class="w-5" />
|
|
39
27
|
{/snippet}
|
|
40
28
|
</CheckboxRow>
|
|
41
|
-
<CheckboxRow label="Level 3" bind:checked={
|
|
29
|
+
<CheckboxRow label="Level 3" bind:checked={mapOptions.evLevels.lvl3}>
|
|
42
30
|
{#snippet icon()}
|
|
43
|
-
<MarkerIcon
|
|
31
|
+
<MarkerIcon svg={ROW_ICONS.evLevel3} class="w-5" />
|
|
44
32
|
{/snippet}
|
|
45
33
|
</CheckboxRow>
|
|
46
34
|
</SubmenuRow>
|