aboutsummaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorStruan Donald <struan@exo.org.uk>2019-01-17 17:35:09 +0000
committerStruan Donald <struan@exo.org.uk>2019-03-25 14:40:52 +0000
commitdf452727860a9597d83e615b10dfb00e0f9ad8e4 (patch)
tree5c73680e5de976bfcf3ba265dd60754d3e6ffb43 /web
parent4b1d07e90966994e13245fd1323d65a0d1dd2457 (diff)
[Northamptonshire] use Alloy vector tiles for assets
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
Diffstat (limited to 'web')
-rw-r--r--web/cobrands/fixmystreet-uk-councils/alloy.js127
-rw-r--r--web/cobrands/fixmystreet/assets.js10
-rw-r--r--web/cobrands/northamptonshire/assets.js481
3 files changed, 616 insertions, 2 deletions
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<len; ++i) {
+ geom = features[i].geometry;
+ if(geom) {
+ geom.transform(remote, local);
+ }
+ }
+ }
+ this.layer.addFeatures(features);
+ }
+ } else {
+ this.bounds = null;
+ }
+ // only fire loadend things if we've got all the tiles
+ if (this.count == this.max) {
+ if ( this.layer.checkFeature ) {
+ this.layer.checkFeature(null, fixmystreet.get_lonlat_from_dom());
+ }
+ this.layer.events.triggerEvent("loadend", {response: resp});
+ }
+ },
+
+});
+
+fixmystreet.assets.alloy_defaults = {
+ http_options: {
+ base: "https://alloy-api-tile01.yotta.co.uk/api/render-layer/tile/${layerid}/28/${layerVersion}-/${z}/${x}/${y}",
+ },
+ format_class: OpenLayers.Format.GeoJSON,
+ srsName: "EPSG:3857",
+ strategy_class: OpenLayers.Strategy.Alloy
+};
+
+})();
diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js
index 1761e6a3e..d22db7bed 100644
--- a/web/cobrands/fixmystreet/assets.js
+++ b/web/cobrands/fixmystreet/assets.js
@@ -190,7 +190,12 @@ OpenLayers.Layer.VectorNearest = OpenLayers.Class(OpenLayers.Layer.VectorAsset,
updateUSRNField: function() {
if (this.fixmystreet.usrn) {
var usrn_field = this.fixmystreet.usrn.field;
- var selected_usrn = this.selected_feature ? this.selected_feature.attributes[this.fixmystreet.usrn.attribute] : '';
+ var selected_usrn;
+ if ( this.selected_feature ) {
+ selected_usrn = this.fixmystreet.getUSRN ?
+ this.fixmystreet.getUSRN(this.selected_feature) :
+ this.selected_feature.attributes[this.fixmystreet.usrn.attribute];
+ }
$("input[name=" + usrn_field + "]").val(selected_usrn);
}
},
@@ -521,7 +526,8 @@ fixmystreet.assets = {
options.format_options.geometryName = options.geometryName;
}
protocol_options.format = new options.format_class(options.format_options);
- protocol = new OpenLayers.Protocol.HTTP(protocol_options);
+ var protocol_class = options.protocol_class || OpenLayers.Protocol.HTTP;
+ protocol = new protocol_class(protocol_options);
} else {
protocol_options = {
version: "1.1.0",
diff --git a/web/cobrands/northamptonshire/assets.js b/web/cobrands/northamptonshire/assets.js
new file mode 100644
index 000000000..2b35de674
--- /dev/null
+++ b/web/cobrands/northamptonshire/assets.js
@@ -0,0 +1,481 @@
+(function(){
+
+if (!fixmystreet.maps) {
+ return;
+}
+
+
+var layers = [
+ /*
+{
+ "layer_name": "Street Lights",
+ "layer": 5,
+ "version": "5.4-9.6-"
+},
+{
+ "layer_name": "Street Lighting Nightscape",
+ "layer": 9,
+ "version": "9.6-"
+},
+{
+ "layer_name": "Carriageways",
+ "layer": 20,
+ "version": "20.54-"
+},
+{
+ "layer_name": "Road Heirarchy",
+ "layer": 39,
+ "version": "39.53-"
+},
+{
+ "layer_name": "Posts",
+ "layer": 59,
+ "version": "59.133-"
+},
+{
+ "layer_name": "Grips",
+ "layer": 61,
+ "version": "61.1-"
+},
+{
+ "layer_name": "Traffic Monitoring",
+ "layer": 62,
+ "version": "62.2-"
+},
+{
+ "layer_name": "Special Treatment",
+ "layer": 64,
+ "version": "64.1-"
+},
+{
+ "layer_name": "Gully",
+ "layer": 66,
+ "version": "66.9-"
+},
+{
+ "layer_name": "Channel",
+ "layer": 68,
+ "version": "68.2-"
+},
+{
+ "layer_name": "Comms Cabinet",
+ "layer": 69,
+ "version": "69.1-"
+},
+{
+ "layer_name": "Steps",
+ "layer": 70,
+ "version": "70.1-"
+},
+{
+ "layer_name": "Step Handrail",
+ "layer": 71,
+ "version": "71.1-"
+},
+{
+ "layer_name": "Tree Group",
+ "layer": 74,
+ "version": "74.1-"
+},
+{
+ "layer_name": "Defects Ancillary Items",
+ "layer": 171,
+ "version": "171.33-"
+},
+{
+ "layer_name": "Speed Limit",
+ "layer": 172,
+ "version": "172.33-"
+},
+{
+ "layer_name": "PRoW Network",
+ "layer": 173,
+ "version": "173.1-"
+},
+{
+ "layer_name": "Footway Schemes",
+ "layer": 174,
+ "version": "174.1-"
+},
+{
+ "layer_name": "FINGER POST",
+ "layer": 178,
+ "version": "178.39-"
+},
+{
+ "layer_name": "GAPS",
+ "layer": 179,
+ "version": "179.1-"
+},
+{
+ "layer_name": "OBSTRUCTIONS",
+ "layer": 182,
+ "version": "182.2-"
+},
+{
+ "layer_name": "STEPS",
+ "layer": 184,
+ "version": "184.2-"
+},
+{
+ "layer_name": "Gate Types",
+ "layer": 191,
+ "version": "191.2-"
+},
+{
+ "layer_name": "Gate Condition",
+ "layer": 192,
+ "version": "192.2-"
+},
+{
+ "layer_name": "Bridge Type",
+ "layer": 193,
+ "version": "193.17-"
+},
+{
+ "layer_name": "Bridge Condition",
+ "layer": 194,
+ "version": "194.17-"
+},
+{
+ "layer_name": "PRoW Net By Type",
+ "layer": 201,
+ "version": "201.1-"
+},
+{
+ "layer_name": "Finger Post Condition",
+ "layer": 209,
+ "version": "209.39-"
+},
+{
+ "layer_name": "F Post Path Type",
+ "layer": 210,
+ "version": "210.39-"
+},
+{
+ "layer_name": "AW_Sewer",
+ "layer": 215,
+ "version": "215.1-"
+},
+{
+ "layer_name": "CCTV",
+ "layer": 218,
+ "version": "218.1-"
+},
+{
+ "layer_name": "VMS",
+ "layer": 219,
+ "version": "219.1-"
+},
+{
+ "layer_name": "Warning Signs",
+ "layer": 220,
+ "version": "220.1-"
+},
+{
+ "layer_name": "Traffic Calming",
+ "layer": 221,
+ "version": "221.1-"
+},
+{
+ "layer_name": "Bluetooth Counter",
+ "layer": 222,
+ "version": "222.1-"
+},
+{
+ "layer_name": "Midblock",
+ "layer": 223,
+ "version": "223.1-"
+},
+{
+ "layer_name": "Over Height",
+ "layer": 224,
+ "version": "224.1-"
+},
+{
+ "layer_name": "RTI Display",
+ "layer": 226,
+ "version": "226.1-"
+},
+{
+ "layer_name": "System Links",
+ "layer": 227,
+ "version": "227.1-"
+},
+{
+ "layer_name": "CULVERTS (PRoW)",
+ "layer": 229,
+ "version": "229.1-"
+},
+{
+ "layer_name": "PEDESTRIAN GUARDRAIL",
+ "layer": 230,
+ "version": "230.1-"
+},
+{
+ "layer_name": "Traffic Signal Controller",
+ "layer": 231,
+ "version": "231.1-"
+},
+{
+ "layer_name": "Traffic Signal Posts",
+ "layer": 232,
+ "version": "232.1-"
+},
+ */
+{
+ "categories": [ "Grit Bin - damaged/replacement", "Grit Bin - empty/refill" ],
+ "item_name": "grit bin",
+ "layer_name": "Grit Bins",
+ "layer": 13,
+ "version": "13.7-"
+},
+{
+ "categories": [ "Highway Bridges - Damaged/Unsafe" ],
+ "asset_type": 'area',
+ "item_name": 'bridge',
+ "layer_name": "Structures",
+ "layer": 14,
+ "version": "14.3-"
+},
+{
+ "categories": [ "Damaged / Missing / Facing Wrong Way", "Obscured by vegetation or Dirty" ],
+ "item_name": "sign",
+ "layer_name": "Signs",
+ "layer": 303,
+ "version": "303.1-"
+},
+{
+ "categories": [ "Shelter Damaged", "Sign/Pole Damaged" ],
+ "layer_name": "Bus Stop",
+ "layer": 72,
+ "version": "72.8-"
+},
+{
+ "categories": [ "Bridge-Damaged/ Missing" ],
+ "item_name": "bridge",
+ "layer_name": "BRIDGES",
+ "layer": 177,
+ "version": "177.18-"
+},
+{
+ "categories": [ "Gate - Damaged/ Missing" ],
+ "layer_name": "GATE",
+ "layer": 181,
+ "version": "181.3-"
+},
+{
+ "categories": [ "Stile-Damaged/Missing" ],
+ "layer_name": "STILE",
+ "layer": 185,
+ "version": "185.3-"
+},
+{
+ "categories": [ "Sign/Waymarking - Damaged/Missing" ],
+ "item_name": "waymarking",
+ "layer_name": "WAYMARK POST",
+ "layer": 187,
+ "version": "187.3-"
+},
+{
+ "categories": [
+ "Damaged/Exposed Wiring / Vandalised",
+ "Lamp/Bulb Failure",
+ "Signal Failure",
+ "Signal Failure all out",
+ "Signal Stuck",
+ "Signal Head Failure",
+ "Request Timing Review",
+ "Damaged Control box",
+ "Signal Failure/Damaged - Toucan/Pelican",
+ ],
+ "item_name": "signal or crossing",
+ "layer_name": "TL Junction",
+ "layer": 225,
+ "version": "225.5-"
+},
+{
+ "categories": [
+ "Fallen Tree",
+ "Restricted Visibility / Overgrown / Overhanging",
+ "Restricted Visibility",
+ ],
+ "layer_name": "Tree",
+ "layer": 228,
+ "version": "228.24-"
+},
+{
+ "categories": [ "Safety Bollard - Damaged/Missing" ],
+ "layer_name": "Safety Bollard",
+ "layer": 233,
+ "version": "233.27-"
+},
+];
+
+$.each(layers, function(index, layer) {
+ if ( layer.categories ) {
+ fixmystreet.assets.add($.extend(true, {}, fixmystreet.assets.alloy_defaults, {
+ protocol: OpenLayers.Protocol.Alloy,
+ http_options: {
+ layerid: layer.layer,
+ layerVersion: layer.version,
+ },
+ non_interactive: false,
+ asset_type: layer.asset_type || 'spot',
+ body: "Northamptonshire County Council",
+ asset_category: layer.categories,
+ asset_item: layer.item_name || layer.layer_name.toLowerCase(),
+ attributes: {
+ asset_resource_id: function() {
+ return this.fid;
+ }
+ }
+ }));
+ }
+});
+
+fixmystreet.assets.add($.extend(true, {}, fixmystreet.assets.alloy_defaults, {
+ protocol: OpenLayers.Protocol.Alloy,
+ http_options: {
+ layerid: 221,
+ layerVersion: '221.4-',
+ },
+ body: "Northamptonshire County Council",
+ road: true,
+ asset_type: "area",
+ always_visible: false,
+ non_interactive: true,
+ asset_category: [
+ "Damaged Speed Humps",
+ ],
+ usrn: {
+ attribute: 'fid',
+ field: 'asset_resource_id'
+ },
+ getUSRN: function(feature) {
+ return feature.fid;
+ }
+}));
+
+var barrier_style = new OpenLayers.Style({
+ fill: false,
+ strokeColor: "#555555",
+ strokeOpacity: 1,
+ strokeWidth: 4
+});
+
+fixmystreet.assets.add($.extend(true, {}, northants_defaults, {
+ protocol_class: OpenLayers.Protocol.Alloy,
+ http_options: {
+ layerid: 230,
+ layerVersion: '230.2-',
+ },
+ stylemap: new OpenLayers.StyleMap({
+ 'default': barrier_style
+ }),
+ body: "Northamptonshire County Council",
+ road: true,
+ always_visible: false,
+ non_interactive: true,
+ asset_category: [
+ "Pedestrian Barriers - Damaged / Missing",
+ ],
+ usrn: {
+ attribute: 'fid',
+ field: 'asset_resource_id'
+ },
+ getUSRN: function(feature) {
+ return feature.fid;
+ }
+}));
+
+var highways_style = new OpenLayers.Style({
+ fill: false,
+ strokeColor: "#111111",
+ strokeOpacity: 0.1,
+ strokeWidth: 7
+});
+
+fixmystreet.assets.add($.extend(true, {}, fixmystreet.assets.alloy_defaults, {
+ protocol: OpenLayers.Protocol.Alloy,
+ http_options: {
+ layerid: 308,
+ layerVersion: '308.8-',
+ },
+ stylemap: new OpenLayers.StyleMap({
+ 'default': highways_style
+ }),
+ body: "Northamptonshire County Council",
+ road: true,
+ always_visible: false,
+ non_interactive: true,
+ asset_category: [
+ "Loose / Raised/Sunken",
+ "Broken / Missing",
+ "Blocked - flooding private property",
+ "Blocked - flooding road/path",
+ "Blocked/Damaged",
+ "Blocked Ditch",
+ "Blocked Ditch Causing Flooding",
+ "Obstruction (Not Vegetation)",
+ "Pothole / Failed Reinstatement",
+ "Slabs - Uneven / Damaged / Cracked",
+ "Slabs - Missing",
+ "Damaged/Loose",
+ "Missing",
+ "Crash Barriers - Damaged / Missing",
+ "Road Markings - Worn/Faded",
+ "Flooding",
+ "Mud on Road",
+ "Potholes / Highway Condition",
+ "Spill - Oil/Diesel",
+ "Damaged/Missing",
+ "Weeds",
+ "Verges - Damaged by Vehicles",
+ "Icy Footpath",
+ "Icy Road",
+ "Missed published Gritted Route",
+ ],
+ usrn: {
+ attribute: 'fid',
+ field: 'asset_resource_id'
+ },
+ getUSRN: function(feature) {
+ return feature.fid;
+ }
+}));
+
+var prow_style = new OpenLayers.Style({
+ fill: false,
+ strokeColor: "#115511",
+ strokeOpacity: 0.1,
+ strokeWidth: 7
+});
+
+fixmystreet.assets.add($.extend(true, {}, fixmystreet.assets.alloy_defaults, {
+ protocol_class: OpenLayers.Protocol.Alloy,
+ http_options: {
+ layerid: 173,
+ layerVersion: '173.1-',
+ },
+ stylemap: new OpenLayers.StyleMap({
+ 'default': prow_style
+ }),
+ body: "Northamptonshire County Council",
+ road: true,
+ always_visible: false,
+ non_interactive: true,
+ asset_category: [
+ "Livestock",
+ "Passage-Obstructed/Overgrown"
+ ],
+ usrn: {
+ attribute: 'fid',
+ field: 'asset_resource_id'
+ },
+ getUSRN: function(feature) {
+ return feature.fid;
+ }
+}));
+
+})();