javascript - 将递归与其他函数连接在一起 | Canvas ,JavaScript

标签 javascript animation canvas recursion

我正在尝试制作“正在生长的树”的动画。问题是我无法连接下面这两个函数以使其正常工作。

到目前为止,我有一个从底部到顶部绘制直线(树干)的函数:
http://jsfiddle.net/FTCcW/1/

下面是绘制整棵树的函数代码:

function stick(d) {

    if (d==0)
        return;

    context.beginPath();
    context.moveTo(0,70);
    context.lineTo(0,0);
    context.lineWidth = 3;
    context.strokeStyle = 'gray';
    context.stroke();

    if (d==1) {
        context.strokeStyle = 'green';
        context.stroke(); }


    context.save();
    context.scale(0.75,0.75);
    context.translate(-35,-60);
    context.rotate(-30 * Math.PI/180);
    stick(d-1);
    context.restore();


    context.save();
    context.scale(0.75,0.75);
    context.translate(35,-60);
    context.rotate(30 * Math.PI/180);
    stick(d-1);
    context.restore();
}

stick(17);

我尝试了几个选项,但没有一个给出正确的结果,所以我决定寻求帮助。

最佳答案

动画的问题在于您必须逐步拆分算法。

这意味着您必须将递归算法转换为迭代算法。

为此,您可以:

  1. 将您的stick 函数拆分为子函数[ Demo ]:

    function pre(i) {
        context.save();
        context.scale(0.75,0.75);
        context.translate(i * 35,-60);
        context.rotate(i * 30 * Math.PI/180); 
    }
    function post() {
        context.restore();
    }
    function middle(d) {
        context.beginPath();
        context.moveTo(0,70);
        context.lineTo(0,0);
        context.lineWidth = 3;
        context.strokeStyle = 'gray';
        context.stroke();
    
        if (d==1) {
            context.strokeStyle = 'green';
            context.stroke();
        }
    }
    function stick(d, i) {
        if(i) pre(i);
        if(d > 0) {
            middle(d);
            stick(d-1, -1);
            stick(d-1, 1);
        }
        if(i) post();
    }
    
  2. 不是调用函数,而是将调用推送到队列(数组)并循环它:

    function stick(n, i) {
        function main(d, i) {
            // Note the order of pushing is the inverse!
            // You must push first the last function
    
            if(i) queue.push([], post);
            if(d > 0) {
                queue.push([d-1,-1], main);
                queue.push([d-1,1], main);
                queue.push([d], middle);
            }
            if(i) queue.push([i], pre);
        }
    
        queue.push([n, 0], main);
    
        while(queue.length) {
            (queue.pop()).apply(null, queue.pop());
        }
    }
    

完整代码[ Demo ]:

function stick(n, i) {
    var queue = [];

    function pre(i) {
        context.save();
        context.scale(0.75,0.75);
        context.translate(i * 35,-60);
        context.rotate(i * 30 * Math.PI/180); 
    }
    function post() {
        context.restore();
    }
    function middle(d) {
        context.beginPath();
        context.moveTo(0,70);
        context.lineTo(0,0);
        context.lineWidth = 3;
        context.strokeStyle = 'gray';
        context.stroke();

        if (d==1) {
            context.strokeStyle = 'green';
            context.stroke();
        }
    }
    function main(d, i) {
        if(i) queue.push([], post);
        if(d > 0) {
            queue.push([d-1,-1], main);
            queue.push([d-1,1], main);
            queue.push([d], middle);
        }
        if(i) queue.push([i], pre);
    }

    queue.push([n, 0], main);

    while(queue.length) {
        (queue.pop()).apply(null, queue.pop());
    }
}

现在,将它转换为动画是微不足道的。只需将 while 循环替换为以下内容:

(function step() {
    if (queue.length) {
        (queue.pop()).apply(null, queue.pop());
        setTimeout(step, 100);
    }
})();

但是,由于只有 main 函数会进行视觉更改,所以最好使用 [ Demo ]

(function step() {
    if (queue.length) {
        var f = queue.pop(),
            args = queue.pop();
        f.apply(null, args);
        if(f === main) setTimeout(step, 100);
        else step();
    }
})();

或者您可能希望在每个步骤中执行更多操作,[ Demo ]:

var iter = 1000;
(function step() {
    var i = iter,
        d = new Date();
    while (queue.length && --i>=0) {
        var f = queue.pop(),
            args = queue.pop();
        f.apply(null, args);
    }
    iter = Math.max(50, iter*60/(new Date()-d)|0);
    if (queue.length) f === main ? setTimeout(step, 100) : step();
})();

关于javascript - 将递归与其他函数连接在一起 | Canvas ,JavaScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20731024/

相关文章:

javascript - 使用 Javascript 编写 future 的一天

iphone - 用户与 uiview 和动画完成 block 的交互

javascript - 将一个旋转对象包含在另一个旋转对象中 FabricJS

javascript - Highcharts - 导出模块

javascript - 如何从网格构建唯一值列表?

javascript - Angular2 SharedService 默认传递 ID 但可以更改

ios - 如何通过更改变换位置来更改 UIView 的位置?

CSS3 动画 IE11 问题

java - 如何停止或暂停 Canvas 上的绘图

html - 使用与文本不同的背景颜色绘制 HTML5 Canvas?