UNPKG

26.7 kBJavaScriptView Raw
1var moment = require('../module/moment');
2var DateUtil = require('./DateUtil');
3var util = require('vis-util');
4
5/**
6 * The class TimeStep is an iterator for dates. You provide a start date and an
7 * end date. The class itself determines the best scale (step size) based on the
8 * provided start Date, end Date, and minimumStep.
9 *
10 * If minimumStep is provided, the step size is chosen as close as possible
11 * to the minimumStep but larger than minimumStep. If minimumStep is not
12 * provided, the scale is set to 1 DAY.
13 * The minimumStep should correspond with the onscreen size of about 6 characters
14 *
15 * Alternatively, you can set a scale by hand.
16 * After creation, you can initialize the class by executing first(). Then you
17 * can iterate from the start date to the end date via next(). You can check if
18 * the end date is reached with the function hasNext(). After each step, you can
19 * retrieve the current date via getCurrent().
20 * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours,
21 * days, to years.
22 *
23 * Version: 1.2
24 *
25 * @param {Date} [start] The start date, for example new Date(2010, 9, 21)
26 * or new Date(2010, 9, 21, 23, 45, 00)
27 * @param {Date} [end] The end date
28 * @param {number} [minimumStep] Optional. Minimum step size in milliseconds
29 * @param {Date|Array.<Date>} [hiddenDates] Optional.
30 * @param {{showMajorLabels: boolean}} [options] Optional.
31 * @constructor TimeStep
32 */
33function TimeStep(start, end, minimumStep, hiddenDates, options) {
34 this.moment = moment;
35
36 // variables
37 this.current = this.moment();
38 this._start = this.moment();
39 this._end = this.moment();
40
41 this.autoScale = true;
42 this.scale = 'day';
43 this.step = 1;
44
45 // initialize the range
46 this.setRange(start, end, minimumStep);
47
48 // hidden Dates options
49 this.switchedDay = false;
50 this.switchedMonth = false;
51 this.switchedYear = false;
52 if (Array.isArray(hiddenDates)) {
53 this.hiddenDates = hiddenDates;
54 }
55 else if (hiddenDates != undefined) {
56 this.hiddenDates = [hiddenDates];
57 }
58 else {
59 this.hiddenDates = [];
60 }
61
62 this.format = TimeStep.FORMAT; // default formatting
63 this.options = options ? options : {};
64
65}
66
67// Time formatting
68TimeStep.FORMAT = {
69 minorLabels: {
70 millisecond:'SSS',
71 second: 's',
72 minute: 'HH:mm',
73 hour: 'HH:mm',
74 weekday: 'ddd D',
75 day: 'D',
76 week: 'D',
77 month: 'MMM',
78 quarter: 'MMM',
79 year: 'YYYY'
80 },
81 majorLabels: {
82 millisecond:'HH:mm:ss',
83 second: 'D MMMM HH:mm',
84 minute: 'ddd D MMMM',
85 hour: 'ddd D MMMM',
86 weekday: 'MMMM YYYY',
87 day: 'MMMM YYYY',
88 week: 'MMMM YYYY',
89 month: 'YYYY',
90 quarter: 'YYYY',
91 year: ''
92 }
93};
94
95/**
96 * Set custom constructor function for moment. Can be used to set dates
97 * to UTC or to set a utcOffset.
98 * @param {function} moment
99 */
100TimeStep.prototype.setMoment = function (moment) {
101 this.moment = moment;
102
103 // update the date properties, can have a new utcOffset
104 this.current = this.moment(this.current.valueOf());
105 this._start = this.moment(this._start.valueOf());
106 this._end = this.moment(this._end.valueOf());
107};
108
109/**
110 * Set custom formatting for the minor an major labels of the TimeStep.
111 * Both `minorLabels` and `majorLabels` are an Object with properties:
112 * 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'quarter', 'year'.
113 * @param {{minorLabels: Object, majorLabels: Object}} format
114 */
115TimeStep.prototype.setFormat = function (format) {
116 var defaultFormat = util.deepExtend({}, TimeStep.FORMAT);
117 this.format = util.deepExtend(defaultFormat, format);
118};
119
120/**
121 * Set a new range
122 * If minimumStep is provided, the step size is chosen as close as possible
123 * to the minimumStep but larger than minimumStep. If minimumStep is not
124 * provided, the scale is set to 1 DAY.
125 * The minimumStep should correspond with the onscreen size of about 6 characters
126 * @param {Date} [start] The start date and time.
127 * @param {Date} [end] The end date and time.
128 * @param {int} [minimumStep] Optional. Minimum step size in milliseconds
129 */
130TimeStep.prototype.setRange = function(start, end, minimumStep) {
131 if (!(start instanceof Date) || !(end instanceof Date)) {
132 throw "No legal start or end date in method setRange";
133 }
134
135 this._start = (start != undefined) ? this.moment(start.valueOf()) : new Date();
136 this._end = (end != undefined) ? this.moment(end.valueOf()) : new Date();
137
138 if (this.autoScale) {
139 this.setMinimumStep(minimumStep);
140 }
141};
142
143/**
144 * Set the range iterator to the start date.
145 */
146TimeStep.prototype.start = function() {
147 this.current = this._start.clone();
148 this.roundToMinor();
149};
150
151/**
152 * Round the current date to the first minor date value
153 * This must be executed once when the current date is set to start Date
154 */
155TimeStep.prototype.roundToMinor = function() {
156 // round to floor
157 // to prevent year & month scales rounding down to the first day of week we perform this separately
158 if (this.scale == 'week') {
159 this.current.weekday(0);
160 }
161 // IMPORTANT: we have no breaks in this switch! (this is no bug)
162 // noinspection FallThroughInSwitchStatementJS
163 switch (this.scale) {
164 case 'year':
165 this.current.year(this.step * Math.floor(this.current.year() / this.step));
166 this.current.month(0);
167 case 'quarter': this.current.month(0); // eslint-disable-line no-fallthrough
168 case 'month': this.current.date(1); // eslint-disable-line no-fallthrough
169 case 'week': // eslint-disable-line no-fallthrough
170 case 'day': // eslint-disable-line no-fallthrough
171 case 'weekday': this.current.hours(0); // eslint-disable-line no-fallthrough
172 case 'hour': this.current.minutes(0); // eslint-disable-line no-fallthrough
173 case 'minute': this.current.seconds(0); // eslint-disable-line no-fallthrough
174 case 'second': this.current.milliseconds(0); // eslint-disable-line no-fallthrough
175 //case 'millisecond': // nothing to do for milliseconds
176 }
177
178 if (this.step != 1) {
179 // round down to the first minor value that is a multiple of the current step size
180 switch (this.scale) {
181 case 'millisecond': this.current.subtract(this.current.milliseconds() % this.step, 'milliseconds'); break;
182 case 'second': this.current.subtract(this.current.seconds() % this.step, 'seconds'); break;
183 case 'minute': this.current.subtract(this.current.minutes() % this.step, 'minutes'); break;
184 case 'hour': this.current.subtract(this.current.hours() % this.step, 'hours'); break;
185 case 'weekday': // intentional fall through
186 case 'day': this.current.subtract((this.current.date() - 1) % this.step, 'day'); break;
187 case 'week': this.current.subtract(this.current.week() % this.step, 'week'); break;
188 case 'month': this.current.subtract(this.current.month() % this.step, 'month'); break;
189 case 'quarter': this.current.subtract((this.current.quarter() - 1) % this.step, 'quarter'); break;
190 case 'year': this.current.subtract(this.current.year() % this.step, 'year'); break;
191 default: break;
192 }
193 }
194};
195
196/**
197 * Check if the there is a next step
198 * @return {boolean} true if the current date has not passed the end date
199 */
200TimeStep.prototype.hasNext = function () {
201 return (this.current.valueOf() <= this._end.valueOf());
202};
203
204/**
205 * Do the next step
206 */
207TimeStep.prototype.next = function() {
208 var prev = this.current.valueOf();
209
210 // Two cases, needed to prevent issues with switching daylight savings
211 // (end of March and end of October)
212 switch (this.scale) {
213 case 'millisecond': this.current.add(this.step, 'millisecond'); break;
214 case 'second': this.current.add(this.step, 'second'); break;
215 case 'minute': this.current.add(this.step, 'minute'); break;
216 case 'hour':
217 this.current.add(this.step, 'hour');
218
219 if (this.current.month() < 6) {
220 this.current.subtract(this.current.hours() % this.step, 'hour');
221 } else {
222 if (this.current.hours() % this.step !== 0) {
223 this.current.add(this.step - this.current.hours() % this.step, 'hour');
224 }
225 }
226 break;
227 case 'weekday': // intentional fall through
228 case 'day': this.current.add(this.step, 'day'); break;
229 case 'week':
230 if (this.current.weekday() !== 0){ // we had a month break not correlating with a week's start before
231 this.current.weekday(0); // switch back to week cycles
232 this.current.add(this.step, 'week');
233 } else if(this.options.showMajorLabels === false) {
234 this.current.add(this.step, 'week'); // the default case
235 } else { // first day of the week
236 var nextWeek = this.current.clone();
237 nextWeek.add(1, 'week');
238 if(nextWeek.isSame(this.current, 'month')){ // is the first day of the next week in the same month?
239 this.current.add(this.step, 'week'); // the default case
240 } else { // inject a step at each first day of the month
241 this.current.add(this.step, 'week');
242 this.current.date(1);
243 }
244 }
245 break;
246 case 'month': this.current.add(this.step, 'month'); break;
247 case 'quarter': this.current.add(this.step, 'quarter'); break;
248 case 'year': this.current.add(this.step, 'year'); break;
249 default: break;
250 }
251
252 if (this.step != 1) {
253 // round down to the correct major value
254 switch (this.scale) {
255 case 'millisecond': if(this.current.milliseconds() > 0 && this.current.milliseconds() < this.step) this.current.milliseconds(0); break;
256 case 'second': if(this.current.seconds() > 0 && this.current.seconds() < this.step) this.current.seconds(0); break;
257 case 'minute': if(this.current.minutes() > 0 && this.current.minutes() < this.step) this.current.minutes(0); break;
258 case 'hour': if(this.current.hours() > 0 && this.current.hours() < this.step) this.current.hours(0); break;
259 case 'weekday': // intentional fall through
260 case 'day': if(this.current.date() < this.step+1) this.current.date(1); break;
261 case 'week': if(this.current.week() < this.step) this.current.week(1); break; // week numbering starts at 1, not 0
262 case 'month': if(this.current.month() < this.step) this.current.month(0); break;
263 case 'quarter': if(this.current.quarter() < this.step+1) this.current.quarter(1); break;
264 case 'year': break; // nothing to do for year
265 default: break;
266 }
267 }
268
269 // safety mechanism: if current time is still unchanged, move to the end
270 if (this.current.valueOf() == prev) {
271 this.current = this._end.clone();
272 }
273
274 // Reset switches for year, month and day. Will get set to true where appropriate in DateUtil.stepOverHiddenDates
275 this.switchedDay = false;
276 this.switchedMonth = false;
277 this.switchedYear = false;
278
279 DateUtil.stepOverHiddenDates(this.moment, this, prev);
280};
281
282
283/**
284 * Get the current datetime
285 * @return {Moment} current The current date
286 */
287TimeStep.prototype.getCurrent = function() {
288 return this.current.clone();
289};
290
291/**
292 * Set a custom scale. Autoscaling will be disabled.
293 * For example setScale('minute', 5) will result
294 * in minor steps of 5 minutes, and major steps of an hour.
295 *
296 * @param {{scale: string, step: number}} params
297 * An object containing two properties:
298 * - A string 'scale'. Choose from 'millisecond', 'second',
299 * 'minute', 'hour', 'weekday', 'day', 'week', 'month', 'quarter, 'year'.
300 * - A number 'step'. A step size, by default 1.
301 * Choose for example 1, 2, 5, or 10.
302 */
303TimeStep.prototype.setScale = function(params) {
304 if (params && typeof params.scale == 'string') {
305 this.scale = params.scale;
306 this.step = params.step > 0 ? params.step : 1;
307 this.autoScale = false;
308 }
309};
310
311/**
312 * Enable or disable autoscaling
313 * @param {boolean} enable If true, autoascaling is set true
314 */
315TimeStep.prototype.setAutoScale = function (enable) {
316 this.autoScale = enable;
317};
318
319
320/**
321 * Automatically determine the scale that bests fits the provided minimum step
322 * @param {number} [minimumStep] The minimum step size in milliseconds
323 */
324TimeStep.prototype.setMinimumStep = function(minimumStep) {
325 if (minimumStep == undefined) {
326 return;
327 }
328
329 //var b = asc + ds;
330
331 var stepYear = (1000 * 60 * 60 * 24 * 30 * 12);
332 var stepQuarter = (1000 * 60 * 60 * 24 * 30 * 3);
333 var stepMonth = (1000 * 60 * 60 * 24 * 30);
334 var stepDay = (1000 * 60 * 60 * 24);
335 var stepHour = (1000 * 60 * 60);
336 var stepMinute = (1000 * 60);
337 var stepSecond = (1000);
338 var stepMillisecond= (1);
339
340 // find the smallest step that is larger than the provided minimumStep
341 if (stepYear*1000 > minimumStep) {this.scale = 'year'; this.step = 1000;}
342 if (stepYear*500 > minimumStep) {this.scale = 'year'; this.step = 500;}
343 if (stepYear*100 > minimumStep) {this.scale = 'year'; this.step = 100;}
344 if (stepYear*50 > minimumStep) {this.scale = 'year'; this.step = 50;}
345 if (stepYear*10 > minimumStep) {this.scale = 'year'; this.step = 10;}
346 if (stepYear*5 > minimumStep) {this.scale = 'year'; this.step = 5;}
347 if (stepYear > minimumStep) {this.scale = 'year'; this.step = 1;}
348 if (stepQuarter > minimumStep) {this.scale = 'quarter'; this.step = 1;}
349 if (stepMonth > minimumStep) {this.scale = 'month'; this.step = 1;}
350 if (stepDay*7 > minimumStep) {this.scale = 'week'; this.step = 1;}
351 if (stepDay*2 > minimumStep) {this.scale = 'day'; this.step = 2;}
352 if (stepDay > minimumStep) {this.scale = 'day'; this.step = 1;}
353 if (stepDay/2 > minimumStep) {this.scale = 'weekday'; this.step = 1;}
354 if (stepHour*4 > minimumStep) {this.scale = 'hour'; this.step = 4;}
355 if (stepHour > minimumStep) {this.scale = 'hour'; this.step = 1;}
356 if (stepMinute*15 > minimumStep) {this.scale = 'minute'; this.step = 15;}
357 if (stepMinute*10 > minimumStep) {this.scale = 'minute'; this.step = 10;}
358 if (stepMinute*5 > minimumStep) {this.scale = 'minute'; this.step = 5;}
359 if (stepMinute > minimumStep) {this.scale = 'minute'; this.step = 1;}
360 if (stepSecond*15 > minimumStep) {this.scale = 'second'; this.step = 15;}
361 if (stepSecond*10 > minimumStep) {this.scale = 'second'; this.step = 10;}
362 if (stepSecond*5 > minimumStep) {this.scale = 'second'; this.step = 5;}
363 if (stepSecond > minimumStep) {this.scale = 'second'; this.step = 1;}
364 if (stepMillisecond*200 > minimumStep) {this.scale = 'millisecond'; this.step = 200;}
365 if (stepMillisecond*100 > minimumStep) {this.scale = 'millisecond'; this.step = 100;}
366 if (stepMillisecond*50 > minimumStep) {this.scale = 'millisecond'; this.step = 50;}
367 if (stepMillisecond*10 > minimumStep) {this.scale = 'millisecond'; this.step = 10;}
368 if (stepMillisecond*5 > minimumStep) {this.scale = 'millisecond'; this.step = 5;}
369 if (stepMillisecond > minimumStep) {this.scale = 'millisecond'; this.step = 1;}
370};
371
372/**
373 * Snap a date to a rounded value.
374 * The snap intervals are dependent on the current scale and step.
375 * Static function
376 * @param {Date} date the date to be snapped.
377 * @param {string} scale Current scale, can be 'millisecond', 'second',
378 * 'minute', 'hour', 'weekday, 'day', 'week', 'month', 'quarter', 'year'.
379 * @param {number} step Current step (1, 2, 4, 5, ...
380 * @return {Date} snappedDate
381 */
382TimeStep.snap = function(date, scale, step) {
383 var clone = moment(date);
384
385 if (scale == 'year') {
386 var year = clone.year() + Math.round(clone.month() / 12);
387 clone.year(Math.round(year / step) * step);
388 clone.month(0);
389 clone.date(0);
390 clone.hours(0);
391 clone.minutes(0);
392 clone.seconds(0);
393 clone.milliseconds(0);
394 }
395 else if (scale == 'quarter') {
396 if ((clone.month() % 3 == 1 && clone.date() > 15) || clone.month() % 3 == 2) {
397 clone.date(1);
398 clone.month(Math.floor(clone.month() / 3) * 3);
399 clone.add(1, 'quarter');
400 // important: first set Date to 1, after that change the month and the quarter.
401 } else {
402 clone.date(1);
403 clone.month(Math.floor(clone.month() / 3) * 3);
404 }
405
406 clone.hours(0);
407 clone.minutes(0);
408 clone.seconds(0);
409 clone.milliseconds(0);
410 }
411 else if (scale == 'month') {
412 if (clone.date() > 15) {
413 clone.date(1);
414 clone.add(1, 'month');
415 // important: first set Date to 1, after that change the month.
416 }
417 else {
418 clone.date(1);
419 }
420
421 clone.hours(0);
422 clone.minutes(0);
423 clone.seconds(0);
424 clone.milliseconds(0);
425 }
426 else if (scale == 'week') {
427 if (clone.weekday() > 2) { // doing it the momentjs locale aware way
428 clone.weekday(0);
429 clone.add(1, 'week');
430 }
431 else {
432 clone.weekday(0);
433 }
434
435 clone.hours(0);
436 clone.minutes(0);
437 clone.seconds(0);
438 clone.milliseconds(0);
439 }
440 else if (scale == 'day') {
441 //noinspection FallthroughInSwitchStatementJS
442 switch (step) {
443 case 5:
444 case 2:
445 clone.hours(Math.round(clone.hours() / 24) * 24); break;
446 default:
447 clone.hours(Math.round(clone.hours() / 12) * 12); break;
448 }
449 clone.minutes(0);
450 clone.seconds(0);
451 clone.milliseconds(0);
452 }
453 else if (scale == 'weekday') {
454 //noinspection FallthroughInSwitchStatementJS
455 switch (step) {
456 case 5:
457 case 2:
458 clone.hours(Math.round(clone.hours() / 12) * 12); break;
459 default:
460 clone.hours(Math.round(clone.hours() / 6) * 6); break;
461 }
462 clone.minutes(0);
463 clone.seconds(0);
464 clone.milliseconds(0);
465 }
466 else if (scale == 'hour') {
467 switch (step) {
468 case 4:
469 clone.minutes(Math.round(clone.minutes() / 60) * 60); break;
470 default:
471 clone.minutes(Math.round(clone.minutes() / 30) * 30); break;
472 }
473 clone.seconds(0);
474 clone.milliseconds(0);
475 } else if (scale == 'minute') {
476 //noinspection FallthroughInSwitchStatementJS
477 switch (step) {
478 case 15:
479 case 10:
480 clone.minutes(Math.round(clone.minutes() / 5) * 5);
481 clone.seconds(0);
482 break;
483 case 5:
484 clone.seconds(Math.round(clone.seconds() / 60) * 60); break;
485 default:
486 clone.seconds(Math.round(clone.seconds() / 30) * 30); break;
487 }
488 clone.milliseconds(0);
489 }
490 else if (scale == 'second') {
491 //noinspection FallthroughInSwitchStatementJS
492 switch (step) {
493 case 15:
494 case 10:
495 clone.seconds(Math.round(clone.seconds() / 5) * 5);
496 clone.milliseconds(0);
497 break;
498 case 5:
499 clone.milliseconds(Math.round(clone.milliseconds() / 1000) * 1000); break;
500 default:
501 clone.milliseconds(Math.round(clone.milliseconds() / 500) * 500); break;
502 }
503 }
504 else if (scale == 'millisecond') {
505 var _step = step > 5 ? step / 2 : 1;
506 clone.milliseconds(Math.round(clone.milliseconds() / _step) * _step);
507 }
508
509 return clone;
510};
511
512/**
513 * Check if the current value is a major value (for example when the step
514 * is DAY, a major value is each first day of the MONTH)
515 * @return {boolean} true if current date is major, else false.
516 */
517TimeStep.prototype.isMajor = function() {
518 if (this.switchedYear == true) {
519 switch (this.scale) {
520 case 'year':
521 case 'quarter':
522 case 'month':
523 case 'week':
524 case 'weekday':
525 case 'day':
526 case 'hour':
527 case 'minute':
528 case 'second':
529 case 'millisecond':
530 return true;
531 default:
532 return false;
533 }
534 }
535 else if (this.switchedMonth == true) {
536 switch (this.scale) {
537 case 'week':
538 case 'weekday':
539 case 'day':
540 case 'hour':
541 case 'minute':
542 case 'second':
543 case 'millisecond':
544 return true;
545 default:
546 return false;
547 }
548 }
549 else if (this.switchedDay == true) {
550 switch (this.scale) {
551 case 'millisecond':
552 case 'second':
553 case 'minute':
554 case 'hour':
555 return true;
556 default:
557 return false;
558 }
559 }
560
561 var date = this.moment(this.current);
562 switch (this.scale) {
563 case 'millisecond':
564 return (date.milliseconds() == 0);
565 case 'second':
566 return (date.seconds() == 0);
567 case 'minute':
568 return (date.hours() == 0) && (date.minutes() == 0);
569 case 'hour':
570 return (date.hours() == 0);
571 case 'weekday': // intentional fall through
572 case 'day':
573 return (date.date() == 1);
574 case 'week':
575 return (date.date() == 1);
576 case 'month':
577 return (date.month() == 0);
578 case 'quarter':
579 return (date.quarter() == 1);
580 case 'year':
581 return false;
582 default:
583 return false;
584 }
585};
586
587
588/**
589 * Returns formatted text for the minor axislabel, depending on the current
590 * date and the scale. For example when scale is MINUTE, the current time is
591 * formatted as "hh:mm".
592 * @param {Date} [date=this.current] custom date. if not provided, current date is taken
593 * @returns {String}
594 */
595TimeStep.prototype.getLabelMinor = function(date) {
596 if (date == undefined) {
597 date = this.current;
598 }
599 if (date instanceof Date) {
600 date = this.moment(date)
601 }
602
603 if (typeof(this.format.minorLabels) === "function") {
604 return this.format.minorLabels(date, this.scale, this.step);
605 }
606
607 var format = this.format.minorLabels[this.scale];
608 // noinspection FallThroughInSwitchStatementJS
609 switch (this.scale) {
610 case 'week':
611 if(this.isMajor() && date.weekday() !== 0){
612 return "";
613 }
614 default: // eslint-disable-line no-fallthrough
615 return (format && format.length > 0) ? this.moment(date).format(format) : '';
616 }
617};
618
619/**
620 * Returns formatted text for the major axis label, depending on the current
621 * date and the scale. For example when scale is MINUTE, the major scale is
622 * hours, and the hour will be formatted as "hh".
623 * @param {Date} [date=this.current] custom date. if not provided, current date is taken
624 * @returns {String}
625 */
626TimeStep.prototype.getLabelMajor = function(date) {
627 if (date == undefined) {
628 date = this.current;
629 }
630 if (date instanceof Date) {
631 date = this.moment(date)
632 }
633
634 if (typeof(this.format.majorLabels) === "function") {
635 return this.format.majorLabels(date, this.scale, this.step);
636 }
637
638 var format = this.format.majorLabels[this.scale];
639 return (format && format.length > 0) ? this.moment(date).format(format) : '';
640};
641
642TimeStep.prototype.getClassName = function() {
643 var _moment = this.moment;
644 var m = this.moment(this.current);
645 var current = m.locale ? m.locale('en') : m.lang('en'); // old versions of moment have .lang() function
646 var step = this.step;
647 var classNames = [];
648
649 /**
650 *
651 * @param {number} value
652 * @returns {String}
653 */
654 function even(value) {
655 return (value / step % 2 == 0) ? ' vis-even' : ' vis-odd';
656 }
657
658 /**
659 *
660 * @param {Date} date
661 * @returns {String}
662 */
663 function today(date) {
664 if (date.isSame(new Date(), 'day')) {
665 return ' vis-today';
666 }
667 if (date.isSame(_moment().add(1, 'day'), 'day')) {
668 return ' vis-tomorrow';
669 }
670 if (date.isSame(_moment().add(-1, 'day'), 'day')) {
671 return ' vis-yesterday';
672 }
673 return '';
674 }
675
676 /**
677 *
678 * @param {Date} date
679 * @returns {String}
680 */
681 function currentWeek(date) {
682 return date.isSame(new Date(), 'week') ? ' vis-current-week' : '';
683 }
684
685 /**
686 *
687 * @param {Date} date
688 * @returns {String}
689 */
690 function currentMonth(date) {
691 return date.isSame(new Date(), 'month') ? ' vis-current-month' : '';
692 }
693
694 /**
695 *
696 * @param {Date} date
697 * @returns {String}
698 */
699 function currentQuarter(date) {
700 return date.isSame(new Date(), 'quarter') ? ' vis-current-quarter' : '';
701 }
702
703 /**
704 *
705 * @param {Date} date
706 * @returns {String}
707 */
708 function currentYear(date) {
709 return date.isSame(new Date(), 'year') ? ' vis-current-year' : '';
710 }
711
712 switch (this.scale) {
713 case 'millisecond':
714 classNames.push(today(current));
715 classNames.push(even(current.milliseconds()));
716 break;
717 case 'second':
718 classNames.push(today(current));
719 classNames.push(even(current.seconds()));
720 break;
721 case 'minute':
722 classNames.push(today(current));
723 classNames.push(even(current.minutes()));
724 break;
725 case 'hour':
726 classNames.push('vis-h' + current.hours() + (this.step == 4 ? '-h' + (current.hours() + 4) : ''));
727 classNames.push(today(current));
728 classNames.push(even(current.hours()));
729 break;
730 case 'weekday':
731 classNames.push('vis-' + current.format('dddd').toLowerCase());
732 classNames.push(today(current));
733 classNames.push(currentWeek(current));
734 classNames.push(even(current.date()));
735 break;
736 case 'day':
737 classNames.push('vis-day' + current.date());
738 classNames.push('vis-' + current.format('MMMM').toLowerCase());
739 classNames.push(today(current));
740 classNames.push(currentMonth(current));
741 classNames.push(this.step <= 2 ? today(current) : '');
742 classNames.push(this.step <= 2 ? 'vis-' + current.format('dddd').toLowerCase() : '');
743 classNames.push(even(current.date() - 1));
744 break;
745 case 'week':
746 classNames.push('vis-week' + current.format('w'));
747 classNames.push(currentWeek(current));
748 classNames.push(even(current.week()));
749 break;
750 case 'month':
751 classNames.push('vis-' + current.format('MMMM').toLowerCase());
752 classNames.push(currentMonth(current));
753 classNames.push(even(current.month()));
754 break;
755 case 'quarter':
756 classNames.push('vis-q' + current.quarter());
757 classNames.push(currentQuarter(current));
758 classNames.push(even(current.quarter()));
759 break;
760 case 'year':
761 classNames.push('vis-year' + current.year());
762 classNames.push(currentYear(current));
763 classNames.push(even(current.year()));
764 break;
765 }
766 return classNames.filter(String).join(" ");
767};
768
769module.exports = TimeStep;