CodePen Home OO HTML5 Video Player w/Data-Attribute Targeting

 


HMTL...

<div class="wrapper">

    <div class="section">

        <h1>(Another) HMTL5 Video Pen</h1>

        <h2>This time with data-attribute targeting of UI components</h2>

    </div>

    <div class="js-video">

        <video class="js-media" poster="http://media.w3.org/2010/05/sintel/poster.png">

            <source id="mp4" src="http://media.w3.org/2010/05/sintel/trailer.mp4" type="video/mp4">

            <source id="webm" src="http://media.w3.org/2010/05/sintel/trailer.webm" type="video/webm">

            <source id="ogv" src="http://media.w3.org/2010/05/sintel/trailer.ogv" type="video/ogg">

            <p>Your user agent does not support the HTML5 Video element.</p>

        </video>

        <div class="ui">

            <div class="ui-left">

                <i data-playPause class="fa fa-play ui-icon"></i>

                <i data-mute class="fa fa-volume-up ui-icon"></i>

            </div>

            <div class="ui-right">

                <div data-progress class="progress">

                    <div data-buffer class="progress-buffer"></div>

                    <div data-time class="progress-time"></div>

                </div>

            </div>

        </div>

    </div>

    <div class="section">

      Just throw the data attributes on the UI elements you want to create and functionality is good to go. Create the styles for the elements yourself and customize your video player experience.

    </div>

</div>


----------------------------------------

CSS..

@mixin border-radius($radius: 4px) {

  -webkit-border-radius: $radius;

  -moz-border-radius: $radius;

  border-radius: $radius;

};


@mixin appearance($appearance: none) {

  -webkit-appearance: $appearance;

  -moz-appearance: $appearance;

  appearance: $appearance;

}


/*********************

 * Background

 *********************/

