+
+// Label constants for the labelsKMB and labelsKMG2 options.
+// (i.e. '100000' -> '100K')
+var KMB_LABELS = [ 'K', 'M', 'B', 'T', 'Q' ];
+var KMG2_BIG_LABELS = [ 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' ];
+var KMG2_SMALL_LABELS = [ 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y' ];
+
+/**
+ * @private
+ * Return a string version of a number. This respects the digitsAfterDecimal
+ * and maxNumberWidth options.
+ * @param {number} x The number to be formatted
+ * @param {Dygraph} opts An options view
+ */
+export function numberValueFormatter(x, opts) {
+ var sigFigs = opts('sigFigs');
+
+ if (sigFigs !== null) {
+ // User has opted for a fixed number of significant figures.
+ return floatFormat(x, sigFigs);
+ }
+
+ var digits = opts('digitsAfterDecimal');
+ var maxNumberWidth = opts('maxNumberWidth');
+
+ var kmb = opts('labelsKMB');
+ var kmg2 = opts('labelsKMG2');
+
+ var label;
+
+ // switch to scientific notation if we underflow or overflow fixed display.
+ if (x !== 0.0 &&
+ (Math.abs(x) >= Math.pow(10, maxNumberWidth) ||
+ Math.abs(x) < Math.pow(10, -digits))) {
+ label = x.toExponential(digits);
+ } else {
+ label = '' + round_(x, digits);
+ }
+
+ if (kmb || kmg2) {
+ var k;
+ var k_labels = [];
+ var m_labels = [];
+ if (kmb) {
+ k = 1000;
+ k_labels = KMB_LABELS;
+ }
+ if (kmg2) {
+ if (kmb) console.warn("Setting both labelsKMB and labelsKMG2. Pick one!");
+ k = 1024;
+ k_labels = KMG2_BIG_LABELS;
+ m_labels = KMG2_SMALL_LABELS;
+ }
+
+ var absx = Math.abs(x);
+ var n = pow(k, k_labels.length);
+ for (var j = k_labels.length - 1; j >= 0; j--, n /= k) {
+ if (absx >= n) {
+ label = round_(x / n, digits) + k_labels[j];
+ break;
+ }
+ }
+ if (kmg2) {
+ // TODO(danvk): clean up this logic. Why so different than kmb?
+ var x_parts = String(x.toExponential()).split('e-');
+ if (x_parts.length === 2 && x_parts[1] >= 3 && x_parts[1] <= 24) {
+ if (x_parts[1] % 3 > 0) {
+ label = round_(x_parts[0] /
+ pow(10, (x_parts[1] % 3)),
+ digits);
+ } else {
+ label = Number(x_parts[0]).toFixed(2);
+ }
+ label += m_labels[Math.floor(x_parts[1] / 3) - 1];
+ }
+ }
+ }
+
+ return label;
+};
+
+/**
+ * variant for use as an axisLabelFormatter.
+ * @private
+ */
+export function numberAxisLabelFormatter(x, granularity, opts) {
+ return numberValueFormatter.call(this, x, opts);
+};
+
+/**
+ * @type {!Array.<string>}
+ * @private
+ * @constant
+ */
+var SHORT_MONTH_NAMES_ = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+
+
+/**
+ * Convert a JS date to a string appropriate to display on an axis that
+ * is displaying values at the stated granularity. This respects the
+ * labelsUTC option.
+ * @param {Date} date The date to format
+ * @param {number} granularity One of the Dygraph granularity constants
+ * @param {Dygraph} opts An options view
+ * @return {string} The date formatted as local time
+ * @private
+ */
+export function dateAxisLabelFormatter(date, granularity, opts) {
+ var utc = opts('labelsUTC');
+ var accessors = utc ? DateAccessorsUTC : DateAccessorsLocal;
+
+ var year = accessors.getFullYear(date),
+ month = accessors.getMonth(date),
+ day = accessors.getDate(date),
+ hours = accessors.getHours(date),
+ mins = accessors.getMinutes(date),
+ secs = accessors.getSeconds(date),
+ millis = accessors.getSeconds(date);
+
+ if (granularity >= DygraphTickers.Granularity.DECADAL) {
+ return '' + year;
+ } else if (granularity >= DygraphTickers.Granularity.MONTHLY) {
+ return SHORT_MONTH_NAMES_[month] + ' ' + year;
+ } else {
+ var frac = hours * 3600 + mins * 60 + secs + 1e-3 * millis;
+ if (frac === 0 || granularity >= DygraphTickers.Granularity.DAILY) {
+ // e.g. '21 Jan' (%d%b)
+ return zeropad(day) + ' ' + SHORT_MONTH_NAMES_[month];
+ } else {
+ return hmsString_(hours, mins, secs);
+ }
+ }
+};
+// alias in case anyone is referencing the old method.
+// Dygraph.dateAxisFormatter = Dygraph.dateAxisLabelFormatter;
+
+/**
+ * Return a string version of a JS date for a value label. This respects the
+ * labelsUTC option.
+ * @param {Date} date The date to be formatted
+ * @param {Dygraph} opts An options view
+ * @private
+ */
+export function dateValueFormatter(d, opts) {
+ return dateString_(d, opts('labelsUTC'));
+};