Reputation: 415
I am continuing to animate a model of a transportation system. The code builds stations, connects them with lines, builds "pods" to run along them, then works out the shortest path between random start and end stations.
The problems I am having are a) the pods are traveling one at a time, rather than simultaneously. b) the pod color is supposed to be related to the number of passengers, but this is clearly not happening. c) I suspect I am producing a bottleneck in calculating the animation points, as it seems to run more hesitantly than it should.
I would also like to be able to flag the arrival of each pod, so that it can be reloaded, and start a new journey.
Something is wrong with the animation section, but I can't work out what. Any help would be appreciated!
animate();
var lastTime = 0;
var speed = 1; // higher is slower
function animate(time) {
for (var i = 0; i < podArray.length; i++) {
var aPod = podArray[i];
// calculate incremental points along the path
var points = calcWaypoints(aPod.wayStations);
// return if the desired time hasn't elapsed
if ((time - lastTime) < speed) {
requestAnimationFrame(animate);
return;
}
lastTime = time;
//function animate(){
ctx3.clearRect(0, 0, layer3.width, layer3.height);
if (t < points.length - 1) {
requestAnimationFrame(animate);
}
// draw pod from the last waypoint to the current waypoint
ctx3.beginPath();
ctx3.moveTo(aPod.startX, aPod.startY); //(points[t - 1].x, points[t - 1].y);
ctx3.arc(points[t].x, points[t].y, 4, 0, Math.PI * 2, true);
ctx3.fillStyle = aPod.color;
ctx3.fill();
t++;
}
}
Upvotes: 0
Views: 96
Reputation: 78650
a) Your calcWaypoints
function takes a parameter that is a list of waystation, and then you ignore that parameter and calculate all points for all pods. This is creating one big array of all points, starting with the first pod's points, then the 2nd's, etc. This is why it starts with the first, then the 2nd then the third.
function calcWaypoints(nextArray) {
var frams = 100;
var waypoints = [];
for (var i = 1; i < nextArray.length; i++) {
var pt0 = nextArray[i - 1];
var pt1 = nextArray[i];
var dx = pt1[0] - pt0[0];
var dy = pt1[1] - pt0[1];
for (var j = 0; j < frams; j++) {
var x = pt0[0] + dx * j / frams //+ dxOff;
var y = pt0[1] + dy * j / frams //+ dyOff;
waypoints.push({
x: x,
y: y
});
};
}
return waypoints;
}
b) This has the same cause as the previous, because you are using the same points for each pod, the pods are written over one another. In addition, you are clearing the canvas between each point. This clear should be moved out of the loop. ctx3.clearRect(0, 0, layer3.width, layer3.height);
requestAnimationFrame
in your loop.I hacked together a few of the above changes and it is working. You should still clean it up a lot more:
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);
};
})();
//STATIONS*************************************
var station = [
['A', 150, 100],
['B', 300, 100],
['C', 200, 175],
['D', 100, 250],
['E', 300, 250],
['G', 400, 250],
['F', 350, 200],
['Airport', 500, 200],
['Central', 500, 350]
];
function draw2() {
for (var i = 0; i < station.length; i++) {
var radius = 10;
ctx2.beginPath();
ctx2.arc(station[i][1], station[i][2], radius, 0, 2 * Math.PI);
ctx2.stroke();
ctx2.fillStyle = 'yellow';
ctx2.fill();
//ADD STATION LETTERS
ctx2.font = '10pt Calibri';
ctx2.fillStyle = 'black';
ctx2.textAlign = 'center';
ctx2.fillText(station[i][0], station[i][1], (station[i][2]) + 4);
}
}
draw2();
//END STATIONS*************************************
//START LINES**************************************
var lineArray = [
['A', 'B', ],
['B', 'A', 'C'],
['C', 'B', 'D', 'E'],
['D', 'C', 'E'],
['E', 'D', 'F', 'G', 'Central'],
['F', 'E', 'G'],
['G', 'F', 'E', 'Airport'],
['Airport', 'G', 'Central'],
['Central', 'E', 'Airport']
];
function drawLines() {
for (m = 0; m < lineArray.length; m++) {
ctx1.lineWidth = 1;
ctx1.beginPath();
for (p = 1; p < lineArray[m].length; p++) {
var startStat = lineArray[m][0];
var stat = lookUp(startStat);
var beginX = station[stat][1];
var beginY = station[stat][2];
ctx1.moveTo(beginX, beginY);
var endStat = lineArray[m][p];
var endSt = lookUp(endStat);
var closeX = station[endSt][1];
var closeY = station[endSt][2];
ctx1.lineTo(closeX, closeY);
}
ctx1.stroke();
}
}
drawLines();
//END LINES*************************************
//SHORTEST PATH*********************************
function Graph() {
var neighbors = this.neighbors = {}; // Key = vertex, value = array of neighbors.
this.addEdge = function (u, v) {
if (neighbors[u] === undefined) { // Add the edge u -> v.
neighbors[u] = [];
}
neighbors[u].push(v);
if (neighbors[v] === undefined) { // Also add the edge v -> u in order
neighbors[v] = []; // to implement an undirected graph.
} // For a directed graph, delete
neighbors[v].push(u); // these four lines.
};
return this;
}
function shortestPath(graph, source, target) {
var stationPath = [];
var coordPath = [];
if (source == target) { // Delete these four lines if
print(source); // you want to look for a cycle
return; // when the source is equal to
} // the target.
var queue = [source],
visited = {
source: true
},
predecessor = {},
tail = 0;
while (tail < queue.length) {
var u = queue[tail++], // Pop a vertex off the queue.
neighbors = graph.neighbors[u];
for (var i = 0; i < neighbors.length; ++i) {
var v = neighbors[i];
if (visited[v]) {
continue;
}
visited[v] = true;
if (v === target) { // Check if the path is complete.
var path = [v]; // If so, backtrack through the path.
while (u !== source) {
path.push(u);
u = predecessor[u];
}
path.push(u);
path.reverse();
print(path.join(' → '));
//console.log('Path: ' + path);
for (s = 1; s < path.length; s++) {
stationPath.push(path[s]);
}
//console.log('Waypoints: ' + stationPath);
for (t = 0; t < stationPath.length; t++) {
staCo = lookUp(stationPath[t]);
staCoX = station[staCo][1];
staCoY = station[staCo][2];
coordPath.push([staCoX, staCoY]);
}
//console.log(coordPath);
return coordPath;
}
predecessor[v] = u;
queue.push(v);
}
}
print('there is no path from ' + source + ' to ' + target);
}
function print(s) { // A quick and dirty way to display output.
s = s || '';
document.getElementById('display').innerHTML += s + '<br>';
}
function findShortestPath(s1, s2) {
var graph = new Graph();
for (w = 0; w < lineArray.length; w++) {
var baseStation = lineArray[w][0];
for (z = 1; z < lineArray[w].length; z++) {
graph.addEdge(baseStation, lineArray[w][z]);
}
}
return (shortestPath(graph, s1, s2));
};
function lookUp(sta) {
//console.log(sta);
for (n = 0; n < station.length; n++) {
if (sta == station[n][0]) {
return n;
break;
}
}
}
//BUILD PODS*************************************
var podArray = [];
function Pod(startX, startY, wayStations, riders, color) {
this.startX = startX;
this.startY = startY;
this.wayStations = wayStations;
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;
}
//PROGRAM PODS*********************************************
for (i = 0; i < 3; i++) { //NUMBER OF PODS
//Start Station
var startOff = Math.floor(Math.random() * station.length);
var begSta = station[startOff][0];
var fromX = station[startOff][1];
var fromY = station[startOff][2];
//END STATION
var destNum = Math.floor(Math.random() * station.length);
while (startOff == destNum) {
destNum = Math.floor(Math.random() * station.length);
}
var endSta = station[destNum][0];
function getWayStations(beg, end) {
var fsp = findShortestPath(beg, end);
var nextArray = [];
nextArray.push([fromX, fromY]);
for (var f = 0; f < fsp.length; f++) {
nextArray.push(fsp[f]);
}
return nextArray;
}
//LOAD POD DATA
podArray.push(new Pod(
startX = fromX,
startY = fromY,
wayStations = getWayStations(begSta, endSta),
riders = randomPass(),
color = colorArray[riders - 1]))
}
//END PROGRAM PODS*********************************************
// calc waypoints traveling along nextArray
function calcWaypoints(nextArray) {
var frams = 100;
var waypoints = [];
for (var i = 1; i < nextArray.length; i++) {
var pt0 = nextArray[i - 1];
var pt1 = nextArray[i];
var dx = pt1[0] - pt0[0];
var dy = pt1[1] - pt0[1];
for (var j = 0; j < frams; j++) {
var x = pt0[0] + dx * j / frams //+ dxOff;
var y = pt0[1] + dy * j / frams //+ dyOff;
waypoints.push({
x: x,
y: y
});
};
}
return (waypoints);
}
animate();
var lastTime = 0;
var speed = 1; // higher is slower
function animate(time) {
// return if the desired time hasn't elapsed
if ((time - lastTime) < speed) {
requestAnimationFrame(animate);
return;
}
lastTime = time;
ctx3.clearRect(0, 0, layer3.width, layer3.height);
var callAgain = false;
for (var i = 0; i < podArray.length; i++) {
var aPod = podArray[i];
// calculate incremental points along the path
var points = calcWaypoints(aPod.wayStations);
if (t < points.length - 1) {
callAgain = true;
}
// draw pod from the last waypoint to the current waypoint
if(points.length > t){
ctx3.beginPath();
ctx3.moveTo(aPod.startX, aPod.startY); //(points[t - 1].x, points[t - 1].y);
ctx3.fillStyle = aPod.color;
ctx3.arc(points[t].x, points[t].y, 4, 0, Math.PI * 2, true);
ctx3.fill();
}
}
t++;
if(callAgain) requestAnimationFrame(animate);
}
<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>
<div id="display">
</id>
Upvotes: 1