Encontrar alineaciones

Supongamos que tengo un bloque de texto al azar en una sola línea. Al igual que

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Pero por la razón que sea (ajustes de ancho en el elemento que lo contiene, uso del zoom de texto, etc.), en la pantalla del visor se muestra como dos o más líneas.

Lorem ipsum dolor sit amet,

consectetur adipiscing elit.

o

Lorem ipsum dolor sit

amet, consectetur

adipiscing elit.

¿Hay alguna forma de averiguar a través de javascript dónde ocurren esos cambios de línea?

$('p').text() y $('p').html() return Lorem ipsum dolor sit amet, consectetur adipiscing elit. independientemente de cómo se muestre el texto.

Bueno, si quieres algo que es ridículamente simple y probablemente demasiado inútil para ti (necesitará una gran modificación si tienes algún tipo de HTML dentro del párrafo), eche un vistazo a esto:

 var para = $('p'); para.each(function(){ var current = $(this); var text = current.text(); var words = text.split(' '); current.text(words[0]); var height = current.height(); for(var i = 1; i < words.length; i++){ current.text(current.text() + ' ' + words[i]); if(current.height() > height){ height = current.height(); // (i-1) is the index of the word before the text wraps console.log(words[i-1]); } } }); 

Es tan ridículamente simple que podría funcionar. Lo que hace es dividir el texto por espacios, luego agregar las palabras palabra por palabra, observando cualquier aumento en la altura del elemento, lo que indicaría un ajuste de línea.

Échale un vistazo aquí: http://www.jsfiddle.net/xRPYN/2/

Para un caso de uso como la generación de PDF.

Puede limitar los caracteres por línea; si se produce una división en la palabra del medio, ajuste de manera adecuada.

Para obtener caracteres más precisos por línea, puede usar fonts monoespaciadas y luego determinar el ancho por carácter para cada fuente permitida. Luego, divida el ancho del carácter por el tamaño del ancho permitido de la línea de texto, y tendrá los caracteres permitidos por línea para esa fuente.

Podría usar fonts no monoespaciadas, pero luego deberá medir el ancho de cada letra, ugh. Una forma de automatizar la adivinación de ancho es tener un lapso que no tenga margen o relleno, agregar cada carácter para cada fuente (y tamaño), luego medir el ancho del tramo y usarlo.

He terminado el código:

 /** * jQuery getFontSizeCharObject * @version 1.0.0 * @date September 18, 2010 * @since 1.0.0, September 18, 2010 * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle} * @author Benjamin "balupton" Lupton {@link http://www.balupton.com} * @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com} * @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/ */ $.getFontSizeCharObject = function(fonts,sizes,chars){ var fonts = fonts||['Arial','Times'], sizes = sizes||['12px','14px'], chars = chars||['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','y','x','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','Y','X','Z', '0','1','2','3','4','5','6','7','8','9','-','=', '!','@','#','$','%','^','&','*','(',')','_','+', '[',']','{','}','\\','|', ';',"'",':','"', ',','.','/','< ','>','?',' '], font_size_char = {}, $body = $('body'), $span = $('').appendTo($body); $.each(fonts, function(i,font){ $span.css('font-family', font); font_size_char[font] = font_size_char[font]||{}; $.each(sizes, function(i,size){ $span.css('font-size',size); font_size_char[font][size] = font_size_char[font][size]||{}; $.each(chars,function(i,char){ if ( char === ' ' ) { $span.html(' '); } else { $span.text(char); } var width = $span.width()||0; font_size_char[font][size][char] = width; }); }); }); $span.remove(); return font_size_char; }; /** * jQuery adjustedText Element Function * @version 1.0.0 * @date September 18, 2010 * @since 1.0.0, September 18, 2010 * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle} * @author Benjamin "balupton" Lupton {@link http://www.balupton.com} * @copyright (c) 2010 Benjamin Arthur Lupton {@link http://www.balupton.com} * @license Attribution-ShareAlike 2.5 Generic {@link http://creativecommons.org/licenses/by-sa/2.5/ */ $.fn.adjustedText = function(text,maxLineWidth){ var $this = $(this), font_size_char = $.getFontSizeCharObject(), char_width = font_size_char['Times']['14px'], maxLineWidth = parseInt(maxLineWidth,10), newlinesAt = [], lineWidth = 0, lastSpace = null; text = text.replace(/\s+/g, ' '); $.each(text,function(i,char){ var width = char_width[char]||0; lineWidth += width; if ( /^[\-\s]$/.test(char) ) { lastSpace = i; } //console.log(i,char,lineWidth,width); if ( lineWidth >= maxLineWidth ) { newlinesAt.push(lastSpace||i); lineWidth = width; lastSpace = null; } }); $.each(newlinesAt,function(i,at){ text = text.substring(0,at+i)+"\n"+text.substring(at+i); }); text = text.replace(/\ ?\n\ ?/g, "\n"); console.log(text,newlinesAt); $this.text(text); return $this; }; $(function(){ var $body = $('body'), $textarea = $('#mytext'), $btn = $('#mybtn'), $div = $('#mydiv'); if ( $textarea.length === 0 && $div.length === 0 ) { $body.empty(); $textarea = $('').val('(When spoken repeatedly, often three times in succession: blah blah blah!) Imitative of idle, meaningless talk; used sometimes in a slightly derogatory manner to mock or downplay another\'s words, or to show disinterest in a diatribe, rant, instructions, unsolicited advice, parenting, etc. Also used when recalling and retelling another\'s words, as a substitute for the portions of the speech deemed irrelevant.').appendTo($body); $div = $('
').appendTo($body); $btn = $('').click(function(){ $div.adjustedText($textarea.val(),'300px'); }).appendTo($body); $div.add($textarea).css({ 'width':'300px', 'font-family': 'Times', 'font-size': '14px' }); $div.css({ 'width':'auto', 'white-space':'pre', 'text-align':'left' }); } });

Esto es lo que terminé usando (no dudes en criticar y copiar para tus propios nefastos propósitos).

En primer lugar, cuando la edición llega desde el usuario, se divide con $(editableElement).lineText(userInput) .

 jQuery.fn.lineText = function (userInput) { var a = userInput.replace(/\n/g, " \n
").split(" "); $.each(a, function(i, val) { if(!val.match(/\n/) && val!="") a[i] = '' + val + ''; }); $(this).html(a.join(" ")); };

El reemplazo de nueva línea ocurre porque el cuadro de texto de edición está $(editableElement).text() con $(editableElement).text() , que ignora las tags
, pero igual cambiarán la altura de la siguiente línea en la pantalla para fines de composición tipográfica. Esto no era parte del objective inicial, solo fruta bastante baja.

Cuando necesito extraer texto formateado, llamo $(editableElement).getLines() , donde

 jQuery.fn.getLines = function (){ var count = $(this).children(".word-measure").length; var lineAcc = [$(this).children(".word-measure:eq(0)").text()]; var textAcc = []; for(var i=1; i 

El resultado final es una lista de hashes, cada uno contiene el contenido y el desplazamiento vertical de una sola línea de texto.

 [{"text":"Some dummy set to","top":363}, {"text":"demonstrate...","top":382}, {"text":"The output of this","top":420}, {"text":"wrap-detector.","top":439}] 

Si solo quiero texto sin formato, $(editableElement).text() aún regresa

 "Some dummy set to demonstrate... The output of this wrap-detector." 

Las soluciones anteriores no funcionan una vez que tienes una estructura más compleja como un enlace en un párrafo (por ejemplo, puedes tener dentro de un

).

Así que creé una biblioteca de JavaScript para detectar dónde se ajustan las líneas que funcionan en esos casos: http://github.com/xdamman/js-line-wrap-detector

Espero que esto ayude.

Tengo una situación en la que necesito ajustar cada línea en un lapso. Lo hago para poder agregar un efecto de relleno acolchado a un bloque de texto. Agregar el fondo a una etiqueta span que envuelve el texto solo rellenará el comienzo y el final del bloque de texto, cada línea debe ser envuelta individualmente.

Esto es lo que se me ocurrió basado en las sugerencias anteriores:

 $.fn.highlghtWrap = function () { this.each( function () { var current = $( this ); var text = current.text(); var words = text.split( ' ' ); var line = ''; var lines = []; current.text( words[ 0 ] ); var height = current.height(); line = words[ 0 ]; for ( var i = 1; i < words.length; i++ ) { current.text( current.text() + ' ' + words[ i ] ); if ( current.height() > height ) { lines.push( line ); line = words[ i ]; height = current.height(); } else { line = line + ' ' + words[ i ]; } } lines.push( line ); current.html( '' ); $.each( lines, function ( v, a ) { current.html( current.html() + '' + a + ' ' ); } ); } ); } $( '.home-top_wrapper h2' ).highlghtWrap(); $( '.home-top_wrapper p' ).highlghtWrap(); 

Una forma conceptualmente simple que también funciona cuando hay marcado interno y fonts y estilos arbitrarios, es hacer una primera pasada que simplemente coloca cada palabra en su propio elemento (tal vez ‘SPAN’, o un nombre personalizado como ‘w’).

Luego puede iterar usando getBoundingClientRect () para encontrar dónde cambia la propiedad ‘top’:

 function findBreaks() { var words = document.getElementsByTagName('w'); var lastTop = 0; for (var i=0; i 

Suena lento, pero a menos que los documentos sean realmente grandes, no lo notarás.