JS Video Player

smackdh

Mattias Velamsson

Posted on January 4, 2023

JS Video Player

This is an exercise from the JS30-challange


So, for todays challenge we'll be making a video player in JavaScript.

For reference, this is the HTML skeleton that I'll be using when selecting my different elements.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>HTML Video Player</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="player">
      <video class="player__video viewer" src="video.mp4"></video>

      <div class="player__controls">
        <div class="progress">
          <div class="progress__filled"></div>
        </div>
        <button class="player__button play-toggle" title="Toggle Play"></button>
        <input
          type="range"
          name="volume"
          class="player__slider"
          min="0"
          max="1"
          step="0.05"
          value="1"
        />
        <input
          type="range"
          name="playbackRate"
          class="player__slider"
          min="0.5"
          max="2"
          step="0.1"
          value="1"
        />
        <button data-skip="-15" class="player__button">« 15s</button>
        <button data-skip="15" class="player__button">15s »</button>
        <button class="player__button fullscreenToggle">[ ]</button>
      </div>
    </div>

    <script src="scripts.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Challenges & Goals

As this is my first time trying to build something like this, my main challenges and goal will be:

  • Understanding the different components needed
  • Targeting the correct elements
  • Understanding the logic needed for time, rate and progressbar.


For this specific player, the settings available will be:

  • Skipping forward/backwards
  • Toggling fullscreen
  • Setting playback rate
  • Changing volume
  • Tracking video progress

1. Getting the elements needed

First, I'll make variables for a bunch of elements I need.

const player = document.querySelector(".player");
const video = document.querySelector(".viewer");
const play = document.querySelector(".play-toggle");
const sliders = document.querySelectorAll(".player__slider");
const skipButtons = document.querySelectorAll("[data-skip]");
const progressBar = document.querySelector(".progress__filled");
const progress = document.querySelector(".progress");
const fullScreenToggle = document.querySelector(".fullscreenToggle");
Enter fullscreen mode Exit fullscreen mode

2. Adding Play / Pause

Create the function.

function togglePlay() {
 // console.log("Play/Pause");
  const method = video.paused ? "play" : "pause";
  video[method]();
}
Enter fullscreen mode Exit fullscreen mode

Play the video if it's paused, pause it if it's playing.

In this player, I want the user to be able to click anywhere on the video, as well as using the play/pause button. So I'll be making two event listeners for this.

video.addEventListener("click", togglePlay);
play.addEventListener("click", togglePlay);
Enter fullscreen mode Exit fullscreen mode

And that should do it. Play/Pause should now be working.

3. Adding Volume / Playbackspeed

Create the function and logic.

function handleRangeUpdate() {
  video[this.name] = this.value;
}
Enter fullscreen mode Exit fullscreen mode

"this" refers to the element/object this was called on. Take the video attribute and update it's value.

I have two sliders, both of which I selected with one query earlier. So, I'll iterate over them to get a listener on both.

sliders.forEach((slider) =>
  slider.addEventListener("change", handleRangeUpdate)
);
Enter fullscreen mode Exit fullscreen mode

And now, changes on the slider will call the handleRangeUpdate function, and update the value accordingly.

4. Adding Skipping/Rewinding 15s

This one is pretty much the same as the last one, just with a bit of logic.

Creating the function

 function skip() {
  video.currentTime += parseFloat(this.dataset.skip);
 }
Enter fullscreen mode Exit fullscreen mode

Takes the value of the buttons dataset.skip(see HTML)and adds it to the current time of the video.

Adding a listener

skipButtons.forEach((button) => button.addEventListener("click", skip));
Enter fullscreen mode Exit fullscreen mode

Now, whichever button i click, depending on the value of the dataset.skip, it will either rewind or skip 10s on click.

5. Adding Fullscreen

This was pretty straight forward, as all the instructions could quickly be found in the MDN docs.

Creating the function

function handleFullscreen() {
  if (video.requestFullscreen) {
    video.requestFullscreen();
  } else if (video.webkitRequestFullscreen) {
    video.webkitRequestFullscreen();
  } else if (video.msRequestFullscreen) {
    video.msRequestFullscreen();
  }
}
Enter fullscreen mode Exit fullscreen mode

else if conditions to support other browsers.

Adding a listener

fullScreenToggle.addEventListener("click", handleFullscreen);
Enter fullscreen mode Exit fullscreen mode

And that's it. There's no need to add any conditions for closing fullscreen, as this is already added in the browsers built in fullscreen video player.

6. Updating Progressbar

This one is a tiny bit different as it's an ongoing event as long as the video is playing.

Create the function

function handleProgress() {
  const percent = (video.currentTime / video.duration) * 100;
  progressBar.style.flexBasis = `${percent}%`;
}
Enter fullscreen mode Exit fullscreen mode

We calculate the percent of the video, and set the flexBasis(CSS) value to the calculated percent.

Add a listener

video.addEventListener("timeupdate", handleProgress);
Enter fullscreen mode Exit fullscreen mode

Listens for updates on the time of the video(automatically), and runs the function.

And that's it. Now the progressbar's css will update according to the video's time.

7. Set time manually in progressbar.

To achieve this, we'll use the positioning of the mouseclick comparative to the width of the Progress to get a value.

function time(e) {
  const setTime = (e.offsetX / progress.offsetWidth) * video.duration;
  video.currentTime = setTime;
}
Enter fullscreen mode Exit fullscreen mode

Take the position where I clicked, divided by the width of the progressbar and multiply with duration to get a value.

And then the listener

progress.addEventListener("click", scrub);
Enter fullscreen mode Exit fullscreen mode

Now, to take this functionality up a notch, I also added the option to drag the progressbar up/down - like you usually can do on videoplayers.

let mousedown = false;
progress.addEventListener("mousemove", (e) => mousedown && time(e));
progress.addEventListener("mousedown", () => (mousedown = true));
progress.addEventListener("mouseup", () => (mousedown = false));
Enter fullscreen mode Exit fullscreen mode

Check if mousedown is true and then update the time according to the event(where your mouse is)


Results

Result Screenshot

Thoughts

I have to say it was way less complicated than I thought it would've been. The key points that I felt were either new or interesting were:

  • The various types of listeners you can use.
  • Using HTML5's media element.

Definitely a fun exercise and I'm excited to see what's next in the JS30 challenges.

💖 💪 🙅 🚩
smackdh
Mattias Velamsson

Posted on January 4, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related