HTMLキャンバス上のテキストの高さを確認するにはどうすればよいですか?


148

仕様にはcontext.measureText(text)関数があり、そのテキストを印刷するために必要な幅を教えてくれますが、それがどのくらいの高さであるかを見つける方法が見つかりません。フォントに基づいていることは知っていますが、フォント文字列をテキストの高さに変換する方法がわかりません。


1
私はトップの答えよりも良い方法を知りたいです。任意のポイントフォントを取得し、その上に最大/最小の境界を見つけるアルゴリズムがある場合は、それを聞いてとても幸せです。=)
beatgammit 2011

@tjameson-あるようです。ellisbben(および私の拡張機能)からの回答を参照してください。
Daniel Earwicker

2
Unicode文字 'FULL BLOCK'(U + 2588)を、幅に2を掛けることによって近似値として使用できるかどうか疑問に思っています。
Daniel F

1
答えは要件によって少し異なることに注意してください。たとえば、フォント "a"のレンダリングに必要な高さは、フォントのベースラインより下に伸びるディセンダーのため、文字 "y"のレンダリングに必要な高さとは異なります。以下のHTMLベースの回答はこれを考慮しておらず、テキストに適した全体的な高さを提供しますが、@ Noitidartの回答は特定のテキストのより正確な高さを提供します。
デールアンダーソン

2
このような文字を使用できることを忘れないでください。M̶̢̹̝͖̦̖̭͕̭̣͆̃̀̅̒̊͌̿ͅこれは非常に難しい問題なので、一般的なケースで解決してください。
GetFree

回答:


78

更新 -この作業の例として、Carotaエディターでこの手法を使用しました。

ellisbbenの回答に続き、ベースラインからの上昇と下降を取得する拡張バージョンがあります。つまり、Win32のGetTextMetric API tmAscentと同じでtmDescent、Win32のGetTextMetric API によって返されます。これは、異なるフォント/サイズのスパンでテキストをワードラップして実行する場合に必要です。

メートル線のあるキャンバス上の大きなテキスト

上の画像はSafariのキャンバスで生成されたもので、赤はキャンバスがテキストを描画するように指示された最上部の行、緑はベースライン、青は最下部です(そのため、赤から青が完全な高さです)。

簡潔にするためのjQueryの使用:

var getTextHeight = function(font) {

  var text = $('<span>Hg</span>').css({ fontFamily: font });
  var block = $('<div style="display: inline-block; width: 1px; height: 0px;"></div>');

  var div = $('<div></div>');
  div.append(text, block);

  var body = $('body');
  body.append(div);

  try {

    var result = {};

    block.css({ verticalAlign: 'baseline' });
    result.ascent = block.offset().top - text.offset().top;

    block.css({ verticalAlign: 'bottom' });
    result.height = block.offset().top - text.offset().top;

    result.descent = result.height - result.ascent;

  } finally {
    div.remove();
  }

  return result;
};

テキスト要素に加えて、divを追加しdisplay: inline-blockvertical-alignスタイルを設定し、ブラウザーがどこに配置したかを確認できるようにします。

したがって、オブジェクトはascentdescentおよびheight(これは便宜上ascent+ descentにすぎません)で返されます。それをテストするには、水平線を描く関数を用意する価値があります。

var testLine = function(ctx, x, y, len, style) {
  ctx.strokeStyle = style; 
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.lineTo(x + len, y);
  ctx.closePath();
  ctx.stroke();
};

次に、テキストがキャンバスの上部、基準線、および下部に対してどのように配置されているかを確認できます。

var font = '36pt Times';
var message = 'Big Text';

ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top'; // important!
ctx.font = font;
ctx.fillText(message, x, y);

// Canvas can tell us the width
var w = ctx.measureText(message).width;

// New function gets the other info we need
var h = getTextHeight(font);

testLine(ctx, x, y, w, 'red');
testLine(ctx, x, y + h.ascent, w, 'green');
testLine(ctx, x, y + h.height, w, 'blue');

3
このテキストを使用して高さを決定してみませんか?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789フォントによっては、gおよびMよりはるかに高いまたは低い文字がある場合があります
omatase

1
@ellisbben理由はわかりませんが、この結果があなたの結果と少し異なることに注意してください。たとえば、あなたはCourier New 8pt ==>高さ12ピクセルと言いますが、これはCourier New 8pt ==>高さ13ピクセルと言います。メソッドに「g」を追加しましたが、違いはありませんでした。どちらの値が最も役立つか(必ずしも技術的に正しいとは限りません)。
Orwellophile 2013年

