Skip to content
This repository was archived by the owner on Jul 29, 2019. It is now read-only.

Commit 0a64249

Browse files
marcortwyotamberk
authored andcommitted
Implementation of a week scale feature (#3009)
* Add Gitter badge (#2179) * do not generate source-maps in distribution version * add 'dist' folder for deployment * added Badges * added codeclimate badge * added @Tooa to the support team * added badges from isitmaintained.com (#2517) * do not ignore dist and test folders in master * generated dist files for v4.18.0 * generated dist files for v4.18.1 * Cheap fix for bug #2795 * Update to PR #2826 to use newline format * changed to v4.18.1-SNAPSHOT * chore(docs): general improvements (#2652) * removed NOTICE file * updated license date range to include 2017 * chore(docs): updated support team members * chore: updated dependencies and devDependencies (#2649) * Fixes instanceof Object statements for objects from other windows and iFrames. (#2631) * Replaces instanceof Object checks with typeof to prevent cross tab issues. * Adds missing space. * chore: removed google-analytics from all examples (#2670) * chore(docs): Add note that PRs should be submitted against the `develop` branch (#2623) Related to: #2618 Related to: #2620 * feat(timeline): Change setCustomTimeTitle title parameter to be a string or a function (#2611) * change setCustomTimeTitle title parameter, Now could be an string or a function * Fixed indent and spacing * feat(timeline): refactor tooltip to only use one dom-element (#2662) * feat(network): Allow for image nodes to have a selected or broken image (#2601) * feat(tests): run mocha tests in travis ci (#2687) * Added showX(YZ)Axis options to Graph3d (#2686) * Added showX(YZ)Axis to Graph3d * Added show_Axis options to docs and playground example * Resolved merge conflict * Added show_Axis options to docs and playground example * fix(build): use babel version compatible with [email protected] (#2693) fixes #2685 * feat(docs): use babel preset2015 for custom builds (#2678) * add link to a mentioned example (#2709) * chore(lint): added support for eslint (#2695) * Trivial typo fix in how_to_help doc. (#2714) * fix(timeline): #2598 Flickering onUpdateTimeTooltip (#2702) * Fix redraw order * Fix error when option is not defined * Allow template labels * Add .travis.yml file * Add experiment travis code * Fix react example * Add animation to onUpdateTooltip * fix(timeline): #778 Tooltip does not work with background items in timeline (#2703) * Fix redraw order * Fix error when option is not defined * Allow template labels * Add .travis.yml file * Add experiment travis code * Fix react example * Make items z-index default to 1 * Add initial tests for Timeline PointItem (#2716) * fix(timeline): #2679 TypeError: Cannot read property 'hasOwnProperty' of null (#2735) * Fix redraw order * Fix error when option is not defined * Allow template labels * Add .travis.yml file * Add experiment travis code * Fix react example * Fix bug in item editable * feat(timeline): #2647 Dynamic rolling mode option (#2705) * Fix redraw order * Fix error when option is not defined * Allow template labels * Add .travis.yml file * Add experiment travis code * Fix react example * Add toggleRollingMode option * Update docs with toggleRollingMode option * fixes timestep next issue (#2732) * feat(timeline): added new locales for french and espanol (#2723) * Fix eslint problem on Travis. (#2744) * fix: Range.js "event" is undeclared (#2749) * fix(timeline): #2720 Problems with option editable (#2743) Clean up and centralise edit status for Timeline Items. * feat(network): Improve the performance of the network layout engine (#2729) * Improve the performance of the network layout engine Short-cut the execution of a number of methods in LayoutEngine to make them handle highly-connected graphs better. * Demonstrations of layouts of large networks * Added support to supply an end to bar charts to have them scale (#2760) * Added support to supply an X2 to bar charts to have them scale * Fixed graph2d stacking issue. It no longer takes into account hidden items * Changed x2 to end per recommendation and added this to the docs * Initial tests for timeline ItemSet. (#2750) Somewhat more complicated setup, associated with the need for a real window. * [Timeline] Modify redraw logic to treat scroll as needing restack. (#2774) This addresses #1982 and #1417. It possibly reduces performance, but correctness seems better. * fix(timeline): #2672 Item events original event (#2704) * Fix redraw order * Fix error when option is not defined * Allow template labels * Add .travis.yml file * Add experiment travis code * Fix react example * Fix events returned from mouse events * Fix example * Rename censor to stringifyObject in example * [timeline] Update examples to use ISOString format. (#2791) Resolves #2790 * [timeline] Update serialization example to use ISOString dates. (#2789) Resolves #2696 * added github templates for issues and pull-requests (#2787) fixes #2418 * feat(timeline): Add item data as argument to the template function (#2799) * Fix regression introduced in #2743. (#2796) * Fix for issue #2536 (#2803) * Fix for issue #2536 * Adjusted documentation for fix. * Adjustments due to review * Grrrrr whitespace * Fixed Travis issue * Cheap fix for bug #2795 * Update to PR #2826 to use newline format * Update to gitignore to reflect changes on remote * clean dist folder * Local gitignore update * Just a first example file for the week scale feature * Allowing sourcemap creation * Initial (non-functional) commit to ensure we insert code at the right places (check TODOs) * Functional, not bug-free version which works with locale aware week numbers. * Locale-aware implementation and simplified major labels to a full year * Trying to make the major labels show the correct start date * Working implementation of week numbers using localization. * removing development leftovers * Updated package.json * Reintagrate package.json from accidental deletion * Updates for package.json * Fixing package.json * Integrate the week numbers feature in the documentation. * Reverting local changes to .gitignore * Reverting local changes * Extending examples to cover the case when 1st day of week and 1st day of month align; Fixing display bug so that week numbers are not repeated in minorLabels * Putting the examples into a loop
1 parent 77699b4 commit 0a64249

File tree

5 files changed

+187
-8
lines changed

5 files changed

+187
-8
lines changed

docs/timeline/index.html

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
612612
hour: 'HH:mm',
613613
weekday: 'ddd D',
614614
day: 'D',
615+
week: 'w',
615616
month: 'MMM',
616617
year: 'YYYY'
617618
},
@@ -622,6 +623,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
622623
hour: 'ddd D MMMM',
623624
weekday: 'MMMM YYYY',
624625
day: 'MMMM YYYY',
626+
week: 'MMMM YYYY',
625627
month: 'YYYY',
626628
year: ''
627629
}
@@ -1044,7 +1046,7 @@ <h2 id="Configuration_Options">Configuration Options</h2>
10441046
<td>function</td>
10451047
<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:
10461048
<pre class="prettyprint lang-js">function snap(date: Date, scale: string, step: number) : Date or number</pre>
1047-
The parameter <code>scale</code> can be can be 'millisecond', 'second', 'minute', 'hour', 'weekday, 'day, 'month, or 'year'. The parameter <code>step</code> is a number like 1, 2, 4, 5.
1049+
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.
10481050
</td>
10491051
</tr>
10501052

