javascript - 对于多个 Canvas 对象使用一个还是多个 requestAnimationFrame 更好?

标签 javascript html canvas

我创建了一个小型 Canvas 程序,可以绘制立方体并让它们从墙壁上反射。我的问题是,对于像这样的面向对象的 Canvas 程序,每个新立方体都有自己的animationFrame 更好还是应该由单个“全局”animationFrame 处理?这是一个 fiddle example展示正在运行的程序。

下面是每个多维数据集对象具有的代码示例。

animation: function (animation_type, value_x, value_y) {
   data.animation = requestAnimationFrame(this.animation.bind(this, animation_type, value_x, value_y));
   draw.reflect(value_x, value_y);
}

可以使用YOUR-VARIABLE-NAME.method.animation('x', x-integer-value, y-integer-value)从新对象实例调用此方法

感谢您的宝贵时间。 :)

最佳答案

在多个元素上同时制作动画的代码,共享相同的 requestAnimationFrame、持续时间和 fps。

13/09/2016 - 添加了来自 gizma.com 的缓动公式;每个参数都可以获得单独的缓动公式。

24/09/2016 - 添加了 onCompleteFunction,删除了部分以找出原始值。现在该函数必须接收初始值。当用于动态创建菜单(循环)时,数组推送会出现问题

代码上的数组结构。 任何改进都是非常受欢迎的。

希望有帮助。

    var objects = []; 
    var object = [];
    var obj1 = [];
    var obj2 = [];
    var obj3 = [];
    var obj4 = []

//obj = element, param, unit, initialValue, targetValue, easing formula //
obj1.push(document.getElementById('obj1'), ['left','px', 0, 420, 1], ['top','px', 0 ,120, 6], ['width', '%', 80, 90, 4]);
obj2.push(document.getElementById('obj2'), ['top','px', 0, 420, 7], ['width','%', 80, 90, 2], ['height', 'px', 20,  900, 9]);
obj3.push(document.getElementById('obj3'), ['height','px', 0, 220, 9], ['top','px', 0, -80, 4]);
obj4.push(document.getElementById('obj4'), ['top','px', 20, 620, 1], ['width','px', 120, 380, 4]);

    objects.push(obj1, obj2, obj3, obj4);
