From df452727860a9597d83e615b10dfb00e0f9ad8e4 Mon Sep 17 00:00:00 2001 From: Struan Donald Date: Thu, 17 Jan 2019 17:35:09 +0000 Subject: [Northamptonshire] use Alloy vector tiles for assets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the Vector tiles layers which Alloy provided which don't require and API key or paging. This code is still a bit work in progress as it makes a few assumptions: * the zoom level is hard coded * adding assets to layers assumes things are not async when they are * we are using itemId which is not the correct thing This uses an event to notify that loading a request for a new set of tiles has started and then uses counting to check we've fetched them all and hence can get the layer to check for an asset. It also uses start times to throw away requests for tiles in a previous request if they come in after a new request has started. This also doesn't have anything for putting labels on assets because that information doesn't seem to be in the tiles. A final point is that the tiles can contain multiple assets at the same coőrdinates and we don't do anything about that at the moment so the user will just get the last one added when they click. This includes a dump of all the layers from alloy and then matches them up to categories displayed on FixMyStreet --- .../web/northamptonshire/footer_extra_js.html | 8 + web/cobrands/fixmystreet-uk-councils/alloy.js | 127 ++++++ web/cobrands/fixmystreet/assets.js | 10 +- web/cobrands/northamptonshire/assets.js | 481 +++++++++++++++++++++ 4 files changed, 624 insertions(+), 2 deletions(-) create mode 100644 templates/web/northamptonshire/footer_extra_js.html create mode 100644 web/cobrands/fixmystreet-uk-councils/alloy.js create mode 100644 web/cobrands/northamptonshire/assets.js diff --git a/templates/web/northamptonshire/footer_extra_js.html b/templates/web/northamptonshire/footer_extra_js.html new file mode 100644 index 000000000..8ea4eb06b --- /dev/null +++ b/templates/web/northamptonshire/footer_extra_js.html @@ -0,0 +1,8 @@ +[% scripts.push( + version('/cobrands/fixmystreet/assets.js'), + version('/cobrands/fixmystreet-uk-councils/alloy.js'), + version('/vendor/OpenLayers.Projection.OrdnanceSurvey.js'), + version('/cobrands/northamptonshire/assets.js'), + version('/cobrands/highways/assets.js'), + version('/cobrands/fixmystreet-uk-councils/council_validation_rules.js'), +) %] diff --git a/web/cobrands/fixmystreet-uk-councils/alloy.js b/web/cobrands/fixmystreet-uk-councils/alloy.js new file mode 100644 index 000000000..064237072 --- /dev/null +++ b/web/cobrands/fixmystreet-uk-councils/alloy.js @@ -0,0 +1,127 @@ +(function(){ + +OpenLayers.Protocol.Alloy = OpenLayers.Class(OpenLayers.Protocol.HTTP, { + read: function(options) { + OpenLayers.Protocol.prototype.read.apply(this, arguments); + options = options || {}; + options.params = OpenLayers.Util.applyDefaults( + options.params, this.options.params); + options = OpenLayers.Util.applyDefaults(options, this.options); + var all_tiles = this.getTileRange_(options.scope.bounds, options.scope.layer.maxExtent, options.scope.layer.map); + var rresp; + var start = new Date(); + var max = all_tiles.length; + $(fixmystreet).trigger('alloy:start_request', [start, max]); + for (var i = 0; i < max; i++) { + var resp = new OpenLayers.Protocol.Response({requestType: "read"}); + resp.start = start; + var url = this.getURL(all_tiles[i], options); + resp.priv = OpenLayers.Request.GET({ + url: url, //options.url, + callback: this.createCallback(this.handleRead, resp, options), + params: options.params, + headers: options.headers + }); + rresp = resp; + } + return rresp; + }, + + getURL: function(coords, options) { + return OpenLayers.String.format(options.base, {'layerid': options.layerid, 'layerVersion': options.layerVersion, 'z': 15, 'x': coords[0], 'y': coords[1]}); + }, + + getTileRange_: function(bounds, maxExtent, map) { + var min = this.getTileCoord_([bounds.left, bounds.top], maxExtent, map, true); + var max = this.getTileCoord_([bounds.right, bounds.bottom], maxExtent, map, false); + var coords = []; + for (var i = min[0], ii = max[0]; i <= ii; ++i) { + for (var j = min[1], jj = max[1]; j <= jj; ++j) { + coords.push([i,j]); + } + } + return coords; + }, + + getTileCoord_: function(bounds, maxExtent, map, reverse) { + var origin = new OpenLayers.LonLat(maxExtent.left, maxExtent.top); + var resolution = map.getResolutionForZoom(3); + + var adjustX = reverse ? 0.5 : 0; + var adjustY = reverse ? 0 : 0.5; + var xFromOrigin = Math.floor((bounds[0] - origin.lon) / resolution + adjustX); + var yFromOrigin = Math.floor((bounds[1] - origin.lat) / resolution + adjustY); + var tileCoordX = Math.floor(xFromOrigin / 512); + var tileCoordY = Math.floor(yFromOrigin / 512) * -1; + + if (reverse) { + tileCoordX -= 1; + tileCoordY -= 1; + } + + return [ tileCoordX, tileCoordY ]; + } +}); + +OpenLayers.Strategy.Alloy = OpenLayers.Class(OpenLayers.Strategy.FixMyStreet, { + count: 0, + max: 0, + requestStart: 0, + initialize: function(name, options) { + OpenLayers.Strategy.FixMyStreet.prototype.initialize.apply(this, arguments); + $(fixmystreet).on('alloy:start_request', this.newRequest.bind(this)); + }, + newRequest: function(evt, start, max) { + this.max = max; + this.requestStart = start; + this.count = 0; + this.layer.destroyFeatures(); + }, + merge: function(resp) { + // because we are issuing async requests it's possible that if someone moves the + // map we've triggered a new set of requests, in which case ignore the old ones. + if (resp.start < this.requestStart) { + return; + } + this.count++; + // This if/else clause lifted from OpenLayers.Strategy.BBOX + if (resp.success()) { + var features = resp.features; + if(features && features.length > 0) { + var remote = this.layer.projection; + var local = this.layer.map.getProjectionObject(); + if(!local.equals(remote)) { + var geom; + for(var i=0, len=features.length; i