Reputation: 5566
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.
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.
What do I need to do to get what I want?
Upvotes: 4
Views: 9272
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
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
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