JavaScript - page has to be refreshed to show part

2020-02-16 02:00发布

问题:

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 but when I re-size between logos the page has to be refreshed manually (i.e. by pressing cmd+r) before the PS effect shows again. How can I rectify this so the effect shows automatically after re-sizing?

Here's my code -

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' });
     </script>
  <div id="logo"> <img src="<?php echo home_url(); ?>/wp-content/uploads/2017/10/havoc_logo.png"> </div>

  <!-- particle-slider template -->

style.css

/* RWD for logo */

@media screen and (max-width: 960px) {


    #particle-slider {
        display: none;
    }   


}

@media screen and (min-width: 960px) and (max-width: 1300px) {

    #particle-slider canvas {

                    width: 70%;
                    height: 30%;
                    position: relative;
                    top: 50px;
                    padding-bottom: 50px;


    }
}

@media screen and (min-width: 960px) {

     #logo img {

        display: none;
    } 

}

ps.js

// ┌────────────────────────────────────────────────────────────────────┐ \\
// │ ParticleSlider                   |                     Version 0.9 │ \\
// ├────────────────────────────────────────────────────────────────────┤ \\
// │ Copyright © 2013 Tamino Martinius (http://zaku.eu)                 │ \\
// │ Copyright © 2013 Particleslider.com (http://particleslider.com)    │ \\
// ├────────────────────────────────────────────────────────────────────┤ \\
// │ Terms of usage: (http://particleslider.com/legal/license)            │ \\
// └────────────────────────────────────────────────────────────────────┘ \\
;
function ParticleSlider(a){var b=this;b.sliderId="particle-slider",b.color="#fff",b.hoverColor="#88f",b.width=0,b.height=20,b.ptlGap=0,b.ptlSize=1,b.slideDelay=10,b.arrowPadding=10,b.showArrowControls=!0,b.onNextSlide=null,b.onWidthChange=null,b.onHeightChange=null,b.onSizeChange=null,b.monochrome=!1,b.mouseForce=1e4,b.restless=!0,b.imgs=[];if(a){var c=["color","hoverColor","width","height","ptlGap","ptlSize","slideDelay","arrowPadding","sliderId","showArrowControls","onNextSlide","monochrome","mouseForce","restless","imgs","onSizeChange","onWidthChange","onHeightChange"];for(var d=0,e=c.length;d<e;d++)a[c[d]]&&(b[c[d]]=a[c[d]])}b.$container=b.$("#"+b.sliderId),b.$$children=b.$container.childNodes,b.$controlsContainer=b.$(".controls"),b.$$slides=b.$(".slide",b.$(".slides").childNodes,!0),b.$controlLeft=null,b.$controlRight=null,b.$canv=b.$(".draw"),b.$srcCanv=document.createElement("canvas"),b.$srcCanv.style.display="none",b.$container.appendChild(b.$srcCanv),b.$prevCanv=document.createElement("canvas"),b.$prevCanv.style.display="none",b.$container.appendChild(b.$prevCanv),b.$nextCanv=document.createElement("canvas"),b.$nextCanv.style.display="none",b.$container.appendChild(b.$nextCanv),b.$overlay=document.createElement("p"),b.$container.appendChild(b.$overlay),b.imgControlPrev=null,b.imgControlNext=null,b.$$slides.length<=1&&(b.showArrowControls=!1),b.$controlsContainer&&b.$controlsContainer.childNodes&&b.showArrowControls==!0?(b.$controlLeft=b.$(".left",b.$controlsContainer.childNodes),b.$controlRight=b.$(".right",b.$controlsContainer.childNodes),b.imgControlPrev=new Image,b.imgControlNext=new Image,b.imgControlPrev.onload=function(){b.$prevCanv.height=this.height,b.$prevCanv.width=this.width,b.loadingStep()},b.imgControlNext.onload=function(){b.$nextCanv.height=this.height,b.$nextCanv.width=this.width,b.loadingStep()},b.imgControlPrev.src=b.$controlLeft.getAttribute("data-src"),b.imgControlNext.src=b.$controlRight.getAttribute("data-src")):b.showArrowControls=!1,b.width<=0&&(b.width=b.$container.clientWidth),b.height<=0&&(b.height=b.$container.clientHeight),b.mouseDownRegion=0,b.colorArr=b.parseColor(b.color),b.hoverColorArr=b.parseColor(b.hoverColor),b.mx=-1,b.my=-1,b.swipeOffset=0,b.cw=b.getCw(),b.ch=b.getCh(),b.frame=0,b.nextSlideTimer=!1,b.currImg=0,b.lastImg=0,b.imagesLoaded=0,b.pxlBuffer={first:null},b.recycleBuffer={first:null},b.ctx=b.$canv.getContext("2d"),b.srcCtx=b.$srcCanv.getContext("2d"),b.prevCtx=b.$prevCanv.getContext("2d"),b.nextCtx=b.$nextCanv.getContext("2d"),b.$canv.width=b.cw,b.$canv.height=b.ch,b.shuffle=function(){var a,b;for(var c=0,d=this.length;c<d;c++)b=Math.floor(Math.random()*d),a=this[c],this[c]=this[b],this[b]=a},Array.prototype.shuffle=b.shuffle,b.$canv.onmouseout=function(){b.mx=-1,b.my=-1,b.mouseDownRegion=0},b.$canv.onmousemove=function(a){function c(a){var c=0,d=0,e=typeof a=="string"?b.$(a):a;if(e){c=e.offsetLeft,d=e.offsetTop;var f=document.getElementsByTagName("body")[0];while(e.offsetParent&&e!=f)c+=e.offsetParent.offsetLeft,d+=e.offsetParent.offsetTop,e=e.offsetParent}this.x=c,this.y=d}var d=new c(b.$container);b.mx=a.clientX-d.x+document.body.scrollLeft+document.documentElement.scrollLeft,b.my=a.clientY-d.y+document.body.scrollTop+document.documentElement.scrollTop},b.$canv.onmousedown=function(){if(b.imgs.length>1){var a=0;b.mx>=0&&b.mx<b.arrowPadding*2+b.$prevCanv.width?a=-1:b.mx>0&&b.mx>b.cw-(b.arrowPadding*2+b.$nextCanv.width)&&(a=1),b.mouseDownRegion=a}},b.$canv.onmouseup=function(){if(b.imgs.length>1){var a="";b.mx>=0&&b.mx<b.arrowPadding*2+b.$prevCanv.width?a=-1:b.mx>0&&b.mx>b.cw-(b.arrowPadding*2+b.$nextCanv.width)&&(a=1),a!=0&&b.mouseDownRegion!=0&&(a!=b.mouseDownRegion&&(a*=-1),b.nextSlideTimer&&clearTimeout(b.nextSlideTimer),b.nextSlide(a)),b.mouseDownRegion=0}};if(b.imgs.length==0)for(var d=0,e=b.$$slides.length;d<e;d++){var f=new Image;b.imgs.push(f),f.src=b.$$slides[d].getAttribute("data-src")}b.imgs.length>0&&(b.imgs[0].onload=function(){b.loadingStep()}),b.requestAnimationFrame(function(){b.nextFrame()})}var psParticle=function(a){this.ps=a,this.ttl=null,this.color=a.colorArr,this.next=null,this.prev=null,this.gravityX=0,this.gravityY=0,this.x=Math.random()*a.cw,this.y=Math.random()*a.ch,this.velocityX=Math.random()*10-5,this.velocityY=Math.random()*10-5};psParticle.prototype.move=function(){var a=this.ps,b=this;if(this.ttl!=null&&this.ttl--<=0)a.swapList(b,a.pxlBuffer,a.recycleBuffer),this.ttl=null;else{var c=this.gravityX+a.swipeOffset-this.x,d=this.gravityY-this.y,e=Math.sqrt(Math.pow(c,2)+Math.pow(d,2)),f=Math.atan2(d,c),g=e*.01;a.restless==!0?g+=Math.random()*.1-.05:g<.01&&(this.x=this.gravityX+.25,this.y=this.gravityY+.25);var h=0,i=0;if(a.mx>=0&&a.mouseForce){var j=this.x-a.mx,k=this.y-a.my;h=Math.min(a.mouseForce/(Math.pow(j,2)+Math.pow(k,2)),a.mouseForce),i=Math.atan2(k,j),typeof this.color=="function"&&(i+=Math.PI,h*=.001+Math.random()*.1-.05)}else h=0,i=0;this.velocityX+=g*Math.cos(f)+h*Math.cos(i),this.velocityY+=g*Math.sin(f)+h*Math.sin(i),this.velocityX*=.92,this.velocityY*=.92,this.x+=this.velocityX,this.y+=this.velocityY}},ParticleSlider.prototype.Particle=psParticle,ParticleSlider.prototype.swapList=function(a,b,c){var d=this;a==null?a=new d.Particle(d):b.first==a?a.next!=null?(a.next.prev=null,b.first=a.next):b.first=null:a.next==null?a.prev.next=null:(a.prev.next=a.next,a.next.prev=a.prev),c.first==null?(c.first=a,a.prev=null,a.next=null):(a.next=c.first,c.first.prev=a,c.first=a,a.prev=null)},ParticleSlider.prototype.parseColor=function(a){var b,a=a.replace(" ","");if(b=/^#([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})/.exec(a))b=[parseInt(b[1],16),parseInt(b[2],16),parseInt(b[3],16)];else if(b=/^#([\da-fA-F])([\da-fA-F])([\da-fA-F])/.exec(a))b=[parseInt(b[1],16)*17,parseInt(b[2],16)*17,parseInt(b[3],16)*17];else if(b=/^rgba\(([\d]+),([\d]+),([\d]+),([\d]+|[\d]*.[\d]+)\)/.exec(a))b=[+b[1],+b[2],+b[3],+b[4]];else if(b=/^rgb\(([\d]+),([\d]+),([\d]+)\)/.exec(a))b=[+b[1],+b[2],+b[3]];else return null;isNaN(b[3])&&(b[3]=1),b[3]*=255;return b},ParticleSlider.prototype.loadingStep=function(){var a=this;a.imagesLoaded++;if(a.imagesLoaded>=3||a.showArrowControls==!1)a.resize(),a.slideDelay>0&&(a.nextSlideTimer=setTimeout(function(){a.nextSlide()},1e3*a.slideDelay))},ParticleSlider.prototype.$=function(a,b,c){var d=this;if(a[0]=="."){var e=a.substr(1);b||(b=d.$$children);var f=[];for(var g=0,h=b.length;g<h;g++)b[g].className&&b[g].className==e&&f.push(b[g]);return f.length==0?null:f.length==1&&!c?f[0]:f}return document.getElementById(a.substr(1))},ParticleSlider.prototype.nextFrame=function(){var a=this;a.mouseDownRegion==1&&a.mx<a.cw/2||a.mouseDownRegion==-1&&a.mx>a.cw/2?a.swipeOffset=a.mx-a.cw/2:a.swipeOffset=0;var b=a.pxlBuffer.first,c=null;while(b!=null)c=b.next,b.move(),b=c;a.drawParticles();if(a.frame++%25==0&&(a.cw!=a.getCw()||a.ch!=a.getCh())){var d=a.getCh(),e=a.getCw();a.ch!=e&&typeof a.onWidthChange=="function"&&a.onWidthChange(a,e),a.ch!=d&&typeof a.onHeightChange=="function"&&a.onHeightChange(a,d),typeof a.onSizeChange=="function"&&a.onSizeChange(a,e,d),a.resize()}setTimeout(function(){a.requestAnimationFrame(function(){a.nextFrame()})},15)},ParticleSlider.prototype.nextSlide=function(a){var b=this;b.nextSlideTimer!=null&&b.imgs.length>1?(b.currImg=(b.currImg+b.imgs.length+(a?a:1))%b.imgs.length,b.resize(),b.slideDelay>0&&(b.nextSlideTimer=setTimeout(function(){b.nextSlide()},1e3*b.slideDelay))):b.slideDelay>0&&(b.nextSlideTimer=setTimeout(function(){b.nextSlide()},1e3*b.slideDelay)),typeof b.onNextSlide=="function"&&b.onNextSlide(b.currImg)},ParticleSlider.prototype.drawParticles=function(){var a=this,b=a.ctx.createImageData(a.cw,a.ch),c=b.data,d,e,f,g,h,i,j=a.pxlBuffer.first;while(j!=null){e=~~j.x,f=~~j.y;for(g=e;g<e+a.ptlSize&&g>=0&&g<a.cw;g++)for(h=f;h<f+a.ptlSize&&h>=0&&h<a.ch;h++)d=(h*b.width+g)*4,i=typeof j.color=="function"?j.color():j.color,c[d+0]=i[0],c[d+1]=i[1],c[d+2]=i[2],c[d+3]=i[3];j=j.next}b.data=c,a.ctx.putImageData(b,0,0)},ParticleSlider.prototype.getPixelFromImageData=function(a,b,c){var d=this,e=[];for(var f=0;f<a.width;f+=d.ptlGap+1)for(var g=0;g<a.height;g+=d.ptlGap+1)i=(g*a.width+f)*4,a.data[i+3]>0&&e.push({x:b+f,y:c+g,color:d.monochrome==!0?[d.colorArr[0],d.colorArr[1],d.colorArr[2],d.colorArr[3]]:[a.data[i],a.data[i+1],a.data[i+2],a.data[i+3]]});return e},ParticleSlider.prototype.init=function(a){var b=this;if(b.imgs.length>0){b.$srcCanv.width=b.imgs[b.currImg].width,b.$srcCanv.height=b.imgs[b.currImg].height,b.srcCtx.clearRect(0,0,b.$srcCanv.width,b.$srcCanv.height),b.srcCtx.drawImage(b.imgs[b.currImg],0,0);var c=b.getPixelFromImageData(b.srcCtx.getImageData(0,0,b.$srcCanv.width,b.$srcCanv.height),~~(b.cw/2-b.$srcCanv.width/2),~~(b.ch/2-b.$srcCanv.height/2));if(b.showArrowControls==!0){b.prevCtx.clearRect(0,0,b.$prevCanv.width,b.$prevCanv.height),b.prevCtx.drawImage(b.imgControlPrev,0,0);var d=b.getPixelFromImageData(b.prevCtx.getImageData(0,0,b.$prevCanv.width,b.$prevCanv.height),b.arrowPadding,~~(b.ch/2-b.$prevCanv.height/2));for(var e=0,f=d.length;e<f;e++)d[e].color=function(){return b.mx>=0&&b.mx<b.arrowPadding*2+b.$prevCanv.width?b.hoverColorArr:b.colorArr},c.push(d[e]);b.nextCtx.clearRect(0,0,b.$nextCanv.width,b.$nextCanv.height),b.nextCtx.drawImage(b.imgControlNext,0,0);var g=b.getPixelFromImageData(b.nextCtx.getImageData(0,0,b.$nextCanv.width,b.$nextCanv.height),b.cw-b.arrowPadding-b.$nextCanv.width,~~(b.ch/2-b.$nextCanv.height/2));for(var e=0,f=g.length;e<f;e++)g[e].color=function(){return b.mx>0&&b.mx>b.cw-(b.arrowPadding*2+b.$nextCanv.width)?b.hoverColorArr:b.colorArr},c.push(g[e])}if(b.currImg!=b.lastImg||a==!0)c.shuffle(),b.lastImg=b.currImg;var h=b.pxlBuffer.first;for(var e=0,f=c.length;e<f;e++){var i=null;h!=null?(i=h,h=h.next):(b.swapList(b.recycleBuffer.first,b.recycleBuffer,b.pxlBuffer),i=b.pxlBuffer.first),i.gravityX=c[e].x,i.gravityY=c[e].y,i.color=c[e].color}while(h!=null)h.ttl=~~(Math.random()*10),h.gravityY=~~(b.ch*Math.random()),h.gravityX=~~(b.cw*Math.random()),h=h.next;b.$overlay.innerHTML=b.$$slides[b.currImg].innerHTML}},ParticleSlider.prototype.getCw=function(){var a=this;return Math.min(document.body.clientWidth,a.width,a.$container.clientWidth)},ParticleSlider.prototype.getCh=function(){var a=this;return Math.min(document.body.clientHeight,a.height,a.$container.clientHeight)},ParticleSlider.prototype.resize=function(){var a=this;a.cw=a.getCw(),a.ch=a.getCh(),a.$canv.width=a.cw,a.$canv.height=a.ch,a.init(!0)},ParticleSlider.prototype.setColor=function(a){var b=this;b.colorArr=b.parseColor(a)},ParticleSlider.prototype.setHoverColor=function(a){var b=this;b.hoverColorArr=b.parseColor(a)},ParticleSlider.prototype.requestAnimationFrame=function(a){var b=this,c=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){window.setTimeout(a,1e3/60)};c(a)}
;

回答1:

tl;dr

replace this code:

<script type="text/javascript">
    var ps = new ParticleSlider({ 'width':'1400', 'height': '600' });
</script>

with this code:

<script type="text/javascript">
//wait until the DOM is ready to be queried
document.addEventListener('DOMContentLoaded', function() { //DOM-ready callback
    var ps, timeout;
    handlePS();
    window.addEventListener('resize', 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 (window.ps && typeof ps !== null) {
                ps.init(); //refresh the particle slider since it exists
            } else {
                //otherwise create a new instance of the particle slider
                ps = new ParticleSlider({
                    'width': '1400', 
                    'height': '600'
                });
            }
        }
        else {
            //when the flat logo is displayed, get rid of the particle slider instance
            ps = null;
        }
    }
});
</script>

Explanation: Call init() on resize

One can add a callback for when the resize event occurs (as others have mentioned) and call the init() method depending on the current width of the window.

It might be advisable to move the code that creates the Particle Slider instance to a function, which checks if the width of the window is greater than or equal to 960 pixels (using .clientWidth of document.body) and if so, if the instance has been created or not using a variable ps declared outside the function. If the instance has been created, call the init method; Otherwise create the instance. But if the width is less than 960 pixels then set the variable ps to null.

var ps; //declare out here for use in multiple functions
function handlePS() {
    if (document.body.clientWidth > 960) {
        if (window.ps && typeof ps !== null) {
            ps.init();
        } else {
            ps = new ParticleSlider({'width': '1400', 'height': '600'});
        }
    }
    else {
            ps = null;
    }
}

Then that function can be called when the page loads as well as when the resize event occurs:

handlePS();
window.addEventListener('resize', handlePS);

See a demonstration in this sample page. There are a few other enhancements added:

  • it waits for the DOM to be ready by calling handlePS() and listening for the resize event after the DOMContentLoaded event has been fired by using document.addEventListener
  • it uses setTimeout for a debounce effect so that the init() method is called 250ms after the scroll event ends instead of continuously during a scroll event.

So the code with those enhancements looks like below:

//wait until the DOM is ready to be queried
document.addEventListener('DOMContentLoaded', function() { //DOM-ready callback
    var ps, timeout;
    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 (window.ps && typeof ps !== null) {
                ps.init(); //refresh the particle slider since it exists
            } else {
                //otherwise create a new instance of the particle slider
                ps = new ParticleSlider({
                    'width': '1400', 
                    'height': '600'
                });
            }
        }
        else {
            //when the flat logo is displayed, get rid of the particle slider instance
            ps = null;
        }
    }
});

