画布动画速度

时间:2015-08-17 15:20:12

标签: javascript html5 canvas

我正在整理城市交通系统的模拟,并尝试提高我的Javascript和Canvas技能。我在这里提供了一个简单的版本:https://jsfiddle.net/ftmzm9vp/

两个问题:

1)我希望“豆荚”以统一的速度运行。现在他们都在同一时间到达目的地,这意味着他们以不同的速度旅行。我该如何纠正?

2)显然我需要做的更多 - 让pods沿现有线路行进,找到通往目的地的最佳路径,扩展线路和站点的数量 - 所有这些都将增加计算开销。现在,有了我想要使用的500个pod,动画开始爬行。我重写了整个事情来使用requestAnimFrame,因为我认为它会更快,但它似乎并不是那么顺利。我该怎么做才能改善这一点? 谢谢!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<title>Pod Stations Lines Test</title>
<body>
    <canvas id="layer1" style="z-index: 2;  
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer2" style="z-index: 3;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <canvas id="layer3" style="z-index: 1;
                position:absolute;
                left:0px;
                top:0px;
                " height="600px" width="1000">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
    <script>
        //Modified Source: http://jsfiddle.net/m1erickson/HAbfm/
        //
        layer1 = document.getElementById("layer1");
        ctx1 = layer1.getContext("2d");
        layer2 = document.getElementById("layer2");
        ctx2 = layer2.getContext("2d");
        layer3 = document.getElementById("layer3");
        ctx3 = layer3.getContext("2d");

        window.requestAnimFrame = (function(callback) {
            return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
                window.setTimeout(callback, 1000 / 60);
            };
        })();

        //STATION LIST
        var station = [
            ['A', 100, 50],
            ['B', 300, 50],
            ['C', 200, 150],
            ['D', 100, 250],
            ['E', 300, 250],
            ['F', 400, 250]
        ];


        //DRAW LINES
        function drawLines() {

            ctx1.clearRect(0, 0, layer3.width, layer3.height);

            var linkAB = ctx1.beginPath();
            ctx1.moveTo(station[0][1], station[0][2]);
            ctx1.lineTo(station[1][1], station[1][2]);
            ctx1.stroke();
            var linkBC = ctx1.beginPath();
            ctx1.moveTo(station[1][1], station[1][2]);
            ctx1.lineTo(station[2][1], station[2][2]);
            ctx1.stroke();
            var linkCD = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[3][1], station[3][2]);
            ctx1.stroke();
            var linkDE = ctx1.beginPath();
            ctx1.moveTo(station[3][1], station[3][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkCE = ctx1.beginPath();
            ctx1.moveTo(station[2][1], station[2][2]);
            ctx1.lineTo(station[4][1], station[4][2]);
            ctx1.stroke();
            var linkEF = ctx1.beginPath();
            ctx1.moveTo(station[4][1], station[4][2]);
            ctx1.lineTo(station[5][1], station[5][2]);
            ctx1.stroke();

        }


        //CREATE PODS

        var podArray = [];

        function Pod(startX, startY, endX, endY, riders, color) {
            this.startX = startX;
            this.startY = startY;
            this.endX = endX;
            this.endY = endY;
            this.riders = riders;
            this.color = color;
        }

        var colorArray = ["gold", "orange", "red", "green", "blue", "black"];

        function randomPass() {
            occ = 1 + Math.floor(Math.random() * 6);
            return occ;
            console.log("Riders " + occ);
        }


        for (i = 0; i < 500; i++) {
            var origNum = Math.floor(Math.random() * station.length);
            var origin = {
                x: station[origNum][1],
                y: station[origNum][2]
            }
            var destNum = Math.floor(Math.random() * station.length);
            while (origNum == destNum) {
                destNum = Math.floor(Math.random() * station.length);
            }
            var destination = {
                x: station[destNum][1],
                y: station[destNum][2]
            }

            podArray.push(new Pod(
            startX = origin.x,
            startY = origin.y,
            endX = destination.x,
            endY = destination.y,
            riders = randomPass(),
            color = colorArray[riders - 1]

            ));
        }

        var pct = 0.00;
        var fps = 60;

        //CALL DRAWING AND ANIMATION
        drawLines();
        animate();

        function animate() {
            setTimeout(function() {

                if (pct <= 1.00) {
                    requestAnimFrame(animate)
                };

                // increment the percent (from 0.00 to 1.00)
                pct += .01;

                // clear the canvas
                ctx3.clearRect(0, 0, layer3.width, layer3.height);

                // draw all podArray
                for (var i = 0; i < podArray.length; i++) {

                    // get reference to next aPod
                    var aPod = podArray[i];

                    var dx = aPod.endX - aPod.startX;
                    var dy = aPod.endY - aPod.startY;
                    var nextX = aPod.startX + dx * pct;
                    var nextY = aPod.startY + dy * pct;

                    //create pod on screen
                    ctx3.fillStyle = aPod.color;
                    ctx3.beginPath();
                    ctx3.arc(nextX, nextY, 5, 0, Math.PI * 2, true);
                    ctx3.fillStyle = aPod.color;
                    ctx3.fill();
                    ctx3.closePath();

                    //STATION LETTERS

                    for (s = 0; s < station.length; s++) {
                        ctx2.font = '12pt Calibri';
                        ctx2.fillStyle = 'red';
                        ctx2.textAlign = 'center';
                        ctx2.fillText(station[s][0], station[s][1], (station[s][2]) + 4);
                    }

                }

            }, 1000 / fps);
        }
    </script>
</body>

2 个答案:

答案 0 :(得分:1)

为了让你的豆荚速度相同,你可能会想要使用毕达哥拉斯定理。斜边是每次rAF到来时您希望节点行进的距离。然后从中计算你的x和y。

我不太确定我是否理解pct的作用。

为了加快你想要的rAF:

  1. 杀死你的设置超时
  2. 预渲染
  3. 预先渲染是一项更多的工作,但不是每次绘制每个圆圈,而是每次有画布都不在你绘制的DOM中。然后,你基本上奠定了隐藏的&#39;在可见的DOM画布上,你想要的画布。它以这种方式将绘图保存在内存中。

    您还可以在for循环结束时在画布上绘制每个圆圈。将填充方法拉到它之外,这样画布可以批量绘制而不是一堆小调用(这实际上可以扼杀性能)。

    每次都可以删除设置字体内容。

    Canvas的性能非常棒,但你必须要小心,因为一个小错误会导致巨大的瓶颈。

    这篇文章很好:http://www.html5rocks.com/en/tutorials/canvas/performance/

    Lemme知道你是否还有其他问题。

答案 1 :(得分:1)

您的车辆全部同时到达目的地,因为您正在根据百分比更改其位置。因此,当pct == 1.00时,所有车辆同时到达他们自己的终点,无论他们到达那里需要的距离。

// increment the percent (from 0.00 to 1.00)
pct += .01;

根据行驶距离使车辆到达

问题#1:您可以计算车辆必须行驶的每个航路点(航路点==唯一像素)以完成它的路线。使用每个新动画帧将车辆前进到它的下一个航路点。这导致每辆车根据其路线长度而不是统一的百分比到达。

问题2:对于每辆车,如果你预先计算&amp;将其航点保存到阵列中,您可以在每个动画帧期间轻松地在画布上绘制500辆车。

这里有注释和演示:

&#13;
&#13;
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

ctx.lineWidth=2;

// define routes
var routes=[];
routes.push({
  points:linePoints({x:10,y:10},{x:150,y:10}),
  currentPoint:0,
  color:'red',
});
routes.push({
  points:linePoints({x:10,y:50},{x:250,y:65}),
  currentPoint:0,
  color:'green',
});
routes.push({
  points:linePoints({x:10,y:90},{x:325,y:105}),
  currentPoint:0,
  color:'blue',
});

// animation related vars
var lastTime=0;
var delay=1000/60*5;

// start animating
requestAnimationFrame(animate);

function animate(time){
  // return if the desired time hasn't elapsed
  if(time<lastTime){requestAnimationFrame(animate);return;}
  // redraw each route
  ctx.clearRect(0,0,cw,ch);
  // var used to stop animating if all routes are completed
  var isComplete=true;
  for(var i=0;i<routes.length;i++){
    var r=routes[i];
    // increase the currentPoint, but not beyond points.length-1
    if((r.currentPoint+1)<r.points.length-1){
      isComplete=false;
      r.currentPoint++;
    }
    // draw the route to its current point
    ctx.strokeStyle=r.color;
    ctx.beginPath();
    ctx.moveTo(r.points[0].x,r.points[0].y);
    ctx.lineTo(r.points[r.currentPoint].x,r.points[r.currentPoint].y);
    ctx.stroke();
    ctx.fillStyle=r.color;
    ctx.beginPath();
    ctx.arc(r.points[r.currentPoint].x,r.points[r.currentPoint].y,5,0,Math.PI*2);
    ctx.fill();
  }
  // request another frame unless all routes are completed
  if(!isComplete){
    requestAnimationFrame(animate);
  }
}

function linePoints(p1,p2){
  // start building a points array with the starting point
  var points=[p1];
  var dx=p2.x-p1.x;
  var dy=p2.y-p1.y;
  var count=Math.sqrt(dx*dx+dy*dy)*3;
  for(var pct=0;pct<count;pct++){
    // calc next waypoint on the line
    var x=p1.x+dx*pct/count;
    var y=p1.y+dy*pct/count;
    var lastPt=points[points.length-1];
    // add new waypoint if the its integer pixel value has
    // changed from last waypoint
    if(parseInt(x)!==parseInt(lastPt.x) || parseInt(y)!==parseInt(lastPt.y)){
      points.push({x:x,y:y});
    }
  }
  // force the last point to be the ending point
  points[points.length-1]=p2;
  // return a unique points[] forming a line from p1 to p2
  return(points);
}
&#13;
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
&#13;
<canvas id="canvas" width=350 height=300></canvas>
&#13;
&#13;
&#13;