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 282b97da..77c9431b 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,11 @@ 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)) @@ -152,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 = {} @@ -255,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') @@ -311,6 +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 }), }) 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 () { @@ -633,23 +641,44 @@ L.U.Map.include({ } }, + _setDefaultCenter: function () { + 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 () { 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())) + } 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() }) } else { - this.options.center = this.latLng(this.options.center) - this.setView(this.options.center, this.options.zoom) + this._setDefaultCenter() } }, @@ -1404,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'), }, ], [ @@ -2048,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 }, {}) @@ -2061,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 new file mode 100644 index 00000000..fa10e18a --- /dev/null +++ b/umap/static/umap/test/Map.Init.js @@ -0,0 +1,46 @@ +describe('L.U.Map.initialize', function () { + afterEach(function () { + resetMap() + }) + + 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')) + }) + }) + + 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) + }) + }) +}) diff --git a/umap/static/umap/test/_pre.js b/umap/static/umap/test/_pre.js index c905eb0f..df561c5d 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 @@ +