ANGULAR ANIMATIONS MADE EASY

Bubbling Text Background in Angular 10

An angular 10 directive for floating text background animation

Liraz Shaka Amir
codeburst
Published in
7 min readNov 5, 2020

--

Bubbling text demo gif

If you want to add animations to your website, JavaScript has plenty of libraries that can help. However, this article focuses on adding animations in angular so you have to do things the angular way. This means one thing: importing JS libraries is not so easy (or recommended) so I set myself up for a task, I wanted to build one colossal npm package of my own that contains a lot of the animations we see in JS (as well as new ones of course). For now, I’ll just start with one of those packages.

Please note: If you want to take the easy road here then you can skip this article and just click my easy-to-use solution. If you’re having problems you can find a demo in there also.

Humble Beginnings

It started when I was building my website. I got a notepad (a real one), drew my basic elements, sections, etc., then I got an idea. I want people to dive into my website so I thought of the ocean. When you dive into water you see all of the bubbles around you so I wanted floating bubbles to appear in the background of my site to emulate that experience. But that wasn’t enough for me, I’m a developer! I’m not taking people scuba-diving, I’m taking them to my world — the World Wide Web so my site shouldn’t have air bubbles in it, it should have text bubbling in it!

The only problem was that I wasn’t sure how to go about this, so I did what any sane person would do- I Googled it of course. I figured that someone must have tried this idea out before and I was right; someone had. Meet Gleb, he was the mastermind behind the realization of my dream. Great, I had found my guy but there was a problem — he had created his animation in AngularJS.

this is Gleb — g1eb.com

So I talked to him and he gave me permission to upgrade everything to angular 10.

Getting Started

If you want to know how to do this yourself then you’ve come to the right place. Let’s Start. The first thing you need is an Angular app (this article assumes that you know how to create this). I wanted a directive so that I could inject it everywhere to any element and possibly control a few things dynamically.

Now you need to add a directive to your app, so inside the root of your app run this command:

ng g directive bubbling-text

After that, you need to make sure to add it to your app.module file inside the declarations array:

app.module.ts
https://gist.github.com/blakazulu/9fa3105d67d14302e0fc860f528083f3

We’ll continue with the CSS so let’s go to the main styles.css file:

https://gist.github.com/blakazulu/de3f4a7ea6c4bda0bbd14aa080cdd11b

Let’s quickly review what we did there. We created a class called animated-text and gave it a font family and a shadow (play with a bit to see what you prefer). The position is fixed so you can scroll and it will always be there. Set the bottom to -100vh; why a negative position? We're going to create the letters offscreen and then animate them in. user-select is set to none so that if some annoying user decides he wants to double click somewhere on the screen (or click and drag) the letters won’t be selected. Finally, we create a simple keyframe animation that plays with the opacity, fading in and out of the screen. That’s it.

But that’s not all! I have a little bonus waiting for you at the end!

The Bubbling Text

Now let’s get to business: the bubbling-text.directive.ts. The file is big so there’s no picture this time, just the gist. I know it’s long (this is because I have a lot of colors in there ).

https://gist.github.com/blakazulu/3bad6b840b5d58c94b6955d8bc5bcd0a

First, imports:

imports — bubbling-text.directive.ts

Inputs:

export class BubblingTextDirective implements AfterViewInit {
@Input() maxFontSize = 40;
@Input() colorSchemeArray: string[];
@Input() position: "left" | "right" = "right";
@Input() percentOfScreen = 30;
constructor(private elementRef: ElementRef, private renderer: Renderer2) {}ngAfterViewInit(): void {
this.init();
this.animateBackground();
}

We define the inputs that we want to receive in order to control the CSS properties. Let’s go through them:

