vis-rails 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.gitmodules +3 -0
  4. data/.project +11 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +202 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/lib/vis/rails/engine.rb +6 -0
  10. data/lib/vis/rails/version.rb +5 -0
  11. data/lib/vis/rails.rb +7 -0
  12. data/vendor/assets/javascripts/vis.js +1 -0
  13. data/vendor/assets/stylesheets/vis.css +3 -0
  14. data/vendor/assets/vis/DataSet.js +936 -0
  15. data/vendor/assets/vis/DataView.js +281 -0
  16. data/vendor/assets/vis/EventBus.js +89 -0
  17. data/vendor/assets/vis/events.js +116 -0
  18. data/vendor/assets/vis/graph/ClusterMixin.js +1019 -0
  19. data/vendor/assets/vis/graph/Edge.js +620 -0
  20. data/vendor/assets/vis/graph/Graph.js +2111 -0
  21. data/vendor/assets/vis/graph/Groups.js +80 -0
  22. data/vendor/assets/vis/graph/Images.js +41 -0
  23. data/vendor/assets/vis/graph/NavigationMixin.js +245 -0
  24. data/vendor/assets/vis/graph/Node.js +978 -0
  25. data/vendor/assets/vis/graph/Popup.js +105 -0
  26. data/vendor/assets/vis/graph/SectorsMixin.js +547 -0
  27. data/vendor/assets/vis/graph/SelectionMixin.js +515 -0
  28. data/vendor/assets/vis/graph/dotparser.js +829 -0
  29. data/vendor/assets/vis/graph/img/downarrow.png +0 -0
  30. data/vendor/assets/vis/graph/img/leftarrow.png +0 -0
  31. data/vendor/assets/vis/graph/img/minus.png +0 -0
  32. data/vendor/assets/vis/graph/img/plus.png +0 -0
  33. data/vendor/assets/vis/graph/img/rightarrow.png +0 -0
  34. data/vendor/assets/vis/graph/img/uparrow.png +0 -0
  35. data/vendor/assets/vis/graph/img/zoomExtends.png +0 -0
  36. data/vendor/assets/vis/graph/shapes.js +225 -0
  37. data/vendor/assets/vis/module/exports.js +68 -0
  38. data/vendor/assets/vis/module/header.js +24 -0
  39. data/vendor/assets/vis/module/imports.js +32 -0
  40. data/vendor/assets/vis/shim.js +252 -0
  41. data/vendor/assets/vis/timeline/Controller.js +172 -0
  42. data/vendor/assets/vis/timeline/Range.js +553 -0
  43. data/vendor/assets/vis/timeline/Stack.js +192 -0
  44. data/vendor/assets/vis/timeline/TimeStep.js +449 -0
  45. data/vendor/assets/vis/timeline/Timeline.js +476 -0
  46. data/vendor/assets/vis/timeline/component/Component.js +148 -0
  47. data/vendor/assets/vis/timeline/component/ContentPanel.js +113 -0
  48. data/vendor/assets/vis/timeline/component/CurrentTime.js +101 -0
  49. data/vendor/assets/vis/timeline/component/CustomTime.js +255 -0
  50. data/vendor/assets/vis/timeline/component/Group.js +129 -0
  51. data/vendor/assets/vis/timeline/component/GroupSet.js +546 -0
  52. data/vendor/assets/vis/timeline/component/ItemSet.js +612 -0
  53. data/vendor/assets/vis/timeline/component/Panel.js +112 -0
  54. data/vendor/assets/vis/timeline/component/RootPanel.js +215 -0
  55. data/vendor/assets/vis/timeline/component/TimeAxis.js +522 -0
  56. data/vendor/assets/vis/timeline/component/css/currenttime.css +5 -0
  57. data/vendor/assets/vis/timeline/component/css/customtime.css +6 -0
  58. data/vendor/assets/vis/timeline/component/css/groupset.css +59 -0
  59. data/vendor/assets/vis/timeline/component/css/item.css +93 -0
  60. data/vendor/assets/vis/timeline/component/css/itemset.css +17 -0
  61. data/vendor/assets/vis/timeline/component/css/panel.css +14 -0
  62. data/vendor/assets/vis/timeline/component/css/timeaxis.css +41 -0
  63. data/vendor/assets/vis/timeline/component/css/timeline.css +2 -0
  64. data/vendor/assets/vis/timeline/component/item/Item.js +81 -0
  65. data/vendor/assets/vis/timeline/component/item/ItemBox.js +302 -0
  66. data/vendor/assets/vis/timeline/component/item/ItemPoint.js +237 -0
  67. data/vendor/assets/vis/timeline/component/item/ItemRange.js +251 -0
  68. data/vendor/assets/vis/timeline/component/item/ItemRangeOverflow.js +91 -0
  69. data/vendor/assets/vis/util.js +673 -0
  70. data/vis-rails.gemspec +47 -0
  71. metadata +142 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * @constructor Stack
