Animate Bar programmatically - javascript

I would like a bar to animate from left to right. I have a numerical input. After the submit click, the bar should then be animated.
Unfortunately, I don't know how to trigger the animation. I deliberately set the initial width value to 150px to show that the animation actually works, but it not works if be triggered programmatically.
btn = document.getElementById("btn");
btn.addEventListener('click', () => {
const val = document.querySelector('input').value
draw(val);
})
function draw(val) {
bar = document.getElementById("bar");
bar.style.setProperty('--width', (val * 10) + "px");
}
:root {
--width: 150px;
}
#bar{
background:red;
height:50px;
margin:50px;
transform-origin:top;
animation: grow 2s forwards;
}
#keyframes grow {
from {
width:0px;
}
to {
width:var(--width);
}
}
<input value="5">
<button id="btn">draw</button>
<div id="bar"></div>

Instead of animation, use CSS transtion. Then (almost) any change to an element would be animated.
const runIt = () => {
$('.bar').css('width', '100%');
};
.bar {
height: 5px;
border-radius: 5px;
background: blue;
transition: 2s;
width: 10px;
margin-bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="bar"></div>
<button onclick="runIt()">Run</button>

This seems like a perfect use for CSS Transitions. Rather than adding an animation to the element, just set its width to have a transition time. Then, any time you change the width, it will be animated.
const btn = document.getElementById("btn");
btn.addEventListener('click', () => {
const val = document.querySelector('input').value
draw(val);
})
function draw(val) {
bar = document.getElementById("bar");
bar.style.setProperty('width', (val * 10) + "px");
}
#bar{
background:red;
width: 0;
height:50px;
margin:50px;
transform-origin:top;
transition: width 2s; /* Any time the width changes, it will be animated of 2 seconds */
}
<input value="5">
<button id="btn">Click Me</button>
<div id="bar"></div>

Related

Jquery slidetoggle code to vanilla Javascript that ahndle multiple elements toggle

