There is simple shape(red triangle) and complex(black “U shape”).
I draw blue shape by mouse and willing to find: percentage of the figure been covered by drawing(blue color).
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Canvas</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const radius = 15;
const random_shape = [
{ x: 20, y: 20, width: 20, height: 100 },
{ x: 60, y: 20, width: 20, height: 100 },
{ x: 20, y: 120, width: 60, height: 20 },
];
const triangle = [
{ x: 200, y: 400 },
{ x: 400, y: 200 },
{ x: 600, y: 400 },
];
let isDrawing = false;
let lastX = 0;
let lastY = 0;
let pixelsInsideFigure = 0;
function draw_random_shape() {
for (let i = 0; i < random_shape.length; i++) {
ctx.fillStyle = "black";
ctx.fillRect(
random_shape[i].x,
random_shape[i].y,
random_shape[i].width,
random_shape[i].height
);
}
}
function draw_triangle() {
ctx.beginPath();
ctx.moveTo(triangle[0].x, triangle[0].y);
for (let i = 1; i < triangle.length; i++) {
ctx.lineTo(triangle[i].x, triangle[i].y);
}
ctx.closePath();
ctx.fillStyle = "red";
ctx.fill();
}
function handleMouseDown(e) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
if (pointInShape({ x: lastX, y: lastY }, random_shape)) {
pixelsInsideFigure++;
}
}
function handleMouseMove(e) {
if (!isDrawing) return;
ctx.strokeStyle = "blue";
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.lineWidth = radius;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
if (pointInShape({ x: lastX, y: lastY }, random_shape)) {
pixelsInsideFigure++;
}
}
function handleMouseUp() {
isDrawing = false;
calculatePercentage();
pixelsInsideFigure = 0;
}
function clearUserInput() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw_triangle();
draw_random_shape();
}
function calculatePercentage() {
const coveredArea = calculateCoveredArea(
{ x: lastX, y: lastY },
radius
);
const totalArea = Math.PI * Math.pow(radius, 2);
const coveragePercentage = (coveredArea / totalArea) * 100;
alert(`Area Coverage Percentage: ${coveragePercentage.toFixed(2)}%`);
clearUserInput();
}
function pointInShape(point, vertices) {
let inside = false;
const x = point.x;
const y = point.y;
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
const xi = vertices[i].x;
const yi = vertices[i].y;
const xj = vertices[j].x;
const yj = vertices[j].y;
const intersect =
yi > y != yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}
function calculateCoveredArea(point, radius) {
let coveredArea = 0;
const centerX = point.x;
const centerY = point.y;
for (let x = centerX - radius; x <= centerX + radius; x++) {
for (let y = centerY - radius; y <= centerY + radius; y++) {
const distance = Math.sqrt(
Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2)
);
if (distance <= radius) {
if (pointInShape({ x: x, y: y }, random_shape)) {
console.log("INSIDE RANDOM SHAPE");
coveredArea++;
}
if (pointInShape({ x: x, y: y }, triangle)) {
console.log("INSIDE Triangle");
coveredArea++;
}
}
}
}
return coveredArea;
}
function calculateArea(vertices) {
let area = 0;
for (let i = 0, j = vertices.length - 1; i < vertices.length; j = i++) {
area +=
(vertices[j].x + vertices[i].x) * (vertices[j].y - vertices[i].y);
}
return Math.abs(area / 2);
}
function init() {
draw_triangle();
draw_random_shape();
canvas.addEventListener("mousedown", handleMouseDown);
canvas.addEventListener("mousemove", handleMouseMove);
canvas.addEventListener("mouseup", handleMouseUp);
}
init();
</script>
</body>
</html>
P.S. As reference in Harry Potter 1 I have to lead a wand to fit the shape. To pass the skill you have to properly cover the area.
In provided case I am expecting to get around 60-70%(top left corner).
Searching the internet, asking “bots”, did math adjustments – did not help.
Expecting: proper way to calculate and find the area percentage.
First thing that comes to my mind, you may count total pixels which are showed up after user drawing, then you can compare with target shape pixels count. There is important thing to check counted pixels should be inside boundaries of target shape
4