News

Welcome to End Point’s blog

Ongoing observations by End Point people

Creating a video player with time markers - step by step

Introduction

Today we will show you how to create a video player with time markers using JavaScript and HTML5 only. Libraries that we will use are proven to be stable enough for production projects. What we want to achieve? The final result is visible below:

To simplify (or to make it harder for some of you :)) this tutorial we won't use any package management tools. The demo is available on Github here: https://github.com/peter-hank/video-with-markers

Requirements

We will need some libraries (all of these are free to use in commercial projects):

Step 1 - creating a project skeleton

Let's create a new folder for our project and call it video-with-markers. Inside let's create a new file called "index.html", three folders: "css", "js" and "var".

We also need to copy libraries files and put it into a proper directory:

Let's open the index.html file and fill it with some basic structure, that will include libraries files too.

<!doctype html>
<html>
 <head>
  <meta charset="utf-8"/>
  <meta http-equiv="x-ua-compatible" content="ie=edge"/>
  <title>Video with markers</title>
  <meta name="description" content=""/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <link rel="stylesheet" href="css/video-js.min.css"/>
  <link rel="stylesheet" href="css/videojs.markers.min.css"/>
  <script src="js/jquery-2.0.3.min.js"></script>
  <script src="js/video.min.js"></script>
  <script src="js/videojs-markers.min.js"></script>
 </head>
 <body>
 </body>
</html>

Step 2 - activating player and creating markers

TIP: all the further code should be put inside the body tag.

First, we need to create a video tag:

 

We need to set an element "id" attribute and both classes "video-js vjs-default-skin" to let player CSS apply. Other attributes are not required and are here just for demo purpose. "Data-setup" attribute is an attribute that configures multiple player options. More details can be found in the documentation here: http://docs.videojs.com/docs/guides/options.html.

At this point after launching index.html in a browser we should see a video player like this:

The only thing left is initializing markers. We can do this by adding some JavaScript code under the video player element:

// load video object
 var video = videojs('example_video_1');

 //load markers
 video.markers({
    markers: [
        {time: 9.5, text: "this"},
        {time: 16,  text: "is"},
        {time: 23.6,text: "so"},
        {time: 28,  text: "cool"}
    ];
 });

In this part we load an object of the Video.js player to video variable and then load a list of markers. Each marker object includes time in seconds when it should be shown and marker text.

Now, markers should be visible like on my this image and markers text will be visible after pointing at it:

It needs some additional CSS styling to achieve a result like on the first image but it's not much work.

The end

Almost the end. There are many more Video.js plugins ready to use, for example:

  • videojs-HDtoggle - button which toggles between HD and non-HD source,
  • videojs-playlist - plays videos continuously or by selecting them,
  • videojs-watermark - displays a watermark on top of the video.

With not much effort most of video player functionalities can be finalized. There is always some tweaking, but at least you can have a base for creating your project. And remember, if you will find bugs, report it! And if you have implemented something cool, share it!

Thanks for reading.

14 comments:

pete mulder said...

This was easy, thanks :)

Now I want to combine markers and playlist functionality. Ideally, my markers would be stretched over the timeline of the total (time of) vids in playlist. If that's not doable (I failed badly in my attempts), would you be able to tell how I can dynamically update markers on the timeline. Pleases note that vids don't have the same length, so the timeline needs to be rerendered as welll. Any (!) help would be highly appreciated!

cheers,
pete

Peter Hankiewicz said...

Hi Pete,

It is surely possible to stretch markers over the timeline but it will require creating a new plugin to create ranges. You can try to using this one: https://github.com/danielcebrian/rangeslider-videojs and create multiple ranges and disable a slider also.

Updating markers is pretty easy:
videoObject.markers({
markers: markerArray
});

Peter

pete mulder said...

Thank Peter,
I forked rangeslider-videojs and will have a look.
Will try to keep you posted of how I get one. I may nudge you when I get stick, but I promise not to overdo it - and try not to :)

Yippie-ki-yay said...

Hi Peter. About this plugin, I've been trying to insert pauses on the marks (including commmands in the "onMarkerReached" options, as explain by the author in the forum he post the plugin; but I don't make it work... do you mind to help?

Thanks

Seth

Peter Hankiewicz said...

Hi Yippie-ki-yay,

take a look at this example, it works just fine here:

var video = videojs('example_video_1');

//load markers
video.markers({
markers: [
{time: 9.5, text: "this"},
{time: 150, text: "is"},
{time: 250,text: "so"},
{time: 370, text: "cool"}
],
onMarkerReached: function () {
video.pause();
}
});

Apurv Gandhwani said...

Hi. I got the markers in mt timeline. Now I want to have markers of different color, say few markers of red color and few markers of green color, on a single timeline. How can I achieve this. Please help, I have been struggling with this. I tried to pass two arrays in markers array [ [],[] ] . But it didn't work.

Peter Hankiewicz said...

Hi Apurv,

when creating markers try this:
video.markers({
markers: [
{time: 9.5, text: "this", class: "marker-red"},
{time: 16, text: "is", class: "marker-blue"},
{time: 23.6,text: "so", class: "marker-red"},
{time: 28, text: "cool", class: "marker-blue"}
];
);

Then, in your CSS file set:
.marker-red { background-color: red; }
.marker-blue { background-color: blue; }

Good luck!

Apurv Gandhwani said...

Thanks for the previous solution Peter. I am facing one more problem. I want to jump to markers whenever I click a button. For example, say I have three markers on my timeline and three ui button for each of the marker. When I click first button, I should get jumped to first marker and same for other two buttons.

Peter Hankiewicz said...

Hi Apurv,

you can get a list of markers with:

var markers = player.markers.getMarkers();

Then you need to find a DOM element for each of the markers like this:

// foreach markers
var markerDiv = videoWrapper.find(".vjs-marker[data-marker-key='" + marker.key +"']");
// end foreach

To jump to any marker you can use:

markerDiv.click();

Apurv Gandhwani said...

But how can I connect this thing with the buttons in another component of another parent ?

Peter Hankiewicz said...

If you have the first button: 'button onclick="jumpToMarker(0)"'.

Then you need to create a function called jumpToMarker and using this function find an appropriate marker using the logic from my previous comment.

Apurv Gandhwani said...

@Peter
can I have functionality like this:
I have two different sets of markers array of json objects, Array A and Array B. Below the video player I have two buttons, Button A and Button B. Now by default I show markers array A on video time line. Now when I click button B markers should change on timeline to array B. Same for Button A - when I click it Array B show come as markers. and I want this not to affect the video i.e. player should not reload the video and start it from begining everytime I change markers by button.

Is it possible to achieve this.

Peter Hankiewicz said...

Yes Apurv, you can do it.

When one of these buttons is clicked use player.markers.removeAll() to clean a list of markers and then just reload the list with new objects.

Apurv Gandhwani said...

How will I reload the list?

Will it be something like this:

handleButtonClick(button_id){

switch(button_id){
case "A":
player.markers.removeAll(); //to remove markers
player.markers({ //to add new markers
markerStyle: {},
markers: ArrayA,

});

case "B":
player.markers.removeAll(); //to remove markers
player.markers({ //to add new markers
markerStyle: {},
markers: ArrayB,

});
}
}