#javascript #button #canvas
Вопрос:
Я пытаюсь создать объект button, который может запускать функцию класса (в данном случае show ()), которая изменит цвет кнопки. Проблема в том, что я могу сделать это, только вызывая show() повторно каждый раз, когда меняется цвет. В результате на экране появляется тонна кнопок, но я хотел бы нарисовать кнопку только один раз. Есть ли способ обойти это? (Примечание: У меня увеличена позиция кнопки x, чтобы показать создаваемые кнопки)
let canvas = document.getElementById("JScanvas"),
c = canvas.getContext("2d");
let mousePosition = {
x: 0,
y: 0
};
// ignore, a few functions I might need for this to run
function buildRect(fillColor, outlineColor, outlineSize, x, y, w, h) {
if (fillColor amp;amp; outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.fillStyle = fillColor;
c.fill();
c.lineWidth = outlineSize;
c.strokeStyle = outlineColor;
c.stroke();
} else if (fillColor amp;amp; !outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.fillStyle = fillColor;
c.fill();
} else if (!fillColor amp;amp; outlineColor) {
c.beginPath();
c.rect(x, y, w, h);
c.lineWidth = outlineSize;
c.strokeStyle = outlineColor;
c.stroke();
}
}
function write(str, x, y, color, txtSize, font) {
let size = txtSize.toString();
c.font = size "px" " " font;
c.fillStyle = color;
c.fillText(str, x, y);
}
// end of useless functions
class button {
// mouse is {canvs: canvas, mClicked: t/f, mPosition: mousePosition{x, y}}
constructor(name, order, btnColor, x, y, w, h, txtColor, txtSize, m, f) {
this.name = name;
this.order = order;
this.btnColor = btnColor;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.txtColor = txtColor;
this.txtSize = txtSize;
this.m = m;
this.f = f;
//change color when mouse over button
this.m.canvs.addEventListener("mousemove", (event) => {
console.log("hello there");
if (this.x < this.m.mPosition.x amp;amp; this.m.mPosition.x < this.x this.w amp;amp; this.y < this.m.mPosition.y amp;amp; this.m.mPosition.y < this.y this.h) {
if (this.btnColor[0] != "grey") {
this.btnColor[0] = "grey";
this.x = 50;
this.show();
} else {
this.btnColor[0] = "red";
this.x = 50;
this.show();
}
}
});
}
show() {
if (!this.btnColor[0] amp;amp; !this.btnColor[0]) {
buildRect("transparent", false, 1, this.x, this.y, this.w, this.h);
} else if (!this.btnColor[0]) {
buildRect(false, this.btnColor[1], 1, this.x, this.y, this.w, this.h);
} else if (!this.btnColor[1]) {
buildRect(this.btnColor[0], false, 1, this.x, this.y, this.w, this.h);
} else {
buildRect(this.btnColor[0], this.btnColor[1], 1, this.x, this.y, this.w, this.h);
}
c.fillStyle = this.txtColor;
let theString = String(this.txtSize) "px Arial";
c.font = theString;
let width = Math.round(c.measureText(c.fillText(this.name, -1000, 0)).width);
if (width > this.w) {
let center = this.x (this.w / 2);
let newSize = this.w / width;
c.font = String(this.txtSize * newSize);
let newWidth = Math.round(newSize * width);
c.textAlign = "center";
c.textBaseline = "middle";
c.fillText(this.name, this.x (this.w / 2), this.y (this.h / 2));
} else {
c.textAlign = "center";
c.textBaseline = "middle";
c.fillText(this.name, this.x (this.w / 2), this.y (this.h / 2));
}
}
clickButton(mouseX, mouseY) {
if (mouseX >= this.x amp;amp; mouseX <= this.x this.w amp;amp; mouseY >= this.y amp;amp; mouseY <= this.y this.h) {
return true;
} else {
return false;
}
}
runf() {
this.f();
}
}
//getting mouse position
function getMousePos(canvas, evt) {
const rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener("mousemove", (evt) => {
let r = getMousePos(canvas, event);
mousePosition.x = r.x, mousePosition.y = r.y;
});
let mouse = {
canvs: canvas,
mClicked: false,
mPosition: mousePosition
};
//button object to call: ("red" is the color of the button I am trying to change to grey)
let cookie = new button("cookie", 1, ["red", false], 50, 100, 150, 50, "black", 30, mouse, 2);
cookie.show();
<!DOCTYPE html>
<html>
<head>
<title>Playground</title>
</head>
<body>
<canvas width="1500" height="1500" id="JScanvas"></canvas>
</body>
</html>
Комментарии:
1. Вы должны запомнить старое положение кнопки, чтобы вы могли удалить его, прежде чем рисовать новую кнопку.
2. Возможно, вам следует реализовать кнопку в виде спрайта, чтобы вы могли анимировать ее, а не просто рисовать новые прямоугольники.
3. @Бармар Интересно. Если я сохраню старую позицию, как я удалю старый прямоугольник, учитывая, что он был вызван в исходном show()? Я мог бы сделать спрайт, я полагаю, но разве нет другого способа?
4. Вы можете нарисовать его снова, используя цвет фона, который заставляет его исчезнуть.
5. @Barmar Рисуя его в качестве цвета фона, он действительно исчезает на экране, но я думаю, что код все еще работает. Он продолжает накапливать избыточные отходы.
Ответ №1:
Я думаю, что вы слишком усложнили свой код…
Вот простой пример, где мы меняем цвет, когда мышь находится над прямоугольником
let canvas = document.getElementById("canvas")
let c = canvas.getContext("2d");
class button {
constructor(color, x, y, w, h) {
this.color = color;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
draw(mouse) {
c.beginPath();
c.rect(this.x, this.y, this.w, this.h);
if (mouse.x >= this.x amp;amp; mouse.x <= this.x this.w amp;amp;
mouse.y >= this.y amp;amp; mouse.y <= this.y this.h) {
c.fillStyle = "gray";
} else {
c.fillStyle = this.color;
}
c.fill();
}
}
function getMousePos(evt) {
if (!evt) return { x: 0, y: 0 }
const rect = canvas.getBoundingClientRect();
return { x: evt.clientX - rect.left, y: evt.clientY - rect.top };
}
let buttons = []
buttons.push(new button("red", 50, 100, 40, 20))
buttons.push(new button("blue", 100, 50, 40, 20))
canvas.addEventListener("mousemove", mainDraw);
function mainDraw(evt) {
let mouse = getMousePos(evt)
c.clearRect(0, 0, canvas.width, canvas.height);
buttons.forEach((btn) => {
btn.draw(mouse)
})
}
mainDraw()
<canvas id="canvas" width="150" height="150"></canvas>
Как вы можете видеть, есть только один addEventListener, и он находится за пределами кнопки класса, логика проста, мы очищаем весь холст и рисуем все на каждом событии… вот как это делают игры, я уверен, что это сработает и для того, что вы делаете.