feat(views/geo): support vector maps

This commit is contained in:
Elian Doran
2025-07-24 15:07:47 +03:00
parent 0e590a1bbf
commit 8c4ed2d4da
4 changed files with 320 additions and 44 deletions

View File

@@ -18,6 +18,7 @@
"@fullcalendar/list": "6.1.18",
"@fullcalendar/multimonth": "6.1.18",
"@fullcalendar/timegrid": "6.1.18",
"@maplibre/maplibre-gl-leaflet": "0.1.2",
"@mermaid-js/layout-elk": "0.1.8",
"@mind-elixir/node-menu": "5.0.0",
"@popperjs/core": "2.11.8",

View File

@@ -10,6 +10,8 @@ import toast from "../../../services/toast.js";
import { CommandListenerData, EventData } from "../../../components/app_context.js";
import { createNewNote, moveMarker, setupDragging } from "./editing.js";
import { openMapContextMenu } from "./context_menu.js";
import getMapLayer from "./map_layer.js";
import attributes from "../../../services/attributes.js";
const TPL = /*html*/`
<div class="geo-view">
@@ -138,10 +140,10 @@ export default class GeoView extends ViewMode<MapData> {
const map = L.map(this.$container[0], {
worldCopyJump: true
});
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
detectRetina: true
}).addTo(map);
const layerName = this.parentNote.getLabelValue("mapLayer") ?? "openstreetmap";
const layer = (await getMapLayer(layerName));
layer.addTo(map);
this.map = map;
@@ -264,6 +266,11 @@ export default class GeoView extends ViewMode<MapData> {
if (attributeRows.find((at) => [LOCATION_ATTRIBUTE, "color"].includes(at.name ?? ""))) {
this.#reloadMarkers();
}
// Full reload if map layer is changed.
if (loadResults.getAttributeRows().some(attr => attr.name === "mapLayer" && attributes.isAffecting(attr, this.parentNote))) {
return true;
}
}
async geoMapCreateChildNoteEvent({ ntxId }: EventData<"geoMapCreateChildNote">) {

View File

@@ -0,0 +1,46 @@
import L from "leaflet";
import type { StyleSpecification } from "maplibre-gl";
interface VectorLayer {
type: "vector";
style: string | (() => Promise<StyleSpecification>)
}
interface RasterLayer {
type: "raster";
url: string;
attribution: string;
}
const LAYERS: Record<string, VectorLayer | RasterLayer> = {
"openstreetmap": {
type: "raster",
url: "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
},
"versatiles-colorful": {
type: "vector",
style: async () => {
const style = await import("./styles/colorful/en.json");
return style.default as unknown as StyleSpecification;
}
}
};
export default async function getMapLayer(layerName: string) {
const layer = LAYERS[layerName] ?? LAYERS["openstreetmap"];
if (layer.type === "vector") {
const style = (typeof layer.style === "string" ? layer.style : await layer.style());
await import("@maplibre/maplibre-gl-leaflet");
return L.maplibreGL({
style
});
}
return L.tileLayer(layer.url, {
attribution: layer.attribution,
detectRetina: true
});
}