77 lines
2.2 KiB
TypeScript

export type LinearUnit = 'metric' | 'imperial'
const METERS_PER_FOOT = 0.3048
const FEET_PER_METER = 1 / METERS_PER_FOOT
type LinearControlValueOptions = {
minMeters?: number
maxMeters?: number
}
export function metersToLinearUnit(meters: number, unit: LinearUnit): number {
return unit === 'imperial' ? meters * FEET_PER_METER : meters
}
export function linearUnitToMeters(value: number, unit: LinearUnit): number {
return unit === 'imperial' ? value * METERS_PER_FOOT : value
}
export function linearControlValueToMeters(
value: number,
unit: LinearUnit,
options: LinearControlValueOptions = {},
): number {
const meters = linearUnitToMeters(value, unit)
const minMeters = options.minMeters ?? Number.NEGATIVE_INFINITY
const maxMeters = options.maxMeters ?? Number.POSITIVE_INFINITY
return Math.min(Math.max(meters, minMeters), maxMeters)
}
export function getLinearUnitLabel(unit: LinearUnit): string {
return unit === 'imperial' ? 'ft' : 'm'
}
const SQUARE_FEET_PER_SQUARE_METER = FEET_PER_METER * FEET_PER_METER
export function squareMetersToAreaUnit(squareMeters: number, unit: LinearUnit): number {
return unit === 'imperial' ? squareMeters * SQUARE_FEET_PER_SQUARE_METER : squareMeters
}
export function getAreaUnitLabel(unit: LinearUnit): string {
return unit === 'imperial' ? 'ft²' : 'm²'
}
export function formatAreaLabel(
squareMeters: number,
unit: LinearUnit,
fractionDigits = 1,
): string {
return `${squareMetersToAreaUnit(squareMeters, unit).toFixed(fractionDigits)}${getAreaUnitLabel(unit)}`
}
export function formatLinearMeasurement(meters: number, unit: LinearUnit): string {
if (!Number.isFinite(meters)) return '--'
const absoluteMeters = Math.abs(meters)
if (unit === 'imperial') {
const feet = metersToLinearUnit(absoluteMeters, unit)
let wholeFeet = Math.floor(feet)
let inches = Math.round((feet - wholeFeet) * 12)
if (inches === 12) {
wholeFeet += 1
inches = 0
}
const sign = meters < 0 && (wholeFeet !== 0 || inches !== 0) ? '-' : ''
return `${sign}${wholeFeet}'${inches}"`
}
const roundedMeters = Number.parseFloat(absoluteMeters.toFixed(2))
const sign = meters < 0 && roundedMeters !== 0 ? '-' : ''
return `${sign}${roundedMeters}m`
}