By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,967 Members | 1,210 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,967 IT Pros & Developers. It's quick & easy.

wrapping text through javascript

P: 55
I'm a bit of a hardcore object scripter heh so I don't use css much, my pages are generally entirely rendered with JS, so I have JS equivalents of lots of CSS style solutions...menus, scrolling, etc.... I'm building a paging system and have run into a bit of a snag, when I'm building the pages themselves, I need to know how much text is actually visible in an element, say the overflow is set to hidden... I have no problems getting the element to wrap the text appropriately, but the only way I've come up with to split the string seems a bit like overkill:

I essentially get the offset size of the element with the text before I resize it, then do a bunch of terribly exciting math to figure what percentage of the string will be outside of the areas I have defined as my "text viewers", round down, and cut the string. All in all this works okay, but it's pretty much the bulkiest part of my rendering system and I figure there is another way to do it. Unfortunately googling "split string based on parent element size" doesn't come up with much;)

any help would be greatly appreciated
Oct 3 '08 #1
Share this Question
Share on Google+
7 Replies

Expert Mod 5K+
P: 5,389
hmmm ... not sure i'm getting you right ... but may be you could just create a new element inside the one where you need the text to be displayed with a relative position, fixed size and hidden scrollbars? so that the text just wraps in this new element?

kind regards

PS: btw. i changed the thread title to better describe the problem
Oct 4 '08 #2

P: 55
the wrapping of the text isn't the problem, it's getting the position in the string (character pos) that I have to split at if the string is overflowing outside the element. I CAN hide the overflow, or make the element bigger...since JS is so flexible I have what essentially breaks down to an "overflow" event that fires if the text block is bigger than the element that I'm viewing the text in.

At the moment I use a system akin to bubble sorting to get the string to fit, but it's the slowest part of the render, and I was hoping to speed it up, after a day and a half of looking however, I it seems that there is no "invisible character" that regex can read when a line is wrapped. Defining the text size doesn't bother me that much, but since the whole page that I'm working on is dynamically sized based on window width, shrinking the text is not a viable solution.

I've also been looking for some standard that defines the widths of characters.....since font size is relative to height, every character in any givin type face must have a standard percentage of the hieght that defines it's width, but I can't find any sort of reference for that either:(

Anyway, I have it working, just kinda slow, and no one has been able to help me, so I guess it's prolly time to move on;)
Oct 4 '08 #3

Expert Mod 5K+
P: 5,389
could you give an example to demonstrate the issue more clearly and to work with?

kind regards
Oct 4 '08 #4

P: 55
sure.... this is only sort of working right now.
this is only kinda working right now, but seeing as you just responded I didn't want to make you wait;)

the argment "o" is an object that looks something like this:

Expand|Select|Wrap|Line Numbers
  1. o={str:'some really long string, multi-line or otherwise',sizes:{height:viewableArea.offsetHeight,width:viewableArea.offsetWidth}}
  5. splitTextBlock=function(o){
  6.     var page=document.createElement('div')
  9.     page.innerHTML='SizeTest'
  10.'1px blue inset'
  11.     document.body.appendChild(page)
  12.     var colHeight=page.offsetHeight
  13.     page.innerHTML=o.str
  14.     document.body.appendChild(page)
  15.     var sizes={height:page.offsetHeight,width:page.offsetWidth}
  16.     var colTotA=Math.round(sizes.height/colHeight)+1
  17.     var colTotB=Math.round(o.sizes.height/colHeight)-1
  18.     var colTot=Math.round(colTotA/colTotB)
  19.     var rows=Math.round(o.str.length/colTot)
  20.     var strVal=rows
  21.     var strObj=new Object()
  22.     var curs=0;
  23.     for(var i=0;i<colTot;i++){
  24.         var strObjI=o.str.substring(curs,(curs+strVal))
  25.         page.innerHTML=strObjI
  26.         document.body.appendChild(page)
  27.         var tmpVal=strVal
  28.         if(page.offsetHeight>o.sizes.offsetHeight){
  29.             var c=(page.offsetHeight-o.sizes.offsetHeight)/colHeight
  30.             for(var j=0;j<c;j++){
  31.                 strObjI=(j==0)?o.str.substring(curs,(curs+strVal)):strObjI
  32.                 page.innerHTML=strObjI
  33.                 document.body.appendChild(page)
  34.                 c=Math.round((page.offsetHeight-o.sizes.height)/colHeight)
  35.                 var strObjI=o.str.substring(curs,(curs+(tmpVal-(c*rows))))
  36.                 tmpVal=strObjI.length
  37.             }
  38.         }else if((o.sizes.height-page.offsetHeight)>colHeight){
  39.             var c=(o.sizes.height-page.offsetHeight)/colHeight;
  40.             for(var j=0;j<c;j++){
  41.                 strObjI=(j==0)?o.str.substring(curs,(curs+strVal)):strObjI
  42.                 page.innerHTML=strObjI
  43.                 document.body.appendChild(page)
  44.                 c=Math.round((o.sizes.height-page.offsetHeight)/colHeight)
  45.                 var strObjI=o.str.substring(curs,(curs+(tmpVal+(c*rows))))
  46.                 tmpVal=strObjI.length
  47.             }
  48.         }        
  49.         //var tester=fixSize(o,page,strVal,curs,colHeight,rows)
  50.         o.str=o.str.substring(tmpVal)
  51.         strObj[i+1]=strObjI
  52.         //alert(strObj[i+1]);
  53.     }
  54.     document.body.removeChild(page);
  55.     GL.test=strObj
  56.     return(strObj);
  58. }

