How JavaScript works: SVG and its use cases (part 1)

Gigi Sayfan
SessionStack Blog
Published in
10 min readSep 2, 2021

Overview

This is post # 42 of the series, dedicated to exploring JavaScript and its building components. In the process of identifying and describing the core elements, we also share some rules of thumb we use when building SessionStack, a JavaScript tool for developers to identify, visualize, and reproduce web app bugs through pixel-perfect session replay.

In a previous article How JavaScript Works: the evolution of graphics I describe how browsers progressed from simple images through a slew of insecure technologies like Java applets, ActiveX controls, and Flash applications into modern standard-based graphics technologies. The three pillars of modern graphics in the browsers are SVG, Canvas 2D API, and WebGL. In this article, we will explore SVG, understand its strengths and weaknesses and experiment with its vast capabilities. In a follow-up article, we will dive into more advanced capabilities and learn how SVG interacts with other browser technologies like CSS and of course JavaScript.

However, SVG is a large specification. Just to set expectations, we will taste many of the things SVG can do, but it is by no means a comprehensive treatment of SVG. This will require a book or two. Enjoy the ride and if you find it useful and fascinating be prepared to dive in deeper.

What is SVG?

SVG stands for Scalable Vector Graphics. It is an XML format that can describe vector-based images and it also supports interaction and animations.

It is a W3C standard that has been developed since 1998. SVG 1.0 was published in 2001, followed by SVG 1.1 in 2003 and SVG tiny 1.2 (for mobile devices) in 2008. SVG 2.X is a W3C candidate recommendation.

SVG content can be described in text files or embedded directly in HTML files. SVG is a first-class citizen of the DOM (Document Object Model). It can be styled using CSS and dynamically programmed using Javascript.

SVG 1.1 is largely supported by all modern browsers (some features here and there may only be partially supported). See https://caniuse.com/svg for details.

Let’s jump right in and get to know SVG.

SVG Basics

Let’s start with a trivial example and draw a circle with a radius of 95 using SVG:

JSFiddle:

This draws a filled black circle on a white background. So, now we know what the defaults are. The syntax is XML. The viewBox describes the area that the SVG rendering will occupy compared to its parent element. The <circle> element specifies the center (cx, cy) and the radius)

The units are by default user space (pixels). But, you can also use real-world units (e.g. millimeters) as well as percentages. The following units are supported: em, ex, px, pt, pc, cm, mm, in.

Drawing simple shapes

The simplest use of SVG is just drawing shapes. Out of the box SVG supports the following shapes:

  • Circle
  • Rectangle
  • Ellipse
  • Line
  • Polyline
  • Polygon

There is some overlap here. For example, a circle is just an ellipse where the X radius is equal to the Y radius. A line is just a polyline with two points. A rectangle is just a kind of polygon. The reason for this redundancy is that circles, lines, and rectangles are common shapes and it is more user-friendly to have a dedicated shape. It can also save mistakes. For example, if you try to specify a circle using an ellipse and by mistake type different values for rx and ry.

Note that line and polyline are open shapes, while circle, rectangle, and polygon are closed shapes. All shapes have stroke color and stroke width attributes (the contour if you will). The closed shapes also have a fill attribute.

Here is a simple line with stroke attributes (the default is 1-pixel wide black stroke):

JSFiddle:

Of course, we can combine multiple shapes. Here are the basic shapes:

JSFiddle:

Filled shapes can be transparent by specifying fill=”none”. Rectangles can have rounded corners by specifying rx and ry.

Drawing complex shapes

Basic shapes are great. You can definitely draw anything by carefully constructing polylines and polygons with lots of points. But, SVG has a better solution for drawing complex shapes. The <path> element is the most powerful shape construct.

It is a little programming language of its own. If you’re familiar with turtle graphics then you will feel right at home with the SVG path. With a path, you can create any sequence of lines and curves. You can move the current location as well as draw both in absolute positions and relative positions.

Let’s start unpacking the <path>. There is a single attribute that controls the path called “d” for display. The “d” attribute contains a sequence of one-letter commands. Uppercase commands use absolute positions. Lowercase commands use relative positions.

For example, to move the drawing location to the absolute position 40, 40 you can use the command “M 40 40”. To move the cursor from the current position 30 pixels to the right and 20 pixels down you can use the command “m 30 20”.

Here is a simple path that does exactly that, but also draws half a circle at each point:

JSFiddle:

The arc command (“A” or “a”) is responsible for drawing the half-circles.

The “z” or “Z” command closes open paths.

The path element has two more commands for drawing Bézier curves. The “C” (or “c””) can be used to draw a cubic Bézier curve. The “S” (or “s”) command can be used to string together multiple cubic Bézier curves. The “Q” (or “q”) command can be used to draw quadratic Bézier curves. To chain together multiple quadratic curves you can use the “T” (or “t”) command.

