Вычисление ширины текста с помощью JavaScript



Я хотел бы использовать JavaScript для вычисления ширины строки. Возможно ли это без использования моноширинного шрифта?



Если это не встроенный, моя единственная идея-создать таблицу Ширин для каждого символа, но это довольно неразумно, особенно поддерживая Unicode и разные размеры типов (и все браузеры, если на то пошло).

2748   21  

21 ответов:

создать DIV стиле со следующими стилями. В вашем JavaScript установите размер шрифта и атрибуты, которые вы пытаетесь измерить, поместите свою строку в DIV, а затем прочитайте текущую ширину и высоту DIV. Он будет растягиваться, чтобы соответствовать содержимому,и размер будет в пределах нескольких пикселей от размера строки.

var fontSize = 12;
var test = document.getElementById("Test");
test.style.fontSize = fontSize;
var height = (test.clientHeight + 1) + "px";
var width = (test.clientWidth + 1) + "px"

console.log(height, width);
#Test
{
    position: absolute;
    visibility: hidden;
    height: auto;
    width: auto;
    white-space: nowrap; /* Thanks to Herb Caudill comment */
}
<div id="Test">
    abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>

на HTML 5, вы можете просто использовать холст.способ measureText (дальнейшее объяснение здесь).

попробуйте эту скрипку:

/**
 * Uses canvas.measureText to compute and return the width of the given text of given font in pixels.
 * 
 * @param {String} text The text to be rendered.
 * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana").
 * 
 * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393
 */
function getTextWidth(text, font) {
    // re-use canvas object for better performance
    var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    context.font = font;
    var metrics = context.measureText(text);
    return metrics.width;
}

console.log(getTextWidth("hello there!", "bold 12pt arial"));  // close to 86

эта скрипка сравнивает этот метод холста с вариацией Боб Монтеверде дом на основе метода, так что вы можете анализировать и сравнивать точность результатов.

есть несколько преимуществ такой подход, в том числе:

Примечание: при добавлении текста в DOM, не забудьте также принять во внимание обивка, поля и границы.

примечание 2: в некоторых браузерах это метод дает субпиксельную точность (результат-число с плавающей запятой), на других-нет (результат-только int). Возможно, вы захотите запустить Math.floor (или Math.ceil) на результат, чтобы избежать несоответствий. Поскольку метод на основе DOM никогда не является субпиксельным точным, этот метод имеет даже более высокую точность, чем другие методы здесь.

по данным это jsperf (спасибо участникам в комментариях), то метод холст и DOM-based метод примерно одинаково быстро, если кэширование добавляется к DOM-метод и вы не используете Firefox. В Firefox, почему-то, это метод холст намного быстрее, чем DOM-метод (по состоянию на сентябрь 2014).

вот один я взбил вместе без примера. Похоже, мы все на одной странице.

String.prototype.width = function(font) {
  var f = font || '12px arial',
      o = $('<div></div>')
            .text(this)
            .css({'position': 'absolute', 'float': 'left', 'white-space': 'nowrap', 'visibility': 'hidden', 'font': f})
            .appendTo($('body')),
      w = o.width();

  o.remove();

  return w;
}

используя его просто:"a string".width()

**добавил white-space: nowrap таким образом, строки с шириной больше ширины окна могут быть вычислены.

jQuery:

(function($) {

 $.textMetrics = function(el) {

  var h = 0, w = 0;

  var div = document.createElement('div');
  document.body.appendChild(div);
  $(div).css({
   position: 'absolute',
   left: -1000,
   top: -1000,
   display: 'none'
  });

  $(div).html($(el).html());
  var styles = ['font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing'];
  $(styles).each(function() {
   var s = this.toString();
   $(div).css(s, $(el).css(s));
  });

  h = $(div).outerHeight();
  w = $(div).outerWidth();

  $(div).remove();

  var ret = {
   height: h,
   width: w
  };

  return ret;
 }

})(jQuery);

это работает для меня...

// Handy JavaScript to measure the size taken to render the supplied text;
// you can supply additional style information too if you have it.

function measureText(pText, pFontSize, pStyle) {
    var lDiv = document.createElement('div');

    document.body.appendChild(lDiv);

    if (pStyle != null) {
        lDiv.style = pStyle;
    }
    lDiv.style.fontSize = "" + pFontSize + "px";
    lDiv.style.position = "absolute";
    lDiv.style.left = -1000;
    lDiv.style.top = -1000;

    lDiv.innerHTML = pText;

    var lResult = {
        width: lDiv.clientWidth,
        height: lDiv.clientHeight
    };

    document.body.removeChild(lDiv);
    lDiv = null;

    return lResult;
}

