Reputation:
No one on here ever comments on my questions but maybe this is an easy one? I'm new to coding and I am trying to find a way to navigate a video, as in play the first 10 seconds then stop, play seconds 30-40 then stop, play second 60-30 then stop, etc and to have buttons for it. I have found a tutorial but the buttons don't respond. I've cleaned up the code a bit (don't think I removed anything necessary) and pasted it below. Tutorial link: https://www.sitepoint.com/html5-video-fragments-captions-dynamic-thumbnails/
HTML:
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="script.js"></script>
</head>
<body>
<section class="wrapper">
<div>
<video id="frag1" controls preload="metadata">
<source src="assets/disney.mp4" type='video/mp4;codecs="avc1.42E01E, mp4a.40.2"' data-original="assets/disney.mp4">
<source src="assets/disney.mp4" type='video/webm;codecs="vp8, vorbis"' data-original="assets/disney.mp4">
</video>
<nav>
<button data-start="0">Section One</button>
<button data-start="6">Section Two</button>
<button data-start="17">Section Three</button>
</nav>
</div>
</section>
</body>
</html>
CSS:
@charset "UTF-8";
#main { width: 85%; margin: 1em auto; }
section>div { margin: 0 1.5% 1.5% 0; padding: 1.5%; float: left; background-color: #efefef; }
video { width: 100%; min-height: 430px; }
button { cursor: pointer; }
nav>button { margin: 0.27em; }
nav>button:first-child { margin-left: 0; }
.wrapper { width: 520px; margin: auto; overflow: hidden; text-align: center; }
.p {
text-align: center;
padding-top: 120px;
}
Resources 1×0.5×0.25× Rerun
JAVASCRIPT:
function mediaFragOne()
{
var video, sources, nav, buttons;
video = document.querySelector('video#frag1');
sources = video.getElementsByTagName('source');
nav = document.querySelector('video#frag1+nav');
buttons = nav.getElementsByTagName('button');
for(var i = buttons.length - 1; i >= 0; i--)
{
buttons[i].addEventListener('click', function() {
for (var i = sources.length - 1; i >= 0; i--) {
sources[i].setAttribute(
'src', (sources[i].getAttribute('data-original')
.concat('#t=' + this.getAttribute('data-start'))));
video.load();
video.play();
};
});
}
}
mediaFragOne();
Upvotes: 1
Views: 2849
Reputation: 43880
Use Event Delegation when you have multiple tags to click.
Find an ancestor tag (ex. <nav>
) that all of the target tags (ex. <a>
) have in common. Register the ancestor tag to the event. Now whenever the ancestor tag or its descendant tags triggers the registered event, the callback function bound to the ancestor tag will fire. So essentially that's one event listener for an unlimited number of target tags.
document.querySelector(ancestor).addEventListener('click', callback);
Always have callback function pass the Event Object.
function callback(event) {...
Determine the tag that is the origin of event (button clicked, video time updated, etc...) by referencing Event.target.
const clicked = event.target
In the callback function it should only apply to the target tags and exclude all other tags.
if (clicked.matches('a')) {...
...}
return false;
Details commented in demo
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<style>
:root {
font: 400 2.5vw/1.2 Consolas
}
.vid {
display: block;
margin: 0 auto;
width: 80vw;
}
.btns {
display: flex;
justify-content: center;
width: 80vw;
margin: 0 auto;
}
a {
display: block;
margin: 5px 8px;
border: 1px solid #000;
border-radius: 8px;
text-decoration: none;
text-align: center;
padding: 3px 5px;
width: 15vw;
}
</style>
</head>
<body>
<video class='vid' src='https://storage04.dropshots.com/photos6000/photos/1381926/20170326/005610.mp4' controls></video>
<nav class='btns'>
<a href='#/' data-start='00' data-end='10'>00 - 10</a>
<a href='#/' data-start='10' data-end='20'>10 - 20</a>
<a href='#/' data-start='20' data-end='30'>20 - 30</a>
<a href='#/' data-start='30' data-end='40'>30 - 40</a>
</nav>
<script>
// Declare end
let end;
// Reference the parent tag of all buttons
const btns = document.querySelector('.btns');
// Reference the video
const vid = document.querySelector('.vid');
// Register the click event to nav.btns
btns.addEventListener('click', frag);
// Register the timeupdate event to video.vid
vid.addEventListener('timeupdate', stop);
// Pass Event Object
function frag(event) {
// Event.target always points to the clicked button, time-updated video, etc.
const clicked = event.target;
// if clicked tag is an <a>...
if (clicked.matches('a')) {
// Get the value of its data-start and convert it to a real number
let start = Number(clicked.dataset.start);
// Set end to the value of it data-end and convert it to a real number
end = Number(clicked.dataset.end);
// Set video current time to value of start
vid.currentTime = start;
// Play video
vid.play();
}
// End function
return false;
}
// Pass Event Object
function stop(event) {
// Reference the video
const vid = event.target;
// if it is a <video>...
if (vid.matches('video')) {
// and if that video time is currently at or past the value of end...
if (vid.currentTime >= end) {
// Pause video
vid.pause();
}
}
// End function
return false;
}
</script>
</body>
</html>
Upvotes: 1
Reputation: 163334
This is easier than you're making it to be. Just set the currentTime
property.
Untested, but this should get you started:
document.querySelector('nav').addEventListener('click', (e) => {
if (!e.target.matches('[data-start]')) {
return;
}
document.querySelector('video').currentTime = Number.parseFloat(e.target.dataset.start);
});
Upvotes: 0
Reputation: 4148
Just to elaborate @Brand answer, you can do it like that:
var vid = document.getElementById("frag1"); // set video to variable
var buttons = document.getElementsByTagName("button"); // element collection
for (var i = 0; i < buttons.length; i++) { // run for loop
buttons[i].addEventListener("click", function() { // add event listenr
var dataStart = this.getAttribute('data-start'); // extract start time
var dataEnd = this.getAttribute('data-end'); // extract end time
var dataDuration = Number(dataEnd - dataStart + '000'); // make the duration will assist on the setTimeOut
vid.currentTime = dataStart; // this is the magic
vid.play();
window.setTimeout(function(){ vid.pause(); }, dataDuration);// play according to duration
});
}
<section class="wrapper">
<div>
<video id="frag1" controls preload="metadata" width="400px">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4">
<source src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogg">
</video>
<nav>
<button data-start="0" data-end="10">Section One</button>
<button data-start="30" data-end="40">Section Two</button>
<button data-start="30" data-end="60">Section Three</button>
</nav>
</div>
</section>
You can find a lot more information about this here and here.
Hope that helps.
Upvotes: 0