X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/5410fb6cc6973aa59a278b83ac6dc3785b3b815d..475a3fd83615fec2a1b79d04f3323ae45c917ccd:/app/assets/javascripts/leaflet.map.js diff --git a/app/assets/javascripts/leaflet.map.js b/app/assets/javascripts/leaflet.map.js index fe4b139d1..99d5a6050 100644 --- a/app/assets/javascripts/leaflet.map.js +++ b/app/assets/javascripts/leaflet.map.js @@ -15,109 +15,37 @@ L.OSM.Map = L.Map.extend({ initialize: function (id, options) { L.Map.prototype.initialize.call(this, id, options); - const layerCredits = { - mapnik: { - id: "make_a_donation", - href: "https://supporting.openstreetmap.org", - donate: true - }, - cyclosm: { - id: "cyclosm_credit", - children: { - cyclosm_link: { - id: "cyclosm_name", - href: "https://www.cyclosm.org" - }, - osm_france_link: { - id: "osm_france", - href: "https://openstreetmap.fr/" - } - } - }, - thunderforest: { - id: "thunderforest_credit", - children: { - thunderforest_link: { - id: "andy_allan", - href: "https://www.thunderforest.com/" - } - } - }, - tracestrack: { - id: "tracestrack_credit", - children: { - tracestrack_link: { - id: "tracestrack", - href: "https://www.tracestrack.com/" - } - } - }, - hotosm: { - id: "hotosm_credit", - children: { - hotosm_link: { - id: "hotosm_name", - href: "https://www.hotosm.org/" - }, - osm_france_link: { - id: "osm_france", - href: "https://openstreetmap.fr/" - } - } - } - }; - this.baseLayers = []; - this.baseLayers.push(new L.OSM.Mapnik({ - attribution: makeAttribution("mapnik"), - code: "M", - keyid: "mapnik", - name: I18n.t("javascripts.map.base.standard") - })); - - this.baseLayers.push(new L.OSM.CyclOSM({ - attribution: makeAttribution("cyclosm"), - code: "Y", - keyid: "cyclosm", - name: I18n.t("javascripts.map.base.cyclosm") - })); - - if (OSM.THUNDERFOREST_KEY) { - this.baseLayers.push(new L.OSM.CycleMap({ - attribution: makeAttribution("thunderforest"), - apikey: OSM.THUNDERFOREST_KEY, - code: "C", - keyid: "cyclemap", - name: I18n.t("javascripts.map.base.cycle_map") - })); - - this.baseLayers.push(new L.OSM.TransportMap({ - attribution: makeAttribution("thunderforest"), - apikey: OSM.THUNDERFOREST_KEY, - code: "T", - keyid: "transportmap", - name: I18n.t("javascripts.map.base.transport_map") - })); - } + for (const layerDefinition of OSM.LAYER_DEFINITIONS) { + if (layerDefinition.apiKeyId && !OSM[layerDefinition.apiKeyId]) continue; + + let layerConstructor = L.OSM.TileLayer; + const layerOptions = {}; + + for (const [property, value] of Object.entries(layerDefinition)) { + if (property === "credit") { + layerOptions.attribution = makeAttribution(value); + } else if (property === "nameId") { + layerOptions.name = I18n.t(`javascripts.map.base.${value}`); + } else if (property === "apiKeyId") { + layerOptions.apikey = OSM[value]; + } else if (property === "leafletOsmId") { + layerConstructor = L.OSM[value]; + } else if (property === "leafletOsmDarkId" && OSM.isDarkMap() && L.OSM[value]) { + layerConstructor = L.OSM[value]; + } else { + layerOptions[property] = value; + } + } - if (OSM.TRACESTRACK_KEY) { - this.baseLayers.push(new L.OSM.TracestrackTopo({ - attribution: makeAttribution("tracestrack"), - apikey: OSM.TRACESTRACK_KEY, - code: "P", - keyid: "tracestracktopo", - name: I18n.t("javascripts.map.base.tracestracktop_topo") - })); + const layer = new layerConstructor(layerOptions); + layer.on("add", () => { + this.fire("baselayerchange", { layer: layer }); + }); + this.baseLayers.push(layer); } - this.baseLayers.push(new L.OSM.HOT({ - attribution: makeAttribution("hotosm"), - code: "H", - keyid: "hot", - name: I18n.t("javascripts.map.base.hot") - })); - this.noteLayer = new L.FeatureGroup(); this.noteLayer.options = { code: "N" }; @@ -128,15 +56,20 @@ L.OSM.Map = L.Map.extend({ pane: "overlayPane", code: "G" }); + this.gpsLayer.on("add", () => { + this.fire("overlayadd", { layer: this.gpsLayer }); + }).on("remove", () => { + this.fire("overlayremove", { layer: this.gpsLayer }); + }); + - this.on("layeradd", function (event) { + this.on("baselayerchange", function (event) { if (this.baseLayers.indexOf(event.layer) >= 0) { this.setMaxZoom(event.layer.options.maxZoom); } }); - function makeAttribution(id) { - const layerCredit = layerCredits[id]; + function makeAttribution(credit) { let attribution = ""; attribution += I18n.t("javascripts.map.copyright_text", { @@ -146,8 +79,8 @@ L.OSM.Map = L.Map.extend({ }).prop("outerHTML") }); - attribution += layerCredit.donate ? " ♥ " : ". "; - attribution += makeCredit(layerCredit); + attribution += credit.donate ? " ♥ " : ". "; + attribution += makeCredit(credit); attribution += ". "; attribution += $("", { @@ -185,14 +118,18 @@ L.OSM.Map = L.Map.extend({ var layers = layerParam || "M", layersAdded = ""; - for (var i = this.baseLayers.length - 1; i >= 0; i--) { + for (let i = this.baseLayers.length - 1; i >= 0; i--) { + if (layers.indexOf(this.baseLayers[i].options.code) === -1) { + this.removeLayer(this.baseLayers[i]); + } + } + + for (let i = this.baseLayers.length - 1; i >= 0; i--) { if (layers.indexOf(this.baseLayers[i].options.code) >= 0) { this.addLayer(this.baseLayers[i]); layersAdded = layersAdded + this.baseLayers[i].options.code; } else if (i === 0 && layersAdded === "") { this.addLayer(this.baseLayers[i]); - } else { - this.removeLayer(this.baseLayers[i]); } } }, @@ -208,11 +145,14 @@ L.OSM.Map = L.Map.extend({ }, getMapBaseLayerId: function () { - var baseLayerId; - this.eachLayer(function (layer) { - if (layer.options && layer.options.keyid) baseLayerId = layer.options.keyid; - }); - return baseLayerId; + const layer = this.getMapBaseLayer(); + if (layer) return layer.options.layerId; + }, + + getMapBaseLayer: function () { + for (const layer of this.baseLayers) { + if (this.hasLayer(layer)) return layer; + } }, getUrl: function (marker) { @@ -342,7 +282,7 @@ L.OSM.Map = L.Map.extend({ this.removeObject(); - if (object.type === "note") { + if (object.type === "note" || object.type === "changeset") { this._objectLoader = { abort: function () {} }; @@ -350,18 +290,28 @@ L.OSM.Map = L.Map.extend({ this._object = object; this._objectLayer = L.featureGroup().addTo(this); - L.circleMarker(object.latLng, haloStyle).addTo(this._objectLayer); + if (object.type === "note") { + L.circleMarker(object.latLng, haloStyle).addTo(this._objectLayer); - if (object.icon) { - L.marker(object.latLng, { - icon: object.icon, - opacity: 1, - interactive: true - }).addTo(this._objectLayer); + if (object.icon) { + L.marker(object.latLng, { + icon: object.icon, + opacity: 1, + interactive: true + }).addTo(this._objectLayer); + } + } else if (object.type === "changeset") { + if (object.bbox) { + L.rectangle([ + [object.bbox.minlat, object.bbox.minlon], + [object.bbox.maxlat, object.bbox.maxlon] + ], changesetStyle).addTo(this._objectLayer); + } } if (callback) callback(this._objectLayer.getBounds()); - } else { // element or changeset handled by L.OSM.DataLayer + this.fire("overlayadd", { layer: this._objectLayer }); + } else { // element handled by L.OSM.DataLayer var map = this; this._objectLoader = $.ajax({ url: OSM.apiUrl(object), @@ -378,13 +328,11 @@ L.OSM.Map = L.Map.extend({ } }); - map._objectLayer.interestingNode = function (node, ways, relations) { + map._objectLayer.interestingNode = function (node, wayNodes, relationNodes) { if (object.type === "node") { return true; } else if (object.type === "relation") { - for (var i = 0; i < relations.length; i++) { - if (relations[i].members.indexOf(node) !== -1) return true; - } + return Boolean(relationNodes[node.id]); } else { return false; } @@ -394,6 +342,7 @@ L.OSM.Map = L.Map.extend({ map._objectLayer.addTo(map); if (callback) callback(map._objectLayer.getBounds()); + map.fire("overlayadd", { layer: map._objectLayer }); } }); } @@ -403,6 +352,7 @@ L.OSM.Map = L.Map.extend({ this._object = null; if (this._objectLoader) this._objectLoader.abort(); if (this._objectLayer) this.removeLayer(this._objectLayer); + this.fire("overlayremove", { layer: this._objectLayer }); }, getState: function () { @@ -454,6 +404,14 @@ L.extend(L.Icon.Default.prototype, { } }); +OSM.isDarkMap = function () { + var mapTheme = $("body").attr("data-map-theme"); + if (mapTheme) return mapTheme === "dark"; + var siteTheme = $("html").attr("data-bs-theme"); + if (siteTheme) return siteTheme === "dark"; + return window.matchMedia("(prefers-color-scheme: dark)").matches; +}; + OSM.getUserIcon = function (url) { return L.icon({ iconUrl: url || OSM.MARKER_RED,