I just woke up about 30 minutes as soon as I figure out how I "fixed" this wrong last night, I'll post the updated version;)
Oct 4 '08 #5

P: 55
I appreciate your willingness to help, even if there isn't an easy solution:p anyway, this is what I'm using right now...same idea...

o requires the same thing....

Expand|Select|Wrap|Line Numbers
  1. o={str:'nice long string here',sizes:{height:viewer.offsetHeight,width:viewer.offsetWidth}}
this function returns an object who's properties are chunks of a string that will fit in the defined element without overflow

Expand|Select|Wrap|Line Numbers
  1. chunkBlock=function(o){
  2.     var page=document.createElement('div')
  5.     page.innerHTML='SizeTest'
  6.'1px blue inset'
  7.     document.body.appendChild(page)
  8.     var colHeight=page.offsetHeight
  9.     page.innerHTML=o.str
  10.     document.body.appendChild(page)
  11.     var sizes={height:page.offsetHeight,width:page.offsetWidth}
  12.     var colTotA=Math.round(sizes.height/colHeight)
  13.     var colTotB=Math.round(o.sizes.height/colHeight)
  14.     var colTot=(colTotA/colTotB)
  15.     var rows=Math.round(o.str.length/colTotA)
  16.     var strVal=rows*colTotB
  17.     var strObj=new Object()
  18.     var curs=0;
  19.     for(var i=0;i<colTot;i++){
  20.             var strObjI=o.str.substring(0,(0+strVal))
  21.             page.innerHTML=strObjI
  22.             document.body.appendChild(page)
  23.             var tmpVal=strVal
  24.             var swtch=(page.offsetHeight>o.sizes.height)?'sub':(((o.sizes.height-page.offsetHeight)/colHeight)<1)?'add':'noFire'
  25.             switch(swtch){
  26.                 case 'add':
  27.                     var fire=true
  28.                     var vals={
  29.                         height:function(){return o.sizes.height},
  30.                         oHeight:function(){return page.offsetHeight},
  31.                         func:function(str){return str.substring(0,(tmpVal+(c*rows)))}
  32.                     }break;
  33.                 case 'sub':
  34.                     var fire=true
  35.                     var vals={
  36.                         height:function(){return page.offsetHeight},
  37.                         oHeight:function(){return o.sizes.height},
  38.                         func:function(str,tmpVal,c,rows){return str.substring(0,(tmpVal-(c*rows)))}
  39.                     }break;
  40.                 case 'noFire': 
  41.                     var fire=false;
  42.                     break;
  43.             }
  44.             //alert(swtch)
  45.             if(fire){
  46.                 var cA=(vals.height()-vals.oHeight())/colHeight
  47.                 c=(((vals.height()-vals.oHeight())/colHeight)<1)?1:Math.round(c)
  48.                 //alert(c);
  49.                 for(var j=0;j<cA;j++){
  50.                     //alert(j+' '+c);
  51.                     page.innerHTML=strObjI
  52.                     document.body.appendChild(page)
  53.                     c=(((vals.height()-vals.oHeight())/colHeight)<1)?1:Math.round(c)
  54.                     //if(c<0){break}
  55.                     strObjI=vals.func(o.str,tmpVal,c,rows)
  56.                     tmpVal=strObjI.length
  57.                     var cntu=(vals.height()>vals.oHeight())?true:false;
  58.                     if(!cntu){break}else{cA++}
  59.                 }
  60.             }
  61.         o.str=o.str.substring(tmpVal)
  62.         strObj[i+1]=strObjI
  63.     }
  64.     document.body.removeChild(page);
  65.     GL.test=strObj
  66.     return(strObj);
  67. }
any thoughts would be greatly appreciated:)
Oct 4 '08 #6

Expert Mod 5K+
P: 5,389
ok, i think now i understand what the requirement is ... you have a fixed size element and you want to insert text into it so that all text appears inside a node with that size? ... does it just split the text without semantics? so 'foobar' may be 'foob' and 'ar' then?

btw. to speed this up you could drop the functions that just return any values in your 'vals'-objects because function-calls are much more expensive then just using a reference. next just a hint: you may use firefox for development and set it to use javascript-strict-mode so that you may see some more warnings in the error-console for example the redeclarations of 'vals' and 'fire' (type in about:config in the address bar and filter for strict -> set the value to true) ...

another idea could be:

insert a div with only one character in it ... get the width of this ... now just loop over the string and push the chars into a chunk unless chunk.length * single_char_width_div >= max_width -> i think this would be just one loop to get all chunks?

since you even check the height - is the font-size dynamic? i mean does the font resize?

kind regards
Oct 5 '08 #7

P: 55
I have a regex that I added last night that keeps the chucker from splitting up words now...

I do use firefox for development, and I use firebug to keep track of strict warnings and execution time. The only reason I'm using functions that return is because with the exception of the "o.size.height' return all the rest of the values change during the loop, and I need to get the new value....if I just set variables I only have the value before the final loop fires.

As far as having multiple loops, so far no matter what the window size or string length, the nested loop only fires a max of 2 times....that's why I round the number according to how many rows SHOULD fit in the element, so having the two loops really hasn't hurt my execution time.

The problem with checking the width of a single character is the the width isn't standard...different characters have different widths based on what the font size is...

yes the font-size is dynamic, I don't use classes in the traditional way though, so I just haven't plugged my inherit style into the start of the function yet...

>>>Thanks for your help, I've posted in three other forums, and two of them told me it couldn't be done....even after I told them it was working, I just needed some help cleaning it up!
Oct 5 '08 #8

Post your reply

Sign in to post your reply or Sign up for a free account.