I am implementing a design of custom video controls, having some errors in adapting it, there is a mess in the design.
How can I adapt the responsive design and structure them correctly so that they are in a perfect order similar to the following image:
And in the Speed design add a blue circle that indicates at what speed the video speed has been selected.
Note 1: Additional images needed to animate the audio currently 3 types of audio are being animated in
silencio
thevolumen 1
and it would be necessaryvolumen 3
to add volume 2 http://svgshare.com/i/3uH.svg .Note 2: Additional image to remove the full screen http://svgshare.com/i/3ue.svg , only the image is included
full screen
.
Full code:
$(document).ready(function(){
//INITIALIZE
var video = $('#myVideo');
//remove default control when JS loaded
video[0].removeAttribute("controls");
$('.control').show().css({'bottom':-45});
$('.loading').fadeIn(500);
$('.caption').fadeIn(500);
//before everything get started
video.on('loadedmetadata', function() {
$('.caption').animate({'top':-45},300);
//set video properties
$('.current').text(timeFormat(0));
$('.duration').text(timeFormat(video[0].duration));
updateVolume(0, 0.7);
//start to get video buffering data
setTimeout(startBuffer, 150);
//bind video events
$('.videoContainer')
.append('<div id="init"></div>')
.hover(function() {
$('.control').stop().animate({'bottom':0}, 500);
$('.caption').stop().animate({'top':0}, 500);
}, function() {
if(!volumeDrag && !timeDrag){
$('.control').stop().animate({'bottom':-45}, 500);
$('.caption').stop().animate({'top':-45}, 500);
}
})
.on('click', function() {
$('#init').remove();
$('.btnPlay').addClass('paused');
$(this).unbind('click');
video[0].play();
});
$('#init').fadeIn(200);
});
//display video buffering bar
var startBuffer = function() {
var currentBuffer = video[0].buffered.end(0);
var maxduration = video[0].duration;
var perc = 100 * currentBuffer / maxduration;
$('.bufferBar').css('width',perc+'%');
if(currentBuffer < maxduration) {
setTimeout(startBuffer, 500);
}
};
//display current video play time
video.on('timeupdate', function() {
var currentPos = video[0].currentTime;
var maxduration = video[0].duration;
var perc = 100 * currentPos / maxduration;
$('.timeBar').css('width',perc+'%');
$('.current').text(timeFormat(currentPos));
});
//CONTROLS EVENTS
//video screen and play button clicked
video.on('click', function() { playpause(); } );
$('.btnPlay').on('click', function() { playpause(); } );
var playpause = function() {
if(video[0].paused || video[0].ended) {
$('.btnPlay').addClass('paused');
video[0].play();
}
else {
$('.btnPlay').removeClass('paused');
video[0].pause();
}
};
//speed text clicked
$('.btnx1').on('click', function() { fastfowrd(this, 1); });
$('.btnx3').on('click', function() { fastfowrd(this, 3); });
var fastfowrd = function(obj, spd) {
$('.text').removeClass('selected');
$(obj).addClass('selected');
video[0].playbackRate = spd;
video[0].play();
};
//stop button clicked
$('.btnStop').on('click', function() {
$('.btnPlay').removeClass('paused');
updatebar($('.progress').offset().left);
video[0].pause();
});
//fullscreen button clicked
$('.btnFS').on('click', function() {
if($.isFunction(video[0].webkitEnterFullscreen)) {
video[0].webkitEnterFullscreen();
}
else if ($.isFunction(video[0].mozRequestFullScreen)) {
video[0].mozRequestFullScreen();
}
else {
alert('Your browsers doesn\'t support fullscreen');
}
});
//sound button clicked
$('.sound').click(function() {
video[0].muted = !video[0].muted;
$(this).toggleClass('muted');
if(video[0].muted) {
$('.volumeBar').css('width',0);
}
else{
$('.volumeBar').css('width', video[0].volume*100+'%');
}
});
//VIDEO EVENTS
//video canplay event
video.on('canplay', function() {
$('.loading').fadeOut(100);
});
//video canplaythrough event
//solve Chrome cache issue
var completeloaded = false;
video.on('canplaythrough', function() {
completeloaded = true;
});
//video ended event
video.on('ended', function() {
$('.btnPlay').removeClass('paused');
video[0].pause();
});
//video seeking event
video.on('seeking', function() {
//if video fully loaded, ignore loading screen
if(!completeloaded) {
$('.loading').fadeIn(200);
}
});
//video seeked event
video.on('seeked', function() { });
//video waiting for more data event
video.on('waiting', function() {
$('.loading').fadeIn(200);
});
//VIDEO PROGRESS BAR
//when video timebar clicked
var timeDrag = false; /* check for drag event */
$('.progress').on('mousedown', function(e) {
timeDrag = true;
updatebar(e.pageX);
});
$(document).on('mouseup', function(e) {
if(timeDrag) {
timeDrag = false;
updatebar(e.pageX);
}
});
$(document).on('mousemove', function(e) {
if(timeDrag) {
updatebar(e.pageX);
}
});
var updatebar = function(x) {
var progress = $('.progress');
//calculate drag position
//and update video currenttime
//as well as progress bar
var maxduration = video[0].duration;
var position = x - progress.offset().left;
var percentage = 100 * position / progress.width();
if(percentage > 100) {
percentage = 100;
}
if(percentage < 0) {
percentage = 0;
}
$('.timeBar').css('width',percentage+'%');
video[0].currentTime = maxduration * percentage / 100;
};
//VOLUME BAR
//volume bar event
var volumeDrag = false;
$('.volume').on('mousedown', function(e) {
volumeDrag = true;
video[0].muted = false;
$('.sound').removeClass('muted');
updateVolume(e.pageX);
});
$(document).on('mouseup', function(e) {
if(volumeDrag) {
volumeDrag = false;
updateVolume(e.pageX);
}
});
$(document).on('mousemove', function(e) {
if(volumeDrag) {
updateVolume(e.pageX);
}
});
var updateVolume = function(x, vol) {
var volume = $('.volume');
var percentage;
//if only volume have specificed
//then direct update volume
if(vol) {
percentage = vol * 100;
}
else {
var position = x - volume.offset().left;
percentage = 100 * position / volume.width();
}
if(percentage > 100) {
percentage = 100;
}
if(percentage < 0) {
percentage = 0;
}
//update volume bar and video volume
$('.volumeBar').css('width',percentage+'%');
video[0].volume = percentage / 100;
//change sound icon based on volume
if(video[0].volume == 0){
$('.sound').removeClass('sound2').addClass('muted');
}
else if(video[0].volume > 0.5){
$('.sound').removeClass('muted').addClass('sound2');
}
else{
$('.sound').removeClass('muted').removeClass('sound2');
}
};
//Time format converter - 00:00
var timeFormat = function(seconds){
var m = Math.floor(seconds/60)<10 ? "0"+Math.floor(seconds/60) : Math.floor(seconds/60);
var s = Math.floor(seconds-(m*60))<10 ? "0"+Math.floor(seconds-(m*60)) : Math.floor(seconds-(m*60));
return m+":"+s;
};
});
/* video container */
.videoContainer{
width:600px;
height:350px;
position:relative;
overflow:hidden;
background:#000;
color:#ccc;
}
/* video caption css */
.caption{
display:none;
position:absolute;
top:0;
left:0;
width:100%;
padding:10px;
color:#ccc;
font-size:20px;
font-weight:bold;
box-sizing: border-box;
-ms-box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
background: #1F1F1F; /* fallback */
background:-moz-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
background:-webkit-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
background:-o-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
}
/*** VIDEO CONTROLS CSS ***/
/* control holder */
.control{
background: rgba(0,0,0,.7);
position:absolute;
bottom:0;
left:0;
width:100%;
height: 45px;
/*height: 13%;*/
z-index:5;
display:none;
}
/* control top part */
.topControl {
float: left;
width: 50%;
}
/* control bottom part */
.btmControl{
clear:both;
background: #1F1F1F; /* fallback */
background:-moz-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
background:-webkit-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
background:-o-linear-gradient(top,#242424 50%,#1F1F1F 50%,#171717 100%);
}
.control .btn {
float:left;
width:34px;
height:30px;
padding:0 10px;
cursor:pointer;
}
.control div.btnPlay::after {
content: "";
background-image: url(http://svgshare.com/i/3um.svg);
width: 50px;
height: 50px;
display: inline-block;
background-size: cover;
position: relative;
top: -7px;
}
/*
.control div.paused{
}
*/
.control div.paused::after {
content: "";
background-image: url(http://svgshare.com/i/3vz.svg);
width: 65px;
height: 65px;
display: inline-block;
background-size: cover;
position: relative;
top: -15px;
left: -10px;
}
.control div.spdText {
width: 1em;
height: 1.5em;
line-height: 1.5em;
position: relative;
font-size: 1em;
border-radius: 5%;
color: #29303b;
background-color: hsla(0,0%,100%,.9);
}
.speed {
margin:0;
padding:0;
display: none;
position: absolute;
max-height: 0;
transition: max-height 1s;
}
.speed-title {
text-align: left;
text-transform: none;
padding: 5px 20px 5px 15px;
color: #fff;
font-weight: 700;
font-size: 1.25em;
margin: 0;
line-height: 1.2;
}
.speed li {
padding: 5px 20px 5px 15px;
}
.speed .btnx3:hover, .btnx1:hover {
background-color: #505763;
color: #fff;
box-shadow: none;
}
.spdText:hover .speed {
text-align: center;
display: block;
list-style: none;
max-height: 300px;
transition: max-height 1s;
left:-25px;
background-color: black;
opacity: 0.5;
color: white;
top: -102px;
}
.control div.selected{
font-size:15px;
color:#ccc;
}
.control div.sound::after {
content: "";
background-image: url(http://svgshare.com/i/3ww.svg);
width: 45px;
height: 45px;
display: inline-block;
background-size: cover;
position: relative;
top: -5px;
/*left: -10px;*/
}
.control div.sound2::after {
content: "";
background-image: url(http://svgshare.com/i/3xS.svg);
width: 45px;
height: 45px;
display: inline-block;
background-size: cover;
position: relative;
top: -5px;
/*left: -10px;*/
}
.control div.muted::after {
content: "";
background-image: url(http://svgshare.com/i/3v_.svg);
width: 45px;
height: 45px;
display: inline-block;
background-size: cover;
position: relative;
top: -5px;
}
.control div.btnFS{
float: right;
}
.control div.btnFS::after {
content: "";
background-image: url(http://svgshare.com/i/3wo.svg);
width: 40px;
height: 40px;
display: inline-block;
background-size: cover;
position: relative;
top: 0px;
}
/* PROGRESS BAR CSS */
/* Progress bar */
.progress {
width:85%;
height:10px;
position:relative;
float:left;
cursor:pointer;
}
.progress span {
height:40%;
position:absolute;
top:0;
left:0;
display:block;
}
.timeBar{
z-index:10;
width:0;
background: #2EB3D0;
}
.bufferBar{
z-index:5;
width:0;
background: #ddd;
}
/* time and duration */
.time{
float:right;
text-align:center;
font-size:11px;
line-height:12px;
}
/* VOLUME BAR CSS */
/* volume bar */
.volume{
position:relative;
cursor:pointer;
width:70px;
height:10px;
float:right;
margin-top:10px;
margin-right:10px;
}
.volumeBar{
display:block;
height:40%;
position:absolute;
top:0;
left:0;
background-color:#eee;
z-index:10;
}
/* OTHERS CSS */
/* video screen cover */
.loading, #init{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
background:url(loading.gif) no-repeat 50% 50%;
z-index:2;
display:none;
}
#init{
background:url(bigplay.png) no-repeat 50% 50% !important;
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<!-- Content -->
<section id="wrapper">
<div class="videoContainer">
<video id="myVideo" controls preload="auto" poster="https://i.ytimg.com/vi/x676X3ak3wo/maxresdefault.jpg" width="600" height="350" >
<source src="http://techslides.com/demos/sample-videos/small.mp4" type="video/mp4" />
<source src="http://demo.inwebson.com/html5-video/iceage4.webm" type="video/webM" />
<source src="http://demo.inwebson.com/html5-video/iceage4.ogv" type="video/ogg" />
<p>Your browser does not support the video tag.</p>
</video>
<div class="caption">This is HTML5 video with custom controls</div>
<div class="control">
<div class="btmControl">
<div class="btnPlay btn" title="Play/Pause video"></div>
<!--<div class="btnStop btn" title="Stop video"></div>-->
<div class="spdText btn">x1
<ul class="speed">
<li class="speed-title">Speed</li>
<li class="btnx3">x3</li>
<li class="btnx1 selected">x1</li>
</ul>
</div>
<!--<div class="btnx1 btn text selected" title="Normal speed">x1</div>
<div class="btnx3 btn text" title="Fast forward x3">x3</div>-->
<div class="topControl">
<div class="progress">
<span class="bufferBar"></span>
<span class="timeBar"></span>
</div>
<div class="time">
<span class="current"></span> /
<span class="duration"></span>
</div>
</div>
<div class="btnFS btn" title="Switch to full screen"></div>
<!--<div class="btnLight lighton btn" title="Turn on/off light"></div>-->
<div class="volume" title="Set volume">
<span class="volumeBar"></span>
</div>
<div class="sound sound2 btn" title="Mute/Unmute sound"></div>
</div>
</div>
<div class="loading"></div>
</div>
</section>
If I understood correctly from the question and the comments, what you really want to do is these three things:
We are going to see the three things separately and in the end we put them together in the code.
speed indicator
The blue circle can be easily added with CSS, but there is another problem with the JavaScript code that causes the option to not be disabled. So you have to correct those two things.
The JS code you have right now is this:
Esta parte es incorrecta:
$('.text').removeClass('selected');
. El selector.text
no devuelve nada así que no desactivará nada (al menos no se le quitará la clase selected a nada). Parece que esto es código antiguo porque hay comentado algo que sí tenía la clasetext
. La solución es simple, cambia el selector para que se quite el.selected
a la clase.selected
de esa lista.Y ahora que sabes que la clase selected se va a aplicar/quitar correctamente, puedes estilizar el punto haciendo algo como esto:
Pantalla completa
Cambiar el icono para pantalla completa es algo que vamos a hacer con CSS también, pero antes vamos a ver tu código JS:
...este código tiene problemas que harán que falle de todos modos:
div
que contiene el vídeo.webkitEnterFullscreen
no es una función válida, querríaswebkitRequestFullscreen
(como en moz)Arreglando esas tres cosas (y limpiando un poco, porque es complejo), se vería así:
Y para controlar que el icono cambia, se puede usar los selectores especiales de pantalla completa (por separado porque si se ponen juntas y los navegadores detectan un error en una, ignorarán todas):
Lamentablemente, el modo de ejecución de scripts de StackOverflow impide que se pueda poner el vídeo a pantalla completa, pero he probado y funciona.
Volumen de nivel 2
Ahora, para el volumen tienes un sistema que dependiendo del valor quitará/añadirá clases para que se muestre un icono u otro:
The only thing you would have to do is add one more control. Now instead of breaking into three levels (0, 0-50 or 50-100), you will have to break into 4 levels (0, 0-33, 33-66, 66-100... you can change these values as you like to adjust the icons to whatever you want).
With that change, it would look like this (joining all
removeClass
into one only per line):And all you have to do is add the new CSS (which will be the same as the one in .sound2, only changing the image):
And finally the complete code:
Good, arrange
css
it so that everything looks much better and orderly, greetings, I hope it helps you and is what you are looking forhere the codepen in case you want to edit or see it better
codepen