what i learned last week: creating an animated 2d background with canvas and javascript
Tags: javascript
Published: 2021-09-30 13:41:42

Hello and welcome to this weeks blog entry where I'll [continue](https://dev.to/reyes2981/what-i-learned-last-week-how-to-make-a-bouncing-object-using-vanillajs-part-1-drawing-the-object-5eea) working on [Angry Borgs](https://github.com/reyes2981/angry_borgs_frontend), a 2D game I'm building using vanilla JavaScript for the frontend and Ruby on Rails on the backend. To review, I've successfully modeled physics to create a dynamic `player` object that can be controlled with the `spacebar`. 
<img width="100%" style="width:100%" src="https://media.giphy.com/media/kv1WNKj4J4Nn70ZALP/giphy.gif">
In this entry, I want to add more depth to Angry Borgs so I'm going to build an animated background. The final product for this blog will be a variation of this...
<img width="100%" style="width:100%" src="https://media.giphy.com/media/U7huVmA3TKuqvznInJ/giphy-downsized-large.gif?cid=ecf05e477566r7r89ykcw4f7sbiq9daydg3rni1jwuuumnln&rid=giphy-downsized-large.gif&ct=g">
First, I'll retrieve the `canvas` reference and store it inside a similarly named variable. Next, I need to initialize the context of the canvas element and store that in a variable named `ctx`.
```
const canvas = document.querySelector('canvas');// reference to the CANVAS element
const ctx = canvas.getContext('2d');
```
Next, I create a new [instantiation](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/Image) of the `Image()` constructor and store it inside of a variable. 
```
const backgroundImage = new Image();
```
Note, the above code has the same functionality as the code below. There is no "correct way" to use either form rather up to the situation and your best judgement. 
```
document.create('img');
```
Second, I want to reference the image I'm going to use as the animated background. I can do this by calling `src` on `backgroundImage` and then storing the file path as a string. 
```
backgroundImage.src = 'assets/bg5(1).jpg'; 
```
So far the code should look something like this...
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 
```
Now that we have our variables all set up, what is the next step? We need to not only build out the logic of the program but also organize it. In this case, I'm going to create a `draw()` [Function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions).
```
function draw() {
}
```
Next, we are going to reference the canvas using [`clearRect()`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clearRect) which is a method of the Canvas 2D API [that] erases the pixels in a rectangular area by setting them to transparent black. For this example I want to clear out the entire browser screen so I passed in the following arguments:.
```
x-coordinate = 0,
y-coordinate = 0,
width = canvas.width
height = canvas.height

clearRect(0, 0, canvas.width, canvas.height)
```
<img width="100%" style="width:100%" src="https://media.giphy.com/media/3gPKkEhk8IYwNV3sJI/giphy.gif?cid=ecf05e47nrisixjintxpde9jmaw9fy38vohqj7anz470mf24&rid=giphy.gif&ct=g">
Let's review all of the code I have so far and debug, debug, debug!
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 

function draw() {
clearRect(0, 0, canvas.width, canvas.height)
}
```
If we run the above code what do you think will happen on the browser side? 
![parllx1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/554gk2ez5a0rr3ogl0w3.png)
_NADA!_
Let's call `draw()` and see what happens 
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 

function draw() {
clearRect(0, 0, canvas.width, canvas.height)
}
draw()
```
![parllx2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kq0r7afbhrwc7fx2izib.png)
Sweet, we got an error! 
![parallx3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ewrroxebgx1g6d5pwq4h.png)
The error says `clearRect` is not defined but if you look at the code it's clearly there. Why is there an error? The answer - `clearRect` is a method of the Canvas 2D API. When I run the below code the program has no idea what that function is. How is this fixed?
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 

function draw() {
clearRect(0, 0, canvas.width, canvas.height)
}
draw()
```
You simply need to call `clearRect()` on your `ctx` variable. Remember, `ctx` initializes the context of the canvas element. 
```
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
```
Success! 
![parllx4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jk5he1m0mfvepd2lulfl.png)
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 

function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
draw()
```
Next, within `draw()` I'm going to be using the `requestAnimationFrame()`method which tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.
```
function draw() {
console.log('hello from the draw function')
ctx.clearRect(0, 0, canvas.width, canvas.height)
requestAnimationFrame(draw);
}
```
Sweet, quick review of the code so far!
```
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg'; 

function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
requestAnimationFrame(draw);
}
draw()
```
Next, I'm going to use [`drawImage()`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) which is a method of the Canvas 2D API [that] provides different ways to draw an image onto the canvas. I want to fill out the entire browser screen so I passed in the following arguments:.
```
image = backgroundImage,
x-coordinate = 0,
y-coordinate = 0,
width = canvas.width,
height = canvas.height

ctx.drawImage(backgroundImage, backgroundImage, 0, 0, canvas.width, canvas.height);
```
Awesome, let's head over to the browser and check if we see the image.
```
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);

requestAnimationFrame(draw);
}
```
![parllx6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w5svyi6qnoh5x2e0t33r.png)
<img width="100%" style="width:100%" src="https://media.giphy.com/media/3ohzdIuqJoo8QdKlnW/giphy.gif?cid=ecf05e47fz7oxpm1pwvgzdvc957w1r5okv7ycpdxgabm47wo&rid=giphy.gif&ct=g">
Finally, I don't need a static image I need a dynamic one and I can do that with the following code...
```
backgroundImage.x -= 0.1;
``` 
The above code tells the program to move the `backgroundImage`s x-axis an x-amount of distance. Let's see the final code for better, no pun intended, context.
```
const canvas = document.querySelector('canvas');// reference to the CANVAS element
const ctx = canvas.getContext('2d');
const backgroundImage = new Image();
backgroundImage.src = 'assets/bg5(1).jpg';

function draw() {
console.log('hello from the draw function')
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
backgroundImage.x -= 0.1;
requestAnimationFrame(draw);
}
draw();
```
As you can see above, when the `draw()` function is called it initializes a canvas element, then draws out an image, next the image's x-axis is moved an x amount of distance and finally it "hits" the `requestAnimationFrame()` method where a loop is created. 
<img width="100%" style="width:100%" src="https://media.giphy.com/media/9KERatxMbLWcbf2siJ/giphy.gif?cid=790b7611ef4bbccfe75187b3747ecb97562e4670029c9c6c&rid=giphy.gif&ct=g">

_FIN!_

Thank you for reading.

Say Hi on [LinkedIn](https://www.linkedin.com/in/noe-camarena-b0741467/)! I'm always open to connecting, networking and new opportunities. 

and/or

Checkout my [Github](https://github.com/reyes2981).

RESOURCES
https://dev.to/ibrahima92/make-a-parallax-effect-with-10-lines-of-javascript-3hia
https://luka712.github.io/2018/12/02/Parallax-scrolling/
https://www.youtube.com/watch?v=Mg7ibYWhjPI