UNPKG

datalib

Version:

JavaScript utilites for loading, summarizing and working with data.

232 lines (196 loc) 6.89 kB
var util = require('./util'), d3_time = require('d3-time'), d3_timeF = require('d3-time-format'), d3_numberF = require('d3-format'), numberF = d3_numberF, // defaults to EN-US timeF = d3_timeF, // defaults to EN-US tmpDate = new Date(2000, 0, 1), monthFull, monthAbbr, dayFull, dayAbbr; module.exports = { // Update number formatter to use provided locale configuration. // For more see https://github.com/d3/d3-format numberLocale: numberLocale, number: function(f) { return numberF.format(f); }, numberPrefix: function(f, v) { return numberF.formatPrefix(f, v); }, // Update time formatter to use provided locale configuration. // For more see https://github.com/d3/d3-time-format timeLocale: timeLocale, time: function(f) { return timeF.format(f); }, utc: function(f) { return timeF.utcFormat(f); }, // Set number and time locale simultaneously. locale: function(l) { numberLocale(l); timeLocale(l); }, // automatic formatting functions auto: { number: autoNumberFormat, linear: linearNumberFormat, time: function() { return timeAutoFormat(); }, utc: function() { return utcAutoFormat(); } }, month: monthFormat, // format month name from integer code day: dayFormat, // format week day name from integer code quarter: quarterFormat, // format quarter name from timestamp utcQuarter: utcQuarterFormat // format quarter name from utc timestamp }; // -- Locales ---- // transform 'en-US' style locale string to match d3-format v0.4+ convention function localeRef(l) { return l.length > 4 && 'locale' + ( l[0].toUpperCase() + l[1].toLowerCase() + l[3].toUpperCase() + l[4].toLowerCase() ); } function numberLocale(l) { var f = util.isString(l) ? d3_numberF[localeRef(l)] : d3_numberF.locale(l); if (f == null) throw Error('Unrecognized locale: ' + l); numberF = f; } function timeLocale(l) { var f = util.isString(l) ? d3_timeF[localeRef(l)] : d3_timeF.locale(l); if (f == null) throw Error('Unrecognized locale: ' + l); timeF = f; monthFull = monthAbbr = dayFull = dayAbbr = null; } // -- Number Formatting ---- var e10 = Math.sqrt(50), e5 = Math.sqrt(10), e2 = Math.sqrt(2); function linearRange(domain, count) { if (!domain.length) domain = [0]; if (count == null) count = 10; var start = domain[0], stop = domain[domain.length - 1]; if (stop < start) { error = stop; stop = start; start = error; } var span = (stop - start) || (count = 1, start || stop || 1), step = Math.pow(10, Math.floor(Math.log(span / count) / Math.LN10)), error = span / count / step; // Filter ticks to get closer to the desired count. if (error >= e10) step *= 10; else if (error >= e5) step *= 5; else if (error >= e2) step *= 2; // Round start and stop values to step interval. return [ Math.ceil(start / step) * step, Math.floor(stop / step) * step + step / 2, // inclusive step ]; } function trimZero(f, decimal) { return function(x) { var s = f(x), n = s.indexOf(decimal); if (n < 0) return s; var idx = rightmostDigit(s, n), end = idx < s.length ? s.slice(idx) : ''; while (--idx > n) { if (s[idx] !== '0') { ++idx; break; } } return s.slice(0, idx) + end; }; } function rightmostDigit(s, n) { var i = s.lastIndexOf('e'), c; if (i > 0) return i; for (i=s.length; --i > n;) { c = s.charCodeAt(i); if (c >= 48 && c <= 57) return i+1; // is digit } } function autoNumberFormat(f) { var decimal = numberF.format('.1f')(1)[1]; // get decimal char if (f == null) f = ','; f = d3_numberF.formatSpecifier(f); if (f.precision == null) f.precision = 12; switch (f.type) { case '%': f.precision -= 2; break; case 'e': f.precision -= 1; break; } return trimZero(numberF.format(f), decimal); } function linearNumberFormat(domain, count, f) { var range = linearRange(domain, count); if (f == null) f = ',f'; switch (f = d3_numberF.formatSpecifier(f), f.type) { case 's': { var value = Math.max(Math.abs(range[0]), Math.abs(range[1])); if (f.precision == null) f.precision = d3_numberF.precisionPrefix(range[2], value); return numberF.formatPrefix(f, value); } case '': case 'e': case 'g': case 'p': case 'r': { if (f.precision == null) f.precision = d3_numberF.precisionRound(range[2], Math.max(Math.abs(range[0]), Math.abs(range[1]))) - (f.type === 'e'); break; } case 'f': case '%': { if (f.precision == null) f.precision = d3_numberF.precisionFixed(range[2]) - 2 * (f.type === '%'); break; } } return numberF.format(f); } // -- Datetime Formatting ---- function timeAutoFormat() { var f = timeF.format, formatMillisecond = f('.%L'), formatSecond = f(':%S'), formatMinute = f('%I:%M'), formatHour = f('%I %p'), formatDay = f('%a %d'), formatWeek = f('%b %d'), formatMonth = f('%B'), formatYear = f('%Y'); return function(date) { var d = +date; return (d3_time.second(date) < d ? formatMillisecond : d3_time.minute(date) < d ? formatSecond : d3_time.hour(date) < d ? formatMinute : d3_time.day(date) < d ? formatHour : d3_time.month(date) < d ? (d3_time.week(date) < d ? formatDay : formatWeek) : d3_time.year(date) < d ? formatMonth : formatYear)(date); }; } function utcAutoFormat() { var f = timeF.utcFormat, formatMillisecond = f('.%L'), formatSecond = f(':%S'), formatMinute = f('%I:%M'), formatHour = f('%I %p'), formatDay = f('%a %d'), formatWeek = f('%b %d'), formatMonth = f('%B'), formatYear = f('%Y'); return function(date) { var d = +date; return (d3_time.utcSecond(date) < d ? formatMillisecond : d3_time.utcMinute(date) < d ? formatSecond : d3_time.utcHour(date) < d ? formatMinute : d3_time.utcDay(date) < d ? formatHour : d3_time.utcMonth(date) < d ? (d3_time.utcWeek(date) < d ? formatDay : formatWeek) : d3_time.utcYear(date) < d ? formatMonth : formatYear)(date); }; } function monthFormat(month, abbreviate) { var f = abbreviate ? (monthAbbr || (monthAbbr = timeF.format('%b'))) : (monthFull || (monthFull = timeF.format('%B'))); return (tmpDate.setMonth(month), f(tmpDate)); } function dayFormat(day, abbreviate) { var f = abbreviate ? (dayAbbr || (dayAbbr = timeF.format('%a'))) : (dayFull || (dayFull = timeF.format('%A'))); return (tmpDate.setMonth(0), tmpDate.setDate(2 + day), f(tmpDate)); } function quarterFormat(date) { return Math.floor(date.getMonth() / 3) + 1; } function utcQuarterFormat(date) { return Math.floor(date.getUTCMonth() / 3) + 1; }