From 9c16bbfe51ad1f55b37b7305a00514319f8c2e24 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Thu, 24 Aug 2023 20:48:24 +0200 Subject: [PATCH 1/3] Remove default center to prevent multiple map initialisations We want to init the map view once, in our initCenter method, so we remove any center from the option, to prevent Leaflet to init the map on this centers fix #1277 --- umap/static/umap/js/umap.js | 7 +++---- umap/static/umap/test/Map.Init.js | 16 ++++++++++++++++ umap/static/umap/test/_pre.js | 11 ++++++----- umap/static/umap/test/index.html | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 umap/static/umap/test/Map.Init.js diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index 282b97da..e11ef6bd 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -1,8 +1,6 @@ L.Map.mergeOptions({ overlay: null, datalayers: [], - center: [50, 4], - zoom: 6, hash: true, default_color: 'DarkBlue', default_smoothFactor: 1.0, @@ -86,11 +84,12 @@ L.U.Map.include({ geojson.properties.fullscreenControl = false L.Util.setBooleanFromQueryString(geojson.properties, 'scrollWheelZoom') - // Before calling parent initialize - if (geojson.geometry) this.options.center = this.latLng(geojson.geometry) L.Map.prototype.initialize.call(this, el, geojson.properties) + // After calling parent initialize, as we are doing initCenter our-selves + if (geojson.geometry) this.options.center = this.latLng(geojson.geometry) + this.ui = new L.U.UI(this._container) this.xhr = new L.U.Xhr(this.ui) this.xhr.on('dataloading', (e) => this.fire('dataloading', e)) diff --git a/umap/static/umap/test/Map.Init.js b/umap/static/umap/test/Map.Init.js new file mode 100644 index 00000000..5d57c626 --- /dev/null +++ b/umap/static/umap/test/Map.Init.js @@ -0,0 +1,16 @@ +describe('L.U.Map.initialize', function () { + afterEach(function () { + resetMap() + }) + + it("should not show a minimap by default", function () { + this.map = initMap() + assert.notOk(qs('.leaflet-control-minimap')) + }) + + it("should show a minimap", function () { + this.map = initMap({ miniMap: true }) + assert.ok(qs('.leaflet-control-minimap')) + }) + +}) diff --git a/umap/static/umap/test/_pre.js b/umap/static/umap/test/_pre.js index b8547fb9..b9306d36 100644 --- a/umap/static/umap/test/_pre.js +++ b/umap/static/umap/test/_pre.js @@ -107,10 +107,6 @@ var defaultDatalayerData = function (custom) { function initMap(options) { default_options = { - geometry: { - type: 'Point', - coordinates: [5.0592041015625, 52.05924589011585], - }, type: 'Feature', properties: { umap_id: 42, @@ -197,7 +193,7 @@ function initMap(options) { allowEdit: true, moreControl: true, scaleControl: true, - miniMap: true, + miniMap: false, datalayersControl: true, displayCaptionOnLoad: false, displayPopupFooter: false, @@ -205,7 +201,12 @@ function initMap(options) { }, } default_options.properties.datalayers.push(defaultDatalayerData()) + options = options || {} options.properties = L.extend({}, default_options.properties, options) + options.geometry = { + type: 'Point', + coordinates: [5.0592041015625, 52.05924589011585], + } return new L.U.Map('map', options) } diff --git a/umap/static/umap/test/index.html b/umap/static/umap/test/index.html index c3f5da40..b8ed9b10 100644 --- a/umap/static/umap/test/index.html +++ b/umap/static/umap/test/index.html @@ -67,6 +67,7 @@ + From e636ced4c65ec559f27a88b155507f70bbe3a952 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Thu, 24 Aug 2023 21:24:02 +0200 Subject: [PATCH 2/3] Set default center in case of location error at load --- umap/static/umap/js/umap.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index e11ef6bd..fe89d216 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -310,6 +310,7 @@ L.U.Map.include({ icon: 'umap-fake-class', iconLoading: 'umap-fake-class', flyTo: this.options.easing, + onLocationError: (err) => this.ui.alert({content: err.message}) }) this._controls.fullscreen = new L.Control.Fullscreen({ title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') }, @@ -632,11 +633,17 @@ L.U.Map.include({ } }, + _setDefaultCenter: function () { + this.options.center = this.latLng(this.options.center) + this.setView(this.options.center, this.options.zoom) + }, + initCenter: function () { if (this.options.hash && this._hash.parseHash(location.hash)) { // FIXME An invalid hash will cause the load to fail this._hash.update() } else if (this.options.defaultView === 'locate' && !this.options.noControl) { + this.once('locationerror', this._setDefaultCenter) this._controls.locate.start() } else if (this.options.defaultView === 'bounds') { this.onceDataLoaded(() => this.fitBounds(this.getLayersBounds())) @@ -647,8 +654,7 @@ L.U.Map.include({ if (feature) feature.zoomTo() }) } else { - this.options.center = this.latLng(this.options.center) - this.setView(this.options.center, this.options.zoom) + this._setDefaultCenter() } }, From bdbde7cfd2ba19e878f8aacdb9f9de7d0e735689 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Fri, 25 Aug 2023 09:59:02 +0200 Subject: [PATCH 3/3] Ensure default view when map as no data at load --- umap/static/umap/js/umap.forms.js | 2 +- umap/static/umap/js/umap.js | 47 +++++++++++++++++++++++-------- umap/static/umap/test/Map.Init.js | 44 ++++++++++++++++++++++++----- 3 files changed, 73 insertions(+), 20 deletions(-) diff --git a/umap/static/umap/js/umap.forms.js b/umap/static/umap/js/umap.forms.js index e3569a2d..c401d56f 100644 --- a/umap/static/umap/js/umap.forms.js +++ b/umap/static/umap/js/umap.forms.js @@ -420,7 +420,7 @@ L.FormBuilder.DataLayerSwitcher = L.FormBuilder.Select.extend({ L.FormBuilder.DefaultView = L.FormBuilder.Select.extend({ selectOptions: [ ['center', L._('Saved center and zoom')], - ['bounds', L._('Layers bounds')], + ['data', L._('Fit all data')], ['latest', L._('Latest feature')], ['locate', L._('User location')], ], diff --git a/umap/static/umap/js/umap.js b/umap/static/umap/js/umap.js index fe89d216..77c9431b 100644 --- a/umap/static/umap/js/umap.js +++ b/umap/static/umap/js/umap.js @@ -84,7 +84,6 @@ L.U.Map.include({ geojson.properties.fullscreenControl = false L.Util.setBooleanFromQueryString(geojson.properties, 'scrollWheelZoom') - L.Map.prototype.initialize.call(this, el, geojson.properties) // After calling parent initialize, as we are doing initCenter our-selves @@ -151,7 +150,8 @@ L.U.Map.include({ this.options.slideshow.active === undefined ) this.options.slideshow.active = true - if (this.options.advancedFilterKey) this.options.facetKey = this.options.advancedFilterKey + if (this.options.advancedFilterKey) + this.options.facetKey = this.options.advancedFilterKey // Global storage for retrieving datalayers and features this.datalayers = {} @@ -254,7 +254,11 @@ L.U.Map.include({ if (L.Util.queryString('share')) this.renderShareBox() else if (this.options.onLoadPanel === 'databrowser') this.openBrowser() else if (this.options.onLoadPanel === 'caption') this.displayCaption() - else if (this.options.onLoadPanel === 'facet' || this.options.onLoadPanel === 'datafilters') this.openFacet() + else if ( + this.options.onLoadPanel === 'facet' || + this.options.onLoadPanel === 'datafilters' + ) + this.openFacet() }) this.onceDataLoaded(function () { const slug = L.Util.queryString('feature') @@ -310,7 +314,7 @@ L.U.Map.include({ icon: 'umap-fake-class', iconLoading: 'umap-fake-class', flyTo: this.options.easing, - onLocationError: (err) => this.ui.alert({content: err.message}) + onLocationError: (err) => this.ui.alert({ content: err.message }), }) this._controls.fullscreen = new L.Control.Fullscreen({ title: { false: L._('View Fullscreen'), true: L._('Exit Fullscreen') }, @@ -407,7 +411,11 @@ L.U.Map.include({ if (datalayer.displayedOnLoad()) datalayer.onceDataLoaded(decrementDataToLoad) else decrementDataToLoad() } - if (seen === 0) loaded() && dataLoaded() // no datalayer + if (seen === 0) { + // no datalayer + loaded() + dataLoaded() + } }, indexDatalayers: function () { @@ -634,8 +642,14 @@ L.U.Map.include({ }, _setDefaultCenter: function () { - this.options.center = this.latLng(this.options.center) - this.setView(this.options.center, this.options.zoom) + this.options.center = this.latLng(this.options.center) + this.setView(this.options.center, this.options.zoom) + }, + + hasData: function () { + for (const datalayer of this.datalayers_index) { + if (datalayer.hasData()) return true + } }, initCenter: function () { @@ -645,10 +659,20 @@ L.U.Map.include({ } else if (this.options.defaultView === 'locate' && !this.options.noControl) { this.once('locationerror', this._setDefaultCenter) this._controls.locate.start() - } else if (this.options.defaultView === 'bounds') { - this.onceDataLoaded(() => this.fitBounds(this.getLayersBounds())) + } else if (this.options.defaultView === 'data') { + this.onceDataLoaded(() => { + if (!this.hasData()) { + this._setDefaultCenter() + return + } + this.fitBounds(this.getLayersBounds()) + }) } else if (this.options.defaultView === 'latest') { this.onceDataLoaded(() => { + if (!this.hasData()) { + this._setDefaultCenter() + return + } const datalayer = this.defaultDataLayer(), feature = datalayer.getFeatureByIndex(-1) if (feature) feature.zoomTo() @@ -1409,7 +1433,7 @@ L.U.Map.include({ handler: 'Input', helpEntries: 'facetKey', placeholder: L._('Example: key1,key2,key3'), - label: L._('Facet keys') + label: L._('Facet keys'), }, ], [ @@ -2053,7 +2077,7 @@ L.U.Map.include({ getFacetKeys: function () { return (this.options.facetKey || '').split(',').reduce((acc, curr) => { - const els = curr.split("|") + const els = curr.split('|') acc[els[0]] = els[1] || els[0] return acc }, {}) @@ -2066,5 +2090,4 @@ L.U.Map.include({ }) return bounds }, - }) diff --git a/umap/static/umap/test/Map.Init.js b/umap/static/umap/test/Map.Init.js index 5d57c626..fa10e18a 100644 --- a/umap/static/umap/test/Map.Init.js +++ b/umap/static/umap/test/Map.Init.js @@ -3,14 +3,44 @@ describe('L.U.Map.initialize', function () { resetMap() }) - it("should not show a minimap by default", function () { - this.map = initMap() - assert.notOk(qs('.leaflet-control-minimap')) + describe('Controls', function () { + it('should not show a minimap by default', function () { + this.map = initMap() + assert.notOk(qs('.leaflet-control-minimap')) + }) + + it('should show a minimap', function () { + this.map = initMap({ miniMap: true }) + assert.ok(qs('.leaflet-control-minimap')) + }) }) - it("should show a minimap", function () { - this.map = initMap({ miniMap: true }) - assert.ok(qs('.leaflet-control-minimap')) - }) + describe('DefaultView', function () { + it('should set default view in default mode without data', function (done) { + this.map = initMap({ datalayers: [] }) + // Did not find a better way to wait for tiles to be actually loaded + window.setTimeout(() => { + assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded')) + done() + }, 1000) + }) + it("should set default view in 'data' mode without data", function (done) { + this.map = initMap({ datalayers: [], defaultView: 'data' }) + // Did not find a better way to wait for tiles to be actually loaded + window.setTimeout(() => { + assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded')) + done() + }, 1000) + }) + + it("should set default view in 'latest' mode without data", function (done) { + this.map = initMap({ datalayers: [], defaultView: 'latest' }) + // Did not find a better way to wait for tiles to be actually loaded + window.setTimeout(() => { + assert.ok(qs('#map .leaflet-tile-pane img.leaflet-tile.leaflet-tile-loaded')) + done() + }, 1000) + }) + }) })