Bir HTML tuvalinde metnin yüksekliğini nasıl bulabilirsiniz?


153

Spesifikasyonun, o metni yazdırmak için ne kadar genişliğe ihtiyaç duyacağını size söyleyen bir context.measureText (metin) işlevi vardır, ancak ne kadar uzun olduğunu bulmanın bir yolunu bulamıyorum. Yazı tipine dayandığını biliyorum, ancak bir yazı tipi dizesini metin yüksekliğine dönüştürmeyi bilmiyorum.


1
En iyi cevaptan daha iyi bir yol bilmek isterim. Rasgele nokta yazı tipini alıp üzerinde maks / min sınırlarını bulacak bir algoritma varsa, bunu duymaktan çok mutlu olurum. =)
beatgammit

@tjameson - var gibi görünüyor. Ellisbben'in cevabına (ve benim onu ​​geliştirmeme) bakın.
Daniel Earwicker

2
Unicode Karakter 'FULL BLOCK' (U + 2588) genişliğini ikiyle çarparak bir yaklaşım olarak kullanılabilir mi merak ediyorum.
Daniel F

1
Cevabın biraz ihtiyaçlarınıza bağlı olduğunu belirtmekte fayda var. Örneğin, "a" karakterini oluşturmak için gereken yükseklik, yazı tipinin temel çizgisinin altına uzanan alt çizgi nedeniyle "y" karakterini oluşturmak için gereken yükseklikten farklıdır. Aşağıdaki HTML tabanlı cevaplar bunu hesaba katmaz ve size herhangi bir metin için uygun genel bir yükseklik verirken, @ Noitidart'ın cevabı belirli bir metin için daha kesin bir yükseklik verir.
Dale Anderson

2
Buna benzeyen karakterlere sahip olabileceğinizi unutmayın, bu M̶̢̹̝͖̦̖̭͕̭̣͆̃̀̅̒̊͌̿ͅyüzden bu gerçekten zor bir sorundur, bu yüzden genel durum için çözün.
GetFree

Yanıtlar:


78

GÜNCELLEME - bu çalışmanın bir örneği olarak, bu tekniği Carota editöründe kullandım .

Ellisbben'in cevabını takiben, işte temelden yükseliş ve inişi elde etmek için geliştirilmiş bir sürüm, yani Win32'nin GetTextMetric API'si ile aynı tmAscentve tmDescentgeri dönen . Bu, farklı yazı tiplerinde / boyutlarda yayılma alanlarına sahip sözcük kaydırmalı bir metin dizisi yapmak istiyorsanız gereklidir.

Metrik çizgilerle tuval üzerine büyük metin

Yukarıdaki görüntü Safari'de bir tuval üzerinde oluşturuldu; kırmızı, tuvalin metni çizmesinin söylendiği en üst satır, yeşil taban çizgisi ve mavi alt çizgi (yani kırmızıdan maviye tam yüksekliktir).

Kısa ve özlük için jQuery kullanma:

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

Bir metin öğesine ek olarak display: inline-block, vertical-alignstilini ayarlayabilmek için bir div ekliyorum ve ardından tarayıcının onu nereye koyduğunu buluyorum.

Böylece ascent, descentve ile bir nesneyi geri alırsınız height(bu, kolaylık sağlamak için sadece ascent+ 'dır descent). Test etmek için, yatay bir çizgi çizen bir işleve sahip olmaya değer:

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();
};

Ardından, metnin tuval üzerinde üst, taban çizgisi ve alta göre nasıl konumlandırıldığını görebilirsiniz:

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
Yüksekliği belirlemek için neden bu metni kullanmıyorsunuz? abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 Yazı tipine bağlı olarak g ve M'den çok daha yüksek veya daha düşük karakterlere sahip olabilirsiniz
omatase

1
@ellisbben, nedenini bilmesem de, bunun sonuçlarının sizinkinden biraz farklı olduğunu belirtmekte fayda var. Örneğin, sizinki Courier New 8pt ==> 12 piksel yüksek diyor, bu ise: Courier New 8pt ==> 13 piksel yüksek. Metoduna "g" harfini ekledim ama fark bu değildi. Biri, hangi değerin en yararlı olacağını merak ediyor (teknik olarak doğru olması gerekmez).
Orwellophile

3
İşlerin ancak ilk satırını olarak getTextHeight()değiştirdiğimde var text = $('<span>Hg</span>').css({ 'font-family': fontName, 'font-size' : fontSize });, yani boyutu ayrı olarak eklediğimde doğru şekilde çalışmasını sağlayabildim .
cameron.bracken

1
İngilizce olmayan metinler için nasıl çalıştırılır? bkz. jsfiddle.net/siddjain/6vURk
morpheus

1
teşekkür ederim ! çok uzun <div></div><div style="white-space : nowrap;"></div>
ipleri