The библиотека JavaScript ExtJS имеет большой класс под названием Ext.утиль.TextMetrics, которая "обеспечивает точные измерения пикселей для блоков текста, чтобы вы могли точно определить, насколько высоким и широким в пикселях будет данный блок текста". Вы можете либо использовать его напрямую, либо просмотреть его исходный код, чтобы увидеть, как это делается.

http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html

Я написал небольшой инструмент для этого. Возможно, это кому-то полезно. Это работает без jQuery.

https://github.com/schickling/calculate-size

использование:

var size = calculateSize("Hello world!", {
   font: 'Arial',
   fontSize: '12px'
});

console.log(size.width); // 65
console.log(size.height); // 14

Скрипка:http://jsfiddle.net/PEvL8/

вы можете использовать холст, так что вам не придется иметь дело так много с CSS свойствами:

var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "20pt Arial";  // This can be set programmaticly from the element's font-style if desired
var textWidth = ctx.measureText($("#myElement").text()).width;
<span id="text">Text</span>

<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>

Это должно работать до тех пор, пока тег не имеет других стилей, применяемых к нему. offsetWidth будет включать ширину любых границ, горизонтальное заполнение, вертикальную ширину полосы прокрутки и т. д.

Мне нравится ваша "единственная идея" просто делать статическую карту ширины символов! Это действительно хорошо работает для моих целей. Иногда, по соображениям производительности или потому, что у вас нет легкого доступа к DOM, вам может просто понадобиться быстрый хакерский автономный калькулятор, откалиброванный до одного шрифта. Итак, вот один калиброванный для Helvetica; передайте строку и (необязательно) размер шрифта:

function measureText(str, fontSize = 10) {
  const widths = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.2796875,0.2765625,0.3546875,0.5546875,0.5546875,0.8890625,0.665625,0.190625,0.3328125,0.3328125,0.3890625,0.5828125,0.2765625,0.3328125,0.2765625,0.3015625,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.5546875,0.2765625,0.2765625,0.584375,0.5828125,0.584375,0.5546875,1.0140625,0.665625,0.665625,0.721875,0.721875,0.665625,0.609375,0.7765625,0.721875,0.2765625,0.5,0.665625,0.5546875,0.8328125,0.721875,0.7765625,0.665625,0.7765625,0.721875,0.665625,0.609375,0.721875,0.665625,0.94375,0.665625,0.665625,0.609375,0.2765625,0.3546875,0.2765625,0.4765625,0.5546875,0.3328125,0.5546875,0.5546875,0.5,0.5546875,0.5546875,0.2765625,0.5546875,0.5546875,0.221875,0.240625,0.5,0.221875,0.8328125,0.5546875,0.5546875,0.5546875,0.5546875,0.3328125,0.5,0.2765625,0.5546875,0.5,0.721875,0.5,0.5,0.5,0.3546875,0.259375,0.353125,0.5890625]
  const avg = 0.5279276315789471
  return str
    .split('')
    .map(c => c.charCodeAt(0) < widths.length ? widths[c.charCodeAt(0)] : avg)
    .reduce((cur, acc) => acc + cur) * fontSize
}

этот гигантский уродливый массив-это ширина символов ASCII, индексированная символьным кодом. Так что это просто поддерживает ASCII (в противном случае он принимает среднюю ширину символа). К счастью, ширина в основном линейно масштабируется с размером шрифта, поэтому он работает довольно хорошо при любом размере шрифта. Ему явно не хватает какого-либо понимания Кернинга или лигатур или чего-то еще.

для "калибровки" я просто визуализировал каждый символ до charCode 126 (The mighty tilde) на svg и получил ограничивающую рамку и сохранил ее в этом массиве;больше кода и объяснения и демо здесь.

код-обрезает ниже, "вычисляет" ширину span-тега, добавляет"..."к нему, если он слишком длинный и уменьшает длину текста, пока он не поместится в своем родителе (или пока он не попробовал более тысячи раз)

CSS

div.places {
  width : 100px;
}
div.places span {
  white-space:nowrap;
  overflow:hidden;
}

HTML

<div class="places">
  <span>This is my house</span>
</div>
<div class="places">
  <span>And my house are your house</span>
</div>
<div class="places">
  <span>This placename is most certainly too wide to fit</span>
</div>

JavaScript (с jQuery)

// loops elements classed "places" and checks if their child "span" is too long to fit
$(".places").each(function (index, item) {
    var obj = $(item).find("span");
    if (obj.length) {
        var placename = $(obj).text();
        if ($(obj).width() > $(item).width() && placename.trim().length > 0) {
            var limit = 0;
            do {
                limit++;
                                    placename = placename.substring(0, placename.length - 1);
                                    $(obj).text(placename + "...");
            } while ($(obj).width() > $(item).width() && limit < 1000)
        }
    }
});

попробуйте этот код:

function GetTextRectToPixels(obj)
{
var tmpRect = obj.getBoundingClientRect();
obj.style.width = "auto"; 
obj.style.height = "auto"; 
var Ret = obj.getBoundingClientRect(); 
obj.style.width = (tmpRect.right - tmpRect.left).toString() + "px";
obj.style.height = (tmpRect.bottom - tmpRect.top).toString() + "px"; 
return Ret;
}

ширина и высота текста могут быть получены с помощью clientWidth и clientHeight

var element = document.getElementById ("mytext");

var width = element.clientWidth;
var height = element.clientHeight;

убедитесь, что свойство style position имеет значение absolute

element.style.position = "absolute";

Не обязательно быть внутри div, может быть внутри p или span

лучше всего, чтобы определить, будет ли текст подходит прямо перед отображением элемента. Так что вы можете использовать эту функцию, которая не требует элемента на экране.

function textWidth(text, fontProp) {
    var tag = document.createElement("div");
    tag.style.position = "absolute";
    tag.style.left = "-999em";
    tag.style.whiteSpace = "nowrap";
    tag.style.font = fontProp;
    tag.innerHTML = text;

    document.body.appendChild(tag);

    var result = tag.clientWidth;

    document.body.removeChild(tag);

    return result;
}

использование:

if ( textWidth("Text", "bold 13px Verdana") > elementWidth) {
    ...
}

Скрипка рабочего примера:http://jsfiddle.net/tdpLdqpo/1/

HTML:

<h1 id="test1">
    How wide is this text?
</h1>
<div id="result1"></div>
<hr/>
<p id="test2">
    How wide is this text?
</p>
<div id="result2"></div>
<hr/>
<p id="test3">
    How wide is this text?<br/><br/>
    f sdfj f sdlfj lfj lsdk jflsjd fljsd flj sflj sldfj lsdfjlsdjkf sfjoifoewj flsdjfl jofjlgjdlsfjsdofjisdojfsdmfnnfoisjfoi  ojfo dsjfo jdsofjsodnfo sjfoj ifjjfoewj fofew jfos fojo foew jofj s f j
</p>
<div id="result3"></div>

JavaScript код:

function getTextWidth(text, font) {
    var canvas = getTextWidth.canvas ||
        (getTextWidth.canvas = document.createElement("canvas"));
    var context = canvas.getContext("2d");
    context.font = font;
    var metrics = context.measureText(text);
    return metrics.width;
};

$("#result1")
.text("answer: " +
    getTextWidth(
             $("#test1").text(),
             $("#test1").css("font")) + " px");

$("#result2")
    .text("answer: " +
        getTextWidth(
             $("#test2").text(),
             $("#test2").css("font")) + " px");

$("#result3")
    .text("answer: " +
        getTextWidth(
             $("#test3").text(),
             $("#test3").css("font")) + " px");

строительство ответ Дипака Надара, Я изменил параметр функции, чтобы принимать стили текста и шрифта. Вам не нужно ссылаться на элемент. Кроме того,fontOptions имеют значения по умолчанию, так что вам не нужно поставить все из них.

(function($) {
  $.format = function(format) {
    return (function(format, args) {
      return format.replace(/{(\d+)}/g, function(val, pos) {
        return typeof args[pos] !== 'undefined' ? args[pos] : val;
      });
    }(format, [].slice.call(arguments, 1)));
  };
  $.measureText = function(html, fontOptions) {
    fontOptions = $.extend({
      fontSize: '1em',
      fontStyle: 'normal',
      fontWeight: 'normal',
      fontFamily: 'arial'
    }, fontOptions);
    var $el = $('<div>', {
      html: html,
      css: {
        position: 'absolute',
        left: -1000,
        top: -1000,
        display: 'none'
      }
    }).appendTo('body');
    $(fontOptions).each(function(index, option) {
      $el.css(option, fontOptions[option]);
    });
    var h = $el.outerHeight(), w = $el.outerWidth();
    $el.remove();
    return { height: h, width: w };
  };
}(jQuery));

