rveciana - map-scroller-associated-with-video-position

Map scroller associated with video position

Open raw page in new tab

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>