Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem re-using a Class / Not understanding instantiation

Update - JSFiddle demo here: https://jsfiddle.net/vb2ptmuo/11/

I'm playing around with an interesting effect I came across: https://tympanus.net/codrops/2019/08/07/image-trail-effects/

To start, I have a div containing a bunch of img elements. It dumps them into an array and then creates a trail effect from those images which follows the mouse. You kick this all off via new ImageTrail(".content"). But what if I have more than one set of images and I want to re-trigger it again with those, instead? Example:

    <div class="content">
        <img src="1.jpg">
        <img src="2.jpg">
        <img src="3.jpg">
    </div>
    <div class="content-2">
        <img src="4.jpg">
        <img src="5.jpg">
        <img src="6.jpg">
    </div>

Doing a second new ImageTrail(".content-2") does not replace the first set of images with the second set, even though the code reads to me like it should. You still just see the first set of images in the trail.

I'm also slightly concerned with performance if I'm instantiating the ImageTrail class twice (if that's even a thing), but this is wholly secondary to my main issue.

I feel like there's a simple solution but I'm missing it. Scroll down to the bottom of the demo for the commented code "This doesn't work"

like image 996
daveycroqet Avatar asked Mar 20 '20 04:03

daveycroqet


2 Answers

The main cause is requestAnimationFrame as part of constructor and render method.

Across instances, for this use case, one instance should have the rendering control using requestAnimationFrame.

I did a trick here, for this use case.

Every time a new instance is created, it will cancel earlier instance's render request (done by requestAnimationFrame) by means of cancelAnimationFrame Even i cancelled the request done in render method too.

Check out this jsfiddle for modified code : https://jsfiddle.net/rahultarafdar/mfboqy9g/45/

like image 200
Rahul Tarafdar Avatar answered Nov 15 '22 19:11

Rahul Tarafdar


The Code that you posted has one major problem: it uses global variables to store state of the ImageTrail object. This is a pretty bad programming practice as it leads to unexpected behaviour and defeats the purpose of having a class in the first place.

The reason why only the first set of pictures is shown is because both instances of ImageTrail register a callback for the next animation frame with requestAnimationFrame. The callback (render) of the first instance is always called first, because it registered the listener first. This first render function updates the global mousePos variables. The second render function thinks the mouse has not moved, because lastMousePos and mousePos are the same.

Now to address your problem: first you should move all the state that is used by ImageTrail into the class itsef. That includes mousePos, cacheMousePos and lastMousePos. If you have done that successfully, you should get both imagesets diyplaying at the same time, if you have two instances. To activate/deactivate the rendering of ImageTrails, you could add an active attribute, which gets checked at every render call or you could implement methods that cancel/setup the animation frame for a specific instance. (For details how to use cancelAnimationFrame you could look into the answer from rahul or into the MDN)

like image 42
Garuno Avatar answered Nov 15 '22 18:11

Garuno