Published
Edited
Jun 23, 2020
Insert cell
Insert cell
md `## Boring stuff setting up tiles`
Insert cell
Insert cell
projection = d3.geoMercator()
.center([-73.9888682,40.6916651]) //https://github.com/d3/d3-geo#projection_center, does what it says on the tin
.scale((1 << 24) / (2 * Math.PI)) // this number is actually 333772.1072150545. Why is it this number? I am assuming this has something to do with projecting from a...circle? Because we're dividing by tau?
//https://github.com/d3/d3-geo#projection_scale
.translate([width / 2, height / 2]) //https://github.com/d3/d3-geo#projection_translate. this feature defaults to translating the center point of your map against a 960x500 area svg? I don't really know why that size. What we have here will translate our map's center to the exact center of the div.
.precision(0) //https://github.com/d3/d3-geo#projection_precision, d3 uses something called adaptive sampling to improve rendering and performance (see https://bl.ocks.org/mbostock/3795544), this definitely falls into "I sort of understand this math, Mike" territory
Insert cell
Insert cell
tile = d3.tile() // based on the following parameters, which tiles will I need to fetch?
.size([width, height]) //it's going to fill this space
.scale(projection.scale() * 2 * Math.PI) // again, I am not 100% sure I know what's going oin
.translate(projection([0, 0])) //don't change anything from the projection
Insert cell
tiles = Promise.all(tile().map(async d => {
d.data = await d3.json(`https://tile.nextzen.org/tilezen/vector/v1/256/all/${d.z}/${d.x}/${d.y}.json?api_key=ztkh_UPOQRyakWKMjH_Bzg`); // map the tiles returned by tile() to the tile API endpoint
return d; // look at the different items that are part of the output data!! so many
}))
Insert cell
Insert cell
roads = tiles.map(t => t.data.roads.features.filter(f => f.properties.kind != "ferry" && f.properties.kind != "rail" && f.properties.kind != "highway" && f.properties.kind != undefined)).filter(m => m.length > 0).flat()
Insert cell
Insert cell

chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
Insert cell
Insert cell
names = function(){
let arr = Array.from(new Set(tiles
.map(t => t.data.roads.features
.filter(f => f.properties.kind != "ferry" && f.properties.kind != "rail" && f.properties.kind != "highway" && f.properties.kind != undefined)
.map(m => `${m.properties.name},${m.properties.collision_rank}`)).flat()))

for (let i=0; i < arr.length; i++){
arr[i] = arr[i].split(',')
if (arr[i].length > 2){
arr[i] = [`${arr[i][0]} ${arr[i][1]}`,arr[i][2].trim()]
}
}
return arr
}()
Insert cell
Insert cell
lineslines = function(){
let feat = []
names.forEach(function(n){
let arr = chunk(tiles.map(t => t.data.roads.features.filter(f => f.properties.name == n[0] && f.properties.collision_rank == n[1])).flat().map(s => s.geometry.coordinates).flat(4),2)
if (arr.length > 0){
let obj = {}
obj.type="Feature"
obj.properties = {}
obj.properties.name = n[0]
obj.properties.rank = n[1]
obj.geometry = {}
obj.geometry.type = "LineString"
obj.geometry.coordinates= arr
feat.push(obj)
}
})
let geojson = {};
geojson.type = "FeatureCollection";
geojson.features = feat;
return geojson;
}()
Insert cell
Insert cell
test = function(){
let index = []
lineslines.features.forEach(function(r, idx){
let obj = r
obj.points = []
let set = new Set()
lineslines.features.forEach(function(ki,i){
if (ki.properties.name != r.properties.name){
let int = turf.lineIntersect(r, ki);
if (int.features.length > 0) {
let intString = `${ki.properties.name} and ${r.properties.name}`
if (!set.has(intString)){
set.add(intString)
int.features[0].properties = {}
int.features[0].properties.int1 = ki.properties.name
int.features[0].properties.int2 = r.properties.name
// console.log(int.features[0])
obj.points.push(int.features[0])
// int.features.forEach(function(inter){
// inter.properties = {}
// inter.properties.int1 = ki.properties.name
// inter.properties.int2 = r.properties.name
// obj.points.push(inter)
//})
}}
}
})
obj.points.sort((a,b) => turf.distance(obj.points[0],a)-turf.distance(obj.points[0],b))
index.push(obj)
})
return index}();
Insert cell
test[2].points
Insert cell
// cleanup = function(){
// for (let i=0; i < test.length; i++){
// for (let j = 0; test[i].points; j++){
// if (test[i].points[j+1] !== undefined){
// if (turf.distance(test[i].points[j], test[i].points[j+1]) < .01){
// test[i].points.splice(test[i].points[j+1], 1)
// }
// }
// }
// }
// return test
// }()
Insert cell
makeLines = function(){
let arr = []
//loop through every object with intersection points
for (var i = 0; i < test.length; i++) {
//for each object, loop through the intersection points
for(var j = 0; j < test[i].points.length; j++){
if (test[i].points[j+1] !== undefined){
let obj = {}
obj.type= "Feature",
obj.properties = {};
obj.properties.path = test[i].properties.name
obj.properties.ids = [j, j+1]
obj.geometry = {};
obj.geometry.type = "LineString";
obj.geometry.coordinates= [test[i].points[j].geometry.coordinates, test[i].points[j+1].geometry.coordinates]
arr.push(obj)
}
}
} return arr;
}()
Insert cell
makePoints = function(){
let arr = [];
for (var i = 0; i < test.length; i++){
let obj = test[i].points;
arr.push(obj);
}
return arr.flat()} ();
Insert cell
bbox = function(){
let bb = {}
bb.type = "FeatureCollection"
bb.features = []
let obj = {}
obj.geometry = {}
obj.type = "Feature"
obj.geometry.type = "Polygon"
// [x1,y1][x2,y1][x2,y2][x1,y2][x1,y1]
obj.geometry.coordinates = [[projection.invert([0,0]), projection.invert([width,0]), projection.invert([width,600]), projection.invert([0,600]),projection.invert([0,0])]]
bb.features.push(obj)
return bb
}()
Insert cell
ring = FileAttachment('newyork.json').json()
Insert cell
ringbbox = turf.bbox(ring)
Insert cell
projection.invert([0,0])
Insert cell
projection.invert([width,height])
Insert cell
ringsample = function(){
let arr = []
let r = turf.pointsWithinPolygon(ring, bbox.features[0])
r.features.forEach(function(ri){
let d = turf.circle(ri, .001);
arr.push(d)
})
return arr}()
Insert cell
Insert cell
Insert cell
overlaps = function(){
let arr = []
makeLines.forEach(function(l){
let lineobj = l
lineobj.points = []
ringsample.forEach(function(r){
let dist = turf.lineIntersect(l, r);
if (dist.features.length > 0){
lineobj.points.push(dist)
}
})
if (lineobj.points.length > 0){ arr.push(lineobj)}
})
return arr}()
Insert cell
offset = turf.lineOffset(overlaps[7], .02, {units: 'inches'});
Insert cell
hm = test[39].points.sort((a,b) => turf.distance(test[39].points[0],a)-turf.distance(test[39].points[0],b)).map(p => projection(p.geometry.coordinates))
Insert cell
point = function(){
let arr = []
overlaps.forEach(function(o){
arr.push(o.points)
})
return arr.flat(); }()
Insert cell
tiles[0].data.roads
Insert cell
map = svg`<svg viewBox="0 0 ${width} ${height}" style="width:100%;height:auto; id = "map"">


${tiles.map(d => svg`
<path fill="papayawhip" d="${path(d.data.water)}"></path>
<path fill="none" stroke="#ccc" stroke-width="0.75" d="${path(d.data.roads)}"></path>
<path fill="green" stroke="pink" stroke-width="1" d=${path(d.data.pois)}"></path>
`)}

${point.map(d => svg `<path fill="chartreuse" stroke="chartreuse" stroke-width="5" d="${path(d)}">
</path>`)}



${overlaps.map(d => svg `<path stroke ="${purple[d.points.length]}" fill="none" stroke-width="3" d="${path(d)}"></path>`)}




`
Insert cell
turf.bbox(tiles[10].data.roads.features[0])
Insert cell
test[37].points.sort((a,b) => turf.distance(a,b))
Insert cell
intsample = function(){
let arr = []
test.forEach(function(t){
let arr2 = []
t.points.forEach(p => {
let r = turf.pointsWithinPolygon(p, bbox.features[0])
if (r.features.length > 0){
arr2.push(r)}
})
if(arr2.length > 0){arr.push(arr2)}
})
return arr}()
Insert cell
fuckingA[37]
Insert cell
fuckingA = test.map(t => t.points.map((p, i) => projection(p.geometry.coordinates))).filter(t => t.length > 0)
Insert cell
fuckingA[1][0]
Insert cell
testline = lengths[26]
Insert cell
lengths = function(){
let arr = []
makeLines.forEach(function(m){
if (turf.length(m) < .05){
m.properties.length = turf.length(m)
arr.push(m)
}
})
return arr}()

Insert cell
lengths[(lengths.length)-1]
Insert cell
testcolors = d3.quantize(d3.interpolateHcl("orange", "turquoise"), 10)
Insert cell
d3colors = d3.quantize(d3.interpolateHcl("cyan", "hotpink"), 10)
Insert cell
Insert cell
color = d3.scaleSequential([0, 5], d3.interpolateHcl("cyan", "hotpink"))
Insert cell
reds = ["#fee5d9","#fcae91","#fb6a4a","#de2d26","#a50f15"]
Insert cell
purple = ["#f2f0f7","#cbc9e2","#9e9ac8","#756bb1","#54278f"]
Insert cell
Insert cell
import {legend} from "@d3/color-legend"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more