HTML Canvas
<canvas> is a HTML element that we can draw graphics on it.
It is like a container for our graphics.
We can use JavaScript to draw graphics on <canvas>.
Demo
This demo is going to illustrate how to make lots of bouncing rainbow candies!
We need to have a canvas tag on our HTML file, which defines the area where we want to draw our graphics.
Then, we need to use JavaScript to select our canvas tag, and get the 2d context.
Then, we want to create a class to represent the candies.
Below is the skeleton of our Candy class. We will add more things to the class as we continue.
Let's fill out the this.draw function.
The job of this.draw is to draw the Candy represented by this Candy class on canvas. We need to pass ctx (the 2D context we get from canvas) to this this.draw function, and use ctx to draw a circle.
Now, let's try to instantiate this Candy class, call the draw function and see what happens.
As can bee seen from the above canvas, we have a red candy now. However, this candy is not moving.
To make the candy moving, we need to update the drawing for each given itnerval.
Let's fill out this.animate function.
After we have filled out this.animate function, we need to use browser's window.requestAnimationFrame() API.
This API is to tell browser that we want to perform an animation. Therefore, the browser will call the our specified function to update the object before re-painting.
More details can be found here: MDN web docs: requestAnimationFrame
So, instead of calling this.draw(), we want to make a wrapper function to wrap everything and pass this function to window.requestAnimationFrame().
Therefore, we can see this red candy is moving and bouncing in our canvas.
We can create more candies and apply the same things to get many colorful candies in the canvas.
<canvas
id="my-canvas"
width="400"
height="400"
style = "width: 400; height: 400;"
>
<canvas>
let canvasExample = document.getElementById("my-canvas");
ctx = canvasExample.getContext("2d");
Below is the skeleton of our Candy class. We will add more things to the class as we continue.
function Candy(x, y, radius, color) {
// x y represent the coordinate of the candy's position
this.x = x
this.y = y
// radius represents the radius of our candy.
this.radius = radius
// this is the color of our candy
this.color = color
// Two reversed directions
directions = [-1, 1];
// The incremental movements for x-axis and y-axis
this.xDirection = directions[Math.floor(Math.random() * directions.length)] * ((Math.random() * 5) + 1);
this.yDirection = directions[Math.floor(Math.random() * directions.length)] * ((Math.random() * 5) + 1);
// This function will draw the candy on the canvas
this.draw = (ctx) => {
// ...
}
// This function updates the candy properties and re-draw the candy
this.animate = (ctx) => {
// ...
}
}
The job of this.draw is to draw the Candy represented by this Candy class on canvas. We need to pass ctx (the 2D context we get from canvas) to this this.draw function, and use ctx to draw a circle.
this.draw = (ctx) => {
// Indicate that we are going to draw something
ctx.beginPath();
// Set the fill color
ctx.fillStyle = this.color;
// Draw an arc from coordinate x, y with given radius
// Start the angle from 0 to 2*pi, which forms a circle
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
// Call this function to fill the color
ctx.fill();
}
let candy = new Candy(100, 100, 10, "red");
candy.draw(ctx);
To make the candy moving, we need to update the drawing for each given itnerval.
Let's fill out this.animate function.
this.animate = (ctx) => {
// For each animatiton frame, we want to update the candy's position
// by the pre-defined movements of x-axis and y-axis
this.x += this.xDirection;
this.y += this.yDirection;
// Check if the candy hits the canvas boundaries.
// If the candy hits the boundaries, it should bounce back,
// so we reverse its direction by multiply it by -1
if (this.x + this.radius > ctx.canvas.width || this.x - this.radius < 0) {
// Reverse direction
this.xDirection *= -1;
}
if (this.y + this.radius > ctx.canvas.height || this.y - this.radius < 0) {
// Reverse direction
this.yDirection *= -1;
}
// After updating the candy's position and direction,
// re-draw the candy
this.draw(ctx);
}
So, instead of calling this.draw(), we want to make a wrapper function to wrap everything and pass this function to window.requestAnimationFrame().
let candy = new Candy(100, 100, 10, "red");
// Wrapper function
let startAnimation = () => {
// Before each re-painting, we need to clear previous painting from canvas
ctx.clearRect(0, 0, canvasExample.width, canvasExample.height);
// Call animate() to update Candy's movements and direction
candy.animate(ctx);
// Pass the wrapper function to browser's animation API
requestAnimationFrame(startAnimation);
}
startAnimation();
We can create more candies and apply the same things to get many colorful candies in the canvas.