  • maxFontSize— maximum font size of the letters.
  • colorSchemeArray— colors of the letters.
  • Position—where do we want the letters to appear, to the left or the right of the screen?
  • percentOfScreen— the percent of the screen the letters will take. If we put 100 then the position is not important.

Notice that we gave everything a default value in case no input is entered (except for the colorSchemeArray which we will initialize later in the init() ).

Next, we have the init function that initializes the colorSchemeArray with the default values or the user input. If the user wants a custom pallet he can enter an array of his choice. Let’s say he wants only white, then he can enter:

['#FFFFFF']

Now we're getting to the “hard part”; the animateBackground function. As usual, I will go through every line so you can understand exactly what’s going on.

const renderer = this.renderer;
const elementRef = this.elementRef;

I’m creating these local vars for ease because I’m using them a lot:

const chars = [...Array(26)].map((e, i) => (i + 10).toString(36));

Creating a chars array of all the letters in the alphabet.

Basically, I’m creating a span element for each letter Each span will have the animated-text class we’ve created, and I’ll add unique styles (animation duration, size, color, offset) to each span.

I want the next part to run repeatedly so I’m using setInterval with an interval of 100 milliseconds. If it’s too fast or too slow you can even add it to the user inputs and let the user decide.

The setInterval() method, repeatedly calls a function or executes a code snippet, with a fixed time delay between each call.

const duration = Math.floor(Math.random() * 15);
const offset = Math.floor(Math.random() * this.percentOfScreen);
const size = Math.floor(Math.random() * this.maxFontSize);
const color = this.colorSchemeArray[
Math.floor(Math.random() * this.colorSchemeArray.length)
];

To create unique styles for each element, I’ll be using the Math.floor() and Math.random() methods. The number 15 you see in there — is a magic number.

The Math.floor() function returns the largest integer less than or equal to a given number.

The Math.random() function returns a floating-point, pseudo-random number in the range 0 to less than 1.

So let’s say the maxFontSize is 40. Math.random will create a number between 0–1 (let’s say 0.512). we multiply it by the maxFontSize (we get 20.48), and then “floor” it — the outcome will be that the current span will have a font size of 20px.

const span = renderer.createElement("span");
span.innerText = chars[Math.floor(Math.random() * chars.length)];
renderer.addClass(span, "animated-text");

We now create our span element using the wonderful renderer2 engine. we set it’s inner text to a random char from our array of chars and give it a class of “animated-text”.

renderer.setStyle(span, "color", color);
renderer.setStyle(span, this.position, `${offset}vw`);
renderer.setStyle(span, "font-size", `${size}px`);
renderer.setStyle(span, "animation-duration", `${duration}s`);
renderer.setStyle(span, "color", color);

We now set the unique style for each span, making sure each letter is of a different color, size, and in a different location.

renderer.appendChild(elementRef.nativeElement, span);

Now we append the span (this is the child) we’ve created to the elementRef.nativeElement (this is the parent node). What is that elementRef you ask? Well, that’s the element that’s using our amazing directive. It will basically insert the span to that element inside the DOM.

֫setTimeout(() => {
renderer.removeChild(elementRef.nativeElement, elementRef.nativeElement.firstChild);
}, duration * 1000);

The setTimeout() method calls a function or evaluates an expression after a specified number of milliseconds.

Now we are adding a lot of span elements to our DOM. It will eventually break so we need to remove them but we need to do this with a delay. We are removing the first span element added to the elementRef.nativeElement.

Conclusion

That’s it, you are done, you can now use it like this:

app.component.html
<div bubblingText [position]="'right'"></div>
<div bubblingText [position]="'left'"></div>

You can find a working example in this link. Once again, If you want the easy way — you can skip this article and just click my easy-to-use solution, simply follow the directions there.

But wait, there’s more!

I promised you a bonus. Let’s say you don’t like scuba diving, rather you’d like to add a rain animation to your site. Simply change the keyframes animation in the styles.css to this:

https://gist.github.com/blakazulu/91a2ea9515d055f5f7712c708210a5de

Now see what’s happening. Enjoy!

--

--