jQuery textfill (v18)

Revision 18 of this benchmark created on


Preparation HTML

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<div class="textfill" style="width:100px; height:50px; font-size: 10px;">
  <span>
    My Text Here
  </span>
</div>

Setup

// by GeekyMonkey
  $.fn.textfill1 = function(options) {
    var fontSize = options.maxFontPixels;
    var ourText = $('span:visible:first', this);
    var maxHeight = $(this).height();
    var maxWidth = $(this).width();
    var textHeight;
    var textWidth;
    do {
      ourText.css('font-size', fontSize);
      textHeight = ourText.height();
      textWidth = ourText.width();
      fontSize = fontSize - 1;
    } while ((textHeight > maxHeight || textWidth > maxWidth) && fontSize > 3);
    return this;
  }
  
  // by Alexander Sandstorm
  $.fn.textfill2 = function(options) {
  
      options = jQuery.extend({
          maxFontSize: null,
          minFontSize: 8,
          step: 1
      }, options);
  
      return this.each(function() {
  
          var innerElements = $(this).children(':visible'),
              fontSize = options.maxFontSize || innerElements.css("font-size"), // use current font-size by default
              maxHeight = $(this).height(),
              maxWidth = $(this).width(),
              innerHeight,
              innerWidth;
  
          do {
  
              innerElements.css('font-size', fontSize);
  
              // use the combined height of all children, eg. multiple <p> elements.
              innerHeight = $.map(innerElements, function(e) {
                  return $(e).outerHeight();
              }).reduce(function(p, c) {
                  return p + c;
              }, 0);
  
              innerWidth = innerElements.outerWidth(); // assumes that all inner elements have the same width
              fontSize = fontSize - options.step;
  
          } while ((innerHeight > maxHeight || innerWidth > maxWidth) && fontSize > options.minFontSize);
  
      });
  
  };
  
  // by mekwall
  $.fn.textfill3 = function(maxFontSize) {
    maxFontSize = parseInt(maxFontSize, 10);
    return this.each(function() {
      var ourText = $("span", this),
          parent = ourText.parent(),
          maxHeight = parent.height(),
          maxWidth = parent.width(),
          fontSize = parseInt(ourText.css("fontSize"), 10),
          multiplier = maxWidth / ourText.width(),
          newSize = (fontSize * (multiplier - 0.1));
      ourText.css("fontSize", (maxFontSize > 0 && newSize > maxFontSize) ? maxFontSize : newSize);
    });
  }
  
  $.fn.textfill4 = function(options) {
      var defaults = {
        debug: false,
        maxFontPixels: 40,
        minFontPixels: 4,
        innerTag: 'span',
        widthOnly: false,
        success: null,          // callback when a resizing is done
        callback: null,         // callback when a resizing is done (deprecated, use success)
        fail: null,             // callback when a resizing is failed
        complete: null,         // callback when all is done
        explicitWidth: null,
        explicitHeight: null
      };
      var Opts = $.extend(defaults, options);
  
      function _debug() {
        if (!Opts.debug
        ||  typeof console == 'undefined'
        ||  typeof console.debug == 'undefined') {
          return;
        }
  
        console.debug.apply(console, arguments);
      }
  
      function _warn() {
        if (typeof console == 'undefined'
        ||  typeof console.warn == 'undefined') {
          return;
        }
  
        console.warn.apply(console, arguments);
      }
  
      function _debug_sizing(prefix, ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
        function _m(v1, v2) {
          var marker = ' / ';
          if (v1 > v2) {
            marker = ' > ';
          } else if (v1 == v2) {
            marker = ' = ';
          }
          return marker;
        }
  
        _debug(
          prefix +
          'font: ' + ourText.css('font-size') +
          ', H: ' + ourText.height() + _m(ourText.height(), maxHeight) + maxHeight +
          ', W: ' + ourText.width()  + _m(ourText.width() , maxWidth)  + maxWidth +
          ', minFontPixels: ' + minFontPixels +
          ', maxFontPixels: ' + maxFontPixels
        );
      }
  
      function _sizing(prefix, ourText, func, max, maxHeight, maxWidth, minFontPixels, maxFontPixels) {
        _debug_sizing(prefix + ': ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
        while (minFontPixels < maxFontPixels - 1) {
          var fontSize = Math.floor((minFontPixels + maxFontPixels) / 2)
          ourText.css('font-size', fontSize);
          if (func.call(ourText) <= max) {
            minFontPixels = fontSize;
            if (func.call(ourText) == max) {
              break;
            }
          } else {
            maxFontPixels = fontSize;
          }
          _debug_sizing(prefix + ': ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
        }
        ourText.css('font-size', maxFontPixels);
        if (func.call(ourText) <= max) {
          minFontPixels = maxFontPixels;
          _debug_sizing(prefix + '* ', ourText, maxHeight, maxWidth, minFontPixels, maxFontPixels);
        }
        return minFontPixels;
      }
  
      this.each(function() {
        var ourText = $(Opts.innerTag + ':visible:first', this);
        // Use explicit dimensions when specified
        var maxHeight = Opts.explicitHeight || $(this).height();
        var maxWidth = Opts.explicitWidth || $(this).width();
        var oldFontSize = ourText.css('font-size');
        var fontSize;
  
        _debug('Opts: ', Opts);
        _debug('Vars:' +
          ' maxHeight: ' + maxHeight +
          ', maxWidth: ' + maxWidth
        );
  
        var minFontPixels = Opts.minFontPixels;
        var maxFontPixels = Opts.maxFontPixels <= 0 ? maxHeight : Opts.maxFontPixels;
        var HfontSize = undefined;
        if (!Opts.widthOnly) {
          HfontSize = _sizing('H', ourText, $.fn.height, maxHeight, maxHeight, maxWidth, minFontPixels, maxFontPixels);
        }
        var WfontSize = _sizing('W', ourText, $.fn.width, maxWidth, maxHeight, maxWidth, minFontPixels, maxFontPixels);
  
        if (Opts.widthOnly) {
          ourText.css('font-size', WfontSize);
        } else {
          ourText.css('font-size', Math.min(HfontSize, WfontSize));
        }
        _debug('Final: ' + ourText.css('font-size'));
  
        if (ourText.width()  > maxWidth 
        || (ourText.height() > maxHeight && !Opts.widthOnly)
        ) {
          ourText.css('font-size', oldFontSize);
          if (Opts.fail) {
            Opts.fail(this);
          }
        } else if (Opts.success) {
          Opts.success(this);
        } else if (Opts.callback) {
          _warn('callback is deprecated, use success, instead');
          // call callback on each result
          Opts.callback(this);
        }
      });
  
      // call complete when all is complete
      if (Opts.complete) Opts.complete(this);
  
      return this;
    };
  
  var ourText = $(".textfill");

Teardown



            // reset the size so we can calculate again
  ourText.find("span").css("fontSize", "");
        
  

Test runner

Ready to run.

Testing in
TestOps/sec
textfill by GeekyMonkey
ourText.textfill1({
  maxFontPixels: 36
});
ready
textfill by Alexander Sandstorm
ourText.textfill2({
  maxFontSize: 36
});
ready
textfill by mekwall
ourText.textfill3(36);
ready
// by Russ Painter
ourText.textfill4({
  maxFontSize: 36
});
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.