html { 

  background: url(//eventsonhand.com/wp-content/uploads/2013/07/blurred-background-10-2000x1250.jpg) no-repeat center center fixed; 

  -webkit-background-size: cover;

  -moz-background-size: cover;

  -o-background-size: cover;

  background-size: cover;

}


body {

    font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; 

   font-weight: 300;

  line-height: 1.4;

}


/*********************

 * Wrapper

 *********************/

.wrapper {

  max-width: 600px;

  margin: 0 auto;

}


/*********************

 * Elements inside js-video

 *********************/

video {

  max-width: 100%;

}


.js-video button {

  -webkit-appearance: none;

  -moz-appearance: none;

  appearance: none;

  @include appearance();

}


/*********************

 * UI

 *********************/

.ui {

  background-color: rgba(0,0,0,0.2);

  padding: 10px;

  @include border-radius();

  font-size: 0;

}


.ui > * {

  font-size: 14px;

  display: inline-block;

  vertical-align: middle;

}


.ui-left {

  width: 15%;

}


.ui-right {

  width: 80%;

}


.ui-icon {

  font-size: 20px;

  vertical-align: middle;

  width: 20px;

  margin-right: 10px;

  cursor: pointer;

}


/*********************

 * Progress

 *********************/

.progress {

  background-color: rgba(0,0,0,0.1);

  width: 100%;

  position: relative;

  height: 5px;

  cursor: pointer;

  overflow: hidden;

  @include border-radius();

}


.progress > * {

  position: absolute;

  top: 0;

  left: 0;

  height: 100%;

}


.progress-time {

  background-color: rgba(0,0,0,1);

}


.anim {

  -webkit-transition: width 1000ms linear;

  -moz-transition: width 1000ms linear;

  -ms-transition: width 1000ms linear;

  -o-transition: width 1000ms linear;

  transition: width 1000ms linear;

}


.progress-buffer {

  background-color: rgba(0,0,0, 0.3);

  -webkit-transition: width 250ms linear;

  -moz-transition: width 250ms linear;

  -ms-transition: width 250ms linear;

  -o-transition: width 250ms linear;

  transition: width 250ms linear;

}


.section {

  text-align: center;

  color: #FFFFFF;

  padding: 20px 0;

}


h1 {

  font-family: 'Slabo 13px', serif;

  font-size: 40px;

  margin-bottom: 10px;

}


h2 {

  font-size: 20px

}


-------------------------

JS..


(function(){

  'use strict';

  

  /**

   * Constructor

   */

  var Video = function($element) {

    

    /**

     * Make the reference to the passed

     * in element globally accessible within

     * the Video constructor

     */

    this.$element = $element;

    

    /**

     * Kick off the application

     */

    this.init();

  };

  

  /* Alias prototype */ 

  var proto = Video.prototype;

  

  /**

   * Top level function

   */

  proto.init = function() {

    

    return this.setupHandlers()

               .createChildren()

               .enable();

  };

  

  /**

   * Used to bind 'this' for functions

   */

  proto.setupHandlers = function() {

    this.onPlayPauseHandler = this.playPause.bind(this);

    this.onMuteHandler = this.mute.bind(this);

    this.onTimeUpdateHandler = this.progress.bind(this);

    this.onSeekHandler = this.seek.bind(this);

   

    return this;

  };

  

  /**

   * Create jQuery selectors here

   */

  proto.createChildren = function() {

    this.$video = this.$element.find('.js-media');

    this.$media = this.$video[0];

    this.$playBtn = this.$element.find('[data-playPause]');

    this.$muteBtn = this.$element.find('[data-mute]');

    this.$timeBar = this.$element.find('[data-time]');

    this.$bufferBar = this.$element.find('[data-buffer]');

    this.$progress = this.$element.find('[data-progress]');

    

    return this;

  };

  

  /**

   * Event listeners and functions that need

   * to run on initialization 

   */

  proto.enable = function() {

    this.$playBtn.on('click', this.onPlayPauseHandler);

    this.$muteBtn.on('click', this.onMuteHandler);

    this.$video.on('timeupdate', this.onTimeUpdateHandler);

    this.$progress.on('mousedown', this.onSeekHandler)

                  .on('mouseup', this.onSeekHandler);

    

    return this;

  };

  

  /**

   * Get New Location

   *

   * Uses offsets within the tracking bar

   * to find the position in seconds that the

   * corresponds to in seconds of the video.

   *

   * Returns an object that has the new position 

   * of the seek bar and the actual time time 

   * seconds

   */

  proto.getNewLocation = function(e) {

    var seekBarOffset = this.$progress.offset().left;

    var mouseOffset = e.pageX;

    var mousePosInBar = mouseOffset - seekBarOffset;

    var seekBarWidth = this.$progress.width();

    var duration = this.$media.duration;

    var dist = Math.floor((mousePosInBar / seekBarWidth) * 100);

    var actualSeconds = (dist / 100) * duration;

    var newLocation = (actualSeconds/duration) * 100;

    

    var info = {

      newTime: newLocation,

      actualTime: actualSeconds

    };;

    

    return info;

  };

  

  /**

   * Seek

   *

   * Called on mousedown and mouseup in the progress bar

   * to set the position of the progress bar and time in the

   * video.

   */

  proto.seek = function(e) {

    var info = this.getNewLocation(e);

    this.$media.currentTime = info.actualTime; // Set the time

    this.updateTime(info.newTime);

  };

  

  /**

   * Play

   *

   * Plays or pauses the video

   */

  proto.playPause = function() {

    if (this.$media.paused) {

      this.$media.play();

    } else {

      this.$media.pause();

    }

    

    this.playIconSwap();

  };

  

  proto.playIconSwap = function() {

    if (!this.$media.paused) {

      this.$playBtn.removeClass('fa-play')

                   .addClass('fa-pause');

    } else {

      this.$playBtn.removeClass('fa-pause')

                   .addClass('fa-play');

    }

  };

  

  /**

   * Mute 

   *

   * Mutes the video

   */

  proto.mute = function() {

    if (this.$media.muted) {

      this.$media.muted = false;

    } else {

      this.$media.muted = true;

    }

    

    this.muteIconSwap();

  };

  

  proto.muteIconSwap = function() {

    if (this.$media.muted) {

      this.$muteBtn.removeClass('fa-volume-up')

                   .addClass('fa-volume-down');

    } else {

      this.$muteBtn.removeClass('fa-volume-down')

                   .addClass('fa-volume-up');

    }

  };


  /**

   * Progress

   *

   * 

   */

  proto.progress = function() {

    var currentTime = Math.floor(this.$media.currentTime);

    var duration = this.$media.duration;

    var locationPercent = (currentTime/duration) * 100;

    var buffered = this.$media.buffered.end(0);

    var bufferPercent = Math.floor((buffered/duration) * 100);

    

    this.updateTime(locationPercent);

    this.updateBuffer(bufferPercent);


  };

  

  /**

   * Update Buffer

   *

   * Updates the width of the buffer bar.

   */

  proto.updateBuffer = function(percent) {

    this.$bufferBar.css('width', percent + '%');

  };

  

  /**

   * Update Time

   *

   * Updates the width of the seek bar.

   */

  proto.updateTime = function(percent) {

    this.$timeBar.css('width', percent + '%');

  };

 

  

  // Initialize the Video instance

  return new Video($('.js-video'));

})();









Post a Comment

أحدث أقدم