How JavaScript works: advanced SVG capabilities (part 2)

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

This is post # 46 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.

Overview

In part one of this series we explored SVG, understood its strengths and weaknesses, and experimented with its vast capabilities. We also learned how to draw basic and advanced shapes and how to group and reuse SVG elements. In this article, we will dive into more advanced capabilities and learn how SVG interacts with other browser technologies like CSS and of course JavaScript.

Using images

While SVG primarily deals with vector graphics it pragmatically recognizes that you may sometimes want to mix in some raster images as well.

You may wonder why can’t you just use the HTML <img> element and embed it in your SVG. The reason is that SVG is an XML dialect and as such it doesn’t support embedding arbitrary HTML elements. HTML 5 has special support for embedding SVG, but it’s a one-way street.

The bottom line is that SVG has its own special image element called <image>. Here is an example:

https://jsfiddle.net/zjcve4oq/

One of the major differences between HTML <img> and SVG <image> is that the width and height attributes must be specified for SVG <image>.

The x and y attributes always position the image from the origin, which is not very flexible.

The supported image formats are PNG, JPEG, and SVG (yes, you can have an SVG image inside an SVG tree).

Text and fonts

Text is another type of content that you may want to mix with your vector graphics. You could theoretically, draw your text as vectors, but that would be very labor-intensive. SVG supports text and fonts directly.

You can think about text as a series of predefined shapes. Each letter has a shape (based on the selected font and font attributes) and you can customize it with the standard stroke and fill SVG attributes (as well as gradients and patterns as we will see later).

Here is an example:

https://jsfiddle.net/z0w94q7v/

SVG allows placing text along arbitrary paths, which is very cool. You can do it in CSS as well but in a much more cumbersome way.

Let’s place some text along a curve. First, we define an invisible path then create a <textPath> element within a <text> element and reference the path. In addition, I threw in the <tspan> element around one word to change its stroke to red.

https://jsfiddle.net/j5Ltmpqz/

Gradients and patterns

We explored the stroke, and fill attributes of SVG elements. So far, they were always of a uniform color (possibly semi-translucent). If we want to draw some seriously fancy graphics we need more. This is where gradients come in. The colors can gradually change and add a lot of appeal to the scene.

Gradients come in two flavors: linear and radial. Let’s look at linear gradients first.

Gradients are defined in a <defs> element. Here is a simple gradient with three colors red, blue, and green where red changes gradually to green from 0% to 70%, and then green changes gradually to blue. When no other parameters are specified the gradient is horizontal from left to right. The gradient is used as the fill attribute of a <rect> element:

https://jsfiddle.net/nrkbo8cs/

You can control the opacity of different stops of the gradient and change angle by using a coordinate system that determines where the gradient vector starts and stops using the x1, y1, x2, and y2 attributes. Here is an example, that fills a circle with a skewed gradient with custom opacity:

https://jsfiddle.net/1r9mohyd/

Radial gradients radiate from a single point in a circular fashion up to a given radius (hence the name). Radial gradients can fill any shape. Here is an example:

https://jsfiddle.net/dsm4c9ja/

Patterns are another way to fill the shape in an interesting way. The idea is to use a small drawing that repeats itself to fill another shape. For example, suppose we want to fill a triangle with lots of smiley faces. We define the smiley face pattern and then use it to fill our triangle:

https://jsfiddle.net/95cyb3ws/

Note that I have set the width and height attributes of the pattern to fractions. Pattern units are different by default from content units. It is one of the challenges of working with patterns. There are several ways to configure both the pattern units and the content units. I encourage you to play with the values and see the effects.

Basic transformations

Drawing shapes in specific locations and sizes is great, but often you may want to move shapes around, resize them and rotate them. This is especially true when grouping shapes and using them more than once.

SVG provides the ransform attribute to accomplish that. The available transforms are:

  • translate
  • rotate
  • scale
  • skew
  • matrix

The matrix transform is the most generic and you can express all the other transforms, as well as composition of other transforms using a single matrix.

Let’s see some transforms in action. The same rectangle is translated (moved), then rotated, skewed, and scaled (resized).

https://jsfiddle.net/f5qpjmen/

The matrix transform can perform all of the above in one concise statement, but may not be easy to construct without tools support. Let’s transform a little blue rectangle using a matrix. As you can see in a single transform the rectangle (now purple) was translated, rotated, skewed, and scaled:

https://jsfiddle.net/rotL1cfx/

You can read more about the matrix transform here: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#matrix

Clipping and masking

