Page 7: SVG Tutorial and Transformations
CS559 Spring 2023 Sample Solution
In previous workbooks, we mentioned the SVG (Scalable Vector Graphics) API. It is a (vector, retained-mode, scene-graph) API where the graphics objects are stored as elements in the browser’s DOM.
Learning about SVG is useful: it is a very commonly used web graphics API. It is also a great way to learn about the concepts in a scene graph API, so you will be ready when we get to a 3D scene graph API.
With respect to the topic of this workbook (coordinate systems and transformations), SVG is useful for learning, so we will look at it here. The concepts are the same: we have coordinate systems, transformations that change coordinate systems, objects are drawn in coordinate systems, we create hierarchies, … However, we use them differently.
To start, you should learn the basics of SVG. This is discussed in the CS559 SVG Tutorial. You may find it useful to read beyond the class tutorial - the Mozilla SVG Tutorial (optional) is quite good.
Once you’re comfortable with SVG, we can learn about how it handles transformations and hierarchies to connect with what we saw in Canvas.
Coordinate Systems for Display-List APIs
We saw on previous pages how Canvas (and many other immediate-mode APIs) use a transformation stack approach to handling coordinate systems and hierarchy. Drawing commands use the current transformation. Transformation commands update the current transformation. We use save and restore (push/pop) to save the transformations. Save and restore creates a stack, so I call this approach a transformation stack approach. Because the transformations are stores as matrices (more on that in the next workbook), I will also call it a matrix stack.
The transformation stack (save and restore) model is very procedural: it represents the hierarchical structure of the objects implicitly in the code. There is no representation of groups (unless your code has them). When graphics objects are drawn, the objects are drawn with the current transformation (i.e., in the current coordinate system).
In a retained mode system, the system stores the graphics objects as an explicit data structure. Those objects persist after they are created. They can be changed - and we will see those changes. The coordinate systems that the objects “live” in also must stay around so we can interpret the objects. Indeed, it is useful to be able to change the coordinate system to change the objects.
With SVG, each object has its own coordinate system that it is drawn in. It is a property of every SVG object.
Here is a really simple SVG - with three objects (the SVG is inside of the HTML file 03-07-01.html):
If you look at the svg, you will see that each object has its own transformation defined, giving it its own coordinate system. This coordinate system is stored as a property of the object.
<svg id="mysvg" width="300px" height="150px">
<rect transform="translate(40,30)"
id="rect1" width="20" height="20" x="-10" y="-10" fill="red" />
<circle transform="translate(40,70)"
id="circ1" cx="0" cy="0" r="20" fill="blue" />
<path transform="translate(40,110)"
id="path1" d="M-15,0 h30 l-15,30 Z" fill="orange" />
</svg>
If I want, I can write JavaScript code to change the coordinate systems the objects are in (by changing their transformations).
If you look at 03-07-01.html) you will see that I use a standard animation loop, but on each frame I change the transformation for the circle and the square.
A few things to notice:
- On each iteration, I set the value of the transformation - writing over the old transformation. This is different than Canvas where the transformations were relative to the “current transformation”.
- I access the SVG elements the same way that I access any other DOM element - by using their element ID and searching for them in the document.
- I update the
transform
property - the same one I put in the SVG code itself. I have JavaScript write the transform using the same text I wrote by hand. This may seem a little clunky. In practice, we would use a library to make it more convenient. - Notice that I designed my objects at 0,0, and used translation to put them into place - this is a common paradigm.
Note: in this workbook, you will not need to write code that manipulates SVG using JavaScript. I am doing it to help you understand how objects have transforms and coordinate systems.
Hierarchies, Transforms and Coordinate Systems
In SVG, each object has its own coordinate system. This interacts nicely with the hierarchical way that SVG objects are stored.
All SVG objects are part of another object. By default, the objects we create are part of the SVG element itself (this is what is happening in the earlier examples). Objects can also be placed into groups (you might want to review CS559 SVG Tutorial Part 4: Groups, Transformations, Re-Use and Hierarchies for info on groups in SVG). Groups are SVG objects - just like rectangles and circles. In a sense the “top level” SVG element is a special SVG element (it can contain other elements).
Before, we said that all SVG objects have their own coordinate system. This includes the “top level” SVG element - its coordinate system is usually starting at 0,0 and extending to width, height, but it can be controlled with viewBox
(see CS559 SVG Tutorial Part 2: Coordinate Systems). Groups have coordinate systems too.
The key idea is that each object’s coordinate system is based on its “parent” (the object it is inside of). An object’s transform
tells us how to create its coordinate system from its parent. So, in the case of the examples above, each object is part of the SVG element. So its transformation describes how to change the SVG element to create the new coordinate system for the object.
Here is a simple example. I have taken the example from above, and placed the three shapes in a group. I have changed the group’s coordinate system by setting its transform. All of the object’s transformations are affected by the group’s transformation. In the group’s coordinate system (that we get by applying its transform), we then apply the individual objects transformation. Each object combines its parent’s transform and its own transform. 03-07-02.html
Of course, we can manipulate the group’s transformation as well as the object transformation. Here I am moving the group up and down. 03-07-02a.html
OK, That example is silly and annoying to watch - but it hopefully makes the point: with SVG, we explicitly build a tree of objects. Each object has a coordinate system. We determine an object’s coordinate system by applying its transform to its parent object’s coordinate system. Of course, this works up the tree: if the parent (group) is inside of another group, then it refers to its parent.
Box 3: Groups in SVG
In SVG, we can apply transformations (including rotation, translation and scale) to any object. We can also create special group objects that contain other objects. Of course, we can transform group objects (since we can transform any object).
While we can put SVG right into our HTML files, it is often more convenient to just load from a file. Here’s an example (loaded from 03-07-03.html and 03-07-03.svg):
This example shows how you can apply multiple transforms to a single object by listing transforms in the transform
parameter.
You can read more about how to place SVGs on web pages in the Mozilla (Official) Vector Graphics (optional). You’ll see a lot about supporting old browsers that don’t support SVG, which we don’t need to worry about for class.
On the next page, we will ask you to make a picture using SVG. You do not need to write any JavaScript to change the SVG. You should write the SVG directly.