JavaScript: ‘Running text’ backdrop on canvas

In this interesting post, I will show you how you can get the effect of ‘running text’ as a backdrop using the canvas element in JavaScript.

What is meant by ‘Running Text’

‘Running Text’ is a particular type of animation where our text literally ‘runs’ across the screen. Random words repeatedly appear one after another as the text of a container. The words move from left to right, until the containers right margin. Then they start again from the next line. The animation ends when the container has been completely filled with words.

One can think of several possibilities to put this to use.

Consider the login page of an e-commerce website. In the background, all relevant words which describe the philosophy and ideology of the site are being shown in the background, allowing the user to gain a better experience.

Or if we are looking at the website for an online coding competition, we could have the syntax and keywords of various languages scrolling in the background for a better effect.

Setting up the base canvas

In this post, I will be using the canvas element to create the effect. You can use a div too. The logic and code are very similar.

Let us set up our base canvas.

Open a new Html file. Create a canvas in the body tag like so:

<canvas id="running-text" height=400px width=900px></canvas>

We create a blank canvas of a given width and height.

Now let us focus on the parameters and associated functions required by the animation.

Parameters and associated functions

Our ‘running text’ animation should be as configurable as possible:

  • We want to be able to choose the background color.
  • We want different words to have different colors.

Let us see how we can go about this.

For the background color, we can create a parameter which the user must pass into the animation function. However, having words with different colors is more complicated. For simplicity, I would do it the following way:

I would pass an object into our animation function. In the object, our words would be the keys, and their corresponding colors would be their values.
Suppose I want three words ‘CodeSpeedy’, ‘JavaScript’ and ‘Canvas’. I define my object as follows:

const word_color_pairs={
  'CodeSpeedy': '#ff0000',
  'JavaScript': '#000000',
  'Canvas': '#007fff',
};

We have three words as keys, and each value contains the color of its key. This object will be passed into our function.

We need one thing more. As our function will randomly choose words and render them, we need a way to extract a key value pair at random from the above object. So we create the following function:

const getRandomKVPair=function(object)
{
  const keys=Object.keys(object);
  const rand_key=keys[Math.floor(Math.random()*keys.length)];
  return {
    'key': rand_key,
    'value': object[rand_key],
  };
};

Our function ‘getRandomKVPair’ takes an object as its argument. We get all the keys of that object using the ‘Object.keys’ function. ‘Object.keys’ returns an array of keys of the object given to it.

From that array, we choose one key at random. That key will be our word. The value corresponding to that key is the words’ color. Both of them are returned in an object so that we can use them later.

Now let us look at the preliminary variables and functions our animation will require.

The preliminaries.

We will need the following variables for our animation to run smoothly:

const canvas=document.getElementById('running-text');
const canvas_context=canvas.getContext('2d');
let animation_id=undefined;
let word_x=0;
let word_y=10;

We store the canvas separately. The ‘getContext’ canvas method gives the canvas context for rendering. Here, we use the ‘2d’ parameter to get the 2D rendering context for our canvas. All our rendering will be done on this rendering context.

‘animation_id’ is the interval id of the animation. We need to store this as the animation will have to stop our animation when the canvas is filled.

We also have two coordinates representing the X and Y positions at which we will render our text on the canvas 2D context. The origin of the coordinate system is measured from the upper left corner of the canvas.

Apart from this, we will need a function to explicitly stop the animation when it is required.

const stopRunning=function()
{
  if(animation_id!==undefined)
    window.clearInterval(animation_id);
  animation_id=undefined;
};

Now let us create the main animation function.

The animation

Type in the following code in the script tag:

const startRunning=function(word_color_pairs,canvas_background,interval)
{
  const max_width=canvas.width;
  const max_height=canvas.height;
  //Blanket the canvas with the background.
  canvas_context.fillStyle=canvas_background;
  canvas_context.fillRect(0,0,max_width,max_height);
  const run=function()
  {
    console.log('running');
    if(word_y>max_height)
    {
      stopRunning();
      return;
    }
    //Get info here.
    const w_c_pair=getRandomKVPair(word_color_pairs);
    //The actual width of the string measured in pixels according to the canvas.
    const canvas_font_width=canvas_context.measureText(w_c_pair['key']+' ').width;
    //The font color is set.
    canvas_context.fillStyle=w_c_pair['value'];
    //Render the random keyword.
    canvas_context.fillText(w_c_pair['key']+' ',word_x,word_y);
    //Update the rendering X-coordinate.
    word_x+=canvas_font_width;
    //If the X coordinate goes out of bounds, goto the beginning of the next line.
    if(word_x>max_width)
    {
      word_x=1;
      word_y+=10;
    }
  };
  //Begin the animation.
  animation_id=window.setInterval(run,interval);
};

Let us break down this function bit by bit.

Our function takes in three parameters:

  1. The object of word-color pairs.
  2. The backdrop color.
  3. The time interval of the animation.

The first thing we do is get the dimensions of the canvas. We need these as we will have to adjust our rendering coordinates accordingly.
The ‘fillStyle’ method of the context sets the color to use inside any shape we may render. We use it to set the canvas background color. The ‘fillRect’ method covers the canvas with a rectangle in the color we had set. The net effect is that our canvas is now completely colored in the color we want.

Our inner function ‘run’ will add words to the canvas every time it is called. Let us see how it works.

The core animation logic

We first check the Y-coordinate of rendering. If it is beyond the vertical bounds of the canvas, we stop our animation and ‘run’ terminates.
If we are within bounds, then we get a random key-value pair from the word-color pair object passed in earlier. Recall that the key is the word to render, and its value is its color.

We then get the width the selected word will occupy on the canvas by calling the ‘measureText’ method on the canvas context. This method returns information about the text string passed to it with reference to the canvas context. We use this method and get the width of the word so that we can increment our X-coordinate after rendering.

For rendering our word, we call ‘fillStyle’ again with the color of the word. We then render our word on the canvas at the desired location using the ‘fillText’ method. Note that to separate the words in the canvas, we render the text with an added space to it. The X-coordinate is consistent with this as we compute the width of the word after adding the blank space.

Once the rendering is complete, we update the X-coordinate. If it goes outside the right margin of the canvas, we reset it and move the Y-coordinate for rendering downwards.

At the end of the ‘startRunning’ function, ‘run’ is called repeatedly with the interval given. The interval id is stored as we are stopping it later.

Testing our animation

To test the animation, call the ‘startRunning’ function.

startRunning(word_color_pairs,'#ffff00',50);

If everything has worked out well, we should see the ‘running text’ effect on our canvas. Below is a snapshot of our animation in action.

The complete code

Below is the complete code we have used to get our desired effect.

<html>
  <body>
    <canvas id="running-text" height=400px width=900px></canvas>
    <script>
      const word_color_pairs={
        'CodeSpeedy': '#ff0000',
        'JavaScript': '#000000',
        'Canvas': '#007fff',
      };
      const getRandomKVPair=function(object)
      {
        const keys=Object.keys(object);
        const rand_key=keys[Math.floor(Math.random()*keys.length)];
        return {
          'key': rand_key,
          'value': object[rand_key],
        };
      };
      const canvas=document.getElementById('running-text');
      const canvas_context=canvas.getContext('2d');
      let animation_id=undefined;
      let word_x=0;
      let word_y=10;
      const stopRunning=function()
      {
        if(animation_id!==undefined)
          window.clearInterval(animation_id);
        animation_id=undefined;
      };
      const startRunning=function(word_color_pairs,canvas_background,interval)
      {
        const max_width=canvas.width;
        const max_height=canvas.height;
        //Blanket the canvas with the background.
        canvas_context.fillStyle=canvas_background;
        canvas_context.fillRect(0,0,max_width,max_height);
        const run=function()
        {
          console.log('running');
          if(word_y>max_height)
          {
            stopRunning();
            return;
          }
          //Get info here.
          const w_c_pair=getRandomKVPair(word_color_pairs);
          //The actual width of the string measured in pixels according to the canvas.
          const canvas_font_width=canvas_context.measureText(w_c_pair['key']+' ').width;
          //The font color is set.
          canvas_context.fillStyle=w_c_pair['value'];
          //Render the random keyword.
          canvas_context.fillText(w_c_pair['key']+' ',word_x,word_y);
          //Update the rendering X-coordinate.
          word_x+=canvas_font_width;
          //If the X coordinate goes out of bounds, goto the beginning of the next line.
          if(word_x>max_width)
          {
            word_x=1;
            word_y+=10;
          }
        };
        //Begin the animation.
        animation_id=window.setInterval(run,interval);
      };
      startRunning(word_color_pairs,'#ffff00',50);
    </script>
  </body>
</html>

Along with this, we have a console log statement for debugging purposes. If you open the console, you will find that the message is continuously logged to the console until the animation is stopped. This indicates that our animation works correctly.

Leave a Reply

Your email address will not be published. Required fields are marked *