Drawing Text on the Canvas

by kirupa | 19 November 2015

This may come as a shock to you, so I encourage you to be seated for what I am about to say next. The things you can draw on the canvas aren't limited to just lines and shapes. You can also draw text. Not only that, you can extensively customize the text without breaking too much of a sweat. In this tutorial, we will take a look at what all of this means.


This is a companion discussion topic for the original entry at http://www.kirupa.com/canvas/drawing_text.htm

is it possible to change different colors for each text in a single sentence?
if not is the modification is possible to select & change the text color

Yes! This is a great question, and I spent some time fiddling with this. The main thing to note is that each word or phrase you want to format differently has to have its own set of drawing instructions.

First, here is the full code to see how I have each word in our text have a different color:

<!DOCTYPE html>
<html>

<head>
  <title>Canvas Text Example</title>
  <style>
    canvas {
      border: #333 10px solid;
    }
  </style>
</head>

<body>
  <canvas id="myCanvas" width="550px" height="350px"></canvas>

  <script>

    let words = ["Hello", "Foo", "Hamburger", "Monday", "Cold", "Happy"];
    let canvas = document.querySelector("#myCanvas");
    let ctx = canvas.getContext("2d");

    let h_range = [0, 360];
    let s_range = [90, 100];
    let l_range = [0, 40];
    let a_range = [1, 1];

    // Call first before drawing!
    adjustForHighDPI();

    function drawText() {
      ctx.font = "bold 20px Helvetica, Arial, sans-serif";

      let xPos = 50;
      let yPos = 200;
      let spaceBetweenWord = 5;

      for (let i = 0; i < words.length; i++) {
        let word = words[i];
        let randomColor = getRandomColor(h_range, s_range, l_range, a_range).hslaValue;

        ctx.fillStyle = randomColor;
        ctx.fillText(word, xPos, yPos);

        let lengthOfWord = ctx.measureText(word);
        let measureLength = lengthOfWord.width + 20;

        xPos += measureLength;
      }
    }
    drawText();


    function adjustForHighDPI() {
      //
      // From: https://www.kirupa.com/canvas/canvas_high_dpi_retina.htm
      //

      // get current size of the canvas
      let rect = canvas.getBoundingClientRect();

      // increase the actual size of our canvas
      canvas.width = rect.width * devicePixelRatio;
      canvas.height = rect.height * devicePixelRatio;

      // ensure all drawing operations are scaled
      ctx.scale(devicePixelRatio, devicePixelRatio);

      // scale everything down using CSS
      canvas.style.width = rect.width + 'px';
      canvas.style.height = rect.height + 'px';
    }
      
    //
    // From: https://www.kirupa.com/html5/generating_random_colors.htm
    //
    function getRandomColor(h, s, l, a) {
      let hue = getRandomNumber(h[0], h[1]);
      let saturation = getRandomNumber(s[0], s[1]);
      let lightness = getRandomNumber(l[0], l[1]);
      let alpha = getRandomNumber(a[0] * 100, a[1] * 100) / 100;

      return {
        h: hue,
        s: saturation,
        l: lightness,
        a: alpha,
        hslaValue: getHSLAColor(hue, saturation, lightness, alpha)
      }
    }

    function getRandomNumber(low, high) {
      var r = Math.floor(Math.random() * (high - low + 1)) + low;
      return r;
    }

    function getHSLAColor(h, s, l, a) {
      return `hsl(${h}, ${s}%, ${l}%, ${a})`;
    }
  </script>

</body>

</html>

The code does seem like a lot, but the reason is that (as you can see in the code comments), I had to pull in some code to ensure the content looked good on High DPI screens and some code for generating a random color.

The part to focus on is the drawText function:

function drawText() {
  ctx.font = "bold 20px Helvetica, Arial, sans-serif";

  let xPos = 50;
  let yPos = 200;
  let spaceBetweenWord = 5;

  for (let i = 0; i < words.length; i++) {
    let word = words[i];
    let randomColor = getRandomColor(h_range, s_range, l_range, a_range).hslaValue;

    ctx.fillStyle = randomColor;
    ctx.fillText(word, xPos, yPos);

    let lengthOfWord = ctx.measureText(word);
    let measureLength = lengthOfWord.width + 20;

    xPos += measureLength;
  }
}

I have the xPos variable to track the horizontal position of each word, and I use a loop to treat each word (from the words array) as its own drawing activity. The challenge is in knowing how far to move my horizontal position with each word we print. That is where the last three lines that involve the measureText function come in. The measureText function gets the size of the text, and I use the width of that size and give it a spacing to increment our xPos value by :straight_ruler:

Let me know if you are unblocked here :slight_smile:

Cheers,
Kirupa

Sorry, no random color required, but i can set to selected texts within the same text area, or the user can set.
like this image:

The code I shared will handle that as well. Just replace the random color code with the color you need per text or word. When you say “selected texts”, what do you mean? A user can click on the word and specify their own color?

for example on this page, i added canvas -
https://hindimarathistatus.com/text-on-photo/hanuman-jayanti-wishes-maker-hindi/

& want अपना सन्देश लिखे are 3 words. & want user can change different color of all 3 words within the same text area. I don’t want to create 3 different add texts. this frame is set from the admin backend. i will give the same front option to user as well.

Yes