vis-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ };