javascript - 基于HasClass的jQuery Canvas暂停和启动监听器

标签 javascript jquery html canvas

我在设置一个监听器时遇到问题,该监听器将基于 HasClass 暂停和启动 Canvas 动画。基本上我希望动画在 <a href="#"> 时暂停。有一定的类(Class)。使用 jQuery,我知道如何添加和删除,但不会将它们全部捆绑在一起,因此它们可以很好地协同工作。这有点超出我的舒适区,感谢您的帮助。

下面是我的简单 HTML 代码:

<a id="eY" href="#" class="paused">
    <span class="pause">Pause</span>
    <span class="resume">Resume</span>
</a>
<canvas id="world"> </canvas>

下面是我的 JavaScript:

jQuery(function($) {

    !+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!+-+-+!
function(d, w){
    var FPS = 30;
    var F = 300;
    var N = 3;
    var VERTEX_MAX = 10;
    var TRAIL_QUALITY = 4000;
    var mu = 0.5;
    var bmRandom = function(mu, sigma){
        var x, y, r, tmp=null, tmp2;
        return function(){
            if(tmp !== null){
                tmp2 = tmp;
                tmp = null;
                return y*tmp2+mu;
            }
            do{
                x = Math.random()*2-1;
                y = Math.random()*2-1;
                r = x*x+y*y;
            }while(r>=1);
            tmp = sigma*Math.sqrt(-2*Math.log(r)/r);
            return x*tmp+mu;
        };
    };
    pointCopy = function(src, dst){
        dst.x = src.x;
        dst.y = src.y;
        dst.z = src.z;
        return dst;
    };
    Trail = function(pos, t, color_f){
        this.pos={x:0,y:0,z:0};
        this.start={x:0,y:0,z:0};
        this.goal={x:0,y:0,z:0};
        this.anchor_1={x:0,y:0,z:0};
        this.anchor_2={x:0,y:0,z:0};
        this.start_time = 0;
        this.take_time = 1;
        this.vertexes = [];
        this.anchors_1 = [];
        this.anchors_2 = [];
        this.color_f = color_f;
        pointCopy(pos, this.pos);
        pointCopy(pos, this.start);
        pointCopy(pos, this.goal);
        this.setNextGoal(t);
    };
    Trail.prototype.setNextGoal = function(t, target){
        pointCopy(this.goal, this.start);
        this.anchor_1.x = this.start.x+(this.start.x-this.anchor_2.x)*mu;
        this.anchor_1.y = this.start.y+(this.start.y-this.anchor_2.y)*mu;
        this.anchor_1.z = this.start.z+(this.start.z-this.anchor_2.z)*mu;
        if(target){
            this.anchor_2.x = (this.anchor_1.x+target.x)/2+myrand();
            this.anchor_2.y = (this.anchor_1.y+target.y)/2+myrand();
            this.anchor_2.z = (this.anchor_1.z+target.z)/2+myrand();
            this.goal.x = target.x;
            this.goal.y = target.y;
            this.goal.z = target.z;
        }else{
            this.anchor_2.x = this.anchor_1.x+myrand();
            this.anchor_2.y = this.anchor_1.y+myrand();
            this.anchor_2.z = this.anchor_1.z+myrand();
            this.goal.x = this.anchor_2.x+myrand();
            this.goal.y = this.anchor_2.y+myrand();
            this.goal.z = this.anchor_2.z+myrand();
        }
        this.start_time = t;
        this.take_time = 200+Math.random()*200;
        this.vertexes.push(pointCopy(this.start, {x:0,y:0,z:0}));
        this.anchors_1.push(pointCopy(this.anchor_1, {x:0,y:0,z:0}));
        this.anchors_2.push(pointCopy(this.anchor_2, {x:0,y:0,z:0}));
        if(this.vertexes.length > VERTEX_MAX){
            this.vertexes.splice(0,this.vertexes.length-VERTEX_MAX);
            this.anchors_1.splice(0,this.anchors_1.length-VERTEX_MAX);
            this.anchors_2.splice(0,this.anchors_2.length-VERTEX_MAX);
        }
    };
    Trail.prototype.update = function(t, target){
        bezier3(
            t-this.start_time,
            this.start,
            this.anchor_1,
            this.anchor_2,
            this.goal,
            this.take_time,
            this.pos
            );
        if(t-this.start_time > this.take_time){
            this.setNextGoal(this.start_time+this.take_time, target);
            this.update(t, target);
        }
    };
    Trail.prototype.draw = function(ctx, camera, t){
        var i, dz, dt, ddt, rt, a, v={x:0, y:0, z:0};
        var ps = {x:0, y:0};
        ctx.beginPath();
        if(perspective(this.vertexes[0], camera, ps)){
            ctx.moveTo(ps.x, ps.y);
        }
        var x0 = ps.x;
        rt = (t-this.start_time)/this.take_time;
        for(i=1; i<this.vertexes.length; i++){
            ddt = 0.01;
            for(dt=0; dt<1; dt+=ddt){
                bezier3(dt,
                        this.vertexes[i-1],
                        this.anchors_1[i-1],
                        this.anchors_2[i-1],
                        this.vertexes[i],
                        1,
                        v);
                if(perspective(v, camera, ps)){
                    dz = v.z-camera.z;
                    a = 1-(this.vertexes.length-i+1-dt+rt)/VERTEX_MAX;
                    this.color_f(ctx, a, dz);
                    ctx.lineTo(ps.x, ps.y);
                    ctx.stroke();
                    ctx.beginPath();
                    ctx.moveTo(ps.x, ps.y);
                    ddt = dz/TRAIL_QUALITY+0.01;
                }
            }
        }
        ddt = 0.01;
        for(dt=0; dt<rt; dt+=ddt){
            bezier3(dt,
                    this.start,
                    this.anchor_1,
                    this.anchor_2,
                    this.goal,
                    1,
                    v);
            if(perspective(v, camera, ps)){
                dz = v.z-camera.z;
                a = 1-(1-dt+rt)/VERTEX_MAX;
                this.color_f(ctx, a, dz);
                ctx.lineTo(ps.x, ps.y);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(ps.x, ps.y);
                ddt = dz/TRAIL_QUALITY+0.01;
            }
        }
        if(perspective(this.pos, camera, ps)){
            dz = this.pos.z-camera.z;
            a = 1-1/VERTEX_MAX;
            this.color_f(ctx, a, dz);
            ctx.lineTo(ps.x, ps.y);
            ctx.stroke();
        }
    };
    bezier3 = function(t, a, b, c, d, e, dst){
        t /= e;
        dst.x =
            a.x*(1-t)*(1-t)*(1-t)+
            b.x*3*t*(1-t)*(1-t)+
            c.x*3*t*t*(1-t)+
            d.x*t*t*t;
        dst.y =
            a.y*(1-t)*(1-t)*(1-t)+
            b.y*3*t*(1-t)*(1-t)+
            c.y*3*t*t*(1-t)+
            d.y*t*t*t;
        dst.z =
            a.z*(1-t)*(1-t)*(1-t)+
            b.z*3*t*(1-t)*(1-t)+
            c.z*3*t*t*(1-t)+
            d.z*t*t*t;
    };
    perspective = function(point, camera, dst){
        var dx = point.x-camera.x;
        var dy = point.y-camera.y;
        var dz = point.z-camera.z;
        if(dz > 0){
            dst.x = F*dx/dz;
            dst.y = F*dy/dz;
            return true;
        }
        return false;
    };
    updateScene = function(ctx){
        var i, goal;
        time_now = new Date().getTime();
        var time_d = time_now-time_pre;
        trails[0].update(time_now);
        for(i=1; i<trails.length; i++){
            trails[i].update(time_now, trails[i-1].pos);
        }
        camera.x += (trails[0].pos.x-camera.x)*0.0005*time_d;
        camera.y += (trails[0].pos.y-camera.y)*0.0005*time_d;
        camera.z += (trails[0].pos.z-camera.z-100)*0.0005*time_d;
        time_pre = time_now;
    };
    drawScene = function(ctx){
        var i;
        ctx.clearRect(-canvas.width/2, -canvas.height/2, canvas.width, canvas.height);
        for(i=0; i<trails.length; i++){
            trails[i].draw(ctx, camera, time_now);
        }
    };
    var myrand = bmRandom(0,20);
    var canvas = d.getElementById("world");
    var ctx = canvas.getContext("2d");
    var trails = [];
    var i;
    var time_now = new Date().getTime();
    var time_pre = time_now;
    var camera = {x:0, y:0, z:-200};
    for(i=0; i<N; i++){
        trails.push(new Trail({x:myrand(), y:myrand(), z:myrand()},
                              time_now,
                              function(a,z){return "#FFFFFF";}));
    }
    for(i=0; i<N; i++){
        switch(i%3){
            case 0:
                trails[i].color_f=function(ctx, a, dz){
                    var b = dz<10?0:a*F/dz;
                    b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
                    ctx.strokeStyle = "rgba(230,230,230,"+b+")";
                    ctx.lineWidth = F/dz;
                    ctx.lineCap = b>0.8?"round":"butt";
                };
                break;
            case 1:
                trails[i].color_f=function(ctx, a, dz){
                    var b = dz<10?0:a*F/dz;
                    b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
                    ctx.strokeStyle = "rgba(230, 230,230,"+b+")";
                    ctx.lineWidth = F/dz;
                    ctx.lineCap = b>0.8?"round":"butt";
                };
                break;
            default:
                trails[i].color_f=function(ctx, a, dz){
                    var b = dz<10?0:a*F/dz;
                    b = (b>1?1:b)*(dz<30?(dz-10)/20:1);
                    ctx.strokeStyle = "rgba(132,232,251,"+b+")";
                    ctx.lineWidth = F/dz;
                    ctx.lineCap = b>0.8?"round":"butt";
                };
                break;
        }
    }
    var loop = function(){
        canvas.width = w.innerWidth;
        canvas.height = w.innerHeight;
        ctx.translate(canvas.width/2, canvas.height/2);
        updateScene();
        drawScene(ctx);
        w.requestAnimationFrame(loop);
    }
    loop();
    }(document, window);

    $("#eY").click(function(){
        $("#eY").toggleClass("start");
    });    
});

