Reputation: 3153
I have a canvas and I want to print words on it in horizontal and vertical orientation. The printing itself works fine but I have a somewhat annoying spacing at the beginning of the words, which becomes extremely visible on the vertical text like the EX on the example image.
I just created a little example which shows what I mean
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// Create a red line in position 150
ctx.strokeStyle = "red";
ctx.moveTo(150, 20);
ctx.lineTo(150, 170);
ctx.stroke();
ctx.font = "50px Arial";
// Show the different textAlign values
ctx.textAlign = "start";
ctx.fillText("EX", 150, 50);
ctx.textAlign = "end";
ctx.fillText("EX", 150, 100);
ctx.textAlign = "center";
ctx.fillText("EX", 150, 150);
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
Is there a way to place the beginning of the word at the point I am drawing to or is there a way to calculate the spacing at the beginning and then just subtract it from the starting point of the text?
Upvotes: 2
Views: 592
Reputation: 136698
The TextMetrics interface has actualBoundingBox[...]
information that you can use to know by how much the actual bounding box is offset relatively to the textAlign
and textBaseline
lines.
So adding the measured actualBoundingBoxLeft
to your horizontal position when writing LTR text with the "start"
text-align will remove this gap.
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const input = document.querySelector("input");
input.oninput = draw;
draw();
function draw() {
const txt = input.value;
ctx.clearRect(0, 0, c.width, c.height);
ctx.fillStyle = "black";
// Create a red line in position 150
ctx.strokeStyle = "red";
ctx.moveTo(150, 20);
ctx.lineTo(150, 180);
ctx.stroke();
ctx.font = "50px Arial";
ctx.textBaseline = "top"; // needed for the ascent and decsent measurements
// Show the original textAlign
ctx.textAlign = "start";
ctx.fillText(txt, 150, 30);
// fixed
ctx.fillStyle = "green";
const metrics = ctx.measureText(txt);
ctx.fillText(txt, 150 + metrics.actualBoundingBoxLeft, 110);
// Draw the box around our text
ctx.translate( 150, 110 );
const x = 0; // we already did offset by actualBoundingBoxLeft
const y = metrics.actualBoundingBoxAscent * -1;
const width = metrics.actualBoundingBoxRight + metrics.actualBoundingBoxLeft;
const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent;
ctx.strokeRect(x, y, width, height);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
<input value="Éxy"><br>
<canvas id="myCanvas" width="300" height="200" style="border:1px solid #d3d3d3;"></canvas>
Upvotes: 1