class UnitPrefixConverter {
constructor() {
this.unitPrefixDict = {
'f': 10 ** -15,
'p': 10 ** -12,
'n': 10 ** -9,
'µ': 10 ** -6,
'm': 10 ** -3,
'': 10 ** 0,
'K': 10 ** 3,
'M': 10 ** 6,
'G': 10 ** 9,
'T': 10 ** 12,
'P': 10 ** 15
}
this.skipTrailingZeros = false;
this.factor = 1;
}
convert(value, unit, targetUnit, precision) {
let negativeInputValue = value < 0 ? true : false;
let valueAbsolute = Math.abs(value);
var convertedValuePrecisely, unitPrefix;
for (var i = 0; i < Object.keys(this.unitPrefixDict).length; i++) {
unitPrefix = Object.keys(this.unitPrefixDict)[i];
const nextUnitPrefix = Object.keys(this.unitPrefixDict)[i + 1];
const unitPrefixValue = this.unitPrefixDict[unitPrefix];
const nextUnitPrefixValue = this.unitPrefixDict[nextUnitPrefix];
const convertedValue = Number(valueAbsolute / (unitPrefixValue * this.factor));
convertedValuePrecisely = parseFloat(convertedValue.toPrecision(precision));
if ((convertedValuePrecisely < nextUnitPrefixValue / unitPrefixValue) || nextUnitPrefix === undefined)
break
}
const digitsBeforeDecimalPoint = String(convertedValuePrecisely).split('.')[0].length;
const digitsAfterDecimalPoint = precision - digitsBeforeDecimalPoint;
const skipFixedNumber = digitsAfterDecimalPoint <= 0 || this.skipTrailingZeros ? true : false;
const sign = negativeInputValue ? -1 : 1;
const returnNumber = skipFixedNumber ? convertedValuePrecisely : convertedValuePrecisely.toFixed(digitsAfterDecimalPoint);
return `${sign * returnNumber} ${unitPrefix}${targetUnit}`
}
}
class BinaryUnitPrefixConverter extends UnitPrefixConverter {
constructor() {
super();
this.unitPrefixDict = {
'': 10 ** 0,
'k': 10 ** 3,
'M': 10 ** 6,
'G': 10 ** 9,
'T': 10 ** 12,
'P': 10 ** 15
}
this.skipTrailingZeros = true;
}
}
class LengthUnitPrefixConverter extends UnitPrefixConverter {
constructor() {
super();
this.unitPrefixDict = {
'f': 10 ** -15,
'p': 10 ** -12,
'n': 10 ** -9,
'µ': 10 ** -6,
'm': 10 ** -3,
'c': 10 ** -2,
'd': 10 ** -1,
'': 10 ** 0,
'k': 10 ** 3
}
}
}
/**
* Apply unit conversion. At the moment, only the conversion of unit prefixes is supported. There is no conversion of units - with the exception of bits and bytes.
* @memberof vef.utils.template
* @param {String|Number} value input value
* @param {String} unit unit of input value
* @param {String} targetUnit desired output unit. Support of bit to byte conversion and vice versa only
* @param {String|Number} precision number of digits
* @returns {String} converted value and unit
* @example
* ['12346789', 'bit', 'B', '3'] -> 1.54 MB
* [0.123, 'm', 'm', '3'] -> 1.23 dm
* [12346789, 'bit/s', 'bit/s', '3'] -> 12.3 Mbit/s
*/
function applyUnitConversion(value, unit, targetUnit, precision) {
const isInputUnitBit = unit.match(/bit/i) || unit.match(/^b$/) ? true : false;
const isInputUnitByte = unit.match(/byte/i) || unit.match(/^B$/) ? true : false;
const isTargetUnitBit = targetUnit.match(/bit/i) || targetUnit.match(/^b$/) ? true : false;
const isTargetUnitByte = targetUnit.match(/byte/i) || targetUnit.match(/^B$/) ? true : false;
const isBitConversion = isInputUnitBit || isInputUnitByte ? true : false;
const isLengthConversion = unit.match(/^m$/i) ? true : false;
let Converter;
if (isBitConversion)
Converter = new BinaryUnitPrefixConverter();
else if (isLengthConversion)
Converter = new LengthUnitPrefixConverter();
else
Converter = new UnitPrefixConverter();
if (isInputUnitBit && isTargetUnitByte)
Converter.factor = 8;
if (isInputUnitByte && isTargetUnitBit)
Converter.factor = 1 / 8;
return Converter.convert(value, unit, targetUnit, precision)
}
export { applyUnitConversion };