3

I am currently trying to create a canvas that has a background and a crosshair like object that follows around your mouse, everything works besides the crosshair still showing where it was previously drawn. I'm not sure where to clear the canvas without everything on the canvas being cleared and not showing up here is my code.

canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");

canvas.width = innerWidth;
canvas.height = innerHeight;

class Background {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawBackground() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");
backgroundSky.drawBackground();
backgroundGrass.drawBackground();

class Lens {
    constructor(x, y, radius, color) {
        this.x = x,
        this.y = y,
        this.radius = radius,
        this.color = color
    }

    drawLens() {
        ctx.lineWidth = 10;
        ctx.strokeStyle = "black";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
        ctx.stroke();
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}

class Cross {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawCross() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

addEventListener("mousemove", function(event) { 
    mouseX = event.clientX;
    mouseY = event.clientY;
    const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
    const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
    const lens = new Lens(mouseX, mouseY, 250, "transparent");
    crossX.drawCross();
    crossY.drawCross();
    lens.drawLens();
});
* {
    margin: 0;
    overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <canvas></canvas>
        <script src="index.js" async defer></script>
    </body>
</html>
nickg
  • 123
  • 5
  • 2
    Does this answer your question? [HTML5 Remove previous drawn object in canvas](https://stackoverflow.com/questions/16969787/html5-remove-previous-drawn-object-in-canvas) – ggorlen Jan 13 '21 at 01:20
  • @ggorlen Thank you! I hope I'm not a bother but I don't use JS that much and I'm not sure how to do that – nickg Jan 13 '21 at 01:20
  • 1
    In particular, see the [second answer](https://stackoverflow.com/a/16969840/6243352) in the dupe thread. I posted an answer but it should still be a dupe, so no need to accept it or upvote. In the future, if you add an animation loop to this app, apply the same technique. – ggorlen Jan 13 '21 at 01:21

2 Answers2

1

Clear the entire screen and redraw it per frame:

ctx.clearRect(0, 0, canvas.width, canvas.height);
backgroundSky.drawBackground();
backgroundGrass.drawBackground();
crossX.drawCross();
crossY.drawCross();
lens.drawLens();

Full code:

canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");

canvas.width = innerWidth;
canvas.height = innerHeight;

class Background {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawBackground() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");

class Lens {
    constructor(x, y, radius, color) {
        this.x = x,
        this.y = y,
        this.radius = radius,
        this.color = color
    }

    drawLens() {
        ctx.lineWidth = 10;
        ctx.strokeStyle = "black";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
        ctx.stroke();
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}

class Cross {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawCross() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

addEventListener("mousemove", function(event) { 
    mouseX = event.clientX;
    mouseY = event.clientY;
    const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
    const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
    const lens = new Lens(mouseX, mouseY, 250, "transparent");
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    backgroundSky.drawBackground();
    backgroundGrass.drawBackground();
    crossX.drawCross();
    crossY.drawCross();
    lens.drawLens();
});
* {
    margin: 0;
    overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <canvas></canvas>
        <script src="index.js" async defer></script>
    </body>
</html>
ggorlen
  • 44,755
  • 7
  • 76
  • 106
0

You could redraw the background just before drawing the crosshair.

Your mousemove event listener function would become:

addEventListener("mousemove", function(event) { 
    mouseX = event.clientX;
    mouseY = event.clientY;
    const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
    const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
    const lens = new Lens(mouseX, mouseY, 250, "transparent");
    backgroundSky.drawBackground(); // ⚠️
    backgroundGrass.drawBackground(); // ⚠️
    crossX.drawCross();
    crossY.drawCross();
    lens.drawLens();
});

canvas = document.querySelector("canvas");
ctx = canvas.getContext("2d");

canvas.width = innerWidth;
canvas.height = innerHeight;

class Background {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawBackground() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

const backgroundSky = new Background(0, 0, canvas.width, canvas.height, "#89CFF0");
const backgroundGrass = new Background(0, canvas.height/1.2,canvas.width, canvas.height, "green");
backgroundSky.drawBackground();
backgroundGrass.drawBackground();

class Lens {
    constructor(x, y, radius, color) {
        this.x = x,
        this.y = y,
        this.radius = radius,
        this.color = color
    }

    drawLens() {
        ctx.lineWidth = 10;
        ctx.strokeStyle = "black";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI, false);
        ctx.stroke();
        ctx.fillStyle = this.color;
        ctx.fill();
    }
}

class Cross {
    constructor(x, y, width, height, color) {
        this.x = x,
        this.y = y,
        this.width = width,
        this.height = height,
        this.color = color
    }

    drawCross() {
        ctx.beginPath();
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
}

addEventListener("mousemove", function(event) { 
    mouseX = event.clientX;
    mouseY = event.clientY;
    const crossX = new Cross(mouseX, 0, 10, canvas.height, "black");
    const crossY = new Cross(0, mouseY, canvas.width, 10, "black");
    const lens = new Lens(mouseX, mouseY, 250, "transparent");
    backgroundSky.drawBackground(); // ⚠️
    backgroundGrass.drawBackground(); // ⚠️
    crossX.drawCross();
    crossY.drawCross();
    lens.drawLens();
});
* {
    margin: 0;
    overflow:hidden;
}
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <canvas></canvas>
        <script src="index.js" async defer></script>
    </body>
</html>
cam
  • 3,179
  • 1
  • 12
  • 15