Skip to content

Instantly share code, notes, and snippets.

@betatim
Forked from zross/index.html
Last active July 15, 2016 21:17
Show Gist options
  • Save betatim/df0dda15b75745b966e676e7b85f8748 to your computer and use it in GitHub Desktop.
Save betatim/df0dda15b75745b966e676e7b85f8748 to your computer and use it in GitHub Desktop.
D3, Leaflet animation
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7/leaflet.css" />
<script src="http://d3js.org/d3.v3.min.js" type="text/javascript"></script>
<script src="http://cdn.leafletjs.com/leaflet-0.7/leaflet.js"></script>
<script src='https://api.tiles.mapbox.com/mapbox.js/v1.6.4/mapbox.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox.js/v1.6.4/mapbox.css' rel='stylesheet' />
<style>
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
}
#map {
width: 100%;
height: 100%;
}
svg {
position: relative;
}
path {
fill: none;
stroke-width: 4px;
stroke: black;
stroke-opacity: 0.5;
}
path.true {
stroke: #3366FF;
}
path.false {
stroke: #990099;
}
circle {
fill: yellow;
opacity: 0.75;
}
.area {
fill: #3366FF;
}
.empty {
fill: #990099;
}
</style>
</head>
<body>
<div id="demo"></div>
<div id="map"></div>
<script type="text/javascript">
var mapboxTiles = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '<a href="http://www.mapbox.com/about/maps/" target="_blank">Terms &amp; Feedback</a>'
});
var map = L.map('map')
.addLayer(mapboxTiles)
.setView([40.72332345541449, -74.00390625], 10);
// we will be appending the SVG to the Leaflet map pane
// g (group) element will be inside the svg and it
svg = d3.select(map.getPanes().overlayPane).append("svg"),
// if you don't include the leaflet-zoom-hide when a
// user zooms in or out you will still see the phantom
// original SVG
g = svg.append("g").attr("class", "leaflet-zoom-hide");
//read in the GeoJSON. This function is asynchronous so
// anything that needs the json file should be within
d3.json("linestring2.json", function(collection) {
//stream transform. transforms geometry before passing it to
// listener. Can be used in conjunction with d3.geo.path
// to implement the transform. In this case the transform
var transform = d3.geo.transform({
point: projectPoint
});
//d3.geo.path translates GeoJSON to SVG path codes.
//essentially a path generator. In this case it's
// a path generator referencing our custom "projection"
// which is the Leaflet method latLngToLayerPoint inside
// our function called projectPoint
var d3path = d3.geo.path().projection(transform);
//essentially we're appending our features to the
// group element. We're adding a class with the line name
// and we're making them invisible
var lineFeatures = g.selectAll("path")
.data(collection.features)
.enter()
.append("path")
.attr("class", function(d) {
return d.properties.name
})
.attr("style", "opacity:0.5");
// this is going to be the circle that tracks the
// route, we're appending it to the g element
var marker = g.append("circle");
marker.attr("r", 10)
.attr("id", "marker");
// for now we're selecting just one of the lines. And
// on this one line we're invoking (with the selection.call)
// our transition function. Using callis the same as invoking
// the function by hand but makes it easier to use method
// chaining.
var path = svg.select("path.line0")
.attr("style", "opacity:1")
.call(transition);
// when the user zooms in or out you need to reset
// the view
map.on("viewreset", reset);
// this puts stuff on the map! Without this "path"
// only exists in theory
reset();
var startPoint = pathStartPoint(path);
marker.attr("transform", "translate(" + startPoint[0] + "," + startPoint[1] + ")");
// Reposition the SVG to cover the features.
function reset() {
var bounds = d3path.bounds(collection),
topLeft = bounds[0],
bottomRight = bounds[1];
// here you're setting some styles, width, heigh etc
// to the SVG. Note that we're adding a little height and
// width because otherwise the bounding box would perfectly
// cover our features BUT... since you might be using a big
// circle to represent a 1 dimensional point, the circle
// might get cut off.
svg.attr("width", bottomRight[0] - topLeft[0] + 100)
.attr("height", bottomRight[1] - topLeft[1] + 100)
.style("left", topLeft[0] - 50 + "px")
.style("top", topLeft[1] - 50 + "px");
lineFeatures.attr("d", d3path);
g.attr("transform", "translate(" + (-topLeft[0] + 50) + "," + (-topLeft[1] + 50) + ")" );
}// end reset
function pathStartPoint(path) {
var d = path.attr('d');
console.log(d)
dsplitted = d.split("L")[0].slice(1).split(",");
var point = []
point[0] = parseInt(dsplitted[0]);
point[1] = parseInt(dsplitted[1]);
return point;
}//end pathStartPoint
function transition(path) {
path.transition()
.duration(7500)
.attrTween("stroke-dasharray", tweenDash);
//if you want to have it repeat the sequence
// then uncomment this piece
//.each("end", function() {
// d3.select(this).call(transition);
//}); // infinite loop
} //end transition
function tweenDash() {
var l = path.node().getTotalLength(); //total length of path
var i = d3.interpolateString("0," + l, l + "," + l); // interpolation of stroke-dasharray style attr
console.log(l)
return function(t) {
//t is fraction of time 0-1 since transition began
var marker = d3.select("#marker");
console.log(t)
// p is the point on the line (coordinates) at a given length
// along the line. In this case if l=50 and we're midway through
// the time then this would 25.
var p = path.node().getPointAtLength(t * l);
//Move the marker to that point
marker.attr("transform", "translate(" + p.x + "," + p.y + ")"); //move marker
return i(t);
}
} //end tweenDash
// Use Leaflet to implement a D3 geometric transformation.
// the latLngToLayerPoint is a Leaflet conversion method:
//Returns the map layer point that corresponds to the given geographical
// coordinates (useful for placing overlays on the map).
function projectPoint(x, y) {
var point = map.latLngToLayerPoint(new L.LatLng(y, x));
this.stream.point(point.x, point.y);
}//end projectPoint
});
</script>
</body>
</html>
Display the source blob
Display the rendered blob
Raw
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {"name":"line0"},
"geometry": {
"type": "LineString",
"coordinates": [
[
-73.93592834472656,
40.85329308567513
],
[
-73.94210815429688,
40.826799936046804
],
[
-73.96408081054688,
40.7909394098518
],
[
-73.99978637695312,
40.75557964275591
],
[
-73.9990997314453,
40.73529128534676
],
[
-73.99772644042969,
40.71499673906409
],
[
-73.98468017578125,
40.691051628010236
],
[
-73.96614074707031,
40.65615965408628
],
[
-73.93592834472656,
40.63896734381723
],
[
-73.89266967773438,
40.640530464129945
],
[
-73.86657714843749,
40.65563874006118
],
[
-73.8446044921875,
40.70042247927178
],
[
-73.81782531738281,
40.71551718935035
],
[
-73.80340576171875,
40.73164913017892
]
]
}
},
{
"type": "Feature",
"properties": {"name":"line1"},
"geometry": {
"type": "LineString",
"coordinates": [
[
-73.96133422851562,
40.76806170936614
],
[
-73.93867492675781,
40.75818026660039
],
[
-73.91189575195312,
40.73321007823572
],
[
-73.91876220703125,
40.70510741061974
],
[
-73.85284423828125,
40.72124187397379
]
]
}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment