15

Edit: I didn't really ask all the questions I should have asked in my original question. To help make this easier for people looking for a similar answer, this is what the question ended up being:

How do I make a typewriter effect with a blinking cursor that pauses at the end of the statement, erases the statement, and writes a new one?

Check out Yoshi's answer below. It does exactly that...

blahblahAMYblah
  • 232
  • 2
  • 5
  • 14

3 Answers3

33

demo: http://jsbin.com/araget/5/

/*** Plugin ***/

(function($) {
  // writes the string
  //
  // @param jQuery $target
  // @param String str
  // @param Numeric cursor
  // @param Numeric delay
  // @param Function cb
  // @return void
  function typeString($target, str, cursor, delay, cb) {
    $target.html(function(_, html) {
      return html + str[cursor];
    });

    if (cursor < str.length - 1) {
      setTimeout(function() {
        typeString($target, str, cursor + 1, delay, cb);
      }, delay);
    } else {
      cb();
    }
  }

  // clears the string
  //
  // @param jQuery $target
  // @param Numeric delay
  // @param Function cb
  // @return void
  function deleteString($target, delay, cb) {
    var length;

    $target.html(function(_, html) {
      length = html.length;
      return html.substr(0, length - 1);
    });

    if (length > 1) {
      setTimeout(function() {
        deleteString($target, delay, cb);
      }, delay);
    } else {
      cb();
    }
  }

  // jQuery hook
  $.fn.extend({
    teletype: function(opts) {
      var settings = $.extend({}, $.teletype.defaults, opts);

      return $(this).each(function() {
        (function loop($tar, idx) {
          // type
          typeString($tar, settings.text[idx], 0, settings.delay, function() {
            // delete
            setTimeout(function() {
              deleteString($tar, settings.delay, function() {
                loop($tar, (idx + 1) % settings.text.length);
              });
            }, settings.pause);
          });

        }($(this), 0));
      });
    }
  });

  // plugin defaults  
  $.extend({
    teletype: {
      defaults: {
        delay: 100,
        pause: 5000,
        text: []
      }
    }
  });
}(jQuery));


/*** init ***/

$('#target').teletype({
  text: [
    'Lorem ipsum dolor sit amet, consetetur sadipscing elitr,',
    'sed diam nonumy eirmod tempor invidunt ut labore et dolore',
    'magna aliquyam erat, sed diam voluptua. At vero eos et',
    'accusam et justo duo dolores et ea rebum. Stet clita kasd',
    'gubergren, no sea takimata sanctus est Lorem ipsum dolor sit',
    'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr,',
    'sed diam nonumy eirmod tempor invidunt ut labore et dolore',
    'magna aliquyam erat, sed diam voluptua. At vero eos et accusam',
    'et justo duo dolores et ea rebum. Stet clita kasd gubergren,',
    'no sea takimata sanctus est Lorem ipsum dolor sit amet.'
  ]
});

