'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';
}
});
Solution 1:[1]
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>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Kaiido |
