Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

203
Vistas
Anchura precisa de un carácter monoespaciado

Estoy trabajando en un editor de código con resaltado de sintaxis y necesito saber el ancho exacto de un carácter monoespaciado. Utilizo este valor para calcular la posición de un carácter en una línea, que necesito saber para poder colocar varios elementos de la GUI, como cursores de texto (puede haber varios), rectángulos de selección, información sobre herramientas de advertencia, etc. Hasta ahora He estado usando la siguiente función:

 function getCharacterWidth(char, fontFamily, fontSize) { let span = document.createElement("span"); span.style.fontFamily = fontFamily; span.style.fontSize = fontSize; span.style.position = "absolute"; span.style.visibility = "hidden"; span.style.width = "auto"; span.style.whiteSpace = "nowrap"; span.style.padding = "0"; span.style.margin = "0"; span.style.letterSpacing = "0px"; span.style.wordSpacing = "0px"; span.innerText = char; document.body.appendChild(span); let width = span.getBoundingClientRect().width; span.remove(); return width; }

Ha estado funcionando muy bien, pero luego noté un problema en Google Chrome. Cuando mi editor de texto representa una línea grande, con miles de caracteres, la posición del carácter no se calcula correctamente debido a problemas de redondeo. Parece que en Google Chrome, el width devuelto por getBoundingClientRect() tiene una precisión de 5 decimales como máximo, lo que no es ideal para mi caso de uso. En Firefox, la precisión parece ser mucho mayor, llegando a 15 decimales, por lo que nunca tuve este problema allí.

Después de investigar un poco, escuché sobre esta idea de calcular el ancho de un carácter en función del ancho de un lapso que contiene miles de ese carácter ( https://stackoverflow.com/a/56379770/2197150 ). Entonces, en mi función original, reemplacé span.innerText = char con span.innerText = char.repeat(10000) y devolví width / 10000 . Ayudó, pero el cálculo sigue siendo perceptiblemente incorrecto cuando trato con líneas grandes.

Así que aquí estoy. ¿Cómo puedo calcular el ancho de un carácter con alta precisión, como lo hace Firefox, en otros navegadores?

about 4 years ago · Juan Pablo Isaza
2 Respuestas
Responde la pregunta

0

Esta no es una solución limpia, pero sospecho que no hay una solución realmente limpia.

Puede mantener un "mapa de columnas", basado en el formato de sintaxis <span> s que ya tiene volando. Digamos que tu resaltador te da:

 <div class="line"> var long_line_of_variables = <span class="number">123</span>; </div>

podría medir el desplazamiento izquierdo de este lapso + la columna en la que aparece (= longitud del contenido de texto de los hermanos anteriores = 29) y llegar a

 colums = { '29': 290.456 }

Ahora puede interpolar que la columna 14 tiene 290.456*14/29=140.22 píxeles.
Cuantos más intervalos agreguemos, mejor podremos adivinar:

 colums = { '29': 290.456, '2900': 28997.000 // whoops, not what we would have calculated! }

Este método es heurístico, por lo que deberá encontrar una estrategia que funcione en todos los navegadores, ajustes de zoom/escala de fuente, etc., incluidos

  • agregando más y más tramos a este "mapa"
  • pero tal vez "limpiándolo" de vez en cuando?
  • mantener un mapa global o uno por línea ?
  • sea inteligente con la interpolación: elija la entrada de mapa más cercana (en el mejor intervalo entre entradas)
  • agregar más "sondas de alcance"
    • dividir líneas largas sin ningún formato en fragmentos de N caracteres, envolviéndolos en intervalos o insertando intervalos vacíos en el medio
    • ¿tal vez solo un tramo de sonda justo al final de cada línea?

Habiendo trabajado en problemas y heurísticas similares, mi consejo sería: no lo hagas. :)
Implica muchos ajustes y pruebas, y probablemente sea una pesadilla multiplataforma (por ejemplo, compare la representación y el redondeo de fuentes en Firefox en Win vs Linux vs MacOS vs iOS). En su lugar, intente adjuntar cualquier cosa a un tramo localizado. Entiendo que esto probablemente sea mucho más difícil: muchos editores de texto luchan con líneas largas, especialmente. cuando se trata de JS compilado de tamaño MB ...

about 4 years ago · Juan Pablo Isaza Denunciar

0

Se me ocurrió una solución que ha funcionado bien para mi caso de uso . La idea es calcular el ancho de un carácter en función de la línea más grande de mi editor. Mis elementos de línea se ven así:

 <div class="line"><span class="keyword">let</span><span class="space"> </span><span class="identifier">foo</span></div>

Si queremos calcular el ancho de un carácter basado en esa línea, esto es lo que hacemos:

 let lineElement = document.querySelector(".line"); let lineWidth = lineElement.getBoundingClientRect().width; let charWidth = lineWidth / lineElement.textContent.length;

Hago un seguimiento de la línea más grande que he renderizado en mi editor. Cada vez que represento una nueva línea más grande, actualizo charWidth en función de esa nueva línea.

Esto me permite calcular la posición de un carácter en cualquier columna dada dentro de una línea haciendo una simple column * charWidth . Ha estado funcionando bastante bien hasta ahora, incluso para líneas con más de 100000 caracteres.

Sin embargo, hay una última cosa que tuve que hacer para manejar líneas aún más grandes. Parece que hay un error en Google Chrome donde, cuando intenta representar una línea con un nodo de texto enorme, por ejemplo, <span>many many characters...</span> , no le dará el ancho correcto del elemento (ver Ancho inexacto de elemento grande en Chrome ). Para superar este problema, cada vez que tengo que representar un texto enorme, lo divido en varios tramos, por ejemplo, <span>many many </span><span>characters...</span> .

Ahora puedo renderizar líneas largas de 500000 caracteres con tamaño de fuente 48 sin problemas. Por encima de eso, las cosas vuelven a ponerse raras, con errores de cálculo y otros comportamientos extraños del navegador. Así que decidí establecer un límite estricto de 500000 caracteres representados en una línea. Todo más allá de los 500000n caracteres está oculto para el usuario.

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda