html canvas文本高度,javascript - How can you find the height of text on an HTML canvas? - Stack Overflow...

Here is a simple function. No library needed.

I wrote this function to get the top and bottom bounds relative to baseline. If textBaseline is set to alphabetic. What it does is it creates another canvas, and then draws there, and then finds the top most and bottom most non blank pixel. And that is the top and bottom bounds. It returns it as relative, so if height is 20px, and there is nothing below the baseline, then the top bound is -20.

You must supply characters to it. Otherwise it will give you 0 height and 0 width, obviously.

Usage:

alert(measureHeight('40px serif', 40, 'rg').height)

Here is the function:

function measureHeight(aFont, aSize, aChars, aOptions={}) {

// if you do pass aOptions.ctx, keep in mind that the ctx properties will be changed and not set back. so you should have a devoted canvas for this

// if you dont pass in a width to aOptions, it will return it to you in the return object

// the returned width is Math.ceil'ed

console.error('aChars: "' + aChars + '"');

var defaultOptions = {

width: undefined, // if you specify a width then i wont have to use measureText to get the width

canAndCtx: undefined, // set it to object {can:,ctx:} // if not provided, i will make one

range: 3

};

aOptions.range = aOptions.range || 3; // multiples the aSize by this much

if (aChars === '') {

// no characters, so obviously everything is 0

return {

relativeBot: 0,

relativeTop: 0,

height: 0,

width: 0

};

// otherwise i will get IndexSizeError: Index or size is negative or greater than the allowed amount error somewhere below

}

// validateOptionsObj(aOptions, defaultOptions); // not needed because all defaults are undefined

var can;

var ctx;

if (!aOptions.canAndCtx) {

can = document.createElement('canvas');;

can.mozOpaque = 'true'; // improved performanceo on firefox i guess

ctx = can.getContext('2d');

// can.style.position = 'absolute';

// can.style.zIndex = 10000;

// can.style.left = 0;

// can.style.top = 0;

// document.body.appendChild(can);

} else {

can = aOptions.canAndCtx.can;

ctx = aOptions.canAndCtx.ctx;

}

var w = aOptions.width;

if (!w) {

ctx.textBaseline = 'alphabetic';

ctx.textAlign = 'left';

ctx.font = aFont;

w = ctx.measureText(aChars).width;

}

w = Math.ceil(w); // needed as i use w in the calc for the loop, it needs to be a whole number

// must set width/height, as it wont paint outside of the bounds

can.width = w;

can.height = aSize * aOptions.range;

ctx.font = aFont; // need to set the .font again, because after changing width/height it makes it forget for some reason

ctx.textBaseline = 'alphabetic';

ctx.textAlign = 'left';

ctx.fillStyle = 'white';

console.log('w:', w);

var avgOfRange = (aOptions.range + 1) / 2;

var yBaseline = Math.ceil(aSize * avgOfRange);

console.log('yBaseline:', yBaseline);

ctx.fillText(aChars, 0, yBaseline);

var yEnd = aSize * aOptions.range;

var data = ctx.getImageData(0, 0, w, yEnd).data;

// console.log('data:', data)

var botBound = -1;

var topBound = -1;

// measureHeightY:

for (y=0; y<=yEnd; y++) {

for (var x = 0; x < w; x += 1) {

var n = 4 * (w * y + x);

var r = data[n];

var g = data[n + 1];

var b = data[n + 2];

// var a = data[n + 3];

if (r+g+b > 0) { // non black px found

if (topBound == -1) {

topBound = y;

}

botBound = y; // break measureHeightY; // dont break measureHeightY ever, keep going, we till yEnd. so we get proper height for strings like "`." or ":" or "!"

break;

}

}

}

return {

relativeBot: botBound - yBaseline, // relative to baseline of 0 // bottom most row having non-black

relativeTop: topBound - yBaseline, // relative to baseline of 0 // top most row having non-black

height: (botBound - topBound) + 1,

width: w// EDIT: comma has been added to fix old broken code.

};

}

relativeBot, relativeTop, and height are the useful things in the return object.

Here is example usage:

Page Title

function measureHeight(aFont, aSize, aChars, aOptions={}) {

// if you do pass aOptions.ctx, keep in mind that the ctx properties will be changed and not set back. so you should have a devoted canvas for this

// if you dont pass in a width to aOptions, it will return it to you in the return object

// the returned width is Math.ceil'ed

console.error('aChars: "' + aChars + '"');

var defaultOptions = {

width: undefined, // if you specify a width then i wont have to use measureText to get the width

canAndCtx: undefined, // set it to object {can:,ctx:} // if not provided, i will make one

range: 3

};

aOptions.range = aOptions.range || 3; // multiples the aSize by this much

if (aChars === '') {

// no characters, so obviously everything is 0

return {

relativeBot: 0,

relativeTop: 0,

height: 0,

width: 0

};

// otherwise i will get IndexSizeError: Index or size is negative or greater than the allowed amount error somewhere below

}

// validateOptionsObj(aOptions, defaultOptions); // not needed because all defaults are undefined

var can;

var ctx;

if (!aOptions.canAndCtx) {

can = document.createElement('canvas');;

can.mozOpaque = 'true'; // improved performanceo on firefox i guess

ctx = can.getContext('2d');

// can.style.position = 'absolute';

// can.style.zIndex = 10000;

// can.style.left = 0;

// can.style.top = 0;

// document.body.appendChild(can);

} else {

can = aOptions.canAndCtx.can;

ctx = aOptions.canAndCtx.ctx;

}

var w = aOptions.width;

if (!w) {

ctx.textBaseline = 'alphabetic';

ctx.textAlign = 'left';

ctx.font = aFont;

w = ctx.measureText(aChars).width;

}

w = Math.ceil(w); // needed as i use w in the calc for the loop, it needs to be a whole number

// must set width/height, as it wont paint outside of the bounds

can.width = w;

can.height = aSize * aOptions.range;

ctx.font = aFont; // need to set the .font again, because after changing width/height it makes it forget for some reason

ctx.textBaseline = 'alphabetic';

ctx.textAlign = 'left';

ctx.fillStyle = 'white';

console.log('w:', w);

var avgOfRange = (aOptions.range + 1) / 2;

var yBaseline = Math.ceil(aSize * avgOfRange);

console.log('yBaseline:', yBaseline);

ctx.fillText(aChars, 0, yBaseline);

var yEnd = aSize * aOptions.range;

var data = ctx.getImageData(0, 0, w, yEnd).data;

// console.log('data:', data)

var botBound = -1;

var topBound = -1;

// measureHeightY:

for (y=0; y<=yEnd; y++) {

for (var x = 0; x < w; x += 1) {

var n = 4 * (w * y + x);

var r = data[n];

var g = data[n + 1];

var b = data[n + 2];

// var a = data[n + 3];

if (r+g+b > 0) { // non black px found

if (topBound == -1) {

topBound = y;

}

botBound = y; // break measureHeightY; // dont break measureHeightY ever, keep going, we till yEnd. so we get proper height for strings like "`." or ":" or "!"

break;

}

}

}

return {

relativeBot: botBound - yBaseline, // relative to baseline of 0 // bottom most row having non-black

relativeTop: topBound - yBaseline, // relative to baseline of 0 // top most row having non-black

height: (botBound - topBound) + 1,

width: w

};

}

This is a Heading

This is a paragraph.

The relativeBot and relativeTop are what you see in this image here:

32afe92c8dbbde83dc7eb6fa0b7f8471.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值