var dimensions = $.measureText("Hello World!", { fontWeight: 'bold', fontFamily: 'arial' });

// Font Dimensions: 94px x 18px
$('body').append('<p>').text($.format('Font Dimensions: {0}px x {1}px', dimensions.width, dimensions.height));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Я думаю, что это prety похоже на запись Depak, но основано на работе Луи Лазариса, опубликованной в статье в страница impressivewebs

(function($){

        $.fn.autofit = function() {             

            var hiddenDiv = $(document.createElement('div')),
            content = null;

            hiddenDiv.css('display','none');

            $('body').append(hiddenDiv);

            $(this).bind('fit keyup keydown blur update focus',function () {
                content = $(this).val();

                content = content.replace(/\n/g, '<br>');
                hiddenDiv.html(content);

                $(this).css('width', hiddenDiv.width());

            });

            return this;

        };
    })(jQuery);

событие fit используется для выполнения вызова функции inmediatly после привязки функции к элементу управления.

например: $('input').автоподбор.)(триггер("вписаться");

без jQuery:

String.prototype.width = function (fontSize) {
    var el,
        f = fontSize + " px arial" || '12px arial';
    el = document.createElement('div');
    el.style.position = 'absolute';
    el.style.float = "left";
    el.style.whiteSpace = 'nowrap';
    el.style.visibility = 'hidden';
    el.style.font = f;
    el.innerHTML = this;
    el = document.body.appendChild(el);
    w = el.offsetWidth;
    el.parentNode.removeChild(el);
    return w;
}

// Usage
"MyString".width(12);

The Element.getClientRects() метод возвращает коллекцию DOMRect объекты, которые указывают ограничивающие прямоугольники для каждого поля границы CSS в клиенте. Возвращаемое значение представляет собой коллекцию DOMRect объекты, по одному для каждого поля границы CSS, связанного с элементом. Каждый DOMRect объект содержит только для чтения left,top,right и bottom свойства, описывающие поле границы, в пикселях, с верхним левым относительно верхнего левого края область просмотра.

элемент.getClientRects() by Mozilla Contributors под лицензией CC-BY-SA 2.5.

суммирование всех возвращенных значений ширины прямоугольника дает общую ширину текста в пикселях.

document.getElementById('in').addEventListener('input', function (event) {
    var span = document.getElementById('text-render')
    span.innerText = event.target.value
    var rects = span.getClientRects()
    var widthSum = 0
    for (var i = 0; i < rects.length; i++) {
        widthSum += rects[i].right - rects[i].left
    }
    document.getElementById('width-sum').value = widthSum
})
<p><textarea id='in'></textarea></p>
<p><span id='text-render'></span></p>
<p>Sum of all widths: <output id='width-sum'>0</output>px</p>

в случае, если кто-то еще попал сюда, ища способ измерить ширину строки и способ узнать, какой самый большой размер шрифта будет соответствовать определенной ширине, вот функция, которая строится на решении @Domi с двоичным поиском:

/**
 * Find the largest font size (in pixels) that allows the string to fit in the given width.
 * 
 * @param {String} text The text to be rendered.
 * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold ?px verdana") -- note the use of ? in place of the font size.
 * @param {width} the width in pixels the string must fit in
 * @param {minFontPx} the smallest acceptable font size in pixels
 * @param {maxFontPx} the largest acceptable font size in pixels
**/
function GetTextSizeForWidth( text, font, width, minFontPx, maxFontPx )
{
    for ( ; ; )
    {
        var s = font.replace( "?", maxFontPx );
        var w = GetTextWidth( text, s );
        if ( w <= width )
        {
            return maxFontPx;
        }

        var g = ( minFontPx + maxFontPx ) / 2;

        if ( Math.round( g ) == Math.round( minFontPx ) || Math.round( g ) == Math.round( maxFontPx ) )
        {
            return g;
        }

        s = font.replace( "?", g );
        w = GetTextWidth( text, s );
        if ( w >= width )
        {
            maxFontPx = g;
        }
        else
        {
            minFontPx = g;
        }
    }
}
var textWidth = (function (el) {
    el.style.position = 'absolute';
    el.style.top = '-1000px';
    document.body.appendChild(el);

    return function (text) {
        el.innerHTML = text;
        return el.clientWidth;
    };
})(document.createElement('div'));

Comments

    Ничего не найдено.