diff --git a/docs/graph2d/index.html b/docs/graph2d/index.html index e27d6de1..925b6414 100644 --- a/docs/graph2d/index.html +++ b/docs/graph2d/index.html @@ -841,6 +841,7 @@ function (option, path) { weekday: 'ddd D', day: 'D', month: 'MMM', + quarter: '[Q]Q', year: 'YYYY' }, majorLabels: { @@ -851,6 +852,7 @@ function (option, path) { weekday: 'MMMM YYYY', day: 'MMMM YYYY', month: 'YYYY', + quarter: 'YYYY', year: '' } } @@ -1009,7 +1011,7 @@ function (option, path) { timeAxis.scale String none - Set a fixed scale for the time axis of the Timeline. Choose from 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'. Example usage: + Set a fixed scale for the time axis of the Timeline. Choose from 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'quarter', 'year'. Example usage:
var options = {
   timeAxis: {scale: 'minute', step: 5}
 }
diff --git a/docs/timeline/index.html b/docs/timeline/index.html index 1a6b7c3c..e3841190 100644 --- a/docs/timeline/index.html +++ b/docs/timeline/index.html @@ -623,6 +623,7 @@ function (option, path) { day: 'D', week: 'w', month: 'MMM', + quarter: '[Q]Q', year: 'YYYY' }, majorLabels: { @@ -634,6 +635,7 @@ function (option, path) { day: 'MMMM YYYY', week: 'MMMM YYYY', month: 'YYYY', + quarter: 'YYYY', year: '' } } @@ -1127,7 +1129,7 @@ function (option, path) { function When moving items on the Timeline, they will be snapped to nice dates like full hours or days, depending on the current scale. The snap function can be replaced with a custom function, or can be set to null to disable snapping. The signature of the snap function is:
function snap(date: Date, scale: string, step: number) : Date or number
- The parameter scale can be can be 'millisecond', 'second', 'minute', 'hour', 'weekday, 'week', 'day, 'month, or 'year'. The parameter step is a number like 1, 2, 4, 5. + The parameter scale can be can be 'millisecond', 'second', 'minute', 'hour', 'weekday, 'week', 'day', 'month', 'quarter' or 'year'. The parameter step is a number like 1, 2, 4, 5. @@ -1171,7 +1173,7 @@ function (option, path) { timeAxis.scale String none - Set a fixed scale for the time axis of the Timeline. Choose from 'millisecond', 'second', 'minute', 'hour', 'weekday', 'week', 'day', 'month', 'year'. Example usage: + Set a fixed scale for the time axis of the Timeline. Choose from 'millisecond', 'second', 'minute', 'hour', 'weekday', 'week', 'day', 'month', 'quarter', 'year'. Example usage:
var options = {
   timeAxis: {scale: 'minute', step: 5}
 }
@@ -2153,7 +2155,7 @@ var options = {

- Note: the 'week' scale is not included in the automatic zoom levels as its scale is not a direct logical successor of 'days' nor a logical predecessor of 'months' + Note: the 'week' scale is not included in the automatic zoom levels as its scale is not a direct logical successor of 'days' nor a logical predecessor of 'months'. Same goes for the 'quarter' scale which is not a direct logical successor of 'months' nor a logical predecessor of 'years'.

Examples:

diff --git a/examples/timeline/other/functionLabelFormats.html b/examples/timeline/other/functionLabelFormats.html index f8e442bd..8a7d69ac 100644 --- a/examples/timeline/other/functionLabelFormats.html +++ b/examples/timeline/other/functionLabelFormats.html @@ -86,6 +86,9 @@ case 'month': divider = 1000 * 60 * 60 * 24 * 30; break; + case 'quarter': + divider = 1000 * 60 * 60 * 24 * 30 * 3; + break; case 'year': divider = 1000 * 60 * 60 * 24 * 365; break; @@ -120,6 +123,9 @@ case 'month': divider = 1000 * 60 * 60 * 24 * 30; break; + case 'quarter': + divider = 1000 * 60 * 60 * 24 * 30 * 3; + break; case 'year': divider = 1000 * 60 * 60 * 24 * 365; break; diff --git a/lib/timeline/TimeStep.js b/lib/timeline/TimeStep.js index 1b3c1111..70abd3ed 100644 --- a/lib/timeline/TimeStep.js +++ b/lib/timeline/TimeStep.js @@ -75,6 +75,7 @@ TimeStep.FORMAT = { day: 'D', week: 'D', month: 'MMM', + quarter: 'MMM', year: 'YYYY' }, majorLabels: { @@ -86,6 +87,7 @@ TimeStep.FORMAT = { day: 'MMMM YYYY', week: 'MMMM YYYY', month: 'YYYY', + quarter: 'YYYY', year: '' } }; @@ -107,7 +109,7 @@ TimeStep.prototype.setMoment = function (moment) { /** * Set custom formatting for the minor an major labels of the TimeStep. * Both `minorLabels` and `majorLabels` are an Object with properties: - * 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'. + * 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'quarter', 'year'. * @param {{minorLabels: Object, majorLabels: Object}} format */ TimeStep.prototype.setFormat = function (format) { @@ -162,6 +164,7 @@ TimeStep.prototype.roundToMinor = function() { case 'year': this.current.year(this.step * Math.floor(this.current.year() / this.step)); this.current.month(0); + case 'quarter': this.current.month(0); // eslint-disable-line no-fallthrough case 'month': this.current.date(1); // eslint-disable-line no-fallthrough case 'week': // eslint-disable-line no-fallthrough case 'day': // eslint-disable-line no-fallthrough @@ -183,6 +186,7 @@ TimeStep.prototype.roundToMinor = function() { case 'day': this.current.subtract((this.current.date() - 1) % this.step, 'day'); break; case 'week': this.current.subtract(this.current.week() % this.step, 'week'); break; case 'month': this.current.subtract(this.current.month() % this.step, 'month'); break; + case 'quarter': this.current.subtract((this.current.quarter() - 1) % this.step, 'quarter'); break; case 'year': this.current.subtract(this.current.year() % this.step, 'year'); break; default: break; } @@ -240,6 +244,7 @@ TimeStep.prototype.next = function() { } break; case 'month': this.current.add(this.step, 'month'); break; + case 'quarter': this.current.add(this.step, 'quarter'); break; case 'year': this.current.add(this.step, 'year'); break; default: break; } @@ -255,6 +260,7 @@ TimeStep.prototype.next = function() { case 'day': if(this.current.date() < this.step+1) this.current.date(1); break; case 'week': if(this.current.week() < this.step) this.current.week(1); break; // week numbering starts at 1, not 0 case 'month': if(this.current.month() < this.step) this.current.month(0); break; + case 'quarter': if(this.current.quarter() < this.step+1) this.current.quarter(1); break; case 'year': break; // nothing to do for year default: break; } @@ -290,7 +296,7 @@ TimeStep.prototype.getCurrent = function() { * @param {{scale: string, step: number}} params * An object containing two properties: * - A string 'scale'. Choose from 'millisecond', 'second', - * 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'. + * 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'quarter, 'year'. * - A number 'step'. A step size, by default 1. * Choose for example 1, 2, 5, or 10. */ @@ -323,6 +329,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) { //var b = asc + ds; var stepYear = (1000 * 60 * 60 * 24 * 30 * 12); + var stepQuarter = (1000 * 60 * 60 * 24 * 30 * 3); var stepMonth = (1000 * 60 * 60 * 24 * 30); var stepDay = (1000 * 60 * 60 * 24); var stepHour = (1000 * 60 * 60); @@ -338,7 +345,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) { if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;} if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;} if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;} - if (stepMonth*3 > minimumStep) {this.scale = 'month'; this.step = 3;} + if (stepQuarter > minimumStep) {this.scale = 'quarter'; this.step = 1;} if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;} if (stepDay*7 > minimumStep) {this.scale = 'week'; this.step = 1;} if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;} @@ -368,7 +375,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) { * Static function * @param {Date} date the date to be snapped. * @param {string} scale Current scale, can be 'millisecond', 'second', - * 'minute', 'hour', 'weekday, 'day', 'week', 'month', 'year'. + * 'minute', 'hour', 'weekday, 'day', 'week', 'month', 'quarter', 'year'. * @param {number} step Current step (1, 2, 4, 5, ... * @return {Date} snappedDate */ @@ -385,6 +392,22 @@ TimeStep.snap = function(date, scale, step) { clone.seconds(0); clone.milliseconds(0); } + else if (scale == 'quarter') { + if ((clone.month() % 3 == 1 && clone.date() > 15) || clone.month() % 3 == 2) { + clone.date(1); + clone.month(Math.floor(clone.month() / 3) * 3); + clone.add(1, 'quarter'); + // important: first set Date to 1, after that change the month and the quarter. + } else { + clone.date(1); + clone.month(Math.floor(clone.month() / 3) * 3); + } + + clone.hours(0); + clone.minutes(0); + clone.seconds(0); + clone.milliseconds(0); + } else if (scale == 'month') { if (clone.date() > 15) { clone.date(1); @@ -495,6 +518,7 @@ TimeStep.prototype.isMajor = function() { if (this.switchedYear == true) { switch (this.scale) { case 'year': + case 'quarter': case 'month': case 'week': case 'weekday': @@ -551,6 +575,8 @@ TimeStep.prototype.isMajor = function() { return (date.date() == 1); case 'month': return (date.month() == 0); + case 'quarter': + return (date.quarter() == 1); case 'year': return false; default: @@ -665,6 +691,15 @@ TimeStep.prototype.getClassName = function() { return date.isSame(new Date(), 'month') ? ' vis-current-month' : ''; } + /** + * + * @param {Date} date + * @returns {String} + */ + function currentQuarter(date) { + return date.isSame(new Date(), 'quarter') ? ' vis-current-quarter' : ''; + } + /** * * @param {Date} date @@ -717,6 +752,11 @@ TimeStep.prototype.getClassName = function() { classNames.push(currentMonth(current)); classNames.push(even(current.month())); break; + case 'quarter': + classNames.push('vis-q' + current.quarter()); + classNames.push(currentQuarter(current)); + classNames.push(even(current.quarter())); + break; case 'year': classNames.push('vis-year' + current.year()); classNames.push(currentYear(current)); diff --git a/lib/timeline/optionsGraph2d.js b/lib/timeline/optionsGraph2d.js index 30fed2cf..602465d5 100644 --- a/lib/timeline/optionsGraph2d.js +++ b/lib/timeline/optionsGraph2d.js @@ -113,6 +113,7 @@ let allOptions = { weekday: {string,'undefined': 'undefined'}, day: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, + quarter: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, __type__: {object} }, @@ -124,6 +125,7 @@ let allOptions = { weekday: {string,'undefined': 'undefined'}, day: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, + quarter: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, __type__: {object} }, @@ -238,6 +240,7 @@ let configureOptions = { weekday: 'ddd D', day: 'D', month: 'MMM', + quarter: '[Q]Q', year: 'YYYY' }, majorLabels: { @@ -248,6 +251,7 @@ let configureOptions = { weekday: 'MMMM YYYY', day: 'MMMM YYYY', month: 'YYYY', + quarter: 'YYYY', year: '' } }, diff --git a/lib/timeline/optionsTimeline.js b/lib/timeline/optionsTimeline.js index 5f2a2f59..1d861896 100644 --- a/lib/timeline/optionsTimeline.js +++ b/lib/timeline/optionsTimeline.js @@ -62,6 +62,7 @@ let allOptions = { day: {string,'undefined': 'undefined'}, week: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, + quarter: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, __type__: {object, 'function': 'function'} }, @@ -74,6 +75,7 @@ let allOptions = { day: {string,'undefined': 'undefined'}, week: {string,'undefined': 'undefined'}, month: {string,'undefined': 'undefined'}, + quarter: {string,'undefined': 'undefined'}, year: {string,'undefined': 'undefined'}, __type__: {object, 'function': 'function'} }, @@ -202,6 +204,7 @@ let configureOptions = { day: 'D', week: 'w', month: 'MMM', + quarter: '[Q]Q', year: 'YYYY' }, majorLabels: { @@ -213,6 +216,7 @@ let configureOptions = { day: 'MMMM YYYY', week: 'MMMM YYYY', month: 'YYYY', + quarter: 'YYYY', year: '' } }, @@ -257,7 +261,7 @@ let configureOptions = { start: '', //template: {'function': 'function'}, //timeAxis: { - // scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'], + // scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'quarter', 'year'], // step: [1, 1, 10, 1] //}, showTooltips: true, diff --git a/test/TimeStep.test.js b/test/TimeStep.test.js index 0410163d..cca7e37f 100644 --- a/test/TimeStep.test.js +++ b/test/TimeStep.test.js @@ -55,6 +55,15 @@ describe('TimeStep', function () { assert.equal(timestep.getCurrent().unix(), moment("2018-01-01T00:00:00.000").unix(), "should have the right value after a step"); }); + it('should perform the step with a specified scale (1 quarter)', function () { + var timestep = new TimeStep(new Date(2017, 3, 3), new Date(2017, 3, 5)); + timestep.setScale({ scale: 'quarter', step: 1 }); + timestep.start(); + assert.equal(timestep.getCurrent().unix(), moment("2017-01-01T00:00:00.000").unix(), "should have the right initial value"); + timestep.next(); + assert.equal(timestep.getCurrent().unix(), moment("2017-04-01T00:00:00.000").unix(), "should have the right value after a step"); + }); + it('should perform the step with a specified scale (1 month)', function () { var timestep = new TimeStep(new Date(2017, 3, 3), new Date(2017, 3, 5)); timestep.setScale({ scale: 'month', step: 1 });