- Introduction
- Install
- Basic usage
- Input and conversions
- Formatting
- Working with Tables
- Methods
- Constants
Hi, and welcome to Oliasoft's Unit handling repository! Oliasoft is using this to convert numbers between different units in all of our products. As you probably know we are doing various physics calculation that relies on precise definitions for all input data. We need to know the valid range and precision of a value as well as what unit the given value represent. Before doing calculations we therefor convert all numbers to proper JavaScript numbers in a given known unit used in the calculations. We refer to these values as calculation units. The users of our products are however allowed to input values, either through the GUI or directly using the APIs, in any unit they prefer. We refer to these values as input units. We always store the input value together with its unit unconverted, hence input units is the same as the stored units. Finally, we offer the users to view all graphs and numbers in their preferred units. We refer these values as view units (GUI) or output units (API).
All values with numbers are stored as a string with the following special format;
'number|unit'
Number here is very flexible and all of the following is valid "number" strings:
- 2.13
- -2,13
- 4e-05
- 4E+3
- -120,000.02
- -20 1/2
I.e. it support both . and , as comma/thousands separator, exponents and fractions. Examples of different values can be seen in the units tests. By storing the inputted value without any conversions, we maintain valuable precision where needed and also provide the user with recognizable values. We use base units, as described in for example International System of Units (SI), for conversions. By converting all units to the base first, through intermediate convesions, we are able to keep the amount of conversion permutations to a minimum. The same unit can exists in multiple quantities and we allow custom quantity categories for application flexibility.
npm i @oliasoft/units --save
As mentioned in the introduction this repository is working with numbers and units represented in a special string format. In order to get a string with number and unit use withUnit. Example:
const myValueWithUnit = withUnit(3.14, 'cm'); // '3.14|cm'
It's also possible to convert the number to a different unit before getting the string, by calling unumWithUnit. Given a string with unit you can use getValue and getUnit to get the unit part, or use split to get both as an array.
const myValue = getValue(myValueWithUnit); // '3.14'
const myUnit = getUnit(myValueWithUnit); // 'cm'
const [value, unit] = split(myValueWithUnit); // ['3.14, 'cm']
Never manipulate the strings directly in case we ever change the syntax!
Before doing any calculations with variables stored in our special string format, we need to convert the values from the stored units to the calculation units. Knowing the target unit we will use the convertAndGetValue method for converting and returning the number in the target calculation unit:
const value = convertAndGetValue(number, toUnit, fromUnit);
The first argument is the number with or without unit. The second parameter is the target unit, while the last parameter is an optional from unit that's used as a fallback if the first parameter is given without unit.
Examples:
const value = convertAndGetValue('10|m', 'm'); // 10
value = convertAndGetValue('10|m', 'in'); // 393.7007874015748
value = convertAndGetValue('10', 'in', 'm'); // 393.7007874015748
If you want to convert values without units directly to another unit, you can use the to method. Both pure numbers and string representing numbers are converted.
const convertedValue = to(10, 'm', 'in'); // 393.7007874015748
same as
const convertedValue = to('10', 'm', 'in'); // 393.7007874015748
Quantities are lists of units that represent the same measurement of a given quantity, for example length measured in m, in, ft etc. We have a few different methods for getting the units and quantities. One can use getQuantities to get a list of all the defined quantities or unit categories if you will. Given a quantity there's multiple methods to get units for that quantity. Use getUnitsForQuantity to get a pure list of units, or you can get a list of the objects following the AltUnitWithLabel
interface by calling getAltUnitsListByQuantity which will also return formatted labels for the given unit. For example, m³ for cubic meters. The same labels can also be looked up directly by calling label. To get the base unit for a given quantity one can use the method unitFromQuantity.
getQuantities(); // ['acceleration', 'angleGradient', 'angles', 'areaOther', ...]
getUnitsForQuantity('angle'); // ['deg', 'rad']
unitFromQuantity('force') // 'N'
Since this library is representing numbers and units with strings, we also have the flexibility to work directly with fractions. Use fraction to convert a fraction, given as a string, to the corresponding numeric representation. Similar one can use asFraction to convert a decimal number to a fraction (if it exist). One can also use the method numFraction to convert from fraction to number, which will return the input if the conversion fails unlike fraction
which returns NaN
for failed conversions.
const half = asFraction('0.5') // '1/2';
const numeric = fraction(half) // 0.5;
fraction('13/0') // Infinity;
fraction('Garbage') // NaN;
numFraction('Garbage') // 'Garbage';
Several methods exist for processing GUI inputs and making sure they are valid numbers. Raw inputs from the user can be fed through validateAndClean method, which returns a new valid number-unit string.
validateAndClean('123-', '1234-'); // '1234';
validateAndClean('123|m', '1234'); // '1234|m'
Other similar method is cleanNumStr and toNum which works directly with numbers or numbers given as string. For directly returning the number use cleanNum which is identical to [clenNumStr] except for the return value.
cleanNumStr('1000,000,000.1.1'); // '100000000011'
toNum(',1'); // 0.1
cleanNumStr(',1')); // '0.1';
cleanNum(',1')); // 0.1
For showing a list of all values in different units use altUnitsList which returns a list of the value in all units defined in the given quantity. In order to convert between units with similar precision one can use convertSamePrecision.
altUnitsList('180', 'deg'); // [['180', 'deg', '°'], ['3.14', 'rad', 'rad']]
Given a value-unit string we offer a few methods for query the nature of it. Use isEmptyValueWithUnit to check if the unit is un-initialized (empty) and related use isValueWithUnit to check if a string contains both a value and an "valid" unit. Valid here means an unit known to our repository. Use isNumeric to check if a string represents a valid javascript number.
isEmptyValueWithUnit('10|m'); // false
isEmptyValueWithUnit('|m'); // true
isValueWithUnit('10|m'); // true
isValueWithUnit('10'); // false
isNumeric(1e20); //true
isNumeric('1e20'); //true
isNumeric('e20'); // false
For printing nice numbers in GUI and reports we offer different helpers. As already mentioned, one can get formatted unit labels, for example m³ for cubic meters, by calling label. Calling roundNumberWithLabel gives you a value, rounded to the wanted precision, with unit label. Use round to round just the value. Depending on what value that is stored in the string it can sometimes be hard to know what precision to use for display. The method getNumberOfDigitsToShow will analyse the input and suggest a reasonable precision for you.
const forPrint = roundNumberWithLabel('1000.1284325|kg/m3'); // '1000.13 kg/m³'
const noOfDigits = getNumberOfDigitsToShow(1e9); // 12
const outputValue = round(1e9, noOfDigits); // 0.0000000001
Most of the methods in the library works with single value-unit strings and for tables we encourage you to store the value-unit string directly as keyed objects. Example:
const myTable = [
{ depth: '15|m', anotherDepth: '42|ft', od: '35|in', density: '42|kg/m3' },
{ depth: '16|m', anotherDepth: '43|ft', od: '36|in', density: '43|kg/m3' },
];
That said, we also have support for a special custom table format where the first row specifies the unit and the following rows stores pure numbers without unit.
Example:
const myExcelTable = [
['m', 'ft', 'in', 'kg/m3'],
[15, 42, 35, 42],
[16, 43, 36, 50]
];
This then represent the values 15 m, 42 ft, 35 in, 42 kg/m³, 16 m, 50 in, etc. This format is convenient for storing data imported/exported to i.e. Excel. With data in this shape you can call convertTable to convert all values in the table to different units.
convertTable(['cm', 'ft', 'cm', 'sg'], myExcelTable);
/*
[
['cm', 'ft', 'cm', 'sg'],
[1500, 42, 88.9, 0.042],
[1600, 43, 91.44, 0.05]
]
*/
withUnit(1.123, 'm'); // '1.123|m'
withUnit(-10.314, 'K/100m'); // '-10.314|K/100m'
unumWithUnit(2.2, 'kg/m3', 'sg'); // '2200|kg/m3'
isEmptyValueWithUnit('|m'); // true
isEmptyValueWithUnit(NaN); // false
isEmptyValueWithUnit('m'); // false
isValueWithUnit('m'); // false
isValueWithUnit('5'); // false
isValueWithUnit(5); // false
isValueWithUnit('5|m'); // true
isNumeric(1e20); // true
isNumeric('1e20'); // true
isNumeric(NaN); // false
isNumeric(Infinity); // false
allNumbers([1, 2, 1.2, 5]); // true
allNumbers([1, 2, '1.2', 5]); // false
allNumbers([1, 1, 2, Infinity, 1.2]); // true
Outputs "pretty" number (with thousands separators), taken from this
formatNumber(1.1); // '1.1'
formatNumber(100000.123); // '100,000.123';
formatNumber('100000.123'); // '100,000.123';
charCount('1', '1.1'); // 2;
charCount(1, '1.1'); // 2;
charCount(0, '100000.123'); // 5;
Validates and cleans raw text numeric user input, typically from user input. The previous value is for optionally determining the pre-existing unit. The next text is a raw input string. The return value is reformatted from the next text (removing invalid patterns)
validateAndClean('123', '1234'); // '1234'
validateAndClean('123e15', '123e154'); // '123e154'
validateAndClean('123.|m', '123.'); // '123.|m');
validateAndClean('-2e50|m', '-2e500'); // '-2e50|m'
validateAndClean('2|m', '2e-3'); // '2e-3|m'
Calculates the number of digits to be rounded off, typically for values less than 1 E.g. when trying to format 1e-9 byroundNumber(), the output value will only show '0' if just rounded off with 4 digits fromroundNumber(val) Then it is more useful to calculate the number of digits to be rounded off, and pass this in, i.e.round(val, getNumberOfDigitsToShow(val)) which will return 0.0000000001.
getNumberOfDigitsToShow('1'); // 4
getNumberOfDigitsToShow(0.1); // 4
getNumberOfDigitsToShow(1.1); // 4
getNumberOfDigitsToShow(4.2e-8); // 11
getNumberOfDigitsToShow('100000.123'); // 4
getNumberOfDigitsToShow('100000.123', 3); // 3
getNumberOfDigitsToShow(0); // 4
round(1.11231231); // 1.1123
round('100000.123'); // '100000.123'
round('100000.123', 2); // '100000.12'
round('100000.123|m', 2); // '100000.12|m'
round(null, 2) // null
roundNumberWithLabel('1000.1284325|kg/m3'); // '1000.13 kg/m³'
roundNumberWithLabel('-999.999991|kg/m3', 5); // '-999.99999 kg/m³'
roundNumberWithLabel('-999.999999|kg/m3', 5); // '-1000 kg/m³'
Convert set fraction to decimal value will return either number in decimal format, Infinity if fraction is divided by 0
fraction('1/3'); // 0.333
fraction('1/10'); // 0.1
fraction('13/0'); // Infinity
fraction('13e2b'); // NaN
fraction(null); // NaN
fraction(undefined); // NaN
fraction([1, 2]); // NaN
fraction(''); // NaN
unitFromQuantity('force'); // 'N';
unitFromQuantity('notsupported'); // undefined;
getAltUnitsListByQuantity('angles'); // [{unit: 'deg', label: '°'}, {unit: 'rad', label: 'rad'}];
getAltUnitsListByQuantity('qwe123'); // undefined;
getUnitsForQuantity('force'); // ['tonnes', 'lbf', 'kgf', 'N', 'kN', 'tonneForce', 'klbf']
getUnitsForQuantity('depth'); // ['m', 'ft']
getUnitsForQuantity('acceleration'); // ['ft/s2', 'm/s2'])
getUnitsForQuantity('angles');// ['deg', 'rad']);
getUnitsForQuantity('dls'); // ['deg/10m', 'deg/30m', 'deg/100ft'])
getUnitsForQuantity('shit'); // undefined
toBase('1|m', 'length'); // 1
toBase('1|cm', 'length'); // 0.01
toBase('1|tonnes', 'weight'); // 1000
altUnitsList('10|m', 'length');
/* [['10', 'm', 'm'],
['32.8', 'ft', 'ft'],
['0.01', 'km', 'km'],
['394', 'in', 'in'],
['10000', 'mm', 'mm']]
*/
altUnitsList('180', 'deg');
/*
[['180', 'deg', '°'],
['3.14', 'rad', 'rad']]
*/
const table = [
['m', 'ft', 'in', 'kg/m3'],
[15, 42, 35, 42],
[16, 43, 36, 50]];
convertTable(['cm', 'ft', 'cm', 'sg'], table);
/*
[
['cm', 'ft', 'cm', 'sg'],
[1500, 42, 88.9, 0.042],
[1600, 43, 91.44, 0.05]
]
*/
getQuantities(); // ['acceleration', 'angleGradient', 'angles', 'areaOther', ...]
Find double dot and comma in value and replace it with decimal dot. For example: 123,4 => 123.4 or 123..4 => 123,4
checkAndCleanDecimalComma(123); // 123;
checkAndCleanDecimalComma('36,6'); // '36.6';
checkAndCleanDecimalComma('36..6'); // '36.6';
to(1, 'm', 'ft'); // 1 / 0.3048
to(0, 'C', 'F'); // 32
to(32, 'F', 'C'); // 0
to(50, '%', 'fr'); // 0.5
to(0.125, 'fr', '%'); // 12.5
to(180, 'deg', 'rad').toFixed(4); // '3.1416'
to(1, 'rad', 'deg').toFixed(4); // '57.2958'
to('1,12', 'rad', 'deg').toFixed(4); // '64.1713'
to('1....12', 'rad', 'deg').toFixed(4); // '64.1713'
to('1,,12', 'rad', 'deg').toFixed(4); // '64.1713'
to('1,,.12', 'rad', 'deg').toFixed(4); // '64.1713'
split('-12,2m'); // ['-12.2', 'm'];
split('-12 1/2m'); // ['-12 1/2', 'm'];
getValue('12.2'); // '12.2'
getValue('12.2m'); // '12.2'
getValue('12.2|m'); // '12.2'
getValue('|m'); // '';
getValue('m'); // '';
getUnit('-2|in2'); // 'in2'
getUnit('12.2|m'); // 'm'
getUnit('12.2m'); // 'm';
getUnit('|m'); // 'm';
getUnit('12.2'); // '';
label('m3'); // 'm³'
label('1/bar'); // 'bar⁻¹'
Convert value with unit to another unit Will try to pick fromUnit
from numWithUnit
if it was not provided
convertAndGetValue('1 1/2', 'in', 'in'); // 1.5
convertAndGetValue('1 1/2 in', 'in'); // 1.5
convertAndGetValue('-1 1/2 in', 'in'); // -1.5
convertAndGetValue(2.2, 'notsupported', 'notsupported'); // 2.2
convertAndGetValue(2.2, 'kg/m3', 'sg'); // 2200
convertAndGetValue('2.2', 'kg/m3', 'sg'); // 2200
Convert value with unit to another unit and display it in pretty format. It will preserv the number of digits in the input or alternativly converting to the given number of digits.
convertSamePrecision('1|in', 'cm', 8); // '2.54|cm'
convertSamePrecision('102e-6|in', 'cm'); // '0.000259|cm'
convertSamePrecision(2.54, 'cm', 1); // '3|cm'
convertSamePrecision('10.000|m', 'in'); // '393.7|in'
asFraction(''); // '0'
asFraction('0.1'); // '1/10'
Convert fraction string to number (return input value if conversion fails) For historical reasons, numFraction returns the string value unmodified if it is not able to convert to a number. This is useful where user inputs are filtered through calls to numFraction. For "detecting" when numFraction fails, check if the return value is a string or a number. If it is a string it means number conversion failed. will return string with decimal format of fraction
numFraction(''); // ''
numFraction('1/10'); // 0.1
numFraction(null); // null
Cleaning up and fixing provided number to correct numerical format removing redundant '.' dots, ',' commas, spaces
cleanNumStr('1000,000.1'); // '1000000.1'
cleanNumStr('1000,000,000'); // '1000000000'
cleanNumStr('1/10'); // '1/10'
cleanNumStr('1000,000,000.1.1'); // '100000000011'
cleanNum(1); // 1
cleanNum(',1'); // 0.1
toNum(1); // 1
toNum(',1'); // 0.1
isNonNumerical('123.32asdasds4') // true
isNonNumerical('123.32') // false
LABELS.cm // 'cm'
LABELS.lps // 'L/s'
ALT_UNITS.angles // ['deg', 'rad']
ALT_UNITS.density // ['sg', 'ppg', 'kg/m3', 'lbm/ft3', 'g/cm3', 'lb/ft3']
UNIT_FROM_KEY.length // 'm'
UNIT_FROM_KEY.latitude // '°N'
KNOWN_CONVERSIONS['m|mm'](1) // 1000
DEPRECATED_UNITS['N-m'] // 'Nm'
DEPRECATED_UNITS['ft-lbf'] // 'ftlbf'
UNIT_ALIASES['lbs/ft'] // 'lb/ft'
INTERMEDIATE_CONVERSIONS.mm // 'm'
INTERMEDIATE_CONVERSIONS.t // 'kg'
SPECIAL_NUMBERS_STRING // ['NaN', '-Infinity', 'Infinity']