Video timeline thumbnail · Flowplayer

 

<head/>

<style>

.flowplayer canvas {
   outline: 4px solid #fff;
   position: absolute;
   z-index: 9999;
   display: none;
}

     

<script>

flowplayer(function (api, root) {
   api.bind('ready', function (e, api, video) {
      var thumbheight = Math.round(root.height() / 8);
      root.append($('<canvas/>').attr({
         height: thumbheight,
         width: Math.round(thumbheight * video.width / video.height)
      }));
   });
});

$(function() {

  var withThumbnail = function(fpVideo, callback) {
     var thumb = $('video.fp-thumbnail');
     if (!thumb.length) {
        thumb = fpVideo.clone().addClass('fp-thumbnail').appendTo($('body')).css({
           position: 'absolute',
           left: -9999
        }).on('loadedmetadata', function() {
           callback(thumb);
        });
        thumb[0].load();
     } else if (thumb[0].readyState !== 4) {
        thumb.on('loadedmetadata', function() {
           callback(thumb);
        });
     } else {
        callback(thumb);
     }
  }

  $('.fp-timeline').on('mousemove', function(ev) {
     var timelineOffset = $('.fp-timeline').offset(),
         percentage = (ev.pageX - timelineOffset.left) / $('.fp-timeline').width(),
         canv = $('.flowplayer canvas'),
         canvWidth = canv.width(),
         canvHeight = canv.height(),
         fpVideo = $('.flowplayer video');

     canv.show().css({
        left: Math.round(ev.pageX - (flowplayer().isFullscreen ? canvWidth / 2 : canvWidth + 4 * 2)),
        bottom: Math.round($('.flowplayer .fp-controls').height() + 4 * 2)
     });
     withThumbnail(fpVideo, function(thumb) {
        thumb[0].currentTime = fpVideo[0].duration * percentage;
        thumb.one('seeked', function() {
           var canvas = canv[0];
           var ctx = canvas.getContext('2d');
           ctx.drawImage(thumb[0], 0, 0, canvWidth, canvHeight);
        });
     })
  }).on('mouseleave', function() {
     $('.flowplayer canvas').hide();
  });
});