Making Four-In-A-Row Using JavaScript - Part 6: Blank Canvas
Colin Kiama
Posted on May 27, 2023
Intro
First of all, great job following along with this series! You've completed the first 50% of this tutorial so far!
In the previous blog post, you reorganised the project in preparation for work on the front end of the game. This is the post where the work starts.
Here's your expected outcome at the end of this tutorial:
Here's a breakdown of the image above:
- Top part: Status Area - Displays the colour of the current player's turn as well as a status message explaining what's happening in the game.
- Middle part: Game Board - Displays where players have placed their tokens in the game.
- Bottom Part: Play Again Button: Restarts the game. Shows up when the game is over.
This post will be focused on setting up the canvas - where each part of the game will be displayed on.
Setting Up Constants (Again)
In the same way that you created a constants file for the game logic, you'll also need to create one for the front end.
Create a new directory in src
called constants
then, inside the directory you've just created (src/constants
), create a called index.js
with these contents:
export const FrontEndConfig = {
GAME_BACKGROUND_COLOR: "#122A67",
};
export const StatusMessages = {
DRAW: "DRAW!",
YELLOW_TURN: "YELLOW PLAYER'S TURN",
RED_TURN: "RED PLAYER'S TURN",
YELLOW_WIN: "YELLOW PLAYER WINS!",
RED_WIN: "RED PLAYER WINS!",
};
export const StatusAreaConfig = {
HEIGHT: 100,
PADDING_TOP: 40,
INNER_MARGIN: 28,
INDICATOR_WIDTH: 16,
};
export const BoardConfig = {
WIDTH: 284,
HEIGHT: 242,
MARGIN_TOP: 20,
MARGIN_LEFT: 18,
HORIZONTAL_PADDING: 18,
VERTICAL_PADDING: 16,
SLOT_MARGIN: 8,
SLOT_WIDTH: 28,
BACKGROUND_COLOR: "#1D48B8",
SLOT_OUTLINE_COLOR: "#225FFD",
};
export const TokenColor = {
NONE: "#D9D9D9",
YELLOW: "#EAC02B",
RED: "#EA2B2B",
};
export const PlayAgainButtonConfig = {
WIDTH: 128,
HEIGHT: 40,
TEXT: "Play Again",
MARGIN_BOTTOM: 80,
BORDER_WIDTH: 1,
BACKGROUND_START_COLOR: "#225FFD",
BACKGROUND_END_COLOR: "#1D48B8",
};
Setting Up The Canvas
Adding Canvas To The Body
First, you'll need to add the <canvas>
element to the <body>
of the page. It'll need to have a width
of 320, a height
of 480, and an id
of "canvas". You do this in index.html
. It should look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Four in a row</title>
</head>
<body>
<canvas id="canvas" width="320" height="480"></canvas>
<script src="src/index.js" type="module"></script>
</body>
</html>
Referencing The Canvas In Javascript
Next, you'll reference the <canvas>
element that you've added to the page from JavaScript.
Create a new file called in the src
directory called FrontEnd.js
. This will handle the front-end logic of the game.
Add the following code to the file you've just created:
export default class FrontEnd {
constructor(game) {
this.game = game;
}
}
The constructor of the FrontEnd
class has a parameter called game
which contains an instance of the FourInARowGame
class. The FourInARowGame
instance will be stored in the FrontEnd
class in the game
field. This will be used to update and retrieve the core game's state.
Next, you'll set up the canvas.
In the FrontEnd
class's constructor, obtain a reference to the canvas element on the page and store it in a class field called canvas
:
export default class FrontEnd {
game;
canvas;
constructor(game) {
this.game = game;
this.canvas = document.getElementById("canvas");
}
}
Next, set 2 more fields called width
and height
to the canvas' width and height respectively:
export default class FrontEnd {
game;
canvas;
width;
height;
constructor(game) {
this.game = game;
this.canvas = document.getElementById("canvas");
this.width = canvas.width;
this.height = canvas.height;
}
}
This will come in handy later once you start drawing on the canvas.
Lastly, set the background of the canvas:
import { FrontEndConfig } from "./constants/index.js";
export default class FrontEnd {
game;
canvas;
width;
height;
constructor(game) {
this.game = game;
this.canvas = document.getElementById("canvas");
this.canvas.style.background = FrontEndConfig.GAME_BACKGROUND_COLOR;
this.width = canvas.width;
this.height = canvas.height;
}
}
Now let's see if you've referenced the canvas element properly.
In src/index.js
, update the code to create a new instance of the FrontEnd
class:
import { FourInARowGame } from "./gameLogic/index.js";
import FrontEnd from "./FrontEnd.js";
let frontEnd = new FrontEnd(new FourInARowGame());
If you run an HTTP server and check the address it's pointing to, you should see a blue rectangle (That's the canvas you've created!):
Drawing on the canvas
Let's proceed to draw on the canvas. To do this you'll need to get a 2D canvas rendering context. Another way to think about this is that you're getting a set of art supplies (paints, paintbrushes, stencils, etc.) made for creating 2D drawings.
You'll set this rendering context object in the context
field of your FrontEnd
class:
import { FrontEndConfig } from "./constants/index.js";
export default class FrontEnd {
game;
canvas;
width;
height;
context;
constructor(game) {
this.game = game;
this.canvas = document.getElementById("canvas");
this.canvas.style.background = FrontEndConfig.GAME_BACKGROUND_COLOR;
this.width = canvas.width;
this.height = canvas.height;
this.context = this.canvas.getContext("2d");
}
}
Next up, you'll need to scale the canvas for high-resolution displays to prevent issues with blurry drawings.
First, create a method called enableHiDPIDisplaySupport()
in the FrontEnd
class:
export default class FrontEnd {
// ...
enableHiDPISupport() {
// Get the DPR and size of the canvas
const dpr = window.devicePixelRatio;
const rect = this.canvas.getBoundingClientRect();
// Set the "actual" size of the canvas
this.canvas.width = rect.width * dpr;
this.canvas.height = rect.height * dpr;
// Scale the context to ensure correct drawing operations
this.context.scale(dpr, dpr);
// Set the "drawn" size of the canvas
this.canvas.style.width = `${rect.width}px`;
this.canvas.style.height = `${rect.height}px`;
}
}
Now call the enableHiDPIDisplaySupport()
method in the FrontEnd
class constructor:
export default class FrontEnd {
constructor(game) {
this.game = game;
this.canvas = document.getElementById("canvas");
this.canvas.style.background = FrontEndConfig.GAME_BACKGROUND_COLOR;
this.width = canvas.width;
this.height = canvas.height;
this.context = this.canvas.getContext("2d");
this.enableHiDPIDisplaySupport();
}
// ...
}
You're now ready to start drawing on the canvas.
Create a method called start()
in the FrontEnd
class and draw a white rectangle with a width of 50
and a height of 100
:
export default class FrontEnd {
constructor(game) {
// ...
}
start() {
this.context.fillStyle = "white";
this.context.fillRect(20, 20, 50, 100); // fillRect(x, y, width, height);
}
}
Now go back to src/index.js
and call the start()
method on the FrontEnd
class instance that you created:
import { FourInARowGame } from "./gameLogic/index.js";
import FrontEnd from "./FrontEnd.js";
let frontEnd = new FrontEnd(new FourInARowGame());
frontEnd.start();
Now, if you check your project with an HTTP server, in your browser, you'll see a blue canvas with a white rectangle drawn on it:
Congratulations, you've covered the basics of drawing using the HTML5 Canvas API!
In the next post, you'll draw the game board on the canvas.
Thanks for reading!
Posted on May 27, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.