UNPKG

ag-charts-community

Version:

Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue

463 lines 18 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ticks_1 = require("./ticks"); function formatDefault(x, p) { const xs = x.toPrecision(p); out: for (var n = xs.length, i = 1, i0 = -1, i1 = 0; i < n; ++i) { switch (xs[i]) { case '.': i0 = i1 = i; break; case '0': if (i0 === 0) i0 = i; i1 = i; break; case 'e': break out; default: if (i0 > 0) i0 = 0; break; } } return i0 > 0 ? xs.slice(0, i0) + xs.slice(i1 + 1) : xs; } const formatTypes = { '': formatDefault, // Multiply by 100, and then decimal notation with a percent sign. '%': (x, p) => (x * 100).toFixed(p), // Binary notation, rounded to integer. 'b': (x) => Math.round(x).toString(2), // Converts the integer to the corresponding unicode character before printing. 'c': (x) => String(x), // Decimal notation, rounded to integer. 'd': formatDecimal, // Exponent notation. 'e': (x, p) => x.toExponential(p), // Fixed point notation. 'f': (x, p) => x.toFixed(p), // Either decimal or exponent notation, rounded to significant digits. 'g': (x, p) => x.toPrecision(p), // Octal notation, rounded to integer. 'o': (x) => Math.round(x).toString(8), // Multiply by 100, round to significant digits, and then decimal notation with a percent sign. 'p': (x, p) => formatRounded(x * 100, p), // Decimal notation, rounded to significant digits. 'r': formatRounded, // Decimal notation with a SI prefix, rounded to significant digits. 's': formatPrefixAuto, // Hexadecimal notation, using upper-case letters, rounded to integer. 'X': (x) => Math.round(x).toString(16).toUpperCase(), // Hexadecimal notation, using lower-case letters, rounded to integer. 'x': (x) => Math.round(x).toString(16) }; const prefixes = ['y', 'z', 'a', 'f', 'p', 'n', '\xB5', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']; /** * [[fill]align][sign][#][0][width][grouping_option][.precision][type] */ class FormatSpecifier { constructor(specifier) { if (specifier instanceof FormatSpecifier) { this.fill = specifier.fill; this.align = specifier.align; this.sign = specifier.sign; this.symbol = specifier.symbol; this.zero = specifier.zero; this.width = specifier.width; this.comma = specifier.comma; this.precision = specifier.precision; this.trim = specifier.trim; this.type = specifier.type; this.string = specifier.string; } else { this.fill = specifier.fill === undefined ? ' ' : String(specifier.fill); this.align = specifier.align === undefined ? '>' : String(specifier.align); this.sign = specifier.sign === undefined ? '-' : String(specifier.sign); this.symbol = specifier.symbol === undefined ? '' : String(specifier.symbol); this.zero = !!specifier.zero; this.width = specifier.width === undefined ? undefined : +specifier.width; this.comma = !!specifier.comma; this.precision = specifier.precision === undefined ? undefined : +specifier.precision; this.trim = !!specifier.trim; this.type = specifier.type === undefined ? '' : String(specifier.type); this.string = specifier.string; } } } exports.FormatSpecifier = FormatSpecifier; // [[fill]align][sign][symbol][0][width][,][.precision][~][type] const formatRegEx = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i; const interpolateRegEx = /(#\{(.*?)\})/g; function makeFormatSpecifier(specifier) { if (specifier instanceof FormatSpecifier) { return new FormatSpecifier(specifier); } let found = false; let string = specifier.replace(interpolateRegEx, function () { if (!found) { specifier = arguments[2]; found = true; } return '#{}'; }); const match = formatRegEx.exec(specifier); if (!match) { throw new Error(`Invalid format: ${specifier}`); } return new FormatSpecifier({ fill: match[1], align: match[2], sign: match[3], symbol: match[4], zero: match[5], width: match[6], comma: match[7], precision: match[8] && match[8].slice(1), trim: match[9], type: match[10], string: found ? string : undefined }); } exports.makeFormatSpecifier = makeFormatSpecifier; function tickFormat(start, stop, count, specifier) { const step = ticks_1.tickStep(start, stop, count); const formatSpecifier = makeFormatSpecifier(specifier == undefined ? ',f' : specifier); let precision; switch (formatSpecifier.type) { case 's': { const value = Math.max(Math.abs(start), Math.abs(stop)); if (formatSpecifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) { formatSpecifier.precision = precision; } return exports.formatPrefix(formatSpecifier, value); } case '': case 'e': case 'g': case 'p': case 'r': { if (formatSpecifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) { formatSpecifier.precision = precision - +(formatSpecifier.type === 'e'); } break; } case 'f': case '%': { if (formatSpecifier.precision == null && !isNaN(precision = precisionFixed(step))) { formatSpecifier.precision = precision - +(formatSpecifier.type === '%') * 2; } break; } } return exports.format(formatSpecifier); } exports.tickFormat = tickFormat; let prefixExponent; function formatPrefixAuto(x, p = 0) { const d = formatDecimalParts(x, p); if (!d) { return String(x); } const coefficient = d[0]; const exponent = d[1]; prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3; const i = exponent - prefixExponent + 1; const n = coefficient.length; if (i === n) { return coefficient; } else { if (i > n) { return coefficient + new Array(i - n + 1).join('0'); } if (i > 0) { return coefficient.slice(0, i) + '.' + coefficient.slice(i); } else { const parts = formatDecimalParts(x, Math.max(0, p + i - 1)); return '0.' + new Array(1 - i).join('0') + parts[0]; // less than 1y! } } } function formatDecimal(x) { return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString('en').replace(/,/g, '') : x.toString(10); } function formatGroup(grouping, thousands) { return (value, width) => { const t = []; let i = value.length; let j = 0; let g = grouping[0]; let length = 0; while (i > 0 && g > 0) { if (length + g + 1 > width) { g = Math.max(1, width - length); } t.push(value.substring(i -= g, i + g)); if ((length += g + 1) > width) { break; } g = grouping[j = (j + 1) % grouping.length]; } return t.reverse().join(thousands); }; } function formatNumerals(numerals) { return value => value.replace(/[0-9]/g, i => numerals[+i]); } exports.formatNumerals = formatNumerals; // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k. function formatTrim(s) { out: for (var n = s.length, i = 1, i0 = -1, i1 = 0; i < n; ++i) { switch (s[i]) { case '.': i0 = i1 = i; break; case '0': if (i0 === 0) i0 = i; i1 = i; break; default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break; } } return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s; } function formatRounded(x, p) { const d = formatDecimalParts(x, p); if (!d) { return String(x); } const coefficient = d[0]; const exponent = d[1]; if (exponent < 0) { return '0.' + new Array(-exponent).join('0') + coefficient; } else { if (coefficient.length > exponent + 1) { return coefficient.slice(0, exponent + 1) + '.' + coefficient.slice(exponent + 1); } else { return coefficient + new Array(exponent - coefficient.length + 2).join('0'); } } } // Computes the decimal coefficient and exponent of the specified number x with // significant digits p, where x is positive and p is in [1, 21] or undefined. // For example, formatDecimalParts(1.23) returns ['123', 0]. function formatDecimalParts(x, p) { const sx = p ? x.toExponential(p - 1) : x.toExponential(); const i = sx.indexOf('e'); if (i < 0) { // NaN, ±Infinity return undefined; } const coefficient = sx.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+ // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3). return [ coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +sx.slice(i + 1) ]; } exports.formatDecimalParts = formatDecimalParts; function identity(x) { return x; } defaultLocale({ thousands: ',', grouping: [3], currency: ['$', ''] }); function defaultLocale(definition) { exports.formatDefaultLocale = formatLocale(definition); exports.format = exports.formatDefaultLocale.format; exports.formatPrefix = exports.formatDefaultLocale.formatPrefix; } function exponent(x) { const parts = formatDecimalParts(Math.abs(x)); if (parts) { return parts[1]; } return NaN; } function precisionFixed(step) { return Math.max(0, -exponent(Math.abs(step))); } function precisionPrefix(step, value) { let x = Math.floor(exponent(value) / 3); x = Math.min(8, x); x = Math.max(-8, x); return Math.max(0, x * 3 - exponent(Math.abs(step))); } function precisionRound(step, max) { step = Math.abs(step); max = Math.abs(max) - step; return Math.max(0, exponent(max) - exponent(step)) + 1; } function formatLocale(locale) { const group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(Array.prototype.map.call(locale.grouping, Number), String(locale.thousands)); const currencyPrefix = locale.currency === undefined ? '' : String(locale.currency[0]); const currencySuffix = locale.currency === undefined ? '' : String(locale.currency[1]); const decimal = locale.decimal === undefined ? '.' : String(locale.decimal); const numerals = locale.numerals === undefined ? identity : formatNumerals(Array.prototype.map.call(locale.numerals, String)); const percent = locale.percent === undefined ? '%' : String(locale.percent); const minus = locale.minus === undefined ? '\u2212' : String(locale.minus); const nan = locale.nan === undefined ? 'NaN' : String(locale.nan); function newFormat(specifier) { const formatSpecifier = makeFormatSpecifier(specifier); let fill = formatSpecifier.fill; let align = formatSpecifier.align; const sign = formatSpecifier.sign; const symbol = formatSpecifier.symbol; let zero = formatSpecifier.zero; const width = formatSpecifier.width; let comma = formatSpecifier.comma; let precision = formatSpecifier.precision; let trim = formatSpecifier.trim; let type = formatSpecifier.type; // The 'n' type is an alias for ',g'. if (type === 'n') { comma = true; type = 'g'; } else if (!formatTypes[type]) { // The '' type, and any invalid type, is an alias for '.12~g'. if (precision === undefined) { precision = 12; } trim = true; type = 'g'; } // If zero fill is specified, padding goes after sign and before digits. if (zero || (fill === '0' && align === '=')) { zero = true; fill = '0'; align = '='; } // Compute the prefix and suffix. // For SI-prefix, the suffix is lazily computed. const prefix = symbol === '$' ? currencyPrefix : symbol === '#' && /[boxX]/.test(type) ? '0' + type.toLowerCase() : ''; const suffix = symbol === '$' ? currencySuffix : /[%p]/.test(type) ? percent : ''; // What format function should we use? // Is this an integer type? // Can this type generate exponential notation? const formatType = formatTypes[type]; const maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified, // or clamp the specified precision to the supported range. // For significant precision, it must be in [1, 21]. // For fixed precision, it must be in [0, 20]. if (precision === undefined) { precision = 6; } else if (/[gprs]/.test(type)) { precision = Math.max(1, Math.min(21, precision)); } else { precision = Math.max(0, Math.min(20, precision)); } function format(x) { let valuePrefix = prefix; let valueSuffix = suffix; let value; if (type === 'c') { valueSuffix = formatType(+x) + valueSuffix; value = ''; } else { const nx = +x; // Determine the sign. -0 is not less than 0, but 1 / -0 is! var valueNegative = x < 0 || 1 / nx < 0; // Perform the initial formatting. value = isNaN(nx) ? nan : formatType(Math.abs(nx), precision); // Trim insignificant zeros. if (trim) { value = formatTrim(value); } // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign. if (valueNegative && +value === 0 && sign !== '+') { valueNegative = false; } // Compute the prefix and suffix. let signPrefix = valueNegative ? (sign === '(' ? sign : minus) : (sign === '-' || sign === '(' ? '' : sign); let signSuffix = valueNegative && sign === '(' ? ')' : ''; valuePrefix = signPrefix + valuePrefix; valueSuffix = (type === 's' ? prefixes[8 + prefixExponent / 3] : '') + valueSuffix + signSuffix; // Break the formatted value into the integer “value” part that can be // grouped, and fractional or exponential “suffix” part that is not. if (maybeSuffix) { for (let i = 0, n = value.length; i < n; i++) { const c = value.charCodeAt(i); if (48 > c || c > 57) { valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix; value = value.slice(0, i); break; } } } } // If the fill character is not '0', grouping is applied before padding. if (comma && !zero) value = group(value, Infinity); // Compute the padding. let length = valuePrefix.length + value.length + valueSuffix.length; let padding = length < width ? new Array(width - length + 1).join(fill) : ''; // If the fill character is '0', grouping is applied after padding. if (comma && zero) { value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity); padding = ''; } // Reconstruct the final output based on the desired alignment. switch (align) { case '<': value = valuePrefix + value + valueSuffix + padding; break; case '=': value = valuePrefix + padding + value + valueSuffix; break; case '^': value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break; default: value = padding + valuePrefix + value + valueSuffix; break; } const { string } = formatSpecifier; if (string) { return string.replace(interpolateRegEx, () => numerals(value)); } return numerals(value); } return format; } function formatPrefix(specifier, value) { const formatSpecifier = makeFormatSpecifier(specifier); formatSpecifier.type = 'f'; const f = newFormat(formatSpecifier); const e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3; const k = Math.pow(10, -e); const prefix = prefixes[8 + e / 3]; return function (value) { return f(k * +value) + prefix; }; } return { format: newFormat, formatPrefix: formatPrefix }; } exports.formatLocale = formatLocale; //# sourceMappingURL=numberFormat.js.map