Vue SVG

Turn Your Static SVG Drawings Into Interactive Widgets and Infographics With Vue.js

Final product image
What You’ll Be Creating

SVG is a powerful and flexible graphic format, which fits perfectly into the web medium. Unlike raster image formats, such as JPG, PNG, or GIF, SVG is vector-based and consists of “real” objects, which you can select and manipulate in whatever manner you want. So even with some basic scripting, a static image can be animated and made interactive. And that will be the subject of this tutorial. 

SVG and Vue: The Perfect Match

To demonstrate how SVG can be scripted, I selected Vue.js. The reason behind my choice is that, in my opinion, SVG and Vue make the perfect match. First, Vue supports SVG out of the box. And second, SVG, like HTML, is XML-based, so we can apply Vue’s reactivity system to SVG and make it interactive in the same easy and convenient way as we do with HTML templates. 

Quick Primer on Vue and SVG Integration

Before we get to the two use cases which we’ll explore below, let me give you a clue about the way SVG and Vue integration works. 

To get started, we create a basic HTML file and include the Vue framework. Then, we put the SVG we want to manipulate inside. 

Here, we have a rectangular object whose attributes are bound to the data object in the Vue instance. We also have a click event listener, which will invoke the toggleStroke() method. So when we click on the rectangle, the stroke will be toggled.

And here is the Vue code:

See the Pen &lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “=””&gt;Vue”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue”=””&gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue”=””&gt;<a href=”https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue” &amp;gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue”&amp;gt;https:=”” ‘&amp;gt;vue&lt;=”” a&gt;”=””>https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue”&amp;gt;https://codepen.io/tutsplus/pen/PVBoNR/’…</a>” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “&gt;vue”&gt;https:=”” ‘&gt;vue”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue&lt;=”” a&gt;”=””>https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue”&gt;https://codepen.io/tutsplus/pen/PVBoNR/’&amp;…</a>” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “&gt;vue”..”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” ‘&amp;gt;vue”=””&gt;<a href=”https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue&lt;/a&gt;”>https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue&lt;/a&gt;</a>” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “&gt;vue”..”=””&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue”>https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue</a>” &amp;gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “&amp;gt;vue”..”=””&gt;<a href=”https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue” &amp;gt;https:=”” codepen.io=”” tutsplus=”” pen=”” pvbonr=”” “&amp;gt;vue”…&lt;=”” a&gt;..”=””>https://codepen.io/tutsplus/pen/PVBoNR/’&amp;gt;Vue”&amp;gt;https://codepen.io/tutsplus/pen/PVBoNR/”…</a>. SVG Basic Example by Envato Tuts+
(&lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io=”” tutsplus”=””&gt;@tutsplus”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus” &amp;gt;https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”&amp;gt;https:=”” tutsplus’&amp;gt;@tutsplus&lt;=”” a&gt;”=””>https://codepen.io/tutsplus’&amp;gt;@tutsplus”&amp;gt;https://codepen.io/tutsplus’&amp;gt;@tutsplus”…</a>” &gt;https:=”” codepen.io=”” tutsplus”&gt;@tutsplus”&gt;https:=”” tutsplus’&gt;@tutsplus”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus” &gt;https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus&lt;=”” a&gt;”=””>https://codepen.io/tutsplus’&amp;gt;@tutsplus”&gt;https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/…</a>” &gt;https:=”” codepen.io=”” tutsplus”&gt;@tutsplus”&gt;https:=”” ..”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/a&gt;”>https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/a&gt;</a>” &gt;https:=”” codepen.io=”” tutsplus”&gt;@tutsplus”&gt;https:=”” ..”=””&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus”>https://codepen.io/tutsplus’&amp;gt;@tutsplus</a>” &amp;gt;https:=”” codepen.io=”” tutsplus”&amp;gt;@tutsplus”&amp;gt;https:=”” ..”=””&gt;<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus” &amp;gt;https:=”” codepen.io=”” tutsplus”&amp;gt;@tutsplus”&amp;gt;https:=”” …&lt;=”” a&gt;…”=””>https://codepen.io/tutsplus’&amp;gt;@tutsplus”&amp;gt;https://codepen.io/tutsplus”&amp;gt;@tutsplus”…</a>) on &lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io”=””&gt;CodePen”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;<a href=”https://codepen.io’&amp;gt;CodePen” &amp;gt;https:=”” codepen.io’&amp;gt;codepen”&amp;gt;https:=”” codepen.io’&amp;gt;codepen&lt;=”” a&gt;”=””>https://codepen.io’&amp;gt;CodePen”&amp;gt;https://codepen.io’&amp;gt;CodePen”&amp;gt;https://codepe…</a>” &gt;https:=”” codepen.io”&gt;codepen”&gt;https:=”” codepen.io’&gt;codepen”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io’&amp;gt;CodePen” &gt;https:=”” codepen.io’&amp;gt;codepen&lt;=”” a&gt;”=””>https://codepen.io’&amp;gt;CodePen”&gt;https://codepen.io’&amp;gt;CodePen&lt;/a&gt;</a>” &gt;https:=”” codepen.io”&gt;codepen”&gt;https:=”” codepen.io’&gt;codepen”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;<a href=”https://codepen.io’&amp;gt;CodePen&lt;/a&gt;”>https://codepen.io’&amp;gt;CodePen&lt;/a&gt;</a>” &gt;https:=”” codepen.io”&gt;codepen”&gt;https:=”” codepen.io’&gt;codepen”=””&gt;&lt;a href=”<a href=”https://codepen.io’&amp;gt;CodePen”>https://codepen.io’&amp;gt;CodePen</a>” &amp;gt;https:=”” codepen.io”&amp;gt;codepen”&amp;gt;https:=”” codepen.io’&amp;gt;codepen”=””&gt;<a href=”https://codepen.io’&amp;gt;CodePen” &amp;gt;https:=”” codepen.io”&amp;gt;codepen”&amp;gt;https:=”” codepen.io’&amp;gt;codepen&lt;=”” a&gt;”=””>https://codepen.io’&amp;gt;CodePen”&amp;gt;https://codepen.io”&amp;gt;CodePen”&amp;gt;https://codepe…</a>.

As you can see, it’s super easy to combine Vue and SVG. Now, let’s explore some more realistic and useful examples.

Example One: Creating a Countdown Timer Widget

In the first example, we’ll create a countdown timer widget. It will allow users to set minutes and seconds for a given time period and, when started, the timer will show the remaining time in circular progress. 

To draw and animate the progress, we’ll use an SVG circle object and its stroke-dasharray attribute. You can read about the SVG circular progress technique here. Also, to add some structure and nice styling, we’ll use the Card component from Bulma. So make sure you’ve added the framework to your file.

See the Pen &lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” “=””&gt;Vue”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” ‘&amp;gt;vue”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” ‘&amp;gt;vue&lt;=”” a&gt;”=””>https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue”&gt;https://codepen.io/tutsplus/pen/WPKNoL/’&amp;…</a>” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” “&gt;vue”&gt;https:=”” ‘&gt;vue”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” ‘&amp;gt;vue”=””&gt;<a href=”https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue&lt;/a&gt;”>https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue&lt;/a&gt;</a>” &gt;https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” “&gt;vue”..”=””&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue”>https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue</a>” &amp;gt;https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” “&amp;gt;vue”..”=””&gt;<a href=”https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue” &amp;gt;https:=”” codepen.io=”” tutsplus=”” pen=”” wpknol=”” “&amp;gt;vue”…&lt;=”” a&gt;.”=””>https://codepen.io/tutsplus/pen/WPKNoL/’&amp;gt;Vue”&amp;gt;https://codepen.io/tutsplus/pen/WPKNoL/”…</a>. SVG Basic Example by Envato Tuts+
(&lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io=”” tutsplus”=””&gt;@tutsplus”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus” &gt;https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus&lt;=”” a&gt;”=””>https://codepen.io/tutsplus’&amp;gt;@tutsplus”&gt;https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/…</a>” &gt;https:=”” codepen.io=”” tutsplus”&gt;@tutsplus”&gt;https:=”” tutsplus’&gt;@tutsplus”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io=”” tutsplus’&amp;gt;@tutsplus”=””&gt;<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/a&gt;”>https://codepen.io/tutsplus’&amp;gt;@tutsplus&lt;/a&gt;</a>” &gt;https:=”” codepen.io=”” tutsplus”&gt;@tutsplus”&gt;https:=”” ..”=””&gt;&lt;a href=”<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus”>https://codepen.io/tutsplus’&amp;gt;@tutsplus</a>” &amp;gt;https:=”” codepen.io=”” tutsplus”&amp;gt;@tutsplus”&amp;gt;https:=”” ..”=””&gt;<a href=”https://codepen.io/tutsplus’&amp;gt;@tutsplus” &amp;gt;https:=”” codepen.io=”” tutsplus”&amp;gt;@tutsplus”&amp;gt;https:=”” …&lt;=”” a&gt;..”=””>https://codepen.io/tutsplus’&amp;gt;@tutsplus”&amp;gt;https://codepen.io/tutsplus”&amp;gt;@tutsplus”…</a>) on &lt;a href=”&amp;lt;a href=&amp;quot;&amp;lt;a href=” https:=”” codepen.io”=””&gt;CodePen”&amp;gt;&lt;/a&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;&lt;/a&gt;&lt;a href=”<a href=”https://codepen.io’&amp;gt;CodePen” &gt;https:=”” codepen.io’&amp;gt;codepen&lt;=”” a&gt;”=””>https://codepen.io’&amp;gt;CodePen”&gt;https://codepen.io’&amp;gt;CodePen&lt;/a&gt;</a>” &gt;https:=”” codepen.io”&gt;codepen”&gt;https:=”” codepen.io’&gt;codepen”=””&gt;&lt;a href=”&amp;lt;a href=” https:=”” codepen.io’&amp;gt;codepen”=””&gt;<a href=”https://codepen.io’&amp;gt;CodePen&lt;/a&gt;”>https://codepen.io’&amp;gt;CodePen&lt;/a&gt;</a>” &gt;https:=”” codepen.io”&gt;codepen”&gt;https:=”” codepen.io’&gt;codepen”=””&gt;&lt;a href=”<a href=”https://codepen.io’&amp;gt;CodePen”>https://codepen.io’&amp;gt;CodePen</a>” &amp;gt;https:=”” codepen.io”&amp;gt;codepen”&amp;gt;https:=”” codepen.io’&amp;gt;codepen”=””&gt;<a href=”https://codepen.io’&amp;gt;CodePen” &amp;gt;https:=”” codepen.io”&amp;gt;codepen”&amp;gt;https:=”” codepen.io’&amp;gt;codepen&lt;=”” a&gt;”=””>https://codepen.io’&amp;gt;CodePen”&amp;gt;https://codepen.io”&amp;gt;CodePen”&amp;gt;https://codepe…</a>.

We start by adding a card component and then put a header inside with the title of our widget.

Next, we use the image section of the card to put our SVG.

Here, we have a rectangle which serves as a background. We use two circles to create the circular progress. We position them so they perfectly overlap. We set the fill attribute of the first circle to none and use only its stroke as an outline for the progress. 

To create the illusion of drawing a circle, we bind the stroke-dasharray attribute of the second circle to the dasharray() computed property, which we’ll create a bit later. Also, we want the starting point of the drawing to be at 12 o’clock and not at 3 o’clock which is the default. To do this, we rotate the point using the transform attribute. The last object is the text, which we position in the circle’s center. To display the time correctly, with a leading zero, we apply the formatTime() filter, which we’ll create later.

Next, we need to add the controls for the minutes and seconds.

The important controls here are the inputs, which we bind with the corresponding Vue properties by using the v-model directive. We also disable them when the state is set to started or paused. Finally, we add a change event listener, which will call the updateTime() method.

And finally, we add the buttons to control the timer.

Here, we again add click event listeners and some conditions to the buttons, so they will be disabled when not needed.

So far, we’ll need some CSS to correct the spacing and aligning of some parts of the timer.

And now, it’s time to add the Vue code to the equation.

First, we define the necessary properties in the data object, and we add the circumference of the circles as a custom option of the Vue instance. The latter is because we need circumference to be static but not reactive. We create dasharray() computed to calculate the values for the stroke-dasharray attribute.

Now, let’s add the methods:

The updateTime() method updates the value of the timeInSeconds property each time the values change.

The start() method changes the state to started and invokes the _tick() method every second. 

The _tick() method handles the proper update of the progress, minute, and second props.

The pause() method changes the state to paused and stops the clock by clearing the interval.

The stop() method changes the state to stopped, stops the clock, and resets the progress, minute, and second props.

And finally, we add the formatTime() filter to handle the proper display of the time.

And that's it! We successfully used Vue's reactivity features to transform our static SVG drawing into an interactive countdown timer. Let's move on to the next example.

Example Two: Creating an SVG Infographic

In this example, we'll create a small infographic demonstrating what responsive web design is and how it works. Thanks to Vue, we'll be able to animate our SVG illustration and make it more realistic and engaging. 

See the Pen &lt;a href="&amp;lt;a href=&amp;quot;&amp;lt;a href=" https:="" codepen.io="" tutsplus="" pen="" erpxmk="" "=""&gt;Vue"&amp;gt;&lt;/a&gt;&lt;a href="<a href="https://codepen.io/tutsplus/pen/ErpxmK/'&amp;gt;Vue">https://codepen.io/tutsplus/pen/ErpxmK/'&amp;gt;Vue</a>" &amp;gt;https:="" codepen.io="" tutsplus="" pen="" erpxmk="" "&amp;gt;vue"&amp;gt;https:="" '&amp;gt;vue"=""&gt;<a href="https://codepen.io/tutsplus/pen/ErpxmK/'&amp;gt;Vue" &amp;gt;https:="" codepen.io="" tutsplus="" pen="" erpxmk="" "&amp;gt;vue"...&lt;="" a&gt"="">https://codepen.io/tutsplus/pen/ErpxmK/'&amp;gt;Vue"&amp;gt;https://codepen.io/tutsplus/pen/ErpxmK/"...</a>; SVG Basic Example by Envato Tuts+
(&lt;a href="&amp;lt;a href=&amp;quot;&amp;lt;a href=" https:="" codepen.io="" tutsplus"=""&gt;@tutsplus"&amp;gt;&lt;/a&gt;&lt;a href="<a href="https://codepen.io/tutsplus'&amp;gt;@tutsplus">https://codepen.io/tutsplus'&amp;gt;@tutsplus</a>" &amp;gt;https:="" codepen.io="" tutsplus"&amp;gt;@tutsplus"&amp;gt;https:="" tutsplus'&amp;gt;@tutsplus"=""&gt;<a href="https://codepen.io/tutsplus'&amp;gt;@tutsplus" &amp;gt;https:="" codepen.io="" tutsplus"&amp;gt;@tutsplus"&amp;gt;https:="" ...&lt;="" a&gt;"="">https://codepen.io/tutsplus'&amp;gt;@tutsplus"&amp;gt;https://codepen.io/tutsplus"&amp;gt;@tutsplus"...</a>) on &lt;a href="&amp;lt;a href=&amp;quot;&amp;lt;a href=" https:="" codepen.io"=""&gt;CodePen"&amp;gt;&lt;/a&gt;&lt;a href="<a href="https://codepen.io'&amp;gt;CodePen">https://codepen.io'&amp;gt;CodePen</a>" &amp;gt;https:="" codepen.io"&amp;gt;codepen"&amp;gt;https:="" codepen.io'&amp;gt;codepen"=""&gt;<a href="https://codepen.io'&amp;gt;CodePen" &amp;gt;https:="" codepen.io"&amp;gt;codepen"&amp;gt;https:="" codepen.io'&amp;gt;codepen&lt;="" a&gt;"="">https://codepen.io'&amp;gt;CodePen"&amp;gt;https://codepen.io"&amp;gt;CodePen"&amp;gt;https://codepe...</a>.

I created the static parts of the infographic in Illustrator, and then exported it as SVG. Then I added the dynamic parts manually. The dynamic parts are three wireframes, which simulate how one and the same web design is viewed on different devices. Let's create them now.

First, let's create the data objects necessary for the different wireframes.

Every wireframe consists of six rectangles, so for each design we create a separate data object with the necessary values. In the Vue instance, we create another one, which will be the base object. 

Now, let's create the SVG rectangles necessary for the wireframes and bind their attributes to the data values:

Next, we create the animation method with the help of Tween.js. So make sure you've added that library to your file. We use the Vue created() lifecycle hook to initially animate the wireframe from the base object to the laptop design wireframe.

And now, we add overlays to the device icons by positioning transparent SVG rectangles above them. This way, the clicking area will contain the whole icons and not only their outlines. And finally, we add the click event listeners, which will call the anim() method with the selected design.

So now, when we open the infographic, the laptop design will show up gently animated, and when we click on the different device icons, the wireframe design will be updated accordingly with smooth animation. Cool, huh?

Conclusion

As you can see, SVG, in combination with Vue, can be very powerful and flexible. Vue makes it super easy to access and manipulate SVG objects and to make them fully interactive. This way, you can bring life to your static SVG graphics and make them dynamic and more pleasant for users. Such an engagement can dramatically improve the user experience and the overall appearance of your website or application. 

Leave a Comment

Scroll to Top