I have few elements I need to slide, but I don't want to attach whole jQ lib. I like jQ a lot, but whole lib is just overkill in this example.
How to convert jq slideUp/slideDown/toggle to vanilla JS with support of multiple elements passed to function?
JQ code:
var $context = getContext(context);
$($context).on('click', '.menu', function () {
$('.nav').slideToggle();
});
JS code:
var list = document.getElementsByClassName("class1", "class2", "class3");
//or
var list = document.querySelectorAll("class1", "class2", "class3");
var slideUp = function(targets, duration){
// execution
};
slideUp(list, 500);
SO wizards make it happen! :)
I wasn't happy with the last solution I gave you it was rushed and buggy totally unacceptable, Hope you can forgive me...so this is a better version with the clicks of each item working too
const clicker = document.getElementsByClassName("clicker")[0];
clicker.addEventListener("click", function() {
process(document.querySelectorAll(".js-toggle"));
});
[...document.querySelectorAll(".js-toggle")].forEach((element) =>
element.addEventListener("click", function() {
process(this)
})
)
const container = [];
function process(linkToggle) {
container.length = 0
if (linkToggle.length > 0) {
for (let i = 0; i < linkToggle.length; i++) {
container.push(
document.getElementById(linkToggle[i].dataset.container))
animate(container[i])
}
} else {
container.push(
document.getElementById(linkToggle.dataset.container))
animate(container[0])
}
}
function animate(element) {
if (!element.classList.contains("active")) {
element.classList.add("active");
element.style.height = "auto";
let height = parseInt(element.clientHeight || 0)
element.style.height = "0px";
setTimeout(function() {
for (let t = 0; t < container.length; t++) {
do {
container[t].style.height =
parseInt(container[t].style.height || height) +
1 + 'px'
} while (parseInt(container[t].style.height || height) < height);
}
}, 0);
} else {
element.style.height = "0px";
element.addEventListener(
"transitionend",
function() {
element.classList.remove("active");
}, {
once: true
}
);
}
}
.clicker {
cursor: pointer;
background: red;
}
.box {
width: 300px;
border: 1px solid #000;
margin: 10px;
cursor: pointer;
}
.toggle-container {
transition: height 0.35s ease-in-out;
overflow: hidden;
}
.toggle-container:not(.active) {
display: none;
}
<div class="clicker">CLICK ME</div>
<div class="box">
<div class="js-toggle" data-container="toggle-1">Click1</div>
<div class="toggle-container" id="toggle-1">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
<div class="box">
<div class="js-toggle" data-container="toggle-2">Click2</div>
<div class="toggle-container open" id="toggle-2">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
<div class="box">
<div class="js-toggle" data-container="toggle-3">Click3</div>
<div class="toggle-container" id="toggle-3">I have an accordion and am animating the the height for a show reveal - the issue is the height which i need to set to auto as the information is different lengths.<br><br> I have an accordion and am animating the the height fferent lengths.
</div>
</div>
I hope this helps
you could just use css like so ( wasn't sure witch way you wanted to slid but this gives you an idea of how to do it):
var $slider = document.getElementById('slider');
var $toggle = document.getElementById('toggle');
$toggle.addEventListener('click', function() {
var isOpen = $slider.classList.contains('slide-in');
$slider.setAttribute('class', isOpen ? 'slide-out' : 'slide-in');
});
#slider {
position: absolute;
width: 100px;
height: 100px;
background: blue;
transform: translateX(-100%);
-webkit-transform: translateX(-100%);
}
.slide-in {
animation: slide-in 0.5s forwards;
-webkit-animation: slide-in 0.5s forwards;
}
.slide-out {
animation: slide-out 0.5s forwards;
-webkit-animation: slide-out 0.5s forwards;
}
#keyframes slide-in {
100% {
transform: translateX(0%);
}
}
#-webkit-keyframes slide-in {
100% {
-webkit-transform: translateX(0%);
}
}
#keyframes slide-out {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-100%);
}
}
#-webkit-keyframes slide-out {
0% {
-webkit-transform: translateX(0%);
}
100% {
-webkit-transform: translateX(-100%);
}
}
<div id="slider" class="slide-in">
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
</ul>
</div>
<button id="toggle" style="position:absolute; top: 120px;">Toggle</button>
I can't take credit for this its lifted from:
CSS 3 slide-in from left transition
I hope this helps
Could you not simply include the css in the page header so wouldn't need to edit any style sheets, well in any case then how about this:
function SlideDown() {
const element = document.getElementById("slider");
let top = 0;
const up = setInterval(MoveDown, 10);
function MoveDown() {
if (top == 50) {
clearInterval(up);
} else {
top++;
element.style.top = top + '%';
}
}
}
function SlideUp() {
const element = document.getElementById("slider");
let top = parseInt(element.style.top);
const down = setInterval(MoveUp, 10);
function MoveUp() {
if (top == -100) {
clearInterval(down);
} else {
top--;
element.style.top = top + '%';
}
}
}
<!DOCTYPE html>
<html>
<body>
<div id="slider" style="position:absolute; top: -100px;">
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
</ul>
</div>
<button onclick="SlideDown()">Slide Down</button>
<button onclick="SlideUp()">Slide Up</button>
</body>
</html>
I hope this helps

How to make animation on click only?

