@domoinc/multiline-chart
Version:
MultiLineChart - Domo Widget
137 lines (116 loc) • 3.81 kB
JavaScript
class SummaryNumberService {
constructor(config) {
// default for english
var defaultConfig = {
decimal: '.',
thousands: ',',
summary: ['', 'K', 'M', 'B', 'T', 'Q'],
grouping: 3
};
this._config = config || defaultConfig;
}
/**
* Add commas to number in right place
* @param {Number} x the number to add commas to
* @return {String} The number with commas
*/
numberWithCommas(x) {
var parts = x.toString().split(this._config.decimal);
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this._config.thousands);
return parts.join(this._config.decimal);
}
/**
* Create a summary value for any number that you pass in.
* Ex. 999999 -> 999K
* @param {number} val The value you want to summarize.
* @return {string} The summarized value.
*/
summaryNumber (val, numDecimal) {
var result = this.summaryNumberToObject(val, numDecimal);
return result.prefix + result.magnitude;
}
/**
* Create a summary value for any number that you pass in.
* Ex. 999999 -> { prefis: 999, magnitude: K }
* @param {number} val The value you want to summarize.
* @return {object} The prefix and magnitude of val.
*/
summaryNumberToObject(val, numDecimal) {
// If the value is not a number, return the value
if (isNaN(val)) {
return {
prefix: val,
magnitude: ''
};
} else {
val = Number(val);
}
// If the value is negative, convert to positive, create summary,
// and then make negative again
var invert = 1;
if (val < 0) {
val = val * -1;
invert = -1;
}
// Calculate Summary Number
var number = val;
var magnitude = '';
var place;
//Handle really small numbers
val = val < 0.001 ? 0 : val;
//Return decimal if value is a fraction
if (val >= 1) {
place = Math.floor(Math.log(val) / Math.log(Math.pow(10, this._config.grouping)));
number = val / Math.pow(Math.pow(10, this._config.grouping), place);
magnitude = this._config.summary[place] || '';
}
//Invert it here so we don't lose trailing 0's once we convert it to a string
number = number * invert;
//If numDecimal parameter is provided, add that many decimals
//Else use sig figs to determine how many decimals to show
var prefix;
if (numDecimal && numDecimal >= 0) {
prefix = number.toFixed(numDecimal);
} else {
prefix = Number(number.toPrecision(this._config.grouping)).toString();
}
// Check if the rounding has brought the value to the next order of magnitude
// E.g. 999999 should be 1M
if (!numDecimal) {
var numberOfSignificantDigits = (Number(prefix) * invert)
.toString()
.replace(/(?:^|\W)0\.(\w+)(?!\w)/, '')
.replace('.', '')
.length;
if (numberOfSignificantDigits > this._config.grouping) {
prefix = invert * prefix / Math.pow(10, this._config.grouping);
magnitude = this._config.summary[place + 1] || '';
}
}
return {
prefix: this.numberWithCommas(String(prefix)),
magnitude: magnitude
};
}
/**
* Convert a summary number to an approximate number value
* @param {string} val summary number to convert back to string.
* @return {number} val converted to number
*/
reverseSummaryNumber(val) {
var regex = /(\D)$/;
var match = val.toString().match(regex);
var num = parseFloat(val);
if (match) {
var multiplier = this._config.summary.indexOf(match[1]);
if (multiplier > -1) {
num = num * Math.pow(1000, multiplier);
}
}
return isNaN(num) ? 0 : num;
}
}
if (ON_TEST) {
require('./index.spec')(SummaryNumberService);
}
export default SummaryNumberService;