Reputation: 17
I create 6 buttons for 6 rectangles. When click the button, It will change/random colour of that rectangle following colour in an array. How can I do?
var colorArray = [
'#CEF19E',
'#A7DDA7',
'#78BE97',
'#398689',
'#0B476D'
];
var c = canvas.getContext('2d');
c.fillRect(500, 100, 100, 100);
c.fillRect(250, 100, 100, 100);
c.fillRect(500, 500, 100, 100);
c.fillRect(700, 600, 100, 100);
c.fillRect(800, 100, 100, 100);
function changeColor() {
//????
}
Upvotes: 0
Views: 6893
Reputation: 54026
I am adding this answer as the answer given by enxaneta is an example of bad practice in regard to rendering from mouse events.
Mouse events (depending on the device config and mouse type) can fire up to 1000 times a second. If you render from the mouse events this can mean you force a full render at a rate many times higher than can be displayed (60 times a second max). Doing such can quickly drain a laptops batteries for no reason.
Mouse events should always be decoupled from rendering. Use the event listener to just record the mouse state.
When ever you render anything to the DOM you should always do it via a frame request. This ensures you don't present new context out of sync with the display hardware, and don't add additional unseen and needless render and DOM composite cycles to the page.
In the following example I use a update loop that is called via requestAnimationFrame
to check the state of the mouse and make changes if needed.
To ensure that there are no needless renders there is a global semaphore redraw
that must be set to true for the canvas contents to be drawn. That means in the example below the only renders are the first and when a rectangle has changed color.
requestAnimationFrame(update); // will start the update loop when ready.
const ctx = canvas.getContext("2d");
canvas.width = 400;
canvas.height = 260;
var redraw = true; // When this is true the whole scene is rendered in time for the next display referesh
const colors = (() => {
// Warning: MUST have more than one colour.
// At least one colour MUST be different than others.
const cols = ["#CEF19E","#A7DDA7","#78BE97","#398689","#0B476D"];
return {
get random() { return cols[Math.random() * cols.length | 0] },
get default() { return "#DDD" },
};
})();
const rectPos = [[10,10], [150, 10], [290, 10], [10, 150], [150, 150], [290, 150]];
const rectSize = 100;
const rectangle = (x, y, w = rectSize, h= rectSize, style = colors.default) => ({x, y, w, h, style});
const rects = Object.assign(rectPos.map(rect => rectangle(...rect)), {
getUnder(x, y) { return this.find(r => x >= r.x && x < r.x + r.w && y >= r.y && y < r.y + r.h) },
draw() {
for (const r of this) {
ctx.fillStyle = r.style;
ctx.fillRect(r.x, r.y, r.w, r.h);
}
},
}
);
const mouse = {x: 0, y: 0, button: 0, over: false, changed : true};
function mouseEvents(e) {
const bounds = canvas.getBoundingClientRect();
const x = mouse.x = e.pageX - bounds.left - scrollX;
const y = mouse.y = e.pageY - bounds.top - scrollY;
mouse.over = x >= 0 && x < bounds.width && y >= 0 && y < bounds.height;
mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
mouse.changed = true;
}
["down","up","move"].forEach(name => document.addEventListener("mouse" + name, mouseEvents));
function update() {
var cursor = "default";
if (mouse.changed) {
if (mouse.over) {
const rectUnderMouse = rects.getUnder(mouse.x, mouse.y);
if (rectUnderMouse) {
if (mouse.button) {
var newCol = colors.random;
while (newCol === rectUnderMouse.style) { newCol = colors.random };
rectUnderMouse.style = newCol;
mouse.button = false;
redraw = true;
} else {
cursor = "pointer";
}
}
}
}
if (redraw) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
rects.draw();
redraw = false;
}
canvas.style.cursor = cursor;
requestAnimationFrame(update);
}
canvas { position : absolute; top : 0px; left : 0px; }
<canvas id="canvas"></canvas>
Upvotes: 3
Reputation: 1419
Does this short example help? You can duplicate buttons and call same function or use an alias. Run Code Snippet.
var c = document.getElementById("myCanvas");
var ctx = c.getContext('2d');
var colorArray = [
'#CEF19E',
'#A7DDA7',
'#78BE97',
'#398689',
'#0B476D'
];
var fillCombo = [
[10, 10, 150, 80],
[20, 20, 150, 80],
[10, 10, 150, 80],
[20, 20, 150, 80],
[10, 10, 150, 80]
];
function changeColor() {
var randomFill = fillCombo[Math.floor(Math.random() * fillCombo.length)];
var randomColor = colorArray[Math.floor(Math.random() * colorArray.length)];
ctx.beginPath();
ctx.rect(randomFill[0], randomFill[1], randomFill[2], randomFill[3]);
ctx.fillStyle = randomColor;
ctx.fill();
}
<!DOCTYPE HTML>
<html>
<head>
<TITLE>Canvas Example</TITLE>
<META http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body>
<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;"></canvas>
<button onclick="changeColor()">Click Me!!</button>
</body>
</html>
Upvotes: 1
Reputation: 33024
I'm using the method isPointInPath
to detect if the mouse is in the current rectangle and if it is I change the color from white to the color c
in the rects array.
const canvas = document.getElementById("canvas");
const c = canvas.getContext("2d");
let cw = canvas.width = 700,
cx = cw / 2;
let ch = canvas.height = 700,
cy = ch / 2;
c.translate(-200,0);
c.fillStyle = "white";
let mouse = {}
let rects = [
{c:'#CEF19E',data:[500, 100, 100, 100]},
{c:'#A7DDA7',data:[250, 100, 100, 100]},
{c:'#78BE97',data:[500, 500, 100, 100]},
{c:'#398689',data:[700, 600, 100, 100]},
{c:'#0B476D',data:[800, 100, 100, 100]}
]
rects.forEach(r=>{
c.fillRect(...r.data);
})
canvas.addEventListener("mousemove",(evt)=>{
// clear the canvas
c.clearRect(200,0,cw,ch);
mouse = oMousePos(canvas, evt);
//for each rect in the rects array
rects.forEach((r,i)=>{
c.beginPath();
// draw the rect
c.rect(...r.data);
// if thr mouse is inside the rect
if(c.isPointInPath(mouse.x,mouse.y)){
// fill the rect with the color in the rects array
c.fillStyle = r.c;//color
// fill the rect
c.beginPath();
c.fillRect(...r.data);
}else{
// if the mouse is not in the rects array let it be white
c.fillStyle = "white";
c.fillRect(...r.data);
}
})
})
// a function to detect the mouse position on the canvas
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return { //objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
body {
background-color: #222;
}
canvas {
background-color: #000;
display: block;
margin: 0 auto;
margin:calc(50vh - 250px - 5em) auto;
}
<canvas id="canvas"></canvas>
I hope this helps.
Upvotes: 1