From 91ddd09bd2f96af6bc73b97e937a3e461ed697a5 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Wed, 7 Jan 2026 02:38:57 +0100 Subject: [PATCH] Migrate the minimaps from leaflet to MapLibre --- app/assets/javascripts/application.js | 2 +- app/assets/javascripts/leaflet.layers.js | 39 ++++++++++++++----- app/assets/javascripts/leaflet.map.js | 14 +++++-- app/assets/javascripts/leaflet.maptiler.js | 16 +------- app/assets/javascripts/maplibre/i18n.js | 20 ++++++++++ .../initializers/content_security_policy.rb | 2 +- 6 files changed, 63 insertions(+), 30 deletions(-) create mode 100644 app/assets/javascripts/maplibre/i18n.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e6c32fc4d..df2b33b79 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -8,11 +8,11 @@ //= require leaflet/dist/leaflet-src //= require leaflet.osm //= require leaflet.shortbread +//= require i18n //= require leaflet.maptiler //= require leaflet.map //= require leaflet.zoom //= require leaflet.locationfilter -//= require i18n //= require matomo //= require richtext //= require language_selector diff --git a/app/assets/javascripts/leaflet.layers.js b/app/assets/javascripts/leaflet.layers.js index 4a680fac4..5af4e110f 100644 --- a/app/assets/javascripts/leaflet.layers.js +++ b/app/assets/javascripts/leaflet.layers.js @@ -1,3 +1,8 @@ +//= require @maptiler/maplibre-gl-omt-language +//= require maplibre/map +//= require maplibre/styles +//= require maplibre/i18n + L.OSM.layers = function (options) { const control = L.OSM.sidebarPane(options, "layers", "javascripts.map.layers.title", "javascripts.map.layers.header"); @@ -16,21 +21,29 @@ L.OSM.layers = function (options) { input.checked = map.hasLayer(layer); map.whenReady(function () { - const miniMap = L.map(container, { attributionControl: false, zoomControl: false, keyboard: false }) - .addLayer(new layer.constructor(layer.options)); + const styleId = layer.options.leafletOsmId; + const style = OSM.MapLibre.Styles[styleId](layer.options); + const layerDefinition = OSM.LAYER_DEFINITIONS.find(l => l.leafletOsmId === styleId || l.leafletOsmDarkId === styleId); + const miniMap = new OSM.MapLibre.Map({ + container, + style, + interactive: false, + attributionControl: false, + fadeDuration: 0, + zoomSnap: layerDefinition.isVectorStyle ? 0 : 1 + }); - miniMap.dragging.disable(); - miniMap.touchZoom.disable(); - miniMap.doubleClickZoom.disable(); - miniMap.scrollWheelZoom.disable(); + if (styleId === "OpenMapTiles") { + OSM.MapLibre.setOMTMapLanguage(miniMap); + } $ui .on("show", shown) .on("hide", hide); function shown() { - miniMap.invalidateSize(); - setView({ animate: false }); + miniMap.resize(); + setView(false); map.on("moveend", moved); } @@ -42,8 +55,14 @@ L.OSM.layers = function (options) { setView(); } - function setView(options) { - miniMap.setView(map.getCenter(), Math.max(map.getZoom() - 2, 0), options); + function setView(animate = true) { + const center = map.getCenter(); + const zoom = Math.max(Math.floor(map.getZoom() - 3), -1); + if (animate) { + miniMap.easeTo({ center: [center.lng, center.lat], zoom }); + } else { + miniMap.jumpTo({ center: [center.lng, center.lat], zoom }); + } } }); diff --git a/app/assets/javascripts/leaflet.map.js b/app/assets/javascripts/leaflet.map.js index fc71a4049..d56602a9f 100644 --- a/app/assets/javascripts/leaflet.map.js +++ b/app/assets/javascripts/leaflet.map.js @@ -15,10 +15,16 @@ L.OSM.Map = L.Map.extend({ ) => { if (credit) layerOptions.attribution = makeAttribution(credit); if (nameId) layerOptions.name = OSM.i18n.t(`javascripts.map.base.${nameId}`); - const layerConstructor = - (OSM.isDarkMap() && L.OSM[leafletOsmDarkId]) || - L.OSM[leafletOsmId] || - L.OSM.TileLayer; + + if (OSM.isDarkMap() && L.OSM[leafletOsmDarkId]) { + layerOptions.leafletOsmId = leafletOsmDarkId; + } else if (L.OSM[leafletOsmId]) { + layerOptions.leafletOsmId = leafletOsmId; + } else { + layerOptions.leafletOsmId = "TileLayer"; + } + + const layerConstructor = L.OSM[layerOptions.leafletOsmId]; const layer = new layerConstructor(layerOptions); layer.on("add", () => { diff --git a/app/assets/javascripts/leaflet.maptiler.js b/app/assets/javascripts/leaflet.maptiler.js index 3b5572c20..71f4e5f58 100644 --- a/app/assets/javascripts/leaflet.maptiler.js +++ b/app/assets/javascripts/leaflet.maptiler.js @@ -1,4 +1,5 @@ //= require leaflet.maplibre +//= require maplibre/i18n //= require @maptiler/maplibre-gl-omt-language L.OSM.OpenMapTiles = L.OSM.MaplibreGL.extend({ @@ -12,20 +13,7 @@ L.OSM.OpenMapTiles = L.OSM.MaplibreGL.extend({ }, onAdd: function (map) { L.OSM.MaplibreGL.prototype.onAdd.call(this, map); - const maplibreMap = this.getMaplibreMap(); - const supportedLanguages = maplibregl.Map.prototype.supportedLanguages; - for (const preferredLanguage of OSM.preferred_languages) { - const normalizedPreferredLanguage = preferredLanguage - .toLowerCase() - .replace("-", "_"); - const matchedLanguage = supportedLanguages.find( - (supported) => supported.toLowerCase() === normalizedPreferredLanguage - ); - if (matchedLanguage) { - maplibreMap.setLanguage(matchedLanguage); - break; - } - } + OSM.MapLibre.setOMTMapLanguage(this.getMaplibreMap()); }, onRemove: function (map) { L.OSM.MaplibreGL.prototype.onRemove.call(this, map); diff --git a/app/assets/javascripts/maplibre/i18n.js b/app/assets/javascripts/maplibre/i18n.js new file mode 100644 index 000000000..feccf6fa9 --- /dev/null +++ b/app/assets/javascripts/maplibre/i18n.js @@ -0,0 +1,20 @@ +OSM.MapLibre.setOMTMapLanguage = function (map) { + if (!map.style.loaded()) { + map.once("load", () => OSM.MapLibre.setOMTMapLanguage(map)); + return; + } + + for (const preferredLanguage of OSM.preferred_languages) { + const normalizedPreferredLanguage = preferredLanguage + .toLowerCase() + .replace("-", "_"); + // supportedLanguages and setLanguage come from @maptiler/maplibre-gl-omt-language + const matchedLanguage = map.supportedLanguages.find( + (supported) => supported.toLowerCase() === normalizedPreferredLanguage + ); + if (matchedLanguage) { + map.setLanguage(matchedLanguage); + break; + } + } +}; diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index c02ab9996..5dba4745e 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -7,7 +7,7 @@ # https://guides.rubyonrails.org/security.html#content-security-policy-header Rails.application.configure do - connect_src = [:self, "tile.openstreetmap.org"] + connect_src = [:self, "tile.openstreetmap.org", "*.tile.thunderforest.com", "tile.tracestrack.com", "*.openstreetmap.fr", "vector.openstreetmap.org", "api.maptiler.com"] img_src = [:self, :data, "www.gravatar.com", "*.wp.com", "tile.openstreetmap.org", "gps.tile.openstreetmap.org", "*.tile.thunderforest.com", "tile.tracestrack.com", "*.openstreetmap.fr"] script_src = [:self] -- 2.39.5