i am using the HTML5 canvas API to display screen some cable (canvas.fillText), and I to be wondering whether text-decoration (like underline, strikethrough, etc.) was something possible with the canvas API. Unfortunately, I discovered nothing about this.

You are watching: How to underline text in canva

The only solution I discovered was to manually execute the decoration utilizing the canvas illustration API (I mean, explicitly drawing a horizontal line, because that example, to mimic the "underline" decoration).

Is this possible using the canvas text API?


*

*

It won"t work with a integrated method, however here is a simplified function I used successfully based on reading, "HTML5 Canvas: message underline workaround" on the ScriptStock website.

var underline = function(ctx, text, x, y, size, color, thickness ,offset) var broad = ctx.measureText(text).width; switch(ctx.textAlign) instance "center": x -= (width/2); break; instance "right": x -= width; break; y += size+offset; ctx.beginPath(); ctx.strokeStyle = color; ctx.lineWidth = thickness; ctx.moveTo(x,y); ctx.lineTo(x+width,y); ctx.stroke();

*

*

You deserve to do this by making use of measureText and fillRect favor so:

ctx.fillText(text, xPos, yPos);let width = ctx.measureText("Hello World");ctx.fillRect(xPos, yPos, width, 2);The only daunting part around this approach is there is no way to attain the elevation use measureText. Otherwise, you can use that as your Y name: coordinates when drawing your fillRect.

Your Y position will just depend on the height of your text and also how close you"d favor the underline.

See more: Lauv I Met You When I Was 18 (Incl, I Met You When I Was 18 (The Playlist)

Demo in stack Snippets


// get canvas / contextvar deserve to = document.getElementById("my-canvas");var ctx = can.getContext("2d")let xPos=10, yPos=15;let message = "Hello World"ctx.fillText(text, xPos, yPos);let broad = ctx.measureText("Hello World");ctx.fillRect(xPos, yPos, width, 2);

*

I developed an alternate version of Mulhoon"s code. I likewise take into account the message baseline.

const underline = (ctx, text, x, y) => let metrics = measureText(ctx, text) allow fontSize = Math.floor(metrics.actualHeight * 1.4) // 140% the height switch (ctx.textAlign) instance "center" : x -= (metrics.width / 2) ; break situation "right" : x -= metrics.width ; break move (ctx.textBaseline) situation "top" : y += (fontSize) ; break instance "middle" : y += (fontSize / 2) ; rest ctx.save() ctx.beginPath() ctx.strokeStyle = ctx.fillStyle ctx.lineWidth = Math.ceil(fontSize * 0.08) ctx.moveTo(x, y) ctx.lineTo(x + metrics.width, y) ctx.stroke() ctx.restore()

Full Example


const triggerEvent = (el, eventName) => var occasion = document.createEvent("HTMLEvents") event.initEvent(eventName, true, false) el.dispatchEvent(event)const measureText = (ctx, text) => allow metrics = ctx.measureText(text) return width: Math.floor(metrics.width), height: Math.floor(metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent), actualHeight: Math.floor(metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent) const underline = (ctx, text, x, y) => allow metrics = measureText(ctx, text) allow fontSize = Math.floor(metrics.actualHeight * 1.4) // 140% the elevation switch (ctx.textAlign) case "center" : x -= (metrics.width / 2) ; break instance "right" : x -= metrics.width ; rest switch (ctx.textBaseline) situation "top" : y += (fontSize) ; break case "middle" : y += (fontSize / 2) ; rest ctx.save() ctx.beginPath() ctx.strokeStyle = ctx.fillStyle ctx.lineWidth = Math.ceil(fontSize * 0.08) ctx.moveTo(x, y) ctx.lineTo(x + metrics.width, y) ctx.stroke() ctx.restore()const getOrigin = (ctx) => ( x : Math.floor(ctx.canvas.width / 2), y : Math.floor(ctx.canvas.height / 2))const redraw = (ctx, sampleText, fontSize) => let origin = getOrigin(ctx) ctx.font = fontSize + "px Arial" ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height) renderText(ctx, sampleText, origin.x, origin.y, "Yellow", "left", "top") renderText(ctx, sampleText, origin.x, origin.y, "SkyBlue ", "right", "bottom") renderText(ctx, sampleText, origin.x, origin.y, "Tomato", "left", "bottom") renderText(ctx, sampleText, origin.x, origin.y, "Chartreuse ", "right", "top") renderText(ctx, sampleText, origin.x, origin.y, "Black", "center", "middle")const renderText = (ctx, text, x, y, fillStyle, textAlign, textBaseLine) => ctx.fillStyle = fillStyle ctx.textAlign = textAlign ctx.textBaseline = textBaseLine ctx.fillText(text, x, y) underline(ctx, text, x, y)const sampleText = "Hello World"const fontSizes = < 8, 12, 16, 24, 32 >document.addEventListener("DOMContentLoaded", () => let ctx = document.querySelector("#demo").getContext("2d") permit sel = document.querySelector("select") fontSizes.forEach(fontSize => sel.appendChild(new Option(fontSize, fontSize))) sel.addEventListener("change", (e) => redraw(ctx, sampleText, sel.value)) sel.value = fontSizes triggerEvent(sel, "change"))canvas border: thin solid grey label font-weight: bolder label::after content: ": " Font dimension