This project emerged from a request posted on FlashKit. Someone—whose name I never knew—wanted to build a navigation menu that looked like a memo pad, with selection done by circling. Note that circling is determined by what would happen if the path were a string. A counterclockwise loop around an object will cancel out a clockwise loop, just as the string would unwind when pulled. If the end of the path is not reasonably close to the start, the results may differ from your expectation.... An object encircled equally many times in both directions is considered "not circled." For this demo, the only output is a list of the items selected.
Other experiments involving paths drawn by the user:
Here is the key piece: a function that determines whether or not a given path encircles a given point. The point is an object with x and y properties; the path is an array of such objects.
// test whether the points in path encircle given point
isEncircled = function(point, path) {
var angle, prevAngle, windingChange, p;
var bx = point.x;
var by = point.y;
windingNumber = 0; // how many times around the point we wind
// get initial angle from icon to mouse position
p = path[0];
prevAngle = Math.atan2(p.y - by, p.x - bx);
// now follow the path, keeping track of the winding number
for(var i = 1; i < path.length; i++) {
p = path[i];
angle = Math.atan2(p.y - by, p.x - bx);
windingChange = (angle - prevAngle) / (2 * Math.PI);
prevAngle = angle;
// adjust for the sudden jumps between -180 and 180 degrees
windingChange -= Math.round( windingChange );
// update the running total of how many revolutions we've made
windingNumber += windingChange;
}
// it counts if it's almost all the way around
if( Math.abs(windingNumber) > .8) return true;
return false;
}
| © Michael Kantor, 3/2004 | FlashGizmo.com |