Search code examples
angularjsangularangularjs-directiveangular-directive

Convert angularjs directive to angular 10


I want to use this code in my angular project:

'use strict';

/**
 * Floating text animation (random)
 */
angular.module('g1b.text-animation', []).
directive('textAnimation', ['$document', '$interval', '$timeout', function ($document, $interval, $timeout) {
  return {
    restrict: 'A',
    compile: function () {
      return {
        pre: function () {},
        post: function (scope, element) {
          var chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
          $interval(function () {
            for ( var i = 0; i < Math.floor(Math.random() * 5); i++ ) {
              var character = chars[Math.floor(Math.random() * chars.length)];
              var duration = Math.floor(Math.random() * 15);
              var offset = Math.floor(Math.random() * (45 - duration * 3)) + 3;
              var size = 12 + (15 - duration);
              var span = angular.element('<span class="animated-text" style="right:'+offset+'vw; font-size: '+size+'px; animation-duration:'+duration+'s">'+character+'</span>');
              element.append(span);
              $timeout(function (span) {
                span.remove();
              }, duration * 1000, false, span);
            }
          }, 250);
        }
      };
    }
  };
}]);

it also has a CSS file with it. this code is basically a text animation. my problem is I don't know where to start.

this is what I'm trying to achieve: https://rawgit.com/g1eb/angular-text-animation/master/

this is the npm of it: https://github.com/g1eb/angular-text-animation

Update:

I've tried it on my own and this is what I have:

@ViewChildren('styleDiv', {read: ElementRef}) children: QueryList<ElementRef>;

  constructor(private renderer: Renderer2, private host: ElementRef) {
  }

  ngOnInit(): void {
  }

  ngAfterViewInit(): void {
    this.animateBackground();
  }

  private animateBackground(): void {
    const renderer = this.renderer;
    const children = this.children;
    const host = this.host;
    const chars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
      'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    setInterval(() => {
      for (let i = 0; i < Math.floor(Math.random() * 5); i++) {
        const character = chars[Math.floor(Math.random() * chars.length)];
        const duration = Math.floor(Math.random() * 15);
        const offset = Math.floor(Math.random() * (45 - duration * 3)) + 3;
        const size = 12 + (15 - duration);
        const span = '<span class="animated-text" style="right:' + offset + 'vw; font-size: ' +
          +size + 'px; animation-duration:' + duration + 's">' + character + '</span>';
        this.children.first.nativeElement.insertAdjacentHTML('beforeend', span);
        setTimeout(() => {
          // renderer.removeChild(children.first.nativeElement.parentNode, children.first.nativeElement);
        }, duration * 1000, false, host, children, renderer);
      }
    }, 250, host, children, renderer);
  }

it works, but I do have a problem inside the set timeout function. I'm able to add the span to the dom, but not able to remove it.


Solution

  • After talking with the guy who wrote this directive we decided I would write a new directive for angular 2+ and he should approve the pull request in the next couple of days. the new code should be available soon in his repository: https://github.com/g1eb/angular-text-animation

    but for now, here is the new directive:

    import {AfterViewInit, Directive, ElementRef, Input, Renderer2} from '@angular/core';
    
    @Directive({
      selector: '[sbzTextAnimation]'
    })
    export class NgxSbzTextAnimationDirective implements AfterViewInit {
      @Input() maxFontSize = 20;
      @Input() colorSchemeArray: string[];
      @Input() position: 'left' | 'right' = 'right';
    
      constructor(private elementRef: ElementRef, private renderer: Renderer2) {
      }
    
      ngAfterViewInit(): void {
        this.init();
        this.animateBackground();
      }
    
      private init(): void {
        this.colorSchemeArray = this.colorSchemeArray
          ? this.colorSchemeArray
          : [
            '#63b598', '#ce7d78', '#ea9e70', '#a48a9e', '#c6e1e8', '#648177', '#0d5ac1',
            '#f205e6', '#1c0365', '#14a9ad', '#4ca2f9', '#a4e43f', '#d298e2', '#6119d0',
            '#d2737d', '#c0a43c', '#f2510e', '#651be6', '#79806e', '#61da5e', '#cd2f00',
            '#9348af', '#01ac53', '#c5a4fb', '#996635', '#b11573', '#4bb473', '#75d89e',
            '#2f3f94', '#2f7b99', '#da967d', '#34891f', '#b0d87b', '#ca4751', '#7e50a8',
          ];
      }
    
      private animateBackground(): void {
        // need to access them in the setTimeout function
        const renderer = this.renderer;
        const elementRef = this.elementRef;
    
        const chars = [...Array(26)].map((e, i) => (i + 10).toString(36));
    
        setInterval(() => {
          for (let i = 0; i < Math.floor(Math.random() * 5); i++) {
            const duration = Math.floor(Math.random() * 15);
            const offset = Math.floor(Math.random() * (45 - duration * 3)) + 3;
            const size = 12 + (this.maxFontSize - duration);
            const color = this.colorSchemeArray[Math.floor(Math.random() * this.colorSchemeArray.length)];
    
            const span = renderer.createElement('span');
            span.innerText = chars[Math.floor(Math.random() * chars.length)];
            renderer.addClass(span, '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);
    
            renderer.appendChild(elementRef.nativeElement, span);
            setTimeout(() => {
              renderer.removeChild(elementRef.nativeElement, elementRef.nativeElement.firstChild);
            }, duration * 1000, false, elementRef, renderer);
          }
        }, 250);
      }
    }
    
    

    I have also made some changes:

    1. the text is now rainbow colors.
    2. added an input for max font size to be customizable use case: [maxFontSize]="30"
    3. added an input for rainbow colors. if the user only wants one color he can pass one color or different scheme like this: [colorSchemeArray]="['#000"]
    4. added an input for the position of the floating text in the background.

    this is the CSS for the directive (should be in the CSS file of the component using the directive):

    /**
     * Floating text animation styles
     */
    .animated-text {
      cursor: default;
      color: #68C2A3;
      font-family: 'VT323', monospace, sans-serif;
      text-shadow: 0 0 1px #ffffff;
      font-size: 24px;
      position: fixed;
      top: -50px;
      user-select: none;
      -ms-user-select: none;
      -moz-user-select: none;
      -khtml-user-select: none;
      -webkit-touch-callout: none;
      -webkit-user-select: none;
      animation-name: float-animation;
      animation-timing-function: ease-out;
    }
    
    @keyframes float-animation {
      0% {
        top: 100vh;
        opacity: 0;
      }
      25% {
        opacity: 1;
      }
      50% {
        opacity: 1;
      }
      75% {
        opacity: 0;
      }
      100% {
        top: -25px;
        opacity: 0;
      }
    }
    

    here is a full working demo: https://stackblitz.com/edit/floating-text-animation?file=src/app/app.component.html

    Update: here is the link to the final directive on npm: https://www.npmjs.com/package/ngx-sbz-text-animation