JavaScript
var canvas = document.getElementById('canvas');
var fInput = document.getElementById('fInput');
var mInput = document.getElementById('mInput');
var ctx = canvas.getContext('2d');
var mouse = {
x: 100,
y: 100
};
function arc(x, y, radius, thickness, colour) {
ctx.strokeStyle = colour || '#FF0000';
ctx.lineWidth = thickness || 3;
ctx.beginPath();
ctx.arc(x, y, radius , 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
}
function curve(x1, y1, x2, y2, cx, cy, colour, thickness) {
ctx.strokeStyle = colour || '#FF0000';
ctx.lineWidth = thickness || 3;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.quadraticCurveTo(cx, cy, x2, y2);
ctx.stroke();
}
function draw(x1, y1, x2, y2, radius) {
var dx, dy, // delta
cx, cy, // control point
mx, my, // mid point
x3, y3, // outer point
length, // hypotenuse
offset, // control offset
theta;
// Compute mid point
dx = x2 - x1;
dy = y2 - y1;
mx = x1 + dx * parseFloat( mInput.value );
my = y1 + dy * parseFloat( mInput.value );
arc(x1, y1, 5, 1, '#00FF00');
arc(mx, my, 5, 1, '#00FF00');
// Compute control point as a function of length
length = Math.sqrt(dx * dx + dy * dy);
offset = length * parseFloat( fInput.value );
theta = Math.atan2(dy, dx) - Math.PI / 2;
cx = mx + Math.cos(theta) * offset;
cy = my + Math.sin(theta) * offset;
arc(cx, cy, 5, 1, '#00FFFF');
// Angle between control & end point
dx = x2 - cx;
dy = y2 - cy;
theta = Math.atan2(dy, dx);
// Find arrow point
offset = radius + 10;
x3 = x2 - Math.cos(theta) * offset;
y3 = y2 - Math.sin(theta) * offset;
// Draw curve
curve(x1, y1, x3, y3, cx, cy, '#0000FF', 2);
// Draw circle
arc(x2, y2, radius);
}
function refresh() {
canvas.width = Math.max(window.innerWidth, 500);
canvas.height = Math.max(window.innerHeight, 500);
draw(10, 10, mouse.x, mouse.y, 20);
}
fInput.addEventListener('input', function(e){
...