Clipping removes parts of a shape. Consider the venerable Pacman, you can draw a Pacman shape directly using a path, but, it may be easier to draw a circle and then clip a wedge out of it. The clip-path I create here is two overlapping triangles, which cut a wedge out of the circle to create the Pacman shape. I added a filled black circle for the eye and a rotated rectangle (also getting clipped) for the outline of the mouth:

https://jsfiddle.net/93mv6yu0/

Masking performs a similar function to clipping, but the masked parts of the drawing may still show up partially blended with the background of the mask is semi-transparent. If the mask has white fill then it is identical to a clipPath.

Here is accomplishing the same effect as the previous clipping with a mask, except that Pacman is now pink:

https://jsfiddle.net/2a14wefx/

Let’s see how a semi-transparent mask changes things. If I set the mask to a grayscale value like #bbbbbb you can see the packman blended with the background:

https://jsfiddle.net/zg03oqwj/

Filter effects

Gradients, clipping, and masking can create a lot of visual variety, but some effects such as shadow dropping and blurring require additional mechanisms. This is where filters come in. You can create very sophisticated effects with filters, but it requires a deep understanding of several concepts. Consult the filters documentation to gain more insight:

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/filter

In the meantime let’s create some cool effects with filters. Here are a rectangle and a circle using the same filter effect for a little glow and drop shadow:

https://jsfiddle.net/a49ncmz8/

Styling SVG

One of SVG’s claims to fame is that it is a native citizen of the browser DOM. This means that you can style SVG elements with CSS. This is very useful if you have some common themes across your non-SVG content that you want to apply to your SVG content too. You don’t have to try to replicate it using SVG, you can just use your existing CSS.

Additional benefits of using CSS with SVG are separating the look and feel from the SVG structure and applying styles in bulk.

For example, consider a theme of blue stroke of width 2 with a yellow fill. We can apply it to different elements in SVG, but there is no good way to encapsulate that style information. With CSS you can style SVG elements just like you do HTML elements.

Here is the SVG that includes Three text elements and one circle. Note that only the first text element has the SVG attributes:

But, we can add a CSS file that targets the <text> and <circle> SVG elements and all the text elements and circle will be styled the same:

Note that the font-size attribute doesn’t affect <circle> elements, but there is no harm in specifying it. Also, in CSS it’s important to set the font-size using the px unit to match the SVG font-size attribute.

https://jsfiddle.net/spntfmu8/2/

Scripting SVG

Well, if we can apply CSS to SVG we can also script it using JavaScript. The only requirement is to add an `id` attribute to the SVG elements you want to target with JavaScript and then you can reference them and manipulate them from JavaScript.

In the following example, the SVG polygon has an id “start” and a rotate transform initialized to -60 degrees. The onclick handler of the rotate button increases the value so you can see the star rotating around the origin with every click:

https://jsfiddle.net/2Lfoj0be/

You can also add event listeners directly to the SVG elements. In the following example, the fill color of the circle changes from Silver to Yellow when the mouse is over it. It’s also interesting to see that we can access the fill attribute of an SVG element via the style property in JavaScript. The id attribute is not necessary because you can access the circle via this:

https://jsfiddle.net/agu7vL5t/

Animations

SVG can be animated in multiple ways:

  • Via its own <animate> element
  • Via CSS animation
  • Via Javascript

We will focus on the <animate> element here. Note that browser support for particular features may be a limiting factor.

You can add an <animate> element as a sub-element of SVG shapes and use it to change attributes over time.

Let’s take our circle from the previous example and animate its radius so it is contracting and expanding infinitely.

It is very intuitive — pick an attribute, pick a set of values, pick a duration, pick how many times to repeat the animation. Note that the interactive behavior when the mouse is over the circle remains.

https://jsfiddle.net/72qfbcey/

Useful tools

SVG is powerful, but as an XML dialect, it is far from concise. Moreover, when drawing complex scenes that take advantage of the capabilities of SVG you can end up with pretty large and complicated SVG files.

Beyond basic usage, it is best to use proper drawing tools. Luckily there are many established tools that support SVG as an output format. Here is a short list:

  • Inkspace — Open source drawing program that uses SVG as its native file format
  • SVG-Edit — Browser-based SVG editor
  • Adobe Illustrator — Adobe’s vector graphics authoring tool

Conclusion

SVG is a mature and sophisticated graphics format. As a vector-based format, it is compact compared to raster image formats like PNG and JPEG. It is well supported by web browsers. It is a first-class citizen in the DOM, integrating effortlessly with CSS and Javascript. It is useful both for reducing the weight of images in your web pages as well as for adding cool interactive capabilities. It can be created and edited using multiple tools. If you’re a web developer you should be aware of SVG and take advantage of its strengths when appropriate.

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

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

--

--