Skip to content

Instantly share code, notes, and snippets.

@mikelotis
Last active August 10, 2018 02:58
Show Gist options
  • Save mikelotis/6d2fd32f91cf20da2f29fc97f88ac236 to your computer and use it in GitHub Desktop.
Save mikelotis/6d2fd32f91cf20da2f29fc97f88ac236 to your computer and use it in GitHub Desktop.
Edmonton Neighbourhoods & Their Neighbours
border: yes
height: 850

Map shows Edmonton Neighbourhoods. When you mouseover, the mouseovered neighbourhood is colored orange, and the neighbourhoods which it shares borders with are colored green (neighbours). Corresponding names of associated neighbourhood (orange) and neighbours (green) are placed on the top left.

Inspiration

Helper Links For converting lat and longs to screen pixels and using pixel data

Commands on the command-line to convert geojson (lat and longs) to topojson (screen position pixels)

geoproject "d3.geoConicEqualArea().parallels([53.2343, 53.4302]).rotate([113.3, 0]).fitSize([750, 750], d)" < neigh-api.geojson > neigh-pixels.json
geo2svg -w 750 -h 750 < neigh-pixels.json > neigh-pixels.svg
geo2topo neigh-pixels.json > neigh-pixels.topojson

Brief description of command-lines above

  • Geojson (neigh-api.geojson - lats and longs) from OpenData converted to pixels geojson (neigh-pixels.json - pixel positions within 750 x 750).
  • Pixel geojson previewed using geo2svg. Lastly, pixels geojson is converted to topojson.
<!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>
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment