Home > Blockchain >  Not working hide with fadeOut() on moving elements
Not working hide with fadeOut() on moving elements

Time:03-12

I made a small page on which circles are created in random places.

Next, I made an animation and hiding these elements on click with fadeOut()

Here's How It Works https://jsfiddle.net/n7za1t6r/

Now I want all these created circles to move all over the page, I did it, they move, but hiding with fadeOut() stopped working. On click, the animation works, but the element is not hidden

What could be the problem?

//create circle

var widthHeight = 45;
var margin = 25;
var delta = widthHeight   margin;

function createDiv(id, color) {
  let div = document.createElement('div');
  var currentTop = 0;
  var documentHeight = document.documentElement.clientHeight;
  var documentWidth = document.documentElement.clientWidth;
  div.setAttribute('class', id);
  if (color === undefined) {
    let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
    div.style.borderColor = colors[Math.floor(Math.random() * colors.length)];
  }
  else {
   div.style.borderColor = color; 
  }
  div.classList.add("circle");
  div.classList.add("animation");
  
  currentTop = Math.floor(Math.random() * documentHeight) - delta;
  currentLeft = Math.floor(Math.random() * documentWidth) - delta;
  
  var limitedTop = Math.max(margin * -1, currentTop);
  var limitedLeft = Math.max(margin * -1, currentLeft);

  div.style.top = limitedTop   "px";
  div.style.left = limitedLeft   "px";
        
  const nodes = document.querySelectorAll('.animation');
  for(let i = 0; i < nodes.length; i  ) {
  nodes[i].addEventListener('click', (event) => {
    event.target.style.animation = 'Animation 200ms linear';
    setTimeout(() => {
      event.target.style.animation = '';
    }, 220);  });
  }
  
  let clicks = 0;
 
  $(div).click(function() {
    $('#clicks').text(parseInt($('#clicks').text())   1);            
    $(this).fadeOut();
  });
  
  document.body.appendChild(div);
}
    
let i = 0;

const twoSecond = 2000;

setInterval(() => {
  i  = 1;
  createDiv(`circle${i}`);
  animateC();
}, twoSecond);

//move

function makeNewPosition(){
    
    // Get viewport dimensions (remove the dimension of the div)
    var h = $(window).height() - 50;
    var w = $(window).width() - 50;
    
    var nh = Math.floor(Math.random() * h);
    var nw = Math.floor(Math.random() * w);
    
    return [nh,nw];    
    
}

function animateC(){
    var newq = makeNewPosition();
    var oldq = $('.circle').offset();
    var speed = calcSpeed([oldq.top, oldq.left], newq);
    
    $('.circle').animate({ top: newq[0], left: newq[1] }, speed, function(){
      animateC();        
    });
    
};

function calcSpeed(prev, next) {
    
    var x = Math.abs(prev[1] - next[1]);
    var y = Math.abs(prev[0] - next[0]);
    var greatest = x > y ? x : y;
    
    var speedModifier = 0.1;// control the speed here 

    var speed = Math.ceil(greatest/speedModifier);
    return speed;

}
.circle {
  width: 35px;
  height: 35px;
  border-radius: 35px;
  background-color: #ffffff;
  border: 3px solid #000;
  margin: 20px;
  position: absolute;
}

@keyframes Animation {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(.8);
  }
  100% {
    transform: scale(1);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

CodePudding user response:

The reason that .fadeOut() is no longer working is because .fadeOut() internally uses .animate, so gets added to the animate queue.

You can confirm this by removing your animateC and changing your onclick:

  $(div).click(function() {
    $('#clicks').text(parseInt($('#clicks').text())   1);            
    $(this).animate({ top:0 }, 100)
    $(this).fadeOut();
  });

the fadeOut only runs when the animate has completed.

However, you re-animate every circle in a loop, so the .fadeOut() get pushed to the back of a very long queue and appears never run.

In the snippet below, I've limited to 3 circles (with a hack...don't do it this way, just for demo).

If you click the first one when it's first moving and before others appear then you'll see it jump to the top and fadeOut, if you wait until others appear and click them, then you need to wait until all the previously queued animations have completed, but they do eventually fadeOut (depending on how long you waited).

Because of $(".circle").animate adding additional animation to every circle, how long before it fadesOut depends on how many circles there are.

//create circle

var widthHeight = 45;
var margin = 25;
var delta = widthHeight   margin;

function createDiv(id, color) {
  let div = document.createElement('div');
  var currentTop = 0;
  var documentHeight = document.documentElement.clientHeight;
  var documentWidth = document.documentElement.clientWidth;
  div.setAttribute('class', id);
  if (color === undefined) {
    let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
    div.style.borderColor = colors[Math.floor(Math.random() * colors.length)];
  }
  else {
   div.style.borderColor = color; 
  }
  div.classList.add("circle");
  div.classList.add("animation");
  
  currentTop = Math.floor(Math.random() * documentHeight) - delta;
  currentLeft = Math.floor(Math.random() * documentWidth) - delta;
  
  var limitedTop = Math.max(margin * -1, currentTop);
  var limitedLeft = Math.max(margin * -1, currentLeft);

  div.style.top = limitedTop   "px";
  div.style.left = limitedLeft   "px";

  
  let clicks = 0;
 
  $(div).click(function() {
    $('#clicks').text(parseInt($('#clicks').text())   1);            
    $(this).animate({ top:0 }, 100)
    $(this).fadeOut();
  });
  
  document.body.appendChild(div);
}
    
