|
<html xmlns="http://www.w3.org/1999/xhtml"> |
|
<head> |
|
<title>Voronoi Network Flooding</title> |
|
<meta charset="utf-8" /> |
|
<link type="text/css" rel="stylesheet" href="d3map.css" /> |
|
<link type="text/css" rel="stylesheet" href="https://raw.githubusercontent.com/emeeks/d3-carto-map/master/examples/example.css" /> |
|
</head> |
|
<style> |
|
html,body { |
|
height: 100%; |
|
width: 100%; |
|
margin: 0; |
|
} |
|
|
|
#map { |
|
height: 100%; |
|
width: 100%; |
|
position: absolute; |
|
} |
|
|
|
.reproject { |
|
position: absolute; |
|
z-index: 99; |
|
left: 50px; |
|
top: 250px; |
|
} |
|
|
|
|
|
.node { |
|
fill: blue; |
|
stroke: black; |
|
stroke-width: 1 |
|
} |
|
|
|
.voronoi { |
|
fill-opacity: .5; |
|
stroke-opacity: .25; |
|
} |
|
|
|
.roads { |
|
stroke: brown; |
|
stroke-width: 1px; |
|
fill: none; |
|
} |
|
|
|
</style> |
|
<script> |
|
function makeSomeMaps() { |
|
pathSource = 0; |
|
|
|
map = d3.carto.map(); |
|
|
|
d3.select("#map").call(map); |
|
map.centerOn([-88,39],"latlong"); |
|
map.setScale(4); |
|
|
|
map.refresh(); |
|
|
|
wcLayer = d3.carto.layer.tile(); |
|
wcLayer |
|
.tileType("stamen") |
|
.path("watercolor") |
|
.label("Watercolor") |
|
.visibility(true) |
|
|
|
postLayer = d3.carto.layer.topojson(); |
|
postLayer |
|
.path("uspost.topojson") |
|
.label("Postal Routes") |
|
.cssClass("roads") |
|
.renderMode("svg") |
|
.on("load", createMatrix); |
|
|
|
map.addCartoLayer(wcLayer).addCartoLayer(postLayer); |
|
|
|
function createMatrix() { |
|
postdata = postLayer.features() |
|
edgeList = []; |
|
edgeMap = {}; |
|
nodes = []; |
|
nodeHash = {}; |
|
for (x in postdata) { |
|
var line = postdata[x].geometry.coordinates; |
|
var lS = line[0]; |
|
var lE = line[line.length - 1]; |
|
var nA = [lS,lE]; |
|
for (y in nA) { |
|
if (!nodeHash["node" + Math.ceil(nA[y][0] * 1000) + (nA[y][1] * 1000)]) { |
|
var newNode = {label: "Node " + nodes.length, id: nodes.length.toString(), coordinates: [nA[y]], x: nA[y][0], y: nA[y][1]} |
|
nodeHash["node" + Math.ceil(nA[y][0] * 1000) + (nA[y][1] * 1000)] = newNode; |
|
nodes.push(newNode) |
|
} |
|
} |
|
postdata[x].properties.source = nodeHash["node" + Math.ceil(lS[0] * 1000) + (lS[1] * 1000)]; |
|
postdata[x].properties.target = nodeHash["node" + Math.ceil(lE[0] * 1000) + (lE[1] * 1000)]; |
|
postdata[x].properties.cost = d3.geo.length(postdata[x]) * 6371; |
|
} |
|
|
|
var xExtent = d3.extent(nodes, function(d) {return d.x}); |
|
var yExtent = d3.extent(nodes, function(d) {return d.y}); |
|
voronoi = d3.geom.voronoi() |
|
.clipExtent([xExtent,yExtent]) |
|
.clipExtent([[xExtent[0],yExtent[0]],[xExtent[1],yExtent[1]]]) |
|
.x(function (d) {return d.x}) |
|
.y(function (d) {return d.y}); |
|
|
|
vorFeatures = voronoi(nodes).map(function(d,i) { |
|
d.push(d[0]); |
|
return {type:"Feature", id: i, node: nodes[i], geometry: {type: "Polygon", coordinates: [d]}} |
|
}) |
|
|
|
|
|
featureLayer = d3.carto.layer.featureArray(); |
|
featureLayer |
|
.features(vorFeatures) |
|
.label("Feature Array") |
|
.cssClass("voronoi") |
|
.renderMode("svg") |
|
.clickableFeatures(true) |
|
.on("load", function() {d3.selectAll("path.voronoi").on("click", function(d) {flood(d.node.id)})}); |
|
|
|
map.addCartoLayer(featureLayer) |
|
|
|
for (x in postdata) { |
|
if (edgeMap[postdata[x].properties.source.id]) { |
|
edgeMap[postdata[x].properties.source.id][postdata[x].properties.target.id] = postdata[x].properties.cost; |
|
} |
|
else { |
|
edgeMap[postdata[x].properties.source.id] = {}; |
|
edgeMap[postdata[x].properties.source.id][postdata[x].properties.target.id] = postdata[x].properties.cost; |
|
} |
|
if (edgeMap[postdata[x].properties.target.id]) { |
|
edgeMap[postdata[x].properties.target.id][postdata[x].properties.source.id] = postdata[x].properties.cost; |
|
} |
|
else { |
|
edgeMap[postdata[x].properties.target.id] = {}; |
|
edgeMap[postdata[x].properties.target.id][postdata[x].properties.source.id] = postdata[x].properties.cost; |
|
} |
|
} |
|
|
|
graph = new Graph(edgeMap); |
|
} |
|
|
|
function flood(siteID) { |
|
siteDistance = d3.keys(graph.map).map(function(d) {return Infinity}); |
|
siteDistance[siteID] = 0; |
|
|
|
var map = graph.map; |
|
var calculatedSites = [siteID]; |
|
var connectedSites = d3.keys(graph.map[siteID]); |
|
var visitedSites = [siteID]; |
|
var sitesToVisit = [siteID]; |
|
var currentNode = siteID; |
|
var currentCost = 0; |
|
|
|
while (sitesToVisit.length > 0) { |
|
sitesToVisit.splice(0,1); |
|
for (x in connectedSites) { |
|
if (calculatedSites.indexOf(connectedSites[x]) == -1) { |
|
calculatedSites.push(connectedSites[x]); |
|
siteDistance[connectedSites[x]] = currentCost + map[currentNode][connectedSites[x]]; |
|
} |
|
else { |
|
siteDistance[connectedSites[x]] = Math.min(currentCost + map[currentNode][connectedSites[x]], siteDistance[connectedSites[x]]); |
|
} |
|
|
|
if (visitedSites.indexOf(connectedSites[x]) == -1 && sitesToVisit.indexOf(connectedSites[x]) == -1) { |
|
sitesToVisit.push(connectedSites[x]); |
|
} |
|
} |
|
visitedSites.push(currentNode) |
|
|
|
//sort sitesToVisit |
|
sitesToVisit = sitesToVisit.sort(function(a,b) { |
|
if (siteDistance[a] < siteDistance[b]) |
|
return -1; |
|
if (siteDistance[a] > siteDistance[b]) |
|
return 1; |
|
return 0; |
|
}) |
|
currentNode = sitesToVisit[0]; |
|
currentCost = siteDistance[currentNode]; |
|
connectedSites = d3.keys(graph.map[currentNode]); |
|
|
|
} |
|
|
|
color = d3.scale.linear().domain([0,500,3500]).range(["green","yellow","red"]) |
|
d3.selectAll("path.voronoi").style("fill", "lightgray") |
|
.transition() |
|
.delay(function(d) {return siteDistance[d.id] == Infinity ? 5000 : siteDistance[d.id] * 2}) |
|
.duration(1000) |
|
.style("fill", function(d) {return siteDistance[d.id] == Infinity ? "gray" : color(siteDistance[d.id])}) |
|
|
|
|
|
} |
|
|
|
} |
|
</script> |
|
<body onload="makeSomeMaps()"> |
|
<div id="map"></div> |
|
<footer> |
|
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8" type="text/javascript"></script> |
|
<script src="http://d3js.org/topojson.v1.min.js" type="text/javascript"> |
|
</script> |
|
<script src="http://d3js.org/d3.geo.projection.v0.min.js" type="text/javascript"> |
|
</script> |
|
<script src="http://bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/tile.js" type="text/javascript"> |
|
</script> |
|
<script src="http://bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/d3.quadtiles.js" type="text/javascript"> |
|
</script> |
|
<script src="http://bl.ocks.org/emeeks/raw/f3105fda25ff785dc5ed/d3.geo.raster.js" type="text/javascript"> |
|
</script> |
|
<script src="https://rawgit.com/emeeks/d3-carto-map/master/d3.carto.map.js" type="text/javascript"> |
|
</script> |
|
<script src="dijkstra.js" type="text/javascript"> |
|
</script> |
|
</footer> |
|
</body> |
|
</html> |