@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.
- package/LICENSE +21 -0
- package/README.md +61 -126
- package/dist/lib/MonitorDetailPanel.svelte +23 -20
- package/dist/lib/MonitorMapLayout.svelte +147 -77
- package/dist/lib/abort.d.ts +16 -0
- package/dist/lib/abort.js +51 -0
- 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 +54 -24
- 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/requests.d.ts +2 -1
- package/dist/lib/data-chart/requests.js +5 -2
- 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 +82 -82
- 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/monitor-details.svelte.js +11 -3
- package/dist/lib/monitors/monitors.svelte.d.ts +29 -26
- package/dist/lib/monitors/monitors.svelte.js +35 -126
- package/dist/lib/monitors/retry-load.d.ts +8 -0
- package/dist/lib/monitors/retry-load.js +11 -0
- package/dist/lib/monitors/subscriptions.d.ts +3 -0
- package/dist/lib/monitors/subscriptions.js +9 -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/abort.ts +59 -0
- 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 +54 -24
- 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/requests.ts +14 -7
- 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 +82 -82
- package/src/lib/monitors/filtered-source.svelte.ts +38 -0
- package/src/lib/monitors/monitor-details.svelte.ts +12 -3
- package/src/lib/monitors/monitors.svelte.ts +62 -153
- package/src/lib/monitors/retry-load.ts +14 -0
- package/src/lib/monitors/subscriptions.ts +17 -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 -9
- package/dist/lib/collocation-sites/collocations.svelte.js +0 -17
- 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 -9
- package/dist/lib/ev-stations/ev-stations.svelte.js +0 -55
- 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 -19
- package/dist/lib/hms/hms.svelte.js +0 -227
- 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 -24
- 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 -79
- 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 -264
- 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
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { FeatureCollection, Point } from "geojson";
|
|
2
|
+
import {
|
|
3
|
+
encodeRef,
|
|
4
|
+
type DataSource,
|
|
5
|
+
type DataStatus,
|
|
6
|
+
type MapFeatureProperties
|
|
7
|
+
} from "@sjvair/map-sdk/data";
|
|
8
|
+
import { fetchEvStations } from "./ev-stations";
|
|
9
|
+
import type { EvStation } from "./types";
|
|
10
|
+
|
|
11
|
+
export type EvLevel = "lvl2" | "lvl3";
|
|
12
|
+
|
|
13
|
+
/** A charger on the map: `name` is the station's name; chargers have no value. */
|
|
14
|
+
export interface EvFeatureProperties extends MapFeatureProperties {
|
|
15
|
+
level: EvLevel;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type FetchEvStations = (level: EvLevel, signal?: AbortSignal) => Promise<EvStation[]>;
|
|
19
|
+
|
|
20
|
+
export interface EvStore {
|
|
21
|
+
/** One level's chargers for its plugin; `loading` until the first `load(level)`. */
|
|
22
|
+
dataSource(level: EvLevel): DataSource<EvFeatureProperties>;
|
|
23
|
+
/**
|
|
24
|
+
* Fetches a level once; overlapping calls share the run. A failure sets the status to `error`
|
|
25
|
+
* (its `retry()` fetches again) and rejects.
|
|
26
|
+
*/
|
|
27
|
+
load(level: EvLevel): Promise<void>;
|
|
28
|
+
/** A loaded station by id, from either level. */
|
|
29
|
+
station(id: string): EvStation | undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** NREL has this station in the wrong place, so it is left out (as in 4.x). */
|
|
33
|
+
const DROPPED_STATION = 226154;
|
|
34
|
+
|
|
35
|
+
function toFeatures(
|
|
36
|
+
stations: EvStation[],
|
|
37
|
+
level: EvLevel
|
|
38
|
+
): FeatureCollection<Point, EvFeatureProperties> {
|
|
39
|
+
return {
|
|
40
|
+
type: "FeatureCollection",
|
|
41
|
+
features: stations.map((station) => ({
|
|
42
|
+
type: "Feature",
|
|
43
|
+
properties: {
|
|
44
|
+
refKey: encodeRef({ kind: "feature", id: String(station.id) }),
|
|
45
|
+
name: station.station_name ?? "",
|
|
46
|
+
value: null,
|
|
47
|
+
level
|
|
48
|
+
},
|
|
49
|
+
geometry: { type: "Point", coordinates: [station.longitude, station.latitude] }
|
|
50
|
+
}))
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class EvLevelSource implements DataSource<EvFeatureProperties> {
|
|
55
|
+
status: DataStatus = $state.raw({ state: "loading" });
|
|
56
|
+
features: FeatureCollection<Point, EvFeatureProperties> | null = $state.raw(null);
|
|
57
|
+
readonly scale = null;
|
|
58
|
+
stations: EvStation[] = [];
|
|
59
|
+
|
|
60
|
+
#run: Promise<void> | null = null;
|
|
61
|
+
#loaded = false;
|
|
62
|
+
|
|
63
|
+
constructor(
|
|
64
|
+
private level: EvLevel,
|
|
65
|
+
private fetchStations: FetchEvStations
|
|
66
|
+
) {}
|
|
67
|
+
|
|
68
|
+
load(): Promise<void> {
|
|
69
|
+
if (this.#loaded) return Promise.resolve();
|
|
70
|
+
this.#run ??= this.#fetch();
|
|
71
|
+
return this.#run;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async #fetch(): Promise<void> {
|
|
75
|
+
if (this.status.state !== "loading") this.status = { state: "loading" };
|
|
76
|
+
try {
|
|
77
|
+
const stations = (await this.fetchStations(this.level)).filter(
|
|
78
|
+
(station) => station.id !== DROPPED_STATION
|
|
79
|
+
);
|
|
80
|
+
this.stations = stations;
|
|
81
|
+
this.features = toFeatures(stations, this.level);
|
|
82
|
+
this.status = { state: "ready" };
|
|
83
|
+
this.#loaded = true;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
this.features = null;
|
|
86
|
+
this.status = {
|
|
87
|
+
state: "error",
|
|
88
|
+
error,
|
|
89
|
+
retry: () => {
|
|
90
|
+
this.load().catch(() => {});
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
throw error;
|
|
94
|
+
} finally {
|
|
95
|
+
this.#run = null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** EV chargers by level, each fetched when first wanted. */
|
|
101
|
+
export function createEvStore(fetchStations: FetchEvStations = fetchEvStations): EvStore {
|
|
102
|
+
const levels = {
|
|
103
|
+
lvl2: new EvLevelSource("lvl2", fetchStations),
|
|
104
|
+
lvl3: new EvLevelSource("lvl3", fetchStations)
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
dataSource: (level) => levels[level],
|
|
108
|
+
load: (level) => levels[level].load(),
|
|
109
|
+
station(id) {
|
|
110
|
+
for (const source of Object.values(levels)) {
|
|
111
|
+
const found = source.stations.find((station) => String(station.id) === id);
|
|
112
|
+
if (found) return found;
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { mount, unmount, untrack } from "svelte";
|
|
2
|
+
import { Popup } from "@maptiler/sdk";
|
|
3
|
+
import { maptilerMap, type MapContext } from "@sjvair/map-sdk";
|
|
4
|
+
import EvPopup from "./EvPopup.svelte";
|
|
5
|
+
import type { EvStation } from "./types";
|
|
6
|
+
|
|
7
|
+
export interface StationPopups {
|
|
8
|
+
/** Opens `station`'s popup at `lngLat`, closing any other; it belongs to plugin `pluginId`. */
|
|
9
|
+
open(pluginId: string, station: EvStation, lngLat: [number, number]): void;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The EV station popup, 4.x's (a MapTiler `Popup` with a close button that a map click leaves
|
|
15
|
+
* open). One is open at a time; it closes on a basemap switch, when its plugin leaves the map,
|
|
16
|
+
* and when the GL map is replaced. Call it during component setup: its effects live as long as
|
|
17
|
+
* the component.
|
|
18
|
+
*/
|
|
19
|
+
export function stationPopups(map: MapContext): StationPopups {
|
|
20
|
+
let current: { popup: Popup; pluginId: string } | null = $state.raw(null);
|
|
21
|
+
|
|
22
|
+
function close() {
|
|
23
|
+
const open = current;
|
|
24
|
+
current = null;
|
|
25
|
+
open?.popup.remove();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// A basemap switch or a new GL map closes it.
|
|
29
|
+
$effect(() => {
|
|
30
|
+
void map.basemap.current;
|
|
31
|
+
void map.gl;
|
|
32
|
+
untrack(close);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// So does its plugin leaving the map (its level turned off). A Marker Clusters flip removes and
|
|
36
|
+
// re-adds the plugin in one pass, so the popup stays: the station is still there.
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const ids = map.plugins.map((plugin) => plugin.id);
|
|
39
|
+
const open = current;
|
|
40
|
+
if (open && !ids.includes(open.pluginId)) untrack(close);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
$effect(() => () => untrack(close));
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
open(pluginId, station, lngLat) {
|
|
47
|
+
close();
|
|
48
|
+
const gl = maptilerMap(map);
|
|
49
|
+
if (!gl) return;
|
|
50
|
+
const target = document.createElement("div");
|
|
51
|
+
const instance = mount(EvPopup, { target, props: { station } });
|
|
52
|
+
const popup = new Popup({ closeButton: true, closeOnClick: false, maxWidth: "none" })
|
|
53
|
+
.setLngLat(lngLat)
|
|
54
|
+
.setDOMContent(target);
|
|
55
|
+
popup.on("close", () => {
|
|
56
|
+
unmount(instance);
|
|
57
|
+
if (current?.popup === popup) current = null;
|
|
58
|
+
});
|
|
59
|
+
current = { popup, pluginId };
|
|
60
|
+
popup.addTo(gl);
|
|
61
|
+
},
|
|
62
|
+
close
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import type { Feature, Geometry } from "geojson";
|
|
2
|
-
import type { MapGeoJSONFeature } from "@maptiler/sdk";
|
|
3
|
-
|
|
4
1
|
export interface EvStation {
|
|
5
2
|
access_code: string;
|
|
6
3
|
access_days_time: string;
|
|
@@ -25,34 +22,3 @@ export interface EvStation {
|
|
|
25
22
|
ev_network: string;
|
|
26
23
|
ev_pricing: string;
|
|
27
24
|
}
|
|
28
|
-
|
|
29
|
-
export interface EvStationMarkerProperties {
|
|
30
|
-
icon: string;
|
|
31
|
-
id: number;
|
|
32
|
-
level: "lvl2" | "lvl3";
|
|
33
|
-
station_name: string;
|
|
34
|
-
facility_type: string;
|
|
35
|
-
ev_network: string;
|
|
36
|
-
station_phone: string;
|
|
37
|
-
street_address: string;
|
|
38
|
-
city: string;
|
|
39
|
-
state: string;
|
|
40
|
-
zip: string;
|
|
41
|
-
access_days_time: string;
|
|
42
|
-
access_detail_code: string;
|
|
43
|
-
cards_accepted: string | null;
|
|
44
|
-
ev_pricing: string;
|
|
45
|
-
ev_connector_types: string; // JSON.stringify(string[])
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export type EvStationMapFeature = Feature<Geometry, EvStationMarkerProperties>;
|
|
49
|
-
|
|
50
|
-
export interface EvStationClusterMapFeature extends MapGeoJSONFeature {
|
|
51
|
-
properties: {
|
|
52
|
-
cluster: true;
|
|
53
|
-
cluster_id: number;
|
|
54
|
-
point_count: number;
|
|
55
|
-
point_count_abbreviated: string | number;
|
|
56
|
-
};
|
|
57
|
-
// level is derived from feature.source: "ev-stations-lvl2" | "ev-stations-lvl3"
|
|
58
|
-
}
|
|
@@ -48,7 +48,6 @@ export const SanJoaquin = [
|
|
|
48
48
|
export const Stanislaus = [
|
|
49
49
|
"95355",
|
|
50
50
|
"95350",
|
|
51
|
-
"94550",
|
|
52
51
|
"95351",
|
|
53
52
|
"95307",
|
|
54
53
|
"95380",
|
|
@@ -80,7 +79,6 @@ export const Stanislaus = [
|
|
|
80
79
|
];
|
|
81
80
|
|
|
82
81
|
export const Merced = [
|
|
83
|
-
"95023",
|
|
84
82
|
"95380",
|
|
85
83
|
"93635",
|
|
86
84
|
"95301",
|
|
@@ -101,13 +99,11 @@ export const Merced = [
|
|
|
101
99
|
"95369",
|
|
102
100
|
"95303",
|
|
103
101
|
"95317",
|
|
104
|
-
"95325",
|
|
105
102
|
"93665",
|
|
106
103
|
"95342",
|
|
107
104
|
"95344",
|
|
108
105
|
"95343",
|
|
109
106
|
"93661",
|
|
110
|
-
"09534",
|
|
111
107
|
"95312"
|
|
112
108
|
];
|
|
113
109
|
|
|
@@ -141,7 +137,6 @@ export const Fresno = [
|
|
|
141
137
|
"93706",
|
|
142
138
|
"93711",
|
|
143
139
|
"93705",
|
|
144
|
-
"93245",
|
|
145
140
|
"93612",
|
|
146
141
|
"93657",
|
|
147
142
|
"93710",
|
|
@@ -189,7 +184,6 @@ export const Fresno = [
|
|
|
189
184
|
"93652",
|
|
190
185
|
"93627",
|
|
191
186
|
"93606",
|
|
192
|
-
"93665",
|
|
193
187
|
"93628",
|
|
194
188
|
"93605",
|
|
195
189
|
"93607",
|
|
@@ -235,8 +229,7 @@ export const Fresno = [
|
|
|
235
229
|
"93888",
|
|
236
230
|
"93844",
|
|
237
231
|
"93784",
|
|
238
|
-
"93780"
|
|
239
|
-
"93633"
|
|
232
|
+
"93780"
|
|
240
233
|
];
|
|
241
234
|
|
|
242
235
|
export const Kings = [
|
|
@@ -247,7 +240,6 @@ export const Kings = [
|
|
|
247
240
|
"93204",
|
|
248
241
|
"93656",
|
|
249
242
|
"93242",
|
|
250
|
-
"93249",
|
|
251
243
|
"93266",
|
|
252
244
|
"93201",
|
|
253
245
|
"93202",
|
|
@@ -288,12 +280,9 @@ export const Tulare = [
|
|
|
288
280
|
"93238",
|
|
289
281
|
"93261",
|
|
290
282
|
"93641",
|
|
291
|
-
"93255",
|
|
292
283
|
"93603",
|
|
293
284
|
"93244",
|
|
294
285
|
"93262",
|
|
295
|
-
"93549",
|
|
296
|
-
"93628",
|
|
297
286
|
"93208",
|
|
298
287
|
"93227",
|
|
299
288
|
"93237",
|
|
@@ -412,7 +401,6 @@ export const Calaveras = [
|
|
|
412
401
|
export const Tuolumne = [
|
|
413
402
|
"95370",
|
|
414
403
|
"95327",
|
|
415
|
-
"95247",
|
|
416
404
|
"95383",
|
|
417
405
|
"95321",
|
|
418
406
|
"95379",
|
|
@@ -423,8 +411,6 @@ export const Tuolumne = [
|
|
|
423
411
|
"95310",
|
|
424
412
|
"95346",
|
|
425
413
|
"95364",
|
|
426
|
-
"95224",
|
|
427
|
-
"93541",
|
|
428
414
|
"95305",
|
|
429
415
|
"95335",
|
|
430
416
|
"95314",
|
|
@@ -438,7 +424,6 @@ export const Mono = ["93514", "93546", "93517", "96107", "93529", "96133", "9354
|
|
|
438
424
|
|
|
439
425
|
export const Mariposa = [
|
|
440
426
|
"95338",
|
|
441
|
-
"95333",
|
|
442
427
|
"93601",
|
|
443
428
|
"95311",
|
|
444
429
|
"95329",
|
|
@@ -468,3 +453,31 @@ export const Inyo = [
|
|
|
468
453
|
"93522",
|
|
469
454
|
"93530"
|
|
470
455
|
];
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Every county's ZIPs once, sorted: the EV charger query's `zip` list. A ZIP that spans two
|
|
459
|
+
* counties is in both lists above; `scripts/check-ev-zips.mjs` checks the lists against the
|
|
460
|
+
* Census ZCTA-to-county file.
|
|
461
|
+
*
|
|
462
|
+
* The county lists began as a hand-scraped list. 5.0 only removes ZIPs with no land in their
|
|
463
|
+
* county; it adds none. Border ZIPs with some San Joaquin land (95632 Galt, 95641 Isleton,
|
|
464
|
+
* 94505 Discovery Bay) are left out (decided 2026-11-07): their chargers sit mostly outside
|
|
465
|
+
* the county. Revisit if users ask for chargers just over the county line.
|
|
466
|
+
*/
|
|
467
|
+
export const EV_ZIP_CODES: readonly string[] = [
|
|
468
|
+
...new Set([
|
|
469
|
+
...SanJoaquin,
|
|
470
|
+
...Stanislaus,
|
|
471
|
+
...Merced,
|
|
472
|
+
...Madera,
|
|
473
|
+
...Fresno,
|
|
474
|
+
...Kings,
|
|
475
|
+
...Tulare,
|
|
476
|
+
...Kern,
|
|
477
|
+
...Calaveras,
|
|
478
|
+
...Tuolumne,
|
|
479
|
+
...Mono,
|
|
480
|
+
...Mariposa,
|
|
481
|
+
...Inyo
|
|
482
|
+
])
|
|
483
|
+
].sort();
|
package/src/lib/index.ts
CHANGED
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
* ```svelte
|
|
16
16
|
* <!-- app root -->
|
|
17
17
|
* <script>
|
|
18
|
-
* import { provideMonitorMapRouter } from "@sjvair/monitor-map";
|
|
18
|
+
* import { configureMonitorMap, provideMonitorMapRouter } from "@sjvair/monitor-map";
|
|
19
19
|
* import { route, navigate, p, isActive, Router } from "./router";
|
|
20
20
|
*
|
|
21
|
+
* // Once at startup, before the map or the EV layer is used. The library reads no keys itself.
|
|
22
|
+
* configureMonitorMap({ maptilerKey, nrelKey });
|
|
21
23
|
* provideMonitorMapRouter({ route, navigate, p, isActive, basePath: "/my-map" });
|
|
22
24
|
* </script>
|
|
23
25
|
*
|
|
@@ -25,111 +27,18 @@
|
|
|
25
27
|
* ```
|
|
26
28
|
*
|
|
27
29
|
* A host that must stay light at startup imports from the subpath entries instead:
|
|
28
|
-
* `provideMonitorMapRouter`/`monitorsManager` from
|
|
30
|
+
* `configureMonitorMap`/`provideMonitorMapRouter`/`monitorsManager` from
|
|
31
|
+
* "@sjvair/monitor-map/core" (no map), and
|
|
29
32
|
* `monitorMapRoutes` from "@sjvair/monitor-map/routes" (same tree, lazy layout and routes).
|
|
30
33
|
* `monitorMapRoutes` from this entry stays eager.
|
|
31
34
|
*/
|
|
32
35
|
export { monitorMapRoutes } from "./routes";
|
|
36
|
+
export { configureMonitorMap, monitorMapConfig, type MonitorMapConfig } from "./config.svelte.js";
|
|
33
37
|
export {
|
|
34
38
|
ROUTER_KEY,
|
|
35
39
|
provideMonitorMapRouter,
|
|
36
40
|
useMonitorMapRouter,
|
|
37
41
|
type MonitorMapRouterApi
|
|
38
42
|
} from "./router-context";
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
export { monitorsManager } from "./monitors/monitors.svelte";
|
|
42
|
-
export type { MonitorsManager, MonitorsInitOptions } from "./monitors/monitors.svelte";
|
|
43
|
-
export { collocationSitesManager } from "./collocation-sites/collocations.svelte";
|
|
44
|
-
export type { CollocationSitesManager } from "./collocation-sites/collocations.svelte";
|
|
45
|
-
export { evStationsManager } from "./ev-stations/ev-stations.svelte";
|
|
46
|
-
export type { EvStationsManager } from "./ev-stations/ev-stations.svelte";
|
|
47
|
-
export { hmsManager } from "./hms/hms.svelte";
|
|
48
|
-
export type { HMSManager } from "./hms/hms.svelte";
|
|
49
|
-
export { mapManager, DefaultMapStyle, initializeMap } from "./map/map-manager.svelte.js";
|
|
50
|
-
export type { MapManager } from "./map/map-manager.svelte.js";
|
|
51
|
-
|
|
52
|
-
// Map integrations
|
|
53
|
-
export {
|
|
54
|
-
monitorsMapIntegration,
|
|
55
|
-
MonitorsMapIntegration
|
|
56
|
-
} from "./monitors/monitors-map-integration.svelte";
|
|
57
|
-
export { collocationSitesMapIntegration } from "./collocation-sites/collocations-map-integration.svelte";
|
|
58
|
-
export { evStationsMapIntegration } from "./ev-stations/ev-stations-map-integration.svelte";
|
|
59
|
-
export { windMapIntegration } from "./wind/wind.svelte";
|
|
60
|
-
export { baseLayerSeperator } from "./map/integrations/base-layer-seperator";
|
|
61
|
-
export { hmsFireMapIntegration } from "./hms/hms-fire-map-integration.svelte";
|
|
62
|
-
export { hmsSmokeMapIntegration } from "./hms/hms-smoke-map-integration.svelte";
|
|
63
|
-
|
|
64
|
-
// Components
|
|
65
|
-
export { default as Map } from "./map/Map.svelte";
|
|
66
|
-
export { default as MapShell, type MapShellProps } from "./map/MapShell.svelte";
|
|
67
|
-
export {
|
|
68
|
-
default as LoadScreen,
|
|
69
|
-
loadScreenState,
|
|
70
|
-
enable as enableLoadScreen,
|
|
71
|
-
disable as disableLoadScreen
|
|
72
|
-
} from "./LoadScreen.svelte";
|
|
73
|
-
export type { LoadScreenState } from "./LoadScreen.svelte";
|
|
74
|
-
|
|
75
|
-
// Options toolbar / panel (compose these inside MapShell's `menu` snippet)
|
|
76
|
-
export { default as OptionsBar } from "./options/OptionsBar.svelte";
|
|
77
|
-
export { default as OptionsGroup } from "./options/OptionsGroup.svelte";
|
|
78
|
-
export { default as OptionsMenu } from "./options/OptionsMenu.svelte";
|
|
79
|
-
export { default as CheckboxRow } from "./options/rows/CheckboxRow.svelte";
|
|
80
|
-
export { default as RadioRow } from "./options/rows/RadioRow.svelte";
|
|
81
|
-
export { default as SubmenuRow } from "./options/rows/SubmenuRow.svelte";
|
|
82
|
-
export { default as GroupRow } from "./options/rows/GroupRow.svelte";
|
|
83
|
-
export { default as MarkerIcon } from "./options/rows/MarkerIcon.svelte";
|
|
84
|
-
export { default as PollutantMenu } from "./options/menus/PollutantMenu.svelte";
|
|
85
|
-
export { default as MonitorsMenu } from "./options/menus/MonitorsMenu.svelte";
|
|
86
|
-
export { default as LayersMenu } from "./options/menus/LayersMenu.svelte";
|
|
87
|
-
export { default as OverlaysMenu } from "./options/menus/OverlaysMenu.svelte";
|
|
88
|
-
export { default as SettingsMenu } from "./options/menus/SettingsMenu.svelte";
|
|
89
|
-
export { resetMapOptions } from "./options/reset-map-options";
|
|
90
|
-
export { mapStyleState } from "./map/map-style-state.svelte.js";
|
|
91
|
-
export type { MapStyleState } from "./map/map-style-state.svelte.js";
|
|
92
|
-
|
|
93
|
-
// Legend
|
|
94
|
-
export { default as Legend } from "./legend/Legend.svelte";
|
|
95
|
-
export { default as LegendBar } from "./legend/LegendBar.svelte";
|
|
96
|
-
export {
|
|
97
|
-
pollutantLegendSection,
|
|
98
|
-
fireSmokeLegendSections,
|
|
99
|
-
type LegendSection,
|
|
100
|
-
type LegendBarData,
|
|
101
|
-
type LegendCategory
|
|
102
|
-
} from "./legend/legend-data";
|
|
103
|
-
export { FIRE_LEGEND_CATEGORIES } from "./hms/hms-fire-icon-manager";
|
|
104
|
-
export { SMOKE_LEGEND } from "./hms/hms-smoke-map-integration.svelte";
|
|
105
|
-
|
|
106
|
-
// Integration base classes (extend these to add custom map features)
|
|
107
|
-
export { MapIntegration } from "./map/integrations/map-integration.svelte";
|
|
108
|
-
export { MapLayerIntegration } from "./map/integrations/map-layer-integration.svelte";
|
|
109
|
-
export { MapIconLayerIntegration as MapGeoJSONIntegration } from "./map/integrations/map-geojson-integration.svelte";
|
|
110
|
-
|
|
111
|
-
// Types
|
|
112
|
-
export type { SomeMapIntegration } from "./map/integrations/types";
|
|
113
|
-
export type { WindMapIntegration } from "./wind/wind.svelte";
|
|
114
|
-
export type { EvStationsMapIntegration } from "./ev-stations/ev-stations-map-integration.svelte";
|
|
115
|
-
export type { HMSFireMapIntegration } from "./hms/hms-fire-map-integration.svelte";
|
|
116
|
-
export type { HMSSmokeMapIntegration } from "./hms/hms-smoke-map-integration.svelte";
|
|
117
|
-
export type { HMSFireGroup } from "./hms/hms.svelte";
|
|
118
|
-
export type {
|
|
119
|
-
MonitorMapFeature,
|
|
120
|
-
MonitorMarkerProperties,
|
|
121
|
-
MonitorClusterMapFeature,
|
|
122
|
-
MonitorClusterMarkerProperties,
|
|
123
|
-
MonitorsDataSource,
|
|
124
|
-
MonitorsPollutant
|
|
125
|
-
} from "./monitors/types";
|
|
126
|
-
export type {
|
|
127
|
-
CollocationSiteMapFeature,
|
|
128
|
-
CollocationSiteMarkerProperties
|
|
129
|
-
} from "./collocation-sites/types";
|
|
130
|
-
export type {
|
|
131
|
-
EvStation,
|
|
132
|
-
EvStationMarkerProperties,
|
|
133
|
-
EvStationMapFeature,
|
|
134
|
-
EvStationClusterMapFeature
|
|
135
|
-
} from "./ev-stations/types";
|
|
43
|
+
export { monitorsManager } from "./monitors/monitors.svelte.js";
|
|
44
|
+
export type { MonitorsManager, MonitorsInitOptions } from "./monitors/monitors.svelte.js";
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronDownIcon, InfoIcon } from "@lucide/svelte";
|
|
3
|
-
import
|
|
4
|
-
import type { LegendSection } from "./legend-data";
|
|
3
|
+
import { Legend, legendSection, type MapContext } from "@sjvair/map-sdk";
|
|
5
4
|
|
|
6
|
-
let {
|
|
5
|
+
let { map }: { map: MapContext } = $props();
|
|
7
6
|
|
|
8
7
|
// Independent of which sections are active, so toggling a layer doesn't reset it.
|
|
9
8
|
let collapsed = $state(false);
|
|
9
|
+
|
|
10
|
+
// What map-sdk's Legend would list: a scale with levels, or a status line for a plugin that is
|
|
11
|
+
// loading or failing. The card is hidden while there is none.
|
|
12
|
+
const hasSections = $derived(
|
|
13
|
+
map.plugins.some((plugin) => {
|
|
14
|
+
const data = plugin.legend?.();
|
|
15
|
+
if (!data) return false;
|
|
16
|
+
if ("status" in data) return data.status.state !== "ready";
|
|
17
|
+
return legendSection(data, map.format) !== null;
|
|
18
|
+
})
|
|
19
|
+
);
|
|
10
20
|
</script>
|
|
11
21
|
|
|
12
|
-
{#if
|
|
22
|
+
{#if hasSections}
|
|
13
23
|
<div class="pointer-events-auto w-84 max-w-[calc(100vw-2rem)] rounded-md bg-white shadow">
|
|
14
24
|
<button
|
|
15
25
|
type="button"
|
|
@@ -21,20 +31,9 @@
|
|
|
21
31
|
<span class="flex-1 text-left">Legend</span>
|
|
22
32
|
<ChevronDownIcon size={18} class="transition-transform {collapsed ? '-rotate-90' : ''}" />
|
|
23
33
|
</button>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<p class="mb-2 text-center text-sm font-semibold">
|
|
29
|
-
{section.title}
|
|
30
|
-
{#if section.unit}
|
|
31
|
-
<span class="text-xs font-normal text-gray-500">({section.unit})</span>
|
|
32
|
-
{/if}
|
|
33
|
-
</p>
|
|
34
|
-
<LegendBar bar={section.bar} />
|
|
35
|
-
</div>
|
|
36
|
-
{/each}
|
|
37
|
-
</div>
|
|
38
|
-
{/if}
|
|
34
|
+
<!-- Kept mounted (hidden) when collapsed so the legend doesn't re-read the theme on expand. -->
|
|
35
|
+
<div class="border-t border-gray-200 px-4 py-3 {collapsed ? 'hidden' : ''}">
|
|
36
|
+
<Legend {map} order="top-first" framed={false} />
|
|
37
|
+
</div>
|
|
39
38
|
</div>
|
|
40
39
|
{/if}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { levelFor, NO_LEVEL, type Level, type Scale } from "@sjvair/map-sdk/data";
|
|
2
|
+
|
|
3
|
+
/** The color for a reading no level covers, as map-sdk draws an inactive monitor. */
|
|
4
|
+
export const NEUTRAL_LEVEL_COLOR = "#969696";
|
|
5
|
+
|
|
6
|
+
/** The scale level a reading falls in, or null when there is no scale or no level covers it. */
|
|
7
|
+
export function readingLevel(
|
|
8
|
+
value: string | number | null | undefined,
|
|
9
|
+
scale: Scale | null
|
|
10
|
+
): Level | null {
|
|
11
|
+
if (!scale) return null;
|
|
12
|
+
const level = levelFor(value, scale);
|
|
13
|
+
return level === NO_LEVEL ? null : level;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** A reading as the panel shows it: cut off to a whole number, or "–" when not a number. */
|
|
17
|
+
export function readingDisplay(value: string | number | null | undefined): string {
|
|
18
|
+
// Number("") and Number(null) are 0, not a reading.
|
|
19
|
+
if (value === null || value === undefined || (typeof value === "string" && !value.trim())) {
|
|
20
|
+
return "–";
|
|
21
|
+
}
|
|
22
|
+
const number = Math.trunc(Number(value));
|
|
23
|
+
return Number.isFinite(number) ? number.toString() : "–";
|
|
24
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
2
|
import type { Snippet } from "svelte";
|
|
3
|
-
import type {
|
|
3
|
+
import type { MapContext } from "@sjvair/map-sdk";
|
|
4
4
|
|
|
5
5
|
export interface MapShellProps {
|
|
6
|
-
/**
|
|
7
|
-
|
|
6
|
+
/** The map to show, from `createMap()` (the monitor map uses `createLiveMap()`). */
|
|
7
|
+
map: MapContext;
|
|
8
8
|
/**
|
|
9
9
|
* True once the caller's own data managers have finished their initial
|
|
10
|
-
* load. The shell hides the load screen once the map is
|
|
10
|
+
* load. The shell hides the load screen once the map is ready AND this
|
|
11
11
|
* is true.
|
|
12
12
|
*/
|
|
13
13
|
ready: boolean;
|
|
@@ -56,13 +56,12 @@
|
|
|
56
56
|
|
|
57
57
|
<script lang="ts">
|
|
58
58
|
import LoadScreen, { disable as disableLoadScreen } from "$lib/LoadScreen.svelte";
|
|
59
|
-
import
|
|
59
|
+
import { MapView } from "@sjvair/map-sdk";
|
|
60
60
|
import OptionsBar from "$lib/options/OptionsBar.svelte";
|
|
61
|
-
import { mapManager } from "$lib/map/map-manager.svelte.js";
|
|
62
61
|
import { useMonitorMapRouter } from "$lib/router-context";
|
|
63
62
|
|
|
64
63
|
let {
|
|
65
|
-
|
|
64
|
+
map,
|
|
66
65
|
ready,
|
|
67
66
|
loadError,
|
|
68
67
|
panelOpen,
|
|
@@ -76,28 +75,14 @@
|
|
|
76
75
|
}: MapShellProps = $props();
|
|
77
76
|
|
|
78
77
|
const basePath = providedBasePath ?? (routerEscapeHatch ? useMonitorMapRouter().basePath : "");
|
|
79
|
-
const TRANSITION_MS = 300;
|
|
80
78
|
|
|
81
79
|
$effect(() => {
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
// effect sees a non-null map, it's already safe to reveal — waiting for a
|
|
85
|
-
// further "idle" event here is unreliable since one may never fire again.
|
|
86
|
-
if (mapManager.map && ready) {
|
|
80
|
+
// `map.ready` is map-sdk's signal that the style loaded and the map went idle.
|
|
81
|
+
if (map.ready && ready) {
|
|
87
82
|
disableLoadScreen();
|
|
88
83
|
}
|
|
89
84
|
});
|
|
90
85
|
|
|
91
|
-
$effect(() => {
|
|
92
|
-
if (panelOpen) {
|
|
93
|
-
// Container width snapped to open; resize after layout settles
|
|
94
|
-
requestAnimationFrame(() => mapManager.map?.resize());
|
|
95
|
-
} else {
|
|
96
|
-
// Container width snaps back after the transform transition ends
|
|
97
|
-
setTimeout(() => mapManager.map?.resize(), TRANSITION_MS);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
86
|
/**
|
|
102
87
|
* HACK: Fix for escaping sv-router and allowing navigation to other pages,
|
|
103
88
|
* as well as navigating back
|
|
@@ -131,7 +116,15 @@
|
|
|
131
116
|
<div class="relative flex h-full w-full flex-col md:flex-row">
|
|
132
117
|
<LoadScreen error={loadError} />
|
|
133
118
|
<div class="relative flex-1 overflow-hidden">
|
|
134
|
-
<
|
|
119
|
+
<MapView
|
|
120
|
+
{map}
|
|
121
|
+
label="Air quality monitor map"
|
|
122
|
+
controls="engine"
|
|
123
|
+
featureList={{ position: "top-right", reveal: "focus" }}
|
|
124
|
+
selectionBar={false}
|
|
125
|
+
tooltip="pointer"
|
|
126
|
+
class="h-full w-full"
|
|
127
|
+
/>
|
|
135
128
|
{@render overlays?.()}
|
|
136
129
|
{#if menu || search}
|
|
137
130
|
<OptionsBar {search}>{@render menu?.()}</OptionsBar>
|