JavaScript remove and add the same class simultaneously? - javascript

I'm trying to make so that when a button is clicked, an element's class gets removed and re-added back in. The class provides animations.
Below is the javascript and jsfiddle
https://jsfiddle.net/vxtjjgs7/4/
var container = document.querySelector(".container");
var img = document.querySelector("img");
var button = document.querySelector("button");
var src = ["https://upload.wikimedia.org/wikipedia/commons/5/5b/India_Gate_600x400.jpg", "http://www.elementsofstyleblog.com/wp-content/uploads/2010/02/600x400-princeville-sunset.jpg"];
var active = document.querySelector("active");
button.addEventListener("click", function() {
var randomize = Math.floor(Math.random() * src.length);
img.src = src[randomize];
container.innerHTML = "<img src='" + src[randomize] + "'>";
container.classList.remove("active");
container.classList.add("active");
});
.container {
height: 264px;
opacity: 1;
transform: rotate(20deg) scale(.5);
transition: all 1s;
width: 400px;
}
.container img {
border: 1px solid black;
border-radius: 10px;
height: 100%;
width: 100%;
}
.active {
opacity: 1;
transform: rotate(0deg) scale(1);
transition: all 1s;
}
<div class="container">
<img src="">
</div>
<button>next</button>
You see that when the button is clicked the first time, the image flies in. I want to do that every time the button is clicked. How can I do this?

You can listen for the transitionend event before adding the class back:
if (container.classList.contains("active")) {
container.classList.remove("active");
container.addEventListener("transitionend", handleEnd, false);
} else {
container.classList.add("active");
}
function handleEnd() {
container.removeEventListener("animationend", handleEnd, false);
container.classList.add("active");
}
That lets the transition from removing the class complete before you add the class back. You'll want to be sure to test on your target browsers, some may still need prefixed versions of the event. (Alternately, since you know the transition is set to take one second, just use a one-second setTimeout; but using the event lets you change the duration in the CSS without worrying about changing it in a second location.)
Live Example:
var container = document.querySelector(".container");
var img = document.querySelector("img");
var button = document.querySelector("button");
var src = ["https://upload.wikimedia.org/wikipedia/commons/5/5b/India_Gate_600x400.jpg", "http://www.elementsofstyleblog.com/wp-content/uploads/2010/02/600x400-princeville-sunset.jpg"];
var active = document.querySelector("active");
button.addEventListener("click", function(){
var randomize = Math.floor(Math.random() * src.length);
img.src = src[randomize];
container.innerHTML = "<img src='" + src[randomize] + "'>";
if (container.classList.contains("active")) {
container.classList.remove("active");
container.addEventListener("transitionend", handleEnd, false);
} else {
container.classList.add("active");
}
function handleEnd() {
container.removeEventListener("animationend", handleEnd, false);
container.classList.add("active");
}
});
.container {
height: 264px;
opacity: 1;
transform: rotate(20deg) scale(.5);
transition: all 1s;
width: 400px;
}
.container img {
border: 1px solid black;
border-radius: 10px;
height: 100%;
width: 100%;
}
.active {
opacity: 1;
transform: rotate(0deg) scale(1);
transition: all 1s;
}
<div class="container">
<img src="">
</div>
<button>next</button>

You can do this by checking if the element you are clicking on has the class.
button.addEventListener("click", function() {
var randomize = Math.floor(Math.random() * src.length);
img.src = src[randomize];
container.innerHTML = "<img src='" + src[randomize] + "'>";
if (container.classList.contains("active")) {
container.classList.remove("active");
} else {
container.classList.add("active");
}
});

Related

How to make the element stop falling?

