diff --git a/dist/recline.js b/dist/recline.js index 269c1b57..ed8a7054 100644 --- a/dist/recline.js +++ b/dist/recline.js @@ -93,8 +93,11 @@ this.recline.Backend.Ckan = this.recline.Backend.Ckan || {}; var CKAN_TYPES_MAP = { 'int4': 'integer', + 'int8': 'integer', 'float8': 'float', - 'text': 'string' + 'text': 'string', + 'json': 'object', + 'timestamp': 'date' }; }(jQuery, this.recline.Backend.Ckan)); @@ -2521,12 +2524,22 @@ my.Map = Backbone.View.extend({ geomField: null, lonField: null, latField: null, - autoZoom: true + autoZoom: true, + cluster: false }, options.state ); this.state = new recline.Model.ObjectState(stateData); + this._clusterOptions = { + zoomToBoundsOnClick: true, + //disableClusteringAtZoom: 10, + maxClusterRadius: 80, + singleMarkerMode: false, + skipDuplicateAddTesting: true, + animateAddingMarkers: false + }; + // Listen to changes in the fields this.model.fields.bind('change', function() { self._setupGeometryField(); @@ -2550,6 +2563,9 @@ my.Map = Backbone.View.extend({ self.state.set(self.menu.state.toJSON()); self.redraw(); }); + this.state.bind('change', function() { + self.redraw(); + }); this.elSidebar = this.menu.el; }, @@ -2561,7 +2577,7 @@ my.Map = Backbone.View.extend({ // ### infobox // // Function to create infoboxes used in popups. The default behaviour is very simple and just lists all attributes. - // + // // Users should override this function to customize behaviour i.e. // // view = new View({...}); @@ -2614,14 +2630,34 @@ my.Map = Backbone.View.extend({ } if (this._geomReady() && this.mapReady){ - if (action == 'reset' || action == 'refresh'){ + // removing ad re-adding the layer enables faster bulk loading + this.map.removeLayer(this.features); + this.map.removeLayer(this.markers); + + var countBefore = 0; + this.features.eachLayer(function(){countBefore++;}); + + if (action == 'refresh' || action == 'reset') { this.features.clearLayers(); + // recreate cluster group because of issues with clearLayer + this.map.removeLayer(this.markers); + this.markers = new L.MarkerClusterGroup(this._clusterOptions); this._add(this.model.records.models); } else if (action == 'add' && doc){ this._add(doc); } else if (action == 'remove' && doc){ this._remove(doc); } + + // enable clustering if there is a large number of markers + var countAfter = 0; + this.features.eachLayer(function(){countAfter++;}); + var sizeIncreased = countAfter - countBefore > 0; + if (!this.state.get('cluster') && countAfter > 64 && sizeIncreased) { + this.state.set({cluster: true}); + return; + } + if (this.state.get('autoZoom')){ if (this.visible){ this._zoomToFeatures(); @@ -2629,6 +2665,11 @@ my.Map = Backbone.View.extend({ this._zoomPending = true; } } + if (this.state.get('cluster')) { + this.map.addLayer(this.markers); + } else { + this.map.addLayer(this.features); + } } }, @@ -2684,7 +2725,6 @@ my.Map = Backbone.View.extend({ try { self.features.addData(feature); - } catch (except) { wrongSoFar += 1; var msg = 'Wrong geometry value'; @@ -2703,7 +2743,7 @@ my.Map = Backbone.View.extend({ }); }, - // Private: Remove one or n features to the map + // Private: Remove one or n features from the map // _remove: function(docs){ @@ -2812,7 +2852,7 @@ my.Map = Backbone.View.extend({ // _zoomToFeatures: function(){ var bounds = this.features.getBounds(); - if (bounds.getNorthEast()){ + if (bounds && bounds.getNorthEast() && bounds.getSouthWest()){ this.map.fitBounds(bounds); } else { this.map.setView([0, 0], 2); @@ -2825,6 +2865,7 @@ my.Map = Backbone.View.extend({ // on [OpenStreetMap](http://openstreetmap.org). // _setupMap: function(){ + var self = this; this.map = new L.Map(this.$map.get(0)); var mapUrl = "http://otile{s}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png"; @@ -2832,12 +2873,16 @@ my.Map = Backbone.View.extend({ var bg = new L.TileLayer(mapUrl, {maxZoom: 18, attribution: osmAttribution ,subdomains: '1234'}); this.map.addLayer(bg); - this.features = new L.GeoJSON(null, - {onEachFeature: function(feature,layer) { - layer.bindPopup(feature.properties.popupContent); + this.markers = new L.MarkerClusterGroup(this._clusterOptions); + + this.features = new L.GeoJSON(null,{ + pointToLayer: function (feature, latlng) { + var marker = new L.marker(latlng); + marker.bindPopup(feature.properties.popupContent); + self.markers.addLayer(marker); + return marker; } - }); - this.map.addLayer(this.features); + }); this.map.setView([0, 0], 2); @@ -2910,19 +2955,23 @@ my.MapMenu = Backbone.View.extend({ \
\ \ \ \ -', + ', // Define here events for UI elements events: { 'click .editor-update-map': 'onEditorSubmit', 'change .editor-field-type': 'onFieldTypeChange', - 'click #editor-auto-zoom': 'onAutoZoomChange' + 'click #editor-auto-zoom': 'onAutoZoomChange', + 'click #editor-cluster': 'onClusteringChange' }, initialize: function(options) { @@ -2955,10 +3004,14 @@ my.MapMenu = Backbone.View.extend({ } if (this.state.get('autoZoom')) { this.el.find('#editor-auto-zoom').attr('checked', 'checked'); - } - else { + } else { this.el.find('#editor-auto-zoom').removeAttr('checked'); } + if (this.state.get('cluster')) { + this.el.find('#editor-cluster').attr('checked', 'checked'); + } else { + this.el.find('#editor-cluster').removeAttr('checked'); + } return this; }, @@ -3009,6 +3062,10 @@ my.MapMenu = Backbone.View.extend({ this.state.set({autoZoom: !this.state.get('autoZoom')}); }, + onClusteringChange: function(e){ + this.state.set({cluster: !this.state.get('cluster')}); + }, + // Private: Helper function to select an option from a select list // _selectOption: function(id,value){