function closestPoint(point, line) {
let lineLength = geometric.lineLength(line),
lineInterpolate = geometric.lineInterpolate(line),
precision = 8,
best,
bestLength,
bestDistance = Infinity;
for (let scan, scanLength = 0, scanDistance; scanLength <= lineLength; scanLength += precision) {
const pct = scanLength / lineLength;
if ((scanDistance = distance2(scan = lineInterpolate(pct))) < bestDistance) {
best = scan, bestLength = scanLength, bestDistance = scanDistance;
}
}
precision /= 2;
while (precision > 0.5) {
let before,
after,
beforeLength,
afterLength,
beforeDistance,
afterDistance,
beforePct = beforeLength / lineLength,
afterPct = afterLength / lineLength;
if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = lineInterpolate(beforePct))) < bestDistance) {
best = before, bestLength = beforeLength, bestDistance = beforeDistance;
} else if ((afterLength = bestLength + precision) <= lineLength && (afterDistance = distance2(after = lineInterpolate(afterPct) )) < bestDistance) {
best = after, bestLength = afterLength, bestDistance = afterDistance;
} else {
precision /= 2;
}
}
return best;
function distance2(p) {
const dx = p[0] - point[0],
dy = p[1] - point[1];
return dx * dx + dy * dy;
}
}