<canvas id="canvas" width="500" height="500" style="border:1px solid"></canvas>
<script>
// constants
const TICK_SIZE = 5;
const GIZOM_SIZE = 3;
const CIRCLE_STYLE = "BLACK";
const CIRCLE_LINE_WIDTH = 1;
const FONT = "18px Arial";
const FONT_STYLE = "RED";
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// array of circles;
var circles = [];
// current circle being drawn
var currentCircle = null;
// true if mouse dragging
var dragging = false;
// draws a circle;
function drawCircle(circle) {
var nx,
ny;
ctx.strokeStyle = CIRCLE_STYLE;
ctx.lineWidth = CIRCLE_LINE_WIDTH;
// draw circle
if (!circle.showGizom) {
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
ctx.stroke();
} else {
// calculate the radius
var nx = circle.gx - circle.x;
var ny = circle.gy - circle.y;
circle.r = Math.sqrt(nx * nx + ny * ny);
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
// draw center tick
ctx.moveTo(circle.x - TICK_SIZE, circle.y - TICK_SIZE);
ctx.lineTo(circle.x + TICK_SIZE, circle.y + TICK_SIZE);
ctx.moveTo(circle.x + TICK_SIZE, circle.y - TICK_SIZE);
ctx.lineTo(circle.x - TICK_SIZE, circle.y + TICK_SIZE);
// draw radius line
ctx.moveTo(circle.x, circle.y);
ctx.lineTo(circle.gx, circle.gy);
// draw gizom
ctx.moveTo(circle.gx - GIZOM_SIZE, circle.gy - GIZOM_SIZE);
ctx.lineTo(circle.gx + GIZOM_SIZE, circle.gy + GIZOM_SIZE);
ctx.moveTo(circle.gx + GIZOM_SIZE, circle.gy - GIZOM_SIZE);
ctx.lineTo(circle.gx - GIZOM_SIZE, circle.gy + GIZOM_SIZE);
ctx.stroke();
// draw radius
ctx.font = FONT;
ctx.fillStyle = FONT_STYLE;
ctx.textAlign = "center";
// get the transform to draw the text
nx /= circle.r; // normalise the vector from center to gizom
ny /= circle.r;
if(nx < 0){ // is text upside down
// set the transform to be the revers and from the gizom
ctx.setTransform(-nx, -ny, ny, -nx, circle.gx, circle.gy);
} else {
ctx.setTransform(nx, ny, -ny, nx, circle.x, circle.y);
}
ctx.fillText(circle.r.toFixed(1), circle.r / 2, 0);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore transform
}
}
// draw all circles;
function drawCircles() {
var i = 0,
len = circles.length;
for (; i < len; i++) {
drawCircle(circles[i]);
}
}
// render everything
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawCircles();
}
// create a new circle
function createCircle(x, y) {
return currentCircle = {
x : x,
y : y,
r : 0,
gx : x, // gizom location
gy : y,
showGizom : true,
};
}
// get canvas offset
var canvasTopLeft = canvas.getBoundingClientRect();
// create the mouse object
var mouse = {};
mouse.x = 0;
mouse.y = 0;
mouse.down = false;
mouse.buttonChanged = false;
mouse.button = 0;
mouse.origin = {};
mouse.origin.x = canvasTopLeft.left;
mouse.origin.y = canvasTopLeft.top;
// the mouse event handler
var mouseEvent = function (e) {
mouse.x = e.clientX - mouse.origin.x;
mouse.y = e.clientY - mouse.origin.y;
mouse.buttonChanged = 0;
if (e.type === "mousedown") {
mouse.down = true;
mouse.buttonChanged = e.which;
} else if (e.type === "mouseup") {
mouse.down = false;
mouse.buttonChanged = e.which;
}
update();
}
// add events we want to listen to;
canvas.addEventListener('mousedown', mouseEvent);
canvas.addEventListener('mousemove', mouseEvent);
canvas.addEventListener('mouseup', mouseEvent);
// function to update mouse interaction
function update() {
//if (mouse.down || dragging) { // while the is a need to render
if (mouse.buttonChanged === 1) { // is the left button changed
if (mouse.down) { // is it down
if (currentCircle !== null) { // is there a circle active ??
currentCircle.showGizom = false; // turn off its gizom
}
circles.push(createCircle(mouse.x, mouse.y)); // create a new circle at mouse
dragging = true; // flag that we are dragging
} else {
dragging = false; // stop dragging
}
}
if (dragging) { // while dragging move the circle gizom
currentCircle.gx = mouse.x;
currentCircle.gy = mouse.y;
}
// draw any updates
render();
//}
}
</script>