DEV Community

Cover image for Animate your SVG text with animejs (and Vue)
Ola B
Ola B

Posted on

Animate your SVG text with animejs (and Vue)

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

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.

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 (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.

Animating

First, install animejs.

GitHub logo juliangarnier / anime

JavaScript animation engine

Important

🎉 Anime.js V4 is now available in early access 🎉

After years in the making, Anime.js V4 is finally available in early access for my GitHub Sponsors!


anime.js

JavaScript animation engine | animejs.com

npm version npm downloads

Anime.js (/ˈæn.ə.meɪ/) is a lightweight JavaScript animation library with a simple, yet powerful API.
It works with CSS properties, SVG, DOM attributes and JavaScript Objects

Getting started | Documentation | Demos and examples | Browser support

Getting started

Download

Via npm

$ npm install animejs --save
Enter fullscreen mode Exit fullscreen mode

or manual download.

Usage

ES6 modules

import anime from 'animejs/lib/anime.es.js';
Enter fullscreen mode Exit fullscreen mode

CommonJS

const anime = require('animejs');
Enter fullscreen mode Exit fullscreen mode

File include

Link anime.min.js in your HTML :

<script src="anime.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

Hello world

anime({
  targets: 'div',
  translateX: 250,
  rotate: '1turn',
  backgroundColor: '#FFF',
  duration: 800
});
Enter fullscreen mode Exit fullscreen mode

Documentation

  • …




Then add animejs animation:

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

Easy? Let me break it down line by line!

    targets: document.getElementsByTagName('svg')[0].children,
Enter fullscreen mode Exit fullscreen mode

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.

    strokeDashoffset: [anime.setDashoffset, 0],
Enter fullscreen mode Exit fullscreen mode

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.

    easing: 'easeInOutBack',
Enter fullscreen mode Exit fullscreen mode

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.

    delay: function(el, i) { return i * 250 },
Enter fullscreen mode Exit fullscreen mode

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.

    direction: 'normal',
Enter fullscreen mode Exit fullscreen mode

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.

First, template:

<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>
Enter fullscreen mode Exit fullscreen mode

You can use SVG Component 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:

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();
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

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 (I have to warn you though, this is still in a WIP stage).

All the best,

Aleksandra (or Ola, for short)

Top comments (0)