Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

110
Vistas
canvas use more ctx element

My task is to create two canvases (big and small). In big one create 5 stars of different colors.

Task: by clicking on the star, change the color of the small canvas to the color of the star. Now the problem is that addEventListener only works on the last element. Any ideas?

.html template:

<canvas style="background-color:rgb(255, 255, 255); border: 1px solid black" id='big'>Обновите браузер</canvas>
<canvas style="background-color:rgb(255, 255, 255); border: 1px solid black" id='small'>Обновите браузер</canvas>

.js 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';
            }
});
about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

context.isPointInPath(x, y) will check if the point at coords x and y is inside the current sub-path that's being traced in the context.

Every time you call ctx.beginPath(), this sub-path is cleared.

To workaround that you would have to retrace the whole list of stars and check one by one if the point falls in there.
However, there is also a Path2D interface that you can use.

This interface allows to hold such sub-path as their own object, and can be used by the context instead of the internal context's path by e.g ctx.fill(path), ctx.stroke(path), ctx.clip(path), ctx.scrollPathIntoView(path), ctx.drawFocusIfNeeded(path, element), and you probably guessed it, ctx.isPointInPath(path, x, y), or ctx.isPointInStroke(path, x, y).

So you can rewrite your code so that each star is stored in its own Path2D instance, store all these instances in an Array and then traverse that Array to check if any of these was hit by the point:

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();
  // store our path in an object also hodling 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) {
  // find the first star that got 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'>Обновите браузер</canvas>
<canvas id='small'>Обновите браузер</canvas>

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda