user3628468
user3628468

Reputation: 121

Canvas issues with updating

<canvas id="ctx" width="500" height="500" style="border:1px solid #000000;"> 

<script type="text/javascript">
 window.onload = function() {
var ctx = document.getElementById("ctx").getContext("2d"); 
    function createText(words) {
     var LENGTH = words.length;
     var LOOPS = LENGTH;
     var reader = 0;

     position = 10;
     while( LOOPS > 0) {
     letter = words.substr(reader,1);

     setTimeout(ctx.fillText(letter,position,10),100); 
     position += 6; 
     reader += 1; 
     LOOPS -= 1; 
      }

    }


    createText("Hello, how are you?");      

    }
</script>


</canvas> 

I want it to do kind of like a typing animation where it paused for a fraction of a second before each letter is printed, but instead it loads all at the same time. What am I doing wrong?

Upvotes: 1

Views: 34

Answers (1)

Loktar
Loktar

Reputation: 35309

So there were a few things making this not work for you, for setTimeout your ctx.fillText was being called right away, as soon as the loop hit it. To stop that you need to wrap it in a function so it will be called during the timeout.

setTimeout(function(){
    // your logic here.
}, 100);

However if you do that you will run into the common issue where you will only get the last letter due to the way variable scoping works in JavaScript. To fix that you need to wrap your function in a closure and pass the values to it.

// loop start
 a++;
 b++;
 setTimeout(
    (function (a,b) {
         return function () {
             // some logic that uses a and b
         }
 })(a, b), 100);
// loop end

The last thing that happens is your timeout is set to 100.. so it will all still happen at once. Meaning every timeout is going to fire after 100ms since the creation loop is so fast. In order to solve this you need to save the delay somewhere and increase that in the loop so they happen after one another. For example the first one will be delayed 100ms, and the next one 200ms, then 300, ect.

// loop start
 a++;
 b++;
 // Increase the time delay each loop iteration
 timeDelay += 100;

 setTimeout(
    (function (a,b) {
         return function () {
             // some logic that uses a and b
         }
 })(a, b), timeDelay);
// loop end

Full working code and demo

Live Demo

 window.onload = function () {
     var ctx = document.getElementById("ctx").getContext("2d");

     function createText(words) {
         var LENGTH = words.length;
         var LOOPS = LENGTH;
         var reader = 0;
         var timeDelay = 100;

         position = 10;

         while (LOOPS > 0) {
             letter = words.substr(reader, 1);

             setTimeout((function (letter, position) {
                 return function () {
                     ctx.fillText(letter, position, 10);
                 }
             })(letter, position), timeDelay);

             position += 6;
             reader += 1;
             LOOPS -= 1;
             timeDelay += 100;
         }

     }

     createText("Hello, how are you?");

 }

Upvotes: 2

Related Questions