JSFiddle - React, Tailwind, and code Playground

HTML

Move mouse over canvas to control the red dot.<br/>
Click on canvas to start/stop animation.<br/>
Green is the closest point on the curve.<br/>
Light red/blue is the closest point on each segment.<br/>
<canvas width="400" height="400"/>

JavaScript

function nearest_point(v, w, p) {
    var l2 = (v.x-w.x)*(v.x-w.x) + (v.y-w.y)*(v.y-w.y);
    if (l2 === 0.0) return v;
    var t = ((p.x-v.x)*(w.x-v.x) + (p.y-v.y)*(w.y-v.y)) / l2;
    if (t < 0.0) return v;
    else if (t > 1.0) return w;
    var projection = {};
    projection.x = v.x + t * (w.x - v.x);
    projection.y = v.y + t * (w.y - v.y);
    return projection;
}

var cvs = document.getElementsByTagName('canvas')[0];
var ctx = cvs.getContext('2d');
var width = cvs.width, height = cvs.height;

function LineSegment() {
    this.x0 = this.y0 = this.x1 = this.y1 = 0.0;
}

LineSegment.prototype.Set = function(x0, y0, x1, y1) {
    this.x0 = x0;
    this.y0 = y0;
    this.x1 = x1;
    this.y1 = y1;
}

var numSegs = 6;
var lineSegs = [];
for (var i = 0; i < numSegs; i++) lineSegs.push(new LineSegment());

ctx.lineCap = ctx.lineJoin = 'round';

var mouseX = width / 2.0, mouseY = width / 2.0;
var mouseRadius = 10.0;

var lastTime = new Date();
var animTime = 0.0;
var animate = true;
function doFrame() {
    // We record what time it is for animation purposes
    var time = new Date();
    var dt = (time - lastTime) / 1000; // deltaTime in seconds for animating
    lastTime = time;
    if (animate) animTime += dt;
    
    // Here we create a list of animated line segments
    for (var i = 0; i < numSegs; i++) {
        lineSegs[i].Set(
            width * i / numSegs,
            Math.sin(4.0 * i / numSegs + animTime) * height / 4.0 + height / 2.0,
            width * (i + 1.0) / numSegs,
            Math.sin(4.0 * (i + 1.0) / numSegs + animTime) * height / 4.0 + height / 2.0
        );
    }
    
    // Clear the background
    ctx.fillStyle = '#cdf';
    ctx.beginPath();
    ctx.rect(0, 0, width, height);
    ctx.fill();
    
    // Compute the closest point on the curve.
    var closestSeg = 0;
    var closestDistSquared = 1e100;
    var closestPoint = {};
    
    for (var i = 0; i < numSegs; i++) {
        var lineSeg = lineSegs[i];
        var np =...