/* Object array structure:
[ [ 0 - object, [0 - param, 1- paramUnit, 2- originalValue, 3 - targetValue, 4 - easeFormula ] ], [... [...] [...] ] ]
*/

    startAnimation(objects, 2, 60); //objectsArray, seconds, fps

 function startAnimation(objects, seconds, fps, onCompleteFunction) {
    var now;
    var fps = fps;
    var duration = seconds * 1000; //miliseconds
    var startTime = Date.now();
    var previous = startTime;

    var interval = 1000/fps;
    var stop = false;
    var delta;

    var frameCounter = 0;
    var elapsed = 0;
    var info = document.createElement('p');
    document.getElementById('info').appendChild(info);  

    animate(objects, now, startTime, previous, fps, interval, stop, delta, duration, elapsed, frameCounter, onCompleteFunction, info);
} 
function animate(objects, now, startTime, previous, fps, interval, stop, delta, duration, elapsed, frameCounter, onCompleteFunction, info) 
{
        if (stop) {
            return;         
        }  
        window.requestAnimationFrame( function() { animate(objects, now, startTime, previous, fps, interval, stop, delta, duration, elapsed, frameCounter, onCompleteFunction, info); }
        );      
        now = Date.now();
        delta = now - previous;
        if (delta > interval) {        
            /* Just `previous = now` is not enough.
            Lets say we set fps at 10 which means
            each frame must take 100ms
            Now frame executes in 16ms (60fps) so
            the loop iterates 7 times (16*7 = 112ms) until
            delta > interval === true
            Eventually this lowers down the FPS as
            112*10 = 1120ms (NOT 1000ms).
            So we have to get rid of that extra 12ms
            by subtracting delta (112) % interval (100).
            Hope that makes sense.  */      
            previous = now - Math.round(delta % interval); //<-- unconsistency on end frames
            elapsed = (previous - startTime)/1000;  // return value in seconds 
            frameCounter++;

            animateObjectsArray(objects, elapsed, duration);
            runInfo(elapsed, previous, startTime, frameCounter, info);

        }
        if (now - startTime >= duration) {
            stop = true;                
            for (var i = 0; i < objects.length; i++) {
                for(var j = 1; j < objects[i].length; j++) {
                    objects[i][0].style[objects[i][j][0]] = String(objects[i][j][3]) + objects[i][j][1];
                }
            }
            onCompleteFunction();
        }
}
function animateObjectsArray(objects, elapsed, duration) {
    for (var i = 0; i < objects.length; i++) {
        for(var j = 1; j < objects[i].length; j++) {
            objects[i][j][5] = Math.round(easeArray[ objects[i][j][4] ]( elapsed , objects[i][j][2], (objects[i][j][3] - objects[i][j][2]), duration/1000) );   
            objects[i][0].style[ objects[i][j][0] ] = String(objects[i][j][5]) + objects[i][j][1];  
        }               
    }

}
function runInfo(elapsed, previous, startTime, frameCounter, info) {     
    info.innerHTML = frameCounter + 'f / ' + parseInt(elapsed) + 's = ' + parseInt(frameCounter/elapsed) + 'fps<br />'; 
}
// t = time (elapsed), b = initialValue, c = change(FinalValue - initialValue), duration)
var easeArray = [
    //0 - simple linear tweening - no easing, no acceleration
    function linearTween(t, b, c, d) {
        return c*t/d + b;
    },
    //1 - quadratic easing in - accelerating from zero velocity
    function easeInQuad(t, b, c, d) {
        t /= d;
        return c*t*t + b;
    },
    //2 - quadratic easing out - decelerating to zero velocity
    function easeOutQuad(t, b, c, d) {
        t /= d;
        return -c * t*(t-2) + b;
    },
    //3 - quadratic easing in/out - acceleration until halfway, then deceleration
    function easeInOutQuad(t, b, c, d) {
        t /= d/2;
        if (t < 1) return c/2*t*t + b;
        t--;
        return -c/2 * (t*(t-2) - 1) + b;
    },
    //4 - cubic easing in - accelerating from zero velocity
    function easeInCubic(t, b, c, d) {
        t /= d;
        return c*t*t*t + b;
    },
    //5 - cubic easing out - decelerating to zero velocity
    function easeOutCubic(t, b, c, d) {
        t /= d;
        t--;
        return c*(t*t*t + 1) + b;
    },
    //6 - cubic easing in/out - acceleration until halfway, then deceleration
    function easeInOutCubic(t, b, c, d) {
        t /= d/2;
        if (t < 1) return c/2*t*t*t + b;
        t -= 2;
        return c/2*(t*t*t + 2) + b;
    },
    //7 - quartic easing in - accelerating from zero velocity
    function easeInQuart(t, b, c, d) {
        t /= d;
        return c*t*t*t*t + b;
    },
    //8 - quartic easing out - decelerating to zero velocity
    function easeOutQuart(t, b, c, d) {
        t /= d;
        t--;
        return -c * (t*t*t*t - 1) + b;
    },
    //9 - quartic easing in/out - acceleration until halfway, then deceleration
    function easeInOutQuart(t, b, c, d) {
        t /= d/2;
        if (t < 1) return c/2*t*t*t*t + b;
        t -= 2;
        return -c/2 * (t*t*t*t - 2) + b;
    },
    //10 - quintic easing in - accelerating from zero velocity
    function easeInQuint(t, b, c, d) {
        t /= d;
        return c*t*t*t*t*t + b;
    },
    //11 - quintic easing out - decelerating to zero velocity
    function easeOutQuint(t, b, c, d) {
        t /= d;
        t--;
        return c*(t*t*t*t*t + 1) + b;
    },
    //12 - quintic easing in/out - acceleration until halfway, then deceleration
    function easeInOutQuint(t, b, c, d) {
        t /= d/2;
        if (t < 1) return c/2*t*t*t*t*t + b;
        t -= 2;
        return c/2*(t*t*t*t*t + 2) + b;
    },
    //13 - sinusoidal easing in - accelerating from zero velocity
    function easeInSine(t, b, c, d) {
        return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
    },
    //14 - sinusoidal easing out - decelerating to zero velocity
    function easeOutSine(t, b, c, d) {
        return c * Math.sin(t/d * (Math.PI/2)) + b;
    },
    //15 - sinusoidal easing in/out - accelerating until halfway, then decelerating
    function easeInOutSine(t, b, c, d) {
        return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
    },
    //16 - exponential easing in - accelerating from zero velocity
    function easeInExpo(t, b, c, d) {
        return c * Math.pow( 2, 10 * (t/d - 1) ) + b;
    },
    //17 - exponential easing out - decelerating to zero velocity
    function easeOutExpo(t, b, c, d) {
        return c * ( -Math.pow( 2, -10 * t/d ) + 1 ) + b;
    },
    //18 - exponential easing in/out - accelerating until halfway, then decelerating
    function easeInOutExpo(t, b, c, d) {
        t /= d/2;
        if (t < 1) return c/2 * Math.pow( 2, 10 * (t - 1) ) + b;
        t--;
        return c/2 * ( -Math.pow( 2, -10 * t) + 2 ) + b;
    },
    //19 - circular easing in - accelerating from zero velocity
    function easeInCirc(t, b, c, d) {
        t /= d;
        return -c * (Math.sqrt(1 - t*t) - 1) + b;
    },
    //20 - circular easing out - decelerating to zero velocity
    function easeOutCirc(t, b, c, d) {
        t /= d;
        t--;
        return c * Math.sqrt(1 - t*t) + b;
    },
    //21 - circular easing in/out - acceleration until halfway, then deceleration
    function easeInOutCirc(t, b, c, d) {
        t /= d/2;
        if (t < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
        t -= 2;
        return c/2 * (Math.sqrt(1 - t*t) + 1) + b;
    }
]

请记住在 html 元素上声明初始参数:

<div class="info" id="info" onClick="" style="position: absolute; width: 600px; height: 100px; bottom: 0px">
</div>

<div class="obj1" id="obj1" onClick="" style="position: absolute; width: 100px; height: 100px; left: 160px; top: 240px; background-color: #00aa00">
</div>

<div class="obj2" id="obj2" onClick="" style="position: absolute; width: 100px; height: 100px; left: 60px; top: 110px; background-color: #00ccdd">
</div>

<div class="obj3" id="obj3" onClick="" style="position: absolute; width: 10px; height: 160px; left: 20px; top: 170px; background-color: #aacc22">
</div>

<div class="obj4" id="obj4" onClick="" style="position: absolute; width: 160px; height: 120px; left: 160px; top: 210px; background-color: #bbcc00">
</div>

https://jsfiddle.net/rrafw/4vxqLs3q/

关于javascript - 对于多个 Canvas 对象使用一个还是多个 requestAnimationFrame 更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24027711/

相关文章:

html - Angular2如何改变不同组件的背景颜色?

javascript - JQuery - 移动 Div/行

javascript - Canvas 中最流畅的跟随动画

javascript - Canvas 在方形预览框中显示部分悬停区域

javascript - 迭代多边形内的每个点

javascript - jQuery 日期选择器在 ASP.Net MVC4 中无法正常工作

javascript - 对象不支持属性或方法 'fill'

c# - 图像按钮中的 asp.net 图像保持静止

javascript - es6中的of和click事件

javascript - 如何让Material-UI DropDownMenu返回选定的