And because you added the jquery tag, jQuery could be used to simplify things a bit:

instead of

window.addEventListener('resize', handlePS);

use:

$(window).on('resize, handlePS);

And replace document.body.clientWidth width $(document).width().

Update

I used the image from your comment in the updated sample page. I also pared down the code used on the Particle Slider demo page and added in that image on this demo page. It still suffers from flashing when there is a resize.



回答2:

Update (30 Oct 2017)

So the issue appeared to be the fact that since you hide the div that is used by ParticleSlider for drawing, it gets Canvas with size 0x0 and this leads to an exception somewhere inside drawParticles method which is called by nextFrame. Another important fact is that ParticleSlider is designed in such a way that after the first call initiated from constructor, nextFrame uses requestAnimationFrame to schedule itself. All other methods (such as nextSlide or resize) just change data but do not re-start animation sequence. Thus exception at the first call stops animation and to fix it, you need to call nextFrame explicitly.

So the basic idea is that you patch nextFrame to track failure/success and call it from resize handler if needed. Here is some code:

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;
});

You can see live demo at this plunker. Open demo in a separate window. Then you'll have 2 seconds to set initial size more or less than 960px so you can simulate any starting conditions. After 2 seconds timeout the main code starts.

Original answer

It looks like you lack a piece of code that would re-shuffle particles when window size is changed to >960px. I haven't tried it, but I expect that something like this should help you (if you use jQuery):

