style - Calcular el ancho del texto con JavaScript
javascript getelementbyid style (21)
Me gustaría usar JavaScript para calcular el ancho de una cadena. ¿Es esto posible sin tener que usar una tipografía monoespaciada?
Si no está integrado, mi única idea es crear una tabla de anchos para cada personaje, pero esto es bastante irrazonable, especialmente para Unicode y diferentes tamaños de tipos (y todos los navegadores, para esa materia).
El método
Element.getClientRects()
devuelve una colección de objetosDOMRect
que indican los rectángulos delimitadores para cada cuadro de borde de CSS en un cliente. El valor devuelto es una colección de objetosDOMRect
, uno para cada cuadro de borde de CSS asociado con el elemento. Cada objetoDOMRect
contieneDOMRect
de solo lecturaleft
,top
,right
ebottom
describen el cuadro del borde, en píxeles, con la parte superior izquierda en relación con la parte superior izquierda de la ventana gráfica.
Element.getClientRects() de Mozilla Contributors está licenciado bajo CC-BY-SA 2.5 .
Al resumir todos los anchos de rectángulo devueltos se obtiene el ancho total del texto en píxeles.
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>
A partir de la respuesta de Deepak Nadar , cambié los parámetros de las funciones para aceptar texto y estilos de fuente. No es necesario hacer referencia a un elemento. Además, las fontOptions
tienen valores predeterminados, por lo que no es necesario que las suministre todas.
(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>
Aquí hay uno que batí juntos sin ejemplo. Parece que todos estamos en la misma página.
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;
}
Usarlo es simple: "a string".width()
** white-space: nowrap
agregado white-space: nowrap
para que se puedan calcular cadenas con un ancho mayor que el ancho de la ventana.
Crea un estilo DIV con los siguientes estilos. En su JavaScript, establezca el tamaño de fuente y los atributos que está tratando de medir, ponga su cadena en el DIV, luego lea el ancho y el alto actuales del DIV. Se estirará para ajustarse al contenido y el tamaño estará dentro de unos pocos píxeles del tamaño de la cadena renderizada.
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>
El ancho y la altura de un texto se pueden obtener con clientWidth
y clientHeight
var element = document.getElementById ("mytext");
var width = element.clientWidth;
var height = element.clientHeight;
asegúrese de que la propiedad de posición de estilo se establece en absoluta
element.style.position = "absolute";
no se requiere que esté dentro de un div
, puede estar dentro de una p
o un span
El código cortado a continuación, "calcula" el ancho de la etiqueta de separación, le agrega "..." si es demasiado largo y reduce la longitud del texto, hasta que encaje en su padre (o hasta que haya intentado más de mil veces)
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 (con 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)
}
}
});
En HTML 5 , solo puede usar el método Canvas.measureText (más explicaciones here ).
/**
* 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://.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
Este violín compara este método de Canvas con una variación del método basado en DOM de Bob Monteverde , para que pueda analizar y comparar la precisión de los resultados.
Hay varias ventajas de este enfoque, incluyendo:
- Más conciso y más seguro que los otros métodos (basados en DOM) porque no cambia el estado global, como su DOM.
- Es posible una mayor personalización al modificar más propiedades de texto de lienzo , como
textAlign
ytextBaseline
.
NOTA: Cuando agregue el texto a su DOM, recuerde también tener en cuenta el relleno, el margen y el borde .
NOTA 2: en algunos navegadores, este método produce una precisión de sub-píxel (el resultado es un número de punto flotante), en otros no (el resultado es solo un int). Es posible que desee ejecutar Math.floor
(o Math.ceil
) en el resultado, para evitar inconsistencias. Dado que el método basado en DOM nunca es sub-pixel preciso, este método tiene una precisión aún mayor que los otros métodos aquí.
De acuerdo con este jsperf (gracias a los colaboradores en los comentarios), el método Canvas y el método basado en DOM son igualmente rápidos, si el almacenamiento en caché se agrega al método basado en DOM y no está usando Firefox. En Firefox, por alguna razón, este método Canvas es mucho más rápido que el método basado en DOM (desde septiembre de 2014).
En caso de que alguien más haya llegado aquí buscando una manera de medir el ancho de una cuerda y una manera de saber cuál es el tamaño de fuente más grande que cabe en un ancho particular, aquí hay una función que se basa en la solución de @ Domi con una búsqueda 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 (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;
}
}
}
Escribí una pequeña herramienta para eso. Quizás sea útil para alguien. Funciona sin 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/
Esto me funciona ...
// 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;
}
Fiddle of working example: 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>
Código de 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");
La biblioteca de JavaScript de ExtJS tiene una gran clase llamada Ext.util.TextMetrics que "proporciona medidas precisas de píxeles para bloques de texto para que pueda determinar exactamente cuán alto y ancho, en píxeles, será un bloque de texto dado". Puede usarlo directamente o ver su código fuente para ver cómo se hace esto.
http://docs.sencha.com/extjs/6.5.3/modern/Ext.util.TextMetrics.html
Lo mejor es detectar si el texto se ajusta justo antes de mostrar el elemento. Así que puedes usar esta función que no requiere que el elemento esté en pantalla.
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) {
...
}
Me gusta tu "única idea" de simplemente hacer un mapa de ancho de caracteres estático. Realmente funciona bien para mis propósitos. A veces, por razones de rendimiento o porque no tiene fácil acceso a un DOM, es posible que solo desee una calculadora autónoma rápida y pirateada calibrada para una sola fuente. Así que aquí está uno calibrado para Helvetica; pasar una cadena y (opcionalmente) un tamaño de fuente:
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
}
Esa gigantesca matriz de feos son anchos de caracteres ASCII indexados por código de caracteres. Así que esto solo es compatible con ASCII (de lo contrario, asume un ancho de caracteres promedio). Afortunadamente, el ancho básicamente aumenta linealmente con el tamaño de la fuente, por lo que funciona bastante bien en cualquier tamaño de fuente. Es notoriamente carente de cualquier conocimiento de kerning o ligaduras o lo que sea.
Para "calibrar" acabo de mostrar todos los caracteres hasta el código de caracteres 126 (la poderosa tilde) en un svg y obtuve el cuadro delimitador y lo guardé en esta matriz; Más código y explicación y demostración aquí .
Prueba este código:
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;
}
Puedes usar el lienzo para no tener que lidiar tanto con las propiedades de 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;
Sin 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);
Supongo que es bastante similar a la entrada de Depak, pero se basa en el trabajo de Louis Lazaris publicado en un artículo en la página de Awesomewebs .
(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);
El evento de ajuste se usa para ejecutar la llamada a la función inmediatamente después de que la función se asocia al control.
por ejemplo: $ (''input''). autofit (). trigger ("fit");
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);
<span id="text">Text</span>
<script>
var textWidth = document.getElementById("text").offsetWidth;
</script>
Esto debería funcionar siempre que la etiqueta <span> no tenga otros estilos aplicados. offsetWidth incluirá el ancho de los bordes, el relleno horizontal, el ancho de la barra de desplazamiento vertical, etc.
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''));