Animate your SVG text with animejs (and Vue)
Tags: javascript, animejs, showdev, vue
Published: 2023-05-18 21:56:07

Are you looking for a non-standard portfolio page welcome text? Do you want to create an animated website to propose to your loved one? 

Say no more!

In this #showdev I'll teach you how to create stunning SVG animation with an equally stunning `animejs` library!

The result will look like this: 

![Gif of result](https://vakme.github.io/howdy.gif)

> NOTE: This post will show you how to create a line drawing animation in animejs. If you want it in a condensed form, straight from the source, visit [the official documentation](https://animejs.com/documentation/#lineDrawing).

## Prerequisites

To create a stunning animated SVG image, first, you will need SVG to animate. There are many tools to do that, available both online and offline. You can, for example, start with generating text using [easysvg](https://github.com/kartsims/easysvg) (written in php, but a great tool nonetheless). 

> Important: Every letter in your SVG should be a separate `<path>` tag! Here paths mark the outlines of the letters.

You will also need a container to run the animation in. It can be anything, pure JS script or a more advanced app. In my case, I'm using a very simple Vue.js app.

## Preparing your SVG

To make our SVG look classy, we need to tweak it a bit: 

1. To provide it with an "outlined" look, set `fill` attribute in every `<path>` tag to `transparent` and set `stroke` attribute to any color you want.
2. Add some extra elements for flavor - directly in SVG code (if you're the pro and a math nerd) or use some editor to do it.

> Use my SVG, if you want: [link to github file](https://github.com/Vakme/vakme.github.io/blob/main/src/assets/howdy.svg).

## Animating

First, install `animejs`.
{% embed https://github.com/juliangarnier/anime %}

Then add animejs animation:

```js
anime({
    targets: document.getElementsByTagName('svg')[0].children,
    strokeDashoffset: [anime.setDashoffset, 0],
    easing: 'easeInOutBack',
    delay: function(el, i) { return i * 250 },
    direction: 'normal',
  });
```

Easy? Let me break it down line by line!

```js
    targets: document.getElementsByTagName('svg')[0].children,
```
In this line, we point to every element we want to animate, in this case to an array of every child element of our SVG. You may need to adjust it a little to the structure of your SVG. 

```js
    strokeDashoffset: [anime.setDashoffset, 0],
```
This is what makes animation happen. It uses `stroke-dashoffset` attribute. If you want to know more about animating SVGs using this attribute, I recommend [this CSS Tricks article](https://css-tricks.com/svg-line-animation-works/).

```js
    easing: 'easeInOutBack',
```
I wanted to add a little "bouncing" at the beginning and the end of the animation of every letter. If you want to test different easing functions on your own, I recommend [easings.net](https://easings.net/).

```js
    delay: function(el, i) { return i * 250 },
```
I wanted to slightly delay every animated path, so I passed a function that multiplies the delay by the index of an element in the table I passed in `targets`.

```js
    direction: 'normal',
```
You can choose from `normal`, `reverse`, and `alternate`.

## Embed this... somewhere

Although animejs can be used in Vanilla, I really wanted to use it in my Vue.js app.

I used Vue.js transitions to do that. [More on them.](https://vuejs.org/guide/built-ins/transition.html)

First, template:
```vue
<Transition appear :css="false" @enter="onEnter" name="howdy">
  <!-- Your SVG goes here. I used v-html because I'm lazy ¯\_(ツ)_/¯  -->
  <div v-html="howdy" />
</Transition>
```
> You can use [SVG Component](https://blog.logrocket.com/using-svg-and-vue-js-a-complete-guide/) to embed your SVG on a page.

I wanted my animation to start on a component render, so I added `appear` keyword to the transitions. I also needed to tell Vue this animation would be purely JS, so I used `:css="false"`. 

Now I only need to write `onEnter` callback: 

```ts
const onEnter = (el: Element, done: () => void) => {
  anime({
    targets: el.getElementsByTagName('svg')[0].children,
    strokeDashoffset: [anime.setDashoffset, 0],
    easing: 'easeInOutBack',
    delay: function(el, i) { return i * 250 },
    direction: 'normal',
    complete: () => {
      done();
    },
  });
}
```

`onEnter` uses the Transition Element as the first argument and `done()` function as the second. We have to call `done()` function at the end of the application to signal to Vue that the animation ended. We can use `complete` hook from animejs to do it.
And we want to animate only descendants of our Transition element, so we can specify `targets` using the first argument.

And... that's it! Sit back and enjoy your animated text!

If you have any questions, I'm happy to answer :) If there's anything to be improved in this short post, let me know, and I'll gladly fix that!

And if you want to see this animation in action, you can visit [my page](https://vakme.github.io/) (I have to warn you though, this is still in a WIP stage).

All the best,

Aleksandra (or Ola, for short)