import { Map as MaplibreMap, NavigationControl, GeolocateControl, addProtocol, } from "/vendor/maplibre-gl/maplibre-gl.mjs"; import { RadarControl } from "/js/radar.js"; import { GpxPanelControl } from "/js/gpx.js"; const CENTER = [17.1077, 48.1486]; const ZOOM = 13; const ONLINE_STYLE = "https://tiles.openfreemap.org/styles/liberty"; const protocol = new pmtiles.Protocol(); addProtocol("pmtiles", protocol.tile); // No label layers here (see docs/architecture.adoc): rendering text needs a // glyphs server, which the offline style deliberately does not depend on. function offlineStyle() { const theme = protomaps_themes_base.namedTheme("light"); const pmtilesUrl = `${window.location.origin}/tiles/offline.pmtiles`; return { version: 8, sources: { offline: { type: "vector", url: `pmtiles://${pmtilesUrl}`, attribution: "© OpenStreetMap contributors", }, }, layers: protomaps_themes_base.layers("offline", theme), }; } class LayerToggleControl { constructor(onSelect) { this._onSelect = onSelect; } onAdd() { this._container = document.createElement("div"); this._container.className = "maplibregl-ctrl maplibregl-ctrl-group layer-toggle"; this._container.innerHTML = ` `; this._container.addEventListener("click", (event) => { const button = event.target.closest("button[data-style]"); if (button) this._onSelect(button.dataset.style); }); return this._container; } onRemove() { this._container.remove(); } setActive(name) { this._container.querySelectorAll("button").forEach((button) => { button.classList.toggle("active", button.dataset.style === name); }); } } const map = new MaplibreMap({ container: "map", style: ONLINE_STYLE, center: CENTER, zoom: ZOOM, }); map.addControl(new NavigationControl(), "top-right"); map.addControl( new GeolocateControl({ positionOptions: { enableHighAccuracy: true }, trackUserLocation: true, showAccuracyCircle: true, }), "top-right", ); map.addControl(new RadarControl(map), "top-right"); const layerToggle = new LayerToggleControl(applyStyle); map.addControl(layerToggle, "top-left"); layerToggle.setActive("online"); map.addControl(new GpxPanelControl(map), "top-left"); function applyStyle(name) { layerToggle.setActive(name); map.setStyle(name === "offline" ? offlineStyle() : ONLINE_STYLE); } // If a local PMTiles file is present, prefer it as the default style — its // presence signals the app is meant to be used offline here. fetch("/api/offline-tiles") .then((response) => response.json()) .then(({ available }) => { if (available) applyStyle("offline"); }) .catch(() => { // Backend check failed; keep the online style. });