Removing solely the selected item, leaving the rest of the elements on the canvas untouched

Just starting out with coding and working on a game for a school project. The idea is to have random circles or "targets" appear on the screen, and the user has to click them. I've been struggling with keeping the "un-clicked" circles on the canvas when a new circle is clicked. Looking for some guidance on how to achieve this. Any simple tips would be greatly appreciated!

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var radiustracker = [];
var xpos = [];
var ypos = [];
var radius;
var x;
var y;
var color = 'blue';
ctx.fillStyle = 'lightblue';
ctx.fillRect(0, 0, canvas.width, canvas.height);

function randomize() {
  radius = Math.floor(Math.random() * 25) + 10;
  x = Math.floor(Math.random() * 600) + 50;
  y = Math.floor(Math.random() * 400) + 50;
  radiustracker.push(radius);
  xpos.push(x);
  ypos.push(y);
  drawCircle(x, y, radius);
}

function drawCircle(x, y, radius) {
  ctx.beginPath();
  ctx.arc(x, y, radius, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
}

function clickCircle(xmus, ymus) {
  for (var i = 0; i < xpos.length; i++) {
    var distance =
      Math.sqrt(
        ((xmus - xpos[i]) * (xmus - xpos[i])) +
        ((ymus - ypos[i]) * (ymus - ypos[i]))
      );
    console.log(distance);
    if (distance < radiustracker[i]) {
      radiustracker[i] = 0;
      ctx.fillStyle = 'lightblue';
      ctx.fillRect(0, 0, canvas.width, canvas.height);
    }
  }
}

var intervall = setInterval(randomize, 1000);
canvas.addEventListener('click', (event) => {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  clickCircle(x, y);
});
#canvas {
  display:inline;
  margins:auto;
}
<body>
<canvas id="canvas" height="500" width="700" ></canvas>
</body>

Answer №1

Using an array of objects is a better approach than having three separate arrays for tracking circle x, y, and r values:

var circlesDrawn = [];
//For each circle drawn, add its properties to the array
circlesDrawn.push({
    x: x,
    y: y,
    r: r
});

This way, data is grouped together logically.

To remove a clicked circle in a JS Canvas, you cannot directly remove it; instead, clearRect can be used efficiently by clearing the canvas and redrawing the remaining circles after removing the clicked one from the circles array (by filtering out the matching x, y, and r).

Additionally, you can implement interval drawing for new circles as well.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var circles = [];

function drawCanvas() {
    //Clear canvas and redraw existing circles
}

function clickCircle(xmus, ymus){
    //Remove clicked circle from array and update canvas
}

canvas.addEventListener('click', (event) => {
    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    clickCircle(x,y);
});

function randomize(){
    //Generate random circle properties and add to array
}

var interval = setInterval(randomize, 1000);

The code has been tidied up to enhance readability and functionality. It draws all circles at the beginning, handles circle removal on click, and adds new circles at intervals. The implementation has been verified and works flawlessly!

Answer №2

Whenever you remove a circle, all circles must be redrawn; there's no getting around that. My modification is fairly straightforward: in the clickCircle function, I first clear the entire canvas and then iterate through each circle, deleting those that were clicked on and redrawing the ones that weren't.

// Remember not to use var as it can cause unexpected behavior. Instead, opt for const and let.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// It's better to store data in a single array rather than separate arrays for radius and positions
const circles = [];
const color = 'blue';
ctx.fillStyle = 'lightblue';
ctx.fillRect(0, 0, canvas.width, canvas.height);

function randomize() {
  // Keep variable scope limited; previously, radius, x, and y were global variables but now they are local to the function
  const radius = Math.floor(Math.random() * 25) + 10;
  const x = Math.floor(Math.random() * 600) + 50;
  const y = Math.floor(Math.random() * 400) + 50;
  const circle = {radius: radius, x: x, y: y}
  circles.push(circle)
  drawCircle(circle)
}

function drawCircle(circle) {
  ctx.beginPath();
  ctx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI);
  ctx.closePath();
  ctx.fillStyle = color;
  ctx.fill();
}

function clickCircle(xmus, ymus) {
  // Clear the canvas
  ctx.fillStyle = 'lightblue';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  
  // Iterate backwards while removing elements within the loop
  for (let i = circles.length - 1; i >= 0; i--) {
    const circle = circles[i]
    const distance =
      // Use ** for exponentiation
      Math.sqrt(
        ((xmus - circle.x) ** 2) +
        ((ymus - circle.y) ** 2)
      );
    if (distance < circle.radius) {
      // Remove item from the array using Array.splice(index, count)
      circles.splice(circles.indexOf(circle), 1);
    } else {
      // Redraw circles that were not clicked
      drawCircle(circle);
    }
  }
}

const intervall = setInterval(randomize, 1000);
canvas.addEventListener('click', (event) => {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  clickCircle(x, y);
});
#canvas {
  display:inline;
  margins:auto;
}
<body>
<canvas id="canvas" height="500" width="700" ></canvas>
</body>

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

Error encountered: TypeError: __webpack_require__.t is not a function - Issue appears only on live server, while localhost runs without any problem

I set up an e-commerce site that runs smoothly on localhost. However, when I deploy it to a live server, an error appears. Interestingly, the error disappears after reloading the page. Here is the code snippet: import React, { useEffect, useState } from & ...

Tips on saving a bitmap image as a png or jpg file while adding text to it

I am working on a project where I need to display an image in a canvas, add some text to it, and save the resulting Bitmap as a png or jpg file. In the future, I want to allow users to input text from an EditText and position it wherever they desire on the ...

Combining the power of Vuforia with the capabilities of Three

I'm having difficulty with the integration of three.js and Vuforia, as I have limited knowledge about OpenGl which makes it challenging to troubleshoot. Our team is working on a small AR app where we aim to utilize Vuforia for tracking and recognitio ...

Issue with SideNav function in MaterializeCss following recent update

After updating the css/js files of the Materializecss design in my project from v0.97.5 to v0.97.8, I noticed that my SideNav isn't functioning correctly anymore. When I try to click on the menu, it slides out but the dark overlay covers the entire sc ...

Tips on manually refreshing AngularJS view using ControllerAs syntax?

As I work on creating a user-friendly dashboard with widgets that can be sorted, docked, and floated, I encountered an issue. The controls I am using generate floating widgets as HTML at the bottom of the DOM, outside the controller scope where they were c ...

What is the reason that an individual would stop another from executing by using $(document).ready(function() { ?

While I understand that it's supposed to be possible to run multiple $(document).ready(function() { on my page, for some reason I'm having trouble doing so. I appreciate those who have pointed out that it should work, but I'm really looking ...

Using JavaScript and jQuery to make calls to the Web API

I am struggling with Java-script callback due to lack of experience. Can anyone provide assistance in resolving the issues I am facing with the code? My goal is to perform a callback from a .json file and search it by ID. While I can display all customers, ...

saving user information with asynchronous HTTP calls

I am encountering an issue while trying to save my form data using AJAX. When I submit the form data in a JavaScript file that calls another PHP file to perform an insertion operation, an error occurs. Here is the code snippet: <button id="submit" cl ...

Choosing between global and local Node packages can be a crucial decision that affects

Recently, I discovered that Angular 2 is installed globally on my system, but I can't remember when I did that or if it's the recommended setup. It seems redundant since Angular can be defined in each project individually. This situation has me ...

Quick fix for obtaining only one response

I'm facing a dilemma where I need to redirect the user to the dashboard page after they log in, but also send their JSON details to my client-side JavaScript. While I know that there can only be one res.send/end/json in a response and dynamic data can ...

Using html data attributes to encode JSON data with strings

Looking for a way to pass data to JavaScript, I decided to create a template tag as shown below: from django.utils.safestring import mark_safe from django import template import json register = template.Library() @register.simple_tag def mydata(): r ...

Please ensure all three of the last checkboxes are ticked before finalizing submission

Here is the list of checkboxes for my PHP form. I am trying to figure out how to write a script that will only allow the form to be submitted if the last three checkboxes are checked. I have tried looking at similar questions but haven't found the sol ...

Just initiate an API request when the data in the Vuex store is outdated or missing

Currently, I am utilizing Vuex for state management within my VueJS 2 application. Within the mounted property of a specific component, I trigger an action... mounted: function () { this.$store.dispatch({ type: 'LOAD_LOCATION', id: thi ...

Struggling to populate dropdown with values from array of objects

My issue is related to displaying mock data in a dropdown using the SUIR dropdown component. mock.onGet("/slotIds").reply(200, { data: { slotIds: [{ id: 1 }, { id: 2 }, { id: 3 }] } }); I'm fetching and updating state with the data: const ...

Information vanishes as the element undergoes modifications

I am currently working with a JSON file that contains information about various events, which I am displaying on a calendar. Whenever an event is scheduled for a particular day, I dynamically add a div element to indicate the presence of an event on the c ...

Identifying the presence of a period within a string

Forgive me for what may seem like a foolish inquiry, but I am unsure of how to search a string to determine if it includes a period. Here's what I have attempted: var text = "This is an example without a period. What next?" alert(text.search(".")); ...

React Navigation Item Toolbar Misplacement

I've been trying to align the navigation item with the logo on the same line within the toolbar, but I'm facing an issue where they keep appearing in different rows. To see the error for yourself, check out the code sandbox here. This is how I s ...

Issues with AJAX junk appearing after the document element in Firefox are causing disruption

Currently, I am utilizing a page fetch script to dynamically insert a web page into a div element on my site. Let's take a look at the code. By the way, I am running this on Firefox with Kubuntu. function fetchContent(URL, divId) { req = wind ...

Error in Laravel 5.5 PusherBroadcaster.php at line 106

I am facing a frustrating issue with the BroadcastException in PusherBroadcaster.php (line 106) error while using Laravel 5.5 and Vue 2.0. Despite trying various solutions, I have been unable to resolve it. Desperately seeking assistance. Here's what ...

Combining Json attributes in Jquery Grouping

My task is to group the displays by sectors, but I couldn't find a method in JSON to achieve this. Below is the code snippet: $(function displays(){ var url = '{% url get_displays %}'; $.getJSON(url, function(data) { var sidebar = ...