var ps = new ParticleSlider({ 'width': '1400', 'height': '600' });

var oldWidth = $(window).width();
$(window).resize(function () {
    var newWidth = $(window).width();
    if (newWidth >= 960 && oldWidth < 960)
        ps.resize(); // this should call init() which in turn should re-shuffle particles
    oldWidth = newWidth;
});

Obviously you can write an equivalent code without jQuery for example as suggested in this SO answer



回答3:

You can use the resize function of ParticleSlider in jquery smart resize. So you will have more control on the function.

var ps = new ParticleSlider({ 'width': '1400', 'height': '600' });
$(window).on("debouncedresize", function( event ) {
    ps.resize();
});


回答4:

The Problem is the following: The slider draws with js into the canvas, seems like the script is loaded once on page load... The slider shall be responsive as the athors say on their site, but in fact the slider is just resized and not replayed on window resize...

To me it seems like calling

ps.nextSlide(0);

on $(window).resize() could help. This reloads the current slide!

If this does not work too, try to reload the whole slider with the init() function or maybe the loadingStep() function! (The documentation is sadly not that clear to me at some points...)

i.e.:

$(window).resize(function(){
    ps.nextSlide(0);
});

You can see the functions availeble here:

http://particleslider.com/documentation/reference



回答5:

Your use case has two major issues:

  • When you init the Particles before the target is visible the image has an invalid size (0x0)
  • Once the Animation is running and you make the resolution smaller the animation keeps running in the background

