Canvas has a very powerful API called drawImage() (w3c):
Its main function is to draw pictures, videos, and even other canvases.
question:He came here in admiration, but missed the mark. When he lowered his head, he saw a big hole on the ground.
The thing is like this, after I read the introduction of w3c and the very convincing and teaching demo, I decided to give it a try based on the idea of practicing to gain true knowledge. It doesn’t matter if I try it~
I laid out the following basic tasks according to the assembly line project:
1. canvas tag+id
<canvas id=canvas1></canvas>
2. Get canvas + set width and height
var cav1 = document.getElementById('canvas1'), wWidth = 800, wHeight = 600; cav1.width = wWidth; cav1.height = wHeight;3. getContext('2d') prepares the canvas
var ctx1 = cav1.getContext('2d');4. Create a new Image() object and give it the attributes of the pictures I like... (don’t think too much)
var bgImg = new Image();bgImg.src = 'images/background.jpg';
5. Finally it’s time to draw. I excitedly wrote this code:
ctx1.drawImage(bgImg,0,0,wWidth,wHeight);
Flustered, I pressed F5 on the browser.
Then there was dead silence...
I thought the code was written wrong, so I went back and checked it carefully, and it was correct.
Copy the key attribute names and methods of w3c and check again. It is indeed correct.
When the picture is printed out, there is also this picture (of a person)!
Later, when I observed the W3C case, the difference from my code is that its images are in HTML.
Then I learned to insert pictures into html,
<img src=./images/background.jpg id=imgs style=display:none></img>
And use getElementById to get this element,
var bgImg = document.getElementById('imgs')Executing drawing again worked.
He actually can!
I think sadly, does it have to be physical? Isn’t it just placed in front of the canvas tag? js loading also has entities, and I still use new, how different than real people!
That's right, isn't it just placed in the front? This involves a sequence issue!
It is true that the image loaded in js is placed in front of the drawing, but it will take some time to load the image. Time needs to be given for image buffering. Wait until the image is loaded successfully before you can draw it. The drawImage method will not be called when the image is used before it has been loaded. Drawing will fail. I see!
Do some people argue that pictures in img tags don’t take time to load? At this time drawImage is not restricted? ! But don’t ignore the window.onload at the beginning of js. Even if the image is loaded slowly, even if the order of the image tags is after the canvas tag, but I have window.onload covering it, my image cannot be loaded, and your drawImage will No chance, right?
The approximate order is this:
<img src=>window.onload = function(){ drawImage}If the image was not inserted in the html structure, this restriction would have been bypassed by my carelessness:
When a picture is requested as a resource and loaded in js, there will naturally be a loading time for the picture.
But because there is no limit, in most cases drawImage is called when the image has not been loaded, and this method will not work.
solve:So is there a good way to solve the problem of drawImage drawing failure due to the image loading sequence?
I have summarized the following three methods:
1. tag+window.onload <img src=>window.onload = function(){ context.drawImage()}The core solution of this approach is onload, which loads the image and drawImage separately. The img is loaded first to ensure that the drawing is used after the loading is completed.
1-2. Insert tags later? Is it feasibleOne situation is that when using the screenshot function, you can also use drawImage, and the screenshot does not take a screenshot of your own existing image, but uses the address of an image as a parameter.
I think this kind of thing requires js to create an img and assign the address to it. Then generate the image and take a screenshot.
var myImg = document.createElement('img');myImg.src = '///';document.body.appendChild(myImg);ctx1.drawImage(myImg,0,0,wWidth,wHeight);Don't want to add extra tags? Do I need to use js as shown below to create a new image object?
var bgImg = new Image();bgImg.src = 'images/background.jpg';
As mentioned before, this kind of image created using new Image() requires time to buffer the image. Wait until the image is loaded successfully before you can draw it.
The image object is ready, but how do you know when the image is actually loaded? Well, there is another way:
While the js task is being executed, do you think I am too close to your execution time? Can you take me out alone and queue me up again, and then execute it again later?
2. Timer asynchronous implementation setTimeout(function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight);},10)Why is the delay in writing 10 here instead of the familiar 1000 or 0?
Because under the test of my specific wifi environment and specific desktop computer, 10 can just show up after the image is loaded, unlike 0 which does not come out, and I don't want to wait for half a day like 1000.
But imagine if you change the picture to a larger one, would this 10 still apply? Will this 10 still apply if the wifi is changed to 2g?
Therefore, the disadvantage of the timer is that there is no guarantee that the image will be loaded after the time is up. If the network is not fast, it will still hang up.
3. img.onloadwindow.onload gives us an idea. Can't we directly monitor the loading completion?
Use the loading event of img to monitor the successful loading of the image, and then execute the drawing effect of the canvas. And this method is more reliable.
bgImg.onload = function(){ console.log('Image loaded successfully'); console.log(this); ctx1.drawImage(bgImg,0,0,wWidth,wHeight); }In fact, these three methods all have the same core, which is to let the image load first. That is, image preloading. But for cached images, image preloading also needs to solve the problem of monitoring cached images when the page is not refreshed.
Found another problem. . . . First, here’s what the background painting looks like after finishing it.
Then the background picture finally came out, and I continued happily.
So I immediately drew a red line. In order to avoid not seeing it, I also increased the width to 20:
bgImg.onload = function(){ ctx1.drawImage(bgImg,0,0,wWidth,wHeight); } /* Draw the red line as follows: */ ctx1.beginPath(); ctx1.moveTo(10,wHeight); ctx1.lineTo (10,wHeight-100); ctx1.lineWidth = 20; ctx1.strokeStyle = 'red'; ctx1.stroke(); ctx1.closePath();But when I press F5, there is still no change, and I still can’t see the red line.
After searching for a long time, I didn’t see it until I turned off the background image:
Ah, it turns out he was covered by the background image!
But why?
I'm thinking there are two possibilities
1. Hierarchy issues
2. Sequence issues
Regarding 1, it feels like the z-index of CSS, where the background image covers the red line. Could it be that the level of the background image is higher than the red line?
I had no way of testing this hypothesis, so I gave up on the second possible reveal.
But why is the background image at the top? Is it because the background image is drawn later?
This can be most easily observed through console.log() printing to observe the execution sequence.
It turns out that the culprit is the onload callback. Like the timer, it is an asynchronous task. Naturally, it is ranked behind the synchronization task (drawing lines below)
So onload seems to be a good solution, but its shortcomings are also exposed here.
Very good, it seems that the promise learning plan should be put on the schedule as soon as possible! Hahaha
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.