Below this text is my code - I am trying to create the chrome dino game, and so far everything is going well, but I have one problem - after the red block jumps, the dino doesn't stop falling down - while it should. I don't understand where my problem is, as I wrote about the same code yesterday and everything worked just fine. The gravity function can be found in the JavaScript under // Gravity.
Notice how it's code is very similar to the jump function, but it doesn't work as good as the jump function. Any help would be appreciated!!!!!
// HTML Elements + Other Variables
const floor1 = document.getElementById("floor1");
const floor2 = document.getElementById("floor2");
const floor3 = document.getElementById("floor3");
const floor4 = document.getElementById("floor4");
const floor5 = document.getElementById("floor5");
const floor6 = document.getElementById("floor6");
const floor7 = document.getElementById("floor7");
const dino = document.getElementById("dino");
const highBird = document.getElementById("highBird");
const lowBird = document.getElementById("lowBird");
const wideCactus = document.getElementById("wideCactus");
const thinCactus = document.getElementById("thinCactus");
let jump = 0;
// Floor Function
setTimeout(function () {
floor1.classList.add("floor1Animation");
}, 0);
setTimeout(function () {
floor2.classList.add("floor2Animation");
}, 1000);
setTimeout(function () {
floor3.classList.add("floor3Animation");
}, 2000);
setTimeout(function () {
floor4.classList.add("floor4Animation");
}, 3000);
setTimeout(function () {
floor5.classList.add("floor5Animation");
}, 4000);
setTimeout(function () {
floor6.classList.add("floor6Animation");
}, 5000);
setTimeout(function () {
floor7.classList.add("floor7Animation");
}, 6000);
// Jump
document.onkeydown = function (event) {
let key = event.key;
if (key == "ArrowUp") {
let jumpCount = 0;
if (dino.offsetTop == 95) {
let jumpInterval = setInterval(function () {
dino.style.top = (dino.offsetTop - 5) + "px";
jumpCount += 1;
jump = true;
if (jumpCount == 20) {
clearInterval(jumpInterval);
jump = false;
jumpCount = 0;
}
}, 10);
}
}
}
// Gravity
setInterval(function () {
if (jump == false) {
let jumpGravity = setInterval(function () {
dino.style.top = (dino.offsetTop + 5) + "px";
}, 10);
if (dino.offsetTop == 95) {
clearInterval(jumpGravity);
}
}
}, 10);
body {
margin: 0;
padding: 0;
justify-content: center;
align-items: center;
display: flex;
width: 100vw;
height: 100vh;
}
#gameBoard {
width: 1000px;
height: 150px;
border: 2px solid black;
overflow: hidden;
margin: auto;
position: relative;
background-color: white;
}
#dino {
width: 30px;
height: 50px;
background-color: red;
left: 10px;
top: 95px;
position: absolute;
}
.floorBackground {
position: relative;
height: 10px;
width: 200px;
display: flex;
justify-content: center;
align-items: center;
}
.floor {
position: absolute;
top: 140px;
height: 10px;
width: 200px;
}
#floor1 {
right: -200px;
background-color: red;
}
.floor1Animation {
animation: floorAnimation 6s infinite linear;
}
#floor2 {
right: -200px;
background-color: blue;
}
.floor2Animation {
animation: floorAnimation 6s infinite linear;
}
#floor3 {
right: -200px;
background-color: green;
}
.floor3Animation {
animation: floorAnimation 6s infinite linear;
}
#floor4 {
right: -200px;
background-color: purple;
}
.floor4Animation {
animation: floorAnimation 6s infinite linear;
}
#floor5 {
right: -200px;
background-color: brown;
}
.floor5Animation {
animation: floorAnimation 6s infinite linear;
}
#floor6 {
right: -200px;
background-color: orange;
}
.floor6Animation {
animation: floorAnimation 6s infinite linear;
}
#floor7 {
right: -200px;
background-color: yellow;
}
.floor7Animation {
animation: floorAnimation 6s infinite linear;
}
#keyframes floorAnimation {
from {
right: -200px;
}
to {
right: 1000px;
}
}
#keyframes jumping {
}
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>
Dino Game
</title>
<link rel = "stylesheet" type = "text/css" href = "DinoCSS.css">
</head>
<body>
<div id = "gameBoard">
<div id = "floor1" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor2" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor3" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor4" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor5" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor6" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "floor7" class = "floor">
<img src = "Pictures/dinoBackground.PNG" class = "floorBackground">
</div>
<div id = "dino"></div>
<div id = "highBird"></div>
<div id = "lowBird"></div>
<div id = "wideCactus"></div>
<div id = "thinCactus"></div>
</div>
<script type = "text/javascript" src = "DinoJS.js"></script>
</body>
</html>
You should try simplifying your code, it may make the issue easier to find or it may even remove it entirely.
I'd suggest using a velocity system, where every frame you adjust the dino's offsetTop by the dino's current velocity, and then subtract the gravity amount from the dino's current velocity.
This causes the velocity to decrease at a constant rate, but the dino's offsetTop position to decrease at an exponential pace, mimicking real gravity.
Then, to make collision work, just test if the dino is at or above the correct "offsetTop" value before subtracting the gravity. If you find that the dino is below the ground, just set the offsetTop to the ground level and clear the velocity.
I'd also suggest moving your game over to the HTML5 Canvas API, since then you just have to deal with properties of objects rather than DOM element style attributes.
Velocity example with canvas:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var x = 10;
var y = 10;
var VelocityX = 0;
var VelocityY = 0;
const gravity = 0.75;
// width and height of the square
var width = 10;
var height = 10;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
x += VelocityX;
if( x > 500) {
x = 0;
}
if ( y >= 450 ) {
y = 450
VelocityY = 0
} else {
y += VelocityY;
VelocityY += gravity; // Higher values = lower position on canvas
}
ctx.fillRect(x, y, width, height);
}
setInterval(animate, 1000 / 60); // 60 FPS
#canvas {
border: 1px solid black;
}
<canvas id="canvas" width="500" height="500"></canvas>
JSFiddle

