Does hiding a div stop animations (CSS or JS)? - javascript

Considering any CSS based loader animation as a reference. Typically, when some callback function is executed on success, the div is hidden so as to indicate that the results have arrived. My question is, does hiding the div actually stop the animation? Or do those still continue to use up CPU cycles?
What about non-CSS animations?

TL;DR
My question is, does hiding the div actually stop the animation? Or do those still continue to use up CPU cycles?
Not sure how the animation state is defined internally, but it's not using CPU cycles once hidden.
What about non-CSS animations?
CPU cycles are not used for rendering, but they are used for the JavaScript calculations under the hood.
Detailed answers with relevant examples/tests below:
CSS
As you can see here, the browser (at least in which I tested it) seems not to waste any cycles on invisible elements. It could vary with browsers as well as the browser versions. I assume older browsers don't care about this, but all the modern ones will try to save as much CPU as possible.
Here's a snippet/proof, try doubling the dark divs until it starts choking, then toggle them and see how the light div behaves:
function dbl(){
var c = document.querySelectorAll('div.reg').length;
for(var i = 0; i < c; i++){
var div = document.createElement('div');
div.className = 'reg';
document.body.appendChild(div);
}
}
function toggle(){
var divs = document.querySelectorAll('div.reg');
for(var i = 0; i < divs.length; i++){
divs[i].style.display =
divs[i].style.display == 'none' ?
'inline-block' : 'none';
}
}
div {height: 50px; width: 50px; margin: 2px; display: inline-block; background: #eee; animation: rot 1s linear infinite}
div.reg {background: #ccc}
#keyframes rot {
0% { transform: rotateZ(0deg) }
100% { transform: rotateZ(360deg) }
}
<button onclick="dbl()">Double dark divs</button>
<button onclick="toggle()">Toggle dark divs</button><br>
<div></div>
<div class="reg"></div>
JS (non-CSS)
For the non-CSS stuff, the browser won't waste any cycles on rendering the animations, but the JavaScript animation calculations will most definitely take place.
var r = 1;
var fps = document.querySelector('span');
var lastFrame = new Date();
function dbl(){
var c = document.querySelectorAll('div.reg').length;
for(var i = 0; i < c; i++){
var div = document.createElement('div');
div.className = 'reg';
document.body.appendChild(div);
}
}
function toggle(){
var divs = document.querySelectorAll('div.reg');
for(var i = 0; i < divs.length; i++){
divs[i].style.display =
divs[i].style.display == 'none' ?
'inline-block' : 'none';
}
}
function rot(){
var divs = document.querySelectorAll('div');
for(var i = 0; i < divs.length; i++){
divs[i].style.transform = 'rotateZ(' + r + 'deg)';
}
r = (r+1)%360;
fps.textContent = parseInt(1000 / (new Date() - lastFrame), 10);
lastFrame = new Date();
window.requestAnimationFrame(rot);
}
function kill() {
var divs = document.querySelectorAll('div.reg');
for(var i = 1; i < divs.length; i++){
divs[i].parentElement.removeChild(divs[i]);
}
}
rot()
div {height: 50px; width: 50px; margin: 2px; display: inline-block; background: #eee;}
div.reg {background: #ccc}
<button onclick="dbl()">Double dark divs</button>
<button onclick="toggle()">Toggle dark divs</button>
<button onclick="kill()">Kill dark dupes</button>FPS: <span></span>
<br>
<div></div><div class="reg"></div>
The JS calculations here are very heavy (on purpose) and you can see they keep running in the background.

Related

Adding a fade between JavaScript slideshow? [duplicate]

I have created a JavaScript Slideshow, but I don't know how to add the fade effect. Please tell me how to do it, and please tell in JavaScript only, no jQuery!
Code:
var imgArray = [
'img/slider1.jpg',
'img/slider2.jpg',
'img/slider3.jpg'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').src = imgArray[curIndex];
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
setTimeout("slideShow()", imgDuration);
}
slideShow();
Much shorter than Ninja's solution and with hardware accelerated CSS3 animation. http://jsfiddle.net/pdb4kb1a/2/ Just make sure that the transition time (1s) is the same as the first timeout function (1000(ms)).
Plain JS
var imgArray = [
'http://placehold.it/300x200',
'http://placehold.it/200x100',
'http://placehold.it/400x300'],
curIndex = 0;
imgDuration = 3000;
function slideShow() {
document.getElementById('slider').className += "fadeOut";
setTimeout(function() {
document.getElementById('slider').src = imgArray[curIndex];
document.getElementById('slider').className = "";
},1000);
curIndex++;
if (curIndex == imgArray.length) { curIndex = 0; }
setTimeout(slideShow, imgDuration);
}
slideShow();
CSS
#slider {
opacity:1;
transition: opacity 1s;
}
#slider.fadeOut {
opacity:0;
}
As an alternative. If you are trying to make a slider.
The usual approach is to animate a frame out and animate a frame in.
This is what makes the slide effect, and the fade effect work. Your example fades in. Which is fine, but maybe not what you really want once you see it working.
If what you really want is to animate images in and ...OUT you need something a little more complex.
To animate images in and out you must use an image element for each, then flip one out and flip one in. The images need to be placed on top of each other in the case of a fade, if you want to slide you lay them beside each other.
Your slideshow function then works the magic, but before you can do that you need to add all those images in your array into the dom, this is called dynamic dom injection and it's really cool.
Make sure you check the fiddle for the full working demo and code it's linked at the bottom.
HTML
<div id="slider">
// ...we will dynamically add your images here, we need element for each image
</div>
JS
var curIndex = 0,
imgDuration = 3000,
slider = document.getElementById("slider"),
slides = slider.childNodes; //get a hook on all child elements, this is live so anything we add will get listed
imgArray = [
'http://placehold.it/300x200',
'http://placehold.it/200x100',
'http://placehold.it/400x300'];
//
// Dynamically add each image frame into the dom;
//
function buildSlideShow(arr) {
for (i = 0; i < arr.length; i++) {
var img = document.createElement('img');
img.src = arr[i];
slider.appendChild(img);
}
// note the slides reference will now contain the images so we can access them
}
//
// Our slideshow function, we can call this and it flips the image instantly, once it is called it will roll
// our images at given interval [imgDuration];
//
function slideShow() {
function fadeIn(e) {
e.className = "fadeIn";
};
function fadeOut(e) {
e.className = "";
};
// first we start the existing image fading out;
fadeOut(slides[curIndex]);
// then we start the next image fading in, making sure if we are at the end we restart!
curIndex++;
if (curIndex == slides.length) {
curIndex = 0;
}
fadeIn(slides[curIndex]);
// now we are done we recall this function with a timer, simple.
setTimeout(function () {
slideShow();
}, imgDuration);
};
// first build the slider, then start it rolling!
buildSlideShow(imgArray);
slideShow();
Fiddle:
http://jsfiddle.net/f8d1js04/2/
you can use this code
var fadeEffect=function(){
return{
init:function(id, flag, target){
this.elem = document.getElementById(id);
clearInterval(this.elem.si);
this.target = target ? target : flag ? 100 : 0;
this.flag = flag || -1;
this.alpha = this.elem.style.opacity ? parseFloat(this.elem.style.opacity) * 100 : 0;
this.elem.si = setInterval(function(){fadeEffect.tween()}, 20);
},
tween:function(){
if(this.alpha == this.target){
clearInterval(this.elem.si);
}else{
var value = Math.round(this.alpha + ((this.target - this.alpha) * .05)) + (1 * this.flag);
this.elem.style.opacity = value / 100;
this.elem.style.filter = 'alpha(opacity=' + value + ')';
this.alpha = value
}
}
}
}();
this is how to use it
fadeEffect.init('fade', 1, 50) // fade in the "fade" element to 50% transparency
fadeEffect.init('fade', 1) // fade out the "fade" element
Much shorter answer:
HTML:
<div class="js-slideshow">
<img src="[your/image/path]">
<img src="[your/image/path]" class="is-shown">
<img src="[your/image/path]">
</div>
Javascript:
setInterval(function(){
var $container = $('.js-slideshow'),
$currentImage = $container.find('.is-shown'),
currentImageIndex = $currentImage.index() + 1,
imagesLength = $container.find('img').length;
$currentImage.removeClass('is-shown');
$currentImage.next('img').addClass('is-shown');
if ( currentImageIndex == imagesLength ) {
$container.find('img').first().addClass('is-shown');
}
}, 5000)
SCSS
.promo-banner {
height: 300px;
width: 100%;
overflow: hidden;
position: relative;
img {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
z-index: -10;
transition: all 800ms;
&.is-shown {
transition: all 800ms;
opacity: 1;
z-index: 10;
}
}
}

how to get cubes to change to black when mouse moves over them

how does one get the cubes made in the grid to turn black with mouse running over? any help would be appreciated.
function Grid(z) {
for (y=0; y < z; y++) {
for (x=0; x < z; x++) {
size = 700 / z;
var div = document.querySelector('#container');
var block = document.createElement('div');
block.style.height = size + 'px';
block.style.width = size + 'px';
block.classList.add('cube');
div.appendChild(block);
}
}
}
function changeBlockColor() {
Grid(16);
var s = document.querySelector('.cube');
s.addEventListener('onmouseover', function(){
s.setAttribute('style', 'background: black');
});
}
changeBlockColor();
I would use CSS to achieve this effect.
.cube {
background-color:red;
}
.cube:hover {
background-color: black;
}
The following is for if you want the cubes to stay black after you finished hovering over them (and then hovered out).
First, your s = document.querySelector('.cube'); will make s only point to the first element with class cube. To solve that, make s an array of all elements of class cube, by using s = document.querySelectorAll('.cube'); instead.
Next, you need to loop through the array s and add the event listener to all its elements:
for(var i = 0; i < s.length; i++) {
s[i].addEventListener('mouseover', function(){
this.setAttribute('style', 'background: black');
});
}
Notice the use of this inside the handler. Inside handler code, this refers to the object that triggered the event (the cube moused over in your case).
No need to have hundred of mouseover Event Listener. Just one is enough
var
divContainer = document.getElementById('container'),
CubeClass = 'cube';
function Grid(z)
{
var sizePx = Math.floor(700 / z) + 'px';
for (let y = 0; y < z; y++)
{
for (let x = 0; x < z; x++)
{
let block = document.createElement('div');
block.style.height = sizePx;
block.style.width = sizePx;
block.className = CubeClass;
divContainer.appendChild(block);
};
};
}
divContainer.onmouseover = function(e)
{
if (!e.target.classList.contains( CubeClass )) return;
e.target.setAttribute('style', 'background: black');
}
divContainer.onmouseout = function(e) // if you need it...
{
if (!e.target.classList.contains( CubeClass )) return;
e.target.removeAttribute('style');
}
The event name you want is mouseover, not onmouseover
Also, querySelector will only find the first matching element, so you need to use querySelectorAll or getElementsByClassName instead
Finally, you need to iterate over all the elements you matched, which are returned in an Object, not an Array, so you need to use a for loop.
Solution
function createGrid(z) {
for (var y = 0; y < z; ++y) {
for (var x = 0; x < z; ++x) {
var size = 700 / z;
var div = document.getElementById('container');
var block = document.createElement('div');
block.style.height = size + 'px';
block.style.width = size + 'px';
block.classList.add('cube');
div.appendChild(block);
}
}
changeBlockColor()
}
function changeBlockColor(){
var cubes = document.querySelectorAll('.cube')
for (var i = 0; i < cubes.length; i++) {
cubes[i].addEventListener("mouseover", function(e) {
e.target.classList.add('active')
})
}
}
createGrid(16);
#container {
display: flex;
flex-wrap: wrap;
}
.cube {
background-color: red;
}
.active {
background-color: black;
}
<div id="container"></div>
Implementation Details
Naming is all preference in JS, but traditionally, names that start with a capital letter are for a class, so I renamed you function to createGrid
At the end of createGrid I call changeBlockColor, rather than call createGrid from inside changeBlockColor, logically it make more sense.
I created a CSS class called active to handle changing the color, as using setAttribute('style') was erasing the height and width styles you applied inside you Grid function.
Feedback
You use querySelector exclusively, you should get to know getElementById as well.
You use var a few times, but don't declare y, x, or size
You can define y and x in your for loop with for(var y=0 and for(var x=0
CSS Solution
Assuming you want the color to revert on mouseout, you can achieve this same effect with CSS using .cube:hover
.cube {
display: inline-block;
width: 50px;
height: 50px;
background-color: red;
}
.cube:hover {
background-color: black;
}
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
<div class="cube"></div>
Performance
A side note about using querySelector('#container') vs getElementById('container'). The first has to traverse the entire DOM looking for the selector, the latter can just go to the internal list of ids and return the reference.
https://jsperf.com/so53824751
Documentation
https://developer.mozilla.org/en-US/docs/Web/Events/mouseover
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById

Changing css animation in javascript

I have a blinking red box in my html it uses css animations. I want to to be able to change it from blinking red and white to green and white. I know this can be done on id elements by using getElementbyId but how would get access to the green aminated box in the css.
The red box looks like this:
#-webkit-keyframes 'noConnection'
{
1% { background-color: red; }
33% { background: white; }
66% { background: red; }
100% { background: white; }
}
The green is this:
#-webkit-keyframes 'Connection'
{
1% { background-color: green; }
33% { background: white; }
66% { background: green; }
100% { background: white; }
}
The animate looks like this:
#animate {
height: 15px;
width: 15px;
}
.cssanimations #animate {
-webkit-animation-direction: normal;
-webkit-animation-duration: 5s;
-webkit-animation-iteration-count: infinite;
-webkit-animation-name: Connection;
-webkit-animation-timing-function: ease;
and I think I have to change the attribute -webkit-animation-name: from javascript to do this but I dont know how to get a handle on it to change it.
Or would I be better off creating a duplicate #animate and renaming it using the getElementById?
Here is a simple web page that demonstrates how to use Javascript to modify a CSS animation. It contains a simple div, and a little Javascript causes the div to move randomly around the page.
In your specific case, you just need to touch up the line that calls "insertRule" to insert your new blinking rule.
<html><head><style></style></head>
<body>
<div id="mymovingdiv">
<h1>Moving Div</h1>
<p>And some little text too</p>
</div>
<script>
function animatedMove(id, xStart, yStart, xEnd, yEnd, secs)
{
// Remove any CSS rules inserted by a previous call to this method
let rulename = `AnimMove${id}`;
let ss = document.styleSheets; // all stylesheets
for (let i = 0; i < ss.length; ++i) { // for each stylesheet...
for (let j = ss[i].cssRules.length - 1; j > 0; j--) { // for each rule...
if (ss[i].cssRules[j].name === rulename) { // does the name match?
ss[i].deleteRule(j);
}
}
}
// Insert a CSS rule for this animation
document.styleSheets[0].insertRule(`#keyframes ${rulename} { 0% { left: ${xStart}px; top: ${yStart}px; } 100% { left: ${xEnd}px; top: ${yEnd}px } }`);
// Remove any CSS rules inserted by a previous call to this method
for (let i = 0; i < ss.length; ++i) { // for each stylesheet...
for (let j = ss[i].cssRules.length - 1; j > 0; j--) { // for each rule...
if (ss[i].cssRules[j].name === rulename) { // does the name match?
ss[i].deleteRule(j);
}
}
}
// Insert a CSS rule for this animation
document.styleSheets[0].insertRule(`#keyframes ${rulename} { 0% { left: ${xStart}px; top: ${yStart}px; } 100% { left: ${xEnd}px; top: ${yEnd}px } }`);
// assign the animation to our element
let el = document.getElementById(id);
el.style.position = 'absolute';
el.style.animation = `${rulename} ${secs}s`;
// Make the element stay where the animation ends
el.style.left = `${xEnd}px`;
el.style.top = `${yEnd}px`;
// Re-clone the element, to reset the animation
el.parentNode.replaceChild(el.cloneNode(true), el);
}
let x = 0;
let y = 0;
function randomMove()
{
let newX = Math.floor(Math.random() * 800);
let newY = Math.floor(Math.random() * 600);
animatedMove('mymovingdiv', x, y, newX, newY, 1);
x = newX;
y = newY;
}
setInterval(randomMove, 1000);
</script>
</body>
</html>
The easiest way to do this is to created two classes in CSS and then toggle between the two.
So something like:
.connection {
animation: 'Connection' 5s ease infinite
}
.no-connection {
animation 'noConnection' 5s ease infinite
}
And then use Javascript to toggle between the two
function toggleConnectionStatus(){
var element = document.getElementById('animate');
if(/* connection is active */) element.className = 'connection';
else element.className = 'no-connection'
}

How to make marquee when hover in - text scroll and infinite loop, out - back to start position?

here is my jsfiddle http://jsfiddle.net/9XdV7/, how to make when hover in - text scroll and infinite loop, out - back to start position? now it can't infinite loop scroll
for (var i = 0; i < $('.list').length; i++) {
var this_el = $('.list').eq(i);
var interval = null;
$(this_el).hover(function() {
var that = $(this);
var this_indent = 0;
interval = setInterval(function(){
this_indent--;
if (this_indent == -($(that).find('.text').width())) {
clearInterval(interval);
this_indent = 0;
// how to loop scroll
}
$(that).css('text-indent', this_indent);
},20);
}, function() {
clearInterval(interval);
$(this).css('text-indent', 0);
});
}
html & css
<div class="list"><div class="text">stringstringstringstring</div></div>
<div class="list"><div class="text">stringstringstring</div></div>
<div class="list"><div class="text">stringstringstringstring</div></div>
.list {
width: 100px;
overflow: hidden;
white-space:nowrap;
height: 15px;
background-color: red;
margin: 10px;
}
.text {
text-align: left;
background-color: purple;
display: inline;
}
Is this what you're looking for? Fiddle
I used mouseenter and mouseleave instead of hover.
$(elem).on("mouseenter",function() { ... });
I stored the identifier belonging to the element in its data: $(this).data("interval",interval);
I added
if(this_indent < -150) {
this_indent = 100;
}
to make the effect infinite. -150 is a value I got from the developer tools. 100 is pure testing.
This still wants some tweaking for determining the point at which to loop, but I think it's basically what you want:
$(function() {
for (var i = 0; i < $('.list').length; i++) {
var this_el = $('.list').eq(i);
var interval = null;
$(this_el).hover(function() {
var that = $(this);
var this_indent = 0;
interval = setInterval(function(){
this_indent--;
if (this_indent < that.width() * -1)
this_indent = that.width();
that.css('text-indent', this_indent);
},20);
}, function() {
clearInterval(interval);
$(this).css('text-indent', 0);
});
}
});
It's looping based on the width of the div, rather than the actual length of the text. If you want the text width, you could look here: Calculating text width

Array slide show not working smoothly with javascript

Written some javascript (very new to this) to center the div and make it full screen adjusting as the window does, that works fine but now I have added some script I found online to transition from one image to another using an array. They seem to be contradicting each other messing up the animation, the biggest problem is when I resize the window. Here is my jsfiddle so you can see for yourself. Thanks in advance.
http://jsfiddle.net/xPZ3W/
function getWidth() {
var w = window.innerWidth;
x = document.getElementById("wrapper");
x.style.transition = "0s linear 0s";
x.style.width= w +"px";
}
function moveHorizontal() {
var w = window.innerWidth;
x = document.getElementById("wss");
x.style.transition = "0s linear 0s";
x.style.left= w / 2 -720 +"px" ;
}
function moveVertical() {
var h = window.innerHeight;
x = document.getElementById("wss");
x.style.transition = "0s linear 0s";
x.style.top= h / 2 -450 +"px" ;
}
var i = 0;
var wss_array = ['http://cdn.shopify.com/s/files/1/0259/8515/t/14/assets/slideshow_3.jpg? 48482','http://cdn.shopify.com/s/files/1/0259/8515/t/14/assets/slideshow_5.jpg?48482'];
var wss_elem;
function wssNext(){
i++;
wss_elem.style.opacity = 0;
if(i > (wss_array.length - 1)){
i = 0;
}
setTimeout('wssSlide()',1000);
}
function wssSlide(){
wss_elem = document.getElementById("wss")
wss_elem.innerHTML = '<img src="'+wss_array[i]+'">';
wss.style.transition = "0.5s linear 0s";
wss_elem.style.opacity = 1;
setTimeout('wssNext()',3000);
}
So I whipped up this JSFiddle from scratch, and I hope it helps out. Pure CSS transitions from class to class using your array URLs to switch among the pictures.
Basically this just advances the "active" class to the next one everytime it's called, provided the first picture is set to "active" class.
var pics = document.getElementById('slideshow').children,
active = 0;
function slideshow() {
for (var i = 0; i < pics.length; i++) {
if (i == active && pics[i].className == "active") {
console.log(i, active, (active + 1) % pics.length);
active = (active + 1) % pics.length;
}
pics[i].className = "";
}
pics[active].className = "active";
setTimeout(slideshow, 2000);
}
setTimeout(slideshow, 2000);
And here's the CSS, which absolutely positions the container, and hides all its children unless it has the active class, to which it will transition smoothly.
#slideshow {
position: absolute;
top: 20%;
bottom: 20%;
left: 20%;
right: 20%;
}
#slideshow img {
position: absolute;
max-height: 100%;
max-width: 100%;
opacity: 0;
transition: opacity 1s linear;
}
#slideshow .active {
opacity: 1;
}

Categories