Last active
July 26, 2016 02:17
-
-
Save ResidentMario/2159ca63831998f05c3fe64933c0df09 to your computer and use it in GitHub Desktop.
New York City Sample Bike Path (D3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>A Week in the Life of a CitiBike</title> | |
<style type="text/css"> | |
html { height: 100% } | |
body { height: 100%; margin: 0; padding: 0 } | |
#map-canvas { height: 100% } | |
</style> | |
<link href='https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.css' | |
rel='stylesheet' type='text/css'/> | |
<meta http-equiv="X-UA-Compatible" content="IE=Edge"> | |
</head> | |
<body> | |
<div id="map-canvas"></div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js"></script> | |
<script src="https://d3js.org/d3.v3.js"></script> | |
<script src="https://d3js.org/d3-queue.v3.js"></script> | |
<script src="L.D3SvgOverlay.js"></script> | |
<script> | |
// Initializes the basemap. | |
var map = L.map("map-canvas",{center:[40.773889, -73.983611],zoom:12}); | |
L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', { | |
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="http://cartodb.com/attributions">CartoDB</a>', | |
subdomains: 'abcd', | |
maxZoom: 19 | |
}).addTo(map); | |
// D3-SVG-Overlay callback wrapper. Leaflet is used only for the base map, all of the programmatic action occurs | |
// in d3 code inside of this callback. | |
var mapOverlay = L.d3SvgOverlay(function(sel,proj){ | |
// Paints a single sampler path. | |
function paintPath(linearray) { | |
console.log(linearray); | |
// Define x and y conversions. | |
var line = d3.svg.line() | |
.x(function(d) { console.log(d); return proj.latLngToLayerPoint(d).x}) | |
.y(function(d) { console.log(d); return proj.latLngToLayerPoint(d).y}); | |
console.log(line); | |
sel.append("path") | |
.datum(linearray) | |
// TODO: Troubleshoot why the line is so funky. | |
.attr({ | |
"class": "sample-line", | |
"d": line, | |
"fill": "transparent", | |
"stroke": "steelblue", | |
"stroke-width": 0.1, | |
"shape-rendering": "crispEdges" | |
}) | |
} | |
// Paints a single sampler path (paints things as a pile of points). | |
// Test method, now disused. | |
function paintPointPath(pointarray) { | |
console.log(pointarray); | |
sel.append('g') | |
.selectAll('circle') | |
.data(pointarray) | |
.enter() | |
.append('circle') | |
.attr({ | |
"cx": function (d) { | |
return proj.latLngToLayerPoint(d).x; | |
}, | |
"cy": function (d) { | |
return proj.latLngToLayerPoint(d).y; | |
}, | |
"r": 0.2 | |
}); | |
} | |
// Paints all of the paths. | |
function paintPathSampler() { | |
d3.json("path_sampler.json", function (data) { | |
console.log(data[0]); | |
paintPath(data[0]); | |
paintPath(data[1]); | |
// paintPointPath(data[0]); | |
}); | |
} | |
// function paintPathSampler() { | |
// d3.json("../../static/post_assets/citibike/bike_week_sampler.json", function (data) { | |
// console.log(data); | |
// console.log(data[0]); | |
// | |
// paintPointPath(data[0]); | |
// | |
// }); | |
// } | |
function delayedHello(callback) { | |
setTimeout(function() { | |
console.log("Hello!"); | |
callback(null); | |
}, 10); | |
} | |
q = d3.queue(); | |
q.defer(paintPathSampler); | |
q.defer(delayedHello); | |
q.await(function(error) { | |
if (error) throw error; | |
console.log("Goodbye!"); | |
}); | |
// ACTUAL CODE | |
// Now we define the functions to be called as part of the visualization. | |
// Set up a d3 queue for managing event order. | |
// var q = d3.queue(); | |
// d3.csv("nyc-starbucks-locations.csv", function(data) { | |
// sel.selectAll('circle') | |
// .data(data) | |
// .enter() | |
// .append('circle') | |
// .attr({ | |
// "cx": function(d) { return proj.latLngToLayerPoint([d.latitude, d.longitude]).x; }, | |
// "cy": function(d) { return proj.latLngToLayerPoint([d.latitude, d.longitude]).y; }, | |
// "r": 4 | |
// }); | |
// }); | |
}); | |
// Add overlay to map. | |
mapOverlay.addTo(map); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Copyright 2015 Teralytics AG | |
* | |
* @author Kirill Zhuravlev <kirill.zhuravlev@teralytics.ch> | |
* | |
*/ | |
(function (factory) { | |
if (typeof define === 'function' && define.amd) { | |
define(['leaflet', 'd3'], factory); | |
} else if (typeof module === 'object' && module.exports) { | |
module.exports = factory(require('leaflet', 'd3')); | |
} else { | |
factory(L, d3); | |
} | |
}(function (L, d3) { | |
// Check requirements | |
if (typeof d3 == "undefined") { | |
throw "D3 SVG Overlay for Leaflet requires D3 library loaded first"; | |
} | |
if (typeof L == "undefined") { | |
throw "D3 SVG Overlay for Leaflet requires Leaflet library loaded first"; | |
} | |
// Tiny stylesheet bundled here instead of a separate file | |
if (L.version >= "1.0") { | |
d3.select("head") | |
.append("style").attr("type", "text/css") | |
.text("g.d3-overlay *{pointer-events:visiblePainted;}"); | |
} | |
// Class definition | |
L.D3SvgOverlay = (L.version < "1.0" ? L.Class : L.Layer).extend({ | |
includes: (L.version < "1.0" ? L.Mixin.Events : []), | |
_undef: function(a){ return typeof a == "undefined" }, | |
_options: function (options) { | |
if (this._undef(options)) { | |
return this.options; | |
} | |
options.zoomHide = this._undef(options.zoomHide) ? false : options.zoomHide; | |
options.zoomDraw = this._undef(options.zoomDraw) ? true : options.zoomDraw; | |
return this.options = options; | |
}, | |
_disableLeafletRounding: function(){ | |
this._leaflet_round = L.Point.prototype._round; | |
L.Point.prototype._round = function(){ return this; }; | |
}, | |
_enableLeafletRounding: function(){ | |
L.Point.prototype._round = this._leaflet_round; | |
}, | |
draw: function () { | |
this._disableLeafletRounding(); | |
this._drawCallback(this.selection, this.projection, this.map.getZoom()); | |
this._enableLeafletRounding(); | |
}, | |
initialize: function (drawCallback, options) { // (Function(selection, projection)), (Object)options | |
this._options(options || {}); | |
this._drawCallback = drawCallback; | |
}, | |
// Handler for "viewreset"-like events, updates scale and shift after the animation | |
_zoomChange: function (evt) { | |
this._disableLeafletRounding(); | |
var newZoom = this._undef(evt.zoom) ? this.map._zoom : evt.zoom; // "viewreset" event in Leaflet has not zoom/center parameters like zoomanim | |
this._zoomDiff = newZoom - this._zoom; | |
this._scale = Math.pow(2, this._zoomDiff); | |
this.projection.scale = this._scale; | |
this._shift = this.map.latLngToLayerPoint(this._wgsOrigin) | |
._subtract(this._wgsInitialShift.multiplyBy(this._scale)); | |
var shift = ["translate(", this._shift.x, ",", this._shift.y, ") "]; | |
var scale = ["scale(", this._scale, ",", this._scale,") "]; | |
this._rootGroup.attr("transform", shift.concat(scale).join("")); | |
if (this.options.zoomDraw) { this.draw() } | |
this._enableLeafletRounding(); | |
}, | |
onAdd: function (map) { | |
this.map = map; | |
var _layer = this; | |
// SVG element | |
if (L.version < "1.0") { | |
map._initPathRoot(); | |
this._svg = d3.select(map._panes.overlayPane) | |
.select("svg"); | |
this._rootGroup = this._svg.append("g"); | |
} else { | |
this._svg = L.svg(); | |
map.addLayer(this._svg); | |
this._rootGroup = d3.select(this._svg._rootGroup).classed("d3-overlay", true); | |
} | |
this._rootGroup.classed("leaflet-zoom-hide", this.options.zoomHide); | |
this.selection = this._rootGroup; | |
// Init shift/scale invariance helper values | |
this._pixelOrigin = map.getPixelOrigin(); | |
this._wgsOrigin = L.latLng([0, 0]); | |
this._wgsInitialShift = this.map.latLngToLayerPoint(this._wgsOrigin); | |
this._zoom = this.map.getZoom(); | |
this._shift = L.point(0, 0); | |
this._scale = 1; | |
// Create projection object | |
this.projection = { | |
latLngToLayerPoint: function (latLng, zoom) { | |
zoom = _layer._undef(zoom) ? _layer._zoom : zoom; | |
var projectedPoint = _layer.map.project(L.latLng(latLng), zoom)._round(); | |
return projectedPoint._subtract(_layer._pixelOrigin); | |
}, | |
layerPointToLatLng: function (point, zoom) { | |
zoom = _layer._undef(zoom) ? _layer._zoom : zoom; | |
var projectedPoint = L.point(point).add(_layer._pixelOrigin); | |
return _layer.map.unproject(projectedPoint, zoom); | |
}, | |
unitsPerMeter: 256 * Math.pow(2, _layer._zoom) / 40075017, | |
map: _layer.map, | |
layer: _layer, | |
scale: 1 | |
}; | |
this.projection._projectPoint = function(x, y) { | |
var point = _layer.projection.latLngToLayerPoint(new L.LatLng(y, x)); | |
this.stream.point(point.x, point.y); | |
}; | |
this.projection.pathFromGeojson = | |
d3.geo.path().projection(d3.geo.transform({point: this.projection._projectPoint})); | |
// Compatibility with v.1 | |
this.projection.latLngToLayerFloatPoint = this.projection.latLngToLayerPoint; | |
this.projection.getZoom = this.map.getZoom.bind(this.map); | |
this.projection.getBounds = this.map.getBounds.bind(this.map); | |
this.selection = this._rootGroup; | |
if (L.version < "1.0") map.on("viewreset", this._zoomChange, this); | |
// Initial draw | |
this.draw(); | |
}, | |
// Leaflet 1.0 | |
getEvents: function() { return {zoomend: this._zoomChange}; }, | |
onRemove: function (map) { | |
if (L.version < "1.0") { | |
map.off("viewreset", this._zoomChange, this); | |
this._rootGroup.remove(); | |
} else { | |
this._svg.remove(); | |
} | |
}, | |
addTo: function (map) { | |
map.addLayer(this); | |
return this; | |
} | |
}); | |
L.D3SvgOverlay.version = "2.2"; | |
// Factory method | |
L.d3SvgOverlay = function (drawCallback, options) { | |
return new L.D3SvgOverlay(drawCallback, options); | |
}; | |
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[[[40.76529, -73.98208], [40.76476, -73.98225], [40.76457, -73.98232], [40.76441, -73.98238], [40.76438, -73.98239], [40.76434, -73.98241], [40.76423, -73.98245], [40.76412, -73.98249], [40.76405, -73.98252], [40.76402, -73.98254], [40.76396, -73.98257], [40.76351, -73.98281], [40.76339, -73.98288], [40.7633, -73.98293], [40.76318, -73.983], [40.76282, -73.98321], [40.76273, -73.98326], [40.76264, -73.98332], [40.76219, -73.9836], [40.76207, -73.98368], [40.76178, -73.98387], [40.76145, -73.98411], [40.7608, -73.98452], [40.76072, -73.98456], [40.76052, -73.98465], [40.76013, -73.98487], [40.76013, -73.98487], [40.75999, -73.98453], [40.75984, -73.98418], [40.75984, -73.98418], [40.75952, -73.98441], [40.7592, -73.98461], [40.75858, -73.98507], [40.75833, -73.98526], [40.75796, -73.98553], [40.75778, -73.98568], [40.75734, -73.986], [40.7567, -73.98648], [40.75603, -73.98695], [40.75603, -73.98695], [40.75582, -73.98644], [40.75582, -73.98644], [40.75505, -73.98668], [40.75434, -73.98691], [40.75362, -73.98713], [40.75332, -73.98723], [40.75303, -73.98732], [40.75291, -73.98735], [40.75218, -73.98754], [40.75187, -73.98761], [40.75183, -73.98762], [40.75145, -73.98771], [40.7512, -73.98774], [40.7507, -73.98783], [40.75036, -73.98789], [40.74988, -73.98798], [40.74968, -73.98804], [40.74957, -73.98809], [40.74948, -73.98814], [40.74925, -73.9883], [40.74924, -73.9883], [40.74923, -73.98829], [40.74919, -73.98819], [40.74912, -73.98804], [40.74912, -73.98802], [40.74911, -73.98802], [40.7491, -73.98801], [40.749, -73.98803], [40.74898, -73.98805], [40.74896, -73.98807], [40.74894, -73.98808], [40.74881, -73.9881], [40.74869, -73.98812], [40.74863, -73.98813], [40.74858, -73.98814], [40.74845, -73.98817], [40.74831, -73.9882], [40.74811, -73.98824], [40.74754, -73.98836], [40.74735, -73.98839], [40.74721, -73.98841], [40.74713, -73.98843], [40.74707, -73.98844], [40.74679, -73.98849], [40.74604, -73.98858], [40.74582, -73.98867], [40.74559, -73.98872], [40.7453, -73.98877], [40.74455, -73.9889], [40.74435, -73.98894], [40.74412, -73.98899], [40.74392, -73.98903], [40.7438, -73.98904], [40.74368, -73.98905], [40.74337, -73.98911], [40.74316, -73.98915], [40.74303, -73.98917], [40.74294, -73.98919], [40.74261, -73.98924], [40.74257, -73.98924], [40.74253, -73.98924], [40.74252, -73.98923], [40.7425, -73.98922], [40.74231, -73.98902], [40.74231, -73.98902], [40.74225, -73.98906], [40.7419, -73.98931], [40.7418, -73.9894], [40.74155, -73.98959], [40.74087, -73.9901], [40.74025, -73.99053], [40.73967, -73.99096], [40.73908, -73.99139], [40.73849, -73.99181], [40.73792, -73.99222], [40.73732, -73.99267], [40.73669, -73.99315], [40.73624, -73.99347], [40.73618, -73.99352], [40.73602, -73.99363], [40.7353, -73.99416], [40.73467, -73.99459], [40.73403, -73.99507], [40.73344, -73.99552], [40.73284, -73.99594], [40.73225, -73.99638], [40.73185, -73.99668], [40.73141, -73.99698], [40.73141, -73.99698], [40.73147, -73.9971], [40.73216, -73.9985], [40.73222, -73.99863], [40.73222, -73.99863], [40.73211, -73.99873], [40.73164, -73.99913], [40.73105, -73.99962], [40.73105, -73.99962], [40.73067, -73.99886], [40.73067, -73.99886], [40.73046, -73.99903]]] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment