function getDataURIForRegion(self, region) {
var dataURI = "data:text/csv,";
dataURI += "Name,Size of Catchment Area,Population of Catchment Area,Average Distance to Health Post,Max Distance to the Health Post%0A";
_.each(self.amenities["hospital"], function(amenity) {
var catchmentArea = self.catchmentAreas[amenity.id];
var settlements = catchmentArea.settlements;
var format = new OpenLayers.Format.GeoJSON;
var sumOfDistances = 0;
var maxDistance = 0;
var Geographic = new OpenLayers.Projection("EPSG:4326");
var Mercator = new OpenLayers.Projection("EPSG:900913");
var amenityPoint = format.parseGeometry(amenity.geometry);
if (amenity.geometry.type == "Point") {
//amenityPoint = new OpenLayers.Geometry.Point(amenity.geometry.coordinates[0], amenity.geometry.coordinates[1]).transform(Geographic, Mercator);
} else { // Its a polygon
amenityPoint = amenityPoint.getCentroid();
}
_.each(catchmentArea.settlements, function (settlement) {
var settlementGeo = format.parseGeometry(settlement.geometry);
var distance = settlementGeo.distanceTo(amenityPoint);
sumOfDistances += distance;
if (distance > maxDistance)
maxDistance = distance;
});
var openLayersGeo = format.parseGeometry(catchmentArea.geometry);
var areaInSquareMeters = openLayersGeo.getGeodesicArea();
var population = 0;
var numberOfSettlementsWithoutPopulation = 0;
_.each(settlements, function(settlement) {
if (typeof settlement.properties.population != "undefined") {
population += parseInt(settlement.properties.population);
}});
dataURI += amenity.properties["name"] + "," + areaInSquareMeters +"," + population + "," + (sumOfDistances/settlements.length) + "," + maxDistance + "%0A";
});
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 line = new OpenLayers.Geometry.LineString([healthPostPoint, settlementGeo]);
var distance = line.getGeodesicLength(Geographic);
//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 fillObjectWithUnknowns(object, expectedProperties) {
var newObject = {};
_.each(expectedProperties, function(property) {
if (_.isUndefined(object[property])) {
newObject[property] = "Unknown";
} else {
newObject[property] = object[property];
}
});
return newObject;
}
function initMap(self) {
var tileUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var tileAttribution = 'Map data © OpenStreetMap contributors';
self.tileLayer = L.tileLayer(tileUrl, {
maxZoom: 18,
attribution: tileAttribution
});
// Create the map
var map = L.map( 'map', {
zoom: 12,
layers: [self.tileLayer],
}).setView([12.4822, -11.9463], 11);
var hash = new L.Hash(map);
var miniMapTileLayer = new L.TileLayer(tileUrl, {minZoom: 0, maxZoom: 13, attribution: tileAttribution });
var miniMap = new L.Control.MiniMap(miniMapTileLayer, { toggleDisplay: true }).addTo(map);
L.control.scale().addTo(map);
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 = {};
self.healthPosts = {};
self.markers = {};
self.converter = new op2geojson();
// Layer controller
self.layersControl = L.control.layers().addTo(map);
map.addLayer(self.settlementsLayerGroup);
self.layersControl.addOverlay(self.settlementsLayerGroup, "Settlements");
self.populationHeatMap = new L.TileLayer.heatMap({
radius: 20,
opacity: 0.8,
gradient: {
0.45: "rgb(0,0,255)",
0.55: "rgb(0,255,255)",
0.65: "rgb(0,255,0)",
0.95: "yellow",
1.0: "rgb(255,0,0)"
}
});
//map.addLayer(self.populationHeatMap);
self.layersControl.addOverlay(self.populationHeatMap, "Population Heat Map");
var emptyFeatureCollection = { type: "FeatureCollection", features: [] };
var hospitalIcon = L.icon({
iconUrl: 'resources/img/hospital.png',
iconSize: [18, 18],
iconAnchor: [9, 9], // point on the icon corresponding to marker's location
popupAnchor: [2, -9] // point to open the popup from relative to iconAnchor
});
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();
}
},
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(amenity) {
return L.geoJson(emptyFeatureCollection, {
style: function(feature) {
return {color: 'red',
fillColor: 'red',
fillOpacity: 0.2,
weight: 10};
},
onEachFeature: function(feature, layer) {
self.amenities[amenity].push(feature);
var center;
if (feature.geometry.type === "Point") {
layer.options.icon = hospitalIcon;
center = feature.geometry.coordinates;
} else {
var format = new OpenLayers.Format.GeoJSON;
var geom = format.parseGeometry(feature.geometry);
center = geom.getCentroid();
}
var catchmentArea = self.catchmentAreas[feature.id];
var healthPostProperties = fillObjectWithUnknowns(feature.properties, ["name", "emergency"]);
if (_.isUndefined(catchmentArea)) {
layer.bindPopup(self.editorTemplate({coordinate: center}) +
self.healthPostTemplate(healthPostProperties) + " No catchment Area");
} else {
layer.bindPopup(self.editorTemplate({coordinate: center}) +
self.healthPostTemplate(healthPostProperties) +
self.catchmentAreaTemplate(catchmentAreaProperties(catchmentArea, feature)));
}
self.markers[feature.id] = layer;
},
filter: function(feature, layer) {
// TODO: Fix and make more efficient
return _.contains(_.values(feature.properties), amenity);
}
});
}
_.each(self.amenitiesShown, function(amenity, i) {
self.amenityLayers[amenity] = createAmenityLayer(amenity);
map.addLayer(self.amenityLayers[amenity]);
self.layersControl.addOverlay(self.amenityLayers[amenity],
self.amenitiesShown[i].charAt(0).toUpperCase() + self.amenitiesShown[i].slice(1));
});
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 += ' Hospital
';
return div;
};
legend.addTo(map);
return map;
}
function formatDistance(distance) {
if (distance == "Unknown") {
return distance;
} else if (distance > 1000) {
return (distance/1000).toFixed(2) + "km";
} else {
return distance.toFixed(0) + "m";
}
}
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;";
}
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(',');
function addSettlementsForArea(catchmentArea) {
// Create the bounding polygon for the query
var poly = "";
_.each(catchmentArea.geometry.coordinates[0], function(coordinatePair) {
poly += coordinatePair[1] + " " + coordinatePair[0] + " ";
});
poly = poly.slice(0, -1);
var query = 'data=[out:json];(node(poly:"' + poly + '");<;node(w););out;';
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;
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: 'grey',
weight: 1,
opacity: 1,
color: 'black',
fillOpacity: 0.1};
},
onEachFeature: function(feature, layer) {
var center;
if (feature.geometry.type === "Point") {
center = feature.geometry.coordinates;
} else {
var format = new OpenLayers.Format.GeoJSON;
var geom = format.parseGeometry(feature.geometry);
center = geom.getCentroid();
}
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";
} else {
self.populationHeatMapData.push({lat: center[1], lon: center[0], value: feature.properties.population});
}
layer.bindPopup(self.editorTemplate({coordinate: center}) + self.settlementTemplate(displayProperties));
}
});
self.settlementsLayerGroup.addLayer(self.catchmentAreaSettlementsLayers[catchmentArea.id]);
self.populationHeatMap.addData(self.populationHeatMapData);
self.populationHeatMap.redraw();
var healthPost = self.healthPosts[catchmentArea.properties.subject];
if (_.isUndefined(healthPost)) {
console.log("No health post found for catchment area");
} else {
var center;
if (healthPost.geometry.type === "Point") {
center = healthPost.geometry.coordinates;
} else {
var format = new OpenLayers.Format.GeoJSON;
var geom = format.parseGeometry(healthPost.geometry);
center = geom.getCentroid();
}
self.markers[catchmentArea.properties.subject].bindPopup(self.editorTemplate({coordinate: center}) +
self.healthPostTemplate(healthPost.properties) +
self.catchmentAreaTemplate(catchmentAreaProperties(catchmentArea, healthPost)));
}
}
}
// Fetch settlement data
self.converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, map.getCenter().lat,
(function(catchmentArea) { return function (data) { processSettlements(data, catchmentArea); }; })(catchmentArea));
}
var query = createQueryData(bbox);
_.each(self.amenitiesShown, function(amenity) {
self.amenities[amenity] = [];
});
self.populationHeatMapData = [];
// Convert the data to GeoJSON
self.converter.fetch("http://overpass-api.de/api/interpreter", query, zoom, map.getCenter().lat, function(data) {
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);
}
}
);
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);
});
});
}
$(document).ready(function() {
var self = this; // the HTMLDocument
self.editorTemplate = _.template('\
\
\
');
self.healthPostTemplate = _.template('
Hospital
\
\
Name | <%= name %> |
\
Emergency | <%= emergency %> |
\
');
self.catchmentAreaTemplate = _.template('Catchment Area
\
\
Surface Area | <%= area %> |
\
Number of Settlements | <%= number_of_settlements %> |
\
Population | <%= population %> |
\
Furthest distance from settlement to health structure | <%= formatDistance(greatest_settlement_dist) %> |
\
Average distance of all settlements from health structure | <%= formatDistance(average_settlement_dist) %> |
\
');
self.settlementTemplate = _.template('Settlement
\
\
Name | <%= name %> |
\
Population | <%= population %> |
\
');
var map = initMap(self);
map.on('moveend', function(e) {
displayMap(self, map);
})
function onLocationFound(e) {
self.currentLocation = e.latlng;
var radius = e.accuracy / 2;
L.marker(e.latlng).addTo(map)
.bindPopup("You are within " + radius + " meters of this point.").openPopup();
}
function onLocationError(e) {
//alert(e.message);
}
map.on('locationfound', onLocationFound);
map.on('locationerror', onLocationError);
map.locate({setView: true, maxZoom: 12});
//displayMap(self, map);
});