I am using a button that triggers 4-5 other buttons with animation. its working fine in Chrome but not in FireFox
I have used a fullscreen background video in my current project, with this button, but in firefox, when i inspect elements, it shows there, but the browser is not displaying the element at all.
inspiration taken by - http://codepen.io/phenax/
'use strict';
(function (document, win) {
var animation_time = 600;
var btn_move_limit = 30;
var item_showing = false;
var className = {
show_items: 'menu--list__show',
revolve: 'menu--list__revolve',
button_cross: 'bar__crossy'
};
var $el = {
toggle_btn: document.querySelector('.js-menu--toggle'),
menu_items: document.querySelector('.js-menu--list'),
items: document.querySelectorAll('.js-item')
};
var constrain = function constrain(val, lim) {
return val > lim ? lim : val < -lim ? -lim : val;
};
var setButtonPosition = function setButtonPosition(left, top) {
$el.toggle_btn.style.left = constrain(left, btn_move_limit) + 'px';
$el.toggle_btn.style.top = constrain(top, btn_move_limit) + 'px';
};
var showAllItems = function showAllItems() {
var item_menu = $el.menu_items.classList;
item_menu.add(className.show_items);
setTimeout(function () {
item_menu.add(className.revolve);
$el.toggle_btn.classList.add(className.button_cross);
item_showing = true;
}, animation_time);
};
var hideAllItems = function hideAllItems() {
var item_menu = $el.menu_items.classList;
item_menu.remove(className.revolve);
$el.toggle_btn.classList.remove(className.button_cross);
setTimeout(function () {
item_menu.remove(className.show_items);
item_showing = false;
setButtonPosition(0, 0);
}, animation_time);
};
var findPosRelative = function findPosRelative(e) {
e = e.pageX ? {
pageX: e.pageX,
pageY: e.pageY
} : e.touches[0];
var offset = {
x: win.innerWidth / 2,
y: win.innerHeight / 2
};
e.pageX = e.pageX - offset.x;
e.pageY = e.pageY - offset.y;
return e;
};
var menuBtnClickHandler = function menuBtnClickHandler() {
if (item_showing)
hideAllItems();
else
showAllItems();
};
var itemClick = function itemClick(e) {
var item_id = e.target.dataset.id;
console.log('Item ID: ' + item_id);
hideAllItems();
};
var mouseMoveMent = function mouseMoveMent(e) {
var left, top;
if (item_showing) {
e = findPosRelative(e);
left = 140 * e.pageX / win.innerWidth;
top = 140 * e.pageY / win.innerHeight;
} else {
left = 0;
top = 0;
}
setButtonPosition(left, top);
};
document.addEventListener('DOMContentLoaded', function () {
$el.toggle_btn.addEventListener('click', menuBtnClickHandler);
for (var i = 0; i < $el.items.length; i++) {
if (window.CP.shouldStopExecution(1)) {
break;
}
$el.items[i].addEventListener('click', itemClick);
}
window.CP.exitedLoop(1);
win.addEventListener('mousemove', mouseMoveMent);
win.addEventListener('touchmove', mouseMoveMent);
});
}(document, window));
.menu--toggle {
position: absolute;
width: 80px;
height: 80px;
border-radius: 50%;
transform: translateX(-50%);
border: none;
outline: none;
cursor: pointer;
left: 0;
top: 0;
color: #222;
z-index: 1;
background-image: url("../images/logo/logo.jpg");
background-position: center;
background-size: cover;
box-shadow: 0 0 0 rgba(204, 169, 44, 0.4);
}
.menu {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
margin-top: -80px;
filter: url("#svgFilter"); }
.menu .item {
position: absolute;
width: 80px;
height: 80px;
border-radius: 50%;
transform: translateX(-50%);
border: none;
outline: none;
cursor: pointer;
left: 0;
top: 0;
background-color: #FFEB3B;
color: #222; }
.menu .item {
transition: all 0.6s ease-in-out; }
.menu--toggle {
transition: all .2s linear; }
.menu--toggle .bar {
width: 20px;
height: 2px;
background-color: #222;
margin: 5px auto;
transition: all 0.6s ease-in-out; }
.menu--toggle.bar__crossy .bar:nth-child(2) {
opacity: 0; }
.menu--toggle.bar__crossy .bar:nth-child(1) {
transform: translateY(7px) rotate(45deg); }
.menu--toggle.bar__crossy .bar:nth-child(3) {
transform: translateY(-7px) rotate(-45deg); }
.menu--list ul {
list-style-type: none;
padding: 0;
margin: 0; }
.menu--list li {
position: absolute;
width: 60px;
height: 80px;
transition: all 0.6s ease-in-out;
transform-origin: 0% 50%; }
.menu--list__show .item {
margin-left: 60px; }
.menu--list__revolve li:nth-child(1) {
transform: rotate(90deg); }
.menu--list__revolve li:nth-child(1) .item {
transform: rotate(270deg); }
.menu--list__revolve li:nth-child(2) {
transform: rotate(180deg); }
.menu--list__revolve li:nth-child(2) .item {
transform: rotate(180deg); }
.menu--list__revolve li:nth-child(3) {
transform: rotate(270deg); }
.menu--list__revolve li:nth-child(3) .item {
transform: rotate(90deg); }
.menu--list__revolve li:nth-child(4) {
transform: rotate(360deg); }
.menu--list__revolve li:nth-child(4) .item {
transform: rotate(0deg); }
<div class="menu">
<nav class="menu--list js-menu--list">
<ul>
<li><button type="button" onClick="window.open('https://www.facebook.com/themadhousecafe', '_blank')" class="fa fa-facebook item js-item" data-id="1"></button></li>
<li><button type="button" onClick="window.open('http://blog.nomadbaker.com/', '_blank')" class="fa item js-item" data-id="2">Blog</button></li>
<li><button type="button" onClick="window.open('#', '_blank')" class="item js-item" data-id="3">Menu</button></li>
<li><button type="button" onClick="window.open('#', '_blank')" class="fa fa-phone item js-item" data-id="4"></button></li>
</ul>
</nav>
<button type="button" class='logo_button menu--toggle js-menu--toggle'>
<div class="bar"></div>
<div class="bar"></div>
<div class="bar"></div>
</button>
</div>
Related
I'm trying to get to grips with javascript, and have followed a tutorial for a simple image slider. I'm trying to add to it and have the background fade to different colours as the slides move. I've managed to figure it out with the right and left arrows (not sure on best practise), but I can't seem to get it right when selecting the indicators. Can anyone advise on a solution?
Thanks in advance.
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
var background = 1;
function indicatorBg(val){
var background = val;
changeBg();
}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background <= 1) {
return false;
} else {
background--;
}
changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
if (background >= 4) {
return false;
} else {
background++;
}
changeBg();
});
function changeBg (){
if (background == 1) {
document.getElementById("carousel__track").className = 'slide-1';
} else if (background == 2) {
document.getElementById("carousel__track").className = 'slide-2';
} else if (background == 3) {
document.getElementById("carousel__track").className = 'slide-3';
} else if (background == 4) {
document.getElementById("carousel__track").className = 'slide-4';
}
}
window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" onclick="indicatorBg(this.value)" class="selected"></li>
<li value="2" onclick="indicatorBg(this.value)"></li>
<li value="3" onclick="indicatorBg(this.value)"></li>
<li value="4" onclick="indicatorBg(this.value)"></li>
</ol>
</div>
</div>
</section>
You forgot to change the background inside the click event handler of the indicators.
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
background = index + 1;
changeBg();
});
});
As far as best practice goes, I typically use class names for CSS and IDs for JavaScript. Personally, I wouldn't recommend you worry about best practices at this stage, but instead, focus on getting the code working and understanding what's going on line-by-line.
There is a lot of solutions, but the simplest solution that I advice is to use odd and even numbers to style the divs in the carousel (meaning that eg. first is green second is orange third is green and so on...
.carousel__slider div:nth-child(2n) /*Selects even numbered elements*/
.carousel__slider div:nth-child(2n+1) /*Selects odd numbered elements*/
Check out the snippet
const left = document.querySelector('.left');
const right = document.querySelector('.right');
const slider = document.querySelector('.carousel__slider');
const indicatorParent = document.querySelector('.carousel__controls ol');
const indicators = document.querySelectorAll('.carousel__controls li');
index = 0;
//var background = 1;
//function indicatorBg(val){
// var background = val;
// changeBg();
//}
indicators.forEach((indicator, i) => {
indicator.addEventListener('click', () => {
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicator.classList.add('selected');
slider.style.transform = 'translateX(' + (i) * -25 + '%)';
index = i;
});
});
left.addEventListener('click', function() {
index = (index > 0) ? index -1 : 0;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background <= 1) {
// return false;
// } else {
// background--;
// }
// changeBg();
});
right.addEventListener('click', function() {
index = (index < 4 - 1) ? index+1 : 3;
document.querySelector('.carousel__controls .selected').classList.remove('selected');
indicatorParent.children[index].classList.add('selected');
slider.style.transform = 'translateX(' + (index) * -25 + '%)';
// if (background >= 4) {
// return false;
// } else {
// background++;
// }
// changeBg();
});
//function changeBg (){
// if (background == 1) {
// document.getElementById("carousel__track").className = 'slide-1';
// } else if (background == 2) {
// document.getElementById("carousel__track").className = 'slide-2';
// } else if (background == 3) {
// document.getElementById("carousel__track").className = 'slide-3';
// } else if (background == 4) {
// document.getElementById("carousel__track").className = 'slide-4';
// }
//}
//window.onload = changeBg;
.carousel {
height: 80vh;
width: 100%;
margin: 0 auto;
}
#carousel__track {
height: 100%;
position: relative;
overflow: hidden;
}
.background {
background: red;
}
.carousel__slider {
height: 100%;
display: flex;
width: 400%;
transition: all 0.3s;
}
.carousel__slider div {
flex-basis: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.carousel__controls .carousel__arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
z-index: 8888
}
.carousel__controls .carousel__arrow i {
font-size: 2.6rem;
}
.carousel__arrow.left {
left: 1em;
}
.carousel__arrow.right {
right: 1em;
}
.carousel__controls ol {
position: absolute;
bottom: 15%;
left: 50%;
transform: translateX(-50%);
list-style: none;
display: flex;
margin: 0;
padding: 0;
}
.carousel__controls ol li {
width: 14px;
height: 14px;
border-radius: 50px;
margin: .5em;
padding: 0;
background: white;
transform: scale(.6);
cursor: pointer;
}
.carousel__controls ol li.selected {
background: black;
transform: scale(1);
transition: all .2s;
transition-delay: .3s;
}
/*.slide-1 {
background: pink;
transition: all 0.4s;
}
.slide-2 {
background: coral;
transition: all 0.4s;
}
.slide-3 {
background: green;
transition: all 0.4s;
}
.slide-4 {
background: orange;
transition: all 0.4s;
}*/
.carousel__slider div:nth-child(2n) {
background-color:orange;
}
.carousel__slider div:nth-child(2n+1) {
background-color:green;
}
<section class="carousel">
<div id="carousel__track">
<div class="carousel__slider">
<div>Slide 1</div>
<div>Slide 2</div>
<div>Slide 3</div>
<div>Slide 4</div>
</div>
<div id="left" class="carousel__controls"><span class="carousel__arrow left"><</span> <span id="right" class="carousel__arrow right">></span>
<ol>
<li value="1" class="selected"></li>
<li value="2" ></li>
<li value="3" ></li>
<li value="4" ></li>
</ol>
</div>
</div>
</section>
So the idea of my work is with the 10 slides in my section will have an element append to the slides, which are drinking can products. When the cursor hovers the cans, the cans will increase the size to show the real detail of the can.
Anyway, I have managed to create my carousel active slide, the 3D effect cans that can rotate clockwise and have a list of different colour cans in CSS (different background for each bottle class).
I can only get the first can working on the active slide, but the rest of the slides are blank. I've only create a list of 3 items in the array hoping to fill up the three slides with the drinking can products but no luck? What am I doing wrong?
I'm calling the initApp function, which has the array of cans because I want to append items, but only one at a time...
so in the each.function(index) - I can add the index, and then in initApp(index). and then in the initApp function I can adjust so that bottle[index] gets selected and then added. But nothing seems to work?? What am I doing wrong? I know there is a bunch of ways I can do this.
Like could I skip the initApp() function and add all the code in the .each(function() { my code to append bottle})??
// slider
$("#products>article").on("click", function(){
$("#products>article").removeClass("active");
$(this).addClass("active");
animate();
});
function getActiveArticle(){
var x = 0;
$("#products>article").each(function(e){
if($("#products>article").eq(e).hasClass("active")){
x = e;
return false;
}
});
return x;
}
function gofwd(){
var activeIndex = getActiveArticle();
var minArticles = 0;
var maxArticles = $("#products>article").length - 1;
if(activeIndex >= maxArticles){
activeIndex = minArticles-1;
}
$("#products>article").removeClass("active");
$("#products>article").eq(activeIndex+1).addClass("active");
animate();
}
function gobwd(){
var activeIndex = getActiveArticle();
var minArticles = 1;
var maxArticles = $("#products>article").length;
$("#products>article").removeClass("active");
$("#products>article").eq(activeIndex-1).addClass("active");
animate();
}
$(document).ready(function(){
animate();
});
function animate(){
var articleIndex = getActiveArticle();
var totalMargin = 25 * (articleIndex+1) - (25*(articleIndex));
var articlePosition = Math.floor($("#products>article").eq(articleIndex).offset().left - $("#products").offset().left) - totalMargin;
var productsHalfWidth = $("#products").width()/2;
if(articleIndex == 0){
var halfWidth = 150;
}else{
var halfWidth = 100;
}
var finalPosition = productsHalfWidth - articlePosition - halfWidth;
$("#products").animate({
"left": finalPosition,
}, {
duration: 500,
easing: 'easeOutBack',
});
}
$(window).on("resize", function(){
animate();
});
var autoPlay = setInterval(function(){
gofwd();
}, 3500);
$("#slider").on("mouseenter", function(){
clearInterval(autoPlay);
});
$("#slider").on("mouseleave", function(){
autoPlay = setInterval(function(){
gofwd();
}, 4500);
});
// cans
const getElement = (selector) => document.querySelector(selector);
const createElement = (tag) => document.createElement(tag);
// const addBackground1 = document.style['background'] = 'url ("https://i.postimg.cc/BZ8rj2NM/sleve.png")';
const addSideStyle = ($side, i) => {
let deg = 3.75 * i;
let bgPosition = 972 - (i * 10.125);
$side.style['background-position'] = bgPosition + 'px 0';
$side.style['-webkit-transform'] = 'rotateY(' + deg + 'deg) translateZ(154px)';
$side.style['-moz-transform'] = 'rotateY(' + deg + 'deg) translateZ(154px)';
$side.style['transform'] = 'rotateY(' + deg + 'deg) translateZ(154px)';
};
const createBottle = () => {
const $bottle = createElement('div');
$bottle.classList.add('bottle');
const $bottleLabel = createBottleLabel();
for (let i = 0; i < 96; i = i + 1){
let $bottleSide = createBottleSide(i);
$bottleLabel.append($bottleSide);
}
$bottle.append($bottleLabel);
return $bottle;
};
const createBottleLabel = () => {
const $bottleLabel = createElement('div');
$bottleLabel.classList.add('label');
return $bottleLabel;
}
const createBottleSide = (i) => {
const $bottleSide = createElement('div');
$bottleSide.classList.add('side');
addSideStyle($bottleSide, i);
return $bottleSide;
};
const changeBottleSize = (clickFn) => {
const _bottle = createElement('div');
_bottle.classList.add('bottle');
_bottle.style['transform'] = 'scale(0.9)';
return _bottle;
}
const clickFn = () => {
const $bottleSize = getElement('.container');
// const $bottle1 = changeBottleSize();
// const $bottle2 = changeBottleSize();
// const $bottle3 = changeBottleSize();
$bottleSize.style['transform'] = 'scale(0.9)';
return $bottleSize;
}
$('#products article').each(function(index) {
$(this).append(initApp())
});
const initApp = (index) => {
const $container = getElement('.container');
const $bottle1 = createBottle();
const $bottle2 = createBottle();
const $bottle3 = createBottle();
[$bottle1, $bottle2, $bottle3].forEach(($bottle, i) => {
$bottle.classList.add('bottle' + i);
});
$container.append($bottle1, $bottle2, $bottle3);
};
initApp();
* {
padding: 0;
margin: 0;
font-family: "Arial";
box-sizing: border-box;
}
body {
background-color: #444;
}
#slider {
position: relative;
overflow: hidden;
width: 90vw;
height: 750px;
margin: 50px auto;
background-color: rgba(255, 255, 255, .5);
}
#products {
position: relative;
display: flex;
width: 100%;
height: 100%;
align-items: center;
padding: 0 25px;
}
#products>article:first-child {
margin-left: 0;
}
#products>article {
position: relative;
min-width: 250px;
min-height: 250px;
margin-left: 25px;
font-size: 17px;
cursor: pointer;
/* background-color: rgba(255,0,0,.5); */
transition: all .3s ease-in-out;
}
#products>article.active {
min-width: 300px;
min-height: 300px;
font-size: 20px;
}
#picText {
position: absolute;
color: #fff;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(-45deg);
}
#id {
color: #fff;
margin: 15px;
}
#gofwd,
#gobwd {
position: absolute;
top: 50%;
padding: 50px 15px;
z-index: 1;
cursor: pointer;
background-color: rgba(255, 255, 255, .6);
transform: translateY(-50%);
transition: all .3s ease-out;
}
#gofwd:hover,
#gobwd:hover {
background-color: #fff;
}
#gobwd {
left: 0;
}
#gofwd {
right: 0;
}
.can {
position: relative;
}
.bottle:hover {
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg)
/* translate3d(350px, 190px, 40px) */
scale(0.7);
}
.bottle {
transition: all 0.2s;
width: 10.125px;
-webkit-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg) translate3d(650px, 190px, 40px);
-moz-transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg) translate3d(650px, 190px, 40px);
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg) translate3d(350px, 190px, 40px);
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
transform: scale(0.2);
position: absolute;
}
.bottle0 {
top: 40px;
left: 100px;
}
.bottle1 {
top: 100px;
left: 500px;
}
.bottle2 {
top: 100px;
left: 700px;
}
.bottle>img {
position: absolute;
top: -180px;
left: -182px;
width: 374px;
}
.label {
-webkit-animation: spin 10s infinite linear;
-moz-animation: spin 10s infinite linear;
animation: spin 10s infinite linear;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
}
.side {
position: absolute;
width: 10.55px;
height: 679px;
margin-bottom: 400px;
}
.bottle0 .side {
background: url("https://i.postimg.cc/BZ8rj2NM/sleve.png");
}
.bottle1 .side {
background: url("https://i.postimg.cc/Fs2RgnN6/passion.png");
}
.bottle2 .side {
background: url("https://i.postimg.cc/zGzJjm40/raspberry.png");
}
#-webkit-keyframes spin {
from {
-webkit-transform: rotateY(0deg);
transform: rotateY(0deg);
}
to {
-webkit-transform: rotateY(-360deg);
transform: rotateY(-360deg);
}
}
#-moz-keyframes spin {
from {
-moz-transform: rotateY(0deg);
transform: rotateY(0deg);
}
to {
-moz-transform: rotateY(-360deg);
transform: rotateY(-360deg);
}
}
#keyframes spin {
from {
-webkit-transform: rotateY(0deg);
-moz-transform: rotateY(0deg);
transform: rotateY(0deg);
}
to {
-webkit-transform: rotateY(-360deg);
-moz-transform: rotateY(-360deg);
transform: rotateY(-360deg);
}
}
#mixin makeSide() {}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<div id="slider">
<span id="gofwd" onClick="gofwd();">></span>
<span id="gobwd" onClick="gobwd();"><</span>
<div id="products">
<article class="active">
<div class="container"></div>
</article>
<article>
<div class="container">
<p id="id">2</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">3</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">4</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">5</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">6</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">7</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">8</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">9</p>
</div>
</article>
<article>
<div class="picture">
<p id="id">10</p>
</div>
</article>
</div>
</div>
If you look at your Javascript Console you should the following error:
you crated the initApp function as a const after calling it, that won't work. You have two options:
move the const initApp up, or
declare it a function like this:
function initApp(index){
// …
}
I'm working on a simple card stack which rotates when clicked, my problem is I cant select a specific card and send it to the front and arrange again the cards according to number. I change the codes but luck, I consumed half a day to make it works, still not working.
I hope you understand me.
Thanks
here is a sample code.
codepen
var cardStack = document.getElementsByClassName('card');
var cardArray = []; // Does not change
var stateArray = []; // Changes - keeps track of card state
var prevStateArray = [];
function cardInit() {
for (var i=0; i<cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
cardArray.push(cNum);
stateArray = cardArray;
};
};
function stackRefresh() {
prevStateArray = stateArray.slice(0);
stateArray.unshift(stateArray.pop());
}
function nextCard() {
stackRefresh();
for (var i=0; i<cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
cardInit();
body {
background-color: #2a2a2a;
}
.card {
width: 200px;
height: 320px;
background-color: #fff;
box-shadow: 0px 2px 4px 0px rgba(0,0,0,0.4);
border-radius: 5px;
display: inline-block;
position: absolute;
transform-origin: 0% 50%;
transition: all 1s ease;
}
.card-stack {
display: inline-block;
text-align: center;
position: relative;
left: 50%;
transform: translateX(-100px);
}
.card1 {
z-index: 1000;
left: 0;
}
.card2 {
z-index: 800;
transform: scale(0.99);
filter: brightness(0.9);
left: 20px;
}
.card3 {
z-index: 600;
transform: scale(0.98);
filter: brightness(0.8);
left: 40px;
}
.card4 {
z-index: 400;
transform: scale(0.97);
filter: brightness(0.7);
left: 60px;
animation-name: remove;
animation-duration: 1s;
}
#keyframes remove {
0% {transform: translateX(0px); opacity: 1};
50% {transform: translateX(-80px); opacity: 0};
51% {transform: translateX(10px) scale(0.97); opacity: 0};
100% {transform: translateX(0px) scale(0.97); opacity: 1;}
}
<div class="card-stack" onclick="nextCard();">
<div class="card">A</div>
<div class="card">B</div>
<div class="card">C</div>
<div class="card">D</div>
</div>
Try this sample
I changed html
<div class="card-stack" onclick="nextCard(event);">
...
And js function
function nextCard(e) {
var clickedCssClass = e.srcElement.classList[1];
if (!clickedCssClass) return;
var match = /(\d+)/.exec(clickedCssClass);
var clickedNumber = match[0];
for(var j = 1; j < clickedNumber ; j++){
stackRefresh();
for (var i=0; i<cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
}
First include the following statement in head section of the html:
<script src="http://code.jquery.com/jquery-3.2.1.js"></script>
Add then change the following tag
<div class="card-stack" onclick="nextCard();">
To
<div class="card-stack">
Finally, I modified the function cardInit as follow:
function cardInit() {
for (var i=0; i<cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
$(cardStack[i]).on("click",function()
{
prevClassName=this.classList[1];
$(".card1").removeClass("card1").addClass(prevClassName);
this.className=this.className.replace(prevClassName,"card1");
});
cardArray.push(cNum);
stateArray = cardArray;
};
};
did you mean this?
I have added a moveTop function like
function moveTop() {
event.preventDefault();
event.stopPropagation();
var index = Array.prototype.slice.call(event.target.parentNode.querySelectorAll('.card')).indexOf(event.target)
var temp = stateArray[index];
prevStateArray = stateArray.slice(0);
stateArray.splice(index, 1);
stateArray.unshift(temp);
refreshCards();
}
var cardStack = document.getElementsByClassName('card');
var cardArray = []; // Does not change
var stateArray = []; // Changes - keeps track of card state
var prevStateArray = [];
function cardInit() {
for (var i = 0; i < cardStack.length; i++) {
var cNum = i + 1;
var cName = 'card' + cNum.toString();
cardStack[i].classList.add(cName);
cardArray.push(cNum);
stateArray = cardArray;
};
};
function stackRefresh() {
prevStateArray = stateArray.slice(0);
stateArray.unshift(stateArray.pop());
}
function nextCard() {
stackRefresh();
refreshCards();
}
function refreshCards() {
for (var i = 0; i < cardStack.length; i++) {
var cName = 'card' + prevStateArray[i].toString();
var cNameNew = 'card' + stateArray[i].toString();
cardStack[i].classList.remove(cName);
cardStack[i].classList.add(cNameNew);
};
}
function moveTop() {
event.preventDefault();
event.stopPropagation();
var index = Array.prototype.slice.call(event.target.parentNode.querySelectorAll('.card')).indexOf(event.target)
var temp = stateArray[index];
prevStateArray = stateArray.slice(0);
stateArray.splice(index, 1);
stateArray.unshift(temp);
refreshCards();
}
cardInit();
body {
background-color: #2a2a2a;
}
.card {
width: 200px;
height: 320px;
background-color: #fff;
box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.4);
border-radius: 5px;
display: inline-block;
position: absolute;
transform-origin: 0% 50%;
transition: all 1s ease;
text-align: right;
}
.card-stack {
display: inline-block;
text-align: center;
position: relative;
left: 50%;
transform: translateX(-100px);
}
.card1 {
z-index: 1000;
left: 0;
}
.card2 {
z-index: 800;
transform: scale(0.99);
filter: brightness(0.9);
left: 20px;
}
.card3 {
z-index: 600;
transform: scale(0.98);
filter: brightness(0.8);
left: 40px;
}
.card4 {
z-index: 400;
transform: scale(0.97);
filter: brightness(0.7);
left: 60px;
animation-name: remove;
animation-duration: 1s;
}
#keyframes remove {
0% {
transform: translateX(0px);
opacity: 1
}
;
50% {
transform: translateX(-80px);
opacity: 0
}
;
51% {
transform: translateX(10px) scale(0.97);
opacity: 0
}
;
100% {
transform: translateX(0px) scale(0.97);
opacity: 1;
}
}
<div class="card-stack" onclick="nextCard();">
<div class="card" onclick="moveTop()">A</div>
<div class="card" onclick="moveTop()">B</div>
<div class="card" onclick="moveTop()">C</div>
<div class="card" onclick="moveTop()">D</div>
</div>
The problem you are having is that you don't know which card was clicked. My guess is to pass the event when calling nextCard():
onclick="nextCard(event)"
And within the function:
function nextCard(event) {
// detect which card was picked
console.log(event.target);
// logic to bring picked card to the top
...
}
I've done a research on this question and found some solutions. However, not every one of them worked. As I understand, async false makes a UI block, which shouldn't be. I could use an overlay until ajax request is completed and on the request success, hide the overlay.
That was my try using a callback argument in the getNewQuote() function (only a small snippet of it):
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback();
return quote;
}, 4000);
};
getNewQuote(function() {
console.log("DONE");
var getRandomColor = function() {
var colors = [
"#ff9966",
"#7f00ff",
"#396afc",
"#0cebeb",
"#06beb6",
"#642b73",
"#36d1dc",
"#cb356b",
"#3a1c71",
"#ef3b36",
"#159957",
"#000046",
"#007991",
"#56ccf2",
"#f2994a",
"#e44d26",
"#4ac29a",
"#f7971e",
"#34e89e",
"#6190e8",
"#3494e6",
"#ee0979"
],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t, qt) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + qt.text + '" ';
twitter += qt.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += qt.author;
tumblr += "&content=";
tumblr += qt.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>")
.prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, qt.text);
$t.find(".quote-author").html("- " + qt.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append(
"<style id='modStyle'>#new-quote:before {background:" + newColor + ";}</style>"
);
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";}");
}
};
var getQuote = function() {
var nq, nc, nh = 0;
nq = getNewQuote();
nc = getRandomColor();
nh = calcNewHeight(nq);
$(".quote-container").children().css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh,
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: "2.5em"
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: "2.5em .75em"
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), nq);
$(".quote-container").children().fadeTo(750, 1);
};
$("#new-quote").on("click", getQuote);
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75em");
getQuote();
});
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.v-wrap {
height: 100%;
text-align: center;
}
.v-wrap:before {
content: "";
display: inline-block;
vertical-align: middle;
width: 0;
height: 100%;
}
.quote-container {
width: 31.25rem;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
padding: 0 2.5rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: .1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: .8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
height: 50%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: .0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all .3s ease-in-out 0s;
transition: all .3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-wrap">
<div class="quote-container" style="">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
Code output:
As you can see, ajax wasn't success
Uncaught TypeError: callback is not a function and Uncaught TypeError: Cannot read property 'text' of undefined (only in the stack snippet).
I found out this error disappears if I remove the getQuote(); function call. However, I need to call it, overwise, my project won't work. I also tried to use return $.ajax but there was a return quote line so I couldn't use it. The full code can be found here on codepen: https://codepen.io/Kestis500/pen/ZvyxKB?editors=0110.
Then I switched to another method using jQuery promises and used information in this thread: https://stackoverflow.com/a/40658281/8889739. Full code: https://codepen.io/Kestis500/pen/qpjxoq?editors=0110.
var MyFirstFunction = function() {
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
return quote;
}, 4000);
};
}
var MySecondFunction = function() {
console.log("DONE");
var getRandomColor = function() {
var colors = [
"#ff9966",
"#7f00ff",
"#396afc",
"#0cebeb",
"#06beb6",
"#642b73",
"#36d1dc",
"#cb356b",
"#3a1c71",
"#ef3b36",
"#159957",
"#000046",
"#007991",
"#56ccf2",
"#f2994a",
"#e44d26",
"#4ac29a",
"#f7971e",
"#34e89e",
"#6190e8",
"#3494e6",
"#ee0979"
],
randomNumber = Math.floor(Math.random() * colors.length);
return colors[randomNumber];
};
var updateText = function($t, qt) {
var twitter = "https://twitter.com/intent/tweet?hashtags=quotes&related=freecodecamp&text=";
twitter += '"' + qt.text + '" ';
twitter += qt.author;
var tumblr = "https://www.tumblr.com/widgets/share/tool?posttype=quote&tags=quotes,freecodecamp&caption=";
tumblr += qt.author;
tumblr += "&content=";
tumblr += qt.text;
tumblr += "&canonicalUrl=https%3A%2F%2Fwww.tumblr.com%2Fbuttons&shareSource=tumblr_share_button";
var $icon = $("<i class='fa fa-quote-left'>")
.prop("aria-hidden", true);
$t.find(".quote-text").html("").append($icon, qt.text);
$t.find(".quote-author").html("- " + qt.author);
$("#tweet-quote").attr("href", twitter);
$("#tumblr-quote").attr("href", tumblr);
};
var calcNewHeight = function(q) {
var $temp = $("<div>", {
class: "quote-container temp",
}).appendTo($("body"));
$temp.append($("<div>", {
class: "quote-text"
}), $("<div>", {
class: "quote-author"
}));
updateText($temp, q);
var h = $temp.height() + 40;
$temp.remove();
return h;
};
var changeColor = function(newColor) {
$("body, .button:not(#new-quote)").animate({
backgroundColor: newColor
});
$("#new-quote").animate({
color: newColor
});
$(".quote-text, .quote-author").css("color", newColor);
if ($("#modStyle").length === 0) {
$("head").append(
"<style id='modStyle'>#new-quote:before {background:" + newColor + ";}</style>"
);
} else {
$("head style#modStyle").html("#new-quote:before {background:" + newColor + ";}");
}
};
var getQuote = function() {
var nq, nc, nh = 0;
nq = getNewQuote();
nc = getRandomColor();
nh = calcNewHeight(nq);
$(".quote-container").children().css("opacity", 0);
changeColor(nc);
$(".quote-container, #new-quote").animate({
height: nh,
}, {
duration: 1000,
queue: false
});
$(".quote-container").animate({
padding: "2.5em"
}, {
duration: 1000,
queue: false
});
$("#new-quote").animate({
padding: "2.5em .75em"
}, {
duration: 1000,
queue: false
});
updateText($(".quote-container"), nq);
$(".quote-container").children().fadeTo(750, 1);
};
$("#new-quote").on("click", getQuote);
$(".quote-container, #new-quote").css({
visibility: "visible",
height: 0
});
$("#new-quote").css("padding", "0 .75em");
getQuote();
}
MyFirstFunction().done(MySecondFunction);
html,
body {
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
background: #333;
color: #333;
font-family: sans-serif;
}
.v-wrap {
height: 100%;
text-align: center;
}
.v-wrap:before {
content: "";
display: inline-block;
vertical-align: middle;
width: 0;
height: 100%;
}
.quote-container {
width: 31.25rem;
background: #fff;
margin: 0;
display: inline-block;
vertical-align: middle;
border-radius: 0.1875rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
visibility: hidden;
padding: 0 2.5rem;
}
.quote-text {
font-size: 1.625rem;
}
.quote-text i {
margin-right: 0.6rem;
}
.quote-text p {
display: inline;
}
.quote-author {
font-size: 1rem;
margin: 0 0.4rem 2rem 0;
text-align: right;
}
.button {
padding: 0.75rem;
text-align: center;
font-size: 1rem;
color: #fff;
border-radius: .1875rem;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
user-select: none;
}
.button:not(#new-quote):hover {
opacity: .8 !important;
}
.button:not(#new-quote) {
min-width: 1rem;
min-height: 1rem;
}
.button i {
vertical-align: middle;
}
#new-quote {
white-space: nowrap;
writing-mode: vertical-lr;
height: 50%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
vertical-align: middle;
background: #fff !important;
margin: 0;
position: relative;
right: 0.25625rem;
color: #333;
visibility: hidden;
}
#new-quote:before {
content: "";
position: absolute;
height: 100%;
width: 0.0625rem;
bottom: 0;
left: 0;
visibility: hidden;
-webkit-transform: scaleY(0);
transform: scaleY(0);
-webkit-transition: all .3s ease-in-out;
transition: all .3s ease-in-out;
}
#new-quote:hover:before {
visibility: visible;
-webkit-transform: scaleY(1);
transform: scaleY(1);
}
footer {
font-size: 0.85rem;
margin-bottom: 1rem;
}
footer a {
text-decoration: none;
color: #fff;
position: relative;
}
footer a:before {
content: "";
position: absolute;
width: 100%;
height: .0625rem;
bottom: 0;
left: 0;
background: #fff;
visibility: hidden;
-webkit-transform: scaleX(0);
transform: scaleX(0);
-webkit-transition: all .3s ease-in-out 0s;
transition: all .3s ease-in-out 0s;
}
footer a:hover:before {
visibility: visible;
-webkit-transform: scaleX(1);
transform: scaleX(1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="v-wrap">
<div class="quote-container" style="">
<div class="quote-text">
</div>
<div class="quote-author"></div>
<a id="tweet-quote" class="button"><i class="fa fa-twitter"></i></a>
<a id="tumblr-quote" class="button"><i class="fa fa-tumblr"></i></a>
</div>
<div id="new-quote" class="button">New quote</div>
<footer>
Created by LukasLSC
</footer>
</div>
Code output:
It broke everything, the gray screen is because of the default codepen background
Uncaught TypeError: Cannot read property 'done' of undefined
You're using return from the asynchronous operation's callback. That just sets the return value of that callback (which is ignored in the case of setTimeout's or XHR's callback), it doesn't set the return value of your function.
You can't return the value from your function, which is why you're adding a callback. Instead:
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback(quote); // <====
}, 4000);
};
...and use the parameter of the callback, e.g.:
getNewQuote(function(quote) {
// Use quote here...
});
Live Example:
var getNewQuote = function(callback) {
var quote = {};
setTimeout(function() {
quote.text = 'Example';
quote.author = 'Example';
callback(quote); // <====
}, 1000);
};
getNewQuote(function(quote) {
console.log("quote:", quote);
});
I have made a slider/seeker out of mousedown and mousemove for my <audio> element. My problem is that as soon as the user leaves the element while still holding their mouse button down, it does not register the mousemove. Here's my code:
/** Variables **/
isPlaying = false;
isBuffering = false;
isScrubbing = false;
isScrubberHolding = false;
tempProgress = 0;
time = playerE.currentTime;
dur = playerE.duration;
/** Binds and Properties **/
player.bind("timeupdate", timeUpdate);
scrubber.bind("mousemove", scrubberGrab);
scrubber.bind("mousedown", scrubberClick);
/** Progress and Buffer **/
function progressWidth(progress) {
var calcProgress = ((progress * 100) + "%");
$(".progress").width(calcProgress);
}
/** Time events **/
function timeUpdate(e) {
/** Update Variables **/
time = playerE.currentTime;
dur = playerE.duration;
/** Update Progress and Buffer **/
if (isScrubbing === false) {
var progress = time / dur;
}
var buffered = playerE.buffered.end(0) / dur;
timeConvert(time);
progressWidth(progress);
}
function setPlayerTime(timeset) {
playerE.currentTime = timeset * dur;
}
function timeConvert(s) {
var h = Math.floor(s / 3600);
s -= h * 3600;
var m = Math.floor(s / 60);
s -= m * 60;
var resultSubstring = ((m < 10 ? '0' + m : m) + ":" + (s < 10 ? '0' + s : s)).substring(0, 5);
$('#playerTime').text(resultSubstring);
}
/** Scrubber **/
$(".player-small").mouseenter(function () {
knob.stop().fadeIn(200);
});
setTimeout(function () {
$(".player-small").mouseleave(function () {
knob.stop().fadeOut(200);
});
}, 3000);
function scrubberClick(e) {
isScrubberHolding = true;
isScrubbing = true;
player.trigger('pause');
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
progressWidth(percent);
tempProgress = percent;
}
$(document).mouseup(function () {
if (isScrubberHolding === true) {
isScrubberHolding = false;
isScrubbing = false;
setPlayerTime(tempProgress)
player.trigger('play');
} else {
isScrubberHolding = false;
}
})
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent)
} else {}
}
See it in action:
var player = $('audio');
var playerE = $('audio')[0];
var playerE = $('audio').get(0);
var canvasviz = $('canvas');
var playbutton = $("#playButton");
var buffering = $("#buffering");
var scrubber = $(".scrubber-con");
var progress = $(".progress");
var buffered = $(".buffered");
var knob = $(".knob");
var analyser = $("#analyzer");
var currentAlbum = "";
var countElement = $('#playlistCount');
var titleElement = $('#trackTitle');
/** Variables **/
isPlaying = false;
isBuffering = false;
isScrubbing = false;
isScrubberHolding = false;
tempProgress = 0;
time = playerE.currentTime;
dur = playerE.duration;
/** Binds and Properties **/
player.bind("timeupdate", timeUpdate);
scrubber.bind("mousemove", scrubberGrab);
scrubber.bind("mousedown", scrubberClick);
/** Progress and Buffer **/
function progressWidth(progress) {
var calcProgress = ((progress * 100) + "%");
$(".progress").width(calcProgress);
}
/** Time events **/
function timeUpdate(e) {
/** Update Variables **/
time = playerE.currentTime;
dur = playerE.duration;
/** Update Progress and Buffer **/
if (isScrubbing === false) {
var progress = time / dur;
}
var buffered = playerE.buffered.end(0) / dur;
timeConvert(time);
progressWidth(progress);
}
function setPlayerTime(timeset) {
playerE.currentTime = timeset * dur;
}
function timeConvert(s) {
var h = Math.floor(s / 3600);
s -= h * 3600;
var m = Math.floor(s / 60);
s -= m * 60;
var resultSubstring = ((m < 10 ? '0' + m : m) + ":" + (s < 10 ? '0' + s : s)).substring(0, 5);
$('#playerTime').text(resultSubstring);
}
/** Scrubber **/
$(".player-small").mouseenter(function () {
knob.stop().fadeIn(200);
});
setTimeout(function () {
$(".player-small").mouseleave(function () {
knob.stop().fadeOut(200);
});
}, 3000);
function scrubberClick(e) {
isScrubberHolding = true;
isScrubbing = true;
player.trigger('pause');
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
progressWidth(percent);
tempProgress = percent;
}
$(document).mouseup(function () {
if (isScrubberHolding === true) {
isScrubberHolding = false;
isScrubbing = false;
setPlayerTime(tempProgress)
player.trigger('play');
} else {
isScrubberHolding = false;
}
})
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var $this = $(this);
var x = e.pageX - $this.offset().left;
var percent = x / $this.width();
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent)
} else {}
}
.player-small {
height: 55px;
width: 100%;
background: #ff4081;
}
.player-height-anim {}
.player-small .left {
height: 55px;
float: left;
width: 56%;
overflow: hidden;
}
.player-small .right {
height: 40px;
position: relative;
top: 8px;
float: right;
width: calc(44% - 2px);
overflow: hidden;
border-left: solid 2px rgba(0, 0, 0, .05);
}
.transport {
overflow: auto;
}
.play-button-con {
height: 55px;
width: 55px;
float: left;
overflow: hidden;
}
#buffering {
height: 55px;
width: 55px;
animation: rotating 900ms ease infinite;
background-image: url(img/player-buffering.svg);
background-size: contain;
display: none;
}
#-webkit-keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
#keyframes rotating {
from {
-ms-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-webkit-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-ms-transform: rotate(360deg);
-moz-transform: rotate(360deg);
-webkit-transform: rotate(360deg);
-o-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotating {
-webkit-animation: rotating 2s linear infinite;
-moz-animation: rotating 2s linear infinite;
-ms-animation: rotating 2s linear infinite;
-o-animation: rotating 2s linear infinite;
animation: rotating 2s linear infinite;
}
#playButton {
width: 55px;
height: 55px;
font-size: 18px;
text-align: center;
background-image: url(img/player-play.svg);
background-size: contain;
image-rendering: crisp-edges;
-webkit-image-rendering: crisp-edges;
}
.playFailed {
pointer-events: none;
}
.next-button-con {
height: 55px;
width: 55px;
float: left;
}
#nextButton {
width: 55px;
height: 55px;
text-align: center;
font-size: 11px;
background-image: url(img/player-next.svg);
background-size: contain;
}
.scrubber-con {
margin: auto;
margin-top: 12px;
height: 30px;
width: calc(100% - 40px);
overflow: visible;
cursor: pointer;
}
.scrubber-container {
float: left;
height: 55px;
width: calc(100% - 154px);
overflow: hidden;
}
.scrubber {
margin: auto;
height: 5px;
background: rgba(0, 0, 0, .04);
position: relative;
top: 13px;
}
.scrubber .knob {
float: right;
height: 13px;
width: 13px;
position: relative;
bottom: 4px;
left: 5px;
background: white;
border-radius: 50px;
display: none;
}
.scrubber .knob:hover {
cursor: grab;
}
.scrubber .knob:active {
cursor: grabbing;
}
.scrubber .progress {
height: 100%;
float: left;
background: white;
width: 0%;
position: relative;
z-index: 1;
}
.scrubber .buffered {
height: 5px;
position: relative;
width: 0%;
background: rgba(0, 0, 0, .2);
transition: ease 1000ms;
}
.time-con {
float: left;
width: 30px;
height: 55px;
}
.time {
position: relative;
top: 20px;
color: white;
font-size: 13px;
}
.player-small .button {
color: white;
float: left;
cursor: pointer;
}
.player-small .button:hover {
background: rgba(0, 0, 0, .12);
}
.analyzer-con {
float: left;
position: relative;
margin-left: 235px;
width: calc(100% - 650px);
height: 60px;
}
#analyzer {
width: 100%;
height: 45px;
margin-top: 8px;
display: none;
}
audio {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="player-small">
<div class="w-ctrl">
<div class="controls">
<div class="left">
<div class="transport">
<div class="play-button-con">
<div class="button playFailed" id="playButton" onclick="togglePlay()">
</div>
<div id="buffering">
</div>
</div>
<div class="next-button-con">
<div class="button" id="nextButton" onclick="next()"></div>
</div>
<div class="scrubber-container" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="scrubber-con" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="scrubber" draggable="false" nmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="progress" draggable="false" onmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false">
<div class="knob" draggable="false" onmousedown="event.preventDefault ? event.preventDefault() : event.returnValue = false"></div>
</div>
<div class="buffered"></div>
</div>
</div>
</div>
<div class="time-con">
<div class="time" id="playerTime">0:00</div>
</div>
</div>
</div>
<div class="right">
<audio id="player" src="your track here" controls="controls" preload="none"></audio>
<div class="info">
<div class="count" id="playlistCount">0/0</div>
<div class="title" id="trackTitle">Track title</div>
</div>
</div>
</div>
</div>
</div>
Grab my custom seeker (left) and move your mouse off the pink area. Now do the same for the audio element (right) you need a track for it to play in order to be able to move its seeker. See how you can drag it even if your mouse is not inside it?
So how can I get this behaviour for my custom seeker?
Since you are binding the mousemove to scrubber, scrubberGrab() will only run when the mouse is over the scrubber element.
Change
scrubber.bind("mousemove", scrubberGrab);
To
$(document).bind("mousemove", scrubberGrab);
function scrubberGrab(e) {
if (isScrubberHolding === true) {
var x = e.pageX - scrubber.offset().left;
var percent = Math.min(Math.max(x / scrubber.width(), 0), 1.0);
tempProgress = percent;
progressWidth(percent);
setPlayerTime(percent);
} else {}
}