Calcola la larghezza del testo con JavaScript

Mi piacerebbe usare JavaScript per calcolare la larghezza di una stringa. Questo è ansible senza dover usare un carattere tipografico monospace?

Se non è integrato, la mia unica idea è quella di creare una tabella di larghezze per ogni personaggio, ma questo è abbastanza irragionevole specialmente supportando Unicode e dimensioni di testo diverse (e tutti i browser per quella materia).

Crea un DIV in stile con i seguenti stili. Nel tuo JavaScript, imposta la dimensione e gli attributi del font che stai cercando di misurare, inserisci la stringa nel DIV, quindi leggi la larghezza e l’altezza attuali del DIV. Si allungherà per adattarsi al contenuto e la dimensione sarà entro pochi pixel della dimensione di rendering della stringa.

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 */ } 
 
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

In HTML 5 , puoi semplicemente utilizzare il metodo Canvas.measureText (ulteriori spiegazioni qui ).

Prova questo violino :

 /** * 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 (eg "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 

Questo violino confronta questo metodo Canvas con una variante del metodo basato su DOM di Bob Monteverde , in modo da poter analizzare e confrontare l’accuratezza dei risultati.

Ci sono diversi vantaggi a questo approccio, tra cui:

  • Più conciso e più sicuro degli altri (basati su DOM) perché non cambia lo stato globale, come il DOM.
  • Ulteriori personalizzazioni sono possibili modificando più proprietà del testo su canvas , come textAlign e textBaseline .

NOTA: quando aggiungi il testo al tuo DOM, ricorda di tenere conto anche di padding, margine e bordo .

NOTA 2: su alcuni browser, questo metodo produce accuratezza sub-pixel (il risultato è un numero in virgola mobile), in altri no (il risultato è solo un int). Potresti voler eseguire Math.floor (o Math.ceil ) sul risultato, per evitare incongruenze. Poiché il metodo basato su DOM non è mai accurato sotto pixel, questo metodo ha una precisione ancora maggiore rispetto agli altri metodi qui.

Secondo questo jsperf (grazie ai contributori nei commenti), il metodo Canvas e il metodo basato su DOM sono altrettanto veloci, se il caching viene aggiunto al metodo basato su DOM e non si utilizza Firefox. In Firefox, per qualche ragione, questo metodo Canvas è molto più veloce del metodo basato su DOM (a partire da settembre 2014).

Ecco uno che ho montato insieme senza un esempio. Sembra che siamo tutti sulla stessa pagina.

 String.prototype.width = function(font) { var f = font || '12px arial', o = $('
') .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() è semplice: "a string".width()

** Aggiunto white-space: nowrap stringhe di larghezza superiore alla larghezza della finestra.

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

Questo funziona per me …

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

La libreria javascript di ExtJS ha una grande class chiamata Ext.util.TextMetrics che “fornisce misurazioni precise dei pixel per blocchi di testo in modo da poter determinare esattamente quanto in alto e in largo, in pixel, un determinato blocco di testo sarà”. Puoi utilizzarlo direttamente o visualizzarne l’origine al codice per vedere come è fatto.

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

Ho scritto un piccolo strumento per questo. Forse è utile a qualcuno. Funziona senza jQuery .

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

Uso:

 var size = calculateSize("Hello world!", { font: 'Arial', fontSize: '12px' }); console.log(size.width); // 65 console.log(size.height); // 14 

Fiddle: http://jsfiddle.net/PEvL8/

Puoi usare la canvas in modo da non dover fare molto con le proprietà 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; 
 Text  

Questo dovrebbe funzionare fintanto che il tag non ha altri stili applicati. offsetWidth includerà la larghezza di qualsiasi bordo, riempimento orizzontale, larghezza della barra di scorrimento verticale, ecc.

Mi piace la tua “unica idea” di fare semplicemente una mappa di larghezza di carattere statico! In realtà funziona bene per i miei scopi. A volte, per motivi di prestazioni o perché non hai un facile accesso a un DOM, puoi semplicemente volere un calcolatore autonomo veloce e autonomo calibrato su un singolo font. Quindi ecco uno calibrato su Helvetica; passare una stringa e (opzionalmente) una dimensione del carattere:

 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 } 

Quel gigantesco array gigante è una larghezza di caratteri ASCII indicizzata dal codice del carattere. Quindi questo supporta solo ASCII (altrimenti assume una larghezza di carattere media). Fortunatamente, la larghezza sostanzialmente scala linearmente con la dimensione del carattere, quindi funziona abbastanza bene con qualsiasi dimensione del carattere. Manca evidentemente la consapevolezza del kerning o delle legature o altro.

Per “calibrare” ho solo reso ogni carattere fino a charCode 126 (la potente tilde) su una svg e ho ottenuto il riquadro di delimitazione e l’ho salvato in questa matrice; più codice e spiegazione e demo qui .

Il codice sotto, “calcola” la larghezza del tag span, aggiunge “…” ad esso se è troppo lungo e riduce la lunghezza del testo, finché non si adatta al suo genitore (o fino a quando non ha provato più di migliaia di volte)

CSS

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

HTML

 
This is my house
And my house are your house
This placename is most certainly too wide to fit

JavaScript (con jQuery)

 // loops elements classd "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) } } }); 

Prova questo codice:

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

La larghezza e l’altezza di un testo possono essere ottenute con clientWidth e clientHeight

 var element = document.getElementById ("mytext"); var width = element.clientWidth; var height = element.clientHeight; 

assicurati che la proprietà della posizione dello stile sia impostata su assoluto

 element.style.position = "absolute"; 

non è necessario essere all’interno di un div , può essere all’interno di una p o di una span

La cosa migliore è rilevare se il testo si adatta bene prima di visualizzare l’elemento. Quindi puoi usare questa funzione che non richiede che l’elemento sia sullo schermo.

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

Uso:

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

Fiddle of working esempio: http://jsfiddle.net/tdpLdqpo/1/

HTML:

 

How wide is this text?


How wide is this text?


How wide is this text?

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 sfj

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

Partendo dalla risposta di Deepak Nadar , ho modificato i parametri delle funzioni per accettare gli stili di testo e di font. Non è necessario fare riferimento a un elemento. Inoltre, fontOptions ha i valori predefiniti, quindi non è necessario fornirli tutti.

 (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 = $('
', { 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('

').text($.format('Font Dimensions: {0}px x {1}px', dimensions.width, dimensions.height));

  

Immagino che questo sia molto simile alla voce di Depak, ma si basa sul lavoro di Louis Lazaris pubblicato su un articolo nella pagina di 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, '
'); hiddenDiv.html(content); $(this).css('width', hiddenDiv.width()); }); return this; }; })(jQuery);

L’evento di adattamento viene utilizzato per eseguire immediatamente la chiamata di funzione dopo che la funzione è stata associata al controllo.

es: $ (‘input’). autofit (). trigger (“fit”);

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

Il metodo Element.getClientRects() restituisce una raccolta di oggetti DOMRect che indicano i rettangoli di delimitazione per ciascuna casella di confine CSS in un client. Il valore restituito è una raccolta di oggetti DOMRect , uno per ciascuna casella di confine CSS associata all’elemento. Ogni object DOMRect contiene proprietà di sola lettura left , top , right e bottom descrivono la casella del bordo, in pixel, con la parte in alto a sinistra rispetto alla parte superiore sinistra della finestra.

Element.getClientRects () di Mozilla Contributors è concesso in licenza in base a CC-BY-SA 2.5 .

Sommando tutte le larghezze di rettangolo restituite, si ottiene la larghezza totale del testo in pixel.

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

Sum of all widths: 0px

Nel caso in cui qualcun altro sia arrivato qui cercando sia un modo per misurare la larghezza di una stringa sia un modo per sapere qual è la dimensione del carattere più grande che si adatta ad una larghezza particolare, ecco una funzione che si basa sulla soluzione di @Domi con una ricerca binaria :

 /** * 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 (eg "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'));