Работа с заменой контекста в javaScript
Всем привет. Народ, подскажите пожалуйста по поводу одной проблемы в сфере фронтенда (html, css, js). В общем у меня есть задача написать прогу, которая будет рисовать круги в канвасе по нажатию на кнопку мышки, причём у этих кругов будет цвет и размер, которые устанавливает пользователь. Я написал класс и дал ему два свойства color и size, а также метод drawLine, который отвечает за рисование кругов. код всего этого предоставляю ниже.
class Line {
constructor(color, size){
this.color = color;
this.size = size;
}
drawLine(){
canvas.addEventListener('mousedown', function(e){
ctx.fillStyle = this.color;
ctx.arc(e.clientX, e.clientY, 30, 0, Math.PI * 2);
ctx.fill();
console.log(this.color);
})
}
}
new Line(generalColor.value).drawLine();
Проблема в том, что метод рисует круги, но всегда чёрные. В принципе понятно почему, ведь в строке ctx.fillStyle = this.color; this ссылает нас к элементу, на котором произошло событие, т.е к канвасу. Вопрос такой: как вернуть к this в методе drawLine контекст класса, т.е чтобы this ссылалось на класс, а не на канвас? Я пробовал менять контекст с помощью метода call вот так:
new Line(generalColor.value).drawLine.call(Line);
но не получилось. Пробовал как-то это обойти костылями, тоже не получилось. В общем опытные JSеры помогите пожалуйста. Заранее спасибо за помощь.
P.s. Хочу решить эту задачку объектно-ориентированным программированием.
Ответы (2 шт):
Вот, должно сработать:
class Line {
constructor(color, size){
this.color = color;
this.size = size;
}
drawLine(){
let line = this; // Трюк, которым все пользуются
canvas.addEventListener('mousedown', function(e){
ctx.fillStyle = line.color;
ctx.arc(e.clientX, e.clientY, 30, 0, Math.PI * 2);
ctx.fill();
console.log(line.color);
})
}
}
Хотя, вы точно уверены что алгоритм верен? Выглядит странно...
Дело в том, что function имеет свой this. Можно использовать, например, стрелочную функцию, у которой нету своего this
class Line {
constructor(color, size){
this.color = color;
this.size = size;
}
drawLine(){
canvas.addEventListener('mousedown', (e) => {
ctx.fillStyle = this.color;
ctx.arc(e.clientX, e.clientY, 30, 0, Math.PI * 2);
ctx.fill();
});
}
}
Вот как можно сделать, чтобы работало:
class Line {
constructor(options) {
this.canvas = options.canvas;
this.color = options.color;
this.size = options.size;
this.ctx = this.canvas.getContext('2d');
this.addListener();
}
addListener() {
this.canvas.addEventListener('mousemove', (e) => {
this.ctx.beginPath();
this.ctx.arc(e.x, e.y, this.size, 0, 2 * Math.PI, false);
this.ctx.fillStyle = this.color;
this.ctx.fill();
this.ctx.closePath();
});
}
}
const canvas = document.createElement('canvas');
document.body.prepend(canvas);
const line = new Line({
canvas: canvas,
color: 'red',
size: '10'
});
canvas {
border: 1px solid black;
}