UNPKG

fitter-js

Version:

Simple text fitting, supports shadow DOM

106 lines (93 loc) 3.95 kB
class Fitter { constructor(options) { this.options = Object.assign(this.defaultOptions, options); this.fit(); } get defaultOptions() { return { element: '[data-fitter]', min: 12, max: 64, multiline: false, } } fit() { let elements; if (this.options.shadowRoot) { elements = typeof this.options.element === 'string' ? this.options.shadowRoot.querySelectorAll(this.options.element) : this.options.element; } else { elements = typeof this.options.element === 'string' ? window.document.querySelectorAll(this.options.element) : this.options.element; } for (const el of elements) { delete el.fitter_set; let style = window.getComputedStyle(el, null); let fontSize = style.getPropertyValue('font-size'); let fontWeight = style.getPropertyValue('font-weight'); let fontFamily = style.getPropertyValue('font-family'); let textSize = this.getTextWidth(el.innerText, `${fontWeight} ${fontSize} ${fontFamily}`); el.style.overflow = 'hidden'; el.style['text-overflow'] = 'ellipsis'; el.style['white-space'] = this.options.multiline ? 'normal' : 'nowrap'; let elSize = el.clientWidth; let canGrow = window.getComputedStyle(el.parentNode, null).getPropertyValue('max-width'); elSize = canGrow && canGrow !== 'none' ? parseFloat(this.getMaxGrowth(canGrow, elSize, el)) : elSize; if (textSize < elSize) { for (let c = parseFloat(fontSize); c < this.options.max; c++) { let r = this.getTextWidth(el.innerText, `${fontWeight} ${c}px ${fontFamily}`); if (r > elSize) { el.style.fontSize = `${c - 1 > this.options.max ? this.options.max : c - 1}px`; el.fitter_set = true; this.listener(el); break; } } if (!el.fitter_set) { el.style.fontSize = `${this.options.max}px`; this.listener(el); } } else { for (let c = this.options.min; c < parseFloat(fontSize); c++) { let r = this.getTextWidth(el.innerText, `${fontWeight} ${c}px ${fontFamily}`); if (r > elSize) { el.style.fontSize = `${c - 1 < this.options.min ? this.options.min : c - 1}px`; el.fitter_set = true; this.listener(el); break; } } if (!el.fitter_set) { el.style.fontSize = `${this.options.min}px`; this.listener(el); } } } } getTextWidth(text, font) { let canvas = this.canvas || (this.canvas = document.createElement('canvas')); let context = canvas.getContext('2d'); context.font = font; return context.measureText(text).width; } getMaxGrowth(canGrow, size, el) { if(canGrow.split('%').length > 1) { let percentage = canGrow.split('%')[0]; return (el.parentNode.clientWidth * (percentage / 100)); } else { return +(`${canGrow}`.split('px').join('')); } } listener(el) { if (this.options.listener) { try { this.options.listener(el, +(`${el.style.fontSize}`.split('px').join(''))); } catch (err) { } } } set(options) { this.options = Object.assign(this.options, options); } } export default Fitter;