94 lines
2.4 KiB
Svelte
94 lines
2.4 KiB
Svelte
<script lang="ts">
|
|
import type { ActionReturn } from 'svelte/action';
|
|
import type { TileLayer, Map as LeafletMap } from 'leaflet';
|
|
import { tilerLayerAttribution, tilerLayerUrl } from '$lib/map/layer';
|
|
import type * as Leaflet from 'leaflet';
|
|
|
|
interface Props {
|
|
map: LeafletMap | null;
|
|
selected: boolean;
|
|
baseLayer: 'osm';
|
|
dataLayer: 'noaa_mrms_merged_composite_reflectivity_qc' | null;
|
|
overlayLayers: string[];
|
|
}
|
|
let { map = $bindable(null), selected, baseLayer, dataLayer }: Props = $props();
|
|
|
|
let mapContainerElement: HTMLElement;
|
|
// await import('leaflet') done at runtime
|
|
let L: Leaflet | null = $state(null);
|
|
// Base layer - openstreetmap, carto, etc
|
|
let layer0: TileLayer;
|
|
// Data layer - composite reflectivity, velocity (the actual data)
|
|
let layer1: TileLayer;
|
|
|
|
// Layer0 (base) updating
|
|
$effect(() => {
|
|
// if leaflet hasn't been imported yet, skip
|
|
// this also sets a dependency, so we'll be re-ran once it has
|
|
if (!L) return;
|
|
if (!map) return;
|
|
|
|
// if there is already a layer0 and a map, remove the old one
|
|
if (layer0 && map) {
|
|
layer0.removeFrom(map);
|
|
}
|
|
|
|
// OpenStreetMap
|
|
if (baseLayer === 'osm') {
|
|
layer0 = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution:
|
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
|
});
|
|
layer0.addTo(map);
|
|
}
|
|
});
|
|
|
|
// Layer1 (data) updating
|
|
$effect(() => {
|
|
if (!L) return;
|
|
if (!map) return;
|
|
|
|
// remove existing layer1, if there is one
|
|
if (layer1 && map) {
|
|
layer1.removeFrom(map);
|
|
}
|
|
|
|
if (dataLayer) {
|
|
layer1 = L.tileLayer(tilerLayerUrl(dataLayer), {
|
|
attribution: tilerLayerAttribution(dataLayer)
|
|
});
|
|
layer1.addTo(map);
|
|
}
|
|
});
|
|
|
|
// ran when the div below (see use:mapAction) is created
|
|
async function mapAction(): Promise<ActionReturn> {
|
|
// dynamically imports leaflet, as it's a browser lib
|
|
L = await import('leaflet');
|
|
// imports leaflet.sync, for syncing
|
|
await import('leaflet.sync');
|
|
|
|
// create the map
|
|
map = L.map(mapContainerElement, {
|
|
// geo center of CONUS
|
|
center: [39.83, -98.583],
|
|
zoom: 5
|
|
});
|
|
|
|
if (!map) return {};
|
|
}
|
|
</script>
|
|
|
|
<div class="map" class:mapselected={selected} bind:this={mapContainerElement} use:mapAction></div>
|
|
|
|
<style>
|
|
.map {
|
|
flex: 1;
|
|
box-sizing: border-box;
|
|
border: 2px solid transparent;
|
|
}
|
|
.mapselected {
|
|
box-sizing: border-box;
|
|
border: 2px solid red;
|
|
}
|
|
</style>
|