video-player-03

by Nic Fontaine

HTML

<div class='container-vid'>
  <video id="myvideo" muted>
    <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
    <source src="https://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg">
  </video>

  <!-- <div class='vid-play'>
    <i class="fa fa-play-circle"></i>
  </div> -->
  
  <div class='timeline-hover'>
    <div class='timeline'>
      <div class='timeline-sel'></div>
      <div id='timeline-bar' class='timeline-bar'></div>
      <div id='timeline-bar-fake' class='timeline-bar-fake'></div>
    </div>
  </div>

</div>

<div id='demo'>fps: </div>

<ul>
  <li>click vid for play/pause</li>
  <li>click timeline while pause - stays paused, indicator shows, vid stays</li>
  <li>release while paused - indicator hide, vid moves, stays paused</li>
  <li>click+drag while paused - indicator &amp; glowbar, vid stays</li>
  <li>release - vid moves, idicator &amp; glowbar hide</li>
  <li>click to play again - at correct time</li>
  <li>onend - timestop goes to 100%</li>
  <li>onend - click timeline, release, &amp; vid stays</li>
</ul>

<!-- <script async src="https://use.fontawesome.com/dfe288b4db.js"></script> -->

CSS

:focus {outline:none;}
::-moz-focus-inner {border:0;}
body { font-family: sans-serif; }

.container-vid {
  position: relative;
  width: 800px;
  /*overflow: hidden;*/
}

video {
  width: 100%;
  display: flex; /* FIXES > 100% + EXTRA HEIGHT ISSUE */
}

.timeline {
  position: absolute;
  overflow: hidden;
  opacity: 0;
  width: 100%;
  margin: 0;
  height: 20px;
  right: 0;
  bottom: 0;
  background: rgba(0,0,0,0.3);
  transition: background 0.1s, height 0.05s ease-in-out;
}

.timeline.show {
  opacity: 1;
}

.container-vid:hover .timeline {
  background: rgba(0,0,0,0.5);
}

.timeline-hover {
  position: absolute;
  bottom: 0;
  right: 0; left: 0;
  height: 40px;
}

.timeline-hover:hover {
  height: 60px;
}

#timeline-bar {
  background: rgba(63,183,166,0.8);
  
/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#3fb2a0+0,09a4a9+100,2a2b30+100 */
background: #3fb2a0; /* Old browsers */
background: -moz-linear-gradient(left, #3fb2a0 0%, #09a4a9 100%, #2a2b30 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(left, #3fb2a0 0%,#09a4a9 100%,#2a2b30 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to right, #3fb2a0 0%,#09a4a9 100%,#2a2b30 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3fb2a0', endColorstr='#2a2b30',GradientType=1 ); /* IE6-9 */

  /* box-shadow: inset 2px 2px 7px rgba(255, 255, 255, .3), inset -2px -2px 7px rgba(0, 0, 0, .07); */

  border-top: 2px solid rgba(255,255,255,0.2);
  border-bottom: 1px solid rgba(0,0,0,0.1);
  border-right: 2px solid rgba(255,255,255,0.7);
  box-sizing: border-box;
  height: 100%;
  width: 100%;
  opacity: 0.7;
  transition: opacity 0.1s;
  transform: translateX(-100%);
  position: relative;
  z-index: 1;
  box-shadow: 0 0 5px rgba(0,0,0,0.6);
}

#timeline-bar:after {
    position: absolute;
    content:"";
    top: -2px;
    right: 0;
    margin-right: -6px;
    width:0;
   ...

JavaScript

/*
BUGS
------

- if target fps is too high, timeline won't move fast enough. need speed as inverse var?
if rAF fps is lowered by browser, [rate] should be increased

- rAF stops when switching tabs but vid does not

- 'onend event is slow, noticeably

*/
var vidConts = document.getElementsByClassName('container-vid');
var vidContsLen = vidConts.length;
// PLAY/PAUSE STATUS CONTAINER FOR EACH VID
var vidsStatus = [];
var vidsWidth = [];
var vidPlayingIndex;

var vid = document.getElementById('myvideo'),
  tLine = document.getElementsByClassName('timeline')[0],
  demo = document.getElementById('demo');
  
var vidPlaying = false; // FLAG INSTEAD OF CHECK VID STATUS
var timeWidth = 0; // CALC WIDTH, RAF USES
var timeWidthPrep; // CALC WIDTH WHEN CLICK BUT DON'T UPDATE B/C RAF USES timeWidth
const fps = 30;
var rate; // FRAMES TO MOVE EVERY 1/60 OF A SECOND
var dragging; // TOGGLE TO INDICATE IF DRAGGING TIME ON TIMELINE

var now;
var then = Date.now();
const interval = 1000/fps;
var delta;
var counter = 1;
var first = then;

// GRAB VALUES WHEN VID LOADS/CANPLAY
// THIS RUNS ONCE, vid.oncanplay WOULD RUN EVERY TIME IT'S TIME IS UPDATED
//(NOTE) NEED TO DO FOR EVERY VID
var i = setInterval(function() {
	if(vid.readyState > 0) {
  
		var minutes = parseInt(vid.duration / 60, 10);
		var seconds = vid.duration % 60;
		duration = seconds;
    // HIDE UNTIL READY
  	// (NOTE) REPLACE W/ CLASS LOOP
  	setTimeout(function() {
 			tLine.classList.add('show'); 
      
  	},500);
		clearInterval(i);
	}
}, 200);

// LOOP THROUGH ALL .container-vid - ADD EVENTS
for (var i=0; i<vidContsLen; i++) {
	vidsStatus.push(null);
  vidsWidth.push(vidConts[i].getElementsByClassName('timeline')[0].clientWidth);
  
	(function(index) {
  	// CTRL - PLAY/PAUSE EVERY VID
  	vidConts[i].getElementsByTagName('video')[0].addEventListener('click', function() {
    	vidToggle(index);
    },false);
    
    vidConts[i].getElementsByTagName('video')[0].addEventListener('ended', function() {
   ...