From c30ae857af7f2e2bccf974da34cf2f3868e7b7f2 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Thu, 4 Jul 2019 21:12:12 +0100 Subject: Improve map JavaScript defensiveness. Add more checking for map things so e.g. on a skipped map page we stop getting JavaScript errors given there is no map present. --- web/js/map-OpenLayers.js | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index ae86269c9..cd2283491 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -304,6 +304,9 @@ $.extend(fixmystreet.utils, { // fixmystreet.select_feature). markers_highlight: function(problem_id) { + if (!fixmystreet.markers) { + return; + } for (var i = 0; i < fixmystreet.markers.features.length; i++) { if (typeof problem_id == 'undefined') { // There is no highlighted marker, so unfade this marker @@ -791,6 +794,10 @@ $.extend(fixmystreet.utils, { $(function(){ + if (!document.getElementById('map')) { + return; + } + // Set specific map config - some other JS included in the // template should define this fixmystreet.maps.config(); -- cgit v1.2.3 From a2e26d96b2fc08f977622f2c3dd7624cf082acbf Mon Sep 17 00:00:00 2001 From: Struan Donald Date: Mon, 9 Sep 2019 16:11:08 +0100 Subject: [IsleOfWight] fix wmts bbox strategy setting Change the way we set the BBOX strategy for the map layer as otherwise when we check for bbox_strategy in display_around this is set but has not been associated with a layer so .activate fails. --- web/js/map-OpenLayers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index cd2283491..ab04d15c9 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -673,7 +673,7 @@ $.extend(fixmystreet.utils, { styleMap: pin_layer_style_map }; if (fixmystreet.page == 'around') { - fixmystreet.bbox_strategy = fixmystreet.bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); + fixmystreet.bbox_strategy = fixmystreet.map_bbox_strategy || new OpenLayers.Strategy.FixMyStreet(); pin_layer_options.strategies = [ fixmystreet.bbox_strategy ]; } if (fixmystreet.page == 'reports') { -- cgit v1.2.3 From 90f4dbe8067639d7274a3b2c05cdd985bf6366c2 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Mon, 19 Aug 2019 12:41:02 +0100 Subject: [OpenLayers] Never send X-Requested-With header. --- web/js/map-OpenLayers.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index cd2283491..4e4201d3a 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -562,6 +562,9 @@ $.extend(fixmystreet.utils, { } else { $.extend(style.defaultStyle, { fillColor: 'black', strokeColor: 'black' }); } + if (!this.features.length) { + return; + } var geometry = this.features[0].geometry; if (geometry.CLASS_NAME == 'OpenLayers.Geometry.Collection' || geometry.CLASS_NAME == 'OpenLayers.Geometry.MultiPolygon') { @@ -1185,3 +1188,15 @@ OpenLayers.Renderer.SVGBig = OpenLayers.Class(OpenLayers.Renderer.SVG, { CLASS_NAME: "OpenLayers.Renderer.SVGBig" }); + +/* Stop sending a needless header so that no preflight CORS request */ +OpenLayers.Request.XMLHttpRequest.prototype.setRequestHeader = function(sName, sValue) { + if (sName.toLowerCase() == 'x-requested-with') { + return; + } + if (!this._headers) { + this._headers = {}; + } + this._headers[sName] = sValue; + return this._object.setRequestHeader(sName, sValue); +}; -- cgit v1.2.3 From 3550b5b2c0ca271a5505198a267ea8c9e94033f1 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Fri, 11 Oct 2019 14:53:30 +0100 Subject: Add map filter debouncing. --- web/js/map-OpenLayers.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 1588bda2e..eb62904b0 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -10,6 +10,19 @@ if (!Object.keys) { }; } +function debounce(fn, delay) { + var timeout; + return function() { + var that = this, args = arguments; + var debounced = function() { + timeout = null; + fn.apply(that, args); + }; + clearTimeout(timeout); + timeout = setTimeout(debounced, delay); + }; +} + var fixmystreet = fixmystreet || {}; fixmystreet.utils = fixmystreet.utils || {}; @@ -428,10 +441,10 @@ $.extend(fixmystreet.utils, { } } - function categories_or_status_changed() { + var categories_or_status_changed = debounce(function() { // If the category or status has changed we need to re-fetch map markers fixmystreet.markers.refresh({force: true}); - } + }, 1000); function replace_query_parameter(qs, id, key) { var value, -- cgit v1.2.3 From abeb4050e895ff93f5f66affd1ff07c3943bd2a9 Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Thu, 14 Nov 2019 14:34:50 +0000 Subject: Use variables for marker size boundaries. --- web/js/map-OpenLayers.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index eb62904b0..c02c72bae 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -250,9 +250,11 @@ $.extend(fixmystreet.utils, { marker_size: function() { var zoom = fixmystreet.map.getZoom() + fixmystreet.zoomOffset; - if (zoom >= 15) { + var size_normal = fixmystreet.maps.zoom_for_normal_size || 15; + var size_small = fixmystreet.maps.zoom_for_small_size || 13; + if (zoom >= size_normal) { return window.selected_problem_id ? 'small' : 'normal'; - } else if (zoom >= 13) { + } else if (zoom >= size_small) { return window.selected_problem_id ? 'mini' : 'small'; } else { return 'mini'; @@ -261,9 +263,11 @@ $.extend(fixmystreet.utils, { selected_marker_size: function() { var zoom = fixmystreet.map.getZoom() + fixmystreet.zoomOffset; - if (zoom >= 15) { + var size_normal = fixmystreet.maps.zoom_for_normal_size || 15; + var size_small = fixmystreet.maps.zoom_for_small_size || 13; + if (zoom >= size_normal) { return 'big'; - } else if (zoom >= 13) { + } else if (zoom >= size_small) { return 'normal'; } else { return 'small'; -- cgit v1.2.3 From 88ad6b00dfc050db1ba5ae9bf14b900382cd24a7 Mon Sep 17 00:00:00 2001 From: Dave Arter Date: Mon, 16 Dec 2019 17:31:41 +0000 Subject: Display GPS marker on /around & /report/new if geolocate link used Attempts to allow for CSS animations by not destroying the marker's DOM element each time a location update is received - with limited success. --- web/js/map-OpenLayers.js | 94 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index eb62904b0..7781d845b 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -375,6 +375,96 @@ $.extend(fixmystreet.utils, { new OpenLayers.LonLat( state.lon, state.lat ), state.zoom ); + }, + + setup_geolocation: function() { + if (!OpenLayers.Control.Geolocate || !fixmystreet.map || + !fixmystreet.utils || !fixmystreet.utils.parse_query_string || + fixmystreet.utils.parse_query_string().geolocate !== '1' + ) { + return; + } + + var layer; + + function createCircleOfUncertainty(e) { + var loc = new OpenLayers.Geometry.Point(e.point.x, e.point.y); + return new OpenLayers.Feature.Vector( + OpenLayers.Geometry.Polygon.createRegularPolygon( + loc, + e.position.coords.accuracy, + 40, + 0 + ), + {}, + { + fillColor: '#0074FF', + fillOpacity: 0.3, + strokeWidth: 0 + } + ); + } + function addGeolocationLayer(e) { + layer = new OpenLayers.Layer.Vector('Geolocation'); + fixmystreet.map.addLayer(layer); + layer.setZIndex(fixmystreet.map.getLayersByName("Pins")[0].getZIndex() - 1); + var marker = new OpenLayers.Feature.Vector( + new OpenLayers.Geometry.Point(e.point.x, e.point.y), + { + marker: true + }, + { + graphicName: 'circle', + strokeColor: '#fff', + strokeWidth: 4, + fillColor: '#0074FF', + fillOpacity: 1, + pointRadius: 10 + } + ); + layer.addFeatures([ createCircleOfUncertainty(e), marker ]); + } + + function updateGeolocationMarker(e) { + if (!layer) { + addGeolocationLayer(e); + } else { + // Reuse the existing circle marker so its DOM element (and + // hopefully CSS animation) is preserved. + var marker = layer.getFeaturesByAttribute('marker', true)[0]; + // Can't reuse the background circle feature as there seems to + // be no easy way to replace its geometry with a new + // circle sized according to this location update's accuracy. + // Instead recreate the feature from scratch. + var uncertainty = createCircleOfUncertainty(e); + // Because we're replacing the accuracy circle, it needs to be + // rendered underneath the location marker. In order to do this + // we have to remove all features and re-add, as simply removing + // and re-adding one feature will always render it on top of others. + layer.removeAllFeatures(); + layer.addFeatures([ uncertainty, marker ]); + + // NB The above still breaks CSS animation because the marker + // was removed from the DOM and re-added. We could leave the + // marker alone and just remove the uncertainty circle + // feature, re-add it as a new feature and then manually shift + // its position in the DOM by getting its element's ID from + // uncertainty.geometry.id and moving it before the + // element. + + // Don't forget to update the position of the GPS marker. + marker.move(new OpenLayers.LonLat(e.point.x, e.point.y)); + } + } + + var control = new OpenLayers.Control.Geolocate({ + bind: false, // Don't want the map to pan to each location + watch: true, + enableHighAccuracy: true + }); + control.events.register("locationupdated", null, updateGeolocationMarker); + fixmystreet.map.addControl(control); + control.activate(); } }); @@ -787,6 +877,10 @@ $.extend(fixmystreet.utils, { setup_inspector_marker_drag(); } + if (fixmystreet.page == "around" || fixmystreet.page == "new") { + fixmystreet.maps.setup_geolocation(); + } + if ( fixmystreet.zoomToBounds ) { zoomToBounds( fixmystreet.markers.getDataExtent() ); } -- cgit v1.2.3 From 757cacc10f51a9c54d02c392e9e39e23202dac72 Mon Sep 17 00:00:00 2001 From: Dave Arter Date: Wed, 8 Jan 2020 17:11:05 +0000 Subject: Reduce duplicate Permalink.updateLink calls when zooming map --- web/js/map-OpenLayers.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 4af5e61d4..a10e13378 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -1108,6 +1108,24 @@ OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink, updateLink: function() { this._updateLink(0); }, + draw: function() { + OpenLayers.Control.Permalink.prototype.draw.apply(this, arguments); + + // fms.com has so many layers now that zooming events were causing + // enough quick-fire history.replaceState calls (in updateLink) + // that iOS Safari was raising "SecurityError: Attempt to use + // history.replaceState() more than 100 times per 30 seconds" errors, + // as well as being throttled on Chrome on Android. Zooming in causes + // lots of layers to come into range simultaneously, and each was + // triggering the 'changelayer' event. In our use we don't include the + // layers state string in the permalink URL (see `delete params.layers` + // above), so there's no need to listen to those events. + this.map.events.un({ + 'changelayer': this.updateLink, + 'changebaselayer': this.updateLink, + scope: this + }); + }, CLASS_NAME: "OpenLayers.Control.PermalinkFMS" }); -- cgit v1.2.3 From 3abb9d14c6879d0dca1f88329ea4bcf6b31d44ee Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Thu, 9 Jan 2020 17:22:56 +0000 Subject: Use our own Permalink class. We are overriding quite a bit of it and not using other bits, so it will be less code to only have our own Control. --- web/js/map-OpenLayers.js | 126 +++++++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 53 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index a10e13378..a8aa7f096 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -1049,51 +1049,61 @@ OpenLayers.Control.ArgParserFMS = OpenLayers.Class(OpenLayers.Control.ArgParser, CLASS_NAME: "OpenLayers.Control.ArgParserFMS" }); -/* Overriding Permalink so that it can pass the correct zoom to OSM */ -OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink, { - _updateLink: function(alter_zoom) { - // this.base was originally set in initialize(), but the window's href - // may have changed since then if e.g. the map filters have been updated. - // NB this won't change the base of the 'problems nearby' permalink on - // /report, as this would result in it pointing at the wrong page. - if (this.base !== '/around' && fixmystreet.page !== 'report') { - this.base = window.location.href; - } +/* Replacing Permalink so that it can do things a bit differently */ +OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control, { + element: null, + base: '', + + initialize: function(element, base, options) { + OpenLayers.Control.prototype.initialize.apply(this, [options]); + this.element = OpenLayers.Util.getElement(element); + this.base = base || document.location.href; + }, - var separator = this.anchor ? '#' : '?'; - var href = this.base; - if (href.indexOf(separator) != -1) { - href = href.substring( 0, href.indexOf(separator) ); + destroy: function() { + if (this.map) { + this.map.events.unregister('moveend', this, this.updateLink); } + OpenLayers.Control.prototype.destroy.apply(this, arguments); + }, - var center = this.map.getCenter(); + draw: function() { + OpenLayers.Control.prototype.draw.apply(this, arguments); - var zoom = this.map.getZoom(); - if ( alter_zoom ) { - zoom += fixmystreet.zoomOffset; - } + // We do not need to listen to change layer events, no layers in our permalinks + this.map.events.on({ + 'moveend': this.updateLink, + scope: this + }); - var params = this.createParams(center, zoom); + // Make it so there is at least a link even though the map may not have + // moved yet. + this.updateLink(); - // Strip out the ugly OpenLayers layers state string - delete params.layers; - if (params.lat && params.lon) { - // No need for the postcode string either, if we have a latlon - delete params.pc; + return this.div; + }, + + updateLink: function() { + // The window's href may have changed if e.g. the map filters have been + // updated. NB this won't change the base of the 'problems nearby' + // permalink on /report, as this would result in it pointing at the + // wrong page. + var href = this.base; + if (this.base !== '/around' && fixmystreet.page !== 'report') { + href = window.location.href; } + var params = this.createParams(href); - href += separator + OpenLayers.Util.getParameterString(params); + if (href.indexOf('?') != -1) { + href = href.substring( 0, href.indexOf('?') ); + } + href += '?' + OpenLayers.Util.getParameterString(params); // Could use mlat/mlon here as well if we are on a page with a marker - if (this.base == '/around') { + if (this.base === '/around') { href += '&js=1'; } - if (this.anchor && !this.element) { - window.location.href = href; - } - else { - this.element.href = href; - } + this.element.href = href; if ('replaceState' in history) { if (fixmystreet.page.match(/around|reports/)) { @@ -1105,27 +1115,37 @@ OpenLayers.Control.PermalinkFMS = OpenLayers.Class(OpenLayers.Control.Permalink, } } }, - updateLink: function() { - this._updateLink(0); - }, - draw: function() { - OpenLayers.Control.Permalink.prototype.draw.apply(this, arguments); - - // fms.com has so many layers now that zooming events were causing - // enough quick-fire history.replaceState calls (in updateLink) - // that iOS Safari was raising "SecurityError: Attempt to use - // history.replaceState() more than 100 times per 30 seconds" errors, - // as well as being throttled on Chrome on Android. Zooming in causes - // lots of layers to come into range simultaneously, and each was - // triggering the 'changelayer' event. In our use we don't include the - // layers state string in the permalink URL (see `delete params.layers` - // above), so there's no need to listen to those events. - this.map.events.un({ - 'changelayer': this.updateLink, - 'changebaselayer': this.updateLink, - scope: this - }); + + createParams: function(href) { + center = this.map.getCenter(); + + var params = OpenLayers.Util.getParameters(href); + + // If there's still no center, map is not initialized yet. + // Break out of this function, and simply return the params from the + // base link. + if (center) { + + params.zoom = this.map.getZoom(); + + var mapPosition = OpenLayers.Projection.transform( + { x: center.lon, y: center.lat }, + this.map.getProjectionObject(), + this.map.displayProjection ); + var lon = mapPosition.x; + var lat = mapPosition.y; + params.lat = Math.round(lat*100000)/100000; + params.lon = Math.round(lon*100000)/100000; + } + + if (params.lat && params.lon) { + // No need for the postcode string either, if we have a latlon + delete params.pc; + } + + return params; }, + CLASS_NAME: "OpenLayers.Control.PermalinkFMS" }); -- cgit v1.2.3 From fa94f1d01dfa350243f40621501e4b497be7455e Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 28 Jan 2020 13:32:15 +0000 Subject: Restrict lat/lon in URL/fields to 6dp. --- web/js/map-OpenLayers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index a8aa7f096..6142b3e23 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -132,8 +132,8 @@ $.extend(fixmystreet.utils, { new OpenLayers.Projection("EPSG:4326") ); - var lat = transformedLonlat.lat; - var lon = transformedLonlat.lon; + var lat = transformedLonlat.lat.toFixed(6); + var lon = transformedLonlat.lon.toFixed(6); document.getElementById('fixmystreet.latitude').value = lat; document.getElementById('fixmystreet.longitude').value = lon; -- cgit v1.2.3 From 1b8f50e5a3ea0a08c88cc5676467743ab03741b2 Mon Sep 17 00:00:00 2001 From: Struan Donald Date: Mon, 9 Dec 2019 17:13:10 +0000 Subject: base files for displaying WMS maps Basic config and setup files for using WMS based map tiles. These still require config in appropriate cobrand perl and javascript files --- web/js/map-OpenLayers.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'web/js/map-OpenLayers.js') diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js index 6142b3e23..182cd79a1 100644 --- a/web/js/map-OpenLayers.js +++ b/web/js/map-OpenLayers.js @@ -943,10 +943,23 @@ $.extend(fixmystreet.utils, { // This option is thankfully used by them both numZoomLevels: fixmystreet.numZoomLevels }, fixmystreet.layer_options[i]); - if (fixmystreet.layer_options[i].matrixIds) { - layer = new fixmystreet.map_type(fixmystreet.layer_options[i]); + var layer_options = fixmystreet.layer_options[i]; + if (layer_options.wms_version) { + var options = { + layers: layer_options.layer_names[0], + size: layer_options.tile_size, + format: layer_options.format + }; + layer = new fixmystreet.map_type( + layer_options.name, + layer_options.url, + options, + layer_options + ); + } else if (layer_options.matrixIds) { + layer = new fixmystreet.map_type(layer_options); } else { - layer = new fixmystreet.map_type(fixmystreet.layer_name, fixmystreet.layer_options[i]); + layer = new fixmystreet.map_type(fixmystreet.layer_name, layer_options); } fixmystreet.map.addLayer(layer); } -- cgit v1.2.3