Shapes come in many forms, from simple (like a red triangle) to complex (such as a black "U shape"). I am currently drawing a blue shape using my mouse and trying to determine the percentage of the figure covered by the 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 drawShapes() {
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 drawTriangle() {
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);
drawTriangle();
drawShapes();
}
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() {
drawTriangle();
drawShapes();
canvas.addEventListener("mousedown", handleMouseDown);
canvas.addEventListener("mousemove", handleMouseMove);
canvas.addEventListener("mouseup", handleMouseUp);
}
init();
</script>
</body>
</html>
P.S. In order to pass the skill, much like in Harry Potter, I have to lead a wand to fit the shape and properly cover the area. https://i.sstatic.net/Egmoo.jpg
In this particular scenario, I anticipate achieving around 60-70% coverage in the top left corner. https://i.sstatic.net/DfQen.png
Despite searching the internet and seeking advice from various sources, including bots and making mathematical adjustments, I have yet to find the proper method to accurately calculate and determine the area percentage.