The trick is to remember that angles (at least in Euclidean space) are periodic by 2*pi. If the difference between the current angle and the target angle is too large (i.e. the cursor has crossed the boundary), just adjust the current angle by adding or subtracting 2*pi accordingly.
In this case, you can try the following: (I've never programmed in Javascript before, so forgive my coding style.)
var dtheta = joint.targetAngle - joint.angle;
if (dtheta > Math.PI) joint.angle += 2*Math.PI;
else if (dtheta < -Math.PI) joint.angle -= 2*Math.PI;
joint.angle += ( joint.targetAngle - joint.angle ) * joint.easing;
EDIT: In this implementation, moving the cursor too quickly around the center of the joint causes it to jerk. This is the intended behavior, since the angular velocity of the joint is always proportional to dtheta
. If this behavior is undesired, the problem can easily be fixed by placing a cap on the angular acceleration of the joint.
To do this, we'll need to keep track of the joint's velocity and impose a maximum acceleration:
joint = {
// snip
velocity: 0,
maxAccel: 0.01
},
Then, for our convenience, we'll introduce a clipping function:
function clip(x, min, max) {
return x < min ? min : x > max ? max : x
}
Now, our movement code looks like this. First, we calculate dtheta
as before, adjusting joint.angle
as necessary:
var dtheta = joint.targetAngle - joint.angle;
if (dtheta > Math.PI) joint.angle += 2*Math.PI;
else if (dtheta < -Math.PI) joint.angle -= 2*Math.PI;
Then, instead of moving the joint immediately, we compute a target velocity and use clip
to force it within our acceptable range.
var targetVel = ( joint.targetAngle - joint.angle ) * joint.easing;
joint.velocity = clip(targetVel,
joint.velocity - joint.maxAccel,
joint.velocity + joint.maxAccel);
joint.angle += joint.velocity;
This produces smooth motion, even when switching directions, while performing calculations in only one dimension. Furthermore, it allows the velocity and acceleration of the joint to be adjusted independently. See demo here: http://codepen.io/anon/pen/HGnDF/