Length Unit Conversion in JavaScript (http://heygrady.com/blog/2011/12/21/length-and-angle-unit-conversion-in-javascript/)
(function(window, document, undefined){ | |
"use strict"; | |
// create a test element | |
var testElem = document.createElement('test'), | |
docElement = document.documentElement, | |
defaultView = document.defaultView, | |
getComputedStyle = defaultView && defaultView.getComputedStyle, | |
computedValueBug, | |
runit = /^(-?[\d+\.\-]+)([a-z]+|%)$/i, | |
convert = {}, | |
conversions = [1/25.4, 1/2.54, 1/72, 1/6], | |
units = ['mm', 'cm', 'pt', 'pc', 'in', 'mozmm'], | |
i = 6; // units.length | |
// add the test element to the dom | |
docElement.appendChild(testElem); | |
// test for the WebKit getComputedStyle bug | |
// @see http://bugs.jquery.com/ticket/10639 | |
if (getComputedStyle) { | |
// add a percentage margin and measure it | |
testElem.style.marginTop = '1%'; | |
computedValueBug = getComputedStyle(testElem).marginTop === '1%'; | |
} | |
// pre-calculate absolute unit conversions | |
while(i--) { | |
convert[units[i] + "toPx"] = conversions[i] ? conversions[i] * convert.inToPx : toPx(testElem, '1' + units[i]); | |
} | |
// remove the test element from the DOM and delete it | |
docElement.removeChild(testElem); | |
testElem = undefined; | |
// convert a value to pixels | |
function toPx(elem, value, prop, force) { | |
// use width as the default property, or specify your own | |
prop = prop || 'width'; | |
var style, | |
inlineValue, | |
ret, | |
unit = (value.match(runit)||[])[2], | |
conversion = unit === 'px' ? 1 : convert[unit + 'toPx'], | |
rem = /r?em/i; | |
if (conversion || rem.test(unit) && !force) { | |
// calculate known conversions immediately | |
// find the correct element for absolute units or rem or fontSize + em or em | |
elem = conversion ? elem : unit === 'rem' ? docElement : prop === 'fontSize' ? elem.parentNode || elem : elem; | |
// use the pre-calculated conversion or fontSize of the element for rem and em | |
conversion = conversion || parseFloat(curCSS(elem, 'fontSize')); | |
// multiply the value by the conversion | |
ret = parseFloat(value) * conversion; | |
} else { | |
// begin "the awesome hack by Dean Edwards" | |
// @see http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 | |
// remember the current style | |
style = elem.style; | |
inlineValue = style[prop]; | |
// set the style on the target element | |
try { | |
style[prop] = value; | |
} catch(e) { | |
// IE 8 and below throw an exception when setting unsupported units | |
return 0; | |
} | |
// read the computed value | |
// if style is nothing we probably set an unsupported unit | |
ret = !style[prop] ? 0 : parseFloat(curCSS(elem, prop)); | |
// reset the style back to what it was or blank it out | |
style[prop] = inlineValue !== undefined ? inlineValue : null; | |
} | |
// return a number | |
return ret; | |
} | |
// return the computed value of a CSS property | |
function curCSS(elem, prop) { | |
var value, | |
pixel, | |
unit, | |
rvpos = /^top|bottom/, | |
outerProp = ["paddingTop", "paddingBottom", "borderTop", "borderBottom"], | |
innerHeight, | |
parent, | |
i = 4; // outerProp.length | |
if (getComputedStyle) { | |
// FireFox, Chrome/Safari, Opera and IE9+ | |
value = getComputedStyle(elem)[prop]; | |
} else if (pixel = elem.style['pixel' + prop.charAt(0).toUpperCase() + prop.slice(1)]) { | |
// IE and Opera support pixel shortcuts for top, bottom, left, right, height, width | |
// WebKit supports pixel shortcuts only when an absolute unit is used | |
value = pixel + 'px'; | |
} else if (prop === 'fontSize') { | |
// correct IE issues with font-size | |
// @see http://bugs.jquery.com/ticket/760 | |
value = toPx(elem, '1em', 'left', 1) + 'px'; | |
} else { | |
// IE 8 and below return the specified style | |
value = elem.currentStyle[prop]; | |
} | |
// check the unit | |
unit = (value.match(runit)||[])[2]; | |
if (unit === '%' && computedValueBug) { | |
// WebKit won't convert percentages for top, bottom, left, right, margin and text-indent | |
if (rvpos.test(prop)) { | |
// Top and bottom require measuring the innerHeight of the parent. | |
innerHeight = (parent = elem.parentNode || elem).offsetHeight; | |
while (i--) { | |
innerHeight -= parseFloat(curCSS(parent, outerProp[i])); | |
} | |
value = parseFloat(value) / 100 * innerHeight + 'px'; | |
} else { | |
// This fixes margin, left, right and text-indent | |
// @see https://bugs.webkit.org/show_bug.cgi?id=29084 | |
// @see http://bugs.jquery.com/ticket/10639 | |
value = toPx(elem, value); | |
} | |
} else if ((value === 'auto' || (unit && unit !== 'px')) && getComputedStyle) { | |
// WebKit and Opera will return auto in some cases | |
// Firefox will pass back an unaltered value when it can't be set, like top on a static element | |
value = 0; | |
} else if (unit && unit !== 'px' && !getComputedStyle) { | |
// IE 8 and below won't convert units for us | |
// try to convert using a prop that will return pixels | |
// this will be accurate for everything (except font-size and some percentages) | |
value = toPx(elem, value) + 'px'; | |
} | |
return value; | |
} | |
// expose the conversion function to the window object | |
window.Length = { | |
toPx: toPx | |
}; | |
}(this, this.document)); |
(function(r,a,n){function i(b,j,c,d){var c=c||"width",e;e=(j.match(o)||[])[2];var a="px"===e?1:k[e+"toPx"],g=/r?em/i;if(a||g.test(e)&&!d)b=a?b:"rem"===e?l:"fontSize"===c?b.parentNode||b:b,a=a||parseFloat(m(b,"fontSize")),b=parseFloat(j)*a;else{d=b.style;e=d[c];try{d[c]=j}catch(f){return 0}b=!d[c]?0:parseFloat(m(b,c));d[c]=e!==n?e:null}return b}function m(b,a){var c,d,e=/^top|bottom/,f=["paddingTop","paddingBottom","borderTop","borderBottom"],h=4;c=g?g(b)[a]:(d=b.style["pixel"+a.charAt(0).toUpperCase()+ | |
a.slice(1)])?d+"px":"fontSize"===a?i(b,"1em","left",1)+"px":b.currentStyle[a];d=(c.match(o)||[])[2];if("%"===d&&p)if(e.test(a)){for(e=(d=b.parentNode||b).offsetHeight;h--;)e-=parseFloat(m(d,f[h]));c=parseFloat(c)/100*e+"px"}else c=i(b,c);else("auto"===c||d&&"px"!==d)&&g?c=0:d&&"px"!==d&&!g&&(c=i(b,c)+"px");return c}var f=a.createElement("test"),l=a.documentElement,g=(a=a.defaultView)&&a.getComputedStyle,p,o=/^(-?[\d+\.\-]+)([a-z]+|%)$/i,k={},a=[1/25.4,1/2.54,1/72,1/6],q="mm,cm,pt,pc,in,mozmm".split(","), | |
h=6;l.appendChild(f);if(g)f.style.marginTop="1%",p="1%"===g(f).marginTop;for(;h--;)k[q[h]+"toPx"]=a[h]?a[h]*k.b:i(f,"1"+q[h]);l.removeChild(f);f=n;r.a={c:i}})(this,this.document); |
(function(window, document, undefined){ | |
"use strict"; | |
var testElem, | |
docElement = document.documentElement, | |
defaultView = document.defaultView, | |
getComputedStyle = defaultView && defaultView.getComputedStyle, | |
computedValueBug, | |
runit = /^(-?[\d+\.\-]+)([a-z]+|%)$/i; | |
// test for the WebKit getComputedStyle bug | |
// @see http://bugs.jquery.com/ticket/10639 | |
if (getComputedStyle) { | |
// create a test element | |
testElem = document.createElement('test'); | |
// add the test element to the dom | |
docElement.appendChild(testElem); | |
// add a percentage margin and measure it | |
testElem.style.marginTop = '1%'; | |
computedValueBug = getComputedStyle(testElem).marginTop === '1%'; | |
// remove the test element from the DOM and delete it | |
docElement.removeChild(testElem); | |
testElem = undefined; | |
} | |
// convert a value to pixels | |
function toPx(elem, value, prop) { | |
// use width as the default property, or specify your own | |
prop = prop || 'width'; | |
// begin "the awesome hack by Dean Edwards" | |
// @see http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 | |
// remember the current style | |
var style = elem.style, | |
inlineValue = style[prop], | |
ret; | |
// set the style on the target element | |
try { | |
style[prop] = value; | |
} catch(e) { | |
// IE 8 and below throw an exception when setting unsupported units | |
return 0; | |
} | |
// read the computed value | |
// if style is nothing we probably set an unsupported unit | |
ret = !style[prop] ? 0 : curCSS(elem, prop); | |
// reset the style back to what it was or blank it out | |
style[prop] = inlineValue !== undefined ? inlineValue : null; | |
// remove the unit and return a number | |
return parseFloat(ret); | |
} | |
// return the computed value of a CSS property | |
function curCSS(elem, prop) { | |
var value, | |
pixel, | |
unit, | |
rvpos = /^top|bottom/, | |
outerProp = ["paddingTop", "paddingBottom", "borderTop", "borderBottom"], | |
innerHeight, | |
parent, | |
i = 4; // outerProp.length | |
if (getComputedStyle) { | |
// FireFox, Chrome/Safari, Opera and IE9+ | |
value = getComputedStyle(elem)[prop]; | |
} else if (pixel = elem.style['pixel' + prop.charAt(0).toUpperCase() + prop.slice(1)]) { | |
// IE and Opera support pixel shortcuts for top, bottom, left, right, height, width | |
// WebKit supports pixel shortcuts only when an absolute unit is used | |
value = pixel + 'px'; | |
} else if (prop === 'fontSize') { | |
// correct IE issues with font-size | |
// @see http://bugs.jquery.com/ticket/760 | |
value = toPx(elem, '1em', 'left') + 'px'; | |
} else { | |
// IE 8 and below return the specified style | |
value = elem.currentStyle[prop]; | |
} | |
// check the unit | |
unit = (value.match(runit)||[])[2]; | |
if (unit === '%' && computedValueBug) { | |
// WebKit won't convert percentages for top, bottom, left, right, margin and text-indent | |
if (rvpos.test(prop)) { | |
// Top and bottom require measuring the innerHeight of the parent. | |
innerHeight = (parent = elem.parentNode || elem).offsetHeight; | |
while (i--) { | |
innerHeight -= parseFloat(curCSS(parent, outerProp[i])); | |
} | |
value = parseFloat(value) / 100 * innerHeight + 'px'; | |
} else { | |
// This fixes margin, left, right and text-indent | |
// @see https://bugs.webkit.org/show_bug.cgi?id=29084 | |
// @see http://bugs.jquery.com/ticket/10639 | |
value = toPx(elem, value); | |
} | |
} else if ((value === 'auto' || (unit && unit !== 'px')) && getComputedStyle) { | |
// WebKit and Opera will return auto in some cases | |
// Firefox will pass back an unaltered value when it can't be set, like top on a static element | |
value = 0; | |
} else if (unit && unit !== 'px' && !getComputedStyle) { | |
// IE 8 and below won't convert units for us | |
// try to convert using a prop that will return pixels | |
// this will be accurate for everything (except font-size and some percentages) | |
value = toPx(elem, value) + 'px'; | |
} | |
return value; | |
} | |
// expose the conversion function to the window object | |
window.Length = { | |
toPx: toPx | |
}; | |
}(this, this.document)); |
(function(window, document, undefined){ | |
"use strict"; | |
var runit = /^(-?[\d+\.\-]+)([a-z]+|%)$/i; | |
// convert a value to pixels | |
function toPx(elem, value, prop) { | |
// use width as the default property, or specify your own | |
prop = prop || 'width'; | |
// begin "the awesome hack by Dean Edwards" | |
// @see http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 | |
// remember the current style | |
var style = elem.style, | |
inlineValue = style[prop], | |
ret; | |
// set the style on the target element | |
try { | |
style[prop] = value; | |
} catch(e) { | |
// IE 8 and below throw an exception when setting unsupported units | |
return 0; | |
} | |
// read the computed value | |
// if style is nothing we probably set an unsupported unit | |
ret = !style[prop] ? 0 : currCSS(elem, prop); | |
// reset the style back to what it was or blank it out | |
style[prop] = inlineValue !== undefined ? inlineValue : null; | |
// remove the unit and return a number | |
return parseFloat(ret); | |
} | |
// return the computed value of a CSS property | |
function currCSS(elem, prop) { | |
var value, | |
pixel, | |
getComputedStyle = document.defaultView && document.defaultView.getComputedStyle, | |
unit; | |
if (getComputedStyle) { | |
// FireFox, Chrome/Safari, Opera and IE9+ | |
value = getComputedStyle(elem)[prop]; | |
} else if (pixel = elem.style['pixel' + prop.charAt(0).toUpperCase() + prop.slice(1)]) { | |
// IE and Opera support pixel shortcuts for top, bottom, left, right, height, width | |
// Chrome supports pixel shortcuts for those properties only when an absolute unit is used | |
value = pixel + 'px'; | |
} else { | |
// IE 8 and below won't convert units for us | |
value = elem.currentStyle[prop]; | |
// check the unit | |
unit = (value.match(runit)||[])[2]; | |
if (unit && unit !== 'px') { | |
// try to convert using a prop that will return pixels | |
// this will be accurate for everything (except font-size and some percentages) | |
value = toPx(elem, value) + 'px'; | |
} | |
} | |
return value; | |
} | |
// expose the conversion function to the window object | |
window.Length = { | |
toPx: toPx | |
}; | |
}(this, this.document)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment