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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more