1

Lets say I have the following text:

The Text

Is it possible to write this text on canvas but with The bold and Text normal?

So it will look this way:

The Text

I know the way to write the entire The Text bold but I cant find a way to format it separately.

  • 2
    **See Also**: [HTML5 Canvas API - formatting individual words with italics](https://stackoverflow.com/q/24163211/1366033) – KyleMit Nov 19 '20 at 19:55

3 Answers3

1

As long as the bold word is first, you could simply write over your existing text:

var canvas = document.body.appendChild(document.createElement("canvas"));
var size = canvas.width = canvas.height = 200;
var ctx = canvas.getContext("2d");
function draw() {
    ctx.clearRect(0, 0, size, size);
    ctx.font = "10pt Courier";
    ctx.fillText("The Text", 100, 100);
    setTimeout(function () {
        ctx.font = "bold 10pt Courier";
        ctx.fillText("The", 100, 100);
        setTimeout(draw, 1000);
    }, 1000);
}
draw();

EDIT 1 - In response to comments

In the case of more complex string, one could use measuretext to compute position and switch the font dynamically:

/**
 * drawText
 * Draws a string on a canvas. Handles <b> tags.
 * @param {{
 *  text: string,
 *  canvas: HTMLCanvasElement,
 *  offsetY?: number
 *  offsetX?: number,
 *  fontFamily?: string
 *  fontSize?: number
 *  clear?: boolean
 * }} params
 * @returns
 */
function drawText(params) {
    //get parameters
    var text = params.text !== void 0 ? params.text : "";
    var canvas = params.canvas !== void 0 ? params.canvas : null;
    if (canvas instanceof HTMLCanvasElement == false) {
        console.error("You must provide a canvas to draw on");
        return false;
    }
    var ctx = canvas.getContext("2d");
    var fontFamily = params.fontFamily !== void 0 ? params.fontFamily : "Courier";
    var fontSize = params.fontSize !== void 0 ? params.fontSize : 10;
    var offsetX = params.offsetX !== void 0 ? params.offsetX : 0;
    var offsetY = params.offsetY !== void 0 ? params.offsetY : 0;
    //Split string by <b> tags
    var formatted = text.split(/<\/b>|<b>/ig)
        .filter(function (val) {
        return val.length > 0;
    });
    //Clear canvas
    if (params.clear !== void 0 ? params.clear : false) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    }
    //set base font
    ctx.font = fontSize + "pt " + fontFamily;
    //Test if we start bold
    var b = (text.substr(0, 1) == "<b");
    for (var i = 0; i < formatted.length; i++) {
        var t = formatted[i];
        //Inverse bold on each step
        b = !b;
        if (b == true) {
            ctx.font = fontSize + "pt " + fontFamily;
        }
        else {
            ctx.font = "bold " + fontSize + "pt " + fontFamily;
        }
        //Calculate offset
        var offset = i === 0 ? 0 : ctx.measureText(formatted.slice(0, i).join("")).width;
        //Draw at position
        ctx.fillText(t, offset + offsetX, offsetY);
    }
    return true;
}
//TEST
var canvas = document.body.appendChild(document.createElement("canvas"));
canvas.width = 230;
canvas.height = 30;
drawText({ text: "I Freaking <b>Love</b> Darth <b>Vader!</b>", canvas: canvas, offsetY: 10 });
drawText({ text: "I Freaking <b>Love</b> Darth <b>Vader!</b>", canvas: canvas, offsetY: 25 });
Emil S. Jørgensen
  • 6,216
  • 1
  • 15
  • 28
1

Drawing text is hard, the hardest part is to compute the position of the text based on fonts (the first bold part at (0, 0), the second at (50, 0)).

I recommend you carota (don't seem maintained anymore but works well), it already handles everything and has an HTML friendly data model. If you don't want any dependencies or if you thing it's too much then Emil's solution is better.

Fathy
  • 4,939
  • 1
  • 23
  • 25
0

Maybe this will help you. Just write the text twice!

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font= "Bold 30px Arial";
ctx.fillText("The",10,50);
ctx.font= "30px Arial";
ctx.fillText("Text",70,50);
<canvas id="myCanvas" width="200" height="100"></canvas>
Mrigank Pawagi
  • 892
  • 1
  • 8
  • 26