Skip to content

Instantly share code, notes, and snippets.

@imbcmdth
Last active August 29, 2015 13:56
Show Gist options
  • Save imbcmdth/8895128 to your computer and use it in GitHub Desktop.
Save imbcmdth/8895128 to your computer and use it in GitHub Desktop.
resize text inside of a block level element to be as large as possible while still fitting completely inside another div without overflow
(function (root, factory) {
if (typeof exports === 'object') {
module.exports = factory(require('masala'));
} else if (typeof define === 'function' && define.amd) {
define(['masala'], factory);
} else {
root.fitText = factory(root.masala);
}
}(this, function (masala) {
var rectEnum = {
'tooLarge': 1,
'tooSmall': 2,
'justRight': 3
};
function compareRectangles (config) {
var outerRect = config.parent.getBoundingClientRect(),
outerHeight = outerRect.height,
outerWidth = outerRect.width;
var innerRect = config.wrapper.getBoundingClientRect(),
innerHeight = innerRect.height,
innerWidth = innerRect.width;
if (innerHeight > outerHeight || innerWidth > outerWidth) {
return rectEnum.tooLarge;
} else if (innerHeight < outerHeight || innerWidth < outerWidth) {
return rectEnum.tooSmall;
} else {
return rectEnum.justRight;
}
}
function roundedAverage(a, b, scale) {
return Math.round(scale * (a + b) / 2) / scale;
}
// Perform binary search for the best font-size
function findBestFontSize (config, bestSize) {
var midSize = roundedAverage(config.minSize, config.maxSize, config.scale),
limitReached = config.minSize >= midSize || midSize >= config.maxSize;
config.wrapper.style.fontSize = midSize + config.units;
var rectSize = compareRectangles(config);
if (rectSize === rectEnum.tooLarge) {
if (limitReached) {
return bestSize;
} else {
config.maxSize = midSize;
return findBestFontSize(config, bestSize);
}
} else if (rectSize === rectEnum.tooSmall) {
if (limitReached) {
return Math.max(midSize, bestSize);
} else {
config.minSize = midSize;
return findBestFontSize(config, midSize);
}
} else {
return midSize;
}
}
function getWrapper (element) {
// if it exists, just get it and return it
var wrap = element.querySelector('.fit-text-wrapper');
if (wrap) {
return wrap;
}
// otherwise we have to create it
wrap = document.createElement('div');
wrap.className = 'fit-text-wrapper';
while (element.childNodes.length) {
wrap.appendChild(element.childNodes[0]);
}
element.appendChild(wrap);
return wrap;
}
function parseNumber(num, defaultNum) {
var parsedNum = parseFloat(num);
return isNaN(parsedNum)
? defaultNum
: parsedNum;
}
function fitTextBase (options) {
var config = {};
if (options.fillParent) {
config.parent = options.element.parentNode;
config.wrapper = options.element;
} else {
config.parent = options.element;
config.wrapper = getWrapper(parent);
}
config.scale = Math.pow(10, parseNumber(options.precision, 0));
config.units = options.units || 'px';
config.minSize = parseNumber(options.minimumSize, 0);
config.maxSize = parseNumber(options.maximumSize, 100);
var bestSize = findBestFontSize(Object.create(config), config.minSize);
config.wrapper.style.fontSize = bestSize + options.units;
}
// Set some defaults for the options-object and make `element` required and return the final function
return masala(fitTextBase, {
element: null,
minimumSize: 0,
maximumSize: 100,
precision: 2,
units: "px",
fillParent: false
});
}));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment