# 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

function bezierApp() {

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

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();
}

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)

canvas.removeEventListener("mousedown", mouseDownListener, false);

return false;
}

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

function mouseMoveListener(evt) {
var posX;
var posY;
var maxX = canvas.width - 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 (!color)
color = "#ffffff";

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

</script>
```