The `<path>` element also supports several line commands. Those commands draw lines from the current position to a new position. The “L” (or “l”) commands draw a line to a new X, Y position. The “H” (or “h”) command draws horizontal lines to a new X location (Y remains the same). The “V” (or “v”) command draws a vertical to a new Y location (X remains the same).

Let’s throw some lines together. I created with my impressive artistic skills two funnels one green and one red that overlap. I also used the fill-opacity attribute so the overlapping parts share both colors:

JSFiddle:

Understanding strokes

Strokes define the look and fill of lines and contours of closed shapes. SVG provides a lot of ways to customize strokes. By default, strokes are one pixel wide and we saw that we can change the stroke width. But, there are many other interesting things we can do with strokes.

First, you can set the opacity of a stroke, just as you do with the fill. Here is a semi-transparent white stroke that crosses two rectangles and shows the colors underneath.

JSFiddle:

Strokes don’t have to be solid lines. Let’s create a dashed stroke with the stroke-dasharray attribute. The numbers in the array determine the length of segments and the spacing between segments. Note, that if you specify an odd number of elements then the segments and spacing will alternate:

JSFiddle:

You can also control the end of lines and how lines join each other using stroke attributes.

The stroke-linecap attribute lets you choose one of three values to terminate lines: butt, square and round. The butt linecap, just terminates the line without regard to the stroke width. The other styles add half of the stroke width to each end:

JSFiddle:

There are also three ways to join line segments: bevel, mitter and round. Let’s see them in action:

JSFiddle:

The interplay between strokes and fills is very interesting. When you were a child you probably colored some shapes, trying not to go outside the lines. SVG works the other way around. First, it renders the filled shape, and only then it renders the stroke around it. Why does it matter? Well, when the stroke has a width it will be rendered on top of the filled shape. In extreme cases, the stroke can completely hide the filled internals. Here are 3 circles with a radius of 30 and stroke widths of 10, 20, and 30. I also render on top of each circle another empty circle with a green stroke, to show the original radius.

You can see that the blue stroke is rendered over the red fill of the circle. When the stroke width is 30 it completely hides the red fill.

JSFiddle:

Grouping and reusing elements

When creating complex scenes, it is useful to group multiple elements together and treat them as a single entity. It is also useful to have multiple instances of these groups. SVG provides the <g> element exactly for this purpose.

Let’s create a smiley face from multiple SVG elements:

JSFiddle:

I created it from scratch and I’m not much of an artist, so pardon me if the proportions are not what you expect from a “professional” smiley face.

What if we want another smiley face in a different position? Do we have to recreate all these elements again? Not really. We can group all the smiley elements into a single <g> element and then reuse it later. Note that we can set attributes like stroke and stroke-width once at the group level for all the group elements.

JSFiddle:

Reusing groups with the <use> element takes advantage of the Xlink standard. SVG as you recall is an XML-based format and Xlink is the XML equivalent for HTML links. If I want four smiley faces organized in a 2x2 grid I can just use the existing smiley three more times and just place them in a different position:

JSFiddle:

This is great, but what if we want to change the stroke or the fill of the other smiley faces? This is not possible when using an existing element. SVG has another solution for that — the <defs> element. Elements in <defs> are not rendered by themselves. We can still use them and then set their style, stroke, and fill properties when we use them. Here are the same 4 smiley faces in different colors. The <g> element is defined inside a <defs> element, so we need to use it 4 times and specify the fill color in each usage.

JSFiddle:

SVG clearly allows you to go from building very simple to highly complex graphics. As with everything else you build in your product, it’s important to understand whether and how your users are using and interacting with the graphics you have developed. Spotting some functional, visual, or performance issues could leave your users unsatisfied while you are completely unaware of that.

A solution like SessionStack allows you to replay user sessions as videos, allowing you to see exactly what happened during their journey. You will visually see what happened when they interacted with your SVG graphics, how they experienced them, and quickly spot any problems that might have occurred. SessionStack allows you to easily resolve these issues and make your product better without having to ask your users for any screenshots, steps to reproduce, etc.

There is a free trial if you’d like to give SessionStack a try.

SessionStack replaying a session

Conclusion

In this article we covered the foundations of SVG, learned how to draw simple and complex shapes and how to structure, group and organize SVG elements. In the next article, we will unlock additional SVG super-powers such as gradients, transformations and see how SVG supports text, fonts and images. In addition, we will explore the synergy between SVG and other browser technologies like CSS and JavaScript.

If you missed the previous chapters of the series, you can find them here:

--

--