123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /**
- * textFit v2.3.1
- * Previously known as jQuery.textFit
- * 11/2014 by STRML (strml.github.com)
- * MIT License
- *
- * To use: textFit(document.getElementById('target-div'), options);
- *
- * Will make the *text* content inside a container scale to fit the container
- * The container is required to have a set width and height
- * Uses binary search to fit text with minimal layout calls.
- * Version 2.0 does not use jQuery.
- */
- /*global define:true, document:true, window:true, HTMLElement:true*/
- (function(root, factory) {
- "use strict";
- // UMD shim
- if (typeof define === "function" && define.amd) {
- // AMD
- define([], factory);
- } else if (typeof exports === "object") {
- // Node/CommonJS
- module.exports = factory();
- } else {
- // Browser
- root.textFit = factory();
- }
- }(typeof global === "object" ? global : this, function () {
- "use strict";
- var defaultSettings = {
- alignVert: false, // if true, textFit will align vertically using css tables
- alignHoriz: false, // if true, textFit will set text-align: center
- multiLine: false, // if true, textFit will not set white-space: no-wrap
- detectMultiLine: true, // disable to turn off automatic multi-line sensing
- minFontSize: 6,
- maxFontSize: 80,
- reProcess: true, // if true, textFit will re-process already-fit nodes. Set to 'false' for better performance
- widthOnly: false, // if true, textFit will fit text to element width, regardless of text height
- alignVertWithFlexbox: false, // if true, textFit will use flexbox for vertical alignment
- };
- return function textFit(els, options) {
- if (!options) options = {};
- // Extend options.
- var settings = {};
- for(var key in defaultSettings){
- if(options.hasOwnProperty(key)){
- settings[key] = options[key];
- } else {
- settings[key] = defaultSettings[key];
- }
- }
- // Convert jQuery objects into arrays
- if (typeof els.toArray === "function") {
- els = els.toArray();
- }
- // Support passing a single el
- var elType = Object.prototype.toString.call(els);
- if (elType !== '[object Array]' && elType !== '[object NodeList]' &&
- elType !== '[object HTMLCollection]'){
- els = [els];
- }
- // Process each el we've passed.
- for(var i = 0; i < els.length; i++){
- processItem(els[i], settings);
- }
- };
- /**
- * The meat. Given an el, make the text inside it fit its parent.
- * @param {DOMElement} el Child el.
- * @param {Object} settings Options for fit.
- */
- function processItem(el, settings){
- if (!isElement(el) || (!settings.reProcess && el.getAttribute('textFitted'))) {
- return false;
- }
- // Set textFitted attribute so we know this was processed.
- if(!settings.reProcess){
- el.setAttribute('textFitted', 1);
- }
- var innerSpan, originalHeight, originalHTML, originalWidth;
- var low, mid, high;
- // Get element data.
- originalHTML = el.innerHTML;
- originalWidth = innerWidth(el);
- originalHeight = innerHeight(el);
- // Don't process if we can't find box dimensions
- if (!originalWidth || (!settings.widthOnly && !originalHeight)) {
- if(!settings.widthOnly)
- throw new Error('Set a static height and width on the target element ' + el.outerHTML +
- ' before using textFit!');
- else
- throw new Error('Set a static width on the target element ' + el.outerHTML +
- ' before using textFit!');
- }
- // Add textFitted span inside this container.
- if (originalHTML.indexOf('textFitted') === -1) {
- innerSpan = document.createElement('span');
- innerSpan.className = 'textFitted';
- // Inline block ensure it takes on the size of its contents, even if they are enclosed
- // in other tags like <p>
- innerSpan.style['display'] = 'inline-block';
- innerSpan.innerHTML = originalHTML;
- el.innerHTML = '';
- el.appendChild(innerSpan);
- } else {
- // Reprocessing.
- innerSpan = el.querySelector('span.textFitted');
- // Remove vertical align if we're reprocessing.
- if (hasClass(innerSpan, 'textFitAlignVert')){
- innerSpan.className = innerSpan.className.replace('textFitAlignVert', '');
- innerSpan.style['height'] = '';
- el.className.replace('textFitAlignVertFlex', '');
- }
- }
- // Prepare & set alignment
- if (settings.alignHoriz) {
- el.style['text-align'] = 'center';
- innerSpan.style['text-align'] = 'center';
- }
- // Check if this string is multiple lines
- // Not guaranteed to always work if you use wonky line-heights
- var multiLine = settings.multiLine;
- if (settings.detectMultiLine && !multiLine &&
- innerSpan.scrollHeight >= parseInt(window.getComputedStyle(innerSpan)['font-size'], 10) * 2){
- multiLine = true;
- }
- // If we're not treating this as a multiline string, don't let it wrap.
- if (!multiLine) {
- el.style['white-space'] = 'nowrap';
- }
- low = settings.minFontSize + 1;
- high = settings.maxFontSize + 1;
- // Binary search for best fit
- while (low <= high) {
- mid = parseInt((low + high) / 2, 10);
- innerSpan.style.fontSize = mid + 'px';
- if(innerSpan.scrollWidth <= originalWidth && (settings.widthOnly || innerSpan.scrollHeight <= originalHeight)){
- low = mid + 1;
- } else {
- high = mid - 1;
- }
- }
- // Sub 1 at the very end, this is closer to what we wanted.
- innerSpan.style.fontSize = (mid - 1) + 'px';
- // Our height is finalized. If we are aligning vertically, set that up.
- if (settings.alignVert) {
- addStyleSheet();
- var height = innerSpan.scrollHeight;
- if (window.getComputedStyle(el)['position'] === "static"){
- el.style['position'] = 'relative';
- }
- if (!hasClass(innerSpan, "textFitAlignVert")){
- innerSpan.className = innerSpan.className + " textFitAlignVert";
- }
- innerSpan.style['height'] = height + "px";
- if (settings.alignVertWithFlexbox && !hasClass(el, "textFitAlignVertFlex")) {
- el.className = el.className + " textFitAlignVertFlex";
- }
- }
- }
- // Calculate height without padding.
- function innerHeight(el){
- var style = window.getComputedStyle(el, null);
- return el.clientHeight -
- parseInt(style.getPropertyValue('padding-top'), 10) -
- parseInt(style.getPropertyValue('padding-bottom'), 10);
- }
- // Calculate width without padding.
- function innerWidth(el){
- var style = window.getComputedStyle(el, null);
- return el.clientWidth -
- parseInt(style.getPropertyValue('padding-left'), 10) -
- parseInt(style.getPropertyValue('padding-right'), 10);
- }
- //Returns true if it is a DOM element
- function isElement(o){
- return (
- typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
- o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName==="string"
- );
- }
- function hasClass(element, cls) {
- return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
- }
- // Better than a stylesheet dependency
- function addStyleSheet() {
- if (document.getElementById("textFitStyleSheet")) return;
- var style = [
- ".textFitAlignVert{",
- "position: absolute;",
- "top: 0; right: 0; bottom: 0; left: 0;",
- "margin: auto;",
- "display: flex;",
- "justify-content: center;",
- "flex-direction: column;",
- "}",
- ".textFitAlignVertFlex{",
- "display: flex;",
- "}",
- ".textFitAlignVertFlex .textFitAlignVert{",
- "position: static;",
- "}",].join("");
- var css = document.createElement("style");
- css.type = "text/css";
- css.id = "textFitStyleSheet";
- css.innerHTML = style;
- document.body.appendChild(css);
- }
- }));
|