Skip to content

Instantly share code, notes, and snippets.

@gmculp
Last active October 1, 2016 22:59
Show Gist options
  • Select an option

  • Save gmculp/137bf0a362ab32c30b13e87c13aa144d to your computer and use it in GitHub Desktop.

Select an option

Save gmculp/137bf0a362ab32c30b13e87c13aa144d to your computer and use it in GitHub Desktop.
Quadtree Map of NYC WiFi Hotspots

A quadtree map of NYC Wi-Fi hotspot locations built with D3.js. Data are from the NYC OpenData.

<!DOCTYPE html>
<meta charset="utf-8">
<title>Quadtree Map of NYC WiFi Hotspots</title>
<style>
html {
display: table;
margin: auto;
}
.full_node {
fill: OrangeRed;
stroke: #808080;
shape-rendering: crispEdges;
}
.empty_node {
fill: none;
stroke: #808080;
shape-rendering: crispEdges;
}
body {
background: ivory;
display: table-cell;
vertical-align: middle;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script>
//declare dimensions of page
//scale based on window width
var w = ($( window ).height()/850)>1?1:$( window ).height()/850;
var width = w*800,
height = w*800;
//initializa projection
var projection = d3.geo.albers();
var path = d3.geo.path().projection(projection);
//data source URL
var URL = "https://data.cityofnewyork.us/resource/7agf-bcsq.json?$where=(lat IS NOT NULL)&$select=lat,long_"
URL = encodeURI(URL); //encode special characters such as spaces and quotes
//geojson URL
var countyJSON = "https://rawgit.com/gmculp/b76fbaa2bf72f92c638f/raw/4d0235b7548e869e373f079e7abd1e8f1e9e81ee/borough.json";
var quadtree;
generate_quadtree_map();
function generate_quadtree_map(){
var pt_arr = [];
$.getJSON(countyJSON, function (json) {
//set the projection
set_projection(projection, path, json, width, height);
$.getJSON(URL, function(json_data){
$.each(json_data, function(i, json_obj){
var cxy = [json_obj.long_,json_obj.lat];
var p = projection(cxy);
pt_arr.push(p);
});
quadtree = d3.geom.quadtree()
.extent([[-1, -1], [width + 1, height + 1]])
(pt_arr);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var this_quadtree = nodes(quadtree);
var this_min = d3.min(this_quadtree, function(d) { if (d.pts) return +d.width;});
var this_max = d3.max(this_quadtree, function(d) { if (d.pts) return +d.width;});
svg.selectAll(".node")
.data(this_quadtree)
.enter().append("rect")
.attr("title", function(d) { return d.node_no; })
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; })
.attr("width", function(d) { return d.width; })
.attr("height", function(d) { return d.height; })
.style("stroke-opacity", 1.0)
.attr('fill-opacity',function(d) {
return 1.0 - (d.width/this_max);
})
.attr("class", function(d) {
if (d.pts){
return "full_node";
}
else{
return "empty_node";
}
});
//add county layer to map
var counties = svg.append("g")
.attr("id", "counties");
counties.selectAll("path")
.data(json.features)
.enter().append("path")
.attr("d", path)
.attr("pointer-events", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.25)
.style("fill", "none");
});
});
}
// Collapse the quadtree into an array of rectangles.
function nodes(quadtree) {
var nodes = [];
var node_cnt = 0;
quadtree.visit(function(node, x1, y1, x2, y2) {
//var node.leaf;
node_cnt++;
//alert(node.nodes.length); //4
var np = node.point;
nodes.push({x: x1, y: y1, width: x2 - x1, height: y2 - y1, area: ((y2 - y1)*(x2-x1)), pts: np, node_no: node_cnt, is_leaf: node.leaf});
});
//alert("node count: " + node_cnt);
return nodes;
}
function set_projection(projection, path, json, map_width, map_height) {
//reset projection
projection
.scale(1)
.translate([0, 0]);
//adjust projection to zoom in on NYC
var this_c = d3.geo.centroid(json);
//first rotate projection to NYC
projection
.rotate([(this_c[0] * -1), 0])
.center([0, this_c[1]])
.precision(.1);
var b = path.bounds(json),
s = .95 / Math.max((b[1][0] - b[0][0]) / map_width, (b[1][1] - b[0][1]) / map_height),
t = [(map_width - s * (b[1][0] + b[0][0])) / 2, (map_height - s * (b[1][1] + b[0][1])) / 2];
//then set scale and center
projection
.scale(s)
.translate(t);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment