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) {
'millisecond'
, 'second'
, 'minute'
, 'hour'
, 'weekday'
, 'day'
, 'month'
, 'year'
. Example usage:
+ '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) {
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.
'millisecond'
, 'second'
, 'minute'
, 'hour'
, 'weekday'
, 'week'
, 'day'
, 'month'
, 'year'
. Example usage:
+ '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 });