How to retrigger function (translate animation )

My animation function only runs once. I've tried removing and adding classes, as well as running a animationend function to create a retrigger. But still no luck. Any vanilla JS ideas?
CSS:
#element {
width: 10px;
height: 10px;
animation: "";
#keyframes movedown {
100% {
transform: translateY(10px);
}
}
JS:
btn_button.onclick = () => {
element.style.animation = "movedown 10s";
};
HTML:
<div id="element"></div>
You can use setTimeout to set element.style.animation to "". Then, you can add animation name again upon button click.
let btn = document.querySelector("#btn");
btn.onclick = () => {
element.style.animation = "movedown 2s";
setTimeout(() => element.style.animation = "", 2000)
};
#element {
width: 10px;
height: 10px;
background-color: red;
}
#keyframes movedown {
100% {
transform: translateY(50px);
}
}
<div id="element"></div>
<button id="btn">Trigger</button>

Animating from display none using JS Promises

I am trying animating an element which has display property set to null. Objective is to recreate something that bootstrap does in modal.
Further Explanation:
An element which is set to display none on page load but when a user clicks a certain button it shows up with animation (fade in for example). Then when user click on close button or that button again it fades out and its display property is set to none again.
Problem:
When box display property is set to none. And i click on the button. It's display is set to block and adding class "Show" both occur simultaneously and instantaneously so element just shows rather than animating
Here is my Code:
HTML:
<button id="btn">Show / Hide</button>
<div id="box" class="show">
</div>
CSS:
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
transition: ease all 0.3s;
}
#box.show {
transition: ease all 0.3s;
opacity: 1;
}
Javascript:
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
box.style.display = "none"
btn.addEventListener("click", function () {
if(box.style.display == "none") {
return new Promise(function(resolve, reject) {
box.style.display = "block";
resolve();
}).then(function() {
box.classList.add('show');
});
} else if(box.style.display == "block") {
return new Promise(function(resolve, reject) {
box.addEventListener('transitionend', function () {
box.style.display = "none";
})
resolve();
}).then(function() {
box.classList.remove('show');
});
}
});
JSFiddle: https://jsfiddle.net/ptLggbmb/1/
Instead of using Promises you could simply use the transitionend listener and for the fadeIn animation force a layout/reflow before applying the class to the box.
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
btn.addEventListener("click", function() {
var prevDisplay = box.style.display;
var listener = function() {
box.style.display = "none";
removeListener(listener);
};
if (prevDisplay !== "none") {
addListener(listener);
box.classList.remove('show');
} else {
removeListener(listener);
box.style.display = null;
box.offsetLeft;
box.classList.add('show');
}
function addListener(fn) {
box.addEventListener('transitionend', fn);
}
function removeListener(fn) {
box.removeEventListener('transitionend', fn);
}
});
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
transition: ease all 0.3s;
}
#box.show {
transition: ease all 0.3s;
opacity: 1;
}
<button id="btn">Show / Hide</button>
<div id="box" class="show">
</div>
I think you overcomplicated this to the extreme, IMHO. Try this (Pure CSS with a simple JS toggle of classes):
https://jsfiddle.net/ptLggbmb/17/
HTML:
<button id="btn">Show / Hide</button>
<div id="box" class="show">
CSS:
#box {
background-color: aquamarine;
height: 100px;
width: 100px;
opacity: 0;
display: none;
transition: ease all 1s;
}
#box.show {
display: block;
opacity: 1;
}
JS:
var box = document.querySelector("#box");
var btn = document.querySelector("#btn");
btn.addEventListener("click", function () {
box.classList.toggle('show');
});

Prevent body from scrolling when a Pop-Up is open