44

Tarayıcılar, geniş çapta desteklendiğinde bu görevi önemsiz hale getirecek olan gelişmiş metin ölçümlerini desteklemeye başlıyor :

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

fontHeightsize, işlenen dizeden bağımsız olarak sabit olan sınırlayıcı kutu yüksekliğini verir. actualHeightişlenmekte olan dizeye özgüdür.

Spec: https://www.w3.org/TR/2012/CR-2dcontext-20121217/#dom-textmetrics-fontboundingboxascent ve hemen altındaki bölümler.

Destek durumu (20-Ağu-2017):


3
Bu özelliklerin daha erken uygulanması için lütfen hata sayfalarına oy verin
Jeremiah Rose

41

Büyük M'nin uzunluğunu kontrol ederek dikey yüksekliğin çok yakın bir tahminini elde edebilirsiniz.

ctx.font = 'bold 10px Arial';

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

9
Genişlik bize satır yüksekliğini nasıl verir?
Richard Barker

13
Belirli bir yazı tipi boyutunda tek bir büyük 'M' genişliğinin satır yüksekliğiyle yaklaşık aynı olduğu anlamına gelir. (Bunun doğru olup olmadığını bilmiyorum ama cevabın söylediği bu)
Nathan

37

Kanvas belirtimi bize bir dizenin yüksekliğini ölçmek için bir yöntem sağlamaz. Bununla birlikte, metninizin boyutunu piksel cinsinden ayarlayabilir ve genellikle dikey sınırların ne olduğunu nispeten kolayca anlayabilirsiniz.

Daha kesin bir şeye ihtiyacınız varsa, metni tuvale atabilir ve ardından piksel verilerini alabilir ve dikey olarak kaç piksel kullanıldığını hesaplayabilirsiniz. Bu nispeten basit olacaktır, ancak çok verimli olmayacaktır. Bunun gibi bir şey yapabilirsiniz (işe yarar, ancak tuvalinize kaldırmak isteyeceğiniz bir metin çizer):

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 için küçük harfli 'm' harfinin genişliğini ölçerek bir yüksekliği taklit ediyorlar ... Bunun nasıl kullanıldığını bilmiyorum ve bu yöntemi önermem. İşte ilgili Bespin yöntemi:

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 spesifikasyonunu yazan kişilerin aklında bunun olduğundan şüpheliyim.
Steve Hanov

17
Bu kesinlikle sevdiğim korkunç bir hack. +1
Allain Lalonde

1
Ben anlamadım Yazı tipi yükselişi ile "m" harfinin genişliği arasındaki bağlantı nerede?
kayahr

6
embir em'in Mvarsayılan yazı tipi boyutundaki harfin yüksekliğine eşit olduğu göreli bir yazı tipi ölçümüdür .
jerone

1
Doğru, yükseklik genişlik değil ... Bağlantı konusunda hala kafam karıştı. Ayrıca, sadece piksel cinsinden yüksekliği önemsediğimiz için ems'nin alakasız olduğunu düşünüyorum.
Prestaul

22

DÜZENLE: Kanvas dönüşümleri kullanıyor musunuz? Öyleyse, dönüşüm matrisini izlemeniz gerekir. Aşağıdaki yöntem, ilk dönüştürmeyle metnin yüksekliğini ölçmelidir.

DÜZENLEME # 2: Garip bir şekilde, bu StackOverflow sayfasında çalıştırdığımda aşağıdaki kod doğru yanıtlar üretmiyor; Bazı stil kurallarının varlığının bu işlevi bozması tamamen mümkündür.

Tuval, CSS tarafından tanımlanan yazı tiplerini kullanır, bu nedenle teoride, belgeye uygun şekilde tasarlanmış bir metin parçası ekleyebilir ve yüksekliğini ölçebiliriz. Bence bu, metni oluşturmaktan ve ardından piksel verilerini kontrol etmekten çok daha kolay ve ayrıca yükselenlere ve altsoylara da saygı göstermeli. Aşağıdakilere göz atın:

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

Yüksekliğini ölçtüğünüz DOM öğesinde yazı tipi stilini doğru yaptığınızdan emin olmalısınız, ancak bu oldukça basittir; gerçekten böyle bir şey kullanmalısın

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 Yol daha iyi çözüm IMO. Taban çizgisinin konumunu da almak mümkün olmalıdır.
Daniel Earwicker

Temeli alan bir cevap eklediniz.
Daniel Earwicker

Bu çalışıyor mu? Bir div'e yapıştırmayı düşünmedim bile. Bunun muhtemelen DOM'a eklenmesi gerekmiyor, değil mi?
beatgammit

Belgenin parçası olmayan bir düğümün hangi boyut ve konum alanlarının bulunduğunu tamamen bilmiyorum. Biliyorsanız, buna hitap eden bir referansı okumakla çok ilgilenirim.
ellisbben

