From c2c8e16453d28b0c103a76e991aae92ec7bc7b31 Mon Sep 17 00:00:00 2001 From: Henry Date: Thu, 21 Jul 2016 20:03:40 -0700 Subject: [PATCH] Added scale sensitive formatting to UTCTimeFormat --- .../commonUI/formats/src/FormatProvider.js | 4 ++ .../commonUI/formats/src/UTCTimeFormat.js | 52 ++++++++++++++++++- platform/features/conductor-v2/bundle.js | 3 +- .../conductor-v2/src/ui/MctConductorAxis.js | 39 +++++++++++++- 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/platform/commonUI/formats/src/FormatProvider.js b/platform/commonUI/formats/src/FormatProvider.js index 4df4a82d3d4..9f8a71368f6 100644 --- a/platform/commonUI/formats/src/FormatProvider.js +++ b/platform/commonUI/formats/src/FormatProvider.js @@ -58,6 +58,10 @@ define([ * @method format * @memberof Format# * @param {number} value the numeric value to format + * @param {number} [threshold] Optionally provides context to the + * format request, allowing for scale-appropriate formatting. This value + * should be the minimum unit to be represented by this format, in ms. For + * example, to display seconds, a threshold of 1 * 1000 should be provided. * @returns {string} the text representation of the value */ diff --git a/platform/commonUI/formats/src/UTCTimeFormat.js b/platform/commonUI/formats/src/UTCTimeFormat.js index 9e85f3ea1c4..be3610d5183 100644 --- a/platform/commonUI/formats/src/UTCTimeFormat.js +++ b/platform/commonUI/formats/src/UTCTimeFormat.js @@ -34,6 +34,12 @@ define([ "YYYY-MM-DD" ]; + var MS = 1, + SECONDS = 1000 * MS, + MINUTES = 60 * SECONDS, + HOURS = 60 * MINUTES, + DAYS = 24 * HOURS, + MONTHS = (365 / 12) * DAYS; /** * Formatter for UTC timestamps. Interprets numeric values as @@ -46,7 +52,51 @@ define([ function UTCTimeFormat() { } - UTCTimeFormat.prototype.format = function (value) { + /** + * Returns an appropriate time format based on the provided value and + * the threshold required. + * @private + */ + function getScaledFormat (d, threshold) { + //Adapted from D3 formatting rules + if (!(d instanceof Date)){ + d = new Date(moment.utc(d)); + } + return [ + [".SSS", function(d) { return d.getMilliseconds() >= threshold; }], + [":ss", function(d) { return d.getSeconds() * SECONDS >= threshold; }], + ["HH:mm", function(d) { return d.getMinutes() * MINUTES >= threshold; }], + ["HH", function(d) { return d.getHours() * HOURS >= threshold; }], + ["ddd DD", function(d) { + return d.getDay() * DAYS >= threshold && + d.getDate() != 1; + }], + ["MMM DD", function(d) { return d.getDate() != 1; }], + ["MMMM", function(d) { + return d.getMonth() * MONTHS >= threshold; + }], + ["YYYY", function() { return true; }] + ].filter(function (row){ + return row[1](d); + })[0][0]; + }; + + /** + * + * @param value + * @param {number} [threshold] Optionally provides context to the + * format request, allowing for scale-appropriate formatting. This value + * should be the minimum unit to be represented by this format, in ms. For + * example, to display seconds, a threshold of 1 * 1000 should be provided. + * @returns {string} the formatted date + */ + UTCTimeFormat.prototype.format = function (value, threshold) { + if (threshold !== undefined){ + var scaledFormat = getScaledFormat(value, threshold); + if (scaledFormat) { + return moment.utc(value).format(scaledFormat); + } + } return moment.utc(value).format(DATE_FORMAT) + "Z"; }; diff --git a/platform/features/conductor-v2/bundle.js b/platform/features/conductor-v2/bundle.js index c0ccd6d150e..d13f0632e17 100644 --- a/platform/features/conductor-v2/bundle.js +++ b/platform/features/conductor-v2/bundle.js @@ -64,7 +64,8 @@ define([ "key": "mctConductorAxis", "implementation": MCTConductorAxis, "depends": [ - "timeConductor" + "timeConductor", + "formatService" ] } ], diff --git a/platform/features/conductor-v2/src/ui/MctConductorAxis.js b/platform/features/conductor-v2/src/ui/MctConductorAxis.js index 9ca410227a6..c175ed24e6c 100644 --- a/platform/features/conductor-v2/src/ui/MctConductorAxis.js +++ b/platform/features/conductor-v2/src/ui/MctConductorAxis.js @@ -32,7 +32,7 @@ define( * labelled 'ticks'. It requires 'start' and 'end' integer values to * be specified as attributes. */ - function MCTConductorAxis(conductor) { + function MCTConductorAxis(conductor, formatService) { function link(scope, element, attrs, ngModelController) { var target = element[0].firstChild, @@ -57,10 +57,43 @@ define( axisElement.call(xAxis); } + // Calculates the precision of date for formatting. Relies on + // D3's behavior to tick on round units + function threshold(date){ + var ms = date.getTime(); + return [ + 365 * 24 * 60 * 60 * 1000, // years + (365 / 12) * 24 * 60 * 60 * 1000, // months + 7 * 24 * 60 * 60 * 1000, // weeks + 24 * 60 * 60 * 1000, // days + 60 * 60 * 1000, // hours + 60 * 1000, // minutes + 1000, // seconds + 1 // ms + ].filter(function (boundary) { + return ms % boundary === 0; + })[0]; + } + + function changeTimeSystem(timeSystem) { + var key = timeSystem.formats()[0]; + if (key !== undefined) { + var format = formatService.getFormat(key); + + //Define a custom format function + xAxis.tickFormat(function (date) { + return format.format(date, threshold(date)); + }); + axisElement.call(xAxis); + } + } + scope.resize = function () { setScale(conductor.bounds().start, conductor.bounds().end); }; + conductor.on('timeSystem', changeTimeSystem); + //On conductor bounds changes, redraw ticks conductor.on('bounds', function (bounds) { setScale(bounds.start, bounds.end); @@ -68,6 +101,10 @@ define( //Set initial scale. setScale(conductor.bounds().start, conductor.bounds().end); + + if (conductor.timeSystem() !== undefined) { + changeTimeSystem(conductor.timeSystem()); + } } return {