animating many elements - pause animation on hover

Hi there,
I haven’t been here since a looong time ! Glad to see it’s still a vibrant community, congrats !
For a project i’m working on, i’m trying to build a filterable system of randomly moving div. I must say that my javascript skills are quite basic, i mostly use common jQuery stuff.
Anyway, I managed to build up something using jQuery and the animate function but it seems quite heavy on CPU and memory consumption over the time : http://www.artefakt.be/dev/RandomDivMove_update.html

As i was looking for a lighter approach, i found this post on kirupa that correspond to what i did (https://www.kirupa.com/html5/animating_many_elements_using_transitions.htm ).
However, i can’t find a way to pause/stop the animation when hovering or clicking an element (as in my first example) (I’ve tried adding/removing a class to cancel the transition on the transform but it’s not working properly).
Is there an easy (?) way to achieve this ?

It has been a long time indeed! The forums have a banner above your post that said it was 11 years ago when you last posted :stuck_out_tongue:

The CSS approach you linked to is tricky, for there isn’t a great way to stop a transition mid-way as you have already found out. There are some hacky solutions to pick on, but I wouldn’t recommend them.

The best solution here would be to stick with a pure JS solution that doesn’t use jQuery. Just requestAnimationFrame. I could have sworn I had a tutorial around how to animate many elements in the DOM using JS, but I seem to never have created it in a way that doesn’t use the native animate method: https://www.kirupa.com/html5/animating_multiple_elements_animate_method.htm

With the holidays, I may not be able to get to this until next week. One approach you can try would be to modify the Falling Snow Effect a bit to have the elements move between random points instead: https://www.kirupa.com/html5/the_falling_snow_effect.htm

Does this help?

Cheers,
Kirupa

Wow, 11 years… That dates me,I guess :slight_smile:
Thank you Kirupa for the quick answer, i’ll look into this.
In the meantime, i followed the tutorial and replace my jQuery code (http://www.artefakt.be/dev/RandomDivMove_kirupa.html), the animation is much smoother indeed.
With this code, wouldn’t it be possible to use keyframes animation instead of transitions ?

i’m also looking into your https://www.kirupa.com/html5/animating_multiple_elements_animate_method.htm tutorial, it’s also close to what i need but once it loops, the elements are jumping to another position (even i change the animation direction to alternate).

I had an idea, and found a sort of hack. Instead of trying to pause the transition, i’m adding a class with a very long transition time on hover, not very clean but that does the trick for the moment.

Can you share your example of that working? That’s the first thing I tried, but I was unable to make it work :slight_smile:

http://www.artefakt.be/dev/RandomDivMove_shadow.html

1 Like

That is really nice! I do think the proper approach is to have the elements move programmatically. I will do my best to tackle that next week.

1 Like

Thank you !

Ubik - here is my attempt at this:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Randomly Moving Elements DOM</title>

  <style>
    .container {
      width: 600px;
      height: 500px;
      background-color: #EEE;
      position: relative;
      overflow: hidden;
    }

    .circle {
      position: absolute;
    }

    .circleChild {
      width: 50px;
      height: 50px;
      background-color: orange;
      opacity: .5;
      border-radius: 50%;
      transition: all .2s cubic-bezier(17, .67, .65, 1.31);
    }

    .circleChild:hover {
      background-color: #333;
      cursor: pointer;
      transform: scale3d(1.2, 1.2, 1);
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
    <div class="circle">
      <div class="circleChild"></div>
    </div>
  </div>

  <script>
    var circles = document.querySelectorAll(".circle");
    var circleObjects = [];

    var containerWidth = 600;
    var containerHeight = 500;

    class Circle {
      constructor(xPos, yPos, el) {
        this.xPos = xPos;
        this.yPos = yPos;
        this.speed = Math.floor(100 + Math.random() * 100);
        this.el = el;

        this.incX = 0;
        this.incY = 0;

        this.signal = 1;

        this.setNewPosition();
      }

      setNewPosition() {
        this.newX = -100 + Math.floor(Math.random() * (containerWidth + 100));
        this.newY = -100 + Math.floor(Math.random() * (containerHeight + 100));

        var diffX = this.xPos - this.newX;
        var diffY = this.yPos - this.newY;

        this.incX = diffX / this.speed;
        this.incY = diffY / this.speed;
      }

      stopMovement() {
        this.signal = 0;
      }

      resumeMovement() {
        this.signal = 1;
      }

      updatePosition() {
        this.xPos -= (this.incX * this.signal);
        this.yPos -= (this.incY * this.signal);

        this.el.style.transform = "translate3d(" + this.xPos + "px, " + this.yPos + "px, 0)";
        // update position for the next draw
        if (Math.round(this.xPos) == Math.round(this.newX)) {
          this.setNewPosition();
        }
      }
    }

    function update() {
      for (var i = 0; i < circles.length; i++) {
        var circle = circles[i];
        var circleObject = circle.associatedObject;
        circleObject.updatePosition();
      }

      requestAnimationFrame(update);
    }

    function stopMovement(e) {
      var circle = e.currentTarget;
      circle.associatedObject.stopMovement();
    }

    function resumeMovement(e) {
      var circle = e.currentTarget;
      circle.associatedObject.resumeMovement();
    }

    function setupCircles() {
      for (var i = 0; i < circles.length; i++) {
        var circle = circles[i];
        circle.addEventListener("mouseenter", stopMovement, false);
        circle.addEventListener("mouseleave", resumeMovement, false);

        var x = -100 + Math.floor(Math.random() * (containerWidth + 100));
        var y = -100 + Math.floor(Math.random() * (containerHeight + 100));

        var circleObject = new Circle(x, y, circle);
        circle.associatedObject = circleObject;
      }
      update();
    }
    setupCircles();


  </script>
</body>

</html>

There is some additional cleanup that you can do to make the naming of variables and functions more clear. I am also not happy with having an eventlistener for each circle as opposed to following the advice in Handling Events for Multiple Elements. I will try to revisit some of this tomorrow :tractor:

Let me know if this helps!

Cheers,
Kirupa

Thank you very much Kirupa, this certainly helps a lot !
I managed to add random rotation but I’m still trying to understand how it works and how i can tweak it to my needs (stop all movement or slow down elements on hovering one element, managing click events)

I’ve made some progress and managed to get close to what i’m trying to achieve using jquery and css classes in addition. However i’m still facing an unwanted behavior when i’m adding a transition duration to .circle (to add smoothness to the movement and transition on hover). Sometimes, it’s not constant, i cannot hover or click elements except for one or two. I’m not sure that is very clear, you can see it in action here : http://www.artefakt.be/dev/Random_div_click.html

For the hover transition, you need to be careful to not set any properties that are already being modified by JavaScript. One way I tried to avoid that is by wrapping my circle elements inside a parent element. For any hover related CSS changes, I only set (in my case) a transform on the parent circle element. The JavaScript affects the .circle element itself, so there is no conflict there.

Indeed, when adding a transition on .circle, the element had to finish the transition to be able to hover it. I’ve reduced the transition time to a short value to avoid this and still be able to transition the elements when clicking on it. It seems to work so far although it’s quite heavy on the cpu… (safari and chrome seems to deal with it better than firefox tough) : http://www.artefakt.be/dev/Random_div_click_filter.html