|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"> |
|
<title>Edmonton-Neighbourhoods</title> |
|
<link href="https://fonts.googleapis.com/css?family=Gaegu" rel="stylesheet"> |
|
<style> |
|
body { |
|
margin-top: 50px; |
|
} |
|
|
|
/* center svg & tooltip */ |
|
svg, div#tooltip { |
|
display: block; |
|
margin: 0 auto; |
|
} |
|
|
|
/* fill for all paths */ |
|
.pathsOverlay{ |
|
fill: gray; |
|
} |
|
|
|
/* neighbourhood border properties */ |
|
.neigh-borders { |
|
fill: none; |
|
stroke: #fff; |
|
stroke-width: 0.025em; |
|
stroke-linejoin: round; |
|
stroke-linecap: round; |
|
pointer-events: none; |
|
} |
|
|
|
/* user interaction title */ |
|
text#title { |
|
font-size: 2em; |
|
} |
|
|
|
/* fixed tooltip */ |
|
div#tooltip { |
|
text-align: center; |
|
max-width: 350px; |
|
max-height: 350px; |
|
font: 0.8em; |
|
margin-top: -720px; |
|
padding-right: 380px; |
|
} |
|
|
|
/* Font from Google Fonts */ |
|
text#title, div#tooltip { |
|
font-family: 'Gaegu', cursive; |
|
pointer-events: none; |
|
} |
|
|
|
/* No margin for P looks neat */ |
|
p { |
|
margin: 0; |
|
} |
|
|
|
|
|
</style> |
|
</head> |
|
<body> |
|
<div id="map"></div> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/3.0.2/topojson.min.js"></script> |
|
<script> |
|
(function() { |
|
//Define SVG's width and height, SVG, and path generator |
|
var width = 750, height = 750; |
|
var svg = d3.select("#map").append("svg") |
|
.attr("width", width).attr("height", height); |
|
var geoPath = d3.geoPath(); |
|
|
|
//svg border |
|
// svg.append("rect") |
|
// .attr("width", width) |
|
// .attr("height", height) |
|
// .style("fill", "none") |
|
// .style("stroke", "black"); |
|
|
|
//Tooltip's absolute div (fixed tooltip) - will transition to view accordingly |
|
var div = d3.select("#map").append("div") |
|
.attr("id", "tooltip") |
|
.style("opacity", 0); |
|
|
|
//To invite user's response |
|
var title = "MOUSEOVER NEIGHBOURHOODS" |
|
var neighbourhoodText = svg.append("text") |
|
.attr("y", height / 36) |
|
.attr("id", "title") |
|
.attr("text-anchor", "left") |
|
.text(title); |
|
|
|
//Topojson prepared via commandline reading of the file and callback assignment |
|
d3.json("neigh-pixels.topojson", neighbourhoods); |
|
|
|
//Callback for the topojson file |
|
function neighbourhoods(error, shapes) { |
|
if(error){ |
|
alert("Error occurred"); |
|
}else { |
|
//Define group for paths, geojson data, and neighbours for neighbourhoods |
|
var g = d3.select("svg").append("g").attr("class", "pathsOverlay"); |
|
var geojson = topojson.feature(shapes, shapes.objects["neigh-pixels"]).features; |
|
var neighbors = topojson.neighbors(shapes.objects["neigh-pixels"].geometries); |
|
|
|
//Define array with neighbours names for search |
|
var neighborsNames = neighbors.map(function(d, i){ |
|
var names = d.map(function(d, i){ return geojson[d].properties.name; }); |
|
return names; |
|
}); |
|
|
|
//Appending paths to group |
|
g.selectAll("path").data(geojson) |
|
.enter().append("path") |
|
.attr("class", "neigh") |
|
.attr("d", function(d){ return geoPath(d); }); |
|
|
|
//Appending neighbourhoods borders |
|
svg.append("path") |
|
.attr("class", "neigh-borders") |
|
.attr("d", geoPath(topojson.mesh(shapes, shapes.objects["neigh-pixels"], function(a, b) { return a !== b; }))); |
|
|
|
//Mouse events for the paths - show selected neighbourhood and associated neighbours |
|
d3.selectAll("path.neigh") |
|
.on("mouseover", findNeighbors) |
|
.on("mouseout", clearNeighbors); |
|
|
|
//Colors mouseovered neighbourhood(orange), selects and colors associated neighbours(green) |
|
function findNeighbors(data, index) { |
|
//Selected neighbourhood and neighbours fill |
|
var selectedColor = "#FE9922"; //orange |
|
var selectedNeighboursColor = "#41A368"; //green |
|
|
|
//alter selected path fill |
|
d3.select(this).style("fill", selectedColor); |
|
|
|
//alter selected path's neighbours' path fill |
|
d3.selectAll("path.neigh").filter(function(d, i){ |
|
return neighbors[index].indexOf(i) > -1; |
|
}).style("fill", selectedNeighboursColor); |
|
|
|
//Transition of div's content in conjuction with the mouseover |
|
div.transition() |
|
.duration(200) |
|
.style("opacity", 1); |
|
div .html(`<strong><p id="neigh-text">Neighbourhood: ${data.properties.name}</p><strong>`+ |
|
`<strong><p id="neighs-text">Neighbours: ${neighborsNames[index]}</p></strong>`); |
|
|
|
/* |
|
Assign colors to match with selected neighbourhood and neighbours |
|
Done after the p tags are available in the DOM |
|
*/ |
|
d3.select("#neigh-text").style("color", `${selectedColor}`); |
|
d3.select("#neighs-text").style("color", `${selectedNeighboursColor}`); |
|
neighbourhoodText.text(""); |
|
}; |
|
|
|
//Control user's invite title. Also reset fixed tooltip and paths fill(color) |
|
function clearNeighbors(d, i){ |
|
d3.selectAll("path.neigh").style("fill", "gray"); |
|
|
|
div.transition() |
|
.duration(500) |
|
.style("opacity", 0); |
|
neighbourhoodText.text(title); |
|
} |
|
} |
|
}; |
|
})() |
|
|
|
</script> |
|
</body> |
|
</html> |