diff --git a/arches/app/media/css/arches.css b/arches/app/media/css/arches.css index 0c8d4a254eb..14f26fb3f07 100644 --- a/arches/app/media/css/arches.css +++ b/arches/app/media/css/arches.css @@ -1175,6 +1175,10 @@ ul.tabbed-report-tab-list { margin-top: -30px; } +.mouse-pointer canvas { + cursor: pointer; +} + .map-card-wrapper { flex: 1; height: 100%; @@ -1390,14 +1394,19 @@ ul.tabbed-report-tab-list { .map-card-feature-list .table { margin-bottom: 0; } - .map-card-feature-tool { - font-size: 0.9em; width: 65px; } -.map-card-feature-tool a { +.map-card-zoom-tool, .map-card-feature-tool { + font-size: 0.9em; +} +.map-card-zoom-tool a, .map-card-feature-tool a { color: #2f527a; } +.map-card-zoom-tool { + float: right; + padding: 10px; +} #map-settings { position: relative; diff --git a/arches/app/media/js/views/components/cards/map.js b/arches/app/media/js/views/components/cards/map.js index 58413888c10..72b2f631d3b 100644 --- a/arches/app/media/js/views/components/cards/map.js +++ b/arches/app/media/js/views/components/cards/map.js @@ -3,68 +3,49 @@ define([ 'knockout', 'knockout-mapping', 'uuid', + 'mapbox-gl', 'mapbox-gl-draw', + 'geojson-extent', 'viewmodels/card-component', 'views/components/map', 'bindings/chosen' -], function(_, ko, koMapping, uuid, MapboxDraw, CardComponentViewModel, MapComponentViewModel) { +], function(_, ko, koMapping, uuid, mapboxgl, MapboxDraw, geojsonExtent, CardComponentViewModel, MapComponentViewModel) { return ko.components.register('map-card', { viewModel: function(params) { var self = this; + var widgets = []; + var drawFeatures; + var newNodeId; + this.featureLookup = {}; + this.selectedFeatureIds = ko.observableArray(); + this.draw = null; CardComponentViewModel.apply(this, [params]); - MapComponentViewModel.apply(this, [params]); - this.activeTab('editor'); - this.featureLookup = {}; - var getDrawFeatures = function() { - var drawFeatures = []; - self.card.widgets().forEach(function(widget) { - var nodeId = widget.node_id(); - if (self.form && self.form.nodeLookup[nodeId].datatype() === 'geojson-feature-collection' && self.tile) { - var featureCollection = koMapping.toJS(self.tile.data[nodeId]); - if (featureCollection) { - featureCollection.features.forEach(function(feature) { - if (!feature.id) { - feature.id = uuid.generate(); - } - feature.properties.nodeId = nodeId; - }); - drawFeatures = drawFeatures.concat(featureCollection.features); - } - } - }); - return drawFeatures; - }; - var drawFeatures = getDrawFeatures(); - var newNodeId; - this.card.widgets().forEach(function(widget) { - var nodeId = widget.node_id(); - if (self.form && self.form.nodeLookup[nodeId].datatype() === 'geojson-feature-collection') { - self.featureLookup[nodeId] = { + if (self.form && self.tile) self.card.widgets().forEach(function(widget) { + var id = widget.node_id(); + var type = self.form.nodeLookup[id].datatype(); + if (type === 'geojson-feature-collection') { + widgets.push(widget); + self.featureLookup[id] = { features: ko.computed(function() { - var features = []; - if (self.tile) { - var featureCollection = koMapping.toJS(self.tile.data[nodeId]); - if (featureCollection) { - features = featureCollection.features; - } - } - return features; + var value = koMapping.toJS(self.tile.data[id]); + if (value) return value.features; + else return []; }), selectedTool: ko.observable() }; - self.featureLookup[nodeId].selectedTool.subscribe(function(selectedTool) { + self.featureLookup[id].selectedTool.subscribe(function(selectedTool) { if (self.draw) { if (selectedTool === '') { self.draw.changeMode('simple_select'); } else if (selectedTool) { _.each(self.featureLookup, function(value, key) { - if (key !== nodeId) { + if (key !== id) { value.selectedTool(null); } }); - newNodeId = nodeId; + newNodeId = id; self.draw.changeMode(selectedTool); } } @@ -72,34 +53,62 @@ define([ } }); - var updateFeatures = function() { + var updateTiles = function() { var featureCollection = self.draw.getAll(); _.each(self.featureLookup, function(value) { value.selectedTool(null); }); - self.card.widgets().forEach(function(widget) { - var nodeId = widget.node_id(); - if (self.form && self.form.nodeLookup[nodeId].datatype() === 'geojson-feature-collection') { - var nodeFeatures = []; - featureCollection.features.forEach(function(feature){ - if (feature.properties.nodeId === nodeId) nodeFeatures.push(feature); + widgets.forEach(function(widget) { + var id = widget.node_id(); + var features = []; + featureCollection.features.forEach(function(feature){ + if (feature.properties.nodeId === id) features.push(feature); + }); + if (ko.isObservable(self.tile.data[id])) { + self.tile.data[id]({ + type: 'FeatureCollection', + features: features }); - if (ko.isObservable(self.tile.data[nodeId])) { - self.tile.data[nodeId]({ - type: 'FeatureCollection', - features: nodeFeatures - }); - } else { - self.tile.data[nodeId].features(nodeFeatures); - } + } else { + self.tile.data[id].features(features); + } + }); + }; + + var getDrawFeatures = function() { + var drawFeatures = []; + widgets.forEach(function(widget) { + var id = widget.node_id(); + var featureCollection = koMapping.toJS(self.tile.data[id]); + if (featureCollection) { + featureCollection.features.forEach(function(feature) { + if (!feature.id) { + feature.id = uuid.generate(); + } + feature.properties.nodeId = id; + }); + drawFeatures = drawFeatures.concat(featureCollection.features); } }); + return drawFeatures; }; + drawFeatures = getDrawFeatures(); + + if (drawFeatures.length > 0) { + params.bounds = geojsonExtent({ + type: 'FeatureCollection', + features: drawFeatures + }); + params.fitBoundsOptions = { padding: 60 }; + } + params.activeTab = 'editor'; + + MapComponentViewModel.apply(this, [params]); this.deleteFeature = function(feature) { if (self.draw) { self.draw.delete(feature.id); - updateFeatures(); + updateTiles(); } }; @@ -122,8 +131,17 @@ define([ map.setStyle(style); }; - this.selectedFeatureIds = ko.observableArray(); - this.draw = null; + this.fitFeatures = function(features) { + var map = self.map(); + var bounds = geojsonExtent({ + type: 'FeatureCollection', + features: features + }); + map.jumpTo(map.cameraForBounds(bounds, { + padding: 40 + })); + }; + this.map.subscribe(function(map) { self.draw = new MapboxDraw({ displayControlsDefault: false @@ -137,11 +155,11 @@ define([ e.features.forEach(function(feature) { self.draw.setFeatureProperty(feature.id, 'nodeId', newNodeId); }); - updateFeatures(); + updateTiles(); }); - map.on('draw.update', updateFeatures); - map.on('draw.delete', updateFeatures); - map.on('draw.modechange', updateFeatures); + map.on('draw.update', updateTiles); + map.on('draw.delete', updateTiles); + map.on('draw.modechange', updateTiles); map.on('draw.selectionchange', function(e) { self.selectedFeatureIds(e.features.map(function(feature) { return feature.id; @@ -157,16 +175,6 @@ define([ if (value.selectedTool()) value.selectedTool(''); }); }); - - setTimeout(function() { - map.resize(); - if (drawFeatures.length > 0) { - self.zoomToGeoJSON({ - type: 'FeatureCollection', - features: drawFeatures - }); - } - }, 1); }); }, template: { diff --git a/arches/app/media/js/views/components/map.js b/arches/app/media/js/views/components/map.js index 6e6ce9a893c..ef607d9191f 100644 --- a/arches/app/media/js/views/components/map.js +++ b/arches/app/media/js/views/components/map.js @@ -5,11 +5,10 @@ define([ 'knockout', 'mapbox-gl', 'mapbox-gl-geocoder', - 'geojson-extent', 'text!templates/views/components/map-popup.htm', 'bindings/mapbox-gl', 'bindings/sortable' -], function($, _, arches, ko, mapboxgl, MapboxGeocoder, geojsonExtent, popupTemplate) { +], function($, _, arches, ko, mapboxgl, MapboxGeocoder, popupTemplate) { var viewModel = function(params) { var self = this; var geojsonSourceFactory = function() { @@ -39,7 +38,7 @@ define([ this.basemaps = []; this.overlays = ko.observableArray(); this.activeBasemap = ko.observable(); - this.activeTab = ko.observable(); + this.activeTab = ko.observable(params.activeTab); this.hideSidePanel = function() { self.activeTab(undefined); }; @@ -47,13 +46,6 @@ define([ var map = self.map(); if (map) setTimeout(function() { map.resize(); }, 1); }); - this.zoomToGeoJSON = function(data, fly) { - var method = fly ? 'flyTo' : 'jumpTo'; - var map = self.map(); - var bounds = new mapboxgl.LngLatBounds(geojsonExtent(data)); - var options = map.cameraForBounds(bounds, {padding: 40}); - map[method](options); - }; mapLayers.forEach(function(layer) { if (!layer.isoverlay) { @@ -157,7 +149,8 @@ define([ center: [x, y], zoom: zoom }, - bounds: bounds + bounds: bounds, + fitBoundsOptions: params.fitBoundsOptions }; this.toggleTab = function(tabName) { @@ -180,35 +173,27 @@ define([ }; var resourceLookup = {}; - var lookupResourceData = function(feature) { - var resourceData = feature.properties; - var resourceId = resourceData.resourceinstanceid; - if (resourceLookup[resourceId]) { - return resourceLookup[resourceId]; - } - resourceData = _.defaults(resourceData, { - 'loading': true, - 'displaydescription': '', - 'map_popup': '', - 'displayname': '', - 'graphid': '', - 'graph_name': '', - 'geometries': [] - }); - resourceData = ko.mapping.fromJS(resourceData); - resourceData.reportURL = arches.urls.resource_report; - resourceData.editURL = arches.urls.resource_editor; - - resourceLookup[resourceId] = resourceData; - $.get(arches.urls.resource_descriptors + resourceId, function(data) { - data.loading = false; - ko.mapping.fromJS(data, resourceLookup[resourceId]); - }); - return resourceLookup[resourceId]; - }; - this.getPopupData = function(feature) { - return lookupResourceData(feature); + var data = feature.properties; + var id = data.resourceinstanceid; + if (id) { + if (resourceLookup[id]) return resourceLookup[id]; + data = _.defaults(data, { + 'loading': true, + 'displayname': '', + 'graph_name': '' + }); + data = ko.mapping.fromJS(data); + data.reportURL = arches.urls.resource_report; + data.editURL = arches.urls.resource_editor; + + resourceLookup[id] = data; + $.get(arches.urls.resource_descriptors + id, function(data) { + data.loading = false; + ko.mapping.fromJS(data, resourceLookup[id]); + }); + return resourceLookup[id]; + } }; this.setupMap = function(map) { @@ -221,7 +206,7 @@ define([ accessToken: mapboxgl.accessToken, mapboxgl: mapboxgl, placeholder: arches.geocoderPlaceHolder, - bbox: bounds + bbox: arches.hexBinBounds }), 'top-right'); layers.subscribe(self.updateLayers); @@ -239,18 +224,24 @@ define([ map.on('click', function(e) { if (hoverFeature) { - var p = new mapboxgl.Popup() + var selectedFeature = hoverFeature; + var popup = new mapboxgl.Popup() .setLngLat(e.lngLat) .setHTML(self.popupTemplate) .addTo(map); ko.applyBindingsToDescendants( self.getPopupData(hoverFeature), - p._content + popup._content ); + map.setFeatureState(selectedFeature, { selected: true }); + popup.on('close', function() { + map.setFeatureState(selectedFeature, { selected: false }); + }); } }); self.map(map); + setTimeout(function() { map.resize(); }, 1); }); }; }; diff --git a/arches/app/templates/views/components/map-editor.htm b/arches/app/templates/views/components/map-editor.htm index f5507123452..b7ca9cbc8dd 100644 --- a/arches/app/templates/views/components/map-editor.htm +++ b/arches/app/templates/views/components/map-editor.htm @@ -125,6 +125,12 @@