3
私は最初の行変更されたとき、私は正常に動作して物事を得ることができるgetTextHeight()までvar text = $('<span>Hg</span>').css({ 'font-family': fontName, 'font-size' : fontSize });、つまりはサイズを個別に追加します。
cameron.bracken 2013

1
英語以外のテキストで機能させるにはどうすればよいですか?参照jsfiddle.net/siddjain/6vURk
モーフィアス

1
ありがとうございました !修正<div></div>するために<div style="white-space : nowrap;"></div>非常に長い文字列を処理するために
ミカエルGauvin

40

大文字Mの長さを確認することにより、垂直方向の高さを非常に正確に近似できます。

ctx.font='bold 10px Arial';

lineHeight=ctx.measureText('M').width;

8
幅はどのようにしてラインの高さの概算を与えますか?
Richard Barker

11
彼らは、与えられたフォントサイズで、単一の資本「M」の幅があることを意味についての行の高さと同じ。(これが本当かどうかはわかりませんが、それが答えが言っていることです)
ネイサン

2
これは実際、私が迅速なプロトタイピングに使用するかなりまともな近似です。完璧ではありませんが、90%のソリューションです。
オースティンD

37

キャンバスの仕様では、文字列の高さを測定する方法を提供していません。ただし、テキストのサイズをピクセル単位で設定でき、通常は垂直境界が比較的簡単にわかるようになります。

より正確なものが必要な場合は、キャンバスにテキストを投げてピクセルデータを取得し、垂直方向に使用されているピクセル数を把握できます。これは比較的単純ですが、あまり効率的ではありません。あなたはこのようなことをすることができます(それは機能しますが、あなたが削除したいキャンバスにテキストを描画します):

function measureTextHeight(ctx, left, top, width, height) {

    // Draw the text in the specified area
    ctx.save();
    ctx.translate(left, top + Math.round(height * 0.8));
    ctx.mozDrawText('gM'); // 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;
}

// Set the font
context.mozTextStyle = '32px Arial';

// Specify a context and a rect that is safe to draw in when calling measureTextHeight
var height = measureTextHeight(context, 0, 0, 50, 50);
console.log(height);

Bespinの場合、小文字の「m」の幅を測定することで高さを偽っています...これがどのように使用されるのかわかりません。この方法はお勧めしません。関連するベスピン法は次のとおりです。

var fixCanvas = function(ctx) {
    // upgrade Firefox 3.0.x text rendering to HTML 5 standard
    if (!ctx.fillText && ctx.mozDrawText) {
        ctx.fillText = function(textToDraw, x, y, maxWidth) {
            ctx.translate(x, y);
            ctx.mozTextStyle = ctx.font;
            ctx.mozDrawText(textToDraw);
            ctx.translate(-x, -y);
        }
    }

    if (!ctx.measureText && ctx.mozMeasureText) {
        ctx.measureText = function(text) {
            ctx.mozTextStyle = ctx.font;
            var width = ctx.mozMeasureText(text);
            return { width: width };
        }
    }

    if (ctx.measureText && !ctx.html5MeasureText) {
        ctx.html5MeasureText = ctx.measureText;
        ctx.measureText = function(text) {
            var textMetrics = ctx.html5MeasureText(text);

            // fake it 'til you make it
            textMetrics.ascent = ctx.html5MeasureText("m").width;

            return textMetrics;
        }
    }

    // for other browsers
    if (!ctx.fillText) {
        ctx.fillText = function() {}
    }

    if (!ctx.measureText) {
        ctx.measureText = function() { return 10; }
    }
};

28
HTML5仕様を作成した人々がこのことを念頭に置いていたのではないかと思います。
スティーブハノフ

17
これは私が絶対に愛している恐ろしい恐ろしいハックです。+1
Allain Lalonde

1
わかりません。フォントのアセントと文字「m」の幅の関係はどこにありますか?
カヤール

6
em1つのemがMデフォルトのフォントサイズの文字の高さに等しい相対フォント測定です。
jerone

1
右、高さは幅ではありません...私はまだ接続について混乱しています。また、ピクセル単位の高さのみを考慮しているので、emsは無関係であると思います。
2012年

35

ブラウザーは高度なテキストメトリックをサポートし始めており、広くサポートされている場合、このタスクは簡単になります。

