Typewriter effect in Angular 2
Asked Answered
W

3

6

I've been trying to create a typewriter effect in Angular2.

My question basically is what is the best approach. The only way I've been able to do this is through CSS animiations. This does not give me the desired result yet. I've tried three approaches so far.

CSS approach

Created a component, with a separate style sheet.

@import url(http://fonts.googleapis.com/css?family=Anonymous+Pro);

.typewriter h2 {
    margin: 0 auto;
    border-right: .15em solid white;
    text-align: center;
    white-space: nowrap;
    overflow: hidden;
    transform: translateY(-50%);
    animation: typewriter 2.5s steps(28) 1s 1 normal both,
             blinkTextCursor 500ms steps(28) infinite normal;
}

@keyframes typewriter{
  from { width: 0 }
  to { width: 100% }
}

@keyframes blinkTextCursor{
  from{border-right-color: rgba(255,255,255,.75);}
  to{border-right-color: transparent;}
}

#typewriterbox {
  display: inline-block;
}

Next the HTML in which the component will be added.

<div class="page-title">
    <animated-typing>CSS Typewriter effect</animated-typing>
</div>

And the component file:

import {Component} from '@angular/core'

@Component({
  moduleId: module.id,
  selector : 'animated-typing',
  styleUrls: ['animated-typing.component.css'],
  template: `<div id="typewriterbox" class="typewriter"><h2><ng-content></ng-content></h2></div>`
})

export class AnimatedTypingComponent {}

Then the other two approaches I've tried, both of which didn't work. Which basically just meant adding a script to my index.html.

Javascript approach

This is some typewriter code I got from codepen. http://codepen.io/gavra/pen/tEpzn

This part fails when getting the HTML.

var destination = document.getElementById("typedtext");

The script uses getElementById, which returns null. Then breaks when it tries to set destination.value. From what I've understood so far this is Not the way to go, but I wanted to see if it's possible.

<script type="text/javascript" src="js/test.js"></script>

// set up text to print, each item in array is new line
var aText = new Array(
"There are only 10 types of people in the world:", 
"Those who understand binary, and those who don't"
);
var iSpeed = 100; // time delay of print out
var iIndex = 0; // start printing array at this posision
var iArrLength = aText[0].length; // the length of the text array
var iScrollAt = 20; // start scrolling up at this many lines

var iTextPos = 0; // initialise text position
var sContents = ''; // initialise contents variable
var iRow; // initialise current row

function typewriter()
{
 sContents =  ' ';
 iRow = Math.max(0, iIndex-iScrollAt);
 var destination = document.getElementById("typedtext");

 while ( iRow < iIndex ) {
  sContents += aText[iRow++] + '<br />';
 }
 destination.innerHTML = sContents + aText[iIndex].substring(0, iTextPos) + "_";
 if ( iTextPos++ == iArrLength ) {
  iTextPos = 0;
  iIndex++;
  if ( iIndex != aText.length ) {
   iArrLength = aText[iIndex].length;
   setTimeout("typewriter()", 500);
  }
 } else {
  setTimeout("typewriter()", iSpeed);
 }
}


typewriter();

Then finally the approach of which I think is what 'Angular' intended. I have however not been able to get that working. Meaning the 'typerwiter' code is in the component ts file. Or maybe through a directive. Since 'all valid javascript code' should also work in typescript I just copied the javascript. Nothing yet though.

Angular2 approach

This is the component file I created. While figuring out Angular 2 I'm also learing typescript so new at that as well. It gives a reference error on the typewriter function. The HTML part in the template stays the same as before.

import {Component} from '@angular/core';

@Component({
  moduleId: module.id,
  selector : 'animated-typing',
  template: `<div><h2><ng-content></ng-content></h2></div>`,
  host: {
    'id':'typedtext'
  }
})

export class AnimatedTypingComponent {

  constructor(){
    typewriter();
  }

}

function typewriter()
{
  // set up text to print, each item in array is new line
  var aText = new Array(
  "I",
  "Love",
  "to",
  "Code."
  );
  var iSpeed = 100; // time delay of print out
  var iIndex = 0; // start printing array at this posision
  var iArrLength = aText[0].length; // the length of the text array
  var iScrollAt = 20; // start scrolling up at this many lines

  var iTextPos = 0; // initialise text position
  var sContents = ''; // initialise contents variable
  var iRow; // initialise current row
  sContents =  ' ';
  iRow = Math.max(0, iIndex-iScrollAt);

  var destination = document.getElementById("typedtext");

  while ( iRow < iIndex ) {
  sContents += aText[iRow++] + '<br />';
  }
  destination.innerText = sContents + aText[iIndex].substring(0, iTextPos) + "_";
  if ( iTextPos++ == iArrLength ) {
  iTextPos = 0;
  iIndex++;
  if ( iIndex != aText.length ) {
   iArrLength = aText[iIndex].length;
   setTimeout("typewriter()", 500);
  }
  } else {
  setTimeout("typewriter()", iSpeed);
  }
}

