The first of the Canvas bitmap operations that we need to look at is the drawImage method, which draws a bitmap onto a canvas. What is interesting about this method is not so much that it provides a link between a bitmap and the canvas object, but the range of bitmap sources that can be used.
The source for a bitmap can either be a bitmap object, another canvas object or a video object. Notice that if you are using a canvas object as the source of the bitmap you have to have actually drawn something on it first and you have to use the canvas object not the drawing context - see later for an example. If you use a video object then the current frame is rendered to the canvas.
To start with the simplest example, you can take any standard Image object and draw it to the canvas. You can derive your image object from the DOM or create it directly within JavaScript. For example, suppose the page contains an image in img then you can then display it on the canvas, with the 2D drawing context stored in ctx using:
ctx.drawImage(img,10, 10);
The drawImage method takes a number of different parameters, but:
drawImage(image,x,y)
simply draws as much of the image as can fit on the canvas with its top left corner at x,y:
The complete program is:
async function getImage(url) {
var img = new Image();
img.src = url;
await imgLoaded(img);
var ctx = document.body.appendChild( createCanvas(600, 600)).
getContext("2d");
ctx.drawImage(img,10, 10);
var img1 = getImage("jeep.jpg")
and makes use of imgLoaded given in the previous section.
If you want to scale the image then use the alternative form of the drawImage method:
drawImage(image,x,y,w,h);
where w and h specify the width and height that the image is scaled to.
For example:
ctx.drawImage(img,10,10,300,300);
The problem here is that you might well distort the bitmap by scaling it unequally in the x and y directions. The solution is to use the object's img.width and img.height properties:
Notice that if you don't specify a width and height when you create the image then these are set to the naturalWidth and naturalHeight properties.
The final form of the drawImage method gives you complete control over the way the image is drawn:
drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
This looks complicated, but it simply specifies the location of a source and a destination rectangle. The source rectangle has its top left corner at sx,sy and is sw wide and sh high. The destination rectangle has its top left corner at dx,dy and is dw wide and dh high. The drawImage copies pixels in the source rectangle to the destination rectangle, performing any scaling that is needed. For example, to display the area of the bitmap cropped and scaled to show the jeep you would use:
Notice that both the source and destination rectangles are scaled versions of the full image size. If you want to avoid distortion, this is the usual method.
Finally you can use all three versions of the drawImage method with another canvas object as the source of the bitmap. For example:
ctx2.drawImage(ctx.canvas,0,0);
will draw the contents of canvas onto the drawing context ctx2 of another canvas object.
You can also draw a canvas object onto itself. For example:
ctx.drawImage(ctx.canvas,0,0.200,200);
will copy the contents of the canvas object back onto itself in a 200 by 200 rectangle if ctx is the drawing context of the canvas object. Notice that the source bitmap is copied before it is drawn back to the canvas so there are no strange interactions between source and destination.
So to summarize:
There are three drawImage methods:
drawImage(image,dx,dy)
drawImage(image,dx,dy,dw,dh)
drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
where image is either a canvas, video or an image object derived either from the DOM or constructed in JavaScript, and sx,sy,sw,sh define the source rectangle and dx,dy,dw,dh define the destination rectangle.
In chapter but not in this extract:
ImageBitmap
Animation
Draw or BitBlt?
The Problem of Speed
Position, Speed & Acceleration
Using BitBlt
Raw Animation
Summary
The fundamental way of getting bitmaps into a web page is to use the <img> tag or the Image object.
Loading an image is always asynchronous. There is no way to pause and wait for an image to load, no matter how hard you try.
The only way to handle asynchronous image loading is to use the onload event handler.
A more modern approach is to wrap the event handler in a function that returns a Promise. The function can then be used with async/await to make the asynchronous operation look perfectly like a synchronous load.
Once you have an image loaded, you can use the drawImage method to draw the pixels to a canvas.
ImageBitmap is the new and faster way to source a bitmap for a canvas.
Animation can be achieved by repeated drawing of the animated object or by drawing a bitmap into a new location – BitBlt. In most cases blitting is faster.
You can arrange to take into account the time between frames to determine how far an object should have moved.
Animation is often best organized around the idea of a sprite, a shape with position, velocity and acceleration.
Sprites are perfect for implementation using object-oriented methods. Doing this loses about 1/3 of the speed you can achieve using a non-object-oriented, direct implementation.
Now available as a paperback or ebook from
Amazon
.