@@ -1088,10 +1090,11 @@ <h2 id="Configuration_Options">Configuration Options</h2>
10881090
<td class="indent">timeAxis.scale</td>
10891091
<td>String</td>
10901092
<td>none</td>
1091-
<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:
1093+
<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:
10921094
<pre class="prettyprint lang-js">var options = {
10931095
timeAxis: {scale: 'minute', step: 5}
10941096
}</pre>
1097+
<p>Note: The 'week' scale only works properly when <a href="#Localization">locales</a> are enabled.</p>
10951098
</td>
10961099
</tr>
10971100

@@ -2023,13 +2026,19 @@ <h3 id="Grid_Backgrounds">Grid Backgrounds</h3>
20232026
<tr>
20242027
<td>Days</td><td><code>vis-day1</code>, <code>vis-day2</code>, ..., <code>vis-day31</code></td>
20252028
</tr>
2029+
<tr>
2030+
<td>Week</td><td><code>vis-week1</code>, <code>vis-week2</code>, ..., <code>vis-week53</code></td>
2031+
</tr>
20262032
<tr>
20272033
<td>Months</td><td><code>vis-january</code>, <code>vis-february</code>, <code>vis-march</code>, <code>vis-april</code>, <code>vis-may</code>, <code>vis-june</code>, <code>vis-july</code>, <code>vis-august</code>, <code>vis-september</code>, <code>vis-october</code>, <code>vis-november</code>, <code>vis-december</code></td>
20282034
</tr>
20292035
<tr>
20302036
<td>Years</td><td><code>vis-year2014</code>, <code>vis-year2015</code>, ...</td>
20312037
</tr>
20322038
</table>
2039+
<p>
2040+
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'
2041+
</p>
20332042

20342043
<p>Examples:</p>
20352044

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<!DOCTYPE HTML>
2+
<html>
3+
<head>
4+
<title>Timeline | Grid styling</title>
5+
6+
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.min.js"></script>
7+
<script src="../../../dist/vis.js"></script>
8+
<link href="../../../dist/vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css"/>
9+
10+
<style type="text/css">
11+
body, html {
12+
font-family: sans-serif;
13+
}
14+
15+
/* alternating column backgrounds */
16+
.vis-time-axis .vis-grid.vis-odd {
17+
background: #f5f5f5;
18+
}
19+
</style>
20+
21+
</head>
22+
<body>
23+
24+
<p>
25+
Week numbers are calculated based on locales. For this to properly work, the timeline must be loaded with a version
26+
of moment.js including locales.</p>
27+
<p>To set a locale for the timeline, specify the option
28+
<code>{locale: STRING}</code>.</p>
29+
<p>To set the scale to use week numbers, use for example <code>{scale: 'week', step: 1}</code>.</p>
30+
<p>The following timeline is initialized with the 'de' locale and items are added with locally localized moment.js
31+
objects. The timeline locale can be switched to another locale at runtime. If you choose the 'en' locale, the week
32+
numbers will be calculated according to the US week calendar numbering scheme.</p>
33+
34+
<p>
35+
<label for="locale">Select a locale:</label>
36+
<select id="locale">
37+
<option value="en">en</option>
38+
<option value="it">it</option>
39+
<option value="nl">nl</option>
40+
<option value="de" selected>de</option>
41+
</select>
42+
</p>
43+
44+
<div id="visualization"></div>
45+
46+
<script type="text/javascript">
47+
var itemCount = 26;
48+
49+
// DOM element where the Timeline will be attached
50+
var container = document.getElementById('visualization');
51+
52+
// just a group for the effects
53+
var groups = new vis.DataSet();
54+
groups.add([{id: 1, content: "ISO Weeks"}, {id: 2, content: "US Weeks"}]);
55+
56+
// Create a DataSet (allows two way data-binding)
57+
var items = new vis.DataSet();
58+
59+
// create a localized moment object based on the current date
60+
var USdate = moment().locale('en').hours(0).minutes(0).seconds(0).milliseconds(0);
61+
62+
// use the locale-aware weekday function to move to the begin of the current week
63+
USdate.weekday(0);
64+
65+
// Iterate and just add a week to use it again in the next iteration
66+
for (var i = 0; i < itemCount; i++) {
67+
var USweekNumber = USdate.format('w');
68+
var USweekStart = USdate.format();
69+
var USweekEnd = USdate.add(1, 'week').format();
70+
items.add({
71+
id: i,
72+
group: 2,
73+
content: 'US week ' + USweekNumber,
74+
start: USweekStart,
75+
end: USweekEnd
76+
});
77+
}
78+
79+
// create another localized moment object - the 'de' locale works according to the ISO8601 leap week calendar system
80+
var DEdate = moment().locale('de').hours(0).minutes(0).seconds(0).milliseconds(0);
81+
DEdate.weekday(0);
82+
for (var j = 0; j < itemCount; j++) {
83+
var DEweekNumber = DEdate.format('w');
84+
var DEweekStart = DEdate.format();
85+
var DEweekEnd = DEdate.add(1, 'week').format();
86+
items.add({
87+
id: itemCount + j,
88+
group: 1,
89+
content: 'ISO week ' + DEweekNumber,
90+
start: DEweekStart,
91+
end: DEweekEnd
92+
});
93+
}
94+
95+
// Configuration for the Timeline
96+
var options = {timeAxis: {scale: 'week', step: 1}, locale: 'de'};
97+
98+
// Create a Timeline
99+
var timeline = new vis.Timeline(container, items, groups, options);
100+
101+
// update the locale when changing the select box value
102+
var select = document.getElementById('locale');
103+
select.onchange = function () {
104+
timeline.setOptions({
105+
locale: this.value
106+
});
107+
};
108+
select.onchange();
109+
</script>
110+
</body>
111+
</html>