I made a small animation
When clicked, the animated square will change its height, but it will also animate when the window size / scale is changed. How to make it animate only when clicked, and in other cases just resize (no animation)
function myClick() {
document.getElementById("myDiv").style.height = Math.floor(Math.random() * 100) + "vmin";
}
#myDiv {
width: 20vmin;
height: 20vmin;
background: green;
transition: height 1s ease;
}
#myDiv:active {
background: blue;
}
<!DOCTYPE html>
<body>
<div id="myDiv" onclick="myClick()"></div>
</body>
</html>
One method is to add a class with transition and remove it after animation finished:
var timer;
document.getElementById("myDiv").addEventListener("transitionend", function(e)
{
clearTimeout(timer);
document.getElementById("myDiv").classList.toggle("clicked", false);
}, false);
function myClick() {
clearTimeout(timer);
document.getElementById("myDiv").classList.toggle("clicked", true);
document.getElementById("myDiv").style.height = Math.floor(Math.random() * 100) + "vmin";
timer = setTimeout(function() { //backup plan
document.getElementById("myDiv").classList.toggle("clicked", false);
}, 2000);
}
#myDiv {
width: 20vmin;
height: 20vmin;
background: green;
}
#myDiv:active {
background: blue;
}
#myDiv.clicked {
transition: height 1s ease;
}
<body>
<div id="myDiv" onclick="myClick()"></div>
</body>
Another method is to remove transition class when window is resized
function myClick() {
document.getElementById("myDiv").classList.toggle("clicked", true);
document.getElementById("myDiv").style.height = Math.floor(Math.random() * 100) + "vmin";
}
window.addEventListener('resize', function() {
document.getElementById("myDiv").classList.toggle("clicked", false);
});
#myDiv {
width: 20vmin;
height: 20vmin;
background: green;
}
#myDiv:active {
background: blue;
}
#myDiv.clicked {
transition: height 1s ease;
}
<body>
<div id="myDiv" onclick="myClick()"></div>
</body>
The only way I know is the listening window resize event.
We are removing the transition effect while resizing in here;
const myDiv = document.getElementById("myDiv")
window.addEventListener('resize', () => {
myDiv.style.transition = "all 0s ease 0s"
});
But then you have to put the transition back when you click like this;
function myClick() {
if(myDiv.style.transition === "all 0s ease 0s"){
myDiv.style.transition = "height 1s ease";
}
myDiv.style.height = Math.floor(Math.random() * 100) + "vmin";
}
Here's one way. It's a bit crude but it works. The div only has an animate class while the animation is taking place, using a timer. I made the timer longer than necessary and it turns yellow to make clear what's happening. I'm not sure if it can be done without a timer kludge.
let animateTimeout;
function myClick() {
let myDiv = document.getElementById("myDiv");
myDiv.style.height = Math.floor(Math.random() * 100) + "vmin";
myDiv.classList.add("animate");
clearTimeout(animateTimeout);
animateTimeout = setTimeout(() => myDiv.classList.remove("animate"), 1500);
}
#myDiv {
width: 20vmin;
height: 20vmin;
background: green;
}
#myDiv.animate {
background: yellow;
transition: height 1s ease;
}
#myDiv:active {
background: blue;
}
<!DOCTYPE html>
<body>
<div id="myDiv" onclick="myClick()"></div>
</body>
</html>

Why is animation (transition) not applied the first time the property is set

Here is a simple setup with a box moving using left property to the right. The property is updated by a button click. Why is transition animation not applied the first time I click on the button?
document.addEventListener('DOMContentLoaded', () => {
const box = document.querySelector('.box');
const button = document.querySelector('button');
button.addEventListener('click', () => {
const current = parseInt(box.style.left);
box.style.left = (isNaN(current) ? 0 : current) + 50 + "px";
});
})
.box {
width: 100px;
height: 100px;
background: green;
position: relative;
transition: left 1s;
}
<button>Click me!</button>
<div class="box"></div>
The initial value of left is auto and auto is not a transitionable value.
You would need to explicitly set left: 0 to have a transition then.
Start with some initial value for left.
document.addEventListener('DOMContentLoaded', () => {
const box = document.querySelector('.box');
const button = document.querySelector('button');
button.addEventListener('click', () => {
const current = parseInt(box.style.left);
box.style.left = (isNaN(current) ? 0 : current) + 50 + "px";
});
})
.box {
left: 0;
width: 100px;
height: 100px;
background: green;
position: relative;
transition: left 1s;
}
<button>Click me!</button>
<div class="box"></div>
As "left" property is intialized as "auto", no transitions can be applied.
Instead try this:
document.addEventListener('DOMContentLoaded', () => {
const box = document.querySelector('.box');
const button = document.querySelector('button');
button.addEventListener('click', () => {
const current = parseInt(box.style.left);
box.style.left = (isNaN(current) ? 0 : current) + 50 + "px";
});
})
.box {
left: 0;
width: 100px;
height: 100px;
background: green;
position: relative;
transition: left 1s;
}
<button>Click me!</button>
<div class="box"></div>

Simon Game : Two colors in a row won't fade properly

I'm trying to build a javascript 'Simon says' game.
So far, I made some basic tests with buttons.
First button 'Start' generates a sequence. Second button 'Show' will show what was generated.
Everything works except when the same color, in the random generated sequence, appears in a row.
Ex: = [ 'blue', 'yellow', 'yellow']
Only in this case the fade-in / fade-out effect won't work.
I checked with DevTools, what was wrong and it seems that the loop adds the class 'fade-out' to both indexes (in the case above..to index 1 and 2).
Why is that? And how can I fix it?
HTML
<div id="container">
<div id="blue" class="btn"></div>
<div id="red" class="btn"></div>
<div id="yellow" class="btn"></div>
<div id="green" class="btn"></div>
</div>
<button id="startBtn">Start</button>
<button id='showMe'>Show</button>
CSS
.btn {
height: 100px;
width: 25vw;
border: 1px solid black;
opacity: 1;
transition: opacity 1s ease;
}
.fade-out {
opacity: 0.5;
transition: opacity 1s ease;
}
#container {
display: flex;
flex-wrap: nowrap;
}
#blue {
background-color: blue;
}
#yellow {
background-color: yellow;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
JS
var color = container.querySelectorAll('div.btn');
var startBtn = document.getElementById('startBtn');
var showBtn = document.getElementById('showMe');
var pcSequence = [],
mySequence = [],
i,
theLoop;
startBtn.addEventListener('click', oneMore, false);
showBtn.addEventListener('click', showSeq, false);
function oneMore(){
pcSequence.push(color[Math.floor(Math.random() * 4)]);
}
function showSeq(){
i = 0;
theLoop = setInterval(function(){
if (i > 0){ pcSequence[i - 1].classList.remove('fade-out'); }
if (i >= pcSequence.length){
clearInterval(theLoop);
} else {
pcSequence[i].classList.add('fade-out');
}
i++;
}, 2000);
}
While I am not seeing the problem with fade-out appearing on two of the squares, I do see that, for example, in your case of blue, yellow, yellow, the yellow isn't doesn't become unfaded-out at all.
If that is the problem you are concerned about, the reason is that you are removing the class and then immediately re-adding it, so the ui is essentially not doing the fade-in.
Another strategy here might be to use the transitionend event to do the fade in, rather than doing that in the interval. Something like this (I put a hack in to force the red and yellow to be set each time):
var color = container.querySelectorAll('div.btn');
var startBtn = document.getElementById('startBtn');
var showBtn = document.getElementById('showMe');
var pcSequence = [],
mySequence = [],
i,
theLoop;
startBtn.addEventListener('click', oneMore, false);
showBtn.addEventListener('click', showSeq, false);
// Force red initially
pcSequence.push(color[1]);
function oneMore(){
// Force yellow each time they press Start
pcSequence.push(color[2]);
//Math.floor(Math.random() * 4)]);
}
function clearTransition() {
var colorSquare = pcSequence[i - 1];
colorSquare.removeEventListener('transitionend', clearTransition);
colorSquare.classList.remove('fade-out');
}
function showSeq(){
i = 0;
theLoop = setInterval(function(){
if (i >= pcSequence.length){
clearInterval(theLoop);
} else {
var colorSquare = pcSequence[i];
colorSquare.classList.add('fade-out');
colorSquare.addEventListener('transitionend', clearTransition);
}
i++;
}, 2000);
}
.btn {
height: 100px;
width: 25vw;
border: 1px solid black;
opacity: 1;
transition: opacity 1s ease;
}
.fade-out {
opacity: 0.5;
transition: opacity 1s ease;
}
#container {
display: flex;
flex-wrap: nowrap;
}
#blue {
background-color: blue;
}
#yellow {
background-color: yellow;
}
#red {
background-color: red;
}
#green {
background-color: green;
}
<div id="container">
<div id="blue" class="btn"></div>
<div id="red" class="btn"></div>
<div id="yellow" class="btn"></div>
<div id="green" class="btn"></div>
</div>
<button id="startBtn">Start</button>
<button id='showMe'>Show</button>