5
Daha iyi bir Canvas API ile paralel bir evrende yalnızca context.measureText (text) .height olacak bir ekran dolusu karmaşık kod için +1
rsp

11

Yazı tipini context.font kullanarak tanımlarsanız, metnin piksel cinsinden yüksekliği yazı tipi boyutuna (pts cinsinden) eşit olmaz mı?


2
Bu kaynak tarafından iddia edilen şey budur: html5canvastutorials.com/tutorials/html5-canvas-text-metrics
Rui Marques

basit durumlar için: yazı tipi adından yüksekliği her zaman ayrıştırabilirsiniz: parseInt (ctx.font.split ('') [0] .replace ('px', '')); // ayrıştırma dizesi: "10px Verdana"
Sean

Yazı tipi boyutu için px, pt, em ve% kullanabilirsiniz. İşte tam da bu yanıtın yanıltıcı olmasının nedeni budur .
Jacksonkr

@Jacksonkr, Evet ama yine de onları ayrıştırıp buna göre ayarlayabilirsin değil mi? Yoksa bu yaklaşımın bir yerde doğasında bir sınırlama var mı?
Pacerier

@Pacerier Sınırlama, saçınızı çekmenize neden olan bazı böcekleri ortaya çıkarabilmenizdir. Sadece karıştırma birimi türlerinin buggy / spagetti koduna yol açabileceğini unutmayın. Bununla birlikte, sorun riski düşük olduğu sürece ara sıra yapılan saldırının üstünde değilim.
Jacksonkr

10

JJ Stiff'in önerdiği gibi, metninizi bir aralığa ekleyebilir ve ardından aralığın offsetHeight değerini ölçebilirsiniz.

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'ta gösterildiği gibi


3
Bu çok güzel bir çözüm, Teşekkürler ... ama bu aralık sayfaya eklenmemişse ve ben ofsetYüksekliğini almadan önce görünmüyorsa neden bilmiyorum Chrome ve Firefox'ta yüksekliği her zaman SIFIR olarak döndürür!
Mustafah

1
Haklısın, sanırım yer kaplaması için doma eklenmesi gerekiyor. İşte bu çalışmanın bir JS Fiddle'ı : jsfiddle.net/mpalmerlee/4NfVR/4 Yukarıdaki kodu da güncelledim.
Matt Palmerlee

ClientHeight'ı kullanmak da bir olasılıktır. Bu cevap soruna bir çözüm olsa da çirkin bir çözümdür. Yine de + 1'ledi.
Daniel F

Bu görünen metnin gerçek yüksekliğini düşünün ve genellikle ... metnin üstünde ek marj karşısına çıkıyor gelmez
Ain Tohvri

8

Sadece Daniel'in cevabına (ki bu harika! Ve kesinlikle doğru!), JQuery'siz versiyonu eklemek için:

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

Yukarıdaki kodu kısa süre önce test ettim ve Mac'teki en son Chrome, FF ve Safari'de harika çalışıyor.

DÜZENLEME: Yazı tipi boyutunu da ekledim ve sistem yazı tipi yerine web yazı tipi ile test ettim - harika çalışıyor.


7

Piksel manipülasyonunu kullanarak bu sorunu ileriye doğru çözdüm.

İşte grafiksel cevap:

İşte kod:

    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
Bu çözümün küçük i ve j gibi noktalı harfleri hesaba katmadığına inanıyorum
wusauarus

4

Bir terminal öykünücüsü yazıyorum, bu yüzden karakterlerin etrafına dikdörtgenler çizmem gerekiyordu.

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

Açıkçası, karakterin kapladığı alan miktarını tam olarak istiyorsanız, yardımcı olmayacaktır. Ancak belirli kullanımlar için size iyi bir yaklaşım verecektir.



3

İşte basit bir işlev. Kitaplığa gerek yok.

Taban çizgisine göre üst ve alt sınırları elde etmek için bu işlevi yazdım. Olarak textBaselineayarlanmışsa alphabetic. Yaptığı şey, başka bir tuval oluşturmak ve ardından oraya çizmek ve ardından en üstteki ve en alttaki boş olmayan pikseli bulmaktır. Ve bu üst ve alt sınırlardır. Göreceli olarak döndürür, dolayısıyla yükseklik 20 piksel ise ve taban çizgisinin altında hiçbir şey yoksa, üst sınırdır -20.

Ona karakter sağlamalısınız. Aksi takdirde size 0 yükseklik ve 0 genişlik verecek.

Kullanım:

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

İşte fonksiyon:

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, relativeTopve heightdönüş nesnesindeki yararlı şeylerdir.

İşte örnek kullanım:

<!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>

relativeBotVe relativeTopburada bu resimde gördüklerinizi şunlardır:

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


3

