Happylab Logo
Published on

Day11: Custom Video Player

Authors
js30

Project Introduction: Custom video player with features including play, pause, volume, speed, fast forward, rewind, and fullscreen.

Project Page: https://iris1114.github.io/javascript30/11_Custom-Video-Player/

Code

/* Get Our Elements */
const player = document.querySelector('.player')
const video = player.querySelector('.viewer')
const progress = player.querySelector('.progress')
const progressBar = player.querySelector('.progress__filled')
const toggle = player.querySelector('.toggle')
const skipButtons = player.querySelectorAll('[data-skip]')
const ranges = player.querySelectorAll('.player__slider')
const fullscreenBtn = player.querySelector('.screen__button')
const iconBtn = player.querySelector('.icon__button')

/* Build out functions */

// Play or pause video
function togglePlay() {
  const method = video.paused ? 'play' : 'pause'
  video[method]()
}

// Update icon UI based on video play/pause state
function updateButton() {
  const icon = this.paused
    ? ` <i class="fas fa-play"></i>`
    : `<i class="fas fa-pause"></i>`
  toggle.innerHTML = icon

  const iconVideo = this.paused ? ` <i class="fas fa-play"></i>` : ``
  iconBtn.innerHTML = iconVideo
}

// Fast forward and rewind - update video currentTime by data-skip value
function skip() {
  video.currentTime += parseFloat(this.dataset.skip)
}

// Update video volume and playbackRate values
function handleRangeUpdate() {
  video[this.name] = this.value
}

// Update progress bar UI and color
function handleProgress() {
  const percent = (video.currentTime / video.duration) * 100
  progressBar.style.flexBasis = `${percent}%`
  progressBar.style.background = '#ff0000'
}

// Change video playback position
function scrub(e) {
  const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration
  video.currentTime = scrubTime
}

// Request fullscreen
function fullscreen() {
  video.requestFullscreen()
}

/* Hook up the event listeners */

// Handle video play/pause
video.addEventListener('click', togglePlay) // Click video to execute togglePlay
toggle.addEventListener('click', togglePlay) // Click bottom toggle to execute togglePlay
video.addEventListener('play', updateButton) // Listen for video play to update button UI
video.addEventListener('pause', updateButton) // Listen for video pause to update button UI

// When video currentTime updates, trigger timeupdate event to update progress bar UI
video.addEventListener('timeupdate', handleProgress)

// Handle fast forward/rewind
skipButtons.forEach((button) => button.addEventListener('click', skip))

// Handle volume and speed sliders
ranges.forEach((range) => range.addEventListener('change', handleRangeUpdate))
ranges.forEach((range) =>
  range.addEventListener('mousemove', handleRangeUpdate)
)

// Handle progress bar - mousedown is true when mouse pressed, false when released
let mousedown = false
progress.addEventListener('click', scrub) // Click progress bar to execute scrub
progress.addEventListener('mousemove', (e) => mousedown && scrub(e)) // If mousedown is true, execute scrub
progress.addEventListener('mousedown', () => (mousedown = true))
progress.addEventListener('mouseup', () => (mousedown = false))

// Handle fullscreen
fullscreenBtn.addEventListener('click', fullscreen)

Additional Notes

video.play()

Starts playback.

video.pause()

Pauses playback.

video.currentTime

Returns the current playback time in seconds. Setting this property changes the current playback position.

video.volume

Sets the volume for media playback. Values range from 0.0 (muted) to 1.0 (maximum volume).

video.playbackRate

Sets the rate at which the media is played. Used to implement user controls for fast/slow playback. Normal playback rate multiplied by this value gives the current playback rate, so 1.0 represents normal speed. Negative values cannot be used for reverse playback.

video.duration

Gives the length of the media in seconds, or zero if no media data is available.

video timeupdate event

Triggered when currentTime updates.

The event firing frequency is determined by the system but is guaranteed to fire between 4-66 times per second (assuming each event handler doesn't exceed 250ms).

mousedown & mouseup & mousemove

  • mousedown: Triggered when any mouse button is pressed, equivalent to touchstart on mobile.
  • mouseup: Triggered when any mouse button is released, equivalent to touchend on mobile.
  • mousemove: Triggered when the mouse moves, usually only bound when needed to avoid constant triggering.

References

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement https://medium.com/@shizukuichi/mouse-event-notes-feb5dd866b0