Reputation: 1331
I am trying to use an image as the background of my canvas. However, I have a hard time to make the image load -- it always shows as blank:
<html>
<script>
var background = new Image();
background.src = "img/map.png";
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
window.onload = function() {
ctx.drawImage(background, 0, 0);
}
</script>
<body>
<canvas id="myCanvas" width="400" height="400"> </canvas>
</body>
</html>
However, if I put the following two lines into the window.onload function, then the image loads without any issue. what causes this issue? As I will use canvas and ctx in other functions, I really want to define them globally rather than individually define them in each function.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
Upvotes: 0
Views: 815
Reputation: 1295
1) The first option is to declare the canvas and context and assign them values after the document has loaded
<!DOCTYPE html>
<html lang="en">
<head>
<title>Onload</title>
<script>
const background = new Image();
background.src = "img/map.png";
let canvas;
let ctx;
window.onload = function() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.drawImage(background, 0, 0);
}
</script>
</head>
<body>
<h1>Method One</h1>
<p>Defined variables globally and assign then after the load event is fired</p>
<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
</html>
2) The second method would be to put the script block after the canvas element so that it is already loaded in the DOM when your javascript tries to access it.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Onload</title>
</head>
<body>
<h1>Method Two</h1>
<p>Put the script after the DOM element you wish to access</p>
<canvas id="myCanvas" width="400" height="400"></canvas>
<script>
const background = new Image();
background.src = "img/map.png";
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
window.onload = function() {
ctx.drawImage(background, 0, 0);
}
</script>
</body>
</html>
I've used the new const
and let
keywords just to highlight the difference between these two approaches, although using var
instead will work fine too. (see let and const)
If you want to avoid global variables then you might structure your code like this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Onload</title>
<script>
const background = new Image();
background.src = "img/map.png";
draw = context => {
context.drawImage(background, 0, 0);
}
window.addEventListener('load', () => {
const canvas = document.querySelector("#myCanvas");
const ctx = canvas.getContext("2d");
draw(ctx);
});
</script>
</head>
<body>
<h1>Refactor</h1>
<p>Add an event listener and pass in context to draw function</p>
<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
</html>
It doesn't matter that I'm using arrow functions, or querySelector, I just prefer these newer methods. The point is to pass in the canvas context to any function that needs it draw(ctx)
.
The two lines of code creating the Image()
and then setting the background had to be done before the document had finished loading, this is a bit of a fudge. What we really need to do is make sure that the image we are trying to set as the background has loaded before calling drawImage()
Using images
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Onload</title>
<script>
draw = context => {
const background = new Image();
background.src = "img/map.png";
background.addEventListener('load', () => {
context.drawImage(background, 0, 0);
});
}
window.addEventListener('load', () => {
const canvas = document.querySelector("#myCanvas");
const ctx = canvas.getContext("2d");
draw(ctx);
});
</script>
</head>
<body>
<h1>Final</h1>
<p>Add an event listener to the image</p>
<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
</html>
Upvotes: 1
Reputation: 4574
you can still use them globally. As canvas is not available immediately you are not able to draw picture before on load.
<script>
var background = new Image();
background.src = "img/map.png";
var canvas;
var ctx ;
window.onload = function() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.drawImage(background, 0, 0);
} </script>
Upvotes: 1