I'm trying to make some kind of animation so that a user can understand or see the steps taken in finding the convex hull for a point set. For example, let's say I'm using this code below for Graham Scan, what are some ways to animate the line additions and removals? Even for a lot of points, it takes time to process and then plots them all almost immediately, and I'm unsure how to help the user experience what's going on...
function GrahamScan(points) {
points.sort(function(a, b){return a.x - b.x})
var stack1 = [];
var stack2 = [];
stack1.push(points[0])
stack1.push(points[1])
for (i=2; i < points.length; i++) {
len = stack1.length > 1;
turn = RTT(stack1[stack1.length-2], stack1[stack1.length-1], points[i]) === 1;
ctx.beginPath();
ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
ctx.stroke();
while (len && !turn) {
stack1.pop();
reDraw(points, stack1, stack2);
len = stack1.length > 1;
if (!len) {
break
}
turn = RTT(stack1[stack1.length-2], stack1[stack1.length-1], points[i]) === 1;
}
stack1.push(points[i]);
}
ctx.beginPath();
ctx.moveTo(stack1[stack1.length-2].x,stack1[stack1.length-2].y);
ctx.lineTo(stack1[stack1.length-1].x,stack1[stack1.length-1].y);
ctx.stroke();
stack2 = [];
stack2.push(points[points.length-1])
stack2.push(points[points.length-2])
for (i=2; i < points.length; i++) {
len = stack2.length > 1;
turn = RTT(stack2[stack2.length-2], stack2[stack2.length-1], points[points.length-i-1]) === 1;
ctx.beginPath();
ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
ctx.stroke();
while (len && !turn) {
stack2.pop();
reDraw(points, stack1, stack2);
len = stack2.length > 1;
if (!len) {
break
}
turn = RTT(stack2[stack2.length-2], stack2[stack2.length-1], points[points.length-i-1]) === 1;
}
stack2.push(points[points.length-i-1]);
}
ctx.beginPath();
ctx.moveTo(stack2[stack2.length-2].x,stack2[stack2.length-2].y);
ctx.lineTo(stack2[stack2.length-1].x,stack2[stack2.length-1].y);
ctx.stroke();
}
function reDraw(points,stack1,stack2) {
ctx.clearRect(0, 0, w, h);
document.getElementById("canvasimg").style.display = "none";
for (j = 0; j < points.length; j++) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(points[j].x-1, points[j].y-1, 3, 3);
ctx.closePath();
}
for (k = 1; k < stack1.length; k++) {
ctx.beginPath();
ctx.moveTo(stack1[k-1].x-1,stack1[k-1].y-1);
ctx.lineTo(stack1[k].x-1,stack1[k].y-1);
ctx.stroke();
}
for (l = 1; l < stack2.length; l++) {
ctx.beginPath();
ctx.moveTo(stack2[l-1].x-1,stack2[l-1].y-1);
ctx.lineTo(stack2[l].x-1,stack2[l].y-1);
ctx.stroke();
}
}
function RTT(a, b, c) {
return Math.sign((b.x - a.x)*(c.y-a.y) - (b.y-a.y)*(c.x-a.x));
}