Page 1: Web Graphics APIs

CS559 Spring 2023 Sample Solution

While the workbook focuses on programming, we need to do a little “graphics 101” so you know some of the terms we need to describe what we’re doing.

Please read the following before we start:

  • (optional) Chapter 1 of Foundations of Computer Graphics - this is a good introduction to the book, but I am making it optional because most of it is advice on programming that doesn’t necessarily apply to us. However, this chapter is nice because it helps give you a sense of the tone of the book.
  • CS559 Tutorial: Image-Based vs. Object-Based Graphics - a bit of basic terminology.
  • CS559 Tutorial: What is a Pixel - if you think you know, make sure you understand the subtleties.
  • CS559 Color Tutorial - you may have already read this in Workbook 1.

Our focus in this class is on “object-based” or “vector” or “primitive-based” graphics, as opposed to “image-based” graphics (sometimes called “raster” graphics, but that is a historical term). You should have just read CS559 Tutorial: Image-Based vs. Object-Based Graphics to understand the difference.

The basic idea is that we create pictures not by describing the color of each pixel (as image-based graphics would do), but rather by using a set of “primitives” (basic objects) that we put together to make pictures.

Even though our display is ultimately an image, the APIs allow us to program in terms of objects/primitives. Something else (the implementation of the APIs) takes care of converting the objects to the image-based representation. This process of “coloring the pixels” is called rendering (although, sometimes the term rendering is reserved for the more specific version of converting 3D scenes to images).

2D Graphics APIs for the Web

For doing object-based (2D) graphics on web pages, there are two main APIs: Canvas and SVG. The naming of canvas is a little unfortunate - not only does it have the same name as the learning management system we use at UW, it also refers to more than just the 2D drawing API. It might be more precise to say the canvas 2D drawing API - but that’s a mouthful. In general, I’ll just refer to it as “Canvas”.

In class, we’ll mainly be using Canvas, but we will look at SVG as well. For the purpose of this workbook, SVG is important because it represents a very different kind of API than Canvas. They both do similar things, but they do it in very different ways. Beyond class, SVG is important because it is often used to make diagrams.

An important distinction we can make for graphics APIs is between immediate vs. retained mode.

  • Immediate mode APIs draw immediately. When you make a function call to create, for example, a rectangle, the rectangle gets drawn immediately. (Conceptually) The system colors the pixels right away. In practice, you may not see the changes immediately (more on that in a bit). But, when you make a drawing call (like to the rectangle function), conceptually, the system colors the pixels. It forgets why it colored the pixels after it’s done. Canvas is an immediate mode API.
  • Retained mode APIs create a list of objects that are drawn on demand. Function calls create objects in some storage (e.g., a list of objects), and eventually this list is drawn. The system remembers the objects, and refers to these when coloring the pixels. SVG is a retained mode API. Retained mode APIs are sometimes called display-list APIs since they keep a list of things to display.

This distinction will become clearer as we work through some examples.

Box 1: Graphics Elements

Web pages are made up of elements - like paragraphs, headings, and buttons, we learned about that in the previous workbook.

To do graphics, we make special elements that give us a rectangular region that we can draw in. For the Canvas API (and actually some other APIs), we create “canvas” elements using the canvas tag. For SVGs, we create “svg” elements using the SVG tag.

Here’s an example with one of each, side by side - 02-01-01.html:

Note that these are normal HTML elements. We can give them ids (and classes), as well as styling them (here they have red borders). In fact, we can use CSS to style them.

By themselves, these elements are pretty boring - we need to write some JavaScript to make them more interesting by drawing something in the box. SVGs will have an alternative, but we’ll get to that later.

Box 2: Drawing 2 Ways

Now I am going to use those same boxes, but draw in them. The HTML is basically the same as box 1. The difference is that the JavaScript is going to add a rectangle to each. Be sure to go look at the JavaScript in 02-01-02.js, which gets loaded at the end of the HTML file 02-01-02.html. You probably want to look at it (and any .js files) in vs code, rather than your browser, to get proper syntax highlighting.

You might notice that this code (and almost all of the examples in this workbook) do not use the window.onload event. Because we load our scripts, we can defer their execution using the script tag.

The canvas code (with comments removed) looks like:

1
2
3
4
let canvas = document.getElementById("canvas1"));
let context = canvas.getContext('2d');
context.fillStyle = "#F00";
context.fillRect(30,30,30,30);

