The Dead Man
The Dead Man

Reputation: 5566

How to add markers in html5 video player on video progress indication bar?

I have a simple custom HTML 5 video player, I would like to add markers to my video player, progress indication bar something like this.

enter image description here

So far Here is my solution just for one marker at 0.6s.

HTML

<div canplay id="video-block">
    <div id="video-container">
        <video id="videoplayer" ref="video"  autoplay webkit-playsinline playsinline>
            <source src="videos/vmerce.mp4" type="video/mp4">
        </video>

    </div>
    <div id="video-controls" style="position: relative; display: block">
        <div id="seek-bar-container">
            <div id="seek-bar">
                <div id="current-time">

                </div>
            </div>
        </div>
        <div id="pause-play-button">
            <img id="play" src="images/play.png"> 
            <img id="pause" src="images/pause.png" style="display:none">
        </div>
    </div>
</div>

Here is js to add markers

$(document).ready(function(){

    //get videoplayer tag element
        var videoplayerID =document.getElementById("videoplayer");
        var ranges = [{
            from: 0,
            to: 6
        },
        {
            from: 6,
            to: 9
        },
        {
            from: 9,
            to: 25
        },
        {
            from: 25,
            to: 38
        }, 
    ];

    console.log(ranges[0].to);

        videoplayerID.addEventListener("timeupdate", function () {
            if ($(this)[0].duration) {
                $(this).parent().parent().find("#current-time").css("width", ($(this)[0].currentTime * 100 / $(this)[0].duration) + "%");
            }

            if (this.currentTime >= ranges[0].to) {

                var bb =$('<div class="bubles"></div>')

                $("#current-time").append(bb);

            }
        });


})

Now when I run my app I get the following.

enter image description here

What do I need to do to get what I want?

Upvotes: 4

Views: 9272

Answers (3)

Govind Totla
Govind Totla

Reputation: 1178

For those, who are looking answer for a videojs package, use the following approach that worked for me.

markers = [
  { time: 10, title: "Introduction" },
  { time: 30, title: "Chapter 1" },
  { time: 50, title: "Chapter 2" },
  { time: 70, title: "Conclusion" }
];

This is my player initialization

this.player = videojs(this.videoPlayerElement.nativeElement, {
  techOrder: ['youtube'],
  sources: [{ type: 'video/youtube', src: 'YT URL' }],
  youtube: { iv_load_policy: 3 }, // Disable annotations
});

// Wait until player is ready and metadata is loaded
this.player.on('loadedmetadata', () => {
  this.addMarkers();
});

and the add Markers Method

addMarkers(): void {
    const player = this.player;
    const duration = player.duration();

    if (isNaN(duration) || duration === 0) {
      console.warn('Video duration is not available.');
      return;
    }

    // Locate the progress bar element within the control bar
    const progressControl = player.el().querySelector('.vjs-progress-holder');

    if (progressControl) {
      this.markers.forEach((time) => {
        if (time < duration) {
          const markerEl = document.createElement('div');
          markerEl.className = 'marker';
          markerEl.style.left = `${(time / duration) * 100}%`;
          markerEl.setAttribute('title', marker.title);

          // Seek to the marker's time when clicked
          markerEl.addEventListener('click', (e) => {
            e.stopPropagation();
            player.currentTime(time);
          });

          // Append marker to the progress control element
          progressControl.appendChild(markerEl);
        }
      });
    } else {
      console.warn('Progress bar element not found');
    }
  }

This is pretty clean approach to have markers. Use the following CSS for beautification

.marker {
  position: absolute;
  height: 8px;
  width: 4px;
  background-color: red;
  border-radius: 2px;
  pointer-events: auto;
  cursor: pointer;
}
.marker[title]:hover::after {
  content: attr(title);
  position: absolute;
  bottom: 20px; /* Adjust for tooltip positioning */
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(0, 0, 0, 0.75);
  color: #fff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 12px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 1000;
}

Upvotes: 0

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20944

You are on the right track with calculating the width of the #current-time bar. Outside of the timeupdate listener do the same for each range or marker.

Loop over each position of the marker and calculate the offset of the left property just like you did with the width property. This will give you the position of each marker on the timeline.

Then in the loop create each marker, give it the left property value and add them, for example, to the #seekbar.

// Video and seekbar
const video = document.getElementById('videoplayer');
const seekBar = document.getElementById('seekbar');

// Positions of markers in seconds.
const positions = [3, 6.5, 7];

// Set the markers when we CAN know the duration of the video.
video.addEventListener('loadedmetadata', () => {

  // Add each marker to the #seekbar element.
  positions.forEach(function(position) {

    // Is position within range of the duration?
    if (position <= video.duration) {

      // Calculate position in percentage..
      const left = (position / video.duration) * 100 + '%';

      // ..create marker and give it the left value..
      const marker = document.createElement('div');
      marker.classList.add('bubles');
      marker.style.left = left;

      // ..and add the marker to the #seekbar.
      seekBar.appendChild(marker);
    }
  });
});

This would place each marker on the timeline with a percentage value. After the loop continue with listening to the timeupdate event.

If you want to incorporate ranges, like in your example, than it would require some modification. But this will help get you started on where you are trying to go.

Upvotes: 4

VrotteOtter
VrotteOtter

Reputation: 11

Have a look at this previous answer on a similar question, I think you will find your solution there. Answered by vnponce.

https://stackoverflow.com/a/39127919/12212335

Upvotes: 1

Related Questions