UNPKG

@domoinc/multiline-chart

Version:

MultiLineChart - Domo Widget

137 lines (116 loc) 3.81 kB
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;