Play the video once loaded to see the example.
I took the idea from this tweet.
I created the path with the help of Geojson.io, and it’s not exact. The idea was showing the possibility of syncing the video with the path.
The video is a timelapse (I don’t dare driving this fast) taken at the paradise valley close to Agadir, Morocco. Go there if you have the opportunity!
The code should be improved. I think that some times don’t work if play is pressed beffore the video ends loading.
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<style>
video {
vertical-align: top;
}
</style>
<body>
<video width="320" height="240" controls>
<source src="valee.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/d3.geo.tile.v0.min.js"></script>
<script>
var width = 450,
height = 500;
var projection = d3.geo.mercator()
.center([-9.52, 30.5809])
.scale(1000000);
var path = d3.geo.path()
.projection(projection);
var tile = d3.geo.tile()
.scale(projection.scale() * 2 * Math.PI)
.translate(projection([0, 0]))
.zoomDelta((window.devicePixelRatio || 1) - .5);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var tiles = tile();
var defs = svg.append("defs");
svg.append("g")
.selectAll("image")
.data(tiles)
.enter().append("image")
.attr("xlink:href", function(d) {
return "http://b.tile.openstreetmap.org/" + d[2] + "/" + d[0] + "/" + d[1] + ".png";
})
.attr("width", Math.round(tiles.scale) + 1)
.attr("height", Math.round(tiles.scale) + 1)
.attr("x", function(d) { return Math.round((d[0] + tiles.translate[0]) * tiles.scale); })
.attr("y", function(d) { return Math.round((d[1] + tiles.translate[1]) * tiles.scale); });
d3.json("path.json", function(error, route) {
var pathLength;
var routeLine = svg.append("path")
.attr("d",path(route))
.attr("stroke","#f44")
.attr("stroke-width","4px")
.attr("fill","none")
.style('stroke-dasharray', function(d) {
pathLength = d3.select(this).node().getTotalLength();
return pathLength + 'px, ' + pathLength + 'px';
})
.style('stroke-dashoffset', function(d) {
return d3.select(this).node().getTotalLength() + 'px';
});
var video = d3.select("video")
.on("play", function(){
var currentTime = this.currentTime;
var duration = this.duration;
routeLine
.style('stroke-dashoffset', function(d) {
return pathLength*(1-(currentTime/duration))+'px';
});
routeLine
.transition()
.duration(1000*(duration - currentTime))
.ease("linear")
.style('stroke-dashoffset', '0px');
})
.on("pause", function(){
routeLine
.transition();
})
.on("seeked", function(){
var currentTime = this.currentTime;
var duration = this.duration;
routeLine
.style('stroke-dashoffset', function(d) {
return pathLength*(1-(currentTime/duration))+'px';
});
});
});
</script>
</body>
</html>