Discover the proportion of the total area occupied by your own artwork within the figure

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.

Answer №1

One method that could be utilized is to tally the total number of pixels visible after a user has finished drawing, and then compare this count with the number of pixels in the target shape. It is crucial to ensure that the counted pixels fall within the boundaries of the target shape.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Increase the identification of HTML element with jQuery

I've encountered an issue while trying to increment the id of 2 HTML elements, hwAddition and itemNumber, upon a button click event. The HTML code in question is as follows: <div id="hwAddition"> <div id="itemNumber" s ...

AngularJS $cookies version 1.6.9 experiencing functionality issues

I recently implemented AngularJS $cookies 1.6.9 in my website to handle cookie management. To test it out, I attempted a basic cookie set like this: $cookies.put('myCookieTest', 'test'); var cookie = $cookies.get('myCookieTest&apo ...

Rotating elements with timed jQuery

I'm having trouble getting the selector to rotate at different intervals. I attempted using an if/else statement to make the first rotation occur after 3 seconds and subsequent rotations occur after 30 seconds. Unfortunately, it's rotating every ...

Example of TypeScript Ambient Namespace Usage

The Namespaces chapter provides an example involving D3.d.ts that I find puzzling. Here is the complete example: declare namespace D3 { export interface Selectors { select: { (selector: string): Selection; (element: ...

Having trouble positioning the right side image on the Bootstrap 4 Landing page

Struggling to incorporate bootstrap 4 into my sample project for the right side background. I'm facing some conflicts and attempts to align it on the right side are not successful. Does anyone know how to do this correctly? Thank you // Navbar scr ...

Having issues with the closest method in DojoQuery on Internet Explorer

Looking for guidance on utilizing the closest method in Dojo to identify the first parent element of an element that needs to be displayed/hidden based on a selected value in a filtering select. It functions correctly in Firefox, but encounters an issue in ...

Searching for a button within the <InsertItemTemplate> using jQuery

I need to implement a small jQuery script that darkens the background of a page, displays a small form, and then removes the form and restores the background when the form is submitted or cancelled. Although I have successfully demonstrated this functiona ...

Tips on customizing the selected icon color in Material-UI's BottomNavigationAction styling

I'm facing an issue with Material-UI styled components and could use some assistance. My goal is to create a BottomNavigation bar in React using Material-UI v5 where the selected option's icon displays in red (#f00) while the unselected icons sho ...

The process of declaring a nullable callback variable in TypeScript

Can the declaration of the resolve variable in the TypeScript code below be simplified while maintaining type safety? I am new to TypeScript, so please bear with me. The objective is to store the promise resolver callback that is passed to the executor fu ...

Converting JSON data into clickable URL links and retrieving information upon clicking

I have a dataset in JSON format. As I iterate through it, I'm inserting selected values into an HTML link element as shown below: getPatchList: function() { $.ajax({ url: "/returneddata" }).done(function(r ...

Retrieve the data value from a click event using the class identifier

The following code will display the correct class name, but not the correct data-validamount. It will only show: undefined. $(".prod_amount_add").click(function(){ var rowAmount = 0; var datavalid = $(this).attr('data-validamount'); ...

Retrieve the chosen selection from select2 by referencing the option's unique identifier

I am currently implementing functionality without using the select2 plugin, which works fine. However, I would like to incorporate the select2 plugin. My goal is to utilize the Select2 plugin to retrieve the selected option and then make an ajax call. Th ...

What are the appropriate levels of access that an operating system should provide for web-based scripting?

Contemplating the level of access web-based applications have to an operating system has been on my mind. I'm pondering: What is the most effective method for determining this currently? Are we seeing a trend towards increased or decreased access? ...

What is the equivalent of specifying globalDevDependencies for npm @types packages in typings?

I am looking to update a project using tsc@2 and remove typings from my toolchain. Updating common dependencies is easy as they are listed in my typings.json file: "dependencies": { "bluebird": "registry:npm/bluebird#3.3.4+20160515010139", "lodash": ...

"Error: Multer is Unable to Read the Undefined File

Despite my best efforts, I am unable to get multer's file upload feature to work. Despite studying numerous tutorials and guides on YouTube, as well as diving into countless StackOverflow threads, I still struggle to make it function properly through ...

Tips for uploading files in asp.net using an ajax call

I have developed a small asp.net web forms application for managing emails. The interface allows users to input mandatory information such as sender, recipient, and subject. I am now looking to implement file attachments in the emails using the asp.net fil ...

Mechanism for creating variables in Angular through factory services

While delving into the world of angular1, I encountered services and factories. Using the .factory() method, I passed in a string that represented the desired service name. Surprisingly, I found myself able to reference a variable matching this string wi ...

Use body-parser instead of using "JSON.parse(body)" for parsing data

When using express, the middleware "body-parser" can be utilized to automatically parse the incoming body. However, in the absence of an express router to apply the middleware to, is there a way to implement it for all requests in my chai test file? This ...

Choosing between radio buttons either horizontally or vertically within a table

Here is the markup I am working with: <table> <tr> <td><input type="radio" name="radio"></td> <td><input type="radio" name="radio"></td> <td><input type="radio" name="radio"></ ...

Experiencing compatibility issues with NextAuth and Prisma on Netlify when using NextJS 14

While the website is functioning correctly on development and production modes, I am encountering issues when testing it on my local machine. After deploying to Netlify, the website fails to work as expected. [There are errors being displayed in the conso ...