Files
CHOMPStation2/tgui/packages/tgui/format.js
2020-08-16 22:27:09 -07:00

117 lines
3.1 KiB
JavaScript

/**
* @file
* @copyright 2020 Aleksej Komarov
* @license MIT
*/
import { clamp, round, toFixed } from 'common/math';
const SI_SYMBOLS = [
'f', // femto
'p', // pico
'n', // nano
'μ', // micro
'm', // milli
// NOTE: This is a space for a reason. When we right align si numbers,
// in monospace mode, we want to units and numbers stay in their respective
// columns. If rendering in HTML mode, this space will collapse into
// a single space anyway.
' ',
'k', // kilo
'M', // mega
'G', // giga
'T', // tera
'P', // peta
'E', // exa
'Z', // zetta
'Y', // yotta
];
const SI_BASE_INDEX = SI_SYMBOLS.indexOf(' ');
/**
* Formats a number to a human readable form, by reducing it to SI units.
* TODO: This is quite a shit code and shit math, needs optimization.
*/
export const formatSiUnit = (
value,
minBase1000 = -SI_BASE_INDEX,
unit = ''
) => {
if (typeof value !== 'number' || !Number.isFinite(value)) {
return value;
}
const realBase10 = Math.floor(Math.log10(value));
const base10 = Math.floor(Math.max(minBase1000 * 3, realBase10));
const realBase1000 = Math.floor(realBase10 / 3);
const base1000 = Math.floor(base10 / 3);
const symbolIndex = clamp(
SI_BASE_INDEX + base1000,
0,
SI_SYMBOLS.length);
const symbol = SI_SYMBOLS[symbolIndex];
const scaledNumber = value / Math.pow(1000, base1000);
const scaledPrecision = realBase1000 > minBase1000
? (2 + base1000 * 3 - base10)
: 0;
// TODO: Make numbers bigger than precision value show
// up to 2 decimal numbers.
const finalString = (
toFixed(scaledNumber, scaledPrecision)
+ ' ' + symbol + unit
);
return finalString.trim();
};
export const formatPower = (value, minBase1000 = 0) => {
return formatSiUnit(value, minBase1000, 'W');
};
export const formatMoney = (value, precision = 0) => {
if (!Number.isFinite(value)) {
return value;
}
// Round the number and make it fixed precision
let fixed = round(value, precision);
if (precision > 0) {
fixed = toFixed(value, precision);
}
fixed = String(fixed);
// Place thousand separators
const length = fixed.length;
let indexOfPoint = fixed.indexOf('.');
if (indexOfPoint === -1) {
indexOfPoint = length;
}
let result = '';
for (let i = 0; i < length; i++) {
if (i > 0 && i < indexOfPoint && (indexOfPoint - i) % 3 === 0) {
// Thin space
result += '\u2009';
}
result += fixed.charAt(i);
}
return result;
};
export const formatCommaNumber = value => {
if (!Number.isFinite(value)) {
return value;
}
// From http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
let parts = value.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
};
// Function from https://stackoverflow.com/a/34841026. CC BY-SA 4.0.
export const formatTime = seconds => {
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor(seconds / 60) % 60;
return [hours, minutes, seconds % 60]
.map(v => v < 10 ? "0" + v : v)
.filter((v, i) => v !== "00" || i > 0)
.join(":");
};