let i = 0;

const twoSecond = 2000;

createDiv(`circle${i}`);
setInterval(() => {
  i  = 1;
  if (i>3) return;
  createDiv(`circle${i}`);
  animateC();
}, twoSecond);

//move

function makeNewPosition(){
    
    // Get viewport dimensions (remove the dimension of the div)
    var h = $(window).height() - 50;
    var w = $(window).width() - 50;
    
    var nh = Math.floor(Math.random() * h);
    var nw = Math.floor(Math.random() * w);
    
    return [nh,nw];    
    
}

function animateC(){
    var newq = makeNewPosition();
    var oldq = $('.circle').offset();
    var speed = calcSpeed([oldq.top, oldq.left], newq);
    
    $('.circle').animate({ top: newq[0], left: newq[1] }, speed, function(){
      animateC();        
    });
    
};

function calcSpeed(prev, next) {
    
    var x = Math.abs(prev[1] - next[1]);
    var y = Math.abs(prev[0] - next[0]);
    var greatest = x > y ? x : y;
    
    var speedModifier = 0.1;// control the speed here 

    var speed = Math.ceil(greatest/speedModifier);
    return speed;

}
.circle {
  width: 35px;
  height: 35px;
  border-radius: 35px;
  background-color: #ffffff;
  border: 3px solid #000;
  margin: 20px;
  position: absolute;
}

@keyframes Animation {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(.8);
  }
  100% {
    transform: scale(1);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


Ideally, you want to update animateC so that it only animates the one div, but that may give a stack overflow (not sure about recursive calls from within an animate, it's ok with a setTimeout, so that could be the solution there).

However, you probably just want the circle to go as soon as you click it, rather than when it's finished its current move, so you need to cancel the animation queue. In your case, via stop()

$(this).stop(true, false);

true, false will clear the queue, but not jump to the end (while .finish() will jump to the end)

Updated snippet - I've left in the jump to top just to show it working

//create circle

var widthHeight = 45;
var margin = 25;
var delta = widthHeight   margin;

let clicks = 0;

function createDiv(id, color) {
  let div = document.createElement('div');
  var currentTop = 0;
  var documentHeight = document.documentElement.clientHeight;
  var documentWidth = document.documentElement.clientWidth;
  div.setAttribute('class', id);
  if (color === undefined) {
    let colors = ['#35def2', '#35f242', '#b2f235', '#f2ad35', '#f24735', '#3554f2', '#8535f2', '#eb35f2', '#f2359b', '#f23547'];
    div.style.borderColor = colors[Math.floor(Math.random() * colors.length)];
  }
  else {
   div.style.borderColor = color; 
  }
  div.classList.add("circle");
  div.classList.add("animation");
  
  currentTop = Math.floor(Math.random() * documentHeight) - delta;
  currentLeft = Math.floor(Math.random() * documentWidth) - delta;
  
  var limitedTop = Math.max(margin * -1, currentTop);
  var limitedLeft = Math.max(margin * -1, currentLeft);

  div.style.top = limitedTop   "px";
  div.style.left = limitedLeft   "px";
  
  $(div).click(function() {
    $('#clicks').text(  clicks);            
    $(this)
        .stop(true, false)
        .animate({ top:0 }, 100)
        .fadeOut();
  });
  
  document.body.appendChild(div);
}
    
let i = 0;

const twoSecond = 2000;

createDiv(`circle${i}`);
setInterval(() => {
  i  = 1;
  //if (i>3) return;
  createDiv(`circle${i}`);
  animateC();
}, twoSecond);

//move

function makeNewPosition(){
    
    // Get viewport dimensions (remove the dimension of the div)
    var h = $(window).height() - 50;
    var w = $(window).width() - 50;
    
    var nh = Math.floor(Math.random() * h);
    var nw = Math.floor(Math.random() * w);
    
    return [nh,nw];    
    
}

function animateC(){
    var newq = makeNewPosition();
    var oldq = $('.circle').offset();
    var speed = calcSpeed([oldq.top, oldq.left], newq);
    
    $('.circle').animate({ top: newq[0], left: newq[1] }, speed, function(){
      animateC();        
    });
    
};

function calcSpeed(prev, next) {
    
    var x = Math.abs(prev[1] - next[1]);
    var y = Math.abs(prev[0] - next[0]);
    var greatest = x > y ? x : y;
    
    var speedModifier = 0.1;// control the speed here 

    var speed = Math.ceil(greatest/speedModifier);
    return speed;

}
.circle {
  width: 35px;
  height: 35px;
  border-radius: 35px;
  background-color: #ffffff;
  border: 3px solid #000;
  margin: 20px;
  position: absolute;
}

@keyframes Animation {
  0% {
    transform: scale(1);
  }
  50% {
    transform: scale(.8);
  }
  100% {
    transform: scale(1);
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p id="clicks"></p>

  • Related