let metrics = ctx.measureText(text);
let fontHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;

fontHeightレンダリングされる文字列に関係なく一定であるバウンディングボックスの高さを取得します。actualHeightレンダリングされる文字列に固有です。

仕様:https : //www.w3.org/TR/2012/CR-2dcontext-20121217/#dom-textmetrics-fontboundingboxascentとそのすぐ下のセクション。

サポート状況(2017年8月20日):


2
誰もがバグページに投票して、これらの機能をより早く実装してください
エレミヤローズ

21

編集:キャンバス変換を使用していますか? その場合、変換行列を追跡する必要があります。次のメソッドは、最初の変換でテキストの高さを測定する必要があります。

編集#2:奇妙なことに、このStackOverflowページで実行すると、以下のコードは正しい答えを生成しません。いくつかのスタイルルールが存在すると、この機能が無効になる可能性があります。

キャンバスはCSSで定義されているフォントを使用するため、理論的には適切にスタイル設定されたテキストのチャンクをドキュメントに追加して、その高さを測定できます。これは、テキストをレンダリングしてからピクセルデータをチェックするよりもはるかに簡単で、アセンダーとディセンダーも尊重する必要があると思います。以下を確認してください。

var determineFontHeight = function(fontStyle) {
  var body = document.getElementsByTagName("body")[0];
  var dummy = document.createElement("div");
  var dummyText = document.createTextNode("M");
  dummy.appendChild(dummyText);
  dummy.setAttribute("style", fontStyle);
  body.appendChild(dummy);
  var result = dummy.offsetHeight;
  body.removeChild(dummy);
  return result;
};

//A little test...
var exampleFamilies = ["Helvetica", "Verdana", "Times New Roman", "Courier New"];
var exampleSizes = [8, 10, 12, 16, 24, 36, 48, 96];
for(var i = 0; i < exampleFamilies.length; i++) {
  var family = exampleFamilies[i];
  for(var j = 0; j < exampleSizes.length; j++) {
    var size = exampleSizes[j] + "pt";
    var style = "font-family: " + family + "; font-size: " + size + ";";
    var pixelHeight = determineFontHeight(style);
    console.log(family + " " + size + " ==> " + pixelHeight + " pixels high.");
  }
}

高さを測定するDOM要素でフォントスタイルが正しいことを確認する必要がありますが、それは非常に簡単です。本当にあなたは何かを使うべきです

var canvas = /* ... */
var context = canvas.getContext("2d");
var canvasFont = " ... ";
var fontHeight = determineFontHeight("font: " + canvasFont + ";");
context.font = canvasFont;
/*
  do your stuff with your font and its height here.
*/

1
+1方法の優れたソリューションIMO。ベースラインの位置も取得できるはずです。
Daniel Earwicker

ベースラインを取得する答えを追加しました。
Daniel Earwicker

これは機能しますか?私はそれをdivに貼り付けることさえ考えていませんでした。これはおそらくDOMに追加する必要さえありません。
beatgammit 2012年

ノードがドキュメントの一部ではない場合、ノードのどのサイズと位置フィールドが存在するかについてはまったく知りません。あなたがそれを知っているなら、私はそれを扱うリファレンスを読むことに超興味があります。
ellisbben 2012年

5
+1は、より優れたCanvas APIを使用した並列ユニバースでのcontext.measureText(text).heightに相当する画面全体の複雑なコード
rsp

11

context.fontを使用してフォントを定義する場合、ピクセル単位のテキストの高さはフォントサイズ(pts)と等しくありませんか?


2
これは、このソースによって主張されているものです。html5canvastutorials.com
Rui Marques

単純な場合:フォント名から常に高さを解析できます:parseInt(ctx.font.split( '')[0] .replace( 'px'、 '')); //解析文字列: "10px Verdana"
Sean

フォントサイズにはpx、pt、em、%を使用できます。これが、この回答が誤解を招く理由です。
Jacksonkr 2017

@Jacksonkr、そうですが、それでもそれらを解析して適切に調整できますか?または、このアプローチにはどこか固有の制限がありますか?
パチェリエ

@Pacerier制限は、あなたがあなたの髪を引き抜く原因となるいくつかのバグを導入するかもしれないということです。ユニットタイプを混在させると、バグの多い/スパゲッティコードが発生する可能性があることに注意してください。とはいえ、問題のリスクが低い限り、私は時折ハックをしていません。
Jacksonkr

