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
Let me know if you are unblocked here
Cheers,
Kirupa