3
+ * Stacks items on top of each other.
4
+ * @param {ItemSet} parent
5
+ * @param {Object} [options]
6
+ */
7
+ function Stack (parent, options) {
8
+ this.parent = parent;
9
+
10
+ this.options = options || {};
11
+ this.defaultOptions = {
12
+ order: function (a, b) {
13
+ //return (b.width - a.width) || (a.left - b.left); // TODO: cleanup
14
+ // Order: ranges over non-ranges, ranged ordered by width, and
15
+ // lastly ordered by start.
16
+ if (a instanceof ItemRange) {
17
+ if (b instanceof ItemRange) {
18
+ var aInt = (a.data.end - a.data.start);
19
+ var bInt = (b.data.end - b.data.start);
20
+ return (aInt - bInt) || (a.data.start - b.data.start);
21
+ }
22
+ else {
23
+ return -1;
24
+ }
25
+ }
26
+ else {
27
+ if (b instanceof ItemRange) {
28
+ return 1;
29
+ }
30
+ else {
31
+ return (a.data.start - b.data.start);
32
+ }
33
+ }
34
+ },
35
+ margin: {
36
+ item: 10
37
+ }
38
+ };
39
+
40
+ this.ordered = []; // ordered items
41
+ }
42
+
43
+ /**
44
+ * Set options for the stack
45
+ * @param {Object} options Available options:
46
+ * {ItemSet} parent
47
+ * {Number} margin
48
+ * {function} order Stacking order
49
+ */
50
+ Stack.prototype.setOptions = function setOptions (options) {
51
+ util.extend(this.options, options);
52
+
53
+ // TODO: register on data changes at the connected parent itemset, and update the changed part only and immediately
54
+ };
55
+
56
+ /**
57
+ * Stack the items such that they don't overlap. The items will have a minimal
58
+ * distance equal to options.margin.item.
59
+ */
60
+ Stack.prototype.update = function update() {
61
+ this._order();
62
+ this._stack();
63
+ };
64
+
65
+ /**
66
+ * Order the items. The items are ordered by width first, and by left position
67
+ * second.
68
+ * If a custom order function has been provided via the options, then this will
69
+ * be used.
70
+ * @private
71
+ */
72
+ Stack.prototype._order = function _order () {
73
+ var items = this.parent.items;
74
+ if (!items) {
75
+ throw new Error('Cannot stack items: parent does not contain items');
76
+ }
77
+
78
+ // TODO: store the sorted items, to have less work later on
79
+ var ordered = [];
80
+ var index = 0;
81
+ // items is a map (no array)
82
+ util.forEach(items, function (item) {
83
+ if (item.visible) {
84
+ ordered[index] = item;
85
+ index++;
86
+ }
87
+ });
88
+
89
+ //if a customer stack order function exists, use it.
90
+ var order = this.options.order || this.defaultOptions.order;
91
+ if (!(typeof order === 'function')) {
92
+ throw new Error('Option order must be a function');
93
+ }
94
+
95
+ ordered.sort(order);
96
+
97
+ this.ordered = ordered;
98
+ };
99
+
100
+ /**
101
+ * Adjust vertical positions of the events such that they don't overlap each
102
+ * other.
103
+ * @private
104
+ */
105
+ Stack.prototype._stack = function _stack () {
106
+ var i,
107
+ iMax,
108
+ ordered = this.ordered,
109
+ options = this.options,
110
+ orientation = options.orientation || this.defaultOptions.orientation,
111
+ axisOnTop = (orientation == 'top'),
112
+ margin;
113
+
114
+ if (options.margin && options.margin.item !== undefined) {
115
+ margin = options.margin.item;
116
+ }
117
+ else {
118
+ margin = this.defaultOptions.margin.item
119
+ }
120
+
121
+ // calculate new, non-overlapping positions
122
+ for (i = 0, iMax = ordered.length; i < iMax; i++) {
123
+ var item = ordered[i];
124
+ var collidingItem = null;
125
+ do {
126
+ // TODO: optimize checking for overlap. when there is a gap without items,
127
+ // you only need to check for items from the next item on, not from zero
128
+ collidingItem = this.checkOverlap(ordered, i, 0, i - 1, margin);
129
+ if (collidingItem != null) {
130
+ // There is a collision. Reposition the event above the colliding element
131
+ if (axisOnTop) {
132
+ item.top = collidingItem.top + collidingItem.height + margin;
133
+ }
134
+ else {
135
+ item.top = collidingItem.top - item.height - margin;
136
+ }
137
+ }
138
+ } while (collidingItem);
139
+ }
140
+ };
141
+
142
+ /**
143
+ * Check if the destiny position of given item overlaps with any
144
+ * of the other items from index itemStart to itemEnd.
145
+ * @param {Array} items Array with items
146
+ * @param {int} itemIndex Number of the item to be checked for overlap
147
+ * @param {int} itemStart First item to be checked.
148
+ * @param {int} itemEnd Last item to be checked.
149
+ * @return {Object | null} colliding item, or undefined when no collisions
150
+ * @param {Number} margin A minimum required margin.
151
+ * If margin is provided, the two items will be
152
+ * marked colliding when they overlap or
153
+ * when the margin between the two is smaller than
154
+ * the requested margin.
155
+ */
156
+ Stack.prototype.checkOverlap = function checkOverlap (items, itemIndex,
157
+ itemStart, itemEnd, margin) {
158
+ var collision = this.collision;
159
+
160
+ // we loop from end to start, as we suppose that the chance of a
161
+ // collision is larger for items at the end, so check these first.
162
+ var a = items[itemIndex];
163
+ for (var i = itemEnd; i >= itemStart; i--) {
164
+ var b = items[i];
165
+ if (collision(a, b, margin)) {
166
+ if (i != itemIndex) {
167
+ return b;
168
+ }
169
+ }
170
+ }
171
+
172
+ return null;
173
+ };
174
+
175
+ /**
176
+ * Test if the two provided items collide
177
+ * The items must have parameters left, width, top, and height.
178
+ * @param {Component} a The first item
179
+ * @param {Component} b The second item
180
+ * @param {Number} margin A minimum required margin.
181
+ * If margin is provided, the two items will be
182
+ * marked colliding when they overlap or
183
+ * when the margin between the two is smaller than
184
+ * the requested margin.
185
+ * @return {boolean} true if a and b collide, else false
186
+ */
187
+ Stack.prototype.collision = function collision (a, b, margin) {
188
+ return ((a.left - margin) < (b.left + b.getWidth()) &&
189
+ (a.left + a.getWidth() + margin) > b.left &&
190
+ (a.top - margin) < (b.top + b.height) &&
191
+ (a.top + a.height + margin) > b.top);
192
+ };
@@ -0,0 +1,449 @@
1
+ /**
2
+ * @constructor TimeStep
3
+ * The class TimeStep is an iterator for dates. You provide a start date and an
4
+ * end date. The class itself determines the best scale (step size) based on the
5
+ * provided start Date, end Date, and minimumStep.
6
+ *
7
+ * If minimumStep is provided, the step size is chosen as close as possible
8
+ * to the minimumStep but larger than minimumStep. If minimumStep is not
9
+ * provided, the scale is set to 1 DAY.
10
+ * The minimumStep should correspond with the onscreen size of about 6 characters
11
+ *
12
+ * Alternatively, you can set a scale by hand.
13
+ * After creation, you can initialize the class by executing first(). Then you
14
+ * can iterate from the start date to the end date via next(). You can check if
15
+ * the end date is reached with the function hasNext(). After each step, you can
16
+ * retrieve the current date via getCurrent().
17
+ * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours,
18
+ * days, to years.
19
+ *
20
+ * Version: 1.2
21
+ *
22
+ * @param {Date} [start] The start date, for example new Date(2010, 9, 21)
23
+ * or new Date(2010, 9, 21, 23, 45, 00)
24
+ * @param {Date} [end] The end date
25
+ * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds
26
+ */
27
+ TimeStep = function(start, end, minimumStep) {
28
+ // variables
29
+ this.current = new Date();
30
+ this._start = new Date();
31
+ this._end = new Date();
32
+
33
+ this.autoScale = true;
34
+ this.scale = TimeStep.SCALE.DAY;
35
+ this.step = 1;
36
+
37
+ // initialize the range
38
+ this.setRange(start, end, minimumStep);
39
+ };
40
+
41
+ /// enum scale
42
+ TimeStep.SCALE = {
43
+ MILLISECOND: 1,
44
+ SECOND: 2,
45
+ MINUTE: 3,
46
+ HOUR: 4,
47
+ DAY: 5,
48
+ WEEKDAY: 6,
49
+ MONTH: 7,
50
+ YEAR: 8
51
+ };
52
+
53
+
54
+ /**
55
+ * Set a new range
56
+ * If minimumStep is provided, the step size is chosen as close as possible
57
+ * to the minimumStep but larger than minimumStep. If minimumStep is not
58
+ * provided, the scale is set to 1 DAY.
59
+ * The minimumStep should correspond with the onscreen size of about 6 characters
60
+ * @param {Date} [start] The start date and time.
61
+ * @param {Date} [end] The end date and time.
62
+ * @param {int} [minimumStep] Optional. Minimum step size in milliseconds
63
+ */
64
+ TimeStep.prototype.setRange = function(start, end, minimumStep) {
65
+ if (!(start instanceof Date) || !(end instanceof Date)) {
66
+ throw "No legal start or end date in method setRange";
67
+ }
68
+
69
+ this._start = (start != undefined) ? new Date(start.valueOf()) : new Date();
70
+ this._end = (end != undefined) ? new Date(end.valueOf()) : new Date();
71
+
72
+ if (this.autoScale) {
73
+ this.setMinimumStep(minimumStep);
74
+ }
75
+ };
76
+
77
+ /**
78
+ * Set the range iterator to the start date.
79
+ */
80
+ TimeStep.prototype.first = function() {
81
+ this.current = new Date(this._start.valueOf());
82
+ this.roundToMinor();
83
+ };
84
+
85
+ /**
86
+ * Round the current date to the first minor date value
87
+ * This must be executed once when the current date is set to start Date
88
+ */
89
+ TimeStep.prototype.roundToMinor = function() {
90
+ // round to floor
91
+ // IMPORTANT: we have no breaks in this switch! (this is no bug)
92
+ //noinspection FallthroughInSwitchStatementJS
93
+ switch (this.scale) {
94
+ case TimeStep.SCALE.YEAR:
95
+ this.current.setFullYear(this.step * Math.floor(this.current.getFullYear() / this.step));
96
+ this.current.setMonth(0);
97
+ case TimeStep.SCALE.MONTH: this.current.setDate(1);
98
+ case TimeStep.SCALE.DAY: // intentional fall through
99
+ case TimeStep.SCALE.WEEKDAY: this.current.setHours(0);
100
+ case TimeStep.SCALE.HOUR: this.current.setMinutes(0);
101
+ case TimeStep.SCALE.MINUTE: this.current.setSeconds(0);
102
+ case TimeStep.SCALE.SECOND: this.current.setMilliseconds(0);
103
+ //case TimeStep.SCALE.MILLISECOND: // nothing to do for milliseconds
104
+ }
105
+
106
+ if (this.step != 1) {
107
+ // round down to the first minor value that is a multiple of the current step size
108
+ switch (this.scale) {
109
+ case TimeStep.SCALE.MILLISECOND: this.current.setMilliseconds(this.current.getMilliseconds() - this.current.getMilliseconds() % this.step); break;
110
+ case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() - this.current.getSeconds() % this.step); break;
111
+ case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() - this.current.getMinutes() % this.step); break;
112
+ case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() - this.current.getHours() % this.step); break;
113
+ case TimeStep.SCALE.WEEKDAY: // intentional fall through
114
+ case TimeStep.SCALE.DAY: this.current.setDate((this.current.getDate()-1) - (this.current.getDate()-1) % this.step + 1); break;
115
+ case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() - this.current.getMonth() % this.step); break;
116
+ case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() - this.current.getFullYear() % this.step); break;
117
+ default: break;
118
+ }
119
+ }
120
+ };
121
+
122
+ /**
123
+ * Check if the there is a next step
124
+ * @return {boolean} true if the current date has not passed the end date
125
+ */
126
+ TimeStep.prototype.hasNext = function () {
127
+ return (this.current.valueOf() <= this._end.valueOf());
128
+ };
129
+
130
+ /**
131
+ * Do the next step
132
+ */
133
+ TimeStep.prototype.next = function() {
134
+ var prev = this.current.valueOf();
135
+
136
+ // Two cases, needed to prevent issues with switching daylight savings
137
+ // (end of March and end of October)
138
+ if (this.current.getMonth() < 6) {
139
+ switch (this.scale) {
140
+ case TimeStep.SCALE.MILLISECOND:
141
+
142
+ this.current = new Date(this.current.valueOf() + this.step); break;
143
+ case TimeStep.SCALE.SECOND: this.current = new Date(this.current.valueOf() + this.step * 1000); break;
144
+ case TimeStep.SCALE.MINUTE: this.current = new Date(this.current.valueOf() + this.step * 1000 * 60); break;
145
+ case TimeStep.SCALE.HOUR:
146
+ this.current = new Date(this.current.valueOf() + this.step * 1000 * 60 * 60);
147
+ // in case of skipping an hour for daylight savings, adjust the hour again (else you get: 0h 5h 9h ... instead of 0h 4h 8h ...)
148
+ var h = this.current.getHours();
149
+ this.current.setHours(h - (h % this.step));
150
+ break;
151
+ case TimeStep.SCALE.WEEKDAY: // intentional fall through
152
+ case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break;
153
+ case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break;
154
+ case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break;
155
+ default: break;
156
+ }
157
+ }
158
+ else {
159
+ switch (this.scale) {
160
+ case TimeStep.SCALE.MILLISECOND: this.current = new Date(this.current.valueOf() + this.step); break;
161
+ case TimeStep.SCALE.SECOND: this.current.setSeconds(this.current.getSeconds() + this.step); break;
162
+ case TimeStep.SCALE.MINUTE: this.current.setMinutes(this.current.getMinutes() + this.step); break;
163
+ case TimeStep.SCALE.HOUR: this.current.setHours(this.current.getHours() + this.step); break;
164
+ case TimeStep.SCALE.WEEKDAY: // intentional fall through
165
+ case TimeStep.SCALE.DAY: this.current.setDate(this.current.getDate() + this.step); break;
166
+ case TimeStep.SCALE.MONTH: this.current.setMonth(this.current.getMonth() + this.step); break;
167
+ case TimeStep.SCALE.YEAR: this.current.setFullYear(this.current.getFullYear() + this.step); break;
168
+ default: break;
169
+ }
170
+ }
171
+
172
+ if (this.step != 1) {
173
+ // round down to the correct major value
174
+ switch (this.scale) {
175
+ case TimeStep.SCALE.MILLISECOND: if(this.current.getMilliseconds() < this.step) this.current.setMilliseconds(0); break;
176
+ case TimeStep.SCALE.SECOND: if(this.current.getSeconds() < this.step) this.current.setSeconds(0); break;
177
+ case TimeStep.SCALE.MINUTE: if(this.current.getMinutes() < this.step) this.current.setMinutes(0); break;
178
+ case TimeStep.SCALE.HOUR: if(this.current.getHours() < this.step) this.current.setHours(0); break;
179
+ case TimeStep.SCALE.WEEKDAY: // intentional fall through
180
+ case TimeStep.SCALE.DAY: if(this.current.getDate() < this.step+1) this.current.setDate(1); break;
181
+ case TimeStep.SCALE.MONTH: if(this.current.getMonth() < this.step) this.current.setMonth(0); break;
182
+ case TimeStep.SCALE.YEAR: break; // nothing to do for year
183
+ default: break;
184
+ }
185
+ }
186
+
187
+ // safety mechanism: if current time is still unchanged, move to the end
188
+ if (this.current.valueOf() == prev) {
189
+ this.current = new Date(this._end.valueOf());
190
+ }
191
+ };
192
+
193
+
194
+ /**
195
+ * Get the current datetime
196
+ * @return {Date} current The current date
197
+ */
198
+ TimeStep.prototype.getCurrent = function() {
199
+ return this.current;
200
+ };
201
+
202
+ /**
203
+ * Set a custom scale. Autoscaling will be disabled.
204
+ * For example setScale(SCALE.MINUTES, 5) will result
205
+ * in minor steps of 5 minutes, and major steps of an hour.
206
+ *
207
+ * @param {TimeStep.SCALE} newScale
208
+ * A scale. Choose from SCALE.MILLISECOND,
209
+ * SCALE.SECOND, SCALE.MINUTE, SCALE.HOUR,
210
+ * SCALE.WEEKDAY, SCALE.DAY, SCALE.MONTH,
211
+ * SCALE.YEAR.
212
+ * @param {Number} newStep A step size, by default 1. Choose for
213
+ * example 1, 2, 5, or 10.
214
+ */
215
+ TimeStep.prototype.setScale = function(newScale, newStep) {
216
+ this.scale = newScale;
217
+
218
+ if (newStep > 0) {
219
+ this.step = newStep;
220
+ }
221
+
222
+ this.autoScale = false;
223
+ };
224
+
225
+ /**
226
+ * Enable or disable autoscaling
227
+ * @param {boolean} enable If true, autoascaling is set true
228
+ */
229
+ TimeStep.prototype.setAutoScale = function (enable) {
230
+ this.autoScale = enable;
231
+ };
232
+
233
+
234
+ /**
235
+ * Automatically determine the scale that bests fits the provided minimum step
236
+ * @param {Number} [minimumStep] The minimum step size in milliseconds
237
+ */
238
+ TimeStep.prototype.setMinimumStep = function(minimumStep) {
239
+ if (minimumStep == undefined) {
240
+ return;
241
+ }
242
+
243
+ var stepYear = (1000 * 60 * 60 * 24 * 30 * 12);
244
+ var stepMonth = (1000 * 60 * 60 * 24 * 30);
245
+ var stepDay = (1000 * 60 * 60 * 24);
246
+ var stepHour = (1000 * 60 * 60);
247
+ var stepMinute = (1000 * 60);
248
+ var stepSecond = (1000);
249
+ var stepMillisecond= (1);
250
+
251
+ // find the smallest step that is larger than the provided minimumStep
252
+ if (stepYear*1000 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1000;}
253
+ if (stepYear*500 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 500;}
254
+ if (stepYear*100 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 100;}
255
+ if (stepYear*50 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 50;}
256
+ if (stepYear*10 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 10;}
257
+ if (stepYear*5 > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 5;}
258
+ if (stepYear > minimumStep) {this.scale = TimeStep.SCALE.YEAR; this.step = 1;}
259
+ if (stepMonth*3 > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 3;}
260
+ if (stepMonth > minimumStep) {this.scale = TimeStep.SCALE.MONTH; this.step = 1;}
261
+ if (stepDay*5 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 5;}
262
+ if (stepDay*2 > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 2;}
263
+ if (stepDay > minimumStep) {this.scale = TimeStep.SCALE.DAY; this.step = 1;}
264
+ if (stepDay/2 > minimumStep) {this.scale = TimeStep.SCALE.WEEKDAY; this.step = 1;}
265
+ if (stepHour*4 > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 4;}
266
+ if (stepHour > minimumStep) {this.scale = TimeStep.SCALE.HOUR; this.step = 1;}
267
+ if (stepMinute*15 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 15;}
268
+ if (stepMinute*10 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 10;}
269
+ if (stepMinute*5 > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 5;}
270
+ if (stepMinute > minimumStep) {this.scale = TimeStep.SCALE.MINUTE; this.step = 1;}
271
+ if (stepSecond*15 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 15;}
272
+ if (stepSecond*10 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 10;}
273
+ if (stepSecond*5 > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 5;}
274
+ if (stepSecond > minimumStep) {this.scale = TimeStep.SCALE.SECOND; this.step = 1;}
275
+ if (stepMillisecond*200 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 200;}
276
+ if (stepMillisecond*100 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 100;}
277
+ if (stepMillisecond*50 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 50;}
278
+ if (stepMillisecond*10 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 10;}
279
+ if (stepMillisecond*5 > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 5;}
280
+ if (stepMillisecond > minimumStep) {this.scale = TimeStep.SCALE.MILLISECOND; this.step = 1;}
281
+ };
282
+
283
+ /**
284
+ * Snap a date to a rounded value. The snap intervals are dependent on the
285
+ * current scale and step.
286
+ * @param {Date} date the date to be snapped
287
+ */
288
+ TimeStep.prototype.snap = function(date) {
289
+ if (this.scale == TimeStep.SCALE.YEAR) {
290
+ var year = date.getFullYear() + Math.round(date.getMonth() / 12);
291
+ date.setFullYear(Math.round(year / this.step) * this.step);
292
+ date.setMonth(0);
293
+ date.setDate(0);
294
+ date.setHours(0);
295
+ date.setMinutes(0);
296
+ date.setSeconds(0);
297
+ date.setMilliseconds(0);
298
+ }
299
+ else if (this.scale == TimeStep.SCALE.MONTH) {
300
+ if (date.getDate() > 15) {
301
+ date.setDate(1);
302
+ date.setMonth(date.getMonth() + 1);
303
+ // important: first set Date to 1, after that change the month.
304
+ }
305
+ else {
306
+ date.setDate(1);
307
+ }
308
+
309
+ date.setHours(0);
310
+ date.setMinutes(0);
311
+ date.setSeconds(0);
312
+ date.setMilliseconds(0);
313
+ }
314
+ else if (this.scale == TimeStep.SCALE.DAY ||
315
+ this.scale == TimeStep.SCALE.WEEKDAY) {
316
+ //noinspection FallthroughInSwitchStatementJS
317
+ switch (this.step) {
318
+ case 5:
319
+ case 2:
320
+ date.setHours(Math.round(date.getHours() / 24) * 24); break;
321
+ default:
322
+ date.setHours(Math.round(date.getHours() / 12) * 12); break;
323
+ }
324
+ date.setMinutes(0);
325
+ date.setSeconds(0);
326
+ date.setMilliseconds(0);
327
+ }
328
+ else if (this.scale == TimeStep.SCALE.HOUR) {
329
+ switch (this.step) {
330
+ case 4:
331
+ date.setMinutes(Math.round(date.getMinutes() / 60) * 60); break;
332
+ default:
333
+ date.setMinutes(Math.round(date.getMinutes() / 30) * 30); break;
334
+ }
335
+ date.setSeconds(0);
336
+ date.setMilliseconds(0);
337
+ } else if (this.scale == TimeStep.SCALE.MINUTE) {
338
+ //noinspection FallthroughInSwitchStatementJS
339
+ switch (this.step) {
340
+ case 15:
341
+ case 10:
342
+ date.setMinutes(Math.round(date.getMinutes() / 5) * 5);
343
+ date.setSeconds(0);
344
+ break;
345
+ case 5:
346
+ date.setSeconds(Math.round(date.getSeconds() / 60) * 60); break;
347
+ default:
348
+ date.setSeconds(Math.round(date.getSeconds() / 30) * 30); break;
349
+ }
350
+ date.setMilliseconds(0);
351
+ }
352
+ else if (this.scale == TimeStep.SCALE.SECOND) {
353
+ //noinspection FallthroughInSwitchStatementJS
354
+ switch (this.step) {
355
+ case 15:
356
+ case 10:
357
+ date.setSeconds(Math.round(date.getSeconds() / 5) * 5);
358
+ date.setMilliseconds(0);
359
+ break;
360
+ case 5:
361
+ date.setMilliseconds(Math.round(date.getMilliseconds() / 1000) * 1000); break;
362
+ default:
363
+ date.setMilliseconds(Math.round(date.getMilliseconds() / 500) * 500); break;
364
+ }
365
+ }
366
+ else if (this.scale == TimeStep.SCALE.MILLISECOND) {
367
+ var step = this.step > 5 ? this.step / 2 : 1;
368
+ date.setMilliseconds(Math.round(date.getMilliseconds() / step) * step);
369
+ }
370
+ };
371
+
372
+ /**
373
+ * Check if the current value is a major value (for example when the step
374
+ * is DAY, a major value is each first day of the MONTH)
375
+ * @return {boolean} true if current date is major, else false.
376
+ */
377
+ TimeStep.prototype.isMajor = function() {
378
+ switch (this.scale) {
379
+ case TimeStep.SCALE.MILLISECOND:
380
+ return (this.current.getMilliseconds() == 0);
381
+ case TimeStep.SCALE.SECOND:
382
+ return (this.current.getSeconds() == 0);
383
+ case TimeStep.SCALE.MINUTE:
384
+ return (this.current.getHours() == 0) && (this.current.getMinutes() == 0);
385
+ // Note: this is no bug. Major label is equal for both minute and hour scale
386
+ case TimeStep.SCALE.HOUR:
387
+ return (this.current.getHours() == 0);
388
+ case TimeStep.SCALE.WEEKDAY: // intentional fall through
389
+ case TimeStep.SCALE.DAY:
390
+ return (this.current.getDate() == 1);
391
+ case TimeStep.SCALE.MONTH:
392
+ return (this.current.getMonth() == 0);
393
+ case TimeStep.SCALE.YEAR:
394
+ return false;
395
+ default:
396
+ return false;
397
+ }
398
+ };
399
+
400
+
401
+ /**
402
+ * Returns formatted text for the minor axislabel, depending on the current
403
+ * date and the scale. For example when scale is MINUTE, the current time is
404
+ * formatted as "hh:mm".
405
+ * @param {Date} [date] custom date. if not provided, current date is taken
406
+ */
407
+ TimeStep.prototype.getLabelMinor = function(date) {
408
+ if (date == undefined) {
409
+ date = this.current;
410
+ }
411
+
412
+ switch (this.scale) {
413
+ case TimeStep.SCALE.MILLISECOND: return moment(date).format('SSS');
414
+ case TimeStep.SCALE.SECOND: return moment(date).format('s');
415
+ case TimeStep.SCALE.MINUTE: return moment(date).format('HH:mm');
416
+ case TimeStep.SCALE.HOUR: return moment(date).format('HH:mm');
417
+ case TimeStep.SCALE.WEEKDAY: return moment(date).format('ddd D');
418
+ case TimeStep.SCALE.DAY: return moment(date).format('D');
419
+ case TimeStep.SCALE.MONTH: return moment(date).format('MMM');
420
+ case TimeStep.SCALE.YEAR: return moment(date).format('YYYY');
421
+ default: return '';
422
+ }
423
+ };
424
+
425
+
426
+ /**
427
+ * Returns formatted text for the major axis label, depending on the current
428
+ * date and the scale. For example when scale is MINUTE, the major scale is
429
+ * hours, and the hour will be formatted as "hh".
430
+ * @param {Date} [date] custom date. if not provided, current date is taken
431
+ */
432
+ TimeStep.prototype.getLabelMajor = function(date) {
433
+ if (date == undefined) {
434
+ date = this.current;
435
+ }
436
+
437
+ //noinspection FallthroughInSwitchStatementJS
438
+ switch (this.scale) {
439
+ case TimeStep.SCALE.MILLISECOND:return moment(date).format('HH:mm:ss');
440
+ case TimeStep.SCALE.SECOND: return moment(date).format('D MMMM HH:mm');
441
+ case TimeStep.SCALE.MINUTE:
442
+ case TimeStep.SCALE.HOUR: return moment(date).format('ddd D MMMM');
443
+ case TimeStep.SCALE.WEEKDAY:
444
+ case TimeStep.SCALE.DAY: return moment(date).format('MMMM YYYY');
445
+ case TimeStep.SCALE.MONTH: return moment(date).format('YYYY');
446
+ case TimeStep.SCALE.YEAR: return '';
447
+ default: return '';
448
+ }
449
+ };