/****************************************** * UnitConverter: Deal with em/px/% conversions ******************************************/ (function() { /** * Create a new converter instance. heightOrElem is used to establish the base height of a line of text, which allows * us to convert % or em into pixels and vice versa. * * @param {number,HTMLElement} heightOrElm the element we'll be converting props for * @param {string,number} [amt] * @param {string} [units] */ var Converter = $.UnitConverter = function(heightOrElm, amt, units) { this.pxHeight = typeof(heightOrElm) === 'number'? heightOrElm : _pxHeight($(heightOrElm)); if(typeof(amt) === 'undefined') { this.load(0); } else { this.load(amt, units); } }; /** * Create a copy of this Converter instance * @param {jQuery} [$e] an element to use as the base, if not provided, uses existing base * @return {Converter} */ Converter.prototype.clone = function($e) { return new Converter($e||this.pxHeight, this.amt, this.units); }; /** * Replace the current instance's measurement with a new one. Use the same base element. * @param {int|string} amt if this is an integer, units must be provided, otherwise units is ignored * @param {string} [units] px, em, or % */ Converter.prototype.load = function(amt, units) { var t = typeof(amt); if( t === 'string' ) { if( amt.match(/[^0-9.-]/) ) { units = _extractType(amt); amt = _extractVal(amt); } else if( amt === '' ) { amt = 0; } else { amt = parseFloat(amt); } } else if( t !== 'number' ) { throw new Error('not a valid number', amt); } this.amt = amt; this.units = units? units : 'px'; return this; }; /** * Add any measurment (e.g. "50px" or "45%") to the current amount * @param {Converter|string} b * @return {Converter} */ Converter.prototype.add = function(b) { if( !(b instanceof Converter) ) { b = this.clone().load(b); } this.amt += b.convert(this.units); return this; }; /** * @param {string} newType one of: px, %, or em * @return {int} the measurement */ Converter.prototype.convert = function(newType) { return _convVal(this, newType); }; /** @return {int} representing the px equivalent of this measurement */ Converter.prototype.px = function() { return this.convert('px'); }; /** * Return a string representation of the current measurement (e.g. "20%" or "5px") * @return {string} */ Converter.prototype.toString = function() { return ''+this.amt+this.units; }; /** * Static method to convert anything into pixels quickly * @param $e * @param amt * @return {int} * @static */ Converter.px = function($e, amt) {return (new Converter($e, amt)).convert('px'); }; function _pxHeight($e) { var h, $d = $('
 
').appendTo($e); h = $d.height(); $d.remove(); return h; } function _extractVal(v) { return parseFloat(v.replace(/[^0-9.-]/, '')); } function _extractType(v) { return v.replace(/.*(em|px|%)$/, '$1'); } function _convVal(a, newUnits) { var amt = a.amt, px = a.pxHeight; if( amt === 0 ) { return 0; } switch(newUnits) { case 'px': switch(a.units) { case 'px': return amt; case 'em': return _emToPx(px, amt); case '%': return _percentToPx(px, amt); default: throw Error('I don\'t know what type '+a.units+' is'); } case 'em': switch(a.units) { case 'px': return _pxToEm(px, amt); case 'em': return amt; case '%': return _percentToEm(px, amt); default: throw Error('I don\'t know what type '+a.units+' is'); } case '%': switch(a.units) { case 'px': return _pxToPercent(px, amt); case 'em': return _emToPercent(px, amt); case '%': return amt; default: throw Error('I don\'t know what type '+a.units+' is'); } default: throw Error('I don\'t know what type '+a.units+' is'); } } function _pxToEm(h, px) { if( px > 0 ) { return _round(px/h, 3); } return 0; } function _emToPx(h, em) { if( em > 0 ) { return _round(em*h, 3); } return 0; } function _percentToPx(h, perc) { return _round(h*perc/100, 3); } function _percentToEm(ph, perc) { return _pxToEm(ph, ph*perc/100); } function _pxToPercent(h, px) { return _round(px/h*100); } function _emToPercent(h, em) { return _pxToPercent(h, _emToPx(h, em)); } function _round(number, decimals) { if( !decimals ) { decimals = 0; } return Math.round(number * Math.pow(10, decimals)) / Math.pow(10, decimals); } })();