diff --git a/package-lock.json b/package-lock.json index 557d3962..47608090 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,10 +18,11 @@ "leaflet-contextmenu": "^1.4.0", "leaflet-editable": "^1.2.0", "leaflet-editinosm": "0.2.3", - "leaflet-formbuilder": "0.2.7", + "leaflet-formbuilder": "0.2.9", "leaflet-fullscreen": "1.0.2", "leaflet-hash": "0.2.1", "leaflet-i18n": "0.3.3", + "leaflet-iconlayers": "^0.2.0", "leaflet-loading": "0.1.24", "leaflet-measurable": "0.1.0", "leaflet-minimap": "^3.6.1", @@ -1384,9 +1385,9 @@ "integrity": "sha1-8HFmTEpSe3b3uPm87HRLJIiVwHE=" }, "node_modules/leaflet-formbuilder": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/leaflet-formbuilder/-/leaflet-formbuilder-0.2.7.tgz", - "integrity": "sha512-5/QXEPmlSPNzl5r8rNlhcQOfI2Bx9vo/FBaBCV7o37MmZZ2jyA4aRu+6j91CnyRmKXfU5f/42E0yJva/Dwnqcw==" + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/leaflet-formbuilder/-/leaflet-formbuilder-0.2.9.tgz", + "integrity": "sha512-6akc6pqVMDqoKxTfXvurK4tfDMqnAYTxqxS8GVkOXipEXumsP9qScLFYEzhuZcMeOJ+AeKZrq8ZCsNti1syusg==" }, "node_modules/leaflet-fullscreen": { "version": "1.0.2", @@ -1406,6 +1407,19 @@ "resolved": "https://registry.npmjs.org/leaflet-i18n/-/leaflet-i18n-0.3.3.tgz", "integrity": "sha512-bl1HkR/8ZbQ9/S2x736rBQL/40P+5zSItMAW5lOpuZSrM5PK0ezsux8znug8JJQtE+2QkBBsWIngfVlGERN0AA==" }, + "node_modules/leaflet-iconlayers": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/leaflet-iconlayers/-/leaflet-iconlayers-0.2.0.tgz", + "integrity": "sha512-iSa5v+Lrovt2wLY3wQnzudatb+l7SEMUOvrmDrky2TkhUjJscrJKj8doP16xG94E2rHQaQmqxUWKGv6JNUfIOQ==", + "dependencies": { + "leaflet": "^0.7.3" + } + }, + "node_modules/leaflet-iconlayers/node_modules/leaflet": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-0.7.7.tgz", + "integrity": "sha512-H1lR7J5VxhvQJQHlW2UywtxO63zilLrnwVsDvjKeyfntffj63Ml94gCk9YPYWBkiQgxisdiA8aJ30Zoou4VhEA==" + }, "node_modules/leaflet-loading": { "version": "0.1.24", "resolved": "https://registry.npmjs.org/leaflet-loading/-/leaflet-loading-0.1.24.tgz", @@ -3584,9 +3598,9 @@ "integrity": "sha1-8HFmTEpSe3b3uPm87HRLJIiVwHE=" }, "leaflet-formbuilder": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/leaflet-formbuilder/-/leaflet-formbuilder-0.2.7.tgz", - "integrity": "sha512-5/QXEPmlSPNzl5r8rNlhcQOfI2Bx9vo/FBaBCV7o37MmZZ2jyA4aRu+6j91CnyRmKXfU5f/42E0yJva/Dwnqcw==" + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/leaflet-formbuilder/-/leaflet-formbuilder-0.2.9.tgz", + "integrity": "sha512-6akc6pqVMDqoKxTfXvurK4tfDMqnAYTxqxS8GVkOXipEXumsP9qScLFYEzhuZcMeOJ+AeKZrq8ZCsNti1syusg==" }, "leaflet-fullscreen": { "version": "1.0.2", @@ -3603,6 +3617,21 @@ "resolved": "https://registry.npmjs.org/leaflet-i18n/-/leaflet-i18n-0.3.3.tgz", "integrity": "sha512-bl1HkR/8ZbQ9/S2x736rBQL/40P+5zSItMAW5lOpuZSrM5PK0ezsux8znug8JJQtE+2QkBBsWIngfVlGERN0AA==" }, + "leaflet-iconlayers": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/leaflet-iconlayers/-/leaflet-iconlayers-0.2.0.tgz", + "integrity": "sha512-iSa5v+Lrovt2wLY3wQnzudatb+l7SEMUOvrmDrky2TkhUjJscrJKj8doP16xG94E2rHQaQmqxUWKGv6JNUfIOQ==", + "requires": { + "leaflet": "^0.7.3" + }, + "dependencies": { + "leaflet": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-0.7.7.tgz", + "integrity": "sha512-H1lR7J5VxhvQJQHlW2UywtxO63zilLrnwVsDvjKeyfntffj63Ml94gCk9YPYWBkiQgxisdiA8aJ30Zoou4VhEA==" + } + } + }, "leaflet-loading": { "version": "0.1.24", "resolved": "https://registry.npmjs.org/leaflet-loading/-/leaflet-loading-0.1.24.tgz", diff --git a/package.json b/package.json index 14288c65..bad0c918 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "leaflet-fullscreen": "1.0.2", "leaflet-hash": "0.2.1", "leaflet-i18n": "0.3.3", + "leaflet-iconlayers": "^0.2.0", "leaflet-loading": "0.1.24", "leaflet-measurable": "0.1.0", "leaflet-minimap": "^3.6.1", diff --git a/scripts/vendorsjs.sh b/scripts/vendorsjs.sh index 793fbeb5..07c33cd7 100755 --- a/scripts/vendorsjs.sh +++ b/scripts/vendorsjs.sh @@ -28,5 +28,6 @@ mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.l mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/purify.js umap/static/umap/vendors/dompurify/ mkdir -p umap/static/umap/vendors/colorbrewer/ && cp node_modules/colorbrewer/index.js umap/static/umap/vendors/colorbrewer/colorbrewer.js mkdir -p umap/static/umap/vendors/simple-statistics/ && cp node_modules/simple-statistics/dist/simple-statistics.min.js umap/static/umap/vendors/simple-statistics/ +mkdir -p umap/static/umap/vendors/iconlayers/ && cp node_modules/leaflet-iconlayers/dist/* umap/static/umap/vendors/iconlayers/ echo 'Done!' diff --git a/umap/static/umap/js/umap.controls.js b/umap/static/umap/js/umap.controls.js index c2bd29df..67baa3dc 100644 --- a/umap/static/umap/js/umap.controls.js +++ b/umap/static/umap/js/umap.controls.js @@ -1178,7 +1178,28 @@ L.U.Map.include({ }, }) -L.U.TileLayerControl = L.Control.extend({ +/* Used in view mode to define the current tilelayer */ +L.U.TileLayerControl = L.Control.IconLayers.extend({ + initialize: function (map, options) { + const layers = [] + map.eachTileLayer((layer) => { + layers.push({ + title: layer.options.name, + layer: layer, + icon: L.Util.template(layer.options.url_template, map.demoTileInfos), + }) + }) + const maxShown = 10 + L.Control.IconLayers.prototype.initialize.call(this, layers.slice(0, maxShown), { + position: 'topleft', + manageLayers: false + }) + this.on('activelayerchange', (e) => map.selectTileLayer(e.layer)) + }, +}) + +/* Used in edit mode to define the default tilelayer */ +L.U.TileLayerChooser = L.Control.extend({ options: { position: 'topleft', }, diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index f4149bd2..159328ee 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -60,8 +60,8 @@ L.U.Map.include({ 'measure', 'editinosm', 'datalayers', - 'tilelayers', 'star', + 'tilelayers', ], initialize: function (el, geojson) { @@ -326,7 +326,7 @@ L.U.Map.include({ }) this._controls.search = new L.U.SearchControl() this._controls.embed = new L.Control.Embed(this, this.options.embedOptions) - this._controls.tilelayers = new L.U.TileLayerControl(this) + this._controls.tilelayersChooser = new L.U.TileLayerChooser(this) this._controls.star = new L.U.StarControl(this) this._controls.editinosm = new L.Control.EditInOSM({ position: 'topleft', @@ -345,6 +345,8 @@ L.U.Map.include({ this.browser = new L.U.Browser(this) this.importer = new L.U.Importer(this) this.drop = new L.U.DropControl(this) + this._controls.tilelayers = new L.U.TileLayerControl(this) + this.renderControls() }, @@ -581,17 +583,15 @@ L.U.Map.include({ initTileLayers: function () { this.tilelayers = [] - for (const i in this.options.tilelayers) { - if (this.options.tilelayers.hasOwnProperty(i)) { - this.tilelayers.push(this.createTileLayer(this.options.tilelayers[i])) - if ( - this.options.tilelayer && - this.options.tilelayer.url_template === - this.options.tilelayers[i].url_template - ) { - // Keep control over the displayed attribution for non custom tilelayers - this.options.tilelayer.attribution = this.options.tilelayers[i].attribution - } + for (const props of this.options.tilelayers) { + let layer = this.createTileLayer(props) + this.tilelayers.push(layer) + if ( + this.options.tilelayer && + this.options.tilelayer.url_template === props.url_template + ) { + // Keep control over the displayed attribution for non custom tilelayers + this.options.tilelayer.attribution = props.attribution } } if ( @@ -646,21 +646,9 @@ L.U.Map.include({ this.setOverlay() }, - eachTileLayer: function (method, context) { - const urls = [] - for (const i in this.tilelayers) { - if (this.tilelayers.hasOwnProperty(i)) { - method.call(context, this.tilelayers[i]) - urls.push(this.tilelayers[i]._url) - } - } - if ( - this.customTilelayer && - Array.prototype.indexOf && - urls.indexOf(this.customTilelayer._url) === -1 - ) { - method.call(context || this, this.customTilelayer) - } + eachTileLayer: function (callback, context) { + if (this.customTilelayer) callback.call(context, this.customTilelayer) + this.tilelayers.forEach((layer) => callback.call(context, layer)) }, setOverlay: function () { @@ -816,8 +804,8 @@ L.U.Map.include({ self.options.tilelayer = tilelayer.toJSON() self.isDirty = true } - if (this._controls.tilelayers) - this._controls.tilelayers.openSwitcher({ callback: callback, className: 'dark' }) + if (this._controls.tilelayersChooser) + this._controls.tilelayersChooser.openSwitcher({ callback: callback, className: 'dark' }) }, manageDatalayers: function () { diff --git a/umap/static/umap/map.css b/umap/static/umap/map.css index 1cdf7412..4c14bfc6 100644 --- a/umap/static/umap/map.css +++ b/umap/static/umap/map.css @@ -161,6 +161,29 @@ background-image: url('./img/16.svg'); background-position: 0px 0px; } +.leaflet-iconLayers-layer { + width: 38px; + height: 38px; + box-shadow: none; + border: 1px solid #bbb; + border-radius: 4px; +} +.leaflet-iconLayers-layerTitleContainer { + display: none; + left: 0; + overflow: hidden; +} +.leaflet-iconLayers-layerTitle { + text-align: center; + display: inline-block; +} +.leaflet-iconLayers:hover .leaflet-iconLayers-layer { + width: 80px; + height: 80px; +} +.leaflet-iconLayers:hover .leaflet-iconLayers-layerTitleContainer { + display: initial; +} diff --git a/umap/static/umap/test/index.html b/umap/static/umap/test/index.html index 4f11268b..bc371d16 100644 --- a/umap/static/umap/test/index.html +++ b/umap/static/umap/test/index.html @@ -21,6 +21,7 @@ + @@ -52,6 +53,7 @@ + diff --git a/umap/templates/umap/css.html b/umap/templates/umap/css.html index e6bd3627..120ff967 100644 --- a/umap/templates/umap/css.html +++ b/umap/templates/umap/css.html @@ -18,6 +18,8 @@ href="{{ STATIC_URL }}umap/vendors/fullscreen/leaflet.fullscreen.css" /> + diff --git a/umap/templates/umap/js.html b/umap/templates/umap/js.html index 6a5b29af..131c1a02 100644 --- a/umap/templates/umap/js.html +++ b/umap/templates/umap/js.html @@ -20,6 +20,7 @@ +