first of all I know this same questions has been asked several times but I cannot get it working properly. On the website Im implementing I open a popUp with some info and then prevent the rest of the body from scrolling. I want to allow to scroll the popup but not the menu. Also avoid using "position: fixed" on the body since it moves the page to the top. What am I missing to prevent the body from scrolling? The body already has the propierty "overflow: hidden". Here is the code I developed:
http://www.produccionsf2f.com/equipo/
HTML:
The overlay to cover the body:
<div id="scid-overlay" class="x-section scid-transition-eio overlay-open" style="margin: 0px;padding: 0px; background-color: hsla(0, 0%, 1%, 0.69);"><div class="x-container max width" style="margin: 0px auto;padding: 0px;height: 0;">
The actual popup:
<div id="scid-overlay" class="x-section scid-transition-eio overlay-open" style="margin: 0px;padding: 0px; background-color: hsla(0, 0%, 1%, 0.69);">
JS:
jQuery(function($){
var overlay = $('#scid-overlay');
var visiblePanel;
$(".scid-hook-link").click(function(event){
openPanel(event);
});
$('.scid-close-button').click(function(event) {
closePanel(event);
});
overlay.click(function(event) {
closePanel(event);
});
function openPanel(event){
event.preventDefault();
var id = $(event.target).attr('id').replace('hook', 'popup');
$(event.target).closest('figure').addClass(' scid-popup');
document.querySelector('#' + id).className += (' scid-panel-open');
overlay.removeClass('overlay-close');
overlay.addClass('overlay-open');
sizePanel(id);
window.location.hash = "#" + id;
visiblePanel = document.querySelector('.scid-panel-open');
};
function closePanel(event){
if(event){
event.preventDefault();
}
if(visiblePanel) {
var id = visiblePanel.id;
console.log(id)
console.log(visiblePanel);
document.querySelector('.scid-popup').classList.remove('scid-popup');
visiblePanel.classList.remove('scid-panel-open');
overlay.removeClass('overlay-open');
overlay.addClass('overlay-close');
sizePanel(id);
}
}
function sizePanel(id) {
var panel = document.querySelector( '#' + id);
if (panel.offsetHeight == 0) {
panel.style.height = panel.scrollHeight + 'px';
} else {
panel.style.height = 0 +'px';
window.location.hash = "";
visiblePanel = null;
}
};
window.onhashchange = function() {
if(visiblePanel && window.location.hash != '#' + visiblePanel.id){
closePanel();
}
}
});
CSS:
.overlay-close {
height: 0;
opacity: 0;
}
.overlay-open {
height: 100%;
opacity: 1
overflow: scroll;
overflow-y: auto;
visibility: visible;
z-index: 69;
}
Body overflow is working fine but you also given overflow-x: scroll to HTML Tag that is creating scrollbar.
You have to remove style of html in your css
html{
overflow-x: hidden;
}
Then overflow on body will be working fine.
http://prntscr.com/gzs7xs

Show element for a second, then hide it

I'm trying to show an element for a short amount of time, then hiding it with a CSS transition, on a button click.
Here's the outline of what I did.
elem has a property of opacity: 0.
Fire event when button gets selected.
The events function will add, then remove a class named show to elem.
CSS has the following property: transition: opacity 500ms ease 1000ms;.
#elem.show has a property of opacity: 1.
The problem is, nothing happens when the button gets clicked on. How can I make element get shown, without a transition effect, then, after 1s close with a transition?
JSFiddle
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
elem.classList.remove('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 1000ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Using setTimeout is not tidy - it is better to listen to the animation end event and remove the show class. I have also used animation to show and hide the element successively - see demo below:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
elem.addEventListener("animationend", function(){
elem.classList.remove('show');
}, false);
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Update
Listening to the animation-end event do not seem necessary actually - it works properly even without it. The gist here is the use of void elem.offsetWidth to forcefully restart the animation:
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.remove('show');
// this force-restarts the CSS animation
void elem.offsetWidth;
elem.classList.add('show');
});
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
}
#elem.show {
animation: anime 1s 1;
}
#keyframes anime {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
<button id="btn">Press Me</button>
<div id="elem"></div>
just do this :
setTimeout(function() { elem.classList.remove('show'); }, 1000);
instead of writing :
elem.classList.remove('show');
To handle repeated clicks, do this ::
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
var timeOutFunc;
btn.addEventListener('click', function() {
elem.classList.add('show');
clearTimeout(timeOutFunc);
timeOutFunc = setTimeout(function() {elem.classList.remove('show') } , 1000);
});
This borrows from other answers, and addresses the multiple press "issue"
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', (function() {
var timer = null;
return function() {
elem.classList.add('show');
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(e => elem.classList.remove('show'), 1000);
};
})());
#elem {
background-color: orange;
width: 100px;
height: 100px;
opacity: 0;
transition: opacity 500ms ease 500ms;
}
#elem.show {
opacity: 1;
transition: none;
}
<button id="btn">Press Me</button>
<div id="elem"></div>
Try with this...i Hope its resolved your prblm
https://jsfiddle.net/b3en368p/5/
var btn = document.getElementById('btn');
var elem = document.getElementById('elem');
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(text){
elem.classList.remove('show');
}, 1000);
});
Add css
#elem {
background-color: orange;
width: 100px;
height: 100px;
display: none;
}
#elem.show {
display: block;
}
Your listener should be like this-
btn.addEventListener('click', function() {
elem.classList.add('show');
setTimeout(function(){
elem.classList.remove('show');
}, 1000);
});

Categories