Skip to content

Commit

Permalink
fix(mapper): automatically select pmtiles layer if set
Browse files Browse the repository at this point in the history
  • Loading branch information
spwoodcock committed Nov 30, 2024
1 parent 6334903 commit 0a437ca
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 69 deletions.
110 changes: 47 additions & 63 deletions src/mapper/src/lib/components/map/layer-switcher.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,49 @@ map = new Map({
import { onDestroy } from 'svelte';
import { clickOutside } from '$lib/utils/clickOutside';
type MapLibreStylePlusMetadata = maplibregl.StyleSpecification & {
metadata: {
thumbnail?: string;
};
};
type Props = {
styles: maplibregl.StyleSpecification[];
selectedStyleName?: string | undefined;
map: maplibregl.Map | undefined;
sourcesIdToReAdd: string[];
switchToNewestStyle: boolean;
};
const { styles, map, sourcesIdToReAdd, switchToNewestStyle = false }: Props = $props();
const { styles, selectedStyleName, map, sourcesIdToReAdd }: Props = $props();
let allStyles: MapLibreStylePlusMetadata[] | [] = $state([]);
let selectedStyleUrl: string | undefined = $state(undefined);
let isClosed = $state(true);
// This variable is used for updating the prop selectedStyleName dynamically
let reactiveStyleSelection: MapLibreStylePlusMetadata | undefined = $state(undefined);
let isOpen = $state(false);
let isFirstLoad = true;
// Get style info when styles are updated
$effect(() => {
if (styles.length > 0) {
// We do not await this to avoid complicating reactive logic
fetchStyleInfo();
} else {
allStyles = [];
}
});
type MapLibreStylePlusMetadata = maplibregl.StyleSpecification & {
metadata: {
thumbnail?: string;
};
};
$effect(() => {
// Set initial selected style
reactiveStyleSelection = allStyles.find((style) => style.name === selectedStyleName) || allStyles[0];
selectedStyleUrl = reactiveStyleSelection?.metadata?.thumbnail;
});
// Update the map when a new style is selected
$effect(() => {
if (reactiveStyleSelection) {
selectStyle(reactiveStyleSelection);
}
});
/**
* Extract the raster thumbnail root tile, or return an empty string.
Expand Down Expand Up @@ -105,9 +120,7 @@ map = new Map({
// Process the current map style
const currentMapStyle = map?.getStyle();
if (currentMapStyle) {
const processedStyle = processStyle(currentMapStyle);
selectedStyleUrl = processedStyle?.metadata?.thumbnail || undefined;
processedStyles.push(processedStyle);
processedStyles.push(processStyle(currentMapStyle));
}
// Process additional styles (download first if style is URL)
Expand All @@ -121,77 +134,48 @@ map = new Map({
}
}
// Filter out duplicate styles based on `name` field
const deduplicatedStyles = [...processedStyles].filter(
// Deduplicate styles by `name`
allStyles = processedStyles.filter(
(style, index, self) => self.findIndex((s) => s.name === style.name) === index,
);
// If a new style is added later, we automatically switch
// to that style, if switchToNewestStyle is true
if (switchToNewestStyle && !isFirstLoad) {
// Determine new styles only on subsequent updates
const newStyles = deduplicatedStyles.filter(
style => !allStyles.find(existingStyle => existingStyle.name === style.name)
);
// Handle new styles (e.g., auto-switch to the newest style)
if (newStyles.length > 0) {
selectStyle(newStyles[newStyles.length - 1]);
}
}
// Update allStyles only if there are changes
if (JSON.stringify(allStyles) !== JSON.stringify(deduplicatedStyles)) {
allStyles = deduplicatedStyles;
}
isFirstLoad = false;
}
function selectStyle(style: MapLibreStylePlusMetadata) {
// returns all the map style i.e. all layers, sources
const currentMapStyle = map?.getStyle();
// reAddLayers: user defined layers that needs to be preserved
const reAddLayers = currentMapStyle?.layers?.filter((layer) => {
return sourcesIdToReAdd?.includes(layer?.source);
});
// reAddSources: user defined sources that needs to be preserved
const reAddSources = Object?.entries(currentMapStyle?.sources)
?.filter(([key]) => sourcesIdToReAdd?.includes(key))
?.map(([key, value]) => ({ [key]: value }));
if (style.name === currentMapStyle.name) return;
selectedStyleUrl = style.metadata.thumbnail;
// changes to selected base layer (note: user defined layer and sources are lost)
// Apply the selected style to the map
// being sure to save sources and layers to add back on top
const reAddLayers = currentMapStyle?.layers?.filter((layer) => sourcesIdToReAdd.includes(layer.source));
const reAddSources = Object.entries(currentMapStyle?.sources || {})
.filter(([key]) => sourcesIdToReAdd.includes(key))
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {});
map?.setStyle(style);
isClosed = !isClosed;
// reapply user defined source
if (reAddSources?.length > 0) {
for (const reAddSource of reAddSources) {
for (const [id, source] of Object.entries(reAddSource)) {
if (!map?.getStyle().sources[id]) {
map?.addSource(id, source);
}
// Re-add sources and layers
if (reAddSources) {
Object.entries(reAddSources).forEach(([id, source]) => {
if (!map?.getStyle().sources[id]) {
map?.addSource(id, source);
}
}
});
}
// reapply user defined layers
if (reAddLayers?.length > 0) {
for (const layer of reAddLayers) {
if (!map?.getStyle().layers.find((layerx) => layerx?.id === layer.id)) {
if (reAddLayers) {
reAddLayers.forEach((layer) => {
if (!map?.getStyle().layers.find((l) => l.id === layer.id)) {
map?.addLayer(layer);
}
}
});
}
}
onDestroy(() => {
allStyles = [];
selectedStyleUrl = undefined;
isClosed = true;
});
</script>

Expand Down
8 changes: 3 additions & 5 deletions src/mapper/src/lib/components/map/main.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
let map: maplibregl.Map | undefined = $state();
let loaded: boolean = $state(false);
let selectedBaselayer: string = $state('OSM');
let taskAreaClicked: boolean = $state(false);
let toggleGeolocationStatus: boolean = $state(false);
let projectSetupStep = $state(null);
Expand Down Expand Up @@ -153,10 +154,6 @@
}
});
let taskAreaClicked: boolean = $state(false);
let toggleGeolocationStatus: boolean = $state(false);
let projectSetupStep = $state(null);
$effect(() => {
projectSetupStep = +projectSetupStepStore.projectSetupStep;
});
Expand Down Expand Up @@ -209,6 +206,7 @@
const offlineBasemapFile = await readFileFromOPFS(`${projectId}/basemap.pmtiles`);
if (offlineBasemapFile) {
await loadOfflinePmtiles(projectId);
selectedBaselayer = 'PMTiles';
}
});
</script>
Expand Down Expand Up @@ -255,7 +253,7 @@
{map}
styles={allBaseLayers}
sourcesIdToReAdd={['tasks', 'entities', 'geolocation']}
switchToNewestStyle={true}
selectedStyleName={selectedBaselayer}
></LayerSwitcher>
<Legend />
</Control>
Expand Down
2 changes: 1 addition & 1 deletion src/mapper/src/lib/fs/opfs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export async function readFileFromOPFS(filePath: string): Promise<File | null> {
if (!filename) {
return null; // Invalid path
}
console.log(`Getting OPFS file: ${filename}`);
// console.log(`Getting OPFS file: ${filename}`);
const fileHandle = await currentDirectoryHandle.getFileHandle(filename);
const fileData = await fileHandle.getFile(); // Read the file
return fileData;
Expand Down

0 comments on commit 0a437ca

Please sign in to comment.