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.
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.