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.