0

I'm creating an "animated letter incrementer" that takes any given word and increments each letter of that word starting from A.

Example:

Word = Dog

D - Increments from A to D [A, B, C, D]
O - Increments from A to O [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]
G - Increments from A to G [A, B, C, D, E, F, G]

The effect I'd like to achieve is similar to this jQuery animated number counter, except I'll be incrementing letters instead of counting numbers. Also, each letter of the word should increment independently, but they should all reach their destination letter at the same time.

JS:

var wordToIncrement = 'DOG';
var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ '.split('');

for (var i = 0, len = wordToIncrement.length; i < len; i++) {

    var letterToIncrementTo = wordToIncrement[i];

    var arrayLength = alphabet.length;
    for (var z = 0; z < arrayLength; z++) {

        var alphabetLetter = alphabet[z];

        if (alphabetLetter == letterToIncrementTo) {

            console.log('MATCH FOUND!');
            console.log('Word Letter: ' + letterToIncrementTo);
            console.log('Alphabet Letter: ' + alphabetLetter);

            alphabetPositionValue = z;
            console.log('VALUE: ' + alphabetPositionValue);

            function incrementToLetter(letterToIncrementTo,alphabetPositionValue) {

                // This is where I'm stuck

                var div = document.getElementById('#word_block');
                div.innerHTML = div.innerHTML + 'Extra stuff';


            }

        }

    }

}

HTML:

<div id="work_block"></div>

How can I complete the code above to achieve similar functionality to the animated number counter example and increment through each letter of the word? I am looking for a javascript-based solution.

cpcdev
  • 1,130
  • 3
  • 18
  • 45

1 Answers1

1

I would build a letter object maintaining the letter and timings. This way you can provide a simple update functionality on the object and the object will itself make sure it produces the correct current letter.

For example:

function Letter(table, letter, duration) {
  this.table = table;                          // lookup-table
  this.letter = letter;                        // target letter
  this.current = 0;                            // index in table
  this.delay = duration / tbl.indexOf(letter); // ms
  this.time = Date.now();                      // current (start) time
  this.done = false;                           // status
}

Then a common prototyped update() method:

Letter.prototype.update = function() {
  if (this.done) return;                       // if done, do no more
  var time = Date.now();                       // get current time
  if (time - this.time >= this.delay) {        // exceeded delay?
    this.time = time;                          // store current time
    if (this.letter === this.table[this.current] || 
        this.current === this.table.length) {  // target reached? unknown letter
      this.done = true;                        // we're done
    }
    else {
      this.current++;                          // next in table
    }
  }
};

Then we can produce the objects from the string:

var letters = [];
word.toUpperCase().split("").forEach(function(l) {
  letters.push(new Letter(tbl, l, 2500));  // 2.5s duration
});

Then animate it:

(function loop() {
   var txt = "", isDone = true;
   letters.forEach(function(l) {
     l.update();
     if (!l.done) isDone = false;
     txt += l.table[l.current];
   });

   // output txt
   if (!isDone) requestAnimationFrame(loop);
   else { /* done */ }
})();

Demo

function Letter(table, letter, duration) {
  this.table = table;
  this.letter = letter;
  this.current = 0;
  this.delay = duration / tbl.indexOf(letter);   // ms
  this.time = Date.now();
  this.done = false;
}
Letter.prototype.update = function() {
  if (this.done) return;
  var time = Date.now();
  if (time - this.time >= this.delay) {
    this.time = time;
    if (this.letter === this.table[this.current] || 
        this.current === this.table.length) {
      this.done = true;
    }
    else {
      this.current++;
    }
  }
};

var word = "hello there";
var tbl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var letters = [];
word.toUpperCase().split("").forEach(function(l) {
  letters.push(new Letter(tbl, l, 2500))
});

(function loop() {
  var txt = "", isDone = true;
  letters.forEach(function(l) {
    l.update();
    if (!l.done) isDone = false;
    txt += l.table[l.current];
  });

  // output txt
  d.innerHTML = txt;
  
  if (!isDone) requestAnimationFrame(loop);
  else { /* done */ }
})();
#d {font:bold 32px monospace}
<div id=d></div>

Misc

If the delay is below 16.7ms it may not increment fast enough. It can be solved by dividing current relative time on duration. Multiply this normalized value with index of the target letter in the table to get a current, just round the result to an integer value.

You can provide different tables to obtain randomness/variation.

  • Thank you for the great solution! Works perfectly! – cpcdev Jun 18 '16 at 03:36
  • How about if the string has spaces? How can I ignore those undefined spaces? Thanks again for your help! – cpcdev Jun 18 '16 at 03:59
  • @cpcdev for spaces just add the space (and any other chars you want to support) to the table. You can add animation using jQuery to the element that shows the text. To animate each letter you can simply modify the Letter object to support this as well (f.ex. color/opacity) and use current time vs. duration to calculate progress (t=[0,1] x effect). –  Jun 18 '16 at 04:15
  • I forgot to mention that requestAnimationFrame do provide a timestamp, but older Safari/Opera/IE does not support it. If these aren't important then Date.now() can be replaced with this timestamp instead. Not so important here though, but I wanted to mention it for future readers. –  Jun 18 '16 at 04:23
  • Thanks for your response. I added the space to the table like you mentioned and it worked, however if you add two words for example "hi there" during the incrementing it appears as one word until the incrementing is finished. Any way around to show the space during the incrementing? – cpcdev Jun 18 '16 at 04:24
  • @cpcdev sure, just insert the space at the beginning. I updated the example using two words. –  Jun 18 '16 at 04:27