diff --git a/README.md b/README.md
index fd524ce..d33f80b 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@
A [Galette](https://galette.eu) plugin to geolocalize members.
Map display uses [Leaflet project](https://leafletjs.com/) while search is provided by [Nominatim](https://nominatim.openstreetmap.org/) API.
+Background tiles are the [OpenFreeMap](https://openfreemap.org/) vector tiles, rendered with [MapLibre GL](https://maplibre.org/): no API key, no registration, and the whole thing can be self-hosted.
* website: https://galette.eu - https://doc.galette.eu/en/master/plugins/maps.html
* bugs and features: http://bugs.galette.eu/projects/galette-plugin-maps
@@ -25,6 +26,7 @@ To use Galette Maps plugin, you'll need a reliable Galette version, and of cours
Un plugin [Galette](https://galette.eu) pour gérer paiments de cotisation et de dons via Maps.
Les cartes sont affichées par le biais du [projet Leaflet](https://leafletjs.com/) tandis que la recherche est assurée par l'API [Nominatim](https://nominatim.openstreetmap.org/).
+Le fond de carte provient des tuiles vectorielles [OpenFreeMap](https://openfreemap.org/), rendues par [MapLibre GL](https://maplibre.org/) : sans clé d'API, sans inscription, et auto-hébergeable.
* site web : https://galette.eu - https://doc.galette.eu/fr/master/plugins/maps.html
* bogues et fonctionnalités : http://bugs.galette.eu/projects/galette-plugin-maps
diff --git a/README.tiles.md b/README.tiles.md
new file mode 100644
index 0000000..5da5ac6
--- /dev/null
+++ b/README.tiles.md
@@ -0,0 +1,145 @@
+# Quick fix — "API KEY REQUIRED" tiles
+
+## Symptom
+
+Every map in the plugin shows the **"API KEY REQUIRED —
+carto.com/basemaps/apikey"** watermark across the tiles.
+
+## Cause
+
+The background map comes from CARTO (`basemaps.cartocdn.com`), which now
+requires an API key for its basemaps.
+
+## Fix
+
+A single file to edit:
+
+```
+galette/plugins/plugin-maps/templates/default/common_scripts.html.twig
+```
+
+### The diff
+
+```diff
+--- a/templates/default/common_scripts.html.twig
++++ b/templates/default/common_scripts.html.twig
+@@ -132,9 +132,9 @@
+ }).addTo(map);
+ {% endif %}
+
+- L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
+- maxZoom: 18,
+- attribution: '{{ _T("Map data (c)", "maps")|e("js") }} {{ _T("OpenStreetMap contributors", "maps")|e("js") }}, {{ _T("Imagery (c)", "maps")|e("js") }} CartoDB'
++ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
++ maxZoom: 19,
++ attribution: '{{ _T("Map data (c)", "maps")|e("js") }} {{ _T("OpenStreetMap contributors", "maps")|e("js") }}'
+ }).addTo(map);
+
+ try {
+```
+
+Copy the diff above into a file (`tiles-quickfix.diff` for example) at plugin top directory, and apply it from there with:
+
+```
+patch -p1 < tiles-quickfix.diff
+```
+
+### Clearing the Twig cache — mandatory
+
+**Without this step, the change has no effect**: Galette serves compiled
+templates and does not notice that a `.twig` file has changed.
+
+Back at Galette top directory:
+
+```
+rm -rf galette/data/cache/*/templates/
+```
+
+The directory usually belongs to the web server user (`www-data`, `apache`), so
+the command has to be run as `root` or through `sudo`. It is rebuilt on its own
+on the next visit; neither a restart nor a reload of the web server is needed.
+
+## Other possible background maps
+
+Every URL below has been tested and answers without an API key. The
+`attribution` block is **mandatory**: keeping it is not a formality, it is the
+condition of the data licence.
+
+### OpenStreetMap — the standard rendering
+
+The one used in the fix above. The simplest, the best known. It renders in
+colour, where CARTO `light_all` was light grey: the Galette markers stand out
+slightly less.
+
+```js
+L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ maxZoom: 19,
+ attribution: '© OpenStreetMap'
+}).addTo(map);
+```
+
+Worth knowing: the OSMF usage policy does cover low traffic sites — which an
+association's Galette instance is — but explicitly asks *not* to hardcode the
+tile URL in distributed software. Which is exactly the trap CARTO has just
+sprung on us.
+
+### OpenStreetMap France
+
+Servers of the OSM-FR association, French rendering, one more zoom level.
+
+```js
+L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
+ maxZoom: 20,
+ subdomains: 'abc',
+ attribution: '© OpenStreetMap — OSM-FR tiles'
+}).addTo(map);
+```
+
+### Humanitarian OSM Team
+
+Same host as OSM-FR, more contrasted style, roads and facilities are very
+readable.
+
+```js
+L.tileLayer('https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
+ maxZoom: 20,
+ subdomains: 'abc',
+ attribution: '© OpenStreetMap — HOT tiles'
+}).addTo(map);
+```
+
+### OpenStreetMap.de
+
+German rendering, local names favoured. Beware, it stops at zoom 18: beyond
+that the server answers a 404 (checked).
+
+```js
+L.tileLayer('https://tile.openstreetmap.de/{z}/{x}/{y}.png', {
+ maxZoom: 18,
+ attribution: '© OpenStreetMap'
+}).addTo(map);
+```
+
+### Esri World Light Gray Base
+
+Visually the closest to what the plugin used to display: very light grey, almost
+without colour, the markers stand out perfectly. Note the unusual `{z}/{y}/{x}`
+order, and the JPEG format.
+
+```js
+L.tileLayer('https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}', {
+ maxZoom: 16,
+ attribution: 'Tiles © Esri — Esri, DeLorme, NAVTEQ'
+}).addTo(map);
+```
+
+One reservation: this is a commercial vendor's courtesy service, with no
+availability commitment. Nothing guarantees it will not do tomorrow what CARTO
+has just done.
+
+### Staying on CARTO
+
+That is possible, but it now means opening an account on
+ and adding the key to the URL. The exact form of
+the URL with a key is given by their interface — we do not reproduce it here, it
+is specific to each account.
diff --git a/gulpfile.js b/gulpfile.js
index 81d232d..5b11870 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -37,6 +37,19 @@ const main_scripts = [
'./node_modules/leaflet-legend/leaflet-legend.js'
];
+const gl_styles = [
+ './node_modules/maplibre-gl/dist/maplibre-gl.css'
+];
+
+// maplibre-gl is pinned to 5.x on purpose: 6.x dropped the UMD build and ships
+// ES modules only, which cannot be concatenated into a classic script. The 5.x
+// dist is already minified and uses syntax uglify-js cannot parse, so this
+// bundle is concatenated as is, never piped through uglify.
+const gl_scripts = [
+ './node_modules/maplibre-gl/dist/maplibre-gl.js',
+ './node_modules/@maplibre/maplibre-gl-leaflet/leaflet-maplibre-gl.js'
+];
+
const main_assets = [
{
'src': './node_modules/leaflet/dist/images/*',
@@ -81,7 +94,12 @@ function styles() {
.pipe(concat('maps-locate.bundle.min.css'))
.pipe(gulp.dest(plugin.public));
- return merge(main, locate);
+ gl = gulp.src(gl_styles)
+ .pipe(cleancss())
+ .pipe(concat('maps-gl.bundle.min.css'))
+ .pipe(gulp.dest(plugin.public));
+
+ return merge(main, locate, gl);
};
function scripts() {
@@ -97,7 +115,11 @@ function scripts() {
.pipe(uglify())
.pipe(gulp.dest(plugin.public));
- return merge(main, locate);
+ gl = gulp.src(gl_scripts)
+ .pipe(concat('maps-gl.bundle.min.js'))
+ .pipe(gulp.dest(plugin.public));
+
+ return merge(main, locate, gl);
};
function assets() {
diff --git a/package-lock.json b/package-lock.json
index 4661b41..17df4fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,13 +9,15 @@
"version": "2.0.0",
"license": "GPL-3.0-or-later",
"dependencies": {
+ "@maplibre/maplibre-gl-leaflet": "^0.1.4",
"leaflet": "^1.8.0",
"leaflet-control-geocoder": "^4.0.0",
"leaflet-gesture-handling": "^1.2.2",
"leaflet-legend": "^1.0.2",
"leaflet.fullscreen": "^5.3.3",
"leaflet.locatecontrol": "^0.90.1",
- "leaflet.markercluster": "^1.5.3"
+ "leaflet.markercluster": "^1.5.3",
+ "maplibre-gl": "^5.24.0"
},
"devDependencies": {
"del": "^6.1.1",
@@ -50,6 +52,130 @@
"node": ">=10.13.0"
}
},
+ "node_modules/@mapbox/jsonlint-lines-primitives": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.3.tgz",
+ "integrity": "sha512-0SElaV0uMxEnxzBhhX9WTuPyUeMsAN/SS0i16tjuba4/mio63MG9khjC1a0JAiPGXAwvwm4UfHJURCN7nyudQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 22"
+ }
+ },
+ "node_modules/@mapbox/point-geometry": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-1.1.0.tgz",
+ "integrity": "sha512-YGcBz1cg4ATXDCM/71L9xveh4dynfGmcLDqufR+nQQy3fKwsAZsWd/x4621/6uJaeB9mwOHE6hPeDgXz9uViUQ==",
+ "license": "ISC"
+ },
+ "node_modules/@mapbox/tiny-sdf": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.2.0.tgz",
+ "integrity": "sha512-LVL4wgI9YAum5V+LNVQO6QgFBPw7/MIIY4XJPNsPDMrjEwcE+JfKk1LuIl8GnF197ejVdC9QdPaxrx5gfgdGXg==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/@mapbox/unitbezier": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz",
+ "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/@mapbox/vector-tile": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@mapbox/vector-tile/-/vector-tile-2.0.5.tgz",
+ "integrity": "sha512-pXj8m7KTsqZt+1jsE0xIpGvqTSbblfkuEJL/NJmNePMtEwxO8V3XMDo9WMSfDeqHvCtBI9Lmt4mGcGR10zecmw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@mapbox/point-geometry": "~1.1.0",
+ "@types/geojson": "^7946.0.16",
+ "pbf": "^4.0.2"
+ }
+ },
+ "node_modules/@mapbox/vector-tile/node_modules/pbf": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.2.tgz",
+ "integrity": "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "resolve-protobuf-schema": "^2.1.0"
+ },
+ "bin": {
+ "pbf": "bin/pbf"
+ }
+ },
+ "node_modules/@mapbox/whoots-js": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz",
+ "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@maplibre/geojson-vt": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/@maplibre/geojson-vt/-/geojson-vt-6.1.1.tgz",
+ "integrity": "sha512-FVMOcmSP/yqol45t7StApEyTL5/vmqBCuFhH9n+fFuINenhaX+YgHHIt1yJ86S8kln3uJLcMvmEU2cfn6E2eCQ==",
+ "license": "ISC",
+ "dependencies": {
+ "kdbush": "^4.1.0"
+ }
+ },
+ "node_modules/@maplibre/maplibre-gl-leaflet": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-leaflet/-/maplibre-gl-leaflet-0.1.4.tgz",
+ "integrity": "sha512-k57wcndZIvq3m08g2je4pjUPGr43ffNW3j+gXbymt8Vi2l1lUERUi1UmdTZcTPN8LuDDYOMWRNBaSLwpAu02ew==",
+ "license": "ISC",
+ "peerDependencies": {
+ "@types/leaflet": "^1.9.0",
+ "leaflet": "^1.9.3",
+ "maplibre-gl": "^2.4.0 || ^3.3.1 || ^4.3.2 || ^5.0.0 || ^6.0.0"
+ }
+ },
+ "node_modules/@maplibre/maplibre-gl-style-spec": {
+ "version": "24.10.0",
+ "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-24.10.0.tgz",
+ "integrity": "sha512-lichxSiagMEBBrqHF0trtMQH9RKh+9jUlIJl0qW0QHvt2H/tbvUWdE+ZzI2Jd0/pT7j/iavLonlPu7EQ/ixTOw==",
+ "license": "ISC",
+ "dependencies": {
+ "@mapbox/jsonlint-lines-primitives": "~2.0.2",
+ "@mapbox/unitbezier": "^1.0.0",
+ "json-stringify-pretty-compact": "^4.0.0",
+ "minimist": "^1.2.8",
+ "quickselect": "^3.0.0",
+ "tinyqueue": "^3.0.0"
+ },
+ "bin": {
+ "gl-style-format": "dist/gl-style-format.mjs",
+ "gl-style-migrate": "dist/gl-style-migrate.mjs",
+ "gl-style-validate": "dist/gl-style-validate.mjs"
+ }
+ },
+ "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-1.0.0.tgz",
+ "integrity": "sha512-fqd515fjBmANKGGsQ286E2Wvj/XvDFpGzwJxq4CI6jMQue6Oy04uCKp+JWKF00xRTmk6cEu1jPJ9p3xqH8YWqQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/@maplibre/mlt": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@maplibre/mlt/-/mlt-1.2.0.tgz",
+ "integrity": "sha512-g45M8gEI4sMO3X9ib4K7n3ZKFf0qQOL+NMkHCnEK51lOrYFHiEssOuZncx1+miIgi1IEE2NcbRMcq8RBkL+QHA==",
+ "license": "(MIT OR Apache-2.0)",
+ "dependencies": {
+ "@mapbox/point-geometry": "^1.1.0"
+ }
+ },
+ "node_modules/@maplibre/vt-pbf": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/@maplibre/vt-pbf/-/vt-pbf-4.3.2.tgz",
+ "integrity": "sha512-j6p0AdjvAR19Z3XaCysle7A4ZSo08tYOzxD0Y9NQylwPAkwJJeYub5b2eVucdeDh7erhv69DahoLOevDRERRUw==",
+ "license": "MIT",
+ "dependencies": {
+ "@mapbox/point-geometry": "^1.1.0",
+ "@types/geojson": "^7946.0.16",
+ "pbf": "^5.1.0"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -95,6 +221,22 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/geojson": {
+ "version": "7946.0.16",
+ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz",
+ "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/leaflet": {
+ "version": "1.9.22",
+ "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.22.tgz",
+ "integrity": "sha512-h3lhECYEKDasG7LFHu+GiHqAvsgLuQvlJvVZzJDGONo3sEL+wUOqSFLnwkZlK0qVxnxbuGFW8iBlJNYs5wgndA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/geojson": "*"
+ }
+ },
"node_modules/@types/node": {
"version": "24.10.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
@@ -697,6 +839,12 @@
"node": ">= 10.13.0"
}
},
+ "node_modules/earcut": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.2.3.tgz",
+ "integrity": "sha512-vnS4AVwp1KHAF13i1vp1/2D5evWy3k5u/iW/B81QVsUZtV8cv2tU0b2VNFlqvh4kYwrFMDdjPCfAmfyJW9y14Q==",
+ "license": "ISC"
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -953,6 +1101,12 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/gl-matrix": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/gl-matrix/-/gl-matrix-3.4.4.tgz",
+ "integrity": "sha512-latSnyDNt/8zYUB6VIJ6PCh2jBjJX6gnDsoCZ7LyW7GkqrD51EWwa9qCoGixj8YqBtETQK/xY7OmpTF8xz1DdQ==",
+ "license": "MIT"
+ },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@@ -1681,6 +1835,18 @@
"url": "https://bevry.me/fund"
}
},
+ "node_modules/json-stringify-pretty-compact": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz",
+ "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==",
+ "license": "MIT"
+ },
+ "node_modules/kdbush": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.1.0.tgz",
+ "integrity": "sha512-e9vurzrXJQrFX6ckpHP3bvj5l+9CnYzkxDNnNQ1h2QTqdWsUAJgXiKdGNcOa1EY85dU8KbQ+z/FdQdB7P+9yfQ==",
+ "license": "ISC"
+ },
"node_modules/last-run": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz",
@@ -1812,6 +1978,52 @@
"node": ">=0.10.0"
}
},
+ "node_modules/maplibre-gl": {
+ "version": "5.24.0",
+ "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-5.24.0.tgz",
+ "integrity": "sha512-ALyFxgtd5R+65UqZ/++lOqwWcC0SNho9c27fYSyLmG7AfnAul2o46F05aDJGPbFU57wos9dgcIySHs0Xe6ia3A==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@mapbox/jsonlint-lines-primitives": "^2.0.2",
+ "@mapbox/point-geometry": "^1.1.0",
+ "@mapbox/tiny-sdf": "^2.1.0",
+ "@mapbox/unitbezier": "^0.0.1",
+ "@mapbox/vector-tile": "^2.0.4",
+ "@mapbox/whoots-js": "^3.1.0",
+ "@maplibre/geojson-vt": "^6.1.0",
+ "@maplibre/maplibre-gl-style-spec": "^24.8.1",
+ "@maplibre/mlt": "^1.1.8",
+ "@maplibre/vt-pbf": "^4.3.0",
+ "@types/geojson": "^7946.0.16",
+ "earcut": "^3.0.2",
+ "gl-matrix": "^3.4.4",
+ "kdbush": "^4.0.2",
+ "murmurhash-js": "^1.0.0",
+ "pbf": "^4.0.1",
+ "potpack": "^2.1.0",
+ "quickselect": "^3.0.0",
+ "tinyqueue": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.14.0",
+ "npm": ">=8.1.0"
+ },
+ "funding": {
+ "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1"
+ }
+ },
+ "node_modules/maplibre-gl/node_modules/pbf": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.2.tgz",
+ "integrity": "sha512-J0ajxARhZfpUEebxYs1vhMGMuLSXtBe1e+fFPDrf2uA2hgo+UshKfNUWOz92HJNz6/NFEXseQPddnHkTreWRqg==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "resolve-protobuf-schema": "^2.1.0"
+ },
+ "bin": {
+ "pbf": "bin/pbf"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -1849,6 +2061,21 @@
"node": "*"
}
},
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/murmurhash-js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/murmurhash-js/-/murmurhash-js-1.0.0.tgz",
+ "integrity": "sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==",
+ "license": "MIT"
+ },
"node_modules/mute-stdout": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz",
@@ -2042,6 +2269,18 @@
"node": ">=8"
}
},
+ "node_modules/pbf": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/pbf/-/pbf-5.1.2.tgz",
+ "integrity": "sha512-mnvGdvOrIvJOBGUEdGkrVXjN8E/VkIJCkf2eS1DH2yv82ORUlLttmDt0rWY38yYZmVwciZwBUvHM20qxBZf40w==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "resolve-protobuf-schema": "^2.1.0"
+ },
+ "bin": {
+ "pbf": "bin/pbf"
+ }
+ },
"node_modules/picomatch": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
@@ -2111,6 +2350,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/potpack": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.1.0.tgz",
+ "integrity": "sha512-pcaShQc1Shq0y+E7GqJqvZj8DTthWV1KeHGdi0Z6IAin2Oi3JnLCOfwnCo84qc+HAp52wT9nK9H7FAJp5a44GQ==",
+ "license": "ISC"
+ },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -2118,6 +2363,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/protocol-buffers-schema": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.1.tgz",
+ "integrity": "sha512-VG2K63Igkiv9p76tk1lilczEK1cT+kCjKtkdhw1dQZV3k3IXJbd3o6Ho8b9zJZaHSnT2hKe4I+ObmX9w6m5SmQ==",
+ "license": "MIT"
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -2139,6 +2390,12 @@
],
"license": "MIT"
},
+ "node_modules/quickselect": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
+ "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
+ "license": "ISC"
+ },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
@@ -2285,6 +2542,15 @@
"node": ">= 10.13.0"
}
},
+ "node_modules/resolve-protobuf-schema": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
+ "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
+ "license": "MIT",
+ "dependencies": {
+ "protocol-buffers-schema": "^3.3.1"
+ }
+ },
"node_modules/reusify": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
@@ -2572,6 +2838,12 @@
"readable-stream": "2 || 3"
}
},
+ "node_modules/tinyqueue": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz",
+ "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==",
+ "license": "ISC"
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
diff --git a/package.json b/package.json
index 0c15a79..04979ed 100644
--- a/package.json
+++ b/package.json
@@ -23,12 +23,14 @@
"ordered-read-streams": "^2.0.0"
},
"dependencies": {
+ "@maplibre/maplibre-gl-leaflet": "^0.1.4",
"leaflet": "^1.8.0",
"leaflet-control-geocoder": "^4.0.0",
"leaflet-gesture-handling": "^1.2.2",
"leaflet-legend": "^1.0.2",
"leaflet.fullscreen": "^5.3.3",
"leaflet.locatecontrol": "^0.90.1",
- "leaflet.markercluster": "^1.5.3"
+ "leaflet.markercluster": "^1.5.3",
+ "maplibre-gl": "^5.24.0"
}
}
diff --git a/templates/default/common_scripts.html.twig b/templates/default/common_scripts.html.twig
index 2cf662b..9477c91 100644
--- a/templates/default/common_scripts.html.twig
+++ b/templates/default/common_scripts.html.twig
@@ -6,6 +6,7 @@
{% if cur_route starts with 'maps_' %}
+
{% endif %}
{% if cur_route == 'maps_localize_member' or cur_route == 'maps_mymap' %}
@@ -30,6 +31,17 @@
shadowSize: [41, 41]
});
+ /**
+ * Vector tiles need WebGL 2; without it we fall back to raster tiles
+ */
+ function _hasWebGL2(){
+ try {
+ return !!(window.WebGL2RenderingContext && document.createElement('canvas').getContext('webgl2'));
+ } catch (err) {
+ return false;
+ }
+ }
+
{% if cur_route != 'maps_map' %}
function _iLiveHere(_id){
$('#' + _id).click(function(e, f,g){
@@ -77,7 +89,8 @@
var _lon = {% if town is defined %}{{ town['longitude'] }}{% else %}2.4609375{% endif %};
var map = L.map(
'map', {
- gestureHandling: true
+ gestureHandling: true,
+ maxZoom: 19
}
).setView([_lat, _lon], {% if town is defined %}12{% else %}6{% endif %});
@@ -118,10 +131,17 @@
}).addTo(map);
{% endif %}
- L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
- maxZoom: 18,
- attribution: '{{ _T("Map data (c)", "maps")|e("js") }} {{ _T("OpenStreetMap contributors", "maps")|e("js") }}, {{ _T("Imagery (c)", "maps")|e("js") }} CartoDB'
- }).addTo(map);
+ if (_hasWebGL2()) {
+ {# Attribution comes from the style sources, the Leaflet control picks it up on load #}
+ L.maplibreGL({
+ style: 'https://tiles.openfreemap.org/styles/positron'
+ }).addTo(map);
+ } else {
+ L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ maxZoom: 19,
+ attribution: '{{ _T("Map data (c)", "maps")|e("js") }} {{ _T("OpenStreetMap contributors", "maps")|e("js") }}'
+ }).addTo(map);
+ }
try {
_mapsBinded(map);
diff --git a/templates/default/headers.html.twig b/templates/default/headers.html.twig
index 3cde5d6..c22873c 100644
--- a/templates/default/headers.html.twig
+++ b/templates/default/headers.html.twig
@@ -6,6 +6,7 @@
{% if cur_route starts with 'maps_' %}
+
{% endif %}
{% if cur_route == 'maps_localize_member' or cur_route == 'maps_mymap' %}