Created
December 24, 2011 09:14
-
-
Save heygrady/1516965 to your computer and use it in GitHub Desktop.
Length Unit Conversion in JavaScript (http://heygrady.com/blog/2011/12/21/length-and-angle-unit-conversion-in-javascript/)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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