Skip to content
This repository has been archived by the owner on Oct 4, 2020. It is now read-only.

Commit

Permalink
[Timeline] Year quarters (almende#3717)
Browse files Browse the repository at this point in the history
* timeline: add 'quarter' support

* add unit test

* update docs

* misc

* 'quarters' scale hidden by default
  • Loading branch information
Francesco Stefanini authored and mojoaxel committed Jun 9, 2019
1 parent 4a7c768 commit 86f3983
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 9 deletions.
4 changes: 3 additions & 1 deletion docs/graph2d/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,7 @@ <h3 id="timelineOptions">Timeline Options</h3>
weekday: 'ddd D',
day: 'D',
month: 'MMM',
quarter: '[Q]Q',
year: 'YYYY'
},
majorLabels: {
Expand All @@ -851,6 +852,7 @@ <h3 id="timelineOptions">Timeline Options</h3>
weekday: 'MMMM YYYY',
day: 'MMMM YYYY',
month: 'YYYY',
quarter: 'YYYY',
year: ''
}
}</pre>
Expand Down Expand Up @@ -1009,7 +1011,7 @@ <h3 id="timelineOptions">Timeline Options</h3>
<td class="indent">timeAxis.scale</td>
<td>String</td>
<td>none</td>
<td>Set a fixed scale for the time axis of the Timeline. Choose from <code>'millisecond'</code>, <code>'second'</code>, <code>'minute'</code>, <code>'hour'</code>, <code>'weekday'</code>, <code>'day'</code>, <code>'month'</code>, <code>'year'</code>. Example usage:
<td>Set a fixed scale for the time axis of the Timeline. Choose from <code>'millisecond'</code>, <code>'second'</code>, <code>'minute'</code>, <code>'hour'</code>, <code>'weekday'</code>, <code>'day'</code>, <code>'month'</code>, <code>'quarter'</code>, <code>'year'</code>. Example usage:
<pre class="prettyprint lang-js options">var options = {
timeAxis: {scale: 'minute', step: 5}
}</pre>
Expand Down
8 changes: 5 additions & 3 deletions docs/timeline/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
day: 'D',
week: 'w',
month: 'MMM',
quarter: '[Q]Q',
year: 'YYYY'
},
majorLabels: {
Expand All @@ -634,6 +635,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
day: 'MMMM YYYY',
week: 'MMMM YYYY',
month: 'YYYY',
quarter: 'YYYY',
year: ''
}
}</pre>
Expand Down Expand Up @@ -1127,7 +1129,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
<td>function</td>
<td>When moving items on the Timeline, they will be snapped to nice dates like full hours or days, depending on the current scale. The <code>snap</code> function can be replaced with a custom function, or can be set to <code>null</code> to disable snapping. The signature of the snap function is:
<pre class="prettyprint lang-js">function snap(date: Date, scale: string, step: number) : Date or number</pre>
The parameter <code>scale</code> can be can be 'millisecond', 'second', 'minute', 'hour', 'weekday, 'week', 'day, 'month, or 'year'. The parameter <code>step</code> is a number like 1, 2, 4, 5.
The parameter <code>scale</code> can be can be 'millisecond', 'second', 'minute', 'hour', 'weekday, 'week', 'day', 'month', 'quarter' or 'year'. The parameter <code>step</code> is a number like 1, 2, 4, 5.
</td>
</tr>

Expand Down Expand Up @@ -1171,7 +1173,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
<td class="indent">timeAxis.scale</td>
<td>String</td>
<td>none</td>
<td>Set a fixed scale for the time axis of the Timeline. Choose from <code>'millisecond'</code>, <code>'second'</code>, <code>'minute'</code>, <code>'hour'</code>, <code>'weekday'</code>, <code>'week'</code>, <code>'day'</code>, <code>'month'</code>, <code>'year'</code>. Example usage:
<td>Set a fixed scale for the time axis of the Timeline. Choose from <code>'millisecond'</code>, <code>'second'</code>, <code>'minute'</code>, <code>'hour'</code>, <code>'weekday'</code>, <code>'week'</code>, <code>'day'</code>, <code>'month'</code>, <code>'quarter'</code>, <code>'year'</code>. Example usage:
<pre class="prettyprint lang-js">var options = {
timeAxis: {scale: 'minute', step: 5}
}</pre>
Expand Down Expand Up @@ -2153,7 +2155,7 @@ <h3 id="Grid_Backgrounds">Grid Backgrounds</h3>
</tr>
</table>
<p>
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'.
</p>

<p>Examples:</p>
Expand Down
6 changes: 6 additions & 0 deletions examples/timeline/other/functionLabelFormats.html
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
48 changes: 44 additions & 4 deletions lib/timeline/TimeStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ TimeStep.FORMAT = {
day: 'D',
week: 'D',
month: 'MMM',
quarter: 'MMM',
year: 'YYYY'
},
majorLabels: {
Expand All @@ -86,6 +87,7 @@ TimeStep.FORMAT = {
day: 'MMMM YYYY',
week: 'MMMM YYYY',
month: 'YYYY',
quarter: 'YYYY',
year: ''
}
};
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
Expand All @@ -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;}
Expand Down Expand Up @@ -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
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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));
Expand Down
4 changes: 4 additions & 0 deletions lib/timeline/optionsGraph2d.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}
},
Expand All @@ -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}
},
Expand Down Expand Up @@ -238,6 +240,7 @@ let configureOptions = {
weekday: 'ddd D',
day: 'D',
month: 'MMM',
quarter: '[Q]Q',
year: 'YYYY'
},
majorLabels: {
Expand All @@ -248,6 +251,7 @@ let configureOptions = {
weekday: 'MMMM YYYY',
day: 'MMMM YYYY',
month: 'YYYY',
quarter: 'YYYY',
year: ''
}
},
Expand Down
6 changes: 5 additions & 1 deletion lib/timeline/optionsTimeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'}
},
Expand All @@ -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'}
},
Expand Down Expand Up @@ -202,6 +204,7 @@ let configureOptions = {
day: 'D',
week: 'w',
month: 'MMM',
quarter: '[Q]Q',
year: 'YYYY'
},
majorLabels: {
Expand All @@ -213,6 +216,7 @@ let configureOptions = {
day: 'MMMM YYYY',
week: 'MMMM YYYY',
month: 'YYYY',
quarter: 'YYYY',
year: ''
}
},
Expand Down Expand Up @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions test/TimeStep.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down

0 comments on commit 86f3983

Please sign in to comment.