javascript - etiqueta - svg stroke
SVG obtiene el ancho del elemento de texto (6)
¿Qué tal algo así para la compatibilidad?
function svgElemWidth(elem) {
var methods = [ // name of function and how to process its result
{ fn: ''getBBox'', w: function(x) { return x.width; }, },
{ fn: ''getBoundingClientRect'', w: function(x) { return x.width; }, },
{ fn: ''getComputedTextLength'', w: function(x) { return x; }, }, // text elements only
];
var widths = [];
var width, i, method;
for (i = 0; i < methods.length; i++) {
method = methods[i];
if (typeof elem[method.fn] === ''function'') {
width = method.w(elem[method.fn]());
if (width !== 0) {
widths.push(width);
}
}
}
var result;
if (widths.length) {
result = 0;
for (i = 0; i < widths.length; i++) {
result += widths[i];
}
result /= widths.length;
}
return result;
}
Esto devuelve el promedio de cualquier resultado válido de los tres métodos. Puede mejorarlo para descartar valores atípicos o para favorecer getComputedTextLength
si el elemento es un elemento de texto.
Advertencia: como dice el comentario, getBoundingClientRect
es complicado. getBoundingClientRect
de los métodos o use esto solo en los elementos donde getBoundingClientRect
arrojará buenos resultados, por lo que no habrá rotación y probablemente no habrá escalado (?)
Estoy trabajando en algunos ECMAScript / JavaScript para un archivo SVG y necesito obtener el width
y height
de un elemento de text
para poder cambiar el tamaño de un rectángulo que lo rodea. En HTML, podría usar los offsetWidth
y offsetHeight
en el elemento, pero parece que esas propiedades no están disponibles.
Aquí hay un fragmento con el que necesito trabajar. Necesito cambiar el ancho del rectángulo cada vez que cambio el texto, pero no sé cómo obtener el width
real (en píxeles) del elemento de text
.
<rect x="100" y="100" width="100" height="100" />
<text>Some Text</text>
¿Algunas ideas?
Con respecto a la longitud del texto, el enlace parece indicar que BBox y getComputedTextLength () pueden devolver valores ligeramente diferentes, pero que son bastante cercanos entre sí.
La especificación SVG tiene un método específico para devolver esta información: getComputedTextLength()
var width = textElement.getComputedTextLength(); // returns a pixel number
No estoy seguro de por qué, pero ninguno de los métodos anteriores funciona para mí. Tuve cierto éxito con el método canvas, pero tuve que aplicar todo tipo de factores de escala. Incluso con los factores de escala, aún tenía resultados inconsistentes entre Safari, Chrome y Firefox.
Entonces, intenté lo siguiente:
var div = document.createElement(''div'');
div.style.position = ''absolute'';
div.style.visibility = ''hidden'';
div.style.height = ''auto'';
div.style.width = ''auto'';
div.style.whiteSpace = ''nowrap'';
div.style.fontFamily = ''YOUR_FONT_GOES_HERE'';
div.style.fontSize = ''100'';
div.style.border = "1px solid blue"; // for convenience when visible
div.innerHTML = "YOUR STRING";
document.body.appendChild(div);
var offsetWidth = div.offsetWidth;
var clientWidth = div.clientWidth;
document.body.removeChild(div);
return clientWidth;
Trabajó increíble y súper preciso, pero solo en Firefox. Escala factores para el rescate de Chrome y Safari, pero no hay alegría. Resulta que los errores de Safari y Chrome no son lineales con la longitud de la cadena o el tamaño de la fuente.
Entonces, acércate al número dos. No me importa mucho el enfoque de la fuerza bruta, pero después de luchar con esto por años decidí probarlo. Decidí generar valores constantes para cada personaje imprimible individual. Normalmente esto sería tedioso, pero por suerte Firefox es muy preciso. Aquí está mi solución de fuerza bruta de dos partes:
<body>
<script>
var div = document.createElement(''div'');
div.style.position = ''absolute'';
div.style.height = ''auto'';
div.style.width = ''auto'';
div.style.whiteSpace = ''nowrap'';
div.style.fontFamily = ''YOUR_FONT'';
div.style.fontSize = ''100''; // large enough for good resolution
div.style.border = "1px solid blue"; // for visible convenience
var character = "";
var string = "array = [";
for(var i=0; i<127; i++) {
character = String.fromCharCode(i);
div.innerHTML = character;
document.body.appendChild(div);
var offsetWidth = div.offsetWidth;
var clientWidth = div.clientWidth;
console.log("ASCII: " + i + ", " + character + ", client width: " + div.clientWidth);
string = string + div.clientWidth;
if(i<126) {
string = string + ", ";
}
document.body.removeChild(div);
}
var space_string = "! !";
div.innerHTML = space_string;
document.body.appendChild(div);
console.log("space width: " + div.clientWidth - space_string.charCodeAt(0)*2);
document.body.removeChild(div);
string = string + "]";
div.innerHTML = string;
document.body.appendChild(div);
</script>
</body>
Nota: El fragmento de arriba tiene que ejecutarse en Firefox para generar una matriz precisa de valores. Además, debe reemplazar el elemento 32 de matriz con el valor de ancho de espacio en el registro de la consola.
Simplemente copio el texto de Firefox en la pantalla y lo pegué en mi código de JavaScript. Ahora que tengo la matriz de longitudes de caracteres imprimibles, puedo implementar una función de ancho de obtención. Aquí está el código:
const LCARS_CHAR_SIZE_ARRAY = [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, 17, 26, 46, 63, 42, 105, 45, 20, 25, 25, 47, 39, 21, 34, 26, 36, 36, 28, 36, 36, 36, 36, 36, 36, 36, 36, 27, 27, 36, 35, 36, 35, 65, 42, 43, 42, 44, 35, 34, 43, 46, 25, 39, 40, 31, 59, 47, 43, 41, 43, 44, 39, 28, 44, 43, 65, 37, 39, 34, 37, 42, 37, 50, 37, 32, 43, 43, 39, 43, 40, 30, 42, 45, 23, 25, 39, 23, 67, 45, 41, 43, 42, 30, 40, 28, 45, 33, 52, 33, 36, 31, 39, 26, 39, 55];
static getTextWidth3(text, fontSize) {
let width = 0;
let scaleFactor = fontSize/100;
for(let i=0; i<text.length; i++) {
width = width + LCARS_CHAR_SIZE_ARRAY[text.charCodeAt(i)];
}
return width * scaleFactor;
}
Bueno, eso es todo. Fuerza bruta, pero es muy precisa en los tres navegadores, y mi nivel de frustración se ha reducido a cero. No estoy seguro de cuánto tiempo durará a medida que evolucionen los navegadores, pero debería ser lo suficientemente largo como para que desarrolle una técnica robusta de métricas de fuentes para mi texto SVG.
document.getElementById(''yourTextId'').getComputedTextLength();
trabajado para mí en
var bbox = textElement.getBBox();
var width = bbox.width;
var height = bbox.height;
y luego establece los atributos del rect en consecuencia.
Enlace: getBBox()
en el estándar SVG v1.1.