Created
August 19, 2024 17:50
-
-
Save aleclarson/a92f76f7bcd3391f7d19880246164abc to your computer and use it in GitHub Desktop.
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
// Adapted from: https://www.npmjs.com/package/to-px | |
const PIXELS_PER_INCH = measure('in', document.body) // 96 | |
export function toPixels(input: number | string, element: HTMLElement = document.body): number { | |
if (typeof input === 'number') return input | |
input = input.toLowerCase() | |
// Support passing a unit with no amount prefix | |
let px = unitToPixels(input, element) | |
if (px !== undefined) { | |
return px | |
} | |
const [amount, unit] = parseUnit(input) | |
if (!unit) { | |
return amount | |
} | |
px = unitToPixels(unit, element) | |
if (px !== undefined) { | |
return amount * px | |
} | |
return measure(input, element, false) | |
} | |
function unitToPixels(unit: string, element: HTMLElement) { | |
switch (unit) { | |
case '%': //Ambiguous, not sure if we should use width or height | |
return element.clientHeight / 100.0 | |
case 'ch': | |
case 'ex': | |
return measure(unit, element) | |
case 'em': | |
return computeProperty(element, 'font-size') | |
case 'rem': | |
return computeProperty(document.body, 'font-size') | |
case 'vw': | |
return window.innerWidth / 100 | |
case 'vh': | |
return window.innerHeight / 100 | |
case 'vmin': | |
return Math.min(window.innerWidth, window.innerHeight) / 100 | |
case 'vmax': | |
return Math.max(window.innerWidth, window.innerHeight) / 100 | |
case 'in': | |
return PIXELS_PER_INCH | |
case 'cm': | |
return PIXELS_PER_INCH / 2.54 | |
case 'mm': | |
return PIXELS_PER_INCH / 25.4 | |
case 'pt': | |
return PIXELS_PER_INCH / 72 | |
case 'pc': | |
return PIXELS_PER_INCH / 6 | |
case 'px': | |
return 1 | |
} | |
} | |
function parseUnit(str: string) { | |
const unitMatch = str.match(/[\d.\-\+]*(.*)/) | |
return [parseFloat(str), unitMatch ? unitMatch[1] : ''] as const | |
} | |
function computeProperty(element: HTMLElement, prop: string) { | |
const [amount, unit] = parseUnit(getComputedStyle(element).getPropertyValue(prop)) | |
return amount * toPixels(unit, element) | |
} | |
export function measure(length: string, element: HTMLElement, isUnit = true) { | |
const testDIV = document.createElement('div') | |
testDIV.style.height = isUnit ? 128 + length : length | |
element.appendChild(testDIV) | |
let size = computeProperty(testDIV, 'height') | |
if (isUnit) { | |
size /= 128 | |
} | |
element.removeChild(testDIV) | |
return size | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment