Incorporate additional ctx components in your canvas design

My task is to generate two canvases, one large and one small. Within the large canvas, I need to create 5 stars with varying colors.

The objective is to change the color of the small canvas to match the color of the star when clicked. The issue arises as the addEventListener function only seems to work on the last element. Any suggestions?

Here is the HTML template:

<canvas style="background-color:rgb(255, 255, 255); border: 1px solid black" id='big'>Update Browser</canvas>
<canvas style="background-color:rgb(255, 255, 255); border: 1px solid black" id='small'>Update Browser</canvas>

Here's the JavaScript script:

const big = document.getElementById("big");
const small = document.getElementById("small");

big.height = 600;
big.width = 600;
small.height = 600;
small.width = 50;

function createStar(moveToX, moveToY, lineToX1, lineToY1, lineToX2, lineToY2, lineToX3, lineToY3, lineToX4, lineToY4, color) {
            ctx = big.getContext('2d');
            ctx.beginPath();
            ctx.moveTo(moveToX, moveToY);
            ctx.lineTo(lineToX1, lineToY1);
            ctx.lineTo(lineToX2, lineToY2);
            ctx.lineTo(lineToX3, lineToY3);
            ctx.lineTo(lineToX4, lineToY4);
            ctx.closePath();
            ctx.strokeStyle = color;
            ctx.fillStyle = color;
            ctx.fill();
            ctx.stroke();
};

const red = new createStar(20, 60, 100, 60, 35, 110, 60, 25, 85, 110, 'red');
const blue = new createStar(120, 60, 200, 60, 135, 110, 160, 25, 185, 110, 'blue');
const green = new createStar(120, 160, 200, 160, 135, 210, 160, 125, 185, 210, 'green');
const black = new createStar(220, 460, 400, 460, 235, 560, 300, 400, 385, 560, 'black');
const yellow = new createStar(220, 260, 300, 260, 235, 310, 260, 225, 285, 310, 'yellow');

big.addEventListener('click', function(e){
            if(ctx.isPointInPath(e.offsetX, e.offsetY)) {
                small.style.backgroundColor = 'red';
            } else {
                small.style.backgroundColor = 'white';
            }
});

Answer №1

context.isPointInPath(x, y) can be utilized to determine if the point at coordinates x and y lies within the current sub-path being traced in the context.

Whenever you invoke ctx.beginPath(), this existing sub-path is erased.

To address this issue, one would need to iterate through all the stars and individually check if the point falls within any of them.
Alternatively, there exists a Path2D interface that provides a solution.

This interface enables the storage of such sub-paths as separate objects which can then be accessed by the context using methods like ctx.fill(path), ctx.stroke(path), ctx.clip(path), ctx.scrollPathIntoView(path),

ctx.drawFocusIfNeeded(path, element)
, and of course, ctx.isPointInPath(path, x, y) or ctx.isPointInStroke(path, x, y).

Hence, a recommended approach is to store each star in its own Path2D instance, add these instances to an Array, and subsequently loop through the Array to verify if any of the stars have been clicked:

const stars = [];
const big = document.getElementById("big");
const small = document.getElementById("small");

big.height = 600;
big.width = 500;
small.height = 600;
small.width = 50;

const ctx = big.getContext("2d");

function createStar(moveToX, moveToY, lineToX1, lineToY1, lineToX2, lineToY2, lineToX3, lineToY3, lineToX4, lineToY4, color) {
  const path = new Path2D();
  // storing the path along with the color
  stars.push({path, color});
  path.moveTo(moveToX, moveToY);
  path.lineTo(lineToX1, lineToY1);
  path.lineTo(lineToX2, lineToY2);
  path.lineTo(lineToX3, lineToY3);
  path.lineTo(lineToX4, lineToY4);
  ctx.strokeStyle = color;
  ctx.fillStyle = color;
  ctx.fill(path);
  ctx.stroke(path);
};

const red = new createStar(20, 60, 100, 60, 35, 110, 60, 25, 85, 110, 'red');
const blue = new createStar(120, 60, 200, 60, 135, 110, 160, 25, 185, 110, 'blue');
const green = new createStar(120, 160, 200, 160, 135, 210, 160, 125, 185, 210, 'green');
const black = new createStar(220, 460, 400, 460, 235, 560, 300, 400, 385, 560, 'black');
const yellow = new createStar(220, 260, 300, 260, 235, 310, 260, 225, 285, 310, 'yellow');

big.addEventListener('click', function(e) {
  // finding the star that was clicked
  const touched = stars.find((star) =>
    ctx.isPointInPath(star.path, e.offsetX, e.offsetY)
  );
  if (touched) {
    small.style.backgroundColor = touched.color;
  } else {
    small.style.backgroundColor = 'white';
  }
});
canvas {
  background-color: rgb(255, 255, 255);
  border: 1px solid black;
}
<canvas id='big'>Please update your browser</canvas>
<canvas id='small'>Please update your browser</canvas>

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

Provide personalized files according to individual preferences

I am looking to create a website that can generate a custom file based on user input. For example, if it's a story, I want the user's name to be inserted into the text where there is a designated variable for swapping, but this customization shou ...

Scrolling behavior in two columns with sticky positioning

Both columns have varying heights, with the left sometimes higher than the right. I want them to start scrolling down simultaneously, but when the shorter column's content ends, it should stick to the bottom of the viewport and "wait" until the taller ...

Ways to conceal an element in Angular based on the truth of one of two conditions

Is there a way to hide an element in Angular if a specific condition is true? I attempted using *ngIf="productID == category.Lane || productID == category.Val", but it did not work as expected. <label>ProductID</label> <ng-select ...

Filtering out specific properties from an element within a JavaScript forEach loop

const findBloodType = bloodCodeArray.find(bloodCode => bloodCode.code.toUpperCase() === bloodType.toUpperCase()).code; In my Angular code, I am trying to retrieve just the 'code' property of the 'bloodCode' element using a callback ...

Displaying information post-inquiry - Google Visualizations

I have a data-table using Google chart and I am looking to establish a connection with the table by sending a URL query. Once the query is sent, I want to display the retrieved data on my web page using JavaScript. How can I achieve this? Below is the cod ...

Here's a unique rewrite of the text: "Learn how to trigger a new action within an existing action

The implementation in Vuex actions is structured as follows. async actionX({ commit, dispatch }) { const data = this.$axios.$get(`/apiUrl`) await Promise.all([ dispatch('actionY', { data: data }), dispatch('actionZ'), ]). ...

Adding Polyfills to ChainWebpack in Vue 3

In my Vue 3 project, how can I integrate path-browserify into vue.config.js? module.exports = { chainWebpack: config => {} } Upon compilation, I encountered the following error: BREAKING CHANGE: webpack < 5 used to include polyfills for node.js ...

Having trouble transforming JSON into an array using Angular.js

Hello there, I'm currently facing some issues with Angular. I've made a request using $http and received a JSON response like: {"y":"1","a":"0"} I need to convert it into an array format like: {y: 1, a: 0} I've tried using angular.fromJs ...

Executing Code in VueJS after an Event has been Successfully Dispatched

I am currently facing an issue where the form in the child component is being cleared before the event containing the entered form data is successfully passed to the parent component. As a result, the event passes empty values to the parent. I have tried u ...

Utilizing AJAX requests in PHP's MVC framework

I am currently working on a game site using a combination of php and javascript. All my classes and data are stored in php and then encoded into json format. The view calls a javascript file which, through an ajax request, retrieves the php data encoded in ...

Ways to access reference data within the parent data map in Firebase

I'm having trouble making this code work properly. The issue I'm encountering is that the res.data() does not appear in the docs object. getProjects = async () => { const colRef = db.collection('parentCollection').orderBy('c ...

What is the most effective method for implementing a "Like" feature without any redundant code?

Currently, I am in the process of creating a "Like" function similar to those found on platforms like Facebook or Instagram. However, I am unsure of the most effective approach to take. I have contemplated two main methods, both of which involve ensuring ...

Tips for utilizing loops in Node.js to store form data as objects and arrays of objects in MongoDB

Having recently started working with MongoDB, I am incorporating Node.js, Express 4, and mongoose (mongoDB) into my project. I am facing an issue when trying to save form data to mongoDB within a loop, especially because my model contains both objects and ...

Having trouble with JavaScript not working when clicking an image and toggling a div?

Why isn't the onclick image and toggle div functionality working with JavaScript? I made the change from: <input type="button" id="Showdiv1" name="Showdiv1" value="Show Div 1" onclick="showDiv('div1')" /> to: <img src="https://d ...

My issue lies in the execution flow with the child process in Node.js

I've been trying to create a function that takes an input string and returns an output string, but I'm facing challenges due to the delay in response. var result = "initial value"; function executeShell(command) { exec("uname&quo ...

The jqxgrid from jqwidget is displaying all content in a single, messy column

After successfully publishing my project from ASP.NET MVC, everything was functioning perfectly. However, upon publication, the JQXWidget JqxGrid displayed data in a mixed-up manner as shown in this image: https://i.sstatic.net/0o1XY.jpg The layout of my ...

Angular dependency injection function

What is the best placement for the common handleError and handleSuccess functions? These functions are commonly used by every service. Where should these functions be placed? Should they be global functions injected as dependencies? (function () { "u ...

Is it feasible to implement automatic window closure on the alternate website?

Imagine I have a website, let's say http://myownsite.com, and my desire is to execute a script that will open a new window on Safari or any other browser for a site which I do not own: http://theothersite.com If I lack control over that specific site ...

Is it possible to alter the background color once the content of an input field has been modified?

I am working with an angular reactive form and I want to dynamically change the background color of all input fields when their value is changed. Some of these input fields are pre-populated and not required. I came across a potential solution on Stack Ove ...

When using React, appending a React Link tag to an existing list item may result in the addition of two objects instead of the desired

Trying to create a loop that checks if an object's date matches with a date on a calendar. If it does, I want to add a React Link tag to the respective li element. The loop logic works well, but the issue is when appending the Link tag using createTex ...