I've modified this example of inverse kinematics in JavaScript with HTML5 Canvas and made it dynamic by seperating it into a function, and it works, but the example only uses 3 points -- start, middle, and end, and I'd like to change the number of points at will. Here's my current fiddle...
function _kinematics(joints, fx, mouse) {
joints.forEach(function (joint) {
joint.target = joint.target || {
x: fx.canvas.width / 2,
y: fx.canvas.height / 2
};
joint.start = joint.start || {
x: 0,
y: 0
};
joint.middle = joint.middle || {
x: 0,
y: 0
};
joint.end = joint.end || {
x: 0,
y: 0
};
joint.length = joint.length || 50;
});
var theta,
$theta,
_theta,
dx,
dy,
distance;
joints.forEach(function (joint) {
if (mouse) {
joint.target.x = mouse.x;
joint.target.y = mouse.y;
}
dx = joint.target.x - joint.start.x;
dy = joint.target.y - joint.start.y;
distance = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
_theta = Math.atan2(dy, dx);
if (distance < joint.length) {
theta = Math.acos(distance / (joint.length + joint.length)) + _theta;
dx = dx - joint.length * Math.cos(theta);
dy = dy - joint.length * Math.sin(theta);
$theta = Math.atan2(dy, dx);
} else {
theta = $theta = _theta;
}
joint.middle.x = joint.start.x + Math.cos(theta) * joint.length;
joint.middle.y = joint.start.y + Math.sin(theta) * joint.length;
joint.end.x = joint.middle.x + Math.cos($theta) * joint.length;
joint.end.y = joint.middle.y + Math.sin($theta) * joint.length;
fx.beginPath();
fx.moveTo(joint.start.x, joint.start.y);
/* for (var i = 0; i < joint.points.length / 2; i++) {
fx.lineTo(joint.points[i].x, joint.points[i].y);
} */
fx.lineTo(joint.middle.x, joint.middle.y);
/* for (var j = joint.points.length / 2; j < joint.points.length; j++) {
fx.lineTo(joint.points[j].x, joint.points[j].y);
} */
fx.lineTo(joint.end.x, joint.end.y);
fx.strokeStyle = "rgba(0,0,0,0.5)";
fx.stroke();
fx.beginPath();
fx.arc(joint.start.x, joint.start.y, 10, 0, Math.PI * 2);
fx.fillStyle = "rgba(255,0,0,0.5)";
fx.fill();
fx.beginPath();
fx.arc(joint.middle.x, joint.middle.y, 10, 0, Math.PI * 2);
fx.fillStyle = "rgba(0,255,0,0.5)";
fx.fill();
fx.beginPath();
fx.arc(joint.end.x, joint.end.y, 10, 0, Math.PI * 2);
fx.fillStyle = "rgba(0,0,255,0.5)";
fx.fill();
});
}
That's just the function, I've omitted the rest for brevity. As you can see, the commented-out lines were my attempt to draw the other points.
Also, here's where I populate the joints
array with the points and such. See commented lines.
populate(_joints, $joints, function() {
var coords = randCoords(map);
var o = {
start: {
x: coords.x,
y: coords.y
},
// points: [],
target: {
x: mouse.x,
y: mouse.y
}
};
/* for (var p = 0; p < 10; p++) {
o.points.push({
x: p === 0 ? o.start.x + (o.length || 50) : o.points[p - 1].x + (o.length || 50),
y: p === 0 ? o.start.y + (o.length || 50) : o.points[p - 1].y + (o.length || 50)
});
}; */
return o;
});
How would I make this function work with n points?