10

JJ Stiffが提案するように、テキストをスパンに追加してから、スパンのoffsetHeightを測定できます。

var d = document.createElement("span");
d.font = "20px arial";
d.textContent = "Hello world!";
document.body.appendChild(d);
var emHeight = d.offsetHeight;
document.body.removeChild(d);

HTML5Rocksに示されているように


3
これはとても良い解決策です、ありがとう...しかし、このspanがページに追加されておらず、offsetHeightを取得する前に表示されていない場合は、なぜなのかわかりません。ChromeとFirefoxでは常に高さをゼロとして返します。
Mustafah 2012

1
正解です。スペースを確保するには、domに追加する必要があります。これは、この作業のJSフィドルです。jsfiddle.net / mpalmerlee / 4NfVR / 4上記のコードも更新しました。
Matt Palmerlee、2007

clientHeightを使用することも可能です。この回答は問題の解決策ですが、醜い回避策です。それでも+1しました。
ダニエルF

これは、表示されるテキストの実際の高さを考慮せず、通常はテキストの上に追加のマージンが出てきます…
Ain Tohvri

8

ダニエルの回答に追加するだけで(これはすばらしいことであり、絶対に正しい!)、JQueryなしのバージョンです。

function objOff(obj)
{
    var currleft = currtop = 0;
    if( obj.offsetParent )
    { do { currleft += obj.offsetLeft; currtop += obj.offsetTop; }
      while( obj = obj.offsetParent ); }
    else { currleft += obj.offsetLeft; currtop += obj.offsetTop; }
    return [currleft,currtop];
}
function FontMetric(fontName,fontSize) 
{
    var text = document.createElement("span");
    text.style.fontFamily = fontName;
    text.style.fontSize = fontSize + "px";
    text.innerHTML = "ABCjgq|"; 
    // if you will use some weird fonts, like handwriting or symbols, then you need to edit this test string for chars that will have most extreme accend/descend values

    var block = document.createElement("div");
    block.style.display = "inline-block";
    block.style.width = "1px";
    block.style.height = "0px";

    var div = document.createElement("div");
    div.appendChild(text);
    div.appendChild(block);

    // this test div must be visible otherwise offsetLeft/offsetTop will return 0
    // but still let's try to avoid any potential glitches in various browsers
    // by making it's height 0px, and overflow hidden
    div.style.height = "0px";
    div.style.overflow = "hidden";

    // I tried without adding it to body - won't work. So we gotta do this one.
    document.body.appendChild(div);

    block.style.verticalAlign = "baseline";
    var bp = objOff(block);
    var tp = objOff(text);
    var taccent = bp[1] - tp[1];
    block.style.verticalAlign = "bottom";
    bp = objOff(block);
    tp = objOff(text);
    var theight = bp[1] - tp[1];
    var tdescent = theight - taccent;

    // now take it off :-)
    document.body.removeChild(div);

    // return text accent, descent and total height
    return [taccent,theight,tdescent];
}

上記のコードをテストしたところ、最新のChrome、FF、MacのSafariで問題なく動作しました。

編集:私はフォントサイズも追加し、システムフォントの代わりにwebfontでテストしました-素晴らしい作品です。


7

私はこの問題を解決しました-ピクセル操作を使用して。

ここにグラフィカルな答えがあります:

ここにコードがあります:

    function textHeight (text, font) {

    var fontDraw = document.createElement("canvas");

    var height = 100;
    var width = 100;

    // here we expect that font size will be less canvas geometry
    fontDraw.setAttribute("height", height);
    fontDraw.setAttribute("width", width);

    var ctx = fontDraw.getContext('2d');
    // black is default
    ctx.fillRect(0, 0, width, height);
    ctx.textBaseline = 'top';
    ctx.fillStyle = 'white';
    ctx.font = font;
    ctx.fillText(text/*'Eg'*/, 0, 0);

    var pixels = ctx.getImageData(0, 0, width, height).data;

    // row numbers where we first find letter end where it ends 
    var start = -1;
    var end = -1;

    for (var row = 0; row < height; row++) {
        for (var column = 0; column < width; column++) {

            var index = (row * width + column) * 4;

            // if pixel is not white (background color)
            if (pixels[index] == 0) {
                // we havent met white (font color) pixel
                // on the row and the letters was detected
                if (column == width - 1 && start != -1) {
                    end = row;
                    row = height;
                    break;
                }
                continue;
            }
            else {
                // we find top of letter
                if (start == -1) {
                    start = row;
                }
                // ..letters body
                break;
            }

        }

    }
   /*
    document.body.appendChild(fontDraw);
    fontDraw.style.pixelLeft = 400;
    fontDraw.style.pixelTop = 400;
    fontDraw.style.position = "absolute";
   */

    return end - start;

}

