aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--web/cobrands/fixmystreet/assets.js97
-rw-r--r--web/cobrands/fixmystreet/fixmystreet.js3
-rw-r--r--web/js/map-OpenLayers.js21
3 files changed, 105 insertions, 16 deletions
diff --git a/web/cobrands/fixmystreet/assets.js b/web/cobrands/fixmystreet/assets.js
index d5dd3bc32..600cd6ab8 100644
--- a/web/cobrands/fixmystreet/assets.js
+++ b/web/cobrands/fixmystreet/assets.js
@@ -4,6 +4,8 @@ var fixmystreet = fixmystreet || {};
var selected_feature = null;
var fault_popup = null;
+var selected_usrn = null;
+var usrn_field = null;
function close_fault_popup() {
if (!!fault_popup) {
@@ -32,6 +34,11 @@ function asset_selected(e) {
return;
}
+ // Pick up the USRN for the location of this asset. NB we do this *before*
+ // handling the attributes on the selected feature in case the feature has
+ // its own USRN which should take precedence.
+ fixmystreet.assets.select_usrn(lonlat);
+
// Set the extra field to the value of the selected feature
$.each(this.fixmystreet.attributes, function (field_name, attribute_name) {
var field_value;
@@ -164,18 +171,9 @@ function select_nearest_asset() {
// No marker to be found so bail out
return;
}
- var closest_feature;
- var closest_distance = null;
- for (var i = 0; i < this.features.length; i++) {
- var candidate = this.features[i];
- var distance = candidate.geometry.distanceTo(marker.geometry);
- if (closest_distance === null || distance < closest_distance) {
- closest_feature = candidate;
- closest_distance = distance;
- }
- }
- if (closest_distance <= threshold && !!closest_feature) {
- get_select_control(this).select(closest_feature);
+ var nearest_feature = this.getNearestFeature(marker.geometry, threshold);
+ if (nearest_feature) {
+ get_select_control(this).select(nearest_feature);
}
}
@@ -443,6 +441,35 @@ fixmystreet.assets = {
fixmystreet.map.addControl(fixmystreet.assets.controls[i]);
fixmystreet.assets.controls[i].activate();
}
+ },
+
+ select_usrn: function(lonlat) {
+ var usrn_providers = fixmystreet.map.getLayersBy('fixmystreet', {
+ test: function(options) {
+ return options && options.usrn;
+ }
+ });
+ if (usrn_providers.length) {
+ var usrn_layer = usrn_providers[0];
+ usrn_field = usrn_layer.fixmystreet.usrn.field;
+ var point = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat);
+ var feature = usrn_layer.getFeatureAtPoint(point);
+ if (feature == null) {
+ // The click wasn't directly over a road, try and find one
+ // nearby
+ feature = usrn_layer.getNearestFeature(point, 10);
+ }
+ if (feature !== null) {
+ selected_usrn = feature.attributes[usrn_layer.fixmystreet.usrn.attribute];
+ } else {
+ selected_usrn = null;
+ }
+ fixmystreet.assets.update_usrn_field();
+ }
+ },
+
+ update_usrn_field: function() {
+ $("input[name="+usrn_field+"]").val(selected_usrn);
}
};
@@ -450,4 +477,50 @@ $(function() {
fixmystreet.assets.init();
});
+OpenLayers.Layer.Vector.prototype.getFeatureAtPoint = function(point) {
+ for (var i = 0; i < this.features.length; i++) {
+ var feature = this.features[i];
+ if (!feature.geometry || !feature.geometry.containsPoint) {
+ continue;
+ }
+ if (feature.geometry.containsPoint(point)) {
+ return feature;
+ }
+ }
+ return null;
+};
+
+
+/*
+ * Returns this layer's feature that's closest to the given
+ * OpenLayers.Geometry.Point, as long as it's within <threshold> metres.
+ * Returns null if no feature meeting these criteria is found.
+ */
+OpenLayers.Layer.Vector.prototype.getNearestFeature = function(point, threshold) {
+ var nearest_feature = null;
+ var nearest_distance = null;
+ for (var i = 0; i < this.features.length; i++) {
+ var candidate = this.features[i];
+ if (!candidate.geometry || !candidate.geometry.distanceTo) {
+ continue;
+ }
+ var details = candidate.geometry.distanceTo(point, {details: true});
+ if (nearest_distance === null || details.distance < nearest_distance) {
+ nearest_distance = details.distance;
+ // The units used for details.distance aren't metres, they're
+ // whatever the map projection uses. Convert to metres in order to
+ // draw a meaningful comparison to the threshold value.
+ var p1 = new OpenLayers.Geometry.Point(details.x0, details.y0);
+ var p2 = new OpenLayers.Geometry.Point(details.x1, details.y1);
+ var line = new OpenLayers.Geometry.LineString([p1, p2]);
+ var distance_m = line.getGeodesicLength(this.map.getProjectionObject());
+
+ if (distance_m <= threshold) {
+ nearest_feature = candidate;
+ }
+ }
+ }
+ return nearest_feature;
+};
+
})();
diff --git a/web/cobrands/fixmystreet/fixmystreet.js b/web/cobrands/fixmystreet/fixmystreet.js
index 0aa01e483..c7bbc8cad 100644
--- a/web/cobrands/fixmystreet/fixmystreet.js
+++ b/web/cobrands/fixmystreet/fixmystreet.js
@@ -417,6 +417,9 @@ $.extend(fixmystreet.set_up, {
} else {
$category_meta.empty();
}
+ if (fixmystreet.assets) {
+ fixmystreet.assets.update_usrn_field();
+ }
});
if (fixmystreet.hooks.update_problem_fields) {
diff --git a/web/js/map-OpenLayers.js b/web/js/map-OpenLayers.js
index 0f6cca2b5..5ebb9a18e 100644
--- a/web/js/map-OpenLayers.js
+++ b/web/js/map-OpenLayers.js
@@ -40,19 +40,32 @@ $.extend(fixmystreet.utils, {
};
$.extend(fixmystreet.maps, {
- // This function might be passed either an OpenLayers.LonLat (so has
- // lon and lat), or an OpenLayers.Geometry.Point (so has x and y).
update_pin: function(lonlat) {
+ // This function might be passed either an OpenLayers.LonLat (so has
+ // lon and lat), or an OpenLayers.Geometry.Point (so has x and y).
+ if (lonlat.x !== undefined && lonlat.y !== undefined) {
+ // It's a Point, convert to a LatLon
+ lonlat = new OpenLayers.LonLat(lonlat.x, lonlat.y);
+ }
+
var transformedLonlat = lonlat.clone().transform(
fixmystreet.map.getProjectionObject(),
new OpenLayers.Projection("EPSG:4326")
);
- var lat = transformedLonlat.lat || transformedLonlat.y;
- var lon = transformedLonlat.lon || transformedLonlat.x;
+ var lat = transformedLonlat.lat;
+ var lon = transformedLonlat.lon;
document.getElementById('fixmystreet.latitude').value = lat;
document.getElementById('fixmystreet.longitude').value = lon;
+
+ // This tight coupling isn't ideal. A better solution would be for the
+ // asset code to register an event handler somewhere, but the correct
+ // place isn't apparent.
+ if (fixmystreet.assets) {
+ fixmystreet.assets.select_usrn(lonlat);
+ }
+
return {
'url': { 'lon': lon, 'lat': lat },
'state': { 'lon': lonlat.lon, 'lat': lonlat.lat }