pasaba por aqui
pasaba por aqui

Reputation: 3519

scale div content to fit a fixed size

I have two div's in my page with the following style.

#currentExpr {
  visibility: hidden;
  height: 1px;
  width: 1px;
}

#currentExprFront {
  height: 3.5cm;
  font-size: 500%;
}
<div id="currentExpr">\( \)</div>
<div id="currentExprFront"></div>

As you see, the first one is hidden. On it, some dynamic processes (JavaScript, call of external server, ...) are done until the div content (a long math ml expression) is obtained and updated.It is done on this hidden div to skip a lot of flicks, fast changes, ... until final content is obtained.

When final content is obtained, currentExpr content is copied to the visible div currentExprFront using the JavaScript statement:

currentExprFront.innerHTML = currentExpr.innerHTML;

Problem: I need to scale the content/div currentExprFront to fit the expected size (3.5cm). Sometimes, the content is bigger than this maximum. A possibility could be, by example, adjusting the font-size percentage.

Any hint? Thanks a lot.

Upvotes: 1

Views: 1132

Answers (2)

pasaba por aqui
pasaba por aqui

Reputation: 3519

Based on @Doug answer, the implemented solution has been replace the statement:

currentExprFront.innerHTML = currentExpr.innerHTML;

with the statements:

const k = 1.25;
const lk = Math.log(k);

function scaleAndCopy( d, o ) {
  /* width and height ratios */
  var h = d.offsetHeight/o.offsetHeight; 
  var v = d.offsetWidth/o.offsetWidth; 

  /* adjust to 1.25^n */ 
  h = Math.pow(1.25,Math.floor(Math.log(h)/lk)); 
  v = Math.pow(1.25,Math.floor(Math.log(v)/lk));

  /* set font size ratio and copy */
  var r = 100*Math.min(h,v); 
  d.style.fontSize = `${r}%`; 
  d.innerHTML = o.innerHTML
}

scale( currentExprFront, currentExpr );

this solution allows a single-step adjustment and keeps the fontSize stable to minor changes in the content, because the possible font size values are not continuous but 100%*1.25^n: ..., 80%, 100%, 125%, 156%, ... .

Upvotes: 0

Doug
Doug

Reputation: 1515

This is a demo of what I tried to explain in the comments -- JavaScript can move very quick, so quick that the user's eye will not notice changes (or the browser may not bother to completely render). So, using this speed advantage...

  • Wrap the content into a container (in this case, a span).
  • Populate the target div with the content that you're outputting.
  • Measure the height of the span vs. the height of the div
  • Increment the font-size based on whether the content is too large or too small.

const target = document.getElementById('target');

const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus ornare orci non tristique facilisis. Sed erat eros, dapibus sed arcu lobortis, consequat mollis odio. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Etiam efficitur metus enim, placerat varius felis fringilla vitae. Sed consectetur massa nec nulla ullamcorper tincidunt. Morbi eu orci hendrerit, egestas mi ac, consequat odio. Aenean id erat vitae sem mollis convallis quis in quam. Donec varius tempus ligula, in vulputate nisl pretium vel. Nullam ac arcu finibus, aliquam erat quis, lacinia metus. Aenean convallis magna et lectus mollis, eget scelerisque turpis dapibus. Donec sit amet erat mi. Sed tempus, tortor vel vehicula feugiat, elit purus fringilla tellus, eget molestie ex libero interdum mauris. Nam vehicula a justo et viverra. Aenean eget fringilla erat, id blandit sapien.';
const longTextBtn = document.getElementById('longText');
longTextBtn.addEventListener('click', ()=>{ addText( longText ); } );

const shortText = 'Lorem ipsum dolor.';
const shortTextBtn = document.getElementById('shortText');
shortTextBtn.addEventListener('click', ()=>{ addText( shortText ); } );

// addText() :: Responsible for creating the span element and 
//              assigning the text to the target div/container
function addText( phrase ){
  target.innerHTML = '';
  
  let targetSpan = document.createElement('span');
      targetSpan.id = 'tempID';
  let data = document.createTextNode( phrase );
  targetSpan.appendChild( data );
  target.appendChild( targetSpan );
  
  resizeText( targetSpan, target );
}

// resizeText() :: A recurssive function that will measure the size
//                 of the content vs. the size of the container and
//                 adjust the font-size accordingly.
// Needed improvements:
//  - Create a stop condition (to prevent an infinite loop)
//  - Create a condition to stop if/when the counter hits zero (0)
function resizeText( span, div ){

  let fontSizeTxt = span.style.fontSize || '10px';
      span.style.fontSize = fontSizeTxt;
  let fontSizeNum = parseInt( fontSizeTxt );

  // IF the text is SMALLER than the containing DIV

  if( div.offsetHeight > span.offsetHeight ){
    span.style.fontSize = `${fontSizeNum + 1}px`;
    // if the text is still too small, rerun
    if( div.offsetHeight > span.offsetHeight ){
      resizeText( span, div );
    }
  }
  
  // IF the text is LARGER than the containing DIV
  
  if( span.offsetHeight > div.offsetHeight ){
    span.style.fontSize = `${fontSizeNum - 1}px`;
    // if the text is still too large, rerun
    if( div.offsetHeight < span.offsetHeight ){
      resizeText( span, div );
    }
  }
  
}
#target{
  width: 200px;
  height: 200px;
  overflow: hidden;
  font-family: Arial;
  border: solid 1px black;
}
  #target span{ display: block; }
<div id="target"></div>
<br />
<button id="longText">Add Long Text</button>
<br />
<button id="shortText">Add Short Text</button>

Upvotes: 3

Related Questions