$('#cursor').teletype({
  text: ['_', ' '],
  delay: 0,
  pause: 500
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<span id="target"></span>
<span id="cursor"></span>
<!-- used for the blinking cursor effect -->

plugin:

(function ($) {
  // writes the string
  //
  // @param jQuery $target
  // @param String str
  // @param Numeric cursor
  // @param Numeric delay
  // @param Function cb
  // @return void
  function typeString($target, str, cursor, delay, cb) {
    $target.html(function (_, html) {
      return html + str[cursor];
    });
    
    if (cursor < str.length - 1) {
      setTimeout(function () {
        typeString($target, str, cursor + 1, delay, cb);
      }, delay);
    }
    else {
      cb();
    }
  }
  
  // clears the string
  //
  // @param jQuery $target
  // @param Numeric delay
  // @param Function cb
  // @return void
  function deleteString($target, delay, cb) {
    var length;
    
    $target.html(function (_, html) {
      length = html.length;
      return html.substr(0, length - 1);
    });
    
    if (length > 1) {
      setTimeout(function () {
        deleteString($target, delay, cb);
      }, delay);
    }
    else {
      cb();
    }
  }

  // jQuery hook
  $.fn.extend({
    teletype: function (opts) {
      var settings = $.extend({}, $.teletype.defaults, opts);
      
      return $(this).each(function () {
        (function loop($tar, idx) {
          // type
          typeString($tar, settings.text[idx], 0, settings.delay, function () {
            // delete
            setTimeout(function () {
              deleteString($tar, settings.delay, function () {
                loop($tar, (idx + 1) % settings.text.length);
              });
            }, settings.pause);
          });
        
        }($(this), 0));
      });
    }
  });

  // plugin defaults  
  $.extend({
    teletype: {
      defaults: {
        delay: 100,
        pause: 5000,
        text: []
      }
    }
  });
}(jQuery));

html:

<span id="target"></span>
<span id="cursor"></span> <!-- used for the blinking cursor effect -->

init:

$('#target').teletype({
  text: [
    'Lorem ipsum dolor sit amet, consetetur sadipscing elitr,',
    'sed diam nonumy eirmod tempor invidunt ut labore et dolore',
    'magna aliquyam erat, sed diam voluptua. At vero eos et',
    'accusam et justo duo dolores et ea rebum. Stet clita kasd',
    'gubergren, no sea takimata sanctus est Lorem ipsum dolor sit',
    'amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr,',
    'sed diam nonumy eirmod tempor invidunt ut labore et dolore',
    'magna aliquyam erat, sed diam voluptua. At vero eos et accusam',
    'et justo duo dolores et ea rebum. Stet clita kasd gubergren,',
    'no sea takimata sanctus est Lorem ipsum dolor sit amet.'
  ]
});

$('#cursor').teletype({
  text: ['_', ' '],
  delay: 0,
  pause: 500
});
dotnetCarpenter
  • 10,019
  • 6
  • 32
  • 54
Yoshi
  • 54,081
  • 14
  • 89
  • 103
  • 1
    Yoshi...you rock! This is exactly what I wanted to do. – blahblahAMYblah Nov 10 '12 at 20:29
  • One more thing though, you know how on the edit I posted that Fiddle http://jsfiddle.net/blahblahAMYblah/aDzUM/ where the second example shows the underscore as it types. Would that be easy to implement in your code too? – blahblahAMYblah Nov 10 '12 at 20:30
  • Also, which value do I need to change to make it pause longer before it erases? I want it to stay on each message for at least a few seconds. Every number I changed was just making the letters type or reverse faster...not creating a pause, so I'm guess that isn't set up for a delay yet. It's probably just running the delete function as soon as it finishes, right? I'm still trying to learn, jQuery, so sorry if this question is silly. – blahblahAMYblah Nov 10 '12 at 20:49
  • Yeah, currently there is no pause available, but that should not be to hard to implement. A simple `setTimeout` around the `deleteString(($tar, setting...` should do it. – Yoshi Nov 10 '12 at 20:51
  • Just saw the underscore addition! That's perfect! I'm going to give you credit for this at the top of my .js file since you did all the hard work. Would you like me to put a link to a web site of yours or something? – blahblahAMYblah Nov 10 '12 at 20:52
  • I'm grinning from ear to ear with how cool this looks with my styles set. Thanks once more. – blahblahAMYblah Nov 10 '12 at 20:57
  • That's great to hear! I added the pause, though the underscore stays at the end while paused. I'll leave that for you to fix ;P – Yoshi Nov 10 '12 at 20:59
  • I noticed that it stays sometimes and doesn't other times. Is that a glitch? Is there a way to make it blink like the one on 9elements.com does? – blahblahAMYblah Nov 10 '12 at 21:11
  • Currently the blinking is just a fake. The underscore is shown only every second char, which gives the effect like it was blinking. To have it blink constantly would require some more code changes to have that "blinking" part independent of the rest. – Yoshi Nov 10 '12 at 21:18
  • So what I ended up doing was simply taking out the bits of your code that added the underscore and then placed one in my HTML with a span around it. I applied a jQuery blinking effect to the span and voilà - it blinks! That also helped with the issue where the cursor was only showing up on every other line too. This looks so cool. Again...thanks. – blahblahAMYblah Nov 11 '12 at 01:39
  • I just saw your latest edit. I'm guessing that's better than my solution, eh? Works like a charm, btw. – blahblahAMYblah Nov 11 '12 at 10:40
  • @blahblahAMYblah Actually your solution got me the idea ;) – Yoshi Nov 11 '12 at 11:30
  • 1
    Can I add HTML inside the variable? Example an ` – TheBlackBenzKid Oct 26 '14 at 18:54
  • How to pause once it's completed all the text. – Praveen M P May 02 '15 at 13:01
  • I have the same question as @PraveenMP how to pause once the text is complete? – Tommy Oct 07 '15 at 19:18
  • @Tommy the question is really old. At the time not repeating indefinately wasn't part of the question, and thus the code does not allow for it. – Yoshi Oct 08 '15 at 06:58
4

Added a simple function at the end, and a few variables in between...

Fiddle

var where, when; //added

$.fn.teletype = function(opts){
    var $this = this,
        defaults = {
            animDelay: 50
        },
        settings = $.extend(defaults, opts);

    var letters = settings.text.length; //added

    where = '#' + $($this).attr('id'); //added
    when = settings.animDelay; //added

    $.each(settings.text, function(i, letter){
        setTimeout(function(){
            $this.html($this.html() + letter);

            if( $($this).html().length == letters ){ reverse(); } // Added to trigger reversing function

        }, settings.animDelay * i);
    });
};

$(function(){
    $('#container').teletype({
        animDelay: 100,
        text: 'Now is the time for all good men to come to the aid of their country...'
    });
});


// Added Reversing Function

    function reverse(){

        if ($(where).html().length > 0){          
            x = $(where).html().length - 1;
            y = $(where).html().substr(0, x);
            $(where).html(y);
            setTimeout(reverse , when);
        }else{
            console.log('Reverse Complete');
            clearTimeout(reverse);
        }
    }
VIDesignz
  • 4,703
  • 3
  • 25
  • 37
0

You can also check out my plugin called jquery-typewriter which does exactly what you want.

it may not have as many features but it is worth taking a look at.

It has a blinking cursor, colored text, etc. which can all be customized.

Here is the link: https://www.npmjs.com/package/jquery-typewriter

Zaphod
  • 508
  • 4
  • 10