Snap.svg determine drag distance along a path

2020-04-09 21:00发布

问题:

As referenced here and updated for use with Snap.svg here, I'd like to better understand how the provided gradSearch function actually works (it's a bit over my head), and whether there are any good alternatives to this approach?

gradSearch = function (l0, pt) {
    l0 = l0 + totLen;
    var l1 = l0,
        dist0 = dist(path.getPointAtLength(l0 % totLen), pt),
        dist1,
        searchDir;

    if (dist(path.getPointAtLength((l0 - searchDl) % totLen), pt) > 
       dist(path.getPointAtLength((l0 + searchDl) % totLen), pt)) {
        searchDir = searchDl;
    } else {
        searchDir = -searchDl;
    }

    l1 += searchDir;
    dist1 = dist(path.getPointAtLength(l1 % totLen), pt);
    while (dist1 < dist0) {
        dist0 = dist1;
        l1 += searchDir;
        dist1 = dist(path.getPointAtLength(l1 % totLen), pt);
    }
    l1 -= searchDir;
    return (l1 % totLen);
}

回答1:

Took me a while to understand the code, but this is how I understand it to be working (trying to keep the explanation simplified):

First the position of the draggable object on the path is recorded as l0 (Note that this is L0, easy to confuse with the number 10 when first looking at the code).

The distance from the new point (where mouse has dragged to) to the position on the path is recorded as dist0.

The if statement then determines which direction to drag in. It does this by adding searchDl value to the path position (i.e. length along the path), and subtracting the same value and seeing which is closer to the mouse position.

Once it knows which direction to move in, it uses the while loop to keep adding/subtracting the position by the searchDl size until the distance between the point on the path and the position of the mouse is as low as it can get.

It then returns the new position on the path.

By changing searchDir to a larger value you can move in larger increments and it can calculate faster at the expense of precision (If I've understood the code correctly).