在这里你可以看到我的JsFiddle to make things easier 。我考虑过的另一个解决方案是使用 CSS 来隐藏 Canvas ,但我说的使用 display:none; 是对的吗?在 Canvas 上不会停止计算,这会有效地给浏览器带来负载?

最佳答案

隐藏 Canvas 只会隐藏元素本身,但不会阻止循环运行。您需要一些东西来告诉动画循环从其内部停止。例如,您可以使用 bool 标志。

示例:

var isRunning = true;                  // this will keep animation running or stop it
var loop = function(){
    canvas.width = w.innerWidth;
    canvas.height = w.innerHeight;
    ctx.translate(canvas.width/2, canvas.height/2);
    updateScene();
    drawScene(ctx);
    if (isRunning) w.requestAnimationFrame(loop);  // check if we're running...
}
loop();

// helper function to restart the loop when toggled from not running, to running    
function toggle() {
    isRunning = !isRunning;
    if (isRunning) loop();  // if new status is running, start loop
};

// move this inside the animation scope so we have access to the loop etc.
$("#eY").click(function(){
    $("#eY").toggleClass("start");
    toggle();                      // also call this
});    

<强> Updated fiddle

可能还有其他问题,我只解决了这个问题。如果应该有的话,就提出新问题。

题外话:很酷的动画,让我想起了 AE/Combustion 中 TrapCode 的 Strokes。

关于javascript - 基于HasClass的jQuery Canvas暂停和启动监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28998999/

相关文章:

ajax - jQuery 在submitHandler 中使用AJAX 进行验证,第二次单击时提交?

jquery - 使用 JavaScript 为 iPad 插入 HTML5 视频

javascript - 针对区域设置代码的驼峰式 ESLint 警告

javascript - 取消绑定(bind)内联 onClick 在 jQuery 中不起作用?

javascript - 连接两个 AJAX 请求返回到 1 个数组

javascript - 通过标记或 JS 强制下载

html - 图像上的模糊部分、实心边缘、响应式图像

html - 新手 HTML5 和 CSS3 问题与定位一些图标

javascript - 仅获取 JavaScript 对象数组中的特定值

javascript - eval_in_page javascript 执行在 firefox 中有效,但在 phantomjs 中无效