From 92e777f862df4e64e9bf3a6779cea4ece1efc5fc Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Tue, 15 Sep 2020 17:08:29 -0700 Subject: [PATCH 01/15] enabling legend to pull legend swatches from multiple arcgis IDs at once --- visualize/static/js/models.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index 672e662d..2f8e2be0 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -305,11 +305,12 @@ function layerModel(options, parent) { type: 'GET', success: function(data) { if (data['layers']) { + var requested_layers = self.arcgislayers.replace(/ /g,'').split(','); + self.legend = {'elements': []}; $.each(data['layers'], function(i, layerobj) { - if (parseInt(layerobj['layerId'], 10) === parseInt(self.arcgislayers, 10)) { - self.legend = {'elements': []}; + if (requested_layers.indexOf(parseInt(layerobj['layerId'], 10).toString()) >= 0) { $.each(layerobj['legend'], function(j, legendobj) { - var swatchURL = self.url.replace('/export', '/'+self.arcgislayers+'/images/'+legendobj['url']), + var swatchURL = self.url.replace('/export', '/'+parseInt(layerobj['layerId'], 10)+'/images/'+legendobj['url']), label = legendobj['label']; if (j < 1 && label === "") { label = layerobj['layerName']; From 36af80854b588c775c011e4923273dd831ae4063 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Wed, 16 Sep 2020 09:53:29 -0700 Subject: [PATCH 02/15] add '/export' to ArcGIS source URLs if they don't have it --- visualize/static/js/models.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index 2f8e2be0..7dd11d9f 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -291,6 +291,17 @@ function layerModel(options, parent) { getArcGISJSONLegend = function(self, protocol) { + + if (self.url.toLowerCase().indexOf('/export') < 0) { + var url_split = self.url.split('?'); + if (url_split[0][url_split[0].length-1] == '/') { + url_split[0] = url_split[0] + "export"; + } else { + url_split[0] = url_split[0] + "/export"; + } + self.url = url_split.join('?'); + } + if (self.url.indexOf('?') < 0) { var url = self.url.replace('/export', '/legend/?f=pjson'); } else { From d391c0fa50ea8746eb65a7bc700c74569a0f2e84 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Thu, 17 Sep 2020 12:10:31 -0700 Subject: [PATCH 03/15] more arcgis layer legend updates --- visualize/static/js/models.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index 7dd11d9f..13c691b9 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -315,6 +315,17 @@ function layerModel(options, parent) { url: url, type: 'GET', success: function(data) { + // append '/export' if missing: + if (self.url.toLowerCase().indexOf('/export') < 0) { + var url_split = self.url.split('?'); + if (url_split[0][url_split[0].length-1] == '/') { + url_split[0] = url_split[0] + "export"; + } else { + url_split[0] = url_split[0] + "/export"; + } + self.url = url_split.join('?'); + } + if (data['layers']) { var requested_layers = self.arcgislayers.replace(/ /g,'').split(','); self.legend = {'elements': []}; From 33fb665f4b2066e224b5054d3a8d7ac7fd4e2fba Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Thu, 17 Sep 2020 12:12:21 -0700 Subject: [PATCH 04/15] clarifying note regarding last commit --- visualize/static/js/models.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index 13c691b9..de1db058 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -316,6 +316,8 @@ function layerModel(options, parent) { type: 'GET', success: function(data) { // append '/export' if missing: + // RDH 2020-09-17: I'm not sure why self.url wasn't already modified earlier in this function, but this step is necessary + // as the '/export' seems to get dropped (a timeout may also have fixed the problem, but this is more absolute). if (self.url.toLowerCase().indexOf('/export') < 0) { var url_split = self.url.split('?'); if (url_split[0][url_split[0].length-1] == '/') { @@ -325,7 +327,7 @@ function layerModel(options, parent) { } self.url = url_split.join('?'); } - + if (data['layers']) { var requested_layers = self.arcgislayers.replace(/ /g,'').split(','); self.legend = {'elements': []}; From 4ee786ad1a22e77c74f3c5a11416c5dcf86bb304 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Mon, 21 Sep 2020 14:59:21 -0700 Subject: [PATCH 05/15] support ArcGIS feature info queries for urls w/o 'Export' --- visualize/static/js/events.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/visualize/static/js/events.js b/visualize/static/js/events.js index fa2d97a1..305bd927 100644 --- a/visualize/static/js/events.js +++ b/visualize/static/js/events.js @@ -6,8 +6,17 @@ if (!app.wrapper.events.hasOwnProperty('clickOnArcRESTLayerEvent')) { app.wrapper.events.clickOnArcRESTLayerEvent = function(layer, evt){ if (app.wrapper.map.getLayerParameter(layer, 'url')){ - var identifyUrl = app.wrapper.map.getLayerParameter(layer, 'url') - .replace('export', app.wrapper.map.getLayerParameter(layer, 'arcgislayers') + '/query'); + + var identifyUrl = app.wrapper.map.getLayerParameter(layer, 'url'); + + if (identifyUrl.indexOf('export') >= 0) { + identifyUrl = identifyUrl.replace('export', app.wrapper.map.getLayerParameter(layer, 'arcgislayers') + '/query'); + } else { + if (identifyUrl[identifyUrl.length-1] != "/") { + identifyUrl += '/' + } + identifyUrl += app.wrapper.map.getLayerParameter(layer, 'arcgislayers') + '/query'; + } } else { var identifyUrl = ''; } From 42c0c8511199b77cb0129baf679a5046c93ab066 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Mon, 21 Sep 2020 14:59:42 -0700 Subject: [PATCH 06/15] allow featureinfo box to be wider on wider screens --- visualize/static/js/models.js | 4 ++-- visualize/static/visualize/css/attribute_report.css | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index de1db058..e78bdaa1 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -1989,7 +1989,7 @@ function viewModel() { // attribute data self.aggregatedAttributes = ko.observable(false); - self.aggregatedAttributesWidth = ko.observable('280px'); + self.aggregatedAttributesWidth = ko.observable('30vw'); self.aggregatedAttributes.subscribe( function() { self.updateAggregatedAttributesOverlayWidthAndScrollbar(); self.showFeatureAttribution( self.featureAttribution() && !($.isEmptyObject(self.aggregatedAttributes())) ); @@ -2009,7 +2009,7 @@ function viewModel() { // var overlayWidth = (document.getElementById('aggregated-attribute-overlay-test').clientWidth+50), // width = overlayWidth < 380 ? overlayWidth : 380; //console.log('setting overlay width to ' + width); - self.aggregatedAttributesWidth(280 + 'px'); + self.aggregatedAttributesWidth('30vw'); }, 500); }; diff --git a/visualize/static/visualize/css/attribute_report.css b/visualize/static/visualize/css/attribute_report.css index 1a3a63d0..5061d238 100644 --- a/visualize/static/visualize/css/attribute_report.css +++ b/visualize/static/visualize/css/attribute_report.css @@ -1,5 +1,6 @@ #aggregated-attribute-overlay { z-index: 1020 !important; + min-width: 280px; } .feature-attributes { From adf883e12a7fe461f3bd6f0e8ae8bb7e53b7a0fe Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Thu, 29 Oct 2020 15:06:27 -0700 Subject: [PATCH 07/15] no slider button should show on 'active' tab ever. --- visualize/static/visualize/css/multilayer.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/visualize/static/visualize/css/multilayer.css b/visualize/static/visualize/css/multilayer.css index a80cfc89..046f241f 100644 --- a/visualize/static/visualize/css/multilayer.css +++ b/visualize/static/visualize/css/multilayer.css @@ -109,3 +109,7 @@ div.tooltip.fade.right.in { div.tooltip.fade.right.in div.tooltip-arrow { margin-left: -5px; } + +div#active td.slider-button { + display: none; +} From 44dd7c3438379200316f2a043a2f39af5f2d1dc6 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Fri, 6 Nov 2020 16:35:28 -0800 Subject: [PATCH 08/15] only ArcRest layers will attempt to retrieve ArcRest legends --- visualize/static/js/models.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index e78bdaa1..ec2dcd7b 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -670,7 +670,7 @@ function layerModel(options, parent) { } // if legend is not provided, try using legend from web services - if ( !self.legend && self.url && (self.arcgislayers !== -1) ) { + if ( self.type == 'ArcRest' && !self.legend && self.url && (self.arcgislayers !== -1) ) { try { getArcGISJSONLegend(self, window.location.protocol); } catch (err) { From 27721aa0304e51dd068a4064bbb26987f9514836 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Sun, 15 Nov 2020 15:27:25 -0800 Subject: [PATCH 09/15] fixing loading status indicator, works on all Arc tile loads, no trigger when active layers are invisible --- visualize/static/js/models.js | 4 ---- visualize/static/js/wrappers/ol6/ol6_events.js | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index e78bdaa1..a9010245 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -658,10 +658,6 @@ function layerModel(options, parent) { self.activateLayer = function(is_companion) { var layer = this; - if (app.wrapper.events.hasOwnProperty('addLayerLoadStart')) { - layer.loadStatus("loading"); - } - if (layer instanceof layerModel) { if (layer.fullyLoaded || layer.isMDAT || layer.isVTR) { diff --git a/visualize/static/js/wrappers/ol6/ol6_events.js b/visualize/static/js/wrappers/ol6/ol6_events.js index 6a38beb6..e7e92c45 100644 --- a/visualize/static/js/wrappers/ol6/ol6_events.js +++ b/visualize/static/js/wrappers/ol6/ol6_events.js @@ -304,7 +304,7 @@ app.wrapper.events.layerLoadStart = function(layerModel) { * @param {object} layerModel - the layerModel to add layer loading logic to */ app.wrapper.events.addLayerLoadStart = function(layerModel) { - if (layerModel.layer.hasOwnProperty('url') && layerModel.layer.url && layerModel.layer.url.length > 0 && layerModel.type.toLowerCase() != 'placeholder') { + if (layerModel.hasOwnProperty('url') && layerModel.url && layerModel.url.length > 0 && layerModel.type.toLowerCase() != 'placeholder') { if (app.wrapper.events.tileSources.indexOf(layerModel.type) >= 0) { layerModel.layer.getSource().on('tileloadstart', function() { app.wrapper.events.layerLoadStart(layerModel); From 53809d1b7257c90be9d3b47b98bd8d300c43031f Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Fri, 11 Dec 2020 10:23:27 -0800 Subject: [PATCH 10/15] scrollable descriptions rather than truncated --- visualize/static/visualize/css/layer-nav.css | 6 ++++++ .../templates/visualize/includes/layer-row.html | 4 ++-- visualize/templates/visualize/planner.html | 1 + visualize/templates/visualize/scenarios.html | 12 ++++++------ 4 files changed, 15 insertions(+), 8 deletions(-) create mode 100644 visualize/static/visualize/css/layer-nav.css diff --git a/visualize/static/visualize/css/layer-nav.css b/visualize/static/visualize/css/layer-nav.css new file mode 100644 index 00000000..fde2cc28 --- /dev/null +++ b/visualize/static/visualize/css/layer-nav.css @@ -0,0 +1,6 @@ +body.template-visualize .layer-info .layer-text { + max-height: 114px; + overflow-y: auto; + border: 1px solid #CCC; + border-radius: 0.3rem; +} diff --git a/visualize/templates/visualize/includes/layer-row.html b/visualize/templates/visualize/includes/layer-row.html index cf570d56..088e71f1 100644 --- a/visualize/templates/visualize/includes/layer-row.html +++ b/visualize/templates/visualize/includes/layer-row.html @@ -100,8 +100,8 @@ -
- +
+ read more. diff --git a/visualize/templates/visualize/planner.html b/visualize/templates/visualize/planner.html index f4fbddc0..21479303 100644 --- a/visualize/templates/visualize/planner.html +++ b/visualize/templates/visualize/planner.html @@ -17,6 +17,7 @@ + {% if MAP_LIBRARY == 'ol5' %} diff --git a/visualize/templates/visualize/scenarios.html b/visualize/templates/visualize/scenarios.html index 17465ffa..8f34a990 100644 --- a/visualize/templates/visualize/scenarios.html +++ b/visualize/templates/visualize/scenarios.html @@ -158,9 +158,9 @@
-
- -
+
+ +
@@ -373,7 +373,7 @@
- + read more. @@ -573,7 +573,7 @@
- + read more. @@ -776,7 +776,7 @@
- + read more. From f80298051a538756101532b2928ce1afb1acc178 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Fri, 11 Dec 2020 15:56:15 -0800 Subject: [PATCH 11/15] hiding info icon if none exists --- visualize/static/js/models.js | 10 +++++++++- visualize/templates/visualize/includes/layer-row.html | 10 ++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index ca74e6ae..1e8c49c3 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -45,6 +45,7 @@ function layerModel(options, parent) { self.data_download = ko.observable(options.data_download || null); self.metadata = ko.observable(options.metadata || null); self.source = ko.observable(options.source || null); + self.hasInfo = ko.observable(false); self.setOptions = function(options, parent) { @@ -230,6 +231,10 @@ function layerModel(options, parent) { self.source(options.source || null); self.tiles = options.tiles || null; + if (options.description || options.kml || options.data_download || options.metadata || options.source) { + self.hasInfo(true); + } + if (self.type === 'checkbox') { self.isCheckBoxLayer(true); } @@ -1583,7 +1588,10 @@ function themeModel(options) { for (var i = 0; i < data.layers.length; i++) { new_layer = app.viewModel.getOrCreateLayer(data.layers[i], null, 'return', null); new_layer.themes.push(theme); - layer_objects.push(new_layer) + layer_objects.push(new_layer); + if (!new_layer.fullyLoaded) { + new_layer.getFullLayerRecord(null, null); + } } theme.layers(layer_objects); }, diff --git a/visualize/templates/visualize/includes/layer-row.html b/visualize/templates/visualize/includes/layer-row.html index 088e71f1..cf1ec0a4 100644 --- a/visualize/templates/visualize/includes/layer-row.html +++ b/visualize/templates/visualize/includes/layer-row.html @@ -2,14 +2,16 @@ - + - - - + + + From 5221ddc3a0eb26590d3ed9c71b719476d2ef5591 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Wed, 16 Dec 2020 17:33:06 -0800 Subject: [PATCH 12/15] merging linear measurement commit b3621fbbf7f431ca2da7656ea03e433d540537b5 from mida fork --- visualize/static/js/map.js | 91 +++++++ visualize/static/js/models.js | 95 +------ .../static/js/wrappers/ol6/ol6_controls.js | 255 ++++++++++++++++++ .../static/js/wrappers/ol6/ol6_events.js | 6 +- visualize/static/js/wrappers/ol6/ol6_map.js | 49 ++++ 5 files changed, 406 insertions(+), 90 deletions(-) diff --git a/visualize/static/js/map.js b/visualize/static/js/map.js index 93e75971..e770ee7c 100644 --- a/visualize/static/js/map.js +++ b/visualize/static/js/map.js @@ -468,3 +468,94 @@ app.setLayerZIndex = function(layer, index) { app.reCenterMap = function () { app.setMapPosition(app.state.x, app.state.y, 7); }; + +app.addDrawingLayerToMap = function(name) { + if (app.wrapper.map.hasOwnProperty('addDrawingLayerToMap')) { + var drawingLayer = app.wrapper.map.addDrawingLayerToMap(name); + } else { + console.log('no addDrawingLayerToMap function defined.'); + } +} + +app.startSketch = function(){ + if (app.wrapper.controls.hasOwnProperty('startSketch')) { + app.wrapper.controls.startSketch(); + } else { + console.log('no startSketch function defined for controls.') + } +} + +app.completeSketch = function() { + if (app.wrapper.controls.hasOwnProperty('completeSketch')) { + app.wrapper.controls.completeSketch(); + } else { + console.log('no completeSketch function defined for controls.') + } +} + +app.startEdit = function() { + var drawingForm = app.viewModel.scenarios.drawingFormModel; + drawingForm.isEditing(true); + app.viewModel.disableFeatureAttribution(); + if (app.wrapper.controls.hasOwnProperty('startEdit')) { + app.wrapper.controls.startEdit(); + } else { + console.log('no startEdit function defined for controls.') + } +} + +app.completeEdit = function() { + var drawingForm = app.viewModel.scenarios.drawingFormModel; + drawingForm.isEditing(false); + if (app.wrapper.controls.hasOwnProperty('completeEdit')) { + app.wrapper.controls.completeEdit(); + } else { + console.log('no completeEdit function defined for controls.') + } + app.viewModel.enableFeatureAttribution(); + if (app.wrapper.map.hasOwnProperty('countFeatures')){ + num_features = app.wrapper.map.countFeatures(app.map.drawingLayer); + if (num_features == 0) { + drawingForm.hasShape(false); + window.alert('You have no shapes drawn. Please draw a shape before saving.'); + app.startSketch(); + } else if (num_features > 1) { + app.consolidatePolygonLayerFeatures(); + } + } else { + console.log('no countFeatures function defined for map'); + } +} + +app.cleanupDrawing = function() { + if (app.wrapper.events.hasOwnProperty('cleanupDrawing')) { + app.wrapper.events.cleanupDrawing(); + } else { + console.log('no cleanupDrawing function defined for events.'); + } +} + +app.consolidatePolygonLayerFeatures = function(){ + if (app.wrapper.controls.hasOwnProperty('consolidatePolygonLayerFeatures')) { + app.wrapper.controls.consolidatePolygonLayerFeatures(); + } else { + console.log('no consolidatePolygonLayerFeatures function defined for controls'); + } +} + +app.getLayerFeatureAsWKT = function(layer, feature_index) { + if (app.wrapper.layer_functions.hasOwnProperty('getLayerFeatureAsWKT')) { + return app.wrapper.layer_functions.getLayerFeatureAsWKT(layer, feature_index); + } else { + console.log('no getLayerFeatureAsWKT function defined for layers'); + } +} + +app.addMeasurementLayerToMap = function(name) { + if (app.wrapper.map.hasOwnProperty('addMeasurementLayerToMap')) { + app.map.measurementLayer = app.wrapper.map.addMeasurementLayerToMap(name); + app.map.addLayer(app.map.measurementLayer); + } else { + console.log('no addDrawingLayerToMap function defined.'); + } +} diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index ec2dcd7b..b69d1f05 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -2323,97 +2323,18 @@ function viewModel() { }; self.toggleLinearMeasurement = function() { - if ($('#linear-measurement i').hasClass('fa-ruler-vertical')) { - self.startLinearMeasurement(); - } else { - self.clearLinearMeasurement(); + if (!app.map.measurementLayer) { + app.addMeasurementLayerToMap(); } - } - - self.handleLinearMeasurements = function(event) { - var geometry = event.geometry; - var units = event.units; - var order = event.order; - var measure = event.measure; - var element = document.getElementById('measurement-output'); - var out = ""; - if (measure < 19) { - var to_fixed_digits = 2; - } else if (measure > 187 ) { - var to_fixed_digits = 0; + if (app.wrapper.controls.hasOwnProperty('startLinearMeasurement')) { + if ($('#linear-measurement i').hasClass('fa-ruler-vertical')) { + app.wrapper.controls.startLinearMeasurement(); } else { - var to_fixed_digits = 1; - } - if(order == 1) { - out += "measure: " + measure.toFixed(to_fixed_digits) + " " + units; - if (units == "km") { - out += "; " + (measure/1.609344).toFixed(to_fixed_digits) + " mi" + "; " + (measure/1.852).toFixed(to_fixed_digits) + " N mi"; - } else if (units == "m") { - out += "; " + (measure/1609.344).toFixed(3) + " mi" + "; " + (measure/1852).toFixed(3) + " N mi"; - } - } else { - out += "measure: " + measure.toFixed(to_fixed_digits) + " " + units + "2"; + app.wrapper.controls.clearLinearMeasurement(); } - element.innerHTML = out; - } - - self.createLinearControl = function() { - // yanked from http://dev.openlayers.org/examples/measure.html - var sketchSymbolizers = { - "Line": { - strokeWidth: 3, - strokeOpacity: 1, - strokeDashstyle: "solid" - } - }; - var style = new OpenLayers.Style(); - style.addRules([ - new OpenLayers.Rule({symbolizer: sketchSymbolizers}) - ]); - var styleMap = new OpenLayers.StyleMap({"default": style}); - - var renderer = OpenLayers.Util.getParameters(window.location.href).renderer; - renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers; - - app.map.linearMeasurementControl = new OpenLayers.Control.Measure( - OpenLayers.Handler.Path, { - persist: true, - handlerOptions: { - layerOptions: { - renderers: renderer, - styleMap: styleMap - } - } - } - ); - - app.map.linearMeasurementControl.events.on({ - 'measure': self.handleLinearMeasurements, - 'measurepartial': self.handleLinearMeasurements - }); - app.map.linearMeasurementControl.geodesic = true; - app.map.linearMeasurementControl.setImmediate(true); - app.map.addControl(app.map.linearMeasurementControl); - - } - - self.startLinearMeasurement = function() { - if (!app.map.linearMeasurementControl) { - self.createLinearControl(); + } else { + window.alert('No linear measurement controls defined for current mapping framework.'); } - // Activate drawing (linestring) - app.map.linearMeasurementControl.activate(); - $('#measurement-display').show(); - // change $('#linear-measurement-button') to work as cancel/clear - $('#linear-measurement i').removeClass('fa-ruler-vertical'); - $('#linear-measurement i').addClass('fa-times'); - } - - self.clearLinearMeasurement = function() { - $('#measurement-display').hide(); - app.map.linearMeasurementControl.deactivate(); - $('#linear-measurement i').removeClass('fa-times'); - $('#linear-measurement i').addClass('fa-ruler-vertical'); } /* marine-life-library, not databased MDAT layers */ diff --git a/visualize/static/js/wrappers/ol6/ol6_controls.js b/visualize/static/js/wrappers/ol6/ol6_controls.js index afc863b9..3bdaad23 100644 --- a/visualize/static/js/wrappers/ol6/ol6_controls.js +++ b/visualize/static/js/wrappers/ol6/ol6_controls.js @@ -335,3 +335,258 @@ app.wrapper.controls.addUTFControl = function(){ */ // app.wrapper.controls.addArcIdentifyControl = function(layer, identifyUrl) { // }; + +app.wrapper.controls.completeSketch = function() { + app.map.addInteraction(app.map.interactions.selectClick); + app.viewModel.enableFeatureAttribution(); + app.map.removeInteraction(app.viewModel.scenarios.drawingFormModel.draw); + app.viewModel.scenarios.drawingFormModel.isDrawing(false); + app.wrapper.controls.enableDoubleClickZoom(); +} + +app.wrapper.controls.startSketch = function() { + var drawingForm = app.viewModel.scenarios.drawingFormModel; + var features = app.map.drawingLayer.getSource().getFeatures(); + if (features.length > 0 && features[0].geometry instanceof ol.geom.Polygon) { + app.wrapper.controls.consolidatePolygonLayerFeatures(); + } + drawingForm.isDrawing(true); + + //activate the draw feature control + drawingForm.draw = new ol.interaction.Draw({ + source: app.map.drawingLayer.getSource(), + type: 'Polygon' + }); + app.map.addInteraction(drawingForm.draw); + //disable feature attribution + app.viewModel.disableFeatureAttribution(); + app.map.removeInteraction(app.map.interactions.selectClick); + drawingForm.draw.on('drawend',function() { + app.wrapper.controls.completeSketch(); + app.viewModel.scenarios.drawingFormModel.showEdit(true); + app.viewModel.scenarios.drawingFormModel.hasShape(true); + setTimeout(function() { + app.wrapper.controls.consolidatePolygonLayerFeatures(); + }, 100); + }); + drawingForm.draw.on('drawabort', app.wrapper.controls.completeSketch); + app.wrapper.controls.disableDoubleClickZoom(); +}; + +app.wrapper.controls.consolidatePolygonLayerFeatures = function(layer){ + var featureList = app.map.drawingLayer.getSource().getFeatures(); + var multipolygon = new ol.geom.MultiPolygon([]); + for (var i = 0; i < featureList.length; i++) { + var feat = featureList[i].getGeometry(); + if (feat instanceof ol.geom.Polygon) { + multipolygon.appendPolygon(feat); + } else if (feat instanceof ol.geom.MultiPolygon){ + var polygons = feat.getPolygons(); + for (var j = 0; j < polygons.length; j++) { + multipolygon.appendPolygon(polygons[j]) + } + } else { + console.log('feature is not an appropriate geometry'); + } + } + app.map.drawingLayer.getSource().clear(); + multipolygon_feature = new ol.Feature({geometry: multipolygon}); + setTimeout(function() { + app.map.drawingLayer.getSource().addFeature(multipolygon_feature); + }, 300); +}; + +app.wrapper.controls.setDoublClickZoomInteraction = function() { + app.map.getInteractions().getArray().forEach(function(interaction) { + if (interaction instanceof ol.interaction.DoubleClickZoom) { + app.map.controls.dblClickInteraction = interaction; + } + }); +}; + +app.wrapper.controls.enableDoubleClickZoom = function() { + if (!app.map.controls.hasOwnProperty('dblClickInteraction')){ + app.wrapper.controls.setDoublClickZoomInteraction(); + } + setTimeout(function() { + app.map.addInteraction(app.map.controls.dblClickInteraction); + }, 300); +}; + +app.wrapper.controls.disableDoubleClickZoom = function() { + if (!app.map.controls.hasOwnProperty('dblClickInteraction')){ + app.wrapper.controls.setDoublClickZoomInteraction(); + } + app.map.removeInteraction(app.map.controls.dblClickInteraction); +}; + +app.wrapper.controls.startEdit = function() { + var drawingForm = app.viewModel.scenarios.drawingFormModel; + // activate the modify feature control + drawingForm.edit = new ol.interaction.Modify({ + source: app.map.drawingLayer.getSource() + }); + // drawingForm.edit.on('modifyend', app.completeEdit); + app.map.addInteraction(drawingForm.edit); +} + +app.wrapper.controls.completeEdit = function() { + var drawingForm = app.viewModel.scenarios.drawingFormModel; + app.map.removeInteraction(drawingForm.edit); +}; + +app.wrapper.controls.getAttributionState = function() { + if ($('.ol-attribution').hasClass('ol-collapsed')) { + return 'hide'; + } else { + return 'show'; + } +} + +app.wrapper.controls.setAttributionState = function(state) { + if (state == 'hide') { + $('.ol-attribution').addClass('ol-collapsed') + } else { + $('.ol-attribution').removeClass('ol-collapsed') + } +} + +/** Measurement contols + * A cross between the old measurement logic and the OL demo here: + * https://openlayers.org/en/latest/examples/measure.html +*/ + +app.wrapper.controls.measurementFeature = false; + +app.wrapper.controls.getFixedLengthHelper = function(rawNumber) { + if (rawNumber < 19) { + var to_fixed_digits = 2; + } else if (rawNumber > 187 ) { + var to_fixed_digits = 0; + } else { + var to_fixed_digits = 1; + } + return rawNumber.toFixed(to_fixed_digits); +} + +/** + * Format length output. + * @param {LineString} line The line. + * @return {string} The formatted length. + */ +app.wrapper.controls.formatLength = function (line) { + var length = ol.sphere.getLength(line); + var output = "measure: "; + if (length > 750) { + numericLength = Math.round((length / 1000) * 100) / 100; + output += app.wrapper.controls.getFixedLengthHelper(numericLength) + ' km; '; + output += app.wrapper.controls.getFixedLengthHelper(numericLength/1.609344) + " mi; "; + output += app.wrapper.controls.getFixedLengthHelper(numericLength/1.852) + " N mi"; + } else { + numericLength = Math.round(length * 100) / 100; + output += app.wrapper.controls.getFixedLengthHelper(numericLength) + ' m; '; + output += app.wrapper.controls.getFixedLengthHelper(numericLength/1609.344) + " mi; "; + output += app.wrapper.controls.getFixedLengthHelper(numericLength/1852) + " N mi"; + } + + return output; +}; + +/** + * Format area output. + * @param {Polygon} polygon The polygon. + * @return {string} Formatted area. + */ +app.wrapper.controls.formatArea = function (polygon) { + var area = ol.sphere.getArea(polygon); + var output; + if (area > 10000) { + output = Math.round((area / 1000000) * 100) / 100 + ' ' + 'km2'; + } else { + output = Math.round(area * 100) / 100 + ' ' + 'm2'; + } + return output; +}; + +app.wrapper.controls.updateMeasurementText = function(event) { + var geom = event.target; + if (!(geom instanceof ol.geom.Polygon || geom instanceof ol.geom.LineString)) { + // For the event type passed by drawEnd + geom = event.feature.getGeometry(); + } + var output; + if (geom instanceof ol.geom.Polygon) { + output = app.wrapper.controls.formatArea(geom); + } else if (geom instanceof ol.geom.LineString) { + output = app.wrapper.controls.formatLength(geom); + } + var element = document.getElementById('measurement-output'); + if (output) { + element.innerHTML = output; + } else { + element.innerHTML = ""; + } + +} + +app.wrapper.controls.createLinearControl = function() { + app.wrapper.controls.linearMeasurementControl = new ol.interaction.Draw({ + source: app.map.measurementLayer.getSource(), + type: 'LineString', // NOTE: When creating area, use 'Polygon'. See https://openlayers.org/en/latest/examples/measure.html + style: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)', + }), + stroke: new ol.style.Stroke({ + color: '#ffcc33', + width: 2, + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#ffcc33', + }), + }), + }) + }); + + app.wrapper.controls.linearMeasurementControl.on('drawstart', app.wrapper.controls.startLinearMeasurement); + app.wrapper.controls.linearMeasurementControl.on('drawend', function(event) { + app.wrapper.controls.updateMeasurementText(event); + ol.Observable.unByKey(app.wrapper.controls.measurementListener); + }); +} + +// app.wrapper.controls.startLinearMeasurement = function(event) { +// app.wrapper.controls.measurementFeature = event.feature; +// app.wrapper.controls.measurementListener = app.wrapper.controls.measurementFeature.getGeometry().on('change', app.wrapper.controls.updateMeasurementText) +// } + +// Not sure why this function was written twice - overloading did not seem to work +// However, later let's get that update logic from the other function (above) working +// in this function. RDH 2/2/2021 +app.wrapper.controls.startLinearMeasurement = function() { + if (!app.wrapper.controls.linearMeasurementControl) { + app.wrapper.controls.createLinearControl(); + } + + // Clear features from Measurement layer! + app.map.measurementLayer.getSource().clear(); + + // Activate drawing (linestring) + app.map.addInteraction(app.wrapper.controls.linearMeasurementControl); + + $('#measurement-display').show(); + // change $('#linear-measurement-button') to work as cancel/clear + $('#linear-measurement i').removeClass('fa-ruler-vertical'); + $('#linear-measurement i').addClass('fa-times'); +} + +app.wrapper.controls.clearLinearMeasurement = function() { + $('#measurement-display').hide(); + app.map.removeInteraction(app.wrapper.controls.linearMeasurementControl); + app.wrapper.controls.measurementFeature = false; + app.map.measurementLayer.getSource().clear(); + $('#linear-measurement i').removeClass('fa-times'); + $('#linear-measurement i').addClass('fa-ruler-vertical'); +} diff --git a/visualize/static/js/wrappers/ol6/ol6_events.js b/visualize/static/js/wrappers/ol6/ol6_events.js index 6a38beb6..25bf73f6 100644 --- a/visualize/static/js/wrappers/ol6/ol6_events.js +++ b/visualize/static/js/wrappers/ol6/ol6_events.js @@ -37,10 +37,10 @@ app.wrapper.events.addFeatureClickEvent = function(){ selectClick.on('select', function(e) { if (e.selected.length > 0) { for (var i = 0; i < e.selected.length; i++) { - var layer = e.selected[0].getLayer(app.map); - if (!layer){ + var layer = e.selected[i].getLayer(app.map); + if (!layer && e.target.getLayer(e.selected[i]) && e.target.getLayer(e.selected[i]).hasOwnProperty('ol_uid')) { // This seems to work for VectorTile layers - layer = app.viewModel.getLayerByOLId(e.target.getLayer(e.selected[0]).ol_uid).layer; + layer = app.viewModel.getLayerByOLId(e.target.getLayer(e.selected[i]).ol_uid).layer; } if (layer){ var mp_layer = layer.get('mp_layer'); diff --git a/visualize/static/js/wrappers/ol6/ol6_map.js b/visualize/static/js/wrappers/ol6/ol6_map.js index 9cd1d582..f119064c 100644 --- a/visualize/static/js/wrappers/ol6/ol6_map.js +++ b/visualize/static/js/wrappers/ol6/ol6_map.js @@ -793,3 +793,52 @@ app.wrapper.map.addUtfLayerToMap = function(layer){ return layer; }; + +/** + * addDrawingLayerToMap - add blank vector layer to the (ol6) map for drawing + */ +app.wrapper.map.addDrawingLayerToMap = function() { + + // var layer = app.wrapper.map.createDrawingLayer(name); + // var style_dict = app.wrapper.map.createOLStyleMap(layer); + var source = new ol.source.Vector({wrapX: false}); + + app.map.drawingLayer = new ol.layer.Vector({ + source: source, + }); + + app.map.addLayer(app.map.drawingLayer); + + return app.map.drawingLayer; +}; + +app.wrapper.map.countFeatures = function(layer) { + return layer.getSource().getFeatures().length; +} + +/* Creating Feature Layers to support map controls */ +app.wrapper.map.addMeasurementLayerToMap = function() { + var source = new ol.source.Vector({wrapX: false}); + + measurementLayer = new ol.layer.Vector({ + source: source, + style: new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.2)', + }), + stroke: new ol.style.Stroke({ + color: '#ffcc33', + width: 2, + }), + image: new ol.style.Circle({ + radius: 7, + fill: new ol.style.Fill({ + color: '#ffcc33', + }), + }), + }) + }); + + return measurementLayer; + +} From 7210313737a6c63eac8e67a0ebbdaa4d18a64ac8 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Wed, 3 Feb 2021 16:58:26 -0800 Subject: [PATCH 13/15] fixing bug where linearmeasurement never dies --- visualize/static/js/wrappers/ol6/ol6_controls.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/visualize/static/js/wrappers/ol6/ol6_controls.js b/visualize/static/js/wrappers/ol6/ol6_controls.js index 3bdaad23..3190b12a 100644 --- a/visualize/static/js/wrappers/ol6/ol6_controls.js +++ b/visualize/static/js/wrappers/ol6/ol6_controls.js @@ -568,6 +568,8 @@ app.wrapper.controls.createLinearControl = function() { app.wrapper.controls.startLinearMeasurement = function() { if (!app.wrapper.controls.linearMeasurementControl) { app.wrapper.controls.createLinearControl(); + } else { + app.wrapper.controls.linearMeasurementControl.setActive(true); } // Clear features from Measurement layer! @@ -584,7 +586,7 @@ app.wrapper.controls.startLinearMeasurement = function() { app.wrapper.controls.clearLinearMeasurement = function() { $('#measurement-display').hide(); - app.map.removeInteraction(app.wrapper.controls.linearMeasurementControl); + app.wrapper.controls.linearMeasurementControl.setActive(false); app.wrapper.controls.measurementFeature = false; app.map.measurementLayer.getSource().clear(); $('#linear-measurement i').removeClass('fa-times'); From 8c3be0e62bc5c44861101d56ffc920469647bdc4 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Fri, 5 Mar 2021 10:27:57 -0800 Subject: [PATCH 14/15] attempted fix for slider loading issues --- visualize/static/js/models.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index d3bf62da..e3c2363f 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -334,7 +334,20 @@ function layerModel(options, parent) { } if (data['layers']) { - var requested_layers = self.arcgislayers.replace(/ /g,'').split(','); + if (typeof(self.arcgislayers) == "number") { + var requested_layers = [self.arcgislayers.toString()]; + } else if (typeof(self.arcgislayers) == "object") { + var requested_layers = []; + for (var i = 0; i < self.arcgislayers.length; i++) { + requested_layers.push(self.arcgislayers[i].toString()); + } + } else if (typeof(self.arcgislayers) == "string"){ + var requested_layers = self.arcgislayers.replace(/ /g,'').split(','); + } else { + // punt + var requested_layers = self.arcgislayers; + } + self.legend = {'elements': []}; $.each(data['layers'], function(i, layerobj) { if (requested_layers.indexOf(parseInt(layerobj['layerId'], 10).toString()) >= 0) { From 3ef93cc5cd0da5bc3f19637fff296b5390b62a74 Mon Sep 17 00:00:00 2001 From: Ryan Hodges Date: Sat, 6 Mar 2021 11:20:37 -0800 Subject: [PATCH 15/15] fix issue where slider doesn't work on initial load --- visualize/static/js/models.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/visualize/static/js/models.js b/visualize/static/js/models.js index e3c2363f..ac281a46 100644 --- a/visualize/static/js/models.js +++ b/visualize/static/js/models.js @@ -968,6 +968,8 @@ function layerModel(options, parent) { } } self.toggleMultilayer(sliderValues); + } else { + self.buildMultilayerValueLookup(); } };