The issue that I am having is keeping the text entered by a user vertically centered within the canvas element. I have built a test environment to try and solve this issue, which I have provided in this post along with a fiddle. Here is my code:
HTML:
Enter Your Text: <br/>
<textarea id="inputtextuser" onkeyup="inputtextgo()" name="Text">Enter Your</textarea> <br/>
TextBaseline:
<select id="inputtextbaseline" onchange="inputtextgo()";>
<option value="alphabetic">alphabetic</option>
<option value="top">top</option>
<option value="bottom">bottom</option>
<option value="middle">middle</option>
<option value="hanging">hanging</option>
</select> <br/>
<canvas id="canvas1" width="300px" height="200px" >Your browser does not support the HTML5 canvas tag.</canvas> <br/>
<div id ="textheightentered"></div>
CSS:
canvas {
border: solid 1px black;
}
JavaScript/jQuery:
//Declaring the Canvas
var canvas1 = document.getElementById('canvas1');
context1 = canvas1.getContext('2d');
//running the function to update the canvas
inputtextgo();
function inputtextgo() {
//Retrieving the text entered by the user
var inputtext = document.getElementById("inputtextuser").value;
//Calling the function to calculate the height on the text entered by the user
var textheight = fontheight(inputtext);
//retrieving the baseline selected by the user
var baseline = document.getElementById("inputtextbaseline").value;
//calculating the new y needed to center the text based on the height of the text
var y = 100 + textheight/2;
//Updating the canvas for the new text entered by the user
context1.clearRect(0, 0, 300, 200);
context1.font = "36px arial";
context1.textBaseline = baseline;
context1.fillText (inputtext, 0, y);
//Drawing a line across the middle of the canvas for reference
context1.strokeStyle="red";
context1.moveTo(5,100);
context1.lineTo(290,100);
context1.stroke();
$("#textheightentered").text("Text Height: " + textheight);
}
function fontheight(text){
var canvas=document.createElement("canvas");
canvas.width = 1000;
canvas.height = 200;
var ctx=canvas.getContext("2d");
function measureTextHeight(left, top, width, height,text) {
// Draw the text in the specified area
ctx.save();
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.baseline = "top";
ctx.fillText(text, 0, 35); // This seems like tall text... Doesn't it?
ctx.restore();
// Get the pixel data from the canvas
var data = ctx.getImageData(left, top, width, height).data,
first = false,
last = false,
r = height,
c = 0;
// Find the last line with a non-white pixel
while(!last && r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
last = r;
break;
}
}
}
// Find the first line with a non-white pixel
while(r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
first = r;
break;
}
}
// If we've got it then return the height
if(first != r) return last - first;
}
// We screwed something up... What do you expect from free code?
return 0;
}
ctx.font= "36px arial";
var height = measureTextHeight(0, 0, canvas.width, canvas.height,text);
//return the height of the string
return height;
} // end $(function(){});
JSFiddle: http://jsfiddle.net/grapien/R6DWN/3/
The issue I am having is that if the user enters a lower case "y" for example the text height changes and the text does not remain in the center of the canvas. This due to the fact that the baseline correction performed in the y variable would need to differ depending on the text entered (combination of lower and uppercase characters) as the text below the baseline is skewing the correction performed in the y variable.
This is where I am having my problems as I would like to keep the text centered at all times within the canvas element. The only thing I can think of is to calculate the non-blank pixels above an below the textbaseline reference point. Then use the difference from the baseline to the ends of the text to offset the text to center it on the canvas. I am not sure how you approach writing this script or if it is even possible. But that is the best approach I have came up with.
If anyone has any thoughts or guidance it would be greatly appreciated as developing an approach to solve this issue has got me stumped.
I believe I have solved this question using the technique I stated in the question. I created a new function that calculates the amount of the font that extends below the baseline of the text entered. Using a similar technique as to what was used to calculate the height. I use the alphabetic baseline then calculate the pixels that contain content above this baseline. See the function below.
function fontheight2(text){
var canvas=document.createElement("canvas");
canvas.width = 1000;
canvas.height = 200;
var ctx=canvas.getContext("2d");
function measureTextHeight(left, top, width, height,text) {
// Draw the text in the specified area
ctx.save();
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.fillText(text, 0, 100); // This seems like tall text... Doesn't it?
ctx.restore();
// Get the pixel data from the canvas
var data = ctx.getImageData(left, top, width, height).data,
first = false,
last = false,
r = 100,
c = 0;
// Find the first line with a non-white pixel
while(r) {
r--;
for(c = 0; c < width; c++) {
if(data[r * width * 4 + c * 4 + 3]) {
first = r;
break;
}
}
// If we've got it then return the height
if(first != r) return 99 - first;
}
// We screwed something up... What do you expect from free code?
return 0;
}
ctx.baseline = "Alphabetic";
ctx.font= "36px arial";
var height = measureTextHeight(0, 0, canvas.width, canvas.height,text);
//return the height of the string
return height;
} // end $(function(){});
From there I simply use the following adjustment to the y to offset the text to center:
var textheight = fontheight(inputtext); //Calculate Text Height
var textheight2 = fontheight2(inputtext); //Calculate portion above the baseline
var difference = textheight - textheight2; // Calculate the portion below the baseline
var y = 100 - difference + textheight/2; // Adjust the y cordinate
This offsets the y to adjust for the portion of the text that is below the text baseline. I have updated the JSFiddle here http://jsfiddle.net/grapien/R6DWN/6/.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With