HTML 5 video & mootools, part 2: Timeline

After creating buttons and a volume slider in the last post, we’re now going to develop a time slider — a movable slider which shows the current time of the video and which can be dragged to move the video playback accordingly.

Needed are two methods: Update the slider when the video is played and update the video when the slider is moved.

From time to range

The position of the slider relative to its width (or range) should correspond the relative timing position of the video (relative to its duration).

So we have:

position = time / duration * range

updatePosition: function(time)

Is called onTimeupdate at the video

The first one is called on every timeupdate-event: It receives the current time from the video, converts it relative to the slider range and then moves the slider to the calculated position.

updateVideo: function(position)

Is called onChange at the slider

The second is the other way around: On changing the slider position we calculate the video position the other way around and move the video playback to that position.

Fireworks and other problems

Unfortunately moving the slider (updating the video time) triggers the timeupdate event, which then moves the slider, which then … A nice fireworks of events – which we better try to avoid. In order to prevent one event from triggering the other, we do not call the set()-method from Slider if the video time has changed (which would then fire an onChange event) but we move the slider by updating the knob position.

We also have to avoid updating the slider if the video is in the seeking-state, because then the knob would jump around while the video is still loading data to find the target position.

Extending the slider

I created a new class (CwVideotimeline) with the methods described above. It is an extension of the Slider-class and automatically attaches the methods to the video events.

Class definition
CwVideotimeline = new Class({

	Implements: [Events, Options],
	Extends: Slider,
	
	options: {
		video: false,
		onChange: function(position) {
			this.updateVideo(position);
		}
	},
	
	initialize: function(element, knob, options)
	{
		this.parent(element, knob, options);
		this.setOptions(options);
		
		// on video timeupdate: call updatePosition		
		$(this.options.video).addEvent('timeupdate', function(an_event) {
			this.updatePosition(an_event.target.get('currentTime'));
		}.bind(this));

		// if we have finished seeking in the video: update the time
		$(this.options.video).addEvent('seeked', function(an_event) {
			this.updatePosition(an_event.target.get('currentTime'));
		}.bind(this));
	},
	
	updatePosition: function(time)
	{
		duration = $(this.options.video).get('duration');
		if (duration == 0 || this.range == 0 || $(this.options.video).get('seeking')) return; // we are seeking or video has no duration

		// we "manually" set the knob position in order to avoid triggering another event
		position = this.toPosition( time / duration * this.range );
		this.knob.setStyle(this.property, position);		
	},
	
	updateVideo: function(position)
	{
		duration = $(this.options.video).get('duration');
		if (duration == 0 || this.range == 0) return;
		videotime = ( position / this.range * duration); // from position to time
		$(this.options.video).set('currentTime', videotime);
	}	

});
Class usage example
var timeSlider = new CwVideotimeline('container', 'knob', {
    range: [0, 200],
    video: 'myvid',
    steps: 100,
    initialStep: 0
});
Chrome problems

Of course one browser always makes trouble: This time it’s Chrome, which does not continue to send timeupdate-events after seeking and suspending the video download. It’s a known bug, so hopefully fixed in the next version. Details: (Bugtracker for Chrome)

Example

See it in action below – note that not only dragging but also clicking the timline works (this is because Fx.Slider already handles this) and the rewind-button automatically updates the slider:

  play pause 0.0s   

CwVideotimeline:

 

 

5 Replies to “HTML 5 video & mootools, part 2: Timeline”

  1. Thanks a lot for your code, I only replaced :

    media_properties.each(function(prop){
    Element.Properties[prop] ={
    set: function(value){
    this[prop] = value;
    },
    get: function(){
    return this[prop];
    }
    //erase:function();
    };
    });
    // woks fine with mootools 1.4

    I use it for web-doc sample :
    (here a video-how-to, sorry in french ;-))
    http://www.alter.be/extranet/media/videoPlayer_4.php

    1. Really? A ton of effort put into showing how to use HTML5 tools and your only response is “cool dj”? Thats all you noticed? ….wow.

      Excellent article author.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.