Javascript Lasso

Often a programming task gets more difficult as one delves into its details. On the other hand, sometimes math comes to the rescue! Douglas wondered if we could implement a kind of lasso mouse move that would enable a user to select an item to move too. This enables silent, "click-less" navigation. I found various mouse gesture scripts on the net but no simple javascript code to achieve the task. How hard could it be?

First there is the question of continuity. When operating systems provide mouse position data it doesn't arrive as a list of adjacent (x,y) pixels. Instead, the (x,y) samples can be very far apart, especially if browser is doing other CPU intensive work. The solution seemed fairly straightforward: The only way to interpolate a continuous path would be to scale down the collected mouse positions until they were pretty much adjacent. By dividing the sample mouse positions by around 20, one can get a pretty continuous path that represents medium to large mouse motions pretty well.

Mouse Coordinates:

The dynamic example above essentially shows the mouse coordinate data scaled down and then displayed on the large grid (with a collision detection active simply to clear the grid).

Now the question becomes "how does one detect that a path has closed back on itself?" The completion of the lasso motion is essentially a collision between the current motion and the path that has been laid out earlier. So this involves a match of the current scaled-down mouse position to a previously scaled-down position. I tried that and discovered the next problem. The current position was matching to the immediately previous mouse position which also scaled down to the same point. So a metric of some kind was needed to measure the lenght of the line, or the recency of the points that had been laid down in order to determine if a loop was involved, or just points at the end of the same segment.

Javascript Lasso Part 2

If one could record how "old" a point was, that might do the trick. "Old" triggered the idea of looking at the mouse motions in 3d, with the third dimension being time or elevation. The mouse traces a path on the ground, but as time goes by, a second point directly above is represented ascending upwards. Whenever the mouse recrosses its path back on the ground, there is a vertical distance between the ground point and sky point. Only when this distance is great enough should we assume the line has looped back on itself.

What seems to work pretty well is to start a counter, and for each new scaled down mouse (x,y) we encounter, we record a counter "depth" for that position. If another mouse coordinate scales down to a previously encountered position, we ignore that if the current counter value and the counter value of the previoius position are too close. This is essentially ascribing a length value to the path between the two.

Note that the algorithm is fairly forgiving when it comes to minor steps back along the path one has drawn. It ignores a shaky hand so to speak.

Javascript Lasso Part 3 - Centepede!

We did sneak one other feature in the demo above that limits the path length. The geeks out there will recognize this behaviour is reminiscent of that 80's game Centepede! We need to limit path length since otherwise if a user moves his/her mouse around the screen enough, they'll make a lasso when they don't really want to. Only recent mouse moves should be measured for the lasso effect. So:

The javascript and jQuery code

Future Enhancements

A simple future improvement would be to add sensitivity to the direction of the lasso effect, clockwise or counterclockwise. To improve reliability we could also insert into the mouseTrail array a continuous line (path) between successive scaled mouse points that don't touch. As well we could return the width and height of the lasso, and its central (x,y) coordinate, and all the objects it touches, the ones inside it, etc...