@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
|
@@ -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
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { type Popup, type MapLayerEventType, type Map as MaptilerMap } from "@maptiler/sdk";
|
|
2
|
-
import type { Geometry } from "geojson";
|
|
3
|
-
import { mapManager } from "$lib/map/map-manager.svelte.js";
|
|
4
|
-
import { MapIconLayerIntegration } from "$lib/map/integrations/map-geojson-integration.svelte";
|
|
5
|
-
import { CollocationIconManager, getCollocationIconId } from "./collocations-icon-manager.svelte";
|
|
6
|
-
import { TooltipManager } from "$lib/map/integrations/tooltip.svelte";
|
|
7
|
-
import { collocationSitesManager } from "./collocations.svelte";
|
|
8
|
-
import { monitorsManager } from "$lib/monitors/monitors.svelte";
|
|
9
|
-
import { monitorsMapIntegration } from "$lib/monitors/monitors-map-integration.svelte";
|
|
10
|
-
import type { CollocationSiteMapFeature, CollocationSiteMarkerProperties } from "./types";
|
|
11
|
-
import { untrack } from "svelte";
|
|
12
|
-
import CollocationTooltip from "./CollocationTooltip.svelte";
|
|
13
|
-
import { mountPopup } from "$lib/map/utils";
|
|
14
|
-
|
|
15
|
-
function collocationTooltip(evt: MapLayerEventType["mousemove"] & object): Popup | void {
|
|
16
|
-
const feature = evt.features?.[0] as unknown as CollocationSiteMapFeature | undefined;
|
|
17
|
-
if (!feature) return;
|
|
18
|
-
return mountPopup(CollocationTooltip, { feature }, evt.lngLat);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
class CollocationSitesMapIntegration extends MapIconLayerIntegration<CollocationSiteMarkerProperties> {
|
|
22
|
-
referenceId: string = "collocation-sites";
|
|
23
|
-
enabled: boolean = $state(false);
|
|
24
|
-
|
|
25
|
-
icons: CollocationIconManager = new CollocationIconManager(monitorsManager);
|
|
26
|
-
tooltipManager: TooltipManager = new TooltipManager();
|
|
27
|
-
|
|
28
|
-
/** The option only applies while monitors are shown with PM2.5. */
|
|
29
|
-
get available(): boolean {
|
|
30
|
-
return monitorsMapIntegration.enabled && monitorsManager.pollutant === "pm25";
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
features: Array<CollocationSiteMapFeature> = $derived.by(() => {
|
|
34
|
-
if (
|
|
35
|
-
!monitorsManager.meta ||
|
|
36
|
-
!monitorsManager.pollutant ||
|
|
37
|
-
!collocationSitesManager.collocationSites ||
|
|
38
|
-
monitorsMapIntegration.features.length === 0
|
|
39
|
-
) {
|
|
40
|
-
return [];
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return collocationSitesManager.collocationSites
|
|
44
|
-
.map((c) => {
|
|
45
|
-
const referenceMonitorFeature = monitorsMapIntegration.features.find(
|
|
46
|
-
(m) => m.properties.id === c.reference_id
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
if (!referenceMonitorFeature) return;
|
|
50
|
-
|
|
51
|
-
const feature: CollocationSiteMapFeature = {
|
|
52
|
-
type: "Feature",
|
|
53
|
-
properties: {
|
|
54
|
-
icon: getCollocationIconId(referenceMonitorFeature!.properties.icon),
|
|
55
|
-
colocated_id: c.colocated_id,
|
|
56
|
-
reference_id: c.reference_id,
|
|
57
|
-
name: c.name
|
|
58
|
-
},
|
|
59
|
-
geometry: c.position! as Geometry
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
return feature;
|
|
63
|
-
})
|
|
64
|
-
.filter((f) => f !== undefined);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
mapLayer: Parameters<MaptilerMap["addLayer"]>[0] = {
|
|
68
|
-
id: this.referenceId,
|
|
69
|
-
type: "symbol",
|
|
70
|
-
source: this.referenceId,
|
|
71
|
-
layout: {
|
|
72
|
-
"icon-allow-overlap": true,
|
|
73
|
-
"icon-ignore-placement": true,
|
|
74
|
-
"icon-image": ["get", "icon"],
|
|
75
|
-
"icon-size": 1
|
|
76
|
-
},
|
|
77
|
-
paint: {}
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
get mapSource(): Parameters<MaptilerMap["addSource"]>[1] {
|
|
81
|
-
return {
|
|
82
|
-
type: "geojson",
|
|
83
|
-
promoteId: "id",
|
|
84
|
-
data: {
|
|
85
|
-
type: "FeatureCollection",
|
|
86
|
-
features: this.features
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
constructor() {
|
|
92
|
-
super();
|
|
93
|
-
|
|
94
|
-
$effect.root(() => {
|
|
95
|
-
$effect(() => {
|
|
96
|
-
const features = this.features;
|
|
97
|
-
if (!mapManager.map || !this.enabled) return;
|
|
98
|
-
mapManager.setDataSource(this.referenceId, features);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// Remove the layer while the option is unavailable (Ozone or Pollutant = None); restore
|
|
102
|
-
// it when it becomes available again if the user still has it checked.
|
|
103
|
-
$effect(() => {
|
|
104
|
-
if (!this.available) {
|
|
105
|
-
untrack(() => this.remove());
|
|
106
|
-
} else if (untrack(() => this.enabled)) {
|
|
107
|
-
untrack(() => this.apply());
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
apply() {
|
|
114
|
-
if (!this.available) {
|
|
115
|
-
this.remove();
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
if (!mapManager.map) return;
|
|
119
|
-
|
|
120
|
-
if (!this.tooltipManager.has(this.referenceId)) {
|
|
121
|
-
this.tooltipManager.register(this.referenceId, collocationTooltip, Number.MAX_SAFE_INTEGER);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
this.tooltipManager.enable();
|
|
125
|
-
|
|
126
|
-
super.apply();
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
remove() {
|
|
130
|
-
this.tooltipManager.disable();
|
|
131
|
-
super.remove();
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export const collocationSitesMapIntegration = new CollocationSitesMapIntegration();
|
|
136
|
-
export type { CollocationSitesMapIntegration as MonitorsMapIntegration };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { getCollocationSites, type CollocationSite } from "@sjvair/sdk";
|
|
2
|
-
|
|
3
|
-
class CollocationSitesManager {
|
|
4
|
-
initialized: boolean = $state(false);
|
|
5
|
-
|
|
6
|
-
collocationSites: Array<CollocationSite> | null = $state(null);
|
|
7
|
-
|
|
8
|
-
async init(): Promise<void> {
|
|
9
|
-
if (this.initialized) return;
|
|
10
|
-
|
|
11
|
-
this.collocationSites = await getCollocationSites();
|
|
12
|
-
|
|
13
|
-
this.initialized = true;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async update(): Promise<void> {
|
|
17
|
-
if (!this.initialized) return;
|
|
18
|
-
|
|
19
|
-
this.collocationSites = await getCollocationSites();
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const collocationSitesManager = new CollocationSitesManager();
|
|
24
|
-
export type { CollocationSitesManager };
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Feature, Geometry } from "geojson";
|
|
2
|
-
|
|
3
|
-
export type CollocationSiteMapFeature = Feature<Geometry, CollocationSiteMarkerProperties>;
|
|
4
|
-
|
|
5
|
-
export interface CollocationSiteMarkerProperties {
|
|
6
|
-
icon: string;
|
|
7
|
-
colocated_id: string;
|
|
8
|
-
reference_id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { EvStationClusterMapFeature } from "../types";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
feature: EvStationClusterMapFeature;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const { feature }: Props = $props();
|
|
9
|
-
|
|
10
|
-
const levelLabel = $derived(feature.source.includes("lvl2") ? "Level 2" : "Level 3");
|
|
11
|
-
</script>
|
|
12
|
-
|
|
13
|
-
<div class="flex flex-col gap-1 p-1">
|
|
14
|
-
<p class="font-semibold">{levelLabel} Chargers</p>
|
|
15
|
-
<p class="text-sm">{feature.properties.point_count} stations</p>
|
|
16
|
-
</div>
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import type { GeoJSONSource, MapLayerEventType, Popup } from "@maptiler/sdk";
|
|
2
|
-
import type { Point } from "geojson";
|
|
3
|
-
import { mapManager } from "$lib/map/map-manager.svelte.js";
|
|
4
|
-
import { mountPopup } from "$lib/map/utils";
|
|
5
|
-
import { clickManager, type ClickHandler } from "$lib/map/integrations/click-manager";
|
|
6
|
-
import { TooltipManager } from "$lib/map/integrations/tooltip.svelte";
|
|
7
|
-
import { EV_STATION_LEVELS, type EvStationLevel } from "./ev-station-icons";
|
|
8
|
-
import type { EvStationClusterMapFeature, EvStationMapFeature } from "./types";
|
|
9
|
-
import EvStationClusterTooltip from "./components/EvStationClusterTooltip.svelte";
|
|
10
|
-
|
|
11
|
-
export interface EvStationsClusterContext {
|
|
12
|
-
referenceId: string;
|
|
13
|
-
featuresByLevel: Record<string, EvStationMapFeature[]>;
|
|
14
|
-
beforeLayer?: string;
|
|
15
|
-
tooltipManager: TooltipManager;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function clusterTooltip(evt: MapLayerEventType["mousemove"] & object): Popup | void {
|
|
19
|
-
const feature = evt.features?.[0] as unknown as EvStationClusterMapFeature | undefined;
|
|
20
|
-
if (!feature) return;
|
|
21
|
-
return mountPopup(EvStationClusterTooltip, { feature }, evt.lngLat);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export class EvStationsClusterRenderer {
|
|
25
|
-
private _levels: EvStationLevel[] = [];
|
|
26
|
-
|
|
27
|
-
constructor(private ctx: EvStationsClusterContext) {}
|
|
28
|
-
|
|
29
|
-
apply(stationClickHandler: ClickHandler): void {
|
|
30
|
-
if (!mapManager.map) return;
|
|
31
|
-
|
|
32
|
-
for (const level of Object.keys(EV_STATION_LEVELS) as EvStationLevel[]) {
|
|
33
|
-
const sourceId = `${this.ctx.referenceId}-${level}`;
|
|
34
|
-
const features = this.ctx.featuresByLevel[level] ?? [];
|
|
35
|
-
const { bg } = EV_STATION_LEVELS[level];
|
|
36
|
-
const clusterBg = bg.replace("rgb(", "rgba(").replace(")", ", 0.6)");
|
|
37
|
-
|
|
38
|
-
mapManager.map.addSource(sourceId, {
|
|
39
|
-
type: "geojson",
|
|
40
|
-
promoteId: "id",
|
|
41
|
-
data: { type: "FeatureCollection", features },
|
|
42
|
-
cluster: true,
|
|
43
|
-
clusterRadius: 40,
|
|
44
|
-
clusterMaxZoom: 9
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
mapManager.map.addLayer(
|
|
48
|
-
{
|
|
49
|
-
id: `${sourceId}-cluster-circle`,
|
|
50
|
-
type: "circle",
|
|
51
|
-
source: sourceId,
|
|
52
|
-
filter: ["has", "point_count"],
|
|
53
|
-
paint: {
|
|
54
|
-
"circle-color": clusterBg,
|
|
55
|
-
"circle-radius": ["step", ["get", "point_count"], 15, 10, 20, 25, 25]
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
this.ctx.beforeLayer
|
|
59
|
-
);
|
|
60
|
-
|
|
61
|
-
mapManager.map.addLayer(
|
|
62
|
-
{
|
|
63
|
-
id: `${sourceId}-cluster-label`,
|
|
64
|
-
type: "symbol",
|
|
65
|
-
source: sourceId,
|
|
66
|
-
filter: ["has", "point_count"],
|
|
67
|
-
layout: {
|
|
68
|
-
"text-field": ["get", "point_count_abbreviated"],
|
|
69
|
-
"text-size": 12,
|
|
70
|
-
"text-allow-overlap": true,
|
|
71
|
-
"text-ignore-placement": true
|
|
72
|
-
},
|
|
73
|
-
paint: { "text-color": "#ffffff" }
|
|
74
|
-
},
|
|
75
|
-
this.ctx.beforeLayer
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
mapManager.map.addLayer(
|
|
79
|
-
{
|
|
80
|
-
id: `${sourceId}-unclustered`,
|
|
81
|
-
type: "symbol",
|
|
82
|
-
source: sourceId,
|
|
83
|
-
filter: ["!", ["has", "point_count"]],
|
|
84
|
-
layout: {
|
|
85
|
-
"icon-image": `ev-station-${level}`,
|
|
86
|
-
"icon-allow-overlap": true,
|
|
87
|
-
"icon-ignore-placement": true,
|
|
88
|
-
"icon-size": 1
|
|
89
|
-
},
|
|
90
|
-
paint: {}
|
|
91
|
-
},
|
|
92
|
-
this.ctx.beforeLayer
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const circleLayerId = `${sourceId}-cluster-circle`;
|
|
96
|
-
const unclusteredLayerId = `${sourceId}-unclustered`;
|
|
97
|
-
|
|
98
|
-
if (!this.ctx.tooltipManager.has(circleLayerId)) {
|
|
99
|
-
this.ctx.tooltipManager.register(circleLayerId, clusterTooltip);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
clickManager.register([circleLayerId], this.makeClusterClickHandler(sourceId));
|
|
103
|
-
clickManager.register([unclusteredLayerId], stationClickHandler);
|
|
104
|
-
|
|
105
|
-
this._levels.push(level);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
remove(): void {
|
|
110
|
-
if (!mapManager.map) return;
|
|
111
|
-
|
|
112
|
-
for (const level of this._levels) {
|
|
113
|
-
const sourceId = `${this.ctx.referenceId}-${level}`;
|
|
114
|
-
const layerIds = [
|
|
115
|
-
`${sourceId}-cluster-circle`,
|
|
116
|
-
`${sourceId}-cluster-label`,
|
|
117
|
-
`${sourceId}-unclustered`
|
|
118
|
-
];
|
|
119
|
-
|
|
120
|
-
for (const layerId of layerIds) {
|
|
121
|
-
clickManager.unregister([layerId]);
|
|
122
|
-
if (mapManager.map.getLayer(layerId)) {
|
|
123
|
-
mapManager.map.removeLayer(layerId);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (mapManager.map.getSource(sourceId)) {
|
|
128
|
-
mapManager.map.removeSource(sourceId);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this._levels = [];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
get unclusteredLayerIds(): string[] {
|
|
136
|
-
return this._levels.map((level) => `${this.ctx.referenceId}-${level}-unclustered`);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
syncFeatures(): void {
|
|
140
|
-
if (!mapManager.map) return;
|
|
141
|
-
for (const level of this._levels) {
|
|
142
|
-
const sourceId = `${this.ctx.referenceId}-${level}`;
|
|
143
|
-
mapManager.setDataSource(sourceId, this.ctx.featuresByLevel[level] ?? []);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private makeClusterClickHandler(sourceId: string): ClickHandler {
|
|
148
|
-
return async (features) => {
|
|
149
|
-
try {
|
|
150
|
-
const feature = features[0];
|
|
151
|
-
if (!feature?.properties?.cluster_id) return;
|
|
152
|
-
const source = mapManager.map?.getSource(sourceId) as GeoJSONSource | undefined;
|
|
153
|
-
if (!source) return;
|
|
154
|
-
const zoom = await source.getClusterExpansionZoom(feature.properties.cluster_id);
|
|
155
|
-
const coords = (feature.geometry as Point).coordinates as [number, number];
|
|
156
|
-
mapManager.map?.easeTo({ center: coords, zoom });
|
|
157
|
-
} catch (err) {
|
|
158
|
-
console.error("EvStations: cluster expansion zoom failed", err);
|
|
159
|
-
}
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
}
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ExpressionSpecification,
|
|
3
|
-
FilterSpecification,
|
|
4
|
-
Map as MaptilerMap,
|
|
5
|
-
Popup
|
|
6
|
-
} from "@maptiler/sdk";
|
|
7
|
-
import type { Geometry } from "geojson";
|
|
8
|
-
import { untrack } from "svelte";
|
|
9
|
-
import { mapManager } from "$lib/map/map-manager.svelte.js";
|
|
10
|
-
import { clickManager, type ClickHandler } from "$lib/map/integrations/click-manager";
|
|
11
|
-
import { MapIconLayerIntegration } from "$lib/map/integrations/map-geojson-integration.svelte";
|
|
12
|
-
import { MapDisplayOption } from "$lib/map/integrations/map-display-option.svelte";
|
|
13
|
-
import { TooltipManager } from "$lib/map/integrations/tooltip.svelte";
|
|
14
|
-
import { mountClickPopup } from "$lib/map/utils";
|
|
15
|
-
import { evStationsManager } from "./ev-stations.svelte";
|
|
16
|
-
import { EvStationIconManager } from "./ev-station-icons";
|
|
17
|
-
import {
|
|
18
|
-
EvStationsClusterRenderer,
|
|
19
|
-
type EvStationsClusterContext
|
|
20
|
-
} from "./ev-stations-cluster-renderer";
|
|
21
|
-
import type { EvStation, EvStationMapFeature, EvStationMarkerProperties } from "./types";
|
|
22
|
-
import EvStationTooltip from "./components/EvStationTooltip.svelte";
|
|
23
|
-
|
|
24
|
-
class EvStationsMapIntegration
|
|
25
|
-
extends MapIconLayerIntegration<EvStationMarkerProperties>
|
|
26
|
-
implements EvStationsClusterContext
|
|
27
|
-
{
|
|
28
|
-
referenceId: string = "ev-stations";
|
|
29
|
-
enabled: boolean = $state(false);
|
|
30
|
-
clustered: boolean = $state(true);
|
|
31
|
-
|
|
32
|
-
icons: EvStationIconManager = new EvStationIconManager();
|
|
33
|
-
tooltipManager: TooltipManager = new TooltipManager();
|
|
34
|
-
private renderer: EvStationsClusterRenderer = new EvStationsClusterRenderer(this);
|
|
35
|
-
private currentPopup: Popup | null = null;
|
|
36
|
-
|
|
37
|
-
displayOptions = $derived.by(() => ({
|
|
38
|
-
lvl2: new MapDisplayOption("Level 2", true, this.icons.get("ev-station-lvl2")!),
|
|
39
|
-
lvl3: new MapDisplayOption("Level 3", true, this.icons.get("ev-station-lvl3")!)
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
|
-
features: Array<EvStationMapFeature> = $derived.by(() => {
|
|
43
|
-
const result: EvStationMapFeature[] = [];
|
|
44
|
-
if (evStationsManager.lvl2Stations) {
|
|
45
|
-
for (const station of evStationsManager.lvl2Stations) {
|
|
46
|
-
result.push(toFeature(station, "lvl2"));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (evStationsManager.lvl3Stations) {
|
|
50
|
-
for (const station of evStationsManager.lvl3Stations) {
|
|
51
|
-
result.push(toFeature(station, "lvl3"));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return result;
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
featuresByLevel: Record<string, EvStationMapFeature[]> = $derived.by(() => {
|
|
58
|
-
const byLevel: Record<string, EvStationMapFeature[]> = {};
|
|
59
|
-
for (const feature of this.features) {
|
|
60
|
-
const level = feature.properties.level;
|
|
61
|
-
if (level === "lvl2" && !this.displayOptions.lvl2.value) continue;
|
|
62
|
-
if (level === "lvl3" && !this.displayOptions.lvl3.value) continue;
|
|
63
|
-
const arr = byLevel[level] ?? [];
|
|
64
|
-
arr.push(feature);
|
|
65
|
-
byLevel[level] = arr;
|
|
66
|
-
}
|
|
67
|
-
return byLevel;
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
filters: FilterSpecification = $derived.by((): FilterSpecification => {
|
|
71
|
-
const levels: string[] = [];
|
|
72
|
-
if (this.displayOptions.lvl2.value) levels.push("lvl2");
|
|
73
|
-
if (this.displayOptions.lvl3.value) levels.push("lvl3");
|
|
74
|
-
if (levels.length === 0) return ["==", ["get", "level"], "none"] as ExpressionSpecification;
|
|
75
|
-
if (levels.length === 2) return ["boolean", true] as ExpressionSpecification;
|
|
76
|
-
return ["==", ["get", "level"], levels[0]] as ExpressionSpecification;
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
private handleStationClick: ClickHandler = (features, evt) => {
|
|
80
|
-
this.currentPopup?.remove();
|
|
81
|
-
const feature = features[0] as unknown as EvStationMapFeature | undefined;
|
|
82
|
-
if (!feature) return;
|
|
83
|
-
this.currentPopup = mountClickPopup(EvStationTooltip, { feature }, evt.lngLat);
|
|
84
|
-
this.currentPopup.addTo(mapManager.map!);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
get mapLayer(): Parameters<MaptilerMap["addLayer"]>[0] {
|
|
88
|
-
return {
|
|
89
|
-
id: this.referenceId,
|
|
90
|
-
type: "symbol",
|
|
91
|
-
source: this.referenceId,
|
|
92
|
-
filter: this.filters,
|
|
93
|
-
layout: {
|
|
94
|
-
"icon-allow-overlap": true,
|
|
95
|
-
"icon-ignore-placement": true,
|
|
96
|
-
"icon-image": ["get", "icon"],
|
|
97
|
-
"icon-size": 1
|
|
98
|
-
},
|
|
99
|
-
paint: {}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
get mapSource(): Parameters<MaptilerMap["addSource"]>[1] {
|
|
104
|
-
return {
|
|
105
|
-
type: "geojson",
|
|
106
|
-
promoteId: "id",
|
|
107
|
-
data: {
|
|
108
|
-
type: "FeatureCollection",
|
|
109
|
-
features: this.features
|
|
110
|
-
}
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
constructor() {
|
|
115
|
-
super();
|
|
116
|
-
|
|
117
|
-
$effect.root(() => {
|
|
118
|
-
// Lazy-fetch level data only once the integration is enabled and the level is on
|
|
119
|
-
$effect(() => {
|
|
120
|
-
if (
|
|
121
|
-
this.enabled &&
|
|
122
|
-
this.displayOptions.lvl2.value &&
|
|
123
|
-
evStationsManager.lvl2Stations === undefined
|
|
124
|
-
) {
|
|
125
|
-
evStationsManager.loadLvl2Stations();
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
$effect(() => {
|
|
130
|
-
if (
|
|
131
|
-
this.enabled &&
|
|
132
|
-
this.displayOptions.lvl3.value &&
|
|
133
|
-
evStationsManager.lvl3Stations === undefined
|
|
134
|
-
) {
|
|
135
|
-
evStationsManager.loadLvl3Stations();
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// Every effect below early-returns while disabled so a data refresh can't re-add the layer.
|
|
140
|
-
// `enabled` is read untracked: the base class's own effect already applies/removes on
|
|
141
|
-
// enabled changes, and tracking it here would apply twice. The guard comes after each
|
|
142
|
-
// effect's tracked reads so its dependencies are always collected; returning before
|
|
143
|
-
// reading anything would leave the effect permanently dead.
|
|
144
|
-
|
|
145
|
-
// Push filter changes to the unclustered layer
|
|
146
|
-
$effect(() => {
|
|
147
|
-
const filter = this.filters;
|
|
148
|
-
if (!mapManager.map || this.clustered) return;
|
|
149
|
-
if (!untrack(() => this.enabled)) return;
|
|
150
|
-
if (mapManager.map.getLayer(this.referenceId)) {
|
|
151
|
-
mapManager.map.setFilter(this.referenceId, filter);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// Sync unclustered source when features change
|
|
156
|
-
$effect(() => {
|
|
157
|
-
const features = this.features;
|
|
158
|
-
if (!mapManager.map || this.clustered) return;
|
|
159
|
-
if (!untrack(() => this.enabled)) return;
|
|
160
|
-
mapManager.setDataSource(this.referenceId, features);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// Sync clustered sources when featuresByLevel changes
|
|
164
|
-
$effect(() => {
|
|
165
|
-
void this.featuresByLevel;
|
|
166
|
-
if (!mapManager.map || !this.clustered) return;
|
|
167
|
-
if (!untrack(() => this.enabled)) return;
|
|
168
|
-
this.renderer.syncFeatures();
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Re-apply when clustered mode switches or data first arrives
|
|
172
|
-
$effect(() => {
|
|
173
|
-
void this.clustered;
|
|
174
|
-
const hasFeatures = Object.keys(this.featuresByLevel).length > 0;
|
|
175
|
-
if (!untrack(() => mapManager.map) || !hasFeatures) return;
|
|
176
|
-
if (!untrack(() => this.enabled)) return;
|
|
177
|
-
untrack(() => this.apply());
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
apply() {
|
|
183
|
-
if (!mapManager.map) return;
|
|
184
|
-
|
|
185
|
-
if (this.clustered) {
|
|
186
|
-
if (mapManager.map.getLayer(this.referenceId)) mapManager.map.removeLayer(this.referenceId);
|
|
187
|
-
if (mapManager.map.getSource(this.referenceId)) mapManager.map.removeSource(this.referenceId);
|
|
188
|
-
clickManager.unregister([this.referenceId]);
|
|
189
|
-
this.tooltipManager.disable();
|
|
190
|
-
this.renderer.remove();
|
|
191
|
-
// Clustering may be toggled again before the icons arrive; only the latest apply runs.
|
|
192
|
-
this.supersedePending();
|
|
193
|
-
this.whenIconsLoad(() => {
|
|
194
|
-
this.renderer.apply(this.handleStationClick);
|
|
195
|
-
this.tooltipManager.enable();
|
|
196
|
-
});
|
|
197
|
-
} else {
|
|
198
|
-
this.renderer.remove();
|
|
199
|
-
this.tooltipManager.disable();
|
|
200
|
-
clickManager.unregister([this.referenceId]);
|
|
201
|
-
super.apply();
|
|
202
|
-
this.whenIconsLoad(() => {
|
|
203
|
-
clickManager.register([this.referenceId], this.handleStationClick);
|
|
204
|
-
this.tooltipManager.enable();
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
remove() {
|
|
210
|
-
clickManager.unregister([this.referenceId]);
|
|
211
|
-
clickManager.unregister(this.renderer.unclusteredLayerIds);
|
|
212
|
-
this.renderer.remove();
|
|
213
|
-
this.currentPopup?.remove();
|
|
214
|
-
this.currentPopup = null;
|
|
215
|
-
super.remove();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function toFeature(station: EvStation, level: "lvl2" | "lvl3"): EvStationMapFeature {
|
|
220
|
-
return {
|
|
221
|
-
type: "Feature",
|
|
222
|
-
properties: {
|
|
223
|
-
icon: `ev-station-${level}`,
|
|
224
|
-
id: station.id,
|
|
225
|
-
level,
|
|
226
|
-
station_name: station.station_name ?? "",
|
|
227
|
-
facility_type: station.facility_type ?? "",
|
|
228
|
-
ev_network: station.ev_network ?? "",
|
|
229
|
-
station_phone: station.station_phone ?? "",
|
|
230
|
-
street_address: station.street_address ?? "",
|
|
231
|
-
city: station.city ?? "",
|
|
232
|
-
state: station.state ?? "",
|
|
233
|
-
zip: station.zip ?? "",
|
|
234
|
-
access_days_time: station.access_days_time ?? "",
|
|
235
|
-
access_detail_code: station.access_detail_code ?? "",
|
|
236
|
-
cards_accepted: station.cards_accepted ?? null,
|
|
237
|
-
ev_pricing: station.ev_pricing ?? "",
|
|
238
|
-
ev_connector_types: JSON.stringify(station.ev_connector_types ?? [])
|
|
239
|
-
},
|
|
240
|
-
geometry: {
|
|
241
|
-
type: "Point",
|
|
242
|
-
coordinates: [station.longitude, station.latitude]
|
|
243
|
-
} as Geometry
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export const evStationsMapIntegration = new EvStationsMapIntegration();
|
|
248
|
-
export type { EvStationsMapIntegration };
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
accessDetailCodeTypes,
|
|
3
|
-
creditCardTypes,
|
|
4
|
-
evConnectorTypes,
|
|
5
|
-
evNetworkTypes,
|
|
6
|
-
facilityTypes
|
|
7
|
-
} from "./data-maps";
|
|
8
|
-
import type { EvStation } from "./types";
|
|
9
|
-
import * as ZipCodes from "./zip-codes";
|
|
10
|
-
|
|
11
|
-
class EvStationsManager {
|
|
12
|
-
lvl2Stations: Array<EvStation> | undefined = $state();
|
|
13
|
-
lvl3Stations: Array<EvStation> | undefined = $state();
|
|
14
|
-
|
|
15
|
-
async loadLvl3Stations(): Promise<void> {
|
|
16
|
-
this.lvl3Stations = await fetchEvStations("dc_fast");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async loadLvl2Stations(): Promise<void> {
|
|
20
|
-
this.lvl2Stations = await fetchEvStations("2");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const zipCodes = Object.values(ZipCodes)
|
|
25
|
-
.reduce((prev, curr) => prev.concat(curr))
|
|
26
|
-
.join(",");
|
|
27
|
-
|
|
28
|
-
async function fetchEvStations(chargingLevel: "2" | "dc_fast"): Promise<Array<EvStation>> {
|
|
29
|
-
const url = new URL(`https://developer.nlr.gov/api/alt-fuel-stations/v1.json`);
|
|
30
|
-
url.searchParams.set("fuel_type", "ELEC");
|
|
31
|
-
url.searchParams.set("state", "CA");
|
|
32
|
-
url.searchParams.set("status", "E");
|
|
33
|
-
url.searchParams.set("access", "public");
|
|
34
|
-
url.searchParams.set("ev_charging_level", chargingLevel);
|
|
35
|
-
url.searchParams.set("zip", zipCodes);
|
|
36
|
-
url.searchParams.set("api_key", import.meta.env.VITE_NREL_KEY);
|
|
37
|
-
|
|
38
|
-
return await fetch(url)
|
|
39
|
-
.then(async (res) => await res.json())
|
|
40
|
-
.then((data) => {
|
|
41
|
-
const fuelStations: Array<EvStation> = data.fuel_stations!;
|
|
42
|
-
return (
|
|
43
|
-
fuelStations
|
|
44
|
-
.map((station) => {
|
|
45
|
-
if (station.access_detail_code) {
|
|
46
|
-
station.access_detail_code = accessDetailCodeTypes.get(station.access_detail_code);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (station.cards_accepted) {
|
|
50
|
-
station.cards_accepted = station.cards_accepted
|
|
51
|
-
.split(" ")
|
|
52
|
-
.map((c: string) => creditCardTypes.get(c))
|
|
53
|
-
.join(", ");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (station.ev_connector_types && station.ev_connector_types.length) {
|
|
57
|
-
station.ev_connector_types = station.ev_connector_types.map((t: string) =>
|
|
58
|
-
evConnectorTypes.get(t)
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (station.ev_network) {
|
|
63
|
-
station.ev_network = evNetworkTypes.get(station.ev_network);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (station.facility_type) {
|
|
67
|
-
station.facility_type = facilityTypes.get(station.facility_type);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return station;
|
|
71
|
-
})
|
|
72
|
-
// remove stations with invalid coordinates
|
|
73
|
-
.filter((station) => station.id !== 226154)
|
|
74
|
-
);
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export const evStationsManager = new EvStationsManager();
|
|
79
|
-
export type { EvStationsManager };
|