Search code examples
htmlcanvasbezier

Finding points on curves in HTML 5 2d Canvas context


Given lines drawn by 2d canvas context functions bezierCurveTo, quadraticCurveTo or arcTo, how can I find points along those lines?

My intent is to draw an object at the midpoint of a curve. Using the SVG DOM, I can do this with methods getPointAtLength & getTotalLength, but I can't see an equivalent in HTML canvas.


Solution

  • You find them the hard way :(

    There isn't an equivalent in HTML canvas. You have to find the midpoints yourself with plain old math.

    I did an example of how to find midpoint of bezier curves for you. Real curve is red, midpoint is the tiny green rectangle. Everything else is just a visual aid.

    var ctx = test.getContext("2d")
    
    function mid(a,b) {
     return (a+b) / 2;
    }
    
    
    var cp1x = 100;
    var cp1y = 150;
    var cp2x = 175;
    var cp2y = 175;
    var x = 200;
    var y = 0;
    
    ctx.lineWidth = 4;
    ctx.strokeStyle = "red";
    ctx.fillStyle = "rgba(0,0,0,0.6)";
    
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    ctx.stroke();
    
    //line goes from start to control point 1
    ctx.strokeStyle = "rgba(0,0,200,0.4)";
    ctx.beginPath();
    ctx.moveTo(0, 0);
    ctx.lineTo(cp1x , cp1y);
    ctx.stroke();
    
    //line goes from end to control point 2
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(cp2x , cp2y);
    ctx.stroke();
    
    //line goes from control point to control point
    ctx.strokeStyle = "rgba(200,0,200,0.4)";
    ctx.beginPath();
    ctx.moveTo(cp1x, cp1y);
    ctx.lineTo(cp2x , cp2y);
    ctx.stroke();
    
    // now find the midpoint of each of those 3 lines
    var ax = mid(cp1x,0);
    var bx = mid(cp2x,x)
    var cx = mid(cp1x,cp2x)
    
    var ay = mid(cp1y,0)    
    var by = mid(cp2y,y)    
    var cy = mid(cp1y,cp2y)
    
        
    // draw midpoints for visual aid 
    // not gonna look exact 'cause square
    // will be drawn from top-right instead of center
    ctx.fillRect(ax, ay, 4, 4);
    ctx.fillRect(bx, by, 4, 4);
    ctx.fillRect(cx, cy, 4, 4);
    
    
    //now draw lines between those three points. These are green
    ctx.strokeStyle = "rgba(0,200,0,0.4)";
    ctx.beginPath();
    ctx.moveTo(ax, ay);
    ctx.lineTo(cx , cy);
    ctx.stroke();
    
    ctx.beginPath();
    ctx.moveTo(bx, by);
    ctx.lineTo(cx , cy);
    ctx.stroke();
    
    //now the midpoint of the green lines:
    // so g1 and g2 are the green line midpoints
    var g1x = mid(ax,cx);
    var g2x = mid(bx,cx);
    
    var g1y = mid(ay,cy); 
    var g2y = mid(by,cy);  
    
    //draw them to make sure:
    ctx.fillRect(g1x , g1y, 4, 4);
    ctx.fillRect(g2x , g2y, 4, 4);
    
    //now one final line, in gray
    ctx.strokeStyle = "rgba(20,20,20,0.4)";
    ctx.beginPath();
    ctx.moveTo(g1x , g1y);
    ctx.lineTo(g2x , g2y);
    ctx.stroke();
     
    //whew! We made it!
    var FinallyTheMidpointx = mid(g1x,g2x); 
    var FinallyTheMidpointy = mid(g1y,g2y); 
    
    //draw something at the midpoint to celebrate
    ctx.fillStyle = "rgba(0,255,0,1)";
    ctx.fillRect(FinallyTheMidpointx, FinallyTheMidpointy, 4, 4);
    <canvas id="test" width="500" height="500"></canvas>