JavaScript를 사용하여 텍스트 너비 계산 고정 폭

JavaScript를 사용하여 문자열 너비를 계산하고 싶습니다. 고정 폭 서체를 사용하지 않고도 가능합니까?

내장되어 있지 않으면 각 문자에 대해 너비 테이블을 만드는 것이 유일한 아이디어이지만 유니 코드 와 다른 유형 크기 (및 해당 문제에 대한 모든 브라우저)를 지원하는 것은 부당 합니다.



답변

다음 스타일로 스타일 화 된 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 에서는 Canvas.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 /programming/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

이 바이올린 은이 Canvas 방법을 Bob Monteverde의 DOM 기반 방법의 변형 과 비교하므로 결과의 정확성을 분석하고 비교할 수 있습니다.

이 방법에는 다음과 같은 몇 가지 장점이 있습니다.

  • DOM과 같은 전역 상태를 변경하지 않기 때문에 다른 (DOM 기반) 방법보다 더 간결하고 안전합니다.
  • 또한, 커스터마이즈가 가능 더 캔버스 텍스트 속성을 수정하는 등, textAligntextBaseline.

참고 : 텍스트를 DOM에 추가 할 때 채우기, 여백 및 경계 도 고려해야합니다 .

참고 2 : 일부 브라우저에서이 방법은 하위 픽셀 정확도 (결과는 부동 소수점 수)를 생성하고 다른 브라우저에서는 그렇지 않습니다 (결과는 정수임). 불일치를 피하기 위해 결과에서 실행 Math.floor(또는 Math.ceil)을 원할 수 있습니다 . DOM 기반 방법은 절대 서브 픽셀 정확도가 아니기 때문에이 방법은 다른 방법보다 정확도가 훨씬 높습니다.

이 jsperf 에 따르면 (주석에 기여한 사람들에게 감사드립니다) 캐싱이 DOM 기반 방법에 추가되고 Firefox를 사용하지 않는 경우 Canvas 방법DOM 기반 방법 이 거의 동일 합니다. Firefox에서 어떤 이유로 든이 Canvas 방법DOM 기반 방법 (2014 년 9 월 기준) 보다 훨씬 빠릅니다 .


답변

여기에 예를 들지 않고 채찍질 한 것이 있습니다. 우리 모두 같은 페이지에있는 것 같습니다.

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


답변

의 ExtJS 자바 스크립트 라이브러리는 “정확히 얼마나 높은 확인할 수 있습니다 넓은 픽셀 단위로 텍스트의 특정 블록이 될 수 있도록 텍스트 블록에 대한 정확한 픽셀 측정을 제공한다”고 Ext.util.TextMetrics라는 큰 클래스를 가지고있다. 직접 사용하거나 소스를보고 코드 작성 방법을 확인할 수 있습니다.

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


답변

나는 단지 정적 문자 너비 맵을하는 “단 하나의 아이디어”를 좋아합니다! 실제로 내 목적에 잘 작동합니다. 때로는 성능상의 이유로 또는 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 만 지원합니다 (그렇지 않으면 평균 문자 너비를 가정합니다). 다행히도 너비는 기본적으로 글꼴 크기와 선형으로 확장되므로 모든 글꼴 크기에서 잘 작동합니다. 커닝이나 합자 등에 대한 인식이 눈에 띄게 부족합니다.

“교정”하기 위해 방금 svg에서 모든 문자를 charCode 126 (강한 물결표)까지 렌더링하고 경계 상자를 가져 와서이 배열에 저장했습니다. 더 많은 코드와 설명 및 데모는 여기에 있습니다 .