On line 1 (which is line 15 of 02-01-02.js, we find the canvas element (that we have given the id “canvas1” when we made it in 02-01-02.html). We need to find the element to draw in it.

On line 2, we pull the context object from the element - this is the object that actually takes care of drawing.

On line 3, we set the color that we are going to draw (the fillStyle). If you don’t remember why #F00 is red, please review the CS559 Color Tutorial.

On line 4, we actually draw the filled rectangle. The first 30,30 means put the top left corner 30 units to the right and 30 units down from the top of the element, and make the square be 30 units wide and 30 units high. In both SVG and Canvas, Y is measured downwards - this is different than you might be used to from math classes. We’ll come back to talk about this later.

The fillRect function draws the rectangle “immediately” - it colors the pixels in the element. No rectangle is actually remembered - once the function is done, all that’s left are the pixels. The browser might not show you things immediately (it might wait to see if other things will be drawn). It might seem obvious, but fillRect draws with the “current color” (that we had set with the fillStyle variable).

SVG is a very different kind of API. The graphics objects (like the rectangle) are actual objects on the web page (in the DOM - document object model, which you should remember from last week). The rectangle will be an object just like the spans of text, buttons and sliders we saw last week.

The SVG example works very differently than the Canvas one. This is slightly simplified (you can see the actual code in 02-01-02.js which has comments that explain the missing details).

1
2
3
4
5
6
7
8
let svg = document.getElementById("svg1");
let square = document.createElementNS('rect');
square.setAttribute("x", "30");
square.setAttribute("y", "30");
square.setAttribute("width", "30");
square.setAttribute("height", "30");
square.setAttribute("fill", "#F00");
svg.appendChild(square);

Just like with canvas, we start by getting the element we’re drawing in (with id svg) on line 1 (which is line 43 of 02-01-02.js). Line 2 is where things get very different: note that we make an element in the DOM - just like we would make a button or piece of text or any other HTML element. The rectangle is a rect element - part of the HTML page, just like any other element. Once we’ve created this element, it stays around. We can set its properties (its position, size and color), and we can add it as part of the SVG element (on line 8).

Note the contrast: with SVG, we made a rectangle object that stays around (since SVG is a retained API - we retain the objects). With Canvas, once we draw and color the pixels, the rectangle only exists to the extent that the pixels are colored.

For this simple example, there isn’t much difference.

When you look at the actual code in 02-01-02.js, you’ll notice that when we make the rect element, we need an extra parameter that tells the web browser that rect is a kind of SVG element.

Box 3: Moving Squares

Here’s a more interesting example that shows the difference between Canvas and SVG…

Again, look at the code (since this is box 3 of page 1, it’s 02-01-03.js). You should recognize the animation loop using requestAnimationFrame from the previous workbook.

For each frame, we update the position of the rectangle (variable newX is set by reading the clock). But how we cause the square to appear in the new place is completely different.

For SVG, we simply need to change the position of the square we had created earlier.

With Canvas, there is no “earlier square” (since it was immediately turned to pixels). To draw a square in a new place, we need to draw a new square. But before that, we need to get rid of any old stuff (by clearing the picture using clearRect). Then we draw a new blue square.

This example hopefully highlights the difference between the immediate mode API (Canvas) and the retained mode API (SVG). In retained mode, the primitives (in this case the square) are represented as data. To move them, we change the data structure. In immediate mode, the primitives are drawn - they are only represented in the code. To animate things, we need to erase the picture and re-draw the picture.

In some ways, immediate mode is easier: we draw what we want, when we want. We can use whatever data structures we want to represent things. In other ways, retained mode is easier: we can create objects, and then alter them as needed.

Box 4: Understanding SVG

We’ll come back and look at SVG more later in the semester. The rest of this workbook focuses on Canvas, with a little SVG thrown in for contrast. If you’re curious, you could start with CS559 SVG Tutorial Part 1: Getting Started with SVG and CS559 SVG Tutorial Part 2: Coordinate Systems, to learn more about SVG. In future weeks, you’ll actually write some SVG yourself and will read those tutorials.

But for now, I want to emphasize the basic idea of SVG: each graphics object (like the square) is an HTML element in the DOM - just the same as anything else (paragraphs, buttons, scripts, …). Adding the rectangle to the SVG element is just like adding a button to a paragraph.

Many of the things we can do with “normal” HTML elements (like text or buttons) can be done with the SVG graphics elements (like rectangles). We can do the same basic things: assign them an id, give them classes, use style sheets, etc. We can even create them right in the HTML using tags. They generate events just like many other kinds of HTML elements. Try moving the mouse over the rectangle on the right, or clicking the red rectangle. Then look into the JavaScript to see that this works just like any other event.

In 02-01-04.html, I’ve made the initial picture right in the HTML file. Note how I color the rectangles using a style sheet (although the style sheet is right inside the HTML file). Understand why some rectangles are blue. Notice how I respond to the events on the rectangles (the rightmost one gets enter and leave events - the leftmost one gets click events).

We’ll come back to SVG, but from this box, note how we can create SVG elements right in our HTML, refer to them from JavaScript, and attach events to them.

Summary: Two APIs

On this page, you got to see two different ways to do graphics on web pages. One using Canvas (an immediate mode API), and the other using SVG (a retained mode API).

We’ll learn to draw something more interesting than a rectangle using Canvas in the next pages.

Next: Drawing with Canvas

There are no points associated with this page.