3

I'm loading a front-end site from Wordpress using a HTML 5 Blank Child Theme. I have a logo effect using particle slider for when I have a screen size of >960px; for screen sizes <960px I have a flat logo image. It all works fine on both Firefox and Google Chrome but when I re-size between logos on Safari the page has to be refreshed manually (i.e. by pressing cmd+r) before the PS effect shows again. The code was sourced from an original question I posted here - Original Stack Q&A

Here's the javascript code I'm now using -

particle-slider.php

<?php /* Template Name: particle-slider */ ?>
<!-- particle-slider template -->

    <div id="particle-slider">
        <div class="slides">
            <div class="slide" data-src="<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logohight.png"></div>
        </div>
        <canvas class="draw" style="width: 100%; height: 100%;"></canvas>
     </div>
     <script type="text/javascript">
        var ps = new ParticleSlider({ 'width':'1400', 'height': '600' });

        // patch nextFrame to track failure/success
        var nextFrameCalled = false;
        ps.oldNextFrame = ps.nextFrame;
        ps.nextFrame = function () {
            try {
                ps.oldNextFrame.apply(this, arguments);
                nextFrameCalled = true;
            } catch (e) {
                console.log(e);
                nextFrameCalled = false;
            }
        };

        var addEvent = function (object, type, callback) {
            if (object.addEventListener) {
                object.addEventListener(type, callback, false);
            } else if (object.attachEvent) {
                object.attachEvent("on" + type, callback);
            } else {
                object["on" + type] = callback;
            }
        };
        var oldWidth = window.innerWidth;
        addEvent(window, 'resize', function () {
            var newWidth = window.innerWidth;
            if (newWidth >= 960 && oldWidth < 960) {
                console.log("Restarting particle slider " + newWidth);
                ps.resize();
                if (!nextFrameCalled)
                    ps.nextFrame();  // force restart animation
                else {
                    // ensure that nextFrameCalled is not still true from previous cycle
                    nextFrameCalled = false;
                    setTimeout(function () {
                        if (!nextFrameCalled)
                            ps.nextFrame();  // force restart animation
                    }, 100);
                }
            }
            oldWidth = newWidth;
        });
    </script>
  <div id="logo"> <img src="<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logo.png"> </div>

  <!-- particle-slider template -->

I need the same effect as is seen on this site here - where the logo switches from particle to static as the page is re-sized. The particle logo re-appears perfectly.

All other relevant code is linked to the original question as nothing has changed. I'm not seeing anything in the console to suggest why it's not working.

Mike.Whitehead
  • 798
  • 18
  • 52

2 Answers2

2

The resize event can fire multiple times, and within that event anything you put in a setTimeout will get called after the current code block has executed. It's hard to say for sure without picking apart ParticleSlider, but I think the mix of global variables (nextFrameCalled, oldWidth) and callbacks firing out of your expected order is the cause.

I think the intention is to debounce the forced restart - you want to call ParticleSlider.nextFrame() but if it's already been called you want to wait 100ms first.

Looking at the answer you've adapted for this question that appears to be a workaround for the canvas element not being visible on requestAnimationFrame - that might still not be available after 100ms or after the ParticleSlider.nextFrame() has been called multiple times in an attempt to get it to fire.

From your original question and selected answer I think you need to ParticleSlider.init() to reset the component, but the flashing you're seeing is due to the fact that it takes a while to run every time it's called. ParticleSlider.nextFrame() doesn't take as long (and uses requestAnimationFrame to avoid jank) but doesn't create the canvas on resize in Safari.

So, to fix:

  1. Use ParticleSlider.init()
  2. Debounce the resize event so you're not firing it lots of times
  3. Fire it once a short delay after the user has stopped firing resize events.

Code will be something like:

var timeout = null;
window.addEventListener('resize', function() {
    // Clear any existing debounced re-init
    clearTimeout(timeout);

    // Set up a re-init to fire in 1/2 a secound
    timeout = setTimeout(function() {
        ps.init();
    }, 500);
});

You'll still see the flash and the delay as the component re-initialises, but only once.

