Edit in JSFiddle

<body id="home">

   <h1>Challenge #9 - Bezier curves</h1>

   <p>
      My take on the <a target="_blank" href="http://weblog.jamisbuck.org/2016/9/24/weekly-programming-challenge-9.html">ninth weekly challenge by Jamis Buck</a>.
   </p>
   <canvas id="scene" width="500" height="500"></canvas>

</body>

<script>
   // Inspired by http://rectangleworld.com/blog/archives/15
   window.addEventListener("load", bezierApp, false);

   function bezierApp() {

      point = function(x, y, rad) {
         if (!x) var x = 0;
         if (!y) var y = 0;
         if (!rad) var rad = 1;
         return {
            x: x,
            y: y,
            rad: rad
         };
      }

      var canvas = document.getElementById('scene');
      var cWidth = canvas.width;
      var cHeight = canvas.height;
      var context = canvas.getContext('2d');
      var dragging = false;

      // Control points
      var c1 = new point(100, 100, 10);
      var c2 = new point(250, 300, 10);
      var c3 = new point(400, 100, 10);

      init();

      function init() {
         drawScreen();
         canvas.addEventListener("mousedown", mouseDownListener, false);
      }

      var hitCtrlPoint = null;

      function mouseDownListener(evt) {
         var bRect = canvas.getBoundingClientRect();
         var mouseX = (evt.clientX - bRect.left) * (canvas.width / bRect.width);
         var mouseY = (evt.clientY - bRect.top) * (canvas.height / bRect.height);

         // Check if user clicked on any of the 3 control points
         if (hitTest(c1, mouseX, mouseY))
            hitCtrlPoint = c1;
         else if (hitTest(c2, mouseX, mouseY))
            hitCtrlPoint = c2;
         else if (hitTest(c3, mouseX, mouseY))
            hitCtrlPoint = c3;

         if (hitCtrlPoint) {
            dragging = true;
            dragHoldX = mouseX - hitCtrlPoint.x;
            dragHoldY = mouseY - hitCtrlPoint.y;
         }

         if (dragging)
            window.addEventListener("mousemove", mouseMoveListener, false);

         canvas.removeEventListener("mousedown", mouseDownListener, false);
         window.addEventListener("mouseup", mouseUpListener, false);

         return false;
      }

      function mouseUpListener(evt) {
         canvas.addEventListener("mousedown", mouseDownListener, false);
         window.removeEventListener("mouseup", mouseUpListener, false);
         if (dragging) {
            dragging = false;
            window.removeEventListener("mousemove", mouseMoveListener, false);
         }
      }

      function mouseMoveListener(evt) {
         var posX;
         var posY;
         var shapeRad = hitCtrlPoint.rad;
         var minX = shapeRad;
         var maxX = canvas.width - shapeRad;
         var minY = shapeRad;
         var maxY = canvas.height - shapeRad;

         // Compute mouse position 
         var bRect = canvas.getBoundingClientRect();
         mouseX = (evt.clientX - bRect.left) * (canvas.width / bRect.width);
         mouseY = (evt.clientY - bRect.top) * (canvas.height / bRect.height);

         // Prevent object from dragging outside of canvas
         posX = mouseX - dragHoldX;
         posX = (posX < minX) ? minX : ((posX > maxX) ? maxX : posX);
         posY = mouseY - dragHoldY;
         posY = (posY < minY) ? minY : ((posY > maxY) ? maxY : posY);

         hitCtrlPoint.x = posX;
         hitCtrlPoint.y = posY;

         drawScreen();
      }

      function hitTest(point, mx, my) {
         var dx;
         var dy;
         dx = mx - point.x;
         dy = my - (point.y);

         // a "hit" will be registered if the distance away from the center 
         // is less than the radius of the circular object
         return (dx * dx + dy * dy < point.rad * point.rad);
      }

      function drawScreen() {
         context.fillStyle = "#000000";
         context.fillRect(0, 0, cWidth, cHeight);

         drawPoint(c1.x, c1.y, 10, "#F00");
         drawPoint(c2.x, c2.y, 10, "#F00");
         drawPoint(c3.x, c3.y, 10, "#F00");

         // Check if control point 1 gets passed control point 3
         var dx = 0;
         if (c1.x > c3.x)
            dx = c1.x - c3.x;

         var length = Math.abs(c1.x - c3.x);
         var segLength = parseFloat((length / 100).toFixed(2));
         var xStart = c1.x;

         for (var i = 0; i <= 1; i += 0.01) {

            var bezierPoint;

            if (dx > 0)
               bezierPoint = computeBezierPoint(c3, c2, c1, i.toFixed(2));
            else
               bezierPoint = computeBezierPoint(c1, c2, c3, i.toFixed(2));

            drawPoint(bezierPoint.x, bezierPoint.y);

            xStart += segLength;
         }
      }

      function computeBezierPoint(c1, c2, c3, t) {
         var pX = c1.x * Math.pow((1 - t), 2) + 2 * c2.x * (1 - t) * t + c3.x * Math.pow(t, 2);
         var pY = c1.y * Math.pow((1 - t), 2) + 2 * c2.y * (1 - t) * t + c3.y * Math.pow(t, 2);
         return new point(pX, pY);
      }

      function drawPoint(x, y, radius, color) {

         if (!radius)
            radius = 1

         if (!color)
            color = "#ffffff";

         context.fillStyle = color;
         context.beginPath();
         context.arc(x, y, radius, 0, 2 * Math.PI);
         context.closePath();
         context.fill();
      }
   }

</script>