Vertical distribution of elements (and animation) - jQuery

I like to know the cleanest method to distribute elements vertically with jQuery. I nailed it but it's not very clean right >< ? I would like to get to do it without plugin... Thank you in advance ;-)
Here my JSFiddle
jQuery(document).ready(function($) {
var gap = 10;
var firstElem = $('#lorem');
if(firstElem.length){
var heightCall = (firstElem.offset().top)+(firstElem.outerHeight())+(gap);
var middleElem = $('#dolore');
middleElem.offset({top : heightCall});
var lastElem = $('#amet');
var NewHeightCall = (middleElem.offset().top)+(middleElem.outerHeight())+(gap);
lastElem.offset({top : NewHeightCall});
/* Animation */
$('#lorem, #dolore, #amet').hover(
function(){
$(this).stop().animate({left: (($(this).offset().left)-(20))+'px',opacity:'0.5'},'slow')
},
function(){
$(this).stop().animate({left: (($(this).offset().left)+(20))+'px',opacity:'1'},'slow')
});
}
});
I have fiddled around with your code:
This is a simplified version:
HTML:
<div id="lorem" class="vertical-block">My first ID div</div>
<div id="dolore" class="vertical-block">My second ID div.<br>My second ID div. My second ID div.</div>
<div id="amet" class="vertical-block">My third ID div</div>
CSS:
.vertical-block {
position: absolute;
padding:15px;
}
#lorem{
top:20%;
right:40px;
background:#f79673;
}
#dolore{
right:80px;
background:#cd7454;
}
#amet{
right:40px;
background:#a15338;
}
.vertical-block:hover {
opacity: 0.5;
padding-right: 30px;
-webkit-transition: all 2s;
transition: all 0.4s;
}
Javascript:
jQuery(document).ready(function($) {
var gap = 10;
var firstElem = $('#lorem');
var top = 0;
$('.vertical-block').each(function(element){
var $currentElement = $(this);
if (top === 0) {
top = $currentElement.offset().top + $currentElement.outerHeight() + gap;
} else {
$currentElement.offset({top: top});
top = top + $currentElement.outerHeight() + gap;
}
});
});
https://jsfiddle.net/rae2x4e0/1/
Now if you want to go for a purely css solution, then:
HTML:
<div class="container">
<div id="lorem" class="vertical-block">My first ID div</div>
<br />
<div id="dolore" class="vertical-block">My second ID div.<br>My second ID div. My second ID div.</div>
<br />
<div id="amet" class="vertical-block">My third ID div</div>
</div>
CSS:
.container {
position-relative;
text-align: right;
padding-top: 10%;
}
.vertical-block {
padding:15px;
display: inline-block;
margin-top: 20px;
}
#lorem{
right:40px;
background:#f79673;
}
#dolore{
right:80px;
background:#cd7454;
}
#amet{
right:40px;
background:#a15338;
}
.vertical-block:hover {
opacity: 0.5;
padding-right: 30px;
-webkit-transition: all 2s;
transition: all 0.4s;
}
https://jsfiddle.net/ycdwpjxw/1/

Categories

Resources