I'd add that ParticleSlider has been deprecated by the authors and replaced with NextParticle - probably to fix these kinds of issues (in fact it has specific features to handle resizing). As it is a paid for component I'd suggest asking them for the help with this, as you should get your money's worth (or switch to an open source component where you can fix these bugs yourself).

Keith
  • 150,284
  • 78
  • 298
  • 434
  • Thanks for this - so I slot this code into my selected answer? Am I replacing some existing code? I'm not that well versed with js so apologies if i sound a little naive. I actually moved away from my selected answer because the image kept flashing erratically and I went for the one below - but, as I've said it doesn't want to work in Safari. If I can fix it using this code I will re-implement it. – Mike.Whitehead Dec 11 '17 at 10:26
  • This site http://teamgeek.co.za/ uses the same particle design and with the same re-size event (particle to static logo for mobile/tablets) and it re-sizes perfectly. I need to be able to re-create this effect. – Mike.Whitehead Dec 11 '17 at 10:55
  • @Mike.Whitehead not really, it's more of a replacement for most of it. I haven't bothered with the IE8 support implemented in your original answer. That teamgeek site is still pretty janky (even on my fairly decent dev machine), so if that's your ideal you may need to account for the stutter and dropped frames. Their implementation doesn't look anything like yours - in particular they call `ParticleSlider.resize()`, which in turn calls `init` - like your originally selected answer on the previous question, rather than the alternate answer you've reproduced here. – Keith Dec 11 '17 at 11:07
  • @Mike.Whitehead `ParticleSlider` is paid for, which means you should get some dedicated support from the people that wrote it (if you don't get that then don't use it). That may be easier than trying to reverse engineer teamgeek's Angular implementation. – Keith Dec 11 '17 at 11:08
  • I've tried your code again and it doesn't work in this instance. – Mike.Whitehead Dec 12 '17 at 10:10
  • The same - the logo won't re-appear after resizing unless you refresh the page manually. I've made contact with nextParticle, hopefully they can shed some light on things. Quite frustrating, I feel so close on both answers from the original bounty question. I know the client will notice it doesn't work on Safari so I have to fix it. – Mike.Whitehead Dec 12 '17 at 22:48
  • Think I've fixed it. I'm going to check it again in the morning and post the answer up on here afterwards. – Mike.Whitehead Dec 13 '17 at 00:38
1

So, I've finally figured this out by retracing my steps using the Q&A from before. Previously there seemed to be an issue with some of the sample links but one appears to work now - example.

I went into the page inspector and noticed a few differences between the code firing this example and the one in the actual answer that was causing the logo to flicker like a light bulb. This is the code I have now put into the wordpress site -

<script type="text/javascript">
        //wait until the DOM is ready to be queried
        (function() {//document.addEventListener('DOMContentLoaded', function() { //DOM-ready callback
            var ps, timeout;
            var img1 = new Image();
            img1.src = '<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logohight.png';//havoc_logo_e6os2n.png';
            var imgs = [ img1 ];
            handlePS();
            window.addEventListener('resize', function() {
                //https://davidwalsh.name/javascript-debounce-function
                if (timeout) { //check if the timer has been set
                    clearTimeout(timeout); //clear the timer
                }
                //set a timer
                timeout = setTimeout(handlePS, 250);
            });

            function handlePS() {
                if (document.body.clientWidth >= 960) {
                    //check if ps is assigned as an instance of the ParticleSlider 
                    if (ps != undefined && typeof ps !== null) {
                        ps.init(); //refresh the particle slider since it exists
                        console.log('called init on ps');
                    } else {
                            if (window.location.search.indexOf('d=1') > -1) {
                                    debugger;
                            }
                        //otherwise create a new instance of the particle slider
                        ps = new ParticleSlider({
                            width: 1400, 
                            height: 600,
                            imgs: imgs
                        });
                    }
                }
                else {
                    //when the flat logo is displayed, get rid of the particle slider instance
                 //   delete ps;
                    ps = null;
                }
            }
        })();
    </script>

It now works fine across all the main browsers - Chrome/Safari/Firefox. It still feels a bit clunky as it pushes the rest of the page down whilst it is re-sizing and it takes probably a few seconds more than I'd like - not sure if there's a timer option to speed the reanimation up? Otherwise, everything is working fine.

Mike.Whitehead
  • 798
  • 18
  • 52