lib/timeline/TimeStep.js

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ TimeStep.FORMAT = {
6969
hour: 'HH:mm',
7070
weekday: 'ddd D',
7171
day: 'D',
72+
week: 'w',
7273
month: 'MMM',
7374
year: 'YYYY'
7475
},
@@ -79,6 +80,7 @@ TimeStep.FORMAT = {
7980
hour: 'ddd D MMMM',
8081
weekday: 'MMMM YYYY',
8182
day: 'MMMM YYYY',
83+
week: 'MMMM YYYY',
8284
month: 'YYYY',
8385
year: ''
8486
}
@@ -101,7 +103,7 @@ TimeStep.prototype.setMoment = function (moment) {
101103
/**
102104
* Set custom formatting for the minor an major labels of the TimeStep.
103105
* Both `minorLabels` and `majorLabels` are an Object with properties:
104-
* 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'.
106+
* 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'.
105107
* @param {{minorLabels: Object, majorLabels: Object}} format
106108
*/
107109
TimeStep.prototype.setFormat = function (format) {
@@ -153,6 +155,7 @@ TimeStep.prototype.roundToMinor = function() {
153155
this.current.year(this.step * Math.floor(this.current.year() / this.step));
154156
this.current.month(0);
155157
case 'month': this.current.date(1);
158+
case 'week': this.current.weekday(0);
156159
case 'day': // intentional fall through
157160
case 'weekday': this.current.hours(0);
158161
case 'hour': this.current.minutes(0);
@@ -170,6 +173,7 @@ TimeStep.prototype.roundToMinor = function() {
170173
case 'hour': this.current.subtract(this.current.hours() % this.step, 'hours'); break;
171174
case 'weekday': // intentional fall through
172175
case 'day': this.current.subtract((this.current.date() - 1) % this.step, 'day'); break;
176+
case 'week': this.current.subtract(this.current.week() % this.step, 'week'); break;
173177
case 'month': this.current.subtract(this.current.month() % this.step, 'month'); break;
174178
case 'year': this.current.subtract(this.current.year() % this.step, 'year'); break;
175179
default: break;
@@ -210,6 +214,21 @@ TimeStep.prototype.next = function() {
210214
break;
211215
case 'weekday': // intentional fall through
212216
case 'day': this.current.add(this.step, 'day'); break;
217+
case 'week':
218+
if (this.current.weekday() !== 0){ // we had a month break not correlating with a week's start before
219+
this.current.weekday(0); // switch back to week cycles
220+
this.current.add(this.step, 'week');
221+
} else { // first day of the week
222+
var nextWeek = this.current.clone();
223+
nextWeek.add(1, 'week');
224+
if(nextWeek.isSame(this.current, 'month')){ // is the first day of the next week in the same month?
225+
this.current.add(this.step, 'week'); // the default case
226+
} else { // inject a step at each first day of the month
227+
this.current.add(this.step, 'week');
228+
this.current.date(1);
229+
}
230+
}
231+
break;
213232
case 'month': this.current.add(this.step, 'month'); break;
214233
case 'year': this.current.add(this.step, 'year'); break;
215234
default: break;
@@ -224,6 +243,7 @@ TimeStep.prototype.next = function() {
224243
case 'hour': if(this.current.hours() > 0 && this.current.hours() < this.step) this.current.hours(0); break;
225244
case 'weekday': // intentional fall through
226245
case 'day': if(this.current.date() < this.step+1) this.current.date(1); break;
246+
case 'week': if(this.current.week() < this.step) this.current.week(1); break; // week numbering starts at 1, not 0
227247
case 'month': if(this.current.month() < this.step) this.current.month(0); break;
228248
case 'year': break; // nothing to do for year
229249
default: break;
@@ -260,7 +280,7 @@ TimeStep.prototype.getCurrent = function() {
260280
* @param {{scale: string, step: number}} params
261281
* An object containing two properties:
262282
* - A string 'scale'. Choose from 'millisecond', 'second',
263-
* 'minute', 'hour', 'weekday', 'day', 'month', 'year'.
283+
* 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'.
264284
* - A number 'step'. A step size, by default 1.
265285
* Choose for example 1, 2, 5, or 10.
266286
*/
@@ -338,7 +358,7 @@ TimeStep.prototype.setMinimumStep = function(minimumStep) {
338358
* Static function
339359
* @param {Date} date the date to be snapped.
340360
* @param {string} scale Current scale, can be 'millisecond', 'second',
341-
* 'minute', 'hour', 'weekday, 'day', 'month', 'year'.
361+
* 'minute', 'hour', 'weekday, 'day', 'week', 'month', 'year'.
342362
* @param {number} step Current step (1, 2, 4, 5, ...
343363
* @return {Date} snappedDate
344364
*/
@@ -370,6 +390,20 @@ TimeStep.snap = function(date, scale, step) {
370390
clone.seconds(0);
371391
clone.milliseconds(0);
372392
}
393+
else if (scale == 'week') {
394+
if (clone.weekday() > 2) { // doing it the momentjs locale aware way
395+
clone.weekday(0);
396+
clone.add(1, 'week');
397+
}
398+
else {
399+
clone.weekday(0);
400+
}
401+
402+
clone.hours(0);
403+
clone.minutes(0);
404+
clone.seconds(0);
405+
clone.milliseconds(0);
406+
}
373407
else if (scale == 'day') {
374408
//noinspection FallthroughInSwitchStatementJS
375409
switch (step) {
@@ -452,6 +486,7 @@ TimeStep.prototype.isMajor = function() {
452486
switch (this.scale) {
453487
case 'year':
454488
case 'month':
489+
case 'week':
455490
case 'weekday':
456491
case 'day':
457492
case 'hour':
@@ -465,6 +500,7 @@ TimeStep.prototype.isMajor = function() {
465500
}
466501
else if (this.switchedMonth == true) {
467502
switch (this.scale) {
503+
case 'week':
468504
case 'weekday':
469505
case 'day':
470506
case 'hour':
@@ -501,6 +537,8 @@ TimeStep.prototype.isMajor = function() {
501537
case 'weekday': // intentional fall through
502538
case 'day':
503539
return (date.date() == 1);
540+
case 'week':
541+
return (date.date() == 1);
504542
case 'month':
505543
return (date.month() == 0);
506544
case 'year':
@@ -530,7 +568,15 @@ TimeStep.prototype.getLabelMinor = function(date) {
530568
}
531569

532570
var format = this.format.minorLabels[this.scale];
533-
return (format && format.length > 0) ? this.moment(date).format(format) : '';
571+
// noinspection FallThroughInSwitchStatementJS
572+
switch (this.scale) {
573+
case 'week':
574+
if(this.isMajor() && date.weekday() !== 0){
575+
return "";
576+
}
577+
default:
578+
return (format && format.length > 0) ? this.moment(date).format(format) : '';
579+
}
534580
};
535581

536582
/**
@@ -624,6 +670,11 @@ TimeStep.prototype.getClassName = function() {
624670
classNames.push(this.step <= 2 ? 'vis-' + current.format('dddd').toLowerCase() : '');
625671
classNames.push(even(current.date() - 1));
626672
break;
673+
case 'week':
674+
classNames.push('vis-week' + current.format('w'));
675+
classNames.push(currentWeek(current));
676+
classNames.push(even(current.week()));
677+
break;
627678
case 'month':
628679
classNames.push('vis-' + current.format('MMMM').toLowerCase());
629680
classNames.push(currentMonth(current));

lib/timeline/component/TimeAxis.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ TimeAxis.prototype._repaintLabels = function () {
227227
var x;
228228
var xNext;
229229
var isMajor, nextIsMajor;
230+
var showMinorGrid;
230231
var width = 0, prevWidth;
231232
var line;
232233
var labelMinor;
@@ -255,7 +256,10 @@ TimeAxis.prototype._repaintLabels = function () {
255256

256257
prevWidth = width;
257258
width = xNext - x;
258-
var showMinorGrid = (width >= prevWidth * 0.4); // prevent displaying of the 31th of the month on a scale of 5 days
259+
switch (step.scale) {
260+
case 'week': showMinorGrid = true; break;
261+
default: showMinorGrid = (width >= prevWidth * 0.4); break; // prevent displaying of the 31th of the month on a scale of 5 days
262+
}
259263

260264
if (this.options.showMinorLabels && showMinorGrid) {
261265
var label = this._repaintMinorText(x, labelMinor, orientation, className);

lib/timeline/optionsTimeline.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ let allOptions = {
5454
hour: {string,'undefined': 'undefined'},
5555
weekday: {string,'undefined': 'undefined'},
5656
day: {string,'undefined': 'undefined'},
57+
week: {string,'undefined': 'undefined'},
5758
month: {string,'undefined': 'undefined'},
5859
year: {string,'undefined': 'undefined'},
5960
__type__: {object, 'function': 'function'}
@@ -65,6 +66,7 @@ let allOptions = {
6566
hour: {string,'undefined': 'undefined'},
6667
weekday: {string,'undefined': 'undefined'},
6768
day: {string,'undefined': 'undefined'},
69+
week: {string,'undefined': 'undefined'},
6870
month: {string,'undefined': 'undefined'},
6971
year: {string,'undefined': 'undefined'},
7072
__type__: {object, 'function': 'function'}
@@ -181,6 +183,7 @@ let configureOptions = {
181183
hour: 'HH:mm',
182184
weekday: 'ddd D',
183185
day: 'D',
186+
week: 'w',
184187
month: 'MMM',
185188
year: 'YYYY'
186189
},
@@ -191,6 +194,7 @@ let configureOptions = {
191194
hour: 'ddd D MMMM',
192195
weekday: 'MMMM YYYY',
193196
day: 'MMMM YYYY',
197+
week: 'MMMM YYYY',
194198
month: 'YYYY',
195199
year: ''
196200
}
@@ -236,7 +240,7 @@ let configureOptions = {
236240
start: '',
237241
//template: {'function': 'function'},
238242
//timeAxis: {
239-
// scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'],
243+
// scale: ['millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'year'],
240244
// step: [1, 1, 10, 1]
241245
//},
242246
tooltip: {

0 commit comments

Comments
 (0)