2
このソリューションでは、小文字のiやjのようなドット付きの文字は考慮されていないと思います
wusauarus

3

私は端末エミュレーターを書いているので、文字の周りに長方形を描く必要がありました。

var size = 10
var lineHeight = 1.2 // CSS "line-height: normal" is between 1 and 1.2
context.font = size+'px/'+lineHeight+'em monospace'
width = context.measureText('m').width
height = size * lineHeight

キャラクターが占める正確なスペースが必要な場合は、明らかに役に立ちません。しかし、それはあなたに特定の用途のための良い近似を与えるでしょう。



3

これは簡単な関数です。ライブラリは必要ありません。

この関数は、ベースラインを基準にして上限と下限を取得するために作成しました。textBaselineがに設定されてalphabeticいる場合。これは、別のキャンバスを作成してそこに描画し、一番上と一番下の空白でないピクセルを見つけます。そして、それが上限と下限です。これは相対値として返されるため、高さが20pxで、ベースラインの下に何もない場合、上限はになり-20ます。

文字を指定する必要があります。それ以外の場合は、明らかに高さと幅が0になります。

使用法:

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

これが関数です:

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.
    };
}

relativeBotrelativeTop、およびheight戻り値のオブジェクトに有用なものです。

次に使用例を示します。

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<script>
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
	};
}

</script>
</head>
<body style="background-color:steelblue;">
<input type="button" value="reuse can" onClick="alert(measureHeight('40px serif', 40, 'rg', {canAndCtx:{can:document.getElementById('can'), ctx:document.getElementById('can').getContext('2d')}}).height)">
<input type="button" value="dont reuse can" onClick="alert(measureHeight('40px serif', 40, 'rg').height)">
<canvas id="can"></canvas>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>

relativeBotそしてrelativeTopあなたはここで、この画像の中に見えるものです。

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_text




2

これは私がここでの他のいくつかの答えに基づいてやったことです:

function measureText(text, font) {
	const span = document.createElement('span');
	span.appendChild(document.createTextNode(text));
	Object.assign(span.style, {
		font: font,
		margin: '0',
		padding: '0',
		border: '0',
		whiteSpace: 'nowrap'
	});
	document.body.appendChild(span);
	const {width, height} = span.getBoundingClientRect();
	span.remove();
	return {width, height};
}

var font = "italic 100px Georgia";
var text = "abc this is a test";
console.log(measureText(text, font));


1

まず、フォントサイズの高さを設定する必要があります。次に、フォントの高さの値に応じて、テキストの現在の高さを決定します。もちろん、クロステキストの行数は、同じです。テキストが最大のテキストボックスの高さを超えない場合、フォントを蓄積する必要があります。すべて表示します。それ以外の場合は、ボックステキスト内のテキストのみを表示します。高い値には独自の定義が必要です。プリセットの高さが大きいほど、表示およびインターセプトする必要があるテキストの高さが大きくなります。

エフェクト処理後(ソルブ)

効果が処理される前(未解決)

  AutoWrappedText.auto_wrap = function(ctx, text, maxWidth, maxHeight) {
var words = text.split("");
var lines = [];
var currentLine = words[0];

var total_height = 0;
for (var i = 1; i < words.length; i++) {
    var word = words[i];
    var width = ctx.measureText(currentLine + word).width;
    if (width < maxWidth) {
        currentLine += word;
    } else {
        lines.push(currentLine);
        currentLine = word;
        // TODO dynamically get font size
        total_height += 25;

        if (total_height >= maxHeight) {
          break
        }
    }
}
if (total_height + 25 < maxHeight) {
  lines.push(currentLine);
} else {
  lines[lines.length - 1] += "…";
}
return lines;};

1

私は、ことがわかっJUST FOR ARIAL境界ボックスの高さを見つけるための最も簡単、最速とaccuratest方法は、特定の文字の幅を使用することです。ユーザーが別のフォントを選択することを許可せずに特定のフォントを使用する場合は、少し調べて、そのフォントに適した文字を見つけることができます。

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="700" height="200" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "100px Arial";
var txt = "Hello guys!"
var Hsup=ctx.measureText("H").width;
var Hbox=ctx.measureText("W").width;
var W=ctx.measureText(txt).width;
var W2=ctx.measureText(txt.substr(0, 9)).width;

