Search code examples
javascripthtmlcanvassingle-threaded

Canvas is not updating until JavaScript has finished executing


Doing Infix to PostFix Stack Implementation using HTML5 canvas. The desired output is, element box in the canvas must have to output every character for 1 sec and then fade away. While the problem is element box in the canvas is updating after the code execution finished, which results in overlapping of all the character in the canvas element box and then fading out after 1 sec.

Please have a look at the code below:

function convert(e){         // when convert button click
    var x = document.getElementById('infix').value;
    var stack = new Stack();
    stack.postFix(x);
}

function elementVisualize(ele){
    var eleVis = canvas.getContext('2d');

    eleVis.fillText(ele,150,150);
    console.log(ele);

    setTimeout(function(){
        eleVis.clearRect(100,80,148,148);
    }, 1000);
}

postFix(exp){           // Stack.postFix function
    for(var i = 0; i < exp.length ; i++){
        var c = exp[i];
        if((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z')){
            elementVisualize(c);
        }
    }

}

is their anyway to update the canvas for each character separately ?


Solution

  • One option would be for elementVisualize to return a Promise that resolves when the rectangle is cleared, and to await that Promise on every iteration of the for loop:

    function elementVisualize(ele){
        var eleVis = canvas.getContext('2d');
    
        eleVis.fillText(ele,150,150);
    
        return new Promise((resolve) => {
            setTimeout(function(){ 
                eleVis.clearRect(100,80,148,148);
                resolve();
            }, 1000);
        });
    }
    
    async postFix(exp){           // Stack.postFix function
         for(var i = 0; i < exp.length ; i++){
         var c = exp[i];
         if((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z')){
               await elementVisualize(c);
         }
    }
    

    If the postFix method can also be called again before all animations are done, and you want it to wait for the previous postFix call's animations to finish, you might consider a persistent queue of sorts, to which postFix pushes items (the characters of exp), and have elementVisualize shift() an item from that array and then call itself again after the animation if there some characters remain in the array.