Now that we understand that Canvas is an immediate mode graphics API, we can look more at what commands it gives us for doing drawing.
Canvas provides a rich set of options for creating shapes and coloring and styling them. We won't talk about all of them here, but I'll give you the basic options and then encourage you to go out onto the web to read and to try things on your own.
I recommend reading this page first and then going on to other web resources (listed at the end of this page). I'll try to explain the concepts, and point you to things that give details.
You might wonder why I don't put "live code boxes" where the actual code that gets run appears on the page itself and you can read and tinker with it in place. Most of the better tutorials on the web do this. And its great since the code is right there in the text, and it is really easy to tinker with.
I have tried this in the past. However for CS559, we very quickly get to more complex programs where you will want to use "real tools", so I want you to get used to that with the simple examples. I wanted you to see from the very start how we structure programs. I wanted you to be able to use the debugger.
But this means that (1) you will actually have to go looking at the source code files, and (2) when I do put a snippet of code on a web page, it will be "marked up" as HTML, which makes it harder to look at the HTML.
On page 1 we saw a few simple examples. I will repeat the simplest one here.
Understanding this is quite important, so I'll put the actual drawing code here in the html:
let canvas1 = document.getElementById("canvas1")); let context1 = canvas2.getContext('2d'); context1.fillStyle = "#F00"; context1.fillRect(30,30,30,30);
Line by line:
canvaselement from the DOM. The element is just like any other HTML element.
Now, look at the official Mozilla Tutorial (which I recommend!), and get more details. You can see a few differences - these are worth pointing out:
onloadevent handler for the Canvas, whereas we put the handler into the
onloadevent for the entire page. Either way, we cannot draw into the canvas element until it has been created, so we need to draw after it has been. For us, we wait until the entire page (including the canvas element) has been created.
You may have noticed that when we drew the rectangle, we "filled" its inside with the red color (
In Canvas, we can apply styles (like colors) to both the insides and outsides of shapes (like rectangles). The inside is the "fill" and the outside is the "stroke" (as in, you make a stroke with a pen to draw the outline or boundary of a shape).
You can look at the Official Documentation to see more about what styles are available (including non-constant fills).
But... I want to point out another key concept hidden in that example. When you set a drawing state, it stays for the next object. So, for example, when square 3 in the previous example set dashed lines, the next square also got it (whether it wanted it or not). In the simple example, we can see what is going on - but in a more complex example, the state might get set by some code somewhere very different.
Since the green square didn't know what happened before it, if it wants something specific, it has to reset all of the different pieces of the state!
Instead, a better idea is to have drawing an object "clean up" after itself. If we set some state to draw an object, we set it back before going on to the next one (unless we're sure it wants our changes). To simplify this convention, stated APIs (like Canvas) allow us to "save" and "restore" the state. Observe (and look at the source code!):
Saving and restoring works like a stack: if you save twice, it makes a stack of the two saves. Each restore takes something else off of the stack.
Notice how this leads to nesting, or "hierarchy". We will use this concept (save/restore with a stack) for many things in graphics.
If rectangles (or any shape, for that matter) overlap, the shape that is drawn last covers over anything that was drawn before it. This is like painting with thick paint - we see the last thing drawn. Here is an example:
Of course, if we don't fill, then we don't cover over things inside the rectangle.
Drawing order effects commands that draw the same rectangle (the stroke vs. the fill). The stroke and fill share some of the same area (since the stroke is centered on the line around the filled area, the fill covers half the stroke). Here is another example of order change...
All of our colors so far have been opaque - they cover over what is behind them. We can also make semi-transparent colors. That is, the color lets through some of what's behind it. To do this, we extend our colors with an extra number: the opacity (or alpha). In addition to an amount of red, green, and blue, we add a forth number that is the amount that it covers what is behind it. By default, this is 100% (or 255/255), so things are opaque. But most places where we specify 3 numbers, we can specify a forth - so to make red that only blocks 50% of what it covers, we can say
7F is 127, or about half of 255).
Remember that drawing order matters - the transparent thing covers what was there before it. Things drawn afterwards will cover the transparent thing. Also, the transparent things will let the background (white) through if that is what they cover.
Here is a simple example:
We are using the simple math for transparency (it's called alpha-blending). We discuss it in class. There are more ways to combine the colors. Canvas supports many of them, but we might not get to learn about them in class.
Note that in the code, I specified colors as
rgba(255,0,0,.5) rather than
#FF00007F. Also, notice that the stroke can be transparent, and we can have transparent dark and light colors.
Canvas has 2 kinds of shapes: rectangles, and everything else. There are also images and text (which I guess are shapes too).
To make a path based shape, you define a "path" - which is basically the outline of the shape, and then you can stroke and fill that. Just as the rectangle had
strokeRect paths have
fill. The biggest difference is that rather than telling stroke and fill what the shape is, it uses the current path. That is, the current path is part of the context, the same way things like fill color and line width are.
The official documentation is the best place to look Mozilla Canvas Shape Tutorial. You can skip over curves for now - we'll learn about them in a few weeks.
Make sure you understand how to make paths, and use them to draw with Canvas. And note that to make a circle, you need to draw an arc that has
2*Math.PI radians of arc to it.
Now we've seen the basics of drawing with Canvas. On the next page, you'll get to try it out. (A02_p3.html).
From this page, make sure you understand the concepts (like drawing state).
You will want to learn more about Canvas drawing (so you can make more interesting pictures). Some of the things (like curves and transformations) we'll introduce in the coming weeks as we introduce the graphics concepts in class. For now, focus on making shapes and giving them styles.
Here are some resources to look at (you don't have to read them all, but do read some beyond just this tutorial):
Ok, now move on to the next page to try this out!