阻止requestAnimationFrame始终运行 [英] Prevent requestAnimationFrame from running all the time
问题描述
我想知道如何只在真正需要时通过 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?
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屋!