tek satır cevap

var height = parseInt(ctx.font) * 1.2; 

CSS "line-height: normal" 1 ile 1,2 arasında

daha fazla bilgi için burayı okuyun



2

Buradaki diğer cevaplardan bazılarına dayanarak yaptığım şey buydu:

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

Her şeyden önce, bir yazı tipi boyutunun yüksekliğini ayarlamanız ve ardından metninizin mevcut yüksekliğini belirlemek için yazı tipi yüksekliğinin değerine göre ne kadar, çapraz metin satırları, tabii ki aynı yükseklikte Metin en büyük metin kutusu Yüksekliğini aşmıyorsa yazı tipinin birikmesi gerekir, tümü gösterilir, aksi takdirde yalnızca kutu metni içindeki metni gösterir. Yüksek değerler sizin kendi tanımınıza ihtiyaç duyar. Önceden ayarlanmış yükseklik ne kadar büyükse görüntülenmesi ve durdurulması gereken metnin yüksekliği o kadar büyük olur.

Etki işlendikten sonra (çöz)

Etki işlenmeden önce (çözülmeden)

  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

Ben bulundu SADECE İÇİN ARIAL sınırlama kutusunun yüksekliğini bulmak için en basit, en hızlı ve accuratest yolu belli harflerin genişliği kullanmaktır. Kullanıcının farklı bir yazı tipi seçmesine izin vermeden belirli bir yazı tipini kullanmayı planlıyorsanız, o yazı tipi için işi yapan doğru harfi bulmak için biraz araştırma yapabilirsiniz.

<!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

yazı tipi boyutunu ayarlamak pratik olmayabilir, çünkü

ctx.font = ''

herhangi bir gömülü yazı tipi etiketinin yanı sıra CSS tarafından tanımlananı kullanacaktır. CSS yazı tipini kullanırsanız, çok kısa görüşlü olan measureText yöntemini kullanarak, programlı bir şekilde yüksekliğin ne olduğu hakkında hiçbir fikriniz olmaz. Yine de başka bir notta, IE8 genişliği ve yüksekliği döndürür.


0

Bu, 1) çok satırlı metin için 2) ve hatta IE9'da işe yarar!

<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

Bunun eski yanıtlanmış bir soru olduğunu biliyorum, ancak ileride başvurmak için kısa, minimal, yalnızca JS (jquery yok) bir çözüm eklemek istiyorum, insanların aşağıdakilerden yararlanabileceğine inanıyorum:

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

Normal durumlarda aşağıdakiler çalışmalıdır:

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

5
Tamamen ve tamamen yanlış. Bir nokta boyutu ile bir piksel boyutu arasında BÜYÜK bir fark vardır. Punto boyutu, sayfanın oluşturulduğu DPI'ye bağlı olarak farklı boyutlarda metinle sonuçlanır, çünkü piksel boyutu bunu hesaba katmaz.
Orvid King

2
Ekran pikselleri kavramına aşina mısınız? Aydınlatıcı bulabilirsin. Ne olursa olsun, pt ve px gerçekten de farklı yüksekliklere işaret ediyor. Yazı tipinin "yüksekliğinden" daha az veya daha fazla doldurabileceğini belirtmek gerekir. Tuval piksellerinin ölçeklendiğinden emin değilim, ama öyle olduğunu varsayıyorum. Yine de "yanlış" bir cevap. Basittir ve birçok durumda kullanılabilir.
Lodewijk

-4

Bu çıldırtıcı ... Metnin yüksekliği yazı tipi boyutu .. Hiçbiriniz dokümantasyonu okumadı mı?

context.font = "22px arial";

bu, yüksekliği 22px olarak ayarlayacaktır.

tek nedeni bir ..

context.measureText(string).width

çünkü genişliğini istediğiniz dizgeyi bilmediği sürece dizgenin genişliği belirlenemez, ancak yazı tipi ile çizilen tüm dizeler için .. yükseklik 22px olacaktır.

px'den başka bir ölçüm kullanırsanız, yükseklik yine aynı olacaktır, ancak bu ölçümle en fazla yapmanız gereken tek şey ölçümü dönüştürmektir.


Bazı harfler sınırların üstüne veya altına uzanabilir, bkz. Whatwg.org/specs/web-apps/current-work/images/baselines.png
Octavia Togami

1
Kötü ifade edilmiş ama yine de genellikle doğrudur.
Lodewijk

Bütün bu cevapları okumak ama benim basit uygulamalar için bu doğru cevap, nk === px oldu
soymak

Tamamen yanlış. Çeşitli yazı tipleriyle önerilen çözümlerden bazılarını deneyin ve büyük farklılıklar bulacaksınız.
Dale Anderson

-4

Yaklaşık çözüm:

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;

Bu, tek aralıklı yazı tipinde doğru sonuç olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.