我正在整理城市交通系统的模拟,并尝试提高我的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>
答案 0 :(得分:1)
为了让你的豆荚速度相同,你可能会想要使用毕达哥拉斯定理。斜边是每次rAF到来时您希望节点行进的距离。然后从中计算你的x和y。
我不太确定我是否理解pct
的作用。
为了加快你想要的rAF:
预先渲染是一项更多的工作,但不是每次绘制每个圆圈,而是每次有画布都不在你绘制的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辆车。
这里有注释和演示:
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;