Clearing HTML canvas

Viewed 71

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>

2 Answers

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>

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>

Related