Làm thế nào bạn có thể tìm thấy chiều cao của văn bản trên một khung vẽ HTML?


148

Thông số kỹ thuật có chức năng context.measureText (văn bản) sẽ cho bạn biết cần bao nhiêu chiều rộng để in văn bản đó, nhưng tôi không thể tìm ra cách để tìm ra chiều cao của nó. Tôi biết nó dựa trên phông chữ, nhưng tôi không biết chuyển đổi chuỗi phông chữ thành chiều cao văn bản.


1
Tôi rất muốn biết một cách tốt hơn so với câu trả lời hàng đầu. Nếu có một số thuật toán để lấy phông chữ tùy ý và tìm giới hạn tối đa / phút trên nó, thì tôi sẽ rất vui khi nghe về nó. =)
beatgammit

@tjameson - dường như có. Xem câu trả lời từ ellvdben (và sự nâng cao của tôi cho nó).
Daniel Earwicker

2
Tôi tự hỏi liệu ký tự Unicode 'FULL BLOCK' (U + 2588) có thể được sử dụng như một xấp xỉ bằng cách nhân chiều rộng của nó với hai.
Daniel F

1
Điều đáng chú ý là câu trả lời phụ thuộc một chút vào yêu cầu của bạn. Ví dụ: chiều cao cần thiết để hiển thị ký tự "a" khác với chiều cao được yêu cầu để hiển thị ký tự "y", do phần giảm dần kéo dài bên dưới đường cơ sở của phông chữ. Các câu trả lời dựa trên HTML dưới đây không tính đến điều này và sẽ cung cấp cho bạn chiều cao chung phù hợp với bất kỳ văn bản nào, trong khi câu trả lời của @ Noitidart cho chiều cao chính xác hơn cho văn bản cụ thể.
Dale Anderson

2
Hãy nhớ rằng bạn có thể có các nhân vật trông như thế này M̶̢̹̝͖̦̖̭͕̭̣͆̃̀̅̒̊͌̿ͅ, vì vậy đây là một vấn đề thực sự khó khăn để giải quyết cho trường hợp chung.
GetFree

Câu trả lời:


78

CẬP NHẬT - cho một ví dụ về hoạt động này, tôi đã sử dụng kỹ thuật này trong trình chỉnh sửa Carota .

Tiếp theo từ câu trả lời của ellvdben, đây là một phiên bản nâng cao để có được sự đi lên và đi xuống từ đường cơ sở, tức là giống như tmAscentvà được tmDescenttrả về bởi API GetTextMetric của Win32 . Điều này là cần thiết nếu bạn muốn thực hiện một dòng văn bản được bao bọc bằng các nhịp với các phông chữ / kích cỡ khác nhau.

Văn bản lớn trên vải với các dòng số liệu

Hình ảnh trên được tạo trên một khung vẽ trong Safari, màu đỏ là dòng trên cùng trong đó khung vẽ được yêu cầu vẽ văn bản, màu xanh lá cây là đường cơ sở và màu xanh lam là đáy (vì vậy màu đỏ thành màu xanh là chiều cao đầy đủ).

Sử dụng jQuery cho gọn gàng:

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

Ngoài một yếu tố văn bản, tôi thêm một div với display: inline-blockđể tôi có thể đặt vertical-alignkiểu của nó và sau đó tìm xem trình duyệt đã đặt nó ở đâu.

Vì vậy, bạn nhận lại một đối tượng với ascent, descentheight(chỉ là ascent+ descentđể thuận tiện). Để kiểm tra nó, đáng để có một hàm vẽ một đường ngang:

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

Sau đó, bạn có thể thấy cách văn bản được định vị trên khung vẽ so với đầu, đường cơ sở và dưới cùng:

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
Tại sao không sử dụng văn bản này để xác định chiều cao? abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 Tùy thuộc vào phông chữ, bạn có thể có các ký tự cao hơn hoặc thấp hơn g và M
omatase

1
@ellisbben đáng lưu ý rằng kết quả của điều này hơi khác với bạn, mặc dù tôi không biết tại sao. Chẳng hạn, bạn nói Courier New 8pt ==> cao 12 pixel, trong khi điều này nói: Courier New 8pt ==> cao 13 pixel. Tôi đã thêm "g" vào phương thức của bạn, nhưng đó không phải là sự khác biệt. Người ta tự hỏi, giá trị nào sẽ hữu ích nhất (không nhất thiết phải đúng về mặt kỹ thuật).
Orwellophile

3
Tôi chỉ có thể làm mọi thứ hoạt động chính xác khi tôi thay đổi dòng đầu tiên getTextHeight()thành var text = $('<span>Hg</span>').css({ 'font-family': fontName, 'font-size' : fontSize });, tức là thêm kích thước riêng.
cameron.bracken

1
Làm thế nào để làm cho nó hoạt động cho văn bản không phải tiếng Anh? xem jsfiddle.net/siddjain/6vURk
morpheus

1
cảm ơn bạn ! sửa đổi <div></div>để <div style="white-space : nowrap;"></div>xử lý chuỗi rất dài
Mickaël Gauvin

40

Bạn có thể lấy xấp xỉ rất gần với chiều cao dọc bằng cách kiểm tra chiều dài của chữ M.

ctx.font='bold 10px Arial';

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

8
Làm thế nào để chiều rộng cho chúng ta một xấp xỉ của chiều cao dòng?
Richard Barker

11
Điều đó có nghĩa là chiều rộng của một chữ hoa 'M' ở một cỡ chữ nhất định gần bằng với chiều cao của dòng. (Không biết điều này có đúng không, nhưng đó là những gì câu trả lời đang nói)
Nathan

2
Đây thực sự là một xấp xỉ khá tốt mà tôi sử dụng để tạo mẫu nhanh. Nó không hoàn hảo, nhưng đó là một giải pháp 90%.
Austin D

37

Thông số canvas không cung cấp cho chúng ta phương pháp đo chiều cao của chuỗi. Tuy nhiên, bạn có thể đặt kích thước của văn bản bằng pixel và bạn thường có thể tìm ra giới hạn dọc tương đối dễ dàng.

Nếu bạn cần một cái gì đó chính xác hơn thì bạn có thể ném văn bản lên khung vẽ và sau đó lấy dữ liệu pixel và tìm hiểu xem có bao nhiêu pixel được sử dụng theo chiều dọc. Điều này sẽ tương đối đơn giản, nhưng không hiệu quả lắm. Bạn có thể làm một cái gì đó như thế này (nó hoạt động, nhưng vẽ một số văn bản lên khung vẽ của bạn mà bạn muốn xóa):

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

Đối với Bespin, họ giả mạo chiều cao bằng cách đo chiều rộng của chữ thường 'm' ... Tôi không biết cách sử dụng này và tôi sẽ không đề xuất phương pháp này. Đây là phương pháp Bespin có liên quan:

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
Tôi nghi ngờ đây là những gì mà những người đã viết thông số HTML5 có trong tâm trí.
Steve Hanov

17
Đây là một hack khủng khiếp khủng khiếp mà tôi hoàn toàn yêu thích. +1
Allain Lalonde

1
Tôi không hiểu Đâu là mối liên hệ giữa phông chữ đi lên và chiều rộng của chữ "m"?
kayahr

6
emlà một phép đo phông tương đối trong đó một em bằng chiều cao của chữ cái Mtrong cỡ chữ mặc định.
giật

1
Phải, chiều cao không phải chiều rộng ... Tôi vẫn bối rối về kết nối. Ngoài ra, tôi nghĩ rằng EMS là không liên quan khi chúng ta chỉ quan tâm đến chiều cao tính bằng pixel.
Prestaul

35

Các trình duyệt đang bắt đầu hỗ trợ các số liệu văn bản nâng cao , điều này sẽ khiến nhiệm vụ này trở nên tầm thường khi được hỗ trợ rộng rãi:

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

fontHeight giúp bạn có chiều cao hộp giới hạn không đổi bất kể chuỗi được kết xuất. actualHeightlà cụ thể cho chuỗi được kết xuất.

Spec: https://www.w3.org/TR/2012/CR-2dcontext-20121217/#dom-textmetrics-fontboundingboxascent và các phần ngay bên dưới nó.

Trạng thái hỗ trợ (20 tháng 8 năm 2017):


2
Mọi người hãy bỏ phiếu trên các trang lỗi để triển khai các tính năng này sớm hơn
Jeremiah Rose

21

EDIT: Bạn đang sử dụng biến đổi canvas? Nếu vậy, bạn sẽ phải theo dõi ma trận biến đổi. Phương pháp sau đây sẽ đo chiều cao của văn bản với biến đổi ban đầu.

EDIT # 2: Điều kỳ lạ là đoạn mã dưới đây không tạo ra câu trả lời đúng khi tôi chạy nó trên trang StackOverflow này; hoàn toàn có thể là sự hiện diện của một số quy tắc phong cách có thể phá vỡ chức năng này.

Canvas sử dụng các phông chữ như được định nghĩa bởi CSS, vì vậy về mặt lý thuyết, chúng ta chỉ cần thêm một đoạn văn bản được tạo kiểu phù hợp vào tài liệu và đo chiều cao của nó. Tôi nghĩ rằng điều này dễ dàng hơn đáng kể so với kết xuất văn bản và sau đó kiểm tra dữ liệu pixel và nó cũng nên tôn trọng sự lên xuống của con cháu. Kiểm tra như sau:

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

Bạn sẽ phải đảm bảo rằng bạn có được kiểu phông chữ chính xác trên phần tử DOM mà bạn đo chiều cao nhưng điều đó khá đơn giản; thực sự bạn nên sử dụng một cái gì đó như

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 Cách giải pháp tốt hơn IMO. Nó có thể có được vị trí của đường cơ sở là tốt.
Daniel Earwicker

Đã thêm một câu trả lời mà có được đường cơ sở.
Daniel Earwicker

Nó có hoạt động không? Tôi thậm chí đã không nghĩ về việc dán nó trong một div. Điều này có lẽ thậm chí không phải được thêm vào DOM, phải không?
beatgammit

Tôi hoàn toàn không biết trường nào có kích thước và vị trí của nút tồn tại khi nó không phải là một phần của tài liệu. Tôi sẽ rất thích đọc một tài liệu tham khảo giải quyết vấn đề đó, nếu bạn biết về một tài liệu tham khảo.
ellvdben

5
+1 cho một loạt mã phức tạp sẽ chỉ là
bối cảnh.measureText

11

Không phải chiều cao của văn bản tính bằng pixel bằng kích thước phông chữ (tính bằng pts) nếu bạn xác định phông chữ bằng bối cảnh.font?


2
Đây là những gì nó được tuyên bố bởi nguồn này: html5canvastutorials.com/tutorials/html5-canvas-text-metrics
Rui Marques

đối với các trường hợp đơn giản: bạn luôn có thể phân tích chiều cao, từ tên phông chữ: parseInt (ctx.font.split ('') [0] .replace ('px', '')); // phân tích cú pháp chuỗi: "10px Verdana"
Sean

Bạn có thể sử dụng px, pt, em và% cho cỡ chữ. Đây chính xác là lý do tại sao câu trả lời này là sai lệch.
Jacksonkr

@Jacksonkr, Yea nhưng bạn vẫn có thể phân tích chúng ra và điều chỉnh cho phù hợp phải không? Hoặc có một giới hạn cố hữu ở đâu đó cho phương pháp này?
Pacerier

@Pacerier Hạn chế là bạn có thể giới thiệu một số lỗi khiến bạn phải nhổ tóc. Chỉ cần nhớ rằng các loại đơn vị trộn có thể dẫn đến mã buggy / spaghetti. Điều đó nói rằng, tôi không ở trên hack thường xuyên miễn là rủi ro cho các vấn đề là thấp.
Jacksonkr

10

Như JJ Stiff gợi ý, bạn có thể thêm văn bản của mình vào một khoảng và sau đó đo độ lệch Độ cao của khoảng đó.

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

Như được hiển thị trên HTML5Rocks