Lastly I've added app.module.ts for good measure. Where the component is imported:

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppComponent }  from './app.component';
import { AnimatedTypingComponent } from './components/features/animated-typing.component';

@NgModule({
  imports:      [ BrowserModule, HttpModule ],
  declarations: [ AppComponent, AnimatedTypingComponent ],
  bootstrap:    [ AppComponent ]
})

export class AppModule { }
Wreak answered 22/12, 2016 at 15:44 Comment(0)
U
9

I recently implemented this for my website. Here is how I did it:

  1. Create the following two variables:

    private typewriter_text: string = "Thank you for your interest";
    private typewriter_display: string = "";
    
  2. Create a continuous self-calling function:

    typingCallback(that) {
      let total_length = that.typewriter_text.length;
      let current_length = that.typewriter_display.length;
      if (current_length < total_length) {
        that.typewriter_display += that.typewriter_text[current_length];
        setTimeout(that.typingCallback, 100, that);
      } else {
        that.typewriter_display = "";
      }
    }
    
  3. Call the self-calling function, to start it, within the angular2 ngOnInit():

    ngOnInit() {
      this.typingCallback(this);
    }
    
  4. The following must appear somewhere in you HTML

    {{typewriter_display }}
    
Unprincipled answered 10/2, 2017 at 7:13 Comment(0)
M
4

you can use the T-Writer.js package.

Install the package:

$ npm install t-writer.js --save

Your TS code :

import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import Typewriter from 't-writer.js';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, AfterViewInit {
  name = 'Angular';
  @ViewChild('tw') typewriterElement;
  @ViewChild('tw2') typewriterElement2;
  @ViewChild('tw3') typewriterElement3;

  ngOnInit() {

   }
  ngAfterViewInit() {
    const target2 = this.typewriterElement2.nativeElement;
    const target3 = this.typewriterElement3.nativeElement;
    const target = this.typewriterElement.nativeElement

    const writer = new Typewriter(target, {
      loop: true,
      typeColor: 'blue'
    })

    writer
      .type(`Without washing the brush, I'm gonna go right into some Van Dyke Brown, some Burnt Umber, and a little bit of Sap Green. Maybe he has a little friend that lives right over here. Maybe there was an old trapper that lived out here and maybe one day he went to check his beaver traps, and maybe he fell into the river and drowned.

Get away from those little Christmas tree things we used to make in school. You want your tree to have some character. Make it special. Just make little strokes like that. We'll put a happy little sky in here. See. We take the corner of the brush and let it play back-and-forth.

You have to make almighty decisions when you're the creator. Just go out and talk to a tree. Make friends with it. Let's have a little bit of fun today. Remember how free clouds are. They just lay around in the sky all day long. This is probably the greatest thing that's ever happened in my life.

Imagination is the key to painting. A beautiful little sunset. God gave you this gift of imagination. Use it. There are no limits in this world.

You can't have light without dark. You can't know happiness unless you've known sorrow. Maybe there's a happy little waterfall happening over here. As trees get older they lose their chlorophyll. Isn't that fantastic that you can make whole mountains in minutes? This is the time to get out all your flustrations, much better than kicking the dog around the house or taking it out on your spouse.

Almost everything is going to happen for you automatically - you don't have to spend any time working or worrying. Water's like me. It's laaazy ... Boy, it always looks for the easiest way to do things Maybe there's a happy little Evergreen that lives here. You got your heavy coat out yet? It's getting colder. Every time you practice, you learn more.

Don't forget to tell these special people in your life just how special they are to you. These trees are so much fun. I get started on them and I have a hard time stopping. If I paint something, I don't want to have to explain what it is.

`)
      .rest(500)
      .start()

    const writer2 = new Typewriter(target2, {
      typeColor: 'blue'
    })
    const writer3 = new Typewriter(target3, {
      typeColor: 'red'
    })

  writer2
  .type('Combo typewriters to')
  .removeCursor()
  .then(writer3.start.bind(writer3))
  .start()

writer3
  .type("create complex effects")
  .rest(500)
  .clear()
  .changeTypeColor('red')
  .type("defy user expectations")
  .rest(500)
  .clear()
  .changeTypeColor('blue')
  .type("generate a custom loop")
  .rest(500)
  .clear()
  .changeTypeColor('black')
  .then(writer2.start.bind(writer2))
  }
}


HTML Tag

<hello name="{{ name }}"></hello>
<div class="beside"> <span class="tw" #tw2> </span><span #tw3></span> </div>

<h1 class="tw" #tw></h1>
Manofwar answered 29/4, 2020 at 7:17 Comment(0)
S
0

If you want to stop reloading, change the "typingCallback" function to:

typingCallback(that) {

  let total_length = that.typewriter_text.length;
  let current_length = that.typewriter_display.length;
  if (current_length < total_length) {
    that.typewriter_display += that.typewriter_text[current_length];
    setTimeout(that.typingCallback, 100, that);
  }  
}
Slosberg answered 18/5, 2019 at 1:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.