Reputation: 141
fontsize = 50px
pink line: y in
ctx.fillText(text, x, y);
blue line: y - 50
khaki line: y + 50
pic1: with
ctx.textBaseline = "bottom";
the letter's top exceeds positionY - fontsize
pic2:with
ctx.textBaseline = "top";
the letter's bottom exceeds positionY + fontsize
It's strange.
Why and how to solve this problem?
My case is I need to blur the text, but Safari don't support ctx.filter
So I write a customBlur filter using getImageData & putImageData.
But when use it to blur the text, I encountered this problem:
I can't get the right y-axis position of my text.
Tried hanging/ideographic/middle/alphabetic, they all get worse result.
Thank you, I didn't know there was a useful code snippet support. I made the code snippet. As follows, looks like it depends on the font.
When I use Verdana, English words works well but Chinese characters and some symbol didn't.
When I switch to PingFang SC, only Chinese characters in hanging mode made it to be in a predictable space.
ctx.font = "50px Verdana, PingFang SC" works the best with bottom mode.
let radios = Array.from(document.querySelectorAll("[type='radio']"))
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cx = canvas.width/2;
let cy = canvas.height/2;
ctx.font="50px Verdana, PingFang SC";
ctx.fillStyle = "blue";
ctx.textAlign="center";
ctx.textBaseline="top";
//ctx.textBaseline="middle";
//ctx.textBaseline="bottom";
//ctx.textBaseline="alphabetic";
//ctx.textBaseline="hanging";
radios.forEach(r=>{
r.addEventListener("input",()=>{
if(r.checked){
ctx.textBaseline=r.value;
ctx.clearRect(0, 0, canvas.width,canvas.height);
draw()
}
})
})
draw();
function draw(){
ctx.fillText("abpf-+=|{}[]中文",cx,cy);
ctx.strokeStyle="red";
ctx.moveTo(5,cy);
ctx.lineTo(445,cy);
ctx.stroke();
ctx.moveTo(5,cy - 50);
ctx.lineTo(445,cy - 50);
ctx.stroke();
ctx.moveTo(5,cy + 50);
ctx.lineTo(445,cy + 50);
ctx.stroke();
}
canvas{border:1px solid;}
<canvas width="450" height="150" id="canvas"> :( </canvas>
<p>
<label>top: <input name="textBaseline" type="radio" value="top" checked /></label><br>
<label>middle: <input name="textBaseline" type="radio" value="middle" /></label><br>
<label>bottom: <input name="textBaseline" type="radio" value="bottom" /></label><br>
<label>alphabetic: <input name="textBaseline" type="radio" value="alphabetic" /></label><br>
<label>hanging: <input name="textBaseline" type="radio" value="hanging" /></label>
</p>
Upvotes: 1
Views: 122
Reputation: 33024
I doubt that this will solve your problem. However: it's always helpful to make yourself a little demo like this.
let radios = Array.from(document.querySelectorAll("[type='radio']"))
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cx = canvas.width/2;
let cy = canvas.height/2;
ctx.font="50px Verdana";
ctx.fillStyle = "blue";
ctx.textAlign="center";
ctx.textBaseline="top";
//ctx.textBaseline="middle";
//ctx.textBaseline="bottom";
//ctx.textBaseline="alphabetic";
//ctx.textBaseline="hanging";
radios.forEach(r=>{
r.addEventListener("input",()=>{
if(r.checked){
ctx.textBaseline=r.value;
ctx.clearRect(0, 0, canvas.width,canvas.height);
draw()
}
})
})
draw();
function draw(){
ctx.fillText("abpf",cx,cy);
ctx.strokeStyle="red";
ctx.moveTo(5,cy);
ctx.lineTo(245,cy);
ctx.stroke();
}
canvas{border:1px solid;}
<canvas width="250" height="150" id="canvas"> :( </canvas>
<p>
<label>top: <input name="textBaseline" type="radio" value="top" checked /></label><br>
<label>middle: <input name="textBaseline" type="radio" value="middle" /></label><br>
<label>bottom: <input name="textBaseline" type="radio" value="bottom" /></label><br>
<label>alphabetic: <input name="textBaseline" type="radio" value="alphabetic" /></label><br>
<label>hanging: <input name="textBaseline" type="radio" value="hanging" /></label>
</p>
Upvotes: 1