javascript text animation delay issues

Viewed 54

Okay, so I have created this javascript text-animation that has a delay when writing text to my p element "output". The animation works just fine...but I decided that I wanted to add text color to specific words in my "message" parameter. I made that happen by using this code:

function write(message,clear,delay) {
    if(clear == true) clearMessage();
    if(typeof delay != "number") delay = game.message.delay;
    let q = undefined;
    let output = document.getElementById("output");
    let applyingColor = false;
    let dest = output;
    for(var i = 0 ; i < message.length ; i++) {
        let cur = i;
        let letter = message.charAt(i);
        let wait = delay*i;
        

        q = setTimeout(() => {
            if(letter == "<") {
                letter = "";
                applyingColor = true;
                let color = undefined;
                let a = message.substring(cur+1,message.length);
                let colorSig = a.substring(0,a.indexOf("/"));
                color = colorSig;

                let span = document.createElement("span");
                span.style.color = color;
                output.appendChild(span);
                dest = span;
            } else if(letter == ">") {
                letter = "";
                dest = output;
            } else if(letter == "|") {
                letter = "<br>";
            }
            if(applyingColor) {
                if(letter != "/") {
                    return;
                } else {
                    applyingColor = false;
                    return;
                }
            }
            dest.innerHTML += letter;
        },wait);

        writingQueue.push(q);
    }
}

the code above delays each character while also checking for very specific text such as <rgb(255,0,0)/ this is red>. the "<" and the ">" are starting and ending signifiers for the colored text, while the "/" is used to mark where the end of the color goes. The text you want to be colored would go before ">" and after "/". and that makes it red! or any color you want. But I noticed a small detail. Whenever you use this, it creates an additional delay. For example if you did something like...

write("Hello, foo! My name is <red/ bar>!");

it would delay the "b" in "bar" longer than it would delay the "f" in "foo".

I think the problem is being caused by

if(applyingColor) {
    if(letter != "/") {
        return
    } else {
        applyingColor = false
        return
    }
}

at around the bottom body of the q = setTimeout(...). What this code above does is skip over any letters that are not "/" while applyingColor is true, then turns it to false when it eventually reaches that wonderful little marker ("/") and returns one last time.

Honestly I dont know how to fix this. I've been working on this for hours now and my head hurts a lot. I could really use some help!

Oh! I forgot to mention. You can just ignore the "clear" and "delay" parameters. I do not believe they are relevant to my issue. The delay parameter is just the delay between each character. I have it to where it has a default value right now. And clear is just to clear previous text and clear out the writingQueue variable.

1 Answers

The problem in your current code is that as i increases over every iteration, so wait is being recalculated every check.. The first time it's 0 * delay, the second 1 * delay, the third 2 * delay. The solution while implementing only the current code would be to just define wait outside of the for loop.

buggy

let delay = 3;
for(var i = 0 ; i < 93 ; i++) {
   let wait = delay * i;
}
let delay = 3;
let wait = 3 * 3;
for(var i = 0 ; i < 93 ; i++) {

}

good

However, there is an even better way to do javascript animations like the one you made, assuming you want them all to take the same amount of time (given your problem, as I understand it, is that the later letters are taking longer <?>) & you're making a webpage

window.requestAnimationFrame(function)

which will wait until the next frame to execute the code, making it always happen with the illusion of no delay to the user

suboptimal

q = setTimeout(() => if(letter == "<") {
   /*...*/

faster, very rarely skips frames

q = window.requestAnimationFrame(() => if(letter == "<") {
   /*...*/

if you want the letters to change all at once, you can just put the entire for loop in a function and then call it using window.requestAnimationFrame(function).

window.requestAnimationFrame(colorIn);
function colorIn() {
    for(var i = 0 ; i < message.length ; i++) {
      let letter = message.charAt(i);
      if(letter == "<") {
        /*...*/

which will either make the letters changed all at once. if it can't, they'll change after dropping a few frames- though that should only happen if your computer has a virus or you change the color of an absolutely massive string

Related