I tried to handle both issues in the following script.

var ps = null

function init(){
  var isVisible = window.innerWidth >= 960;
  if (!ps && isVisible) {
    // create and init
    ps = new ParticleSlider({
      ptlGap: 1,
      ptlSize: 1,
      width: 1e9,
      height: 100,
    });

    ps.init(false);
  } else if (ps && !isVisible) {
    // stop and remove
    ps.requestAnimationFrame = function() {}; // Stop render loop
    ps = null;
  }
}

window.addEventListener('load', init, false)
window.onload = init;
window.addEventListener('resize', init, false);
window.onresize = init;
html, body {
  background-color: black;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  color: #fff;
  text-align: center;
}

.slides, & > .dg {
  display: none;
}

.low-res {
  display: none;
}

@media screen and (max-width: 959px) {
  .draw {
    display: none;
  }

  .low-res {
    display: inline;
    width: 50%;
  }
}
<html>
  <head>
    <meta name="viewport" content="width=device-width" />
    <title>ParticleSlider</title>
    <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/23500/ps-0.9.js"></script>
  </head>
  <body id="particle-slider">
    <div class="slides">
      <div id="first-slide" class="slide" data-src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGkAAAAgCAMAAAAmC6asAAAAMFBMVEX19vf19vft7u/19vfp6uv19vfx8vP19vf19vf19vf19vfm5+j19vcAAAD19vfl5udu+MchAAAADnRSTlOIVcIz10StZneZEewiAMEzGswAAAF/SURBVHja7ZXZbsQwCEXjneXa/P/fFntm0uRpVGkaqVX8YAW4cMCxkq1ftW7STbpJP1sJb0lFPkJiekuq4TMkfkti+gxpe0uivRmB9LQOlHraNixnYErPONAfcYZntYfv9aDtJTmUO5OCeukGR5paqZtbGaSVzYWIlZ9DI6vVpC6shJw5TzdlZk47qZpldAkteBVToxNJrLGqoil6MPE9A1bSNorUXPYWvbLUjbg37lwRNPYW6x6eJK4ilB2hVmChJw2nWx4He3Map1exMVFvQyMVN78rlexbY7Gk0tWUm7gsHUnikQ6dwzLRLM/tRKIlGMMFoijmpthqBocLFTLWO41GnhrFXZIGTiTz5pIyA9G4uqSeSV3W4bSsqvycg0x9RTpcKHaHHybNOZBXfPa41jNjLCeqjRopzgI4kXYcsDqVZWJaZwVWHpYBTOuoACCvEpjTC3DFd6/oVV9YmPw+CWsb+H1SxVWkkgkoV5B6ijasXnMjBPIf/u436e+TvgDCaqPX6lO5yQAAAABJRU5ErkJggg==">
      </div>
    </div>
    <canvas class="draw"></canvas>
    <img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/23500/codepen-white.png" class="low-res"/>
  </body>
</html>