阻止requestAnimationFrame始终运行 [英] Prevent requestAnimationFrame from running all the time

查看:592
本文介绍了阻止requestAnimationFrame始终运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何只在真正需要时通过 requestAnimationFrame 调用 animate 目前 animate 一直被称​​为产生开销的猜测。

I'd like to know how to call the animate function through requestAnimationFrame only when it's realy needed. Currently the animate is called all the time what generates an overhead I guess.

我已经在我的 animate 函数比较 targetRadius 和初始 radius 他们是一样的。很遗憾,这根本不起作用。

I already tried inside my animate function to compare targetRadius and the inital radius and return false once they are the same. Unfortunately this doesn't work at all.

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

Can someone explain me how to solve that?

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>

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


推荐答案

您需要实施,所以你可以打破循环,例如(根据需要采用):

You need to implement a condition so you can break the loop, for example (adopt as needed):

var isRunning = true;

function loop() {

    ... funky stuff here ...

    /// test condition before looping
    if (isRunning) requestAnimationFrame(loop);
}

现在当您设置 isRunning false ,循环将中断。为方便起见,建议您有一个方法来启动和停止循环:

Now when you set isRunning to false the loop will break. For convenience it's recommended that you have a method to start and stop the loop:

function startLoop(state) {

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

    } else if (!state && isRunning) {
        isRunning = false;
    }
}

条件可以由任何你需要的例如在动画完成之后通过回调来设置。重要的是条件标志可用于使用它的两个范围(即,最通常在全局范围内)。

The condition can be set by anything you need it to be set by, for example on a callback after an animation has finished etc. The important part is that the condition flag is available to both scopes using it (ie. most commonly in the global scope).

UPDATE

在这种情况下更具体的是您的条件(半径)永远不会达到

More specific in this case is that your condition (radius) will never reach the condition required to eventually stop the loop.

您可以执行以下操作:

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

为了触发循环,我们使用一个方法来检查循环正在运行,如果不是,它将复位 isPlaying 标志并启动循环。我们在 mouseover mouseout 中执行此操作:

In order to trigger the loop we use a method that will check if the loop is running, if not it will reset the isPlaying flag and start the loop. We do this inside both mouseover and mouseout:

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

}).on('mouseout', function(){
    mouseover = false;
    startAnim();
});

方法只是检查 isPlaying 不设置它设置为true并启动循环 - 这样循环只启动一次:

The method is simply checking isPlaying and if not set it set it to true and starts the loop - this so that the loop is only started once:

function startAnim() {
    if (!isPlaying) {
        isPlaying = true;
        requestAnimationFrame(animate);
    }
}



在演示中,我添加了控制台日志记录,循环正在运行,当目标被击中。

In the demo I added console logging to show when the loop is running and when targets are hit.

希望这有助于。

这篇关于阻止requestAnimationFrame始终运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