How to slow a function that types a random string from an array when it comes across a period or comma?

Viewed 216

I have a typewriter function as such:

var myArray = [
  'sentence. another sentence.', 
  'this sentence. yet another sentence.', 
];
var rand = myArray[Math.floor(Math.random() * myArray.length)];
var i = 0;
var speed = 55;

function typeWriter() {
  if (i < rand.length) {
    document.getElementById("question").innerHTML += rand.charAt(i);
    i++;
    setTimeout(typeWriter, speed);
  }
}

typeWriter();
<div id="question"></div>

How can I have the typewriter function speed change to say, 80ms, if the character it's currently typing is a period or comma, then return to 55ms when it's typing normal letters? This would help me to imitate the rhythm of speech with the typing function and improve readability. Thanks for your help.

4 Answers

Just change speed or the 2nd param to setTimeout.

While you're at it, you may as well make the code cleaner by:

1) using await instead of setTimeout,

2) name your delays (e.g. DELAYS) as opposed to a bunch of inline constants

3) use a proper for loop instead of a reinventing the for loop with if statements

4) use proper local variables and function params instead of global variables.

5) Use Element.textContent instead of innerHTML

6) Use single quotes in JS unless necessary to do otherwise.

let el = document.querySelector('div');

let wait = delay => new Promise(r => setTimeout(r, delay));

let typeWriter = async sentence => {
  const DELAYS = {'.': 500, ',': 200, default: 55};

  for (let c of sentence) {
    el.textContent += c;
    await wait(DELAYS[c] || DELAYS.default);
  }
};

typeWriter('sentence. a comma, another sentence. this sentence. yet another sentence.');
<div></div>

Just check the current character inside typeWriter, and set the next character's timeout accordingly.

To achieve this, it's practical to use the conditional (ternary) operator (? :):

var myArray = ['sentence. another sentence.', 
              'this sentence. yet another sentence.', 
           ];
var rand = myArray[Math.floor(Math.random() * myArray.length)];
var i = 0;
function typeWriter() {
  if (i < rand.length) {
    document.getElementById("question").innerHTML += rand.charAt(i);
    setTimeout(typeWriter, ['.', ','].includes(rand.charAt(i)) ? 80 : 55);
    i++
  }
}

You already have a variable called speed, so why not change its value when the current character is a comma or a period? (Don't forget to change it back later!).

var myArray = ['sentence. another sentence.', 
              'this sentence. yet another sentence.', 
           ];
var rand = myArray[Math.floor(Math.random() * myArray.length)];
var i = 0;
var speed = 55;
  function typeWriter() {
    if (i < rand.length) {
      document.getElementById("question").innerHTML += rand.charAt(i);
 
    if(rand.charAt(i) == '.' || rand.charAt(i) == ',') {
      speed = 1000;
    }
    else {
      speed = 85;
    }
    i++;
    setTimeout(typeWriter, speed);
  }
}

typeWriter();
<p id="question"></p>

This is how I'd do it (makes it more modular, also in ES6 style)

const typeWriter = (str, writeTo, charDelays) => {
  if (!str) return; // Empty
  const nextChar = str.charAt(0);
  writeTo.textContent += nextChar;
  setTimeout(
    () => typeWriter(str.slice(1), writeTo, charDelays), // typeWriter rest of the string
    charDelays[nextChar] || charDelays.DEFAULT || 55 // Custom delay per character
  );
}

Then you can do this:

typeWriter('my, very awesome, string!?', document.getElementById('question'), {
  '!': 80,
  ',': 80
});
Related