diff options
-rw-r--r-- | resources/data.js | 9 | ||||
-rw-r--r-- | resources/map.js | 526 |
2 files changed, 275 insertions, 260 deletions
diff --git a/resources/data.js b/resources/data.js index 85a77c2..e69de29 100644 --- a/resources/data.js +++ b/resources/data.js @@ -1,9 +0,0 @@ -function getVillages(area, zoom) { - var poly = "12.3 -12.3 12.4 -12.3 12.48 -12.25 12.35 -12.19"; - var query = 'data=[out:json];(node(poly:"' + poly + '");<;);out;'; - - converter = new op2geojson(); - converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, function(data) { - - }); -} diff --git a/resources/map.js b/resources/map.js index 3369656..8159514 100644 --- a/resources/map.js +++ b/resources/map.js @@ -48,6 +48,78 @@ function getDataURIForRegion(self, region) { return dataURI; } +function catchmentAreaProperties(catchmentArea, healthPost) { + var settlements = catchmentArea.settlements; + + var format = new OpenLayers.Format.GeoJSON; + var openLayersGeo = format.parseGeometry(catchmentArea.geometry); + + var sumOfDistances = 0; + var maxDistance = 0; + + var Geographic = new OpenLayers.Projection("EPSG:4326"); + var Mercator = new OpenLayers.Projection("EPSG:900913"); + + var healthPostPoint = format.parseGeometry(healthPost.geometry); + if (healthPost.geometry.type == "Point") { + //amenityPoint = new OpenLayers.Geometry.Point(amenity.geometry.coordinates[0], amenity.geometry.coordinates[1]).transform(Geographic, Mercator); + } else { // Its a polygon + healthPostPoint = healthPostPoint.getCentroid(); + } + + _.each(catchmentArea.settlements, function (settlement) { + var settlementGeo = format.parseGeometry(settlement.geometry); + + var distance = settlementGeo.distanceTo(healthPostPoint); + sumOfDistances += distance; + if (distance > maxDistance) + maxDistance = distance; + }); + + var areaInSquareMeters = openLayersGeo.getGeodesicArea(); + var areaString = areaInSquareMeters.toFixed(2) + "m" + "2".sup(); + if (areaInSquareMeters > 1000000) { + areaString = (areaInSquareMeters / 1000000).toFixed(2) + "km" + "2".sup(); + } + + var areaProperties; + if (typeof settlements == "undefined") { + areaProperties = { area: areaString, + number_of_settlements: "Unknown", + population: "Unknown", + greatest_settlement_dist: "Unknown", + average_settlement_dist: "Unknown" + } + } else { + var population = 0; + var numberOfSettlementsWithoutPopulation = 0; + + _.each(settlements, function(settlement) { + if (typeof settlement.properties.population != "undefined") { + population += parseInt(settlement.properties.population); + } else { + numberOfSettlementsWithoutPopulation++; + }}); + + if (numberOfSettlementsWithoutPopulation != 0) { + if (numberOfSettlementsWithoutPopulation == 1) { + population = population + " (but " + numberOfSettlementsWithoutPopulation + " settlement has no population set)"; + } else { + population = population + " (but " + numberOfSettlementsWithoutPopulation + " settlements have no population set)"; + } + } + + areaProperties = { area: areaString, + number_of_settlements: settlements.length, + population: population, + greatest_settlement_dist: maxDistance, + average_settlement_dist: (sumOfDistances/catchmentArea.settlements.length) + } + } + + return areaProperties; +} + function initMap(self) { self.tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, @@ -60,87 +132,23 @@ function initMap(self) { layers: [self.tileLayer], }).setView([12.4822, -11.9463], 11); - self.amenitiesShown = ["hospital", "doctors", "dentist"]; + self.amenitiesShown = ["hospital"]; self.amenities = {}; self.amenityLayers = {}; // contains the layers for each amenity type + self.catchmentAreaSettlementsLayers = {}; // Settlement layers, addressed by catchmentArea.id + self.settlementsLayerGroup = L.layerGroup(); // A layer group for all the settlement layers, such that they can be treated as one layer in the control self.catchmentAreas = {}; - - // Create the settlement layer - self.settlementLayer = L.geoJson({ type: "FeatureCollection", features: [] }, { - style: function(feature) { - return {fillColor: 'green', - weight: 2, - opacity: 1, - color: 'black', - dashArray: '3', - fillOpacity: 0.1}; - }, - onEachFeature: function(feature, layer) { - var center; - if (feature.geometry.type === "Point") { - center = feature.geometry.coordinates; - } else { - center = feature.geometry.coordinates[0]; - } - - var displayProperties = { name: feature.properties["name"], population: feature.properties["population"] }; - if (typeof displayProperties["name"] == "undefined") - displayProperties["name"] = "Unknown"; - if (typeof displayProperties["population"] == "undefined") - displayProperties["population"] = "Unknown"; - - layer.bindPopup(self.settlementPopupTemplate({ properties: displayProperties, coordinate: center })); - } - }); - map.addLayer(self.settlementLayer); + self.healthPosts = {}; + self.markers = {}; + self.converter = new op2geojson(); // Layer controller self.layersControl = L.control.layers().addTo(map); - self.layersControl.addOverlay(self.settlementLayer, "Settlements"); - - L.control.locate().addTo(map); - - // Legend - var legend = L.control({position: 'bottomright'}); - legend.onAdd = function (map) { - var div = L.DomUtil.create('div', 'info legend'); - div.innerHTML += '<img src="resources/img/hospital.png"> Hospital<br>'; - return div; - }; - legend.addTo(map); - - return map; -} - -function displayMap(self, map) { - - function createQueryData(bbox) { - return "data=[out:json];(" + - "(node[amenity=hospital]("+ bbox +");way[amenity=hospital]("+ bbox +");node(w););" + - "(node[amenity=doctors]("+ bbox +");way[amenity=doctors]("+ bbox +");node(w););" + - "(node[amenity=dentist]("+ bbox +");way[amenity=dentist]("+ bbox +");node(w););" + - "(node(" + bbox + ");relation[type=boundary][boundary=catchment_area];way(r);node(w););" + - ");out;"; - } - function highlightFeature(e) { - var layer = e.target; + map.addLayer(self.settlementsLayerGroup); + self.layersControl.addOverlay(self.settlementsLayerGroup, "Settlements"); - layer.setStyle({ - weight: 5, - color: '#666', - dashArray: '', - fillOpacity: 0.1 - }); - - if (!L.Browser.ie && !L.Browser.opera) { - layer.bringToFront(); - } - } - - function resetHighlight(e) { - self.catchmentAreaLayer.resetStyle(e.target); - } + var emptyFeatureCollection = { type: "FeatureCollection", features: [] }; var hospitalIcon = L.icon({ iconUrl: 'resources/img/hospital.png', @@ -150,47 +158,48 @@ function displayMap(self, map) { popupAnchor: [2, -9] // point to open the popup from relative to iconAnchor }); - var zoom = map.getZoom(); - if (zoom < 10) { - return; - } - - // Make the bounding box string - var bounds = map.getBounds(); - var sw = bounds.getSouthWest(); - var ne = bounds.getNorthEast(); - bbox = [sw.lat, sw.lng, ne.lat, ne.lng].join(','); - - self.converter = new op2geojson(); - var markers = {}; - - function createCatchmentAreaLayer(data) { - return L.geoJson(data, { - style: function(feature) { - return {fillColor: 'green', - weight: 2, - opacity: 1, - color: 'black', - dashArray: '3', - fillOpacity: 0.1}; - }, - onEachFeature: function(feature, layer) { - layer.on({ - mouseover: highlightFeature, - mouseout: resetHighlight, - click: function() { - markers[feature.properties.subject].openPopup(); + self.catchmentAreaLayer = L.geoJson(emptyFeatureCollection, { + style: function(feature) { + return {fillColor: 'green', + weight: 2, + opacity: 1, + color: 'black', + dashArray: '3', + fillOpacity: 0.1}; + }, + onEachFeature: function(feature, layer) { + layer.on({ + mouseover: function(e) { + var layer = e.target; + + layer.setStyle({ + weight: 5, + color: '#666', + dashArray: '', + fillOpacity: 0.1 + }); + + if (!L.Browser.ie && !L.Browser.opera) { + layer.bringToFront(); } - }); - }, - filter: function(feature, layer) { - return _.contains(_.values(feature.properties), "catchment_area"); - } - }); - } + }, + mouseout: function(e) { + self.catchmentAreaLayer.resetStyle(e.target); + }, + click: function() { + self.markers[feature.properties.subject].openPopup(); + } + }); + }, + filter: function(feature, layer) { + return _.contains(_.values(feature.properties), "catchment_area"); + } + }); + map.addLayer(self.catchmentAreaLayer); + self.layersControl.addOverlay(self.catchmentAreaLayer, "Catchment Areas"); - function createAmenityLayer(data, amenity) { - return L.geoJson(data, { + function createAmenityLayer(amenity) { + return L.geoJson(emptyFeatureCollection, { style: function(feature) { return {color: 'red', fillColor: 'red', @@ -209,90 +218,69 @@ function displayMap(self, map) { } var catchmentArea = self.catchmentAreas[feature.id]; - var settlements = catchmentArea.settlements; - - var format = new OpenLayers.Format.GeoJSON; - var openLayersGeo = format.parseGeometry(catchmentArea.geometry); - var sumOfDistances = 0; - var maxDistance = 0; + layer.bindPopup(self.editorTemplate({coordinate: center}) + + self.healthPostTemplate(feature.properties) + + '<div id="' + catchmentArea.id + '">' + + self.catchmentAreaTemplate(catchmentAreaProperties(catchmentArea, feature)) + + '</div>'); - var Geographic = new OpenLayers.Projection("EPSG:4326"); - var Mercator = new OpenLayers.Projection("EPSG:900913"); + self.markers[feature.id] = layer; + }, + filter: function(feature, layer) { + // TODO: Fix and make more efficient + return _.contains(_.values(feature.properties), amenity); + } + }); + } - var featurePoint = format.parseGeometry(feature.geometry); - if (feature.geometry.type == "Point") { - //amenityPoint = new OpenLayers.Geometry.Point(amenity.geometry.coordinates[0], amenity.geometry.coordinates[1]).transform(Geographic, Mercator); - } else { // Its a polygon - featurePoint = featurePoint.getCentroid(); - } + _.each(self.amenitiesShown, function(amenity, i) { + self.amenityLayers[amenity] = createAmenityLayer(amenity); - _.each(catchmentArea.settlements, function (settlement) { - var settlementGeo = format.parseGeometry(settlement.geometry); + map.addLayer(self.amenityLayers[amenity]); + self.layersControl.addOverlay(self.amenityLayers[amenity], + self.amenitiesShown[i].charAt(0).toUpperCase() + self.amenitiesShown[i].slice(1)); + }); - var distance = settlementGeo.distanceTo(featurePoint); - sumOfDistances += distance; - if (distance > maxDistance) - maxDistance = distance; - }); + L.control.locate().addTo(map); - var areaInSquareMeters = openLayersGeo.getGeodesicArea(); - var areaString = areaInSquareMeters.toFixed(2) + "m" + "2".sup(); - if (areaInSquareMeters > 1000000) { - areaString = (areaInSquareMeters / 1000000).toFixed(2) + "km" + "2".sup(); - } + // Legend + var legend = L.control({position: 'bottomright'}); + legend.onAdd = function (map) { + var div = L.DomUtil.create('div', 'info legend'); + div.innerHTML += '<img src="resources/img/hospital.png"> Hospital<br>'; + return div; + }; + legend.addTo(map); - var areaProperties; - if (typeof settlements == "undefined") { - areaProperties = { area: areaString, - number_of_settlements: "Unknown", - population: "Unknown", - greatest_settlement_dist: "Unknown", - average_settlement_dist: "Unknown" - } - } else { - var population = 0; - var numberOfSettlementsWithoutPopulation = 0; + return map; +} - _.each(settlements, function(settlement) { - if (typeof settlement.properties.population != "undefined") { - population += parseInt(settlement.properties.population); - } else { - numberOfSettlementsWithoutPopulation++; - }}); +function displayMap(self, map) { - if (numberOfSettlementsWithoutPopulation != 0) { - if (numberOfSettlementsWithoutPopulation == 1) { - population = population + " (but " + numberOfSettlementsWithoutPopulation + " settlement has no population set)"; - } else { - population = population + " (but " + numberOfSettlementsWithoutPopulation + " settlements have no population set)"; - } - } + function createQueryData(bbox) { + return "data=[out:json];(" + + "(node[amenity=hospital]("+ bbox +");way[amenity=hospital]("+ bbox +");node(w););" + + //"(node[amenity=doctors]("+ bbox +");way[amenity=doctors]("+ bbox +");node(w););" + + //"(node[amenity=dentist]("+ bbox +");way[amenity=dentist]("+ bbox +");node(w););" + + "(node(" + bbox + ");relation[type=boundary][boundary=catchment_area];way(r);node(w););" + + ");out;"; + } - areaProperties = { area: areaString, - number_of_settlements: settlements.length, - population: population, - greatest_settlement_dist: maxDistance, - average_settlement_dist: (sumOfDistances/catchmentArea.settlements.length) - } - } + var zoom = map.getZoom(); + if (zoom < 10) { + return; + } - layer.bindPopup(self.popupTemplate({ properties: $.extend(feature.properties, areaProperties), coordinate: center })); + // Make the bounding box string + var bounds = map.getBounds(); + var sw = bounds.getSouthWest(); + var ne = bounds.getNorthEast(); + bbox = [sw.lat, sw.lng, ne.lat, ne.lng].join(','); - markers[feature.id] = layer; - }, - filter: function(feature, layer) { - // TODO: Fix and make more efficient - return _.contains(_.values(feature.properties), amenity); - } - }); - } + self.converter = new op2geojson(); function addSettlementsForArea(catchmentArea) { - if (typeof catchmentArea.settlements != 'undefined') { - return; - } - // Create the bounding polygon for the query var poly = ""; _.each(catchmentArea.geometry.coordinates[0], function(coordinatePair) { @@ -302,73 +290,111 @@ function displayMap(self, map) { var query = 'data=[out:json];(node(poly:"' + poly + '");<;node(w););out;'; - // Fetch settlement data - self.converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, function(data) { + function processSettlements(data, catchmentArea) { data.features = _.filter(data.features, function(feature) { return _.contains(_.keys(feature.properties), "place") || feature.properties["landuse"] == "residential"; }); catchmentArea.settlements = data.features; - self.settlementLayer.addData(data); - }); + + if (catchmentArea.id in self.catchmentAreaSettlementsLayers) { + self.catchmentAreaSettlementsLayers[catchmentArea.id].clearLayers(); + self.catchmentAreaSettlementsLayers[catchmentArea.id].addData(data); + } else { + self.catchmentAreaSettlementsLayers[catchmentArea.id] = L.geoJson(data, { + style: function(feature) { + return {fillColor: 'green', + weight: 2, + opacity: 1, + color: 'black', + dashArray: '3', + fillOpacity: 0.1}; + }, + onEachFeature: function(feature, layer) { + var center; + if (feature.geometry.type === "Point") { + center = feature.geometry.coordinates; + } else { + center = feature.geometry.coordinates[0]; + } + + var displayProperties = { name: feature.properties["name"], population: feature.properties["population"] }; + if (typeof displayProperties["name"] == "undefined") + displayProperties["name"] = "Unknown"; + if (typeof displayProperties["population"] == "undefined") + displayProperties["population"] = "Unknown"; + + layer.bindPopup(self.editorTemplate({coordinate: center}) + self.settlementTemplate(displayProperties)); + } + }); + self.settlementsLayerGroup.addLayer(self.catchmentAreaSettlementsLayers[catchmentArea.id]); + + $('#' + catchmentArea.id).html(self.catchmentAreaTemplate(catchmentAreaProperties(catchmentArea, self.healthPosts[catchmentArea.properties["subject"]]))); + } + } + + // Fetch settlement data + self.converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, + (function(catchmentArea) { return function (data) { processSettlements(data, catchmentArea); }; })(catchmentArea)); } var query = createQueryData(bbox); - if (typeof self.amenities != "undefined") { - console.log(getDataURIForRegion(self, "region")); - } - self.amenities = {}; _.each(self.amenitiesShown, function(amenity) { self.amenities[amenity] = []; }); // Convert the data to GeoJSON self.converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, function(data) { - if (jQuery.isEmptyObject(self.amenityLayers)) { - - // For each catchment area polygon - _.each( - _.filter(data.features, - function(feature) { - return _.contains(_.values(feature.properties), "catchment_area"); - }), - function(catchmentArea) { - // Add it to the associative array - self.catchmentAreas[catchmentArea.properties["subject"]] = catchmentArea; + self.catchmentAreaLayer.clearLayers(); + var oldCatchmentAreas = self.catchmentAreas; + self.catchmentAreas = {}; + self.healthPosts = {}; + + // For each health post + _.each( + _.filter(data.features, + function(feature) { + return feature.properties["amenity"] == "hospital"; + }), + function(healthPost) { + // Add it to the associative array + self.healthPosts[healthPost.id] = healthPost; + } + ); + + // For each catchment area polygon + _.each( + _.filter(data.features, + function(feature) { + return _.contains(_.values(feature.properties), "catchment_area"); + }), + function(catchmentArea) { + // Add it to the associative array + var subjectId = catchmentArea.properties["subject"]; + + if (subjectId in oldCatchmentAreas) { + catchmentArea = oldCatchmentAreas[subjectId]; + } + + self.catchmentAreas[subjectId] = catchmentArea; + + // If the settlements for this catchment area have already been fetched + if (typeof catchmentArea.settlements == 'undefined') { addSettlementsForArea(catchmentArea); - } - ); - - // Now deal with the catchment areas - self.catchmentAreaLayer = createCatchmentAreaLayer(data); - - _.each(self.amenitiesShown, function(amenity, i) { - self.amenityLayers[amenity] = createAmenityLayer(data, amenity); - - map.addLayer(self.amenityLayers[amenity]); - self.layersControl.addOverlay(self.amenityLayers[amenity], - self.amenitiesShown[i].charAt(0).toUpperCase() + self.amenitiesShown[i].slice(1)); - }); - - map.addLayer(self.catchmentAreaLayer); - self.layersControl.addOverlay(self.catchmentAreaLayer, "Catchment Areas"); - } else { - self.catchmentAreaLayer.clearLayers(); - self.catchmentAreaLayer.addData(data); - - _.each(self.amenitiesShown, function(amenity, i) { - // Update the data for each amenity layer - self.amenityLayers[amenity].clearLayers(); - self.amenityLayers[amenity].addData(data); - }); - - _.each(self.catchmentAreas, function(catchmentArea, i) { - // Update the data for each CatchmentAreaVillageLayer - addSettlementsForArea(catchmentArea); - }); - } + } + } + ); + + self.catchmentAreaLayer.clearLayers(); + self.catchmentAreaLayer.addData(data); + + _.each(self.amenitiesShown, function(amenity, i) { + // Update the data for each amenity layer + self.amenityLayers[amenity].clearLayers(); + self.amenityLayers[amenity].addData(data); + }); }); } @@ -376,32 +402,30 @@ $(document).ready(function() { var self = this; // the HTMLDocument - self.popupTemplate = _.template('<a href="http://www.openstreetmap.org/edit?editor=potlatch2&lat=<%= coordinate[1] %>&lon=<%= coordinate[0] %>&zoom=18">\ + self.editorTemplate = _.template('<a href="http://www.openstreetmap.org/edit?editor=potlatch2&lat=<%= coordinate[1] %>&lon=<%= coordinate[0] %>&zoom=18">\ <img src="resources/img/potlatch.png"></a>\ <a href="http://www.openstreetmap.org/edit?editor=remote&lat=<%= coordinate[1] %>&lon=<%= coordinate[0] %>&zoom=18">\ -<img src="resources/img/josm.png"></a>\ -<h2>Hospital</h2>\ +<img src="resources/img/josm.png"></a>'); + + self.healthPostTemplate = _.template('<h2>Hospital</h2>\ <table width="100%">\ -<tr><td>Name</td><td align="right"><%= properties["name"] %></td></tr>\ -<tr><td>Emergency</td><td align="right" style="text-transform:capitalize;"><%= properties["emergency"] %></td></tr>\ -</table>\ -<h2>Catchment Area</h2>\ +<tr><td>Name</td><td align="right"><%= name %></td></tr>\ +<tr><td>Emergency</td><td align="right" style="text-transform:capitalize;"><%= emergency %></td></tr>\ +</table>'); + + self.catchmentAreaTemplate = _.template('<h2>Catchment Area</h2>\ <table>\ -<tr><td>Surface Area</td><td align="right"><%= properties["area"] %></td></tr>\ -<tr><td>Number of Settlements</td><td align="right"><%= properties["number_of_settlements"] %></td></tr>\ -<tr><td>Population</td><td align="right"><%= properties["population"] %></td></tr>\ -<tr><td>Furthest distance from settlement to health structure</td><td align="right"><%= properties["greatest_settlement_dist"] %></td></tr>\ -<tr><td>Average distance of all settlements from health structure</td><td align="right"><%= properties["average_settlement_dist"] %></td></tr>\ +<tr><td>Surface Area</td><td align="right"><%= area %></td></tr>\ +<tr><td>Number of Settlements</td><td align="right"><%= number_of_settlements %></td></tr>\ +<tr><td>Population</td><td align="right"><%= population %></td></tr>\ +<tr><td>Furthest distance from settlement to health structure</td><td align="right"><%= greatest_settlement_dist %></td></tr>\ +<tr><td>Average distance of all settlements from health structure</td><td align="right"><%= average_settlement_dist %></td></tr>\ </table>'); - self.settlementPopupTemplate= _.template('<a href="http://www.openstreetmap.org/edit?editor=potlatch2&lat=<%= coordinate[1] %>&lon=<%= coordinate[0] %>&zoom=18">\ -<img src="resources/img/potlatch.png"></a>\ -<a href="http://www.openstreetmap.org/edit?editor=remote&lat=<%= coordinate[1] %>&lon=<%= coordinate[0] %>&zoom=18">\ -<img src="resources/img/josm.png"></a>\ -<h3>Settlement</h3>\ + self.settlementTemplate = _.template('<h3>Settlement</h3>\ <table width="100%">\ -<tr><td>Name</td><td align="right"><%= properties["name"] %></td></tr>\ -<tr><td>Population</td><td align="right"><%= properties["population"] %></td></tr>\ +<tr><td>Name</td><td align="right"><%= name %></td></tr>\ +<tr><td>Population</td><td align="right"><%= population %></td></tr>\ </table>'); var map = initMap(self); |