3
Đây là một giải pháp tuyệt vời, Cảm ơn ... nhưng tôi không biết tại sao nếu khoảng này không được thêm vào trang và hiển thị trước khi tôi nhận được offset của nó! nó luôn trả về chiều cao như ZERO trong Chrome và Firefox!
Mustafah

1
Bạn nói đúng, tôi đoán nó phải được thêm vào dom để nó chiếm không gian. Dưới đây là một Fiddle JS của hoạt động này: jsfiddle.net/mpalmerlee/4NfVR/4 Tôi cũng đã cập nhật mã ở trên.
Matt Palmerlee

Sử dụng clientHeight cũng là một khả năng. Câu trả lời này là một giải pháp cho vấn đề, nó là một cách giải quyết xấu xí. + 1'd tuy nhiên.
Daniel F

Điều này không xem xét chiều cao thực tế của văn bản hiển thị và thường đi kèm với lề bổ sung trên đầu văn bản
Ain Tohvri

8

Chỉ cần thêm vào câu trả lời của Daniel (thật tuyệt! Và hoàn toàn đúng!), Phiên bản không có 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];
}

Tôi vừa kiểm tra mã ở trên và hoạt động rất tốt trên Chrome, FF và Safari mới nhất trên Mac.

EDIT: Tôi cũng đã thêm kích thước phông chữ và đã thử nghiệm với webfont thay vì phông chữ hệ thống - hoạt động tuyệt vời.


7

Tôi đã giải quyết vấn đề này một cách khó khăn - sử dụng thao tác pixel.

Đây là câu trả lời đồ họa:

Đây là mã:

    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
Tôi tin rằng giải pháp này không tính đến các chữ cái chấm như chữ thường i và j
wusauarus

3

Tôi đang viết một trình giả lập thiết bị đầu cuối nên tôi cần vẽ hình chữ nhật xung quanh các ký tự.

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

Rõ ràng nếu bạn muốn chính xác dung lượng mà nhân vật chiếm, nó sẽ không giúp ích gì. Nhưng nó sẽ cung cấp cho bạn một xấp xỉ tốt cho một số mục đích sử dụng.



3

Đây là một chức năng đơn giản. Không cần thư viện.

Tôi đã viết hàm này để có được giới hạn trên và dưới so với đường cơ sở. Nếu textBaselineđược đặt thành alphabetic. Những gì nó làm là nó tạo ra một khung vẽ khác, và sau đó vẽ ở đó, và sau đó tìm thấy pixel trên cùng nhiều nhất và dưới cùng. Và đó là giới hạn trên và dưới. Nó trả về nó như là tương đối, vì vậy nếu chiều cao là 20px và không có gì bên dưới đường cơ sở, thì giới hạn trên cùng là-20 .

Bạn phải cung cấp các ký tự cho nó. Nếu không, nó sẽ cung cấp cho bạn 0 chiều cao và 0 chiều rộng, rõ ràng.

Sử dụng:

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

Đây là chức năng:

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, relativeTopheightlà những điều hữu ích trong đối tượng trả về.

Dưới đây là ví dụ sử dụng:

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

Các relativeBotrelativeToplà những gì bạn nhìn thấy trong hình ảnh này ở đây:

https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing bản


3

một dòng trả lời

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

CSS "line-height: normal" nằm trong khoảng từ 1 đến 1.2

đọc ở đây để biết thêm



2

Đây là những gì tôi đã làm dựa trên một số câu trả lời khác ở đây:

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

Trước hết, bạn cần đặt chiều cao của kích thước phông chữ, sau đó theo giá trị của chiều cao phông chữ để xác định chiều cao hiện tại của văn bản của bạn là bao nhiêu, các dòng chữ chéo, tất nhiên, cùng chiều cao của phông chữ cần tích lũy, nếu văn bản không vượt quá chiều cao hộp văn bản lớn nhất, tất cả hiển thị, nếu không, chỉ hiển thị văn bản trong văn bản hộp. Giá trị cao cần định nghĩa của riêng bạn. Chiều cao đặt trước càng lớn, chiều cao của văn bản cần hiển thị và chặn càng lớn.

Sau khi hiệu ứng được xử lý (giải quyết)

Trước khi hiệu ứng được xử lý (chưa giải quyết)

  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

Tôi thấy rằng CHỈ CHO ARIAL cách đơn giản nhất, nhanh nhất và chính xác nhất để tìm chiều cao của khung giới hạn là sử dụng chiều rộng của các chữ cái nhất định. Nếu bạn có kế hoạch sử dụng một phông chữ nhất định mà không cho phép người dùng chọn một phông chữ khác nhau, bạn có thể thực hiện một nghiên cứu nhỏ để tìm đúng chữ cái thực hiện công việc cho phông chữ đó.

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

cài đặt kích thước phông chữ có thể không thực tế, vì cài đặt

ctx.font = ''

sẽ sử dụng một được xác định bởi CSS cũng như bất kỳ thẻ phông chữ nhúng nào. Nếu bạn sử dụng phông chữ CSS, bạn không biết chiều cao là bao nhiêu từ cách lập trình, sử dụng phương thức đo lường, rất ngắn gọn. Trên một lưu ý khác, IE8 DOES trả về chiều rộng và chiều cao.


0

Điều này hoạt động 1) cho văn bản nhiều dòng cũng 2) và ngay cả trong 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

Tôi biết đây là một câu hỏi đã được trả lời cũ, nhưng để tham khảo trong tương lai tôi muốn thêm một giải pháp ngắn, tối thiểu, chỉ dành cho JS (không có jquery) tôi tin rằng mọi người có thể hưởng lợi từ:

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

Trong các tình huống bình thường, nên làm như sau:

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

5
Hoàn toàn và hoàn toàn sai. Có sự khác biệt lớn giữa kích thước điểm và kích thước pixel. Kích thước điểm dẫn đến văn bản có kích thước khác nhau tùy thuộc vào DPI mà trang đang được hiển thị, trong đó kích thước pixel không tính đến điều đó.
Vua Orvid

2
Bạn có quen thuộc với khái niệm pixel màn hình? Bạn có thể thấy nó khai sáng. Bất kể, pt và px thực sự chỉ ra độ cao khác nhau. Điều đáng chú ý là phông chữ có thể lấp đầy ít hơn "chiều cao", hoặc nhiều hơn, dù sao đi nữa. Tôi không chắc chắn nếu pixel pixel được thu nhỏ, nhưng tôi giả sử như vậy. Đó là một câu trả lời "sai", mặc dù. Nó đơn giản và có thể được sử dụng trong nhiều tình huống.
Lodewijk

-4

Điều này thật điên rồ ... Chiều cao của văn bản là kích thước phông chữ .. Không ai trong số các bạn đọc tài liệu?

context.font = "22px arial";

cái này sẽ đặt chiều cao thành 22px.

lý do duy nhất có một ..

context.measureText(string).width

là bởi vì chiều rộng của chuỗi không thể được xác định trừ khi nó biết chuỗi bạn muốn có chiều rộng nhưng đối với tất cả các chuỗi được vẽ bằng phông chữ .. chiều cao sẽ là 22px.

nếu bạn sử dụng một phép đo khác hơn px thì chiều cao vẫn sẽ giống nhau nhưng với phép đo đó, vì vậy, hầu hết bạn sẽ phải làm là chuyển đổi phép đo.


Một số chữ cái có thể mở rộng trên hoặc dưới giới hạn, xem whatwg.org/specs/web-apps/civerse-work/images/baselines.png
Octavia Togami

1
Phrased xấu nhưng vẫn thường đúng.
Lodewijk

đọc tất cả các câu trả lời nhưng đối với ứng dụng đơn giản của tôi thì đây là câu trả lời đúng, pt === px
cướp

Hoàn toàn không chính xác. Hãy thử một số giải pháp được đề xuất với các phông chữ khác nhau và bạn sẽ tìm thấy sự khác biệt lớn.
Dale Anderson

-4

Giải pháp gần đúng:

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;

Đây sẽ là kết quả chính xác trong phông chữ đơn cách.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.