阻止requestAnimationFrame一直运行

dam*_*zzi 1 javascript css jquery html5-canvas requestanimationframe

我想知道如何只在真正需要时调用该animate函数requestAnimationFrame.目前,我animate一直在调用产生开销的东西.

我已经尝试在我的animate函数内部进行比较targetRadius和初始化radius并在它们相同时返回false.不幸的是,这根本不起作用.

有人可以解释我如何解决这个问题吗?

的jsfiddle

HTML:

  <canvas id="ddayCanvas" width="288" height="288" data-image="http://www.topdesignmag.com/wp-content/uploads/2011/07/64.png">
    <div>
        <div class="product-image"></div>
        <div class="product-box">...</div>
        <a href="#" class="overlay">...</a>
    </div>    
  </canvas>
Run Code Online (Sandbox Code Playgroud)

JS:

// Options
var maxImageWidth = 250,
    maxImageHeight = 196;

var canvas = $('#ddayCanvas'),
    canvasWidth = canvas.width(),
    canvasHeight = canvas.height(),
    sectorColor = $('.product-box').css('background-color'),
    context = canvas[0].getContext('2d'),
    imageSrc = canvas.data('image'),
    imageObj = new Image(),
    imageWidth, imageHeight,
    mouseover = false;

    imageObj.onload = function() {
        imageWidth = this.width;
        imageHeight = this.height;

        if (imageWidth > maxImageWidth){
            imageHeight = imageHeight - (imageWidth - maxImageWidth);
            imageWidth = maxImageWidth;
        }

        if (imageHeight > maxImageHeight) {
            imageWidth = imageWidth - (imageHeight - maxImageHeight);
            imageHeight = maxImageHeight;
        }

        drawDday(90); 
    };

    imageObj.src = imageSrc;  

function drawDday (radius) {
    context.clearRect(0, 0, canvasWidth, canvasHeight);
    context.drawImage(imageObj, Math.ceil((canvasWidth - imageWidth) / 2), Math.ceil((canvasHeight - imageHeight) / 2), imageWidth, imageHeight);
    context.fillStyle = sectorColor;
    context.beginPath();
    context.rect(0, 0, canvasWidth, canvasHeight);
    context.arc(canvasWidth/2, canvasHeight/2, radius, 0, Math.PI*2, true);
    context.closePath();
    context.fill();

    // Check out the console
    console.log('test');
}


var radius = baseRadius = 90,
    targetRadius = 110,
    ease = 50,
    speed = 2;

function animate(){
    if(mouseover){
        radius += ((targetRadius-radius)/ease)*speed;
    } else {
        radius -= ((radius-baseRadius)/ease)*speed;
    }
    if(radius > targetRadius) radius = targetRadius;
    if(radius < baseRadius) radius = baseRadius;

    drawDday(radius);   
    requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

canvas.on('mouseover', function(e){
    mouseover = true;
}).on('mouseout', function(){
    mouseover = false;
});
Run Code Online (Sandbox Code Playgroud)

小智 5

您需要实现一个条件,以便您可以打破循环,例如(根据需要采用):

var isRunning = true;

function loop() {

    ... funky stuff here ...

    /// test condition before looping
    if (isRunning) requestAnimationFrame(loop);
}
Run Code Online (Sandbox Code Playgroud)

现在,当你设置isRunningfalse循环将打破.为方便起见,建议您使用方法来启动和停止循环:

function startLoop(state) {

    if (state && !isRunning) {
        isRunning = true;
        loop();             /// starts loop

    } else if (!state && isRunning) {
        isRunning = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

条件可以由你需要设置的任何东西来设置,例如在动画完成后的回调等等.重要的部分是条件标志可用于使用它的两个范围(即最常见的全局)范围).

更新:

在这种情况下更具体的是,您的条件(半径)将永远不会达到最终停止循环所需的条件.

您可以采取以下措施来解决此问题:

DEMO

var isPlaying = false;

function animate(){
    /**
     * To make sure you will reach the condition required you need
     * to either make sure you have a fall-out for the steps or the
     * step will become 0 not adding/subtracting anything so your
     * checks below won't trigger. Here we can use a simple max of
     * the step and a static value to make sure the value is always > 0
    */
    if(mouseover){
        radius += Math.max( ((targetRadius-radius)/ease)*speed, 0.5);
    } else {
        radius -= Math.max( ((radius-baseRadius)/ease)*speed,   0.5);
    }

    /**
     * Now the checks will trigger properly and we can use the
     * isPlaying flag to stop the loop when targets are reached.
    */
    if(radius >= targetRadius) {
        radius = targetRadius;
        isPlaying = false;              /// stop loop after this
    } else if (radius <= baseRadius) {
        radius = baseRadius;
        isPlaying = false;              /// stop loop after this
    }

    drawDday(radius);

    /// loop?
    if (isPlaying === true) requestAnimationFrame(animate);
}
Run Code Online (Sandbox Code Playgroud)

为了触发循环,我们使用一种方法来检查循环是否正在运行,如果不是,它将重置isPlaying标志并启动循环.我们这样做既里面mouseovermouseout:

canvas.on('mouseover', function(e){
    mouseover = true;
    startAnim();

}).on('mouseout', function(){
    mouseover = false;
    startAnim();
});
Run Code Online (Sandbox Code Playgroud)

该方法只是检查isPlaying,如果没有设置它将其设置为true并启动循环 - 这样循环只启动一次:

function startAnim() {
    if (!isPlaying) {
        isPlaying = true;
        requestAnimationFrame(animate);
    }
}
Run Code Online (Sandbox Code Playgroud)

在演示中,我添加了控制台日志记录,以显示循环何时运行以及何时命中目标.

希望这可以帮助.