ctx.fillText(txt, 10, 100);
ctx.rect(10,100, W, -Hsup);
ctx.rect(10,100+Hbox-Hsup, W2, -Hbox);
ctx.stroke();
</script>

<p><strong>Note:</strong> The canvas tag is not supported in Internet 
Explorer 8 and earlier versions.</p>

</body>
</html>


0

ただし、フォントサイズの設定は実用的でない場合があります。

ctx.font = ''

CSSで定義されたものと埋め込みフォントタグを使用します。CSSフォントを使用している場合、プログラム的な方法からの高さはわかりませんが、measureTextメソッドを使用しているため、近視眼的です。ただし、IE8は幅と高さを返します。


0

これは、1)マルチラインテキストでも同様に機能します2)IE9でも機能します!

<div class="measureText" id="measureText">
</div>


.measureText {
  margin: 0;
  padding: 0;
  border: 0;
  font-family: Arial;
  position: fixed;
  visibility: hidden;
  height: auto;
  width: auto;
  white-space: pre-wrap;
  line-height: 100%;
}

function getTextFieldMeasure(fontSize, value) {
    const div = document.getElementById("measureText");

    // returns wrong result for multiline text with last line empty
    let arr = value.split('\n');
    if (arr[arr.length-1].length == 0) {
        value += '.';
    }

    div.innerText = value;
    div.style['font-size']= fontSize + "px";
    let rect = div.getBoundingClientRect();

    return {width: rect.width, height: rect.height};
};

0

私はこれが古い回答の質問であることを知っていますが、将来の参考のために、短い、最小限の、JSのみ(jqueryなし)のソリューションを追加したいと思います。

var measureTextHeight = function(fontFamily, fontSize) 
{
    var text = document.createElement('span');
    text.style.fontFamily = fontFamily;
    text.style.fontSize = fontSize + "px";
    text.textContent = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
    document.body.appendChild(text);
    var result = text.getBoundingClientRect().height;
    document.body.removeChild(text);
    return result;
};

-3

通常の状況では、以下が機能するはずです。

var can = CanvasElement.getContext('2d');          //get context
var lineHeight = /[0-9]+(?=pt|px)/.exec(can.font); //get height from font variable

5
完全かつ完全に間違っています。ポイントサイズとピクセルサイズには大きな違いがあります。ポイントサイズは、ページがレンダリングされるDPIに応じて異なるサイズのテキストになりますが、ピクセルサイズでは考慮されません。
Orvid King、2015

2
画面ピクセルの概念に精通していますか?あなたはそれが悟りを見つけるかもしれません。とにかく、ptとpxは確かに異なる高さを示します。いずれにしても、フォントが「高さ」よりも少なく、またはそれ以上に満たされる可能性があることに注意してください。キャンバスピクセルがスケーリングされているかどうかはわかりませんが、スケーリングされていると思います。しかし、それは「間違った」答えです。シンプルで、多くの状況で使用できます。
Lodewijk 2015年

-4

これはマッドです...テキストの高さはフォントサイズです。ドキュメントを読んだ人はいませんか?

context.font = "22px arial";

これにより、高さが22pxに設定されます。

唯一の理由は..

context.measureText(string).width

これは、フォントで描画されたすべての文字列に対して、幅が必要な文字列がわかっている場合を除いて、文字列の幅を決定できないためです。高さは22pxになります。

px以外の測定値を使用する場合、高さは同じですが、その測定値であるため、せいぜい測定を変換するだけで済みます。


一部の文字は制限の上または下に拡張できます。whatwg.org/ specs / web
Octavia

1
言い回しは悪いが、それでも通常は正しい。
Lodewijk 2014

これらのすべての答えを読んでくださいが、私のシンプルなアプリではこれが正解でした、pt === px
rob

完全に間違っています。さまざまなフォントで提案されているいくつかの解決策を試してみてください。大きな違いが見つかります。
デールアンダーソン

-4

近似解:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.font = "100px Arial";
var txt = "Hello guys!"
var wt = ctx.measureText(txt).width;
var height = wt / txt.length;

これは、等幅フォントでは正確な結果になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.