flot-rails 0.0.3 → 0.0.4

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 (36) hide show
  1. data/lib/flot/rails/version.rb +2 -2
  2. data/vendor/assets/javascripts/excanvas.js +1428 -1428
  3. data/vendor/assets/javascripts/excanvas.min.js +0 -0
  4. data/vendor/assets/javascripts/jquery.colorhelpers.js +179 -179
  5. data/vendor/assets/javascripts/jquery.colorhelpers.min.js +0 -0
  6. data/vendor/assets/javascripts/jquery.flot.canvas.js +345 -317
  7. data/vendor/assets/javascripts/jquery.flot.canvas.min.js +1 -1
  8. data/vendor/assets/javascripts/jquery.flot.categories.js +190 -190
  9. data/vendor/assets/javascripts/jquery.flot.categories.min.js +0 -0
  10. data/vendor/assets/javascripts/jquery.flot.crosshair.js +176 -176
  11. data/vendor/assets/javascripts/jquery.flot.crosshair.min.js +0 -0
  12. data/vendor/assets/javascripts/jquery.flot.errorbars.js +353 -353
  13. data/vendor/assets/javascripts/jquery.flot.errorbars.min.js +0 -0
  14. data/vendor/assets/javascripts/jquery.flot.fillbetween.js +226 -226
  15. data/vendor/assets/javascripts/jquery.flot.fillbetween.min.js +0 -0
  16. data/vendor/assets/javascripts/jquery.flot.image.js +241 -241
  17. data/vendor/assets/javascripts/jquery.flot.image.min.js +0 -0
  18. data/vendor/assets/javascripts/jquery.flot.js +3061 -2980
  19. data/vendor/assets/javascripts/jquery.flot.min.js +5 -4
  20. data/vendor/assets/javascripts/jquery.flot.navigate.js +346 -345
  21. data/vendor/assets/javascripts/jquery.flot.navigate.min.js +86 -96
  22. data/vendor/assets/javascripts/jquery.flot.pie.js +817 -812
  23. data/vendor/assets/javascripts/jquery.flot.pie.min.js +1 -1
  24. data/vendor/assets/javascripts/jquery.flot.resize.js +60 -60
  25. data/vendor/assets/javascripts/jquery.flot.resize.min.js +19 -21
  26. data/vendor/assets/javascripts/jquery.flot.selection.js +360 -360
  27. data/vendor/assets/javascripts/jquery.flot.selection.min.js +0 -0
  28. data/vendor/assets/javascripts/jquery.flot.stack.js +188 -188
  29. data/vendor/assets/javascripts/jquery.flot.stack.min.js +0 -0
  30. data/vendor/assets/javascripts/jquery.flot.symbol.js +71 -71
  31. data/vendor/assets/javascripts/jquery.flot.symbol.min.js +0 -0
  32. data/vendor/assets/javascripts/jquery.flot.threshold.js +142 -142
  33. data/vendor/assets/javascripts/jquery.flot.threshold.min.js +0 -0
  34. data/vendor/assets/javascripts/jquery.flot.time.js +431 -424
  35. data/vendor/assets/javascripts/jquery.flot.time.min.js +1 -1
  36. metadata +5 -3
@@ -1,142 +1,142 @@
1
- /* Flot plugin for thresholding data.
2
-
3
- Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
- Licensed under the MIT license.
5
-
6
- The plugin supports these options:
7
-
8
- series: {
9
- threshold: {
10
- below: number
11
- color: colorspec
12
- }
13
- }
14
-
15
- It can also be applied to a single series, like this:
16
-
17
- $.plot( $("#placeholder"), [{
18
- data: [ ... ],
19
- threshold: { ... }
20
- }])
21
-
22
- An array can be passed for multiple thresholding, like this:
23
-
24
- threshold: [{
25
- below: number1
26
- color: color1
27
- },{
28
- below: number2
29
- color: color2
30
- }]
31
-
32
- These multiple threshold objects can be passed in any order since they are
33
- sorted by the processing function.
34
-
35
- The data points below "below" are drawn with the specified color. This makes
36
- it easy to mark points below 0, e.g. for budget data.
37
-
38
- Internally, the plugin works by splitting the data into two series, above and
39
- below the threshold. The extra series below the threshold will have its label
40
- cleared and the special "originSeries" attribute set to the original series.
41
- You may need to check for this in hover events.
42
-
43
- */
44
-
45
- (function ($) {
46
- var options = {
47
- series: { threshold: null } // or { below: number, color: color spec}
48
- };
49
-
50
- function init(plot) {
51
- function thresholdData(plot, s, datapoints, below, color) {
52
- var ps = datapoints.pointsize, i, x, y, p, prevp,
53
- thresholded = $.extend({}, s); // note: shallow copy
54
-
55
- thresholded.datapoints = { points: [], pointsize: ps, format: datapoints.format };
56
- thresholded.label = null;
57
- thresholded.color = color;
58
- thresholded.threshold = null;
59
- thresholded.originSeries = s;
60
- thresholded.data = [];
61
-
62
- var origpoints = datapoints.points,
63
- addCrossingPoints = s.lines.show;
64
-
65
- var threspoints = [];
66
- var newpoints = [];
67
- var m;
68
-
69
- for (i = 0; i < origpoints.length; i += ps) {
70
- x = origpoints[i];
71
- y = origpoints[i + 1];
72
-
73
- prevp = p;
74
- if (y < below)
75
- p = threspoints;
76
- else
77
- p = newpoints;
78
-
79
- if (addCrossingPoints && prevp != p && x != null
80
- && i > 0 && origpoints[i - ps] != null) {
81
- var interx = x + (below - y) * (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]);
82
- prevp.push(interx);
83
- prevp.push(below);
84
- for (m = 2; m < ps; ++m)
85
- prevp.push(origpoints[i + m]);
86
-
87
- p.push(null); // start new segment
88
- p.push(null);
89
- for (m = 2; m < ps; ++m)
90
- p.push(origpoints[i + m]);
91
- p.push(interx);
92
- p.push(below);
93
- for (m = 2; m < ps; ++m)
94
- p.push(origpoints[i + m]);
95
- }
96
-
97
- p.push(x);
98
- p.push(y);
99
- for (m = 2; m < ps; ++m)
100
- p.push(origpoints[i + m]);
101
- }
102
-
103
- datapoints.points = newpoints;
104
- thresholded.datapoints.points = threspoints;
105
-
106
- if (thresholded.datapoints.points.length > 0) {
107
- var origIndex = $.inArray(s, plot.getData());
108
- // Insert newly-generated series right after original one (to prevent it from becoming top-most)
109
- plot.getData().splice(origIndex + 1, 0, thresholded);
110
- }
111
-
112
- // FIXME: there are probably some edge cases left in bars
113
- }
114
-
115
- function processThresholds(plot, s, datapoints) {
116
- if (!s.threshold)
117
- return;
118
-
119
- if (s.threshold instanceof Array) {
120
- s.threshold.sort(function(a, b) {
121
- return a.below - b.below;
122
- });
123
-
124
- $(s.threshold).each(function(i, th) {
125
- thresholdData(plot, s, datapoints, th.below, th.color);
126
- });
127
- }
128
- else {
129
- thresholdData(plot, s, datapoints, s.threshold.below, s.threshold.color);
130
- }
131
- }
132
-
133
- plot.hooks.processDatapoints.push(processThresholds);
134
- }
135
-
136
- $.plot.plugins.push({
137
- init: init,
138
- options: options,
139
- name: 'threshold',
140
- version: '1.2'
141
- });
142
- })(jQuery);
1
+ /* Flot plugin for thresholding data.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ The plugin supports these options:
7
+
8
+ series: {
9
+ threshold: {
10
+ below: number
11
+ color: colorspec
12
+ }
13
+ }
14
+
15
+ It can also be applied to a single series, like this:
16
+
17
+ $.plot( $("#placeholder"), [{
18
+ data: [ ... ],
19
+ threshold: { ... }
20
+ }])
21
+
22
+ An array can be passed for multiple thresholding, like this:
23
+
24
+ threshold: [{
25
+ below: number1
26
+ color: color1
27
+ },{
28
+ below: number2
29
+ color: color2
30
+ }]
31
+
32
+ These multiple threshold objects can be passed in any order since they are
33
+ sorted by the processing function.
34
+
35
+ The data points below "below" are drawn with the specified color. This makes
36
+ it easy to mark points below 0, e.g. for budget data.
37
+
38
+ Internally, the plugin works by splitting the data into two series, above and
39
+ below the threshold. The extra series below the threshold will have its label
40
+ cleared and the special "originSeries" attribute set to the original series.
41
+ You may need to check for this in hover events.
42
+
43
+ */
44
+
45
+ (function ($) {
46
+ var options = {
47
+ series: { threshold: null } // or { below: number, color: color spec}
48
+ };
49
+
50
+ function init(plot) {
51
+ function thresholdData(plot, s, datapoints, below, color) {
52
+ var ps = datapoints.pointsize, i, x, y, p, prevp,
53
+ thresholded = $.extend({}, s); // note: shallow copy
54
+
55
+ thresholded.datapoints = { points: [], pointsize: ps, format: datapoints.format };
56
+ thresholded.label = null;
57
+ thresholded.color = color;
58
+ thresholded.threshold = null;
59
+ thresholded.originSeries = s;
60
+ thresholded.data = [];
61
+
62
+ var origpoints = datapoints.points,
63
+ addCrossingPoints = s.lines.show;
64
+
65
+ var threspoints = [];
66
+ var newpoints = [];
67
+ var m;
68
+
69
+ for (i = 0; i < origpoints.length; i += ps) {
70
+ x = origpoints[i];
71
+ y = origpoints[i + 1];
72
+
73
+ prevp = p;
74
+ if (y < below)
75
+ p = threspoints;
76
+ else
77
+ p = newpoints;
78
+
79
+ if (addCrossingPoints && prevp != p && x != null
80
+ && i > 0 && origpoints[i - ps] != null) {
81
+ var interx = x + (below - y) * (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]);
82
+ prevp.push(interx);
83
+ prevp.push(below);
84
+ for (m = 2; m < ps; ++m)
85
+ prevp.push(origpoints[i + m]);
86
+
87
+ p.push(null); // start new segment
88
+ p.push(null);
89
+ for (m = 2; m < ps; ++m)
90
+ p.push(origpoints[i + m]);
91
+ p.push(interx);
92
+ p.push(below);
93
+ for (m = 2; m < ps; ++m)
94
+ p.push(origpoints[i + m]);
95
+ }
96
+
97
+ p.push(x);
98
+ p.push(y);
99
+ for (m = 2; m < ps; ++m)
100
+ p.push(origpoints[i + m]);
101
+ }
102
+
103
+ datapoints.points = newpoints;
104
+ thresholded.datapoints.points = threspoints;
105
+
106
+ if (thresholded.datapoints.points.length > 0) {
107
+ var origIndex = $.inArray(s, plot.getData());
108
+ // Insert newly-generated series right after original one (to prevent it from becoming top-most)
109
+ plot.getData().splice(origIndex + 1, 0, thresholded);
110
+ }
111
+
112
+ // FIXME: there are probably some edge cases left in bars
113
+ }
114
+
115
+ function processThresholds(plot, s, datapoints) {
116
+ if (!s.threshold)
117
+ return;
118
+
119
+ if (s.threshold instanceof Array) {
120
+ s.threshold.sort(function(a, b) {
121
+ return a.below - b.below;
122
+ });
123
+
124
+ $(s.threshold).each(function(i, th) {
125
+ thresholdData(plot, s, datapoints, th.below, th.color);
126
+ });
127
+ }
128
+ else {
129
+ thresholdData(plot, s, datapoints, s.threshold.below, s.threshold.color);
130
+ }
131
+ }
132
+
133
+ plot.hooks.processDatapoints.push(processThresholds);
134
+ }
135
+
136
+ $.plot.plugins.push({
137
+ init: init,
138
+ options: options,
139
+ name: 'threshold',
140
+ version: '1.2'
141
+ });
142
+ })(jQuery);
@@ -1,424 +1,431 @@
1
- /* Pretty handling of time axes.
2
-
3
- Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
- Licensed under the MIT license.
5
-
6
- Set axis.mode to "time" to enable. See the section "Time series data" in
7
- API.txt for details.
8
-
9
- */
10
-
11
- (function($) {
12
-
13
- var options = {
14
- xaxis: {
15
- timezone: null, // "browser" for local to the client or timezone for timezone-js
16
- timeformat: null, // format string to use
17
- twelveHourClock: false, // 12 or 24 time in time mode
18
- monthNames: null // list of names of months
19
- }
20
- };
21
-
22
- // round to nearby lower multiple of base
23
-
24
- function floorInBase(n, base) {
25
- return base * Math.floor(n / base);
26
- }
27
-
28
- // Returns a string with the date d formatted according to fmt.
29
- // A subset of the Open Group's strftime format is supported.
30
-
31
- function formatDate(d, fmt, monthNames, dayNames) {
32
-
33
- if (typeof d.strftime == "function") {
34
- return d.strftime(fmt);
35
- }
36
-
37
- var leftPad = function(n, pad) {
38
- n = "" + n;
39
- pad = "" + (pad == null ? "0" : pad);
40
- return n.length == 1 ? pad + n : n;
41
- };
42
-
43
- var r = [];
44
- var escape = false;
45
- var hours = d.getHours();
46
- var isAM = hours < 12;
47
-
48
- if (monthNames == null) {
49
- monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
50
- }
51
-
52
- if (dayNames == null) {
53
- dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
54
- }
55
-
56
- var hours12;
57
-
58
- if (hours > 12) {
59
- hours12 = hours - 12;
60
- } else if (hours == 0) {
61
- hours12 = 12;
62
- } else {
63
- hours12 = hours;
64
- }
65
-
66
- for (var i = 0; i < fmt.length; ++i) {
67
-
68
- var c = fmt.charAt(i);
69
-
70
- if (escape) {
71
- switch (c) {
72
- case 'a': c = "" + dayNames[d.getDay()]; break;
73
- case 'b': c = "" + monthNames[d.getMonth()]; break;
74
- case 'd': c = leftPad(d.getDate()); break;
75
- case 'e': c = leftPad(d.getDate(), " "); break;
76
- case 'H': c = leftPad(hours); break;
77
- case 'I': c = leftPad(hours12); break;
78
- case 'l': c = leftPad(hours12, " "); break;
79
- case 'm': c = leftPad(d.getMonth() + 1); break;
80
- case 'M': c = leftPad(d.getMinutes()); break;
81
- // quarters not in Open Group's strftime specification
82
- case 'q':
83
- c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
84
- case 'S': c = leftPad(d.getSeconds()); break;
85
- case 'y': c = leftPad(d.getFullYear() % 100); break;
86
- case 'Y': c = "" + d.getFullYear(); break;
87
- case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
88
- case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
89
- case 'w': c = "" + d.getDay(); break;
90
- }
91
- r.push(c);
92
- escape = false;
93
- } else {
94
- if (c == "%") {
95
- escape = true;
96
- } else {
97
- r.push(c);
98
- }
99
- }
100
- }
101
-
102
- return r.join("");
103
- }
104
-
105
- // To have a consistent view of time-based data independent of which time
106
- // zone the client happens to be in we need a date-like object independent
107
- // of time zones. This is done through a wrapper that only calls the UTC
108
- // versions of the accessor methods.
109
-
110
- function makeUtcWrapper(d) {
111
-
112
- function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {
113
- sourceObj[sourceMethod] = function() {
114
- return targetObj[targetMethod].apply(targetObj, arguments);
115
- };
116
- };
117
-
118
- var utc = {
119
- date: d
120
- };
121
-
122
- // support strftime, if found
123
-
124
- if (d.strftime != undefined) {
125
- addProxyMethod(utc, "strftime", d, "strftime");
126
- }
127
-
128
- addProxyMethod(utc, "getTime", d, "getTime");
129
- addProxyMethod(utc, "setTime", d, "setTime");
130
-
131
- var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];
132
-
133
- for (var p = 0; p < props.length; p++) {
134
- addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);
135
- addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);
136
- }
137
-
138
- return utc;
139
- };
140
-
141
- // select time zone strategy. This returns a date-like object tied to the
142
- // desired timezone
143
-
144
- function dateGenerator(ts, opts) {
145
- if (opts.timezone == "browser") {
146
- return new Date(ts);
147
- } else if (!opts.timezone || opts.timezone == "utc") {
148
- return makeUtcWrapper(new Date(ts));
149
- } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {
150
- var d = new timezoneJS.Date();
151
- // timezone-js is fickle, so be sure to set the time zone before
152
- // setting the time.
153
- d.setTimezone(opts.timezone);
154
- d.setTime(ts);
155
- return d;
156
- } else {
157
- return makeUtcWrapper(new Date(ts));
158
- }
159
- }
160
-
161
- // map of app. size of time units in milliseconds
162
-
163
- var timeUnitSize = {
164
- "second": 1000,
165
- "minute": 60 * 1000,
166
- "hour": 60 * 60 * 1000,
167
- "day": 24 * 60 * 60 * 1000,
168
- "month": 30 * 24 * 60 * 60 * 1000,
169
- "quarter": 3 * 30 * 24 * 60 * 60 * 1000,
170
- "year": 365.2425 * 24 * 60 * 60 * 1000
171
- };
172
-
173
- // the allowed tick sizes, after 1 year we use
174
- // an integer algorithm
175
-
176
- var baseSpec = [
177
- [1, "second"], [2, "second"], [5, "second"], [10, "second"],
178
- [30, "second"],
179
- [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
180
- [30, "minute"],
181
- [1, "hour"], [2, "hour"], [4, "hour"],
182
- [8, "hour"], [12, "hour"],
183
- [1, "day"], [2, "day"], [3, "day"],
184
- [0.25, "month"], [0.5, "month"], [1, "month"],
185
- [2, "month"]
186
- ];
187
-
188
- // we don't know which variant(s) we'll need yet, but generating both is
189
- // cheap
190
-
191
- var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
192
- [1, "year"]]);
193
- var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
194
- [1, "year"]]);
195
-
196
- function init(plot) {
197
- plot.hooks.processDatapoints.push(function (plot, series, datapoints) {
198
- $.each(plot.getAxes(), function(axisName, axis) {
199
-
200
- var opts = axis.options;
201
-
202
- if (opts.mode == "time") {
203
- axis.tickGenerator = function(axis) {
204
-
205
- var ticks = [];
206
- var d = dateGenerator(axis.min, opts);
207
- var minSize = 0;
208
-
209
- // make quarter use a possibility if quarters are
210
- // mentioned in either of these options
211
-
212
- var spec = (opts.tickSize && opts.tickSize[1] ===
213
- "quarter") ||
214
- (opts.minTickSize && opts.minTickSize[1] ===
215
- "quarter") ? specQuarters : specMonths;
216
-
217
- if (opts.minTickSize != null) {
218
- if (typeof opts.tickSize == "number") {
219
- minSize = opts.tickSize;
220
- } else {
221
- minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
222
- }
223
- }
224
-
225
- for (var i = 0; i < spec.length - 1; ++i) {
226
- if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]
227
- + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
228
- && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
229
- break;
230
- }
231
- }
232
-
233
- var size = spec[i][0];
234
- var unit = spec[i][1];
235
-
236
- // special-case the possibility of several years
237
-
238
- if (unit == "year") {
239
-
240
- // if given a minTickSize in years, just use it,
241
- // ensuring that it's an integer
242
-
243
- if (opts.minTickSize != null && opts.minTickSize[1] == "year") {
244
- size = Math.floor(opts.minTickSize[0]);
245
- } else {
246
-
247
- var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));
248
- var norm = (axis.delta / timeUnitSize.year) / magn;
249
-
250
- if (norm < 1.5) {
251
- size = 1;
252
- } else if (norm < 3) {
253
- size = 2;
254
- } else if (norm < 7.5) {
255
- size = 5;
256
- } else {
257
- size = 10;
258
- }
259
-
260
- size *= magn;
261
- }
262
-
263
- // minimum size for years is 1
264
-
265
- if (size < 1) {
266
- size = 1;
267
- }
268
- }
269
-
270
- axis.tickSize = opts.tickSize || [size, unit];
271
- var tickSize = axis.tickSize[0];
272
- unit = axis.tickSize[1];
273
-
274
- var step = tickSize * timeUnitSize[unit];
275
-
276
- if (unit == "second") {
277
- d.setSeconds(floorInBase(d.getSeconds(), tickSize));
278
- } else if (unit == "minute") {
279
- d.setMinutes(floorInBase(d.getMinutes(), tickSize));
280
- } else if (unit == "hour") {
281
- d.setHours(floorInBase(d.getHours(), tickSize));
282
- } else if (unit == "month") {
283
- d.setMonth(floorInBase(d.getMonth(), tickSize));
284
- } else if (unit == "quarter") {
285
- d.setMonth(3 * floorInBase(d.getMonth() / 3,
286
- tickSize));
287
- } else if (unit == "year") {
288
- d.setFullYear(floorInBase(d.getFullYear(), tickSize));
289
- }
290
-
291
- // reset smaller components
292
-
293
- d.setMilliseconds(0);
294
-
295
- if (step >= timeUnitSize.minute) {
296
- d.setSeconds(0);
297
- } else if (step >= timeUnitSize.hour) {
298
- d.setMinutes(0);
299
- } else if (step >= timeUnitSize.day) {
300
- d.setHours(0);
301
- } else if (step >= timeUnitSize.day * 4) {
302
- d.setDate(1);
303
- } else if (step >= timeUnitSize.month * 2) {
304
- d.setMonth(floorInBase(d.getMonth(), 3));
305
- } else if (step >= timeUnitSize.quarter * 2) {
306
- d.setMonth(floorInBase(d.getMonth(), 6));
307
- } else if (step >= timeUnitSize.year) {
308
- d.setMonth(0);
309
- }
310
-
311
- var carry = 0;
312
- var v = Number.NaN;
313
- var prev;
314
-
315
- do {
316
-
317
- prev = v;
318
- v = d.getTime();
319
- ticks.push(v);
320
-
321
- if (unit == "month" || unit == "quarter") {
322
- if (tickSize < 1) {
323
-
324
- // a bit complicated - we'll divide the
325
- // month/quarter up but we need to take
326
- // care of fractions so we don't end up in
327
- // the middle of a day
328
-
329
- d.setDate(1);
330
- var start = d.getTime();
331
- d.setMonth(d.getMonth() +
332
- (unit == "quarter" ? 3 : 1));
333
- var end = d.getTime();
334
- d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
335
- carry = d.getHours();
336
- d.setHours(0);
337
- } else {
338
- d.setMonth(d.getMonth() +
339
- tickSize * (unit == "quarter" ? 3 : 1));
340
- }
341
- } else if (unit == "year") {
342
- d.setFullYear(d.getFullYear() + tickSize);
343
- } else {
344
- d.setTime(v + step);
345
- }
346
- } while (v < axis.max && v != prev);
347
-
348
- return ticks;
349
- };
350
-
351
- axis.tickFormatter = function (v, axis) {
352
-
353
- var d = dateGenerator(v, axis.options);
354
-
355
- // first check global format
356
-
357
- if (opts.timeformat != null) {
358
- return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
359
- }
360
-
361
- // possibly use quarters if quarters are mentioned in
362
- // any of these places
363
-
364
- var useQuarters = (axis.options.tickSize &&
365
- axis.options.tickSize[1] == "quarter") ||
366
- (axis.options.minTickSize &&
367
- axis.options.minTickSize[1] == "quarter");
368
-
369
- var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
370
- var span = axis.max - axis.min;
371
- var suffix = (opts.twelveHourClock) ? " %p" : "";
372
- var hourCode = (opts.twelveHourClock) ? "%I" : "%H";
373
- var fmt;
374
-
375
- if (t < timeUnitSize.minute) {
376
- fmt = hourCode + ":%M:%S" + suffix;
377
- } else if (t < timeUnitSize.day) {
378
- if (span < 2 * timeUnitSize.day) {
379
- fmt = hourCode + ":%M" + suffix;
380
- } else {
381
- fmt = "%b %d " + hourCode + ":%M" + suffix;
382
- }
383
- } else if (t < timeUnitSize.month) {
384
- fmt = "%b %d";
385
- } else if ((useQuarters && t < timeUnitSize.quarter) ||
386
- (!useQuarters && t < timeUnitSize.year)) {
387
- if (span < timeUnitSize.year) {
388
- fmt = "%b";
389
- } else {
390
- fmt = "%b %Y";
391
- }
392
- } else if (useQuarters && t < timeUnitSize.year) {
393
- if (span < timeUnitSize.year) {
394
- fmt = "Q%q";
395
- } else {
396
- fmt = "Q%q %Y";
397
- }
398
- } else {
399
- fmt = "%Y";
400
- }
401
-
402
- var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);
403
-
404
- return rt;
405
- };
406
- }
407
- });
408
- });
409
- }
410
-
411
- $.plot.plugins.push({
412
- init: init,
413
- options: options,
414
- name: 'time',
415
- version: '1.0'
416
- });
417
-
418
- // Time-axis support used to be in Flot core, which exposed the
419
- // formatDate function on the plot object. Various plugins depend
420
- // on the function, so we need to re-expose it here.
421
-
422
- $.plot.formatDate = formatDate;
423
-
424
- })(jQuery);
1
+ /* Pretty handling of time axes.
2
+
3
+ Copyright (c) 2007-2013 IOLA and Ole Laursen.
4
+ Licensed under the MIT license.
5
+
6
+ Set axis.mode to "time" to enable. See the section "Time series data" in
7
+ API.txt for details.
8
+
9
+ */
10
+
11
+ (function($) {
12
+
13
+ var options = {
14
+ xaxis: {
15
+ timezone: null, // "browser" for local to the client or timezone for timezone-js
16
+ timeformat: null, // format string to use
17
+ twelveHourClock: false, // 12 or 24 time in time mode
18
+ monthNames: null // list of names of months
19
+ }
20
+ };
21
+
22
+ // round to nearby lower multiple of base
23
+
24
+ function floorInBase(n, base) {
25
+ return base * Math.floor(n / base);
26
+ }
27
+
28
+ // Returns a string with the date d formatted according to fmt.
29
+ // A subset of the Open Group's strftime format is supported.
30
+
31
+ function formatDate(d, fmt, monthNames, dayNames) {
32
+
33
+ if (typeof d.strftime == "function") {
34
+ return d.strftime(fmt);
35
+ }
36
+
37
+ var leftPad = function(n, pad) {
38
+ n = "" + n;
39
+ pad = "" + (pad == null ? "0" : pad);
40
+ return n.length == 1 ? pad + n : n;
41
+ };
42
+
43
+ var r = [];
44
+ var escape = false;
45
+ var hours = d.getHours();
46
+ var isAM = hours < 12;
47
+
48
+ if (monthNames == null) {
49
+ monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
50
+ }
51
+
52
+ if (dayNames == null) {
53
+ dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
54
+ }
55
+
56
+ var hours12;
57
+
58
+ if (hours > 12) {
59
+ hours12 = hours - 12;
60
+ } else if (hours == 0) {
61
+ hours12 = 12;
62
+ } else {
63
+ hours12 = hours;
64
+ }
65
+
66
+ for (var i = 0; i < fmt.length; ++i) {
67
+
68
+ var c = fmt.charAt(i);
69
+
70
+ if (escape) {
71
+ switch (c) {
72
+ case 'a': c = "" + dayNames[d.getDay()]; break;
73
+ case 'b': c = "" + monthNames[d.getMonth()]; break;
74
+ case 'd': c = leftPad(d.getDate()); break;
75
+ case 'e': c = leftPad(d.getDate(), " "); break;
76
+ case 'h': // For back-compat with 0.7; remove in 1.0
77
+ case 'H': c = leftPad(hours); break;
78
+ case 'I': c = leftPad(hours12); break;
79
+ case 'l': c = leftPad(hours12, " "); break;
80
+ case 'm': c = leftPad(d.getMonth() + 1); break;
81
+ case 'M': c = leftPad(d.getMinutes()); break;
82
+ // quarters not in Open Group's strftime specification
83
+ case 'q':
84
+ c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
85
+ case 'S': c = leftPad(d.getSeconds()); break;
86
+ case 'y': c = leftPad(d.getFullYear() % 100); break;
87
+ case 'Y': c = "" + d.getFullYear(); break;
88
+ case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
89
+ case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
90
+ case 'w': c = "" + d.getDay(); break;
91
+ }
92
+ r.push(c);
93
+ escape = false;
94
+ } else {
95
+ if (c == "%") {
96
+ escape = true;
97
+ } else {
98
+ r.push(c);
99
+ }
100
+ }
101
+ }
102
+
103
+ return r.join("");
104
+ }
105
+
106
+ // To have a consistent view of time-based data independent of which time
107
+ // zone the client happens to be in we need a date-like object independent
108
+ // of time zones. This is done through a wrapper that only calls the UTC
109
+ // versions of the accessor methods.
110
+
111
+ function makeUtcWrapper(d) {
112
+
113
+ function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {
114
+ sourceObj[sourceMethod] = function() {
115
+ return targetObj[targetMethod].apply(targetObj, arguments);
116
+ };
117
+ };
118
+
119
+ var utc = {
120
+ date: d
121
+ };
122
+
123
+ // support strftime, if found
124
+
125
+ if (d.strftime != undefined) {
126
+ addProxyMethod(utc, "strftime", d, "strftime");
127
+ }
128
+
129
+ addProxyMethod(utc, "getTime", d, "getTime");
130
+ addProxyMethod(utc, "setTime", d, "setTime");
131
+
132
+ var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];
133
+
134
+ for (var p = 0; p < props.length; p++) {
135
+ addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);
136
+ addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);
137
+ }
138
+
139
+ return utc;
140
+ };
141
+
142
+ // select time zone strategy. This returns a date-like object tied to the
143
+ // desired timezone
144
+
145
+ function dateGenerator(ts, opts) {
146
+ if (opts.timezone == "browser") {
147
+ return new Date(ts);
148
+ } else if (!opts.timezone || opts.timezone == "utc") {
149
+ return makeUtcWrapper(new Date(ts));
150
+ } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {
151
+ var d = new timezoneJS.Date();
152
+ // timezone-js is fickle, so be sure to set the time zone before
153
+ // setting the time.
154
+ d.setTimezone(opts.timezone);
155
+ d.setTime(ts);
156
+ return d;
157
+ } else {
158
+ return makeUtcWrapper(new Date(ts));
159
+ }
160
+ }
161
+
162
+ // map of app. size of time units in milliseconds
163
+
164
+ var timeUnitSize = {
165
+ "second": 1000,
166
+ "minute": 60 * 1000,
167
+ "hour": 60 * 60 * 1000,
168
+ "day": 24 * 60 * 60 * 1000,
169
+ "month": 30 * 24 * 60 * 60 * 1000,
170
+ "quarter": 3 * 30 * 24 * 60 * 60 * 1000,
171
+ "year": 365.2425 * 24 * 60 * 60 * 1000
172
+ };
173
+
174
+ // the allowed tick sizes, after 1 year we use
175
+ // an integer algorithm
176
+
177
+ var baseSpec = [
178
+ [1, "second"], [2, "second"], [5, "second"], [10, "second"],
179
+ [30, "second"],
180
+ [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
181
+ [30, "minute"],
182
+ [1, "hour"], [2, "hour"], [4, "hour"],
183
+ [8, "hour"], [12, "hour"],
184
+ [1, "day"], [2, "day"], [3, "day"],
185
+ [0.25, "month"], [0.5, "month"], [1, "month"],
186
+ [2, "month"]
187
+ ];
188
+
189
+ // we don't know which variant(s) we'll need yet, but generating both is
190
+ // cheap
191
+
192
+ var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
193
+ [1, "year"]]);
194
+ var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
195
+ [1, "year"]]);
196
+
197
+ function init(plot) {
198
+ plot.hooks.processOptions.push(function (plot, options) {
199
+ $.each(plot.getAxes(), function(axisName, axis) {
200
+
201
+ var opts = axis.options;
202
+
203
+ if (opts.mode == "time") {
204
+ axis.tickGenerator = function(axis) {
205
+
206
+ var ticks = [];
207
+ var d = dateGenerator(axis.min, opts);
208
+ var minSize = 0;
209
+
210
+ // make quarter use a possibility if quarters are
211
+ // mentioned in either of these options
212
+
213
+ var spec = (opts.tickSize && opts.tickSize[1] ===
214
+ "quarter") ||
215
+ (opts.minTickSize && opts.minTickSize[1] ===
216
+ "quarter") ? specQuarters : specMonths;
217
+
218
+ if (opts.minTickSize != null) {
219
+ if (typeof opts.tickSize == "number") {
220
+ minSize = opts.tickSize;
221
+ } else {
222
+ minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
223
+ }
224
+ }
225
+
226
+ for (var i = 0; i < spec.length - 1; ++i) {
227
+ if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]
228
+ + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
229
+ && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
230
+ break;
231
+ }
232
+ }
233
+
234
+ var size = spec[i][0];
235
+ var unit = spec[i][1];
236
+
237
+ // special-case the possibility of several years
238
+
239
+ if (unit == "year") {
240
+
241
+ // if given a minTickSize in years, just use it,
242
+ // ensuring that it's an integer
243
+
244
+ if (opts.minTickSize != null && opts.minTickSize[1] == "year") {
245
+ size = Math.floor(opts.minTickSize[0]);
246
+ } else {
247
+
248
+ var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));
249
+ var norm = (axis.delta / timeUnitSize.year) / magn;
250
+
251
+ if (norm < 1.5) {
252
+ size = 1;
253
+ } else if (norm < 3) {
254
+ size = 2;
255
+ } else if (norm < 7.5) {
256
+ size = 5;
257
+ } else {
258
+ size = 10;
259
+ }
260
+
261
+ size *= magn;
262
+ }
263
+
264
+ // minimum size for years is 1
265
+
266
+ if (size < 1) {
267
+ size = 1;
268
+ }
269
+ }
270
+
271
+ axis.tickSize = opts.tickSize || [size, unit];
272
+ var tickSize = axis.tickSize[0];
273
+ unit = axis.tickSize[1];
274
+
275
+ var step = tickSize * timeUnitSize[unit];
276
+
277
+ if (unit == "second") {
278
+ d.setSeconds(floorInBase(d.getSeconds(), tickSize));
279
+ } else if (unit == "minute") {
280
+ d.setMinutes(floorInBase(d.getMinutes(), tickSize));
281
+ } else if (unit == "hour") {
282
+ d.setHours(floorInBase(d.getHours(), tickSize));
283
+ } else if (unit == "month") {
284
+ d.setMonth(floorInBase(d.getMonth(), tickSize));
285
+ } else if (unit == "quarter") {
286
+ d.setMonth(3 * floorInBase(d.getMonth() / 3,
287
+ tickSize));
288
+ } else if (unit == "year") {
289
+ d.setFullYear(floorInBase(d.getFullYear(), tickSize));
290
+ }
291
+
292
+ // reset smaller components
293
+
294
+ d.setMilliseconds(0);
295
+
296
+ if (step >= timeUnitSize.minute) {
297
+ d.setSeconds(0);
298
+ }
299
+ if (step >= timeUnitSize.hour) {
300
+ d.setMinutes(0);
301
+ }
302
+ if (step >= timeUnitSize.day) {
303
+ d.setHours(0);
304
+ }
305
+ if (step >= timeUnitSize.day * 4) {
306
+ d.setDate(1);
307
+ }
308
+ if (step >= timeUnitSize.month * 2) {
309
+ d.setMonth(floorInBase(d.getMonth(), 3));
310
+ }
311
+ if (step >= timeUnitSize.quarter * 2) {
312
+ d.setMonth(floorInBase(d.getMonth(), 6));
313
+ }
314
+ if (step >= timeUnitSize.year) {
315
+ d.setMonth(0);
316
+ }
317
+
318
+ var carry = 0;
319
+ var v = Number.NaN;
320
+ var prev;
321
+
322
+ do {
323
+
324
+ prev = v;
325
+ v = d.getTime();
326
+ ticks.push(v);
327
+
328
+ if (unit == "month" || unit == "quarter") {
329
+ if (tickSize < 1) {
330
+
331
+ // a bit complicated - we'll divide the
332
+ // month/quarter up but we need to take
333
+ // care of fractions so we don't end up in
334
+ // the middle of a day
335
+
336
+ d.setDate(1);
337
+ var start = d.getTime();
338
+ d.setMonth(d.getMonth() +
339
+ (unit == "quarter" ? 3 : 1));
340
+ var end = d.getTime();
341
+ d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
342
+ carry = d.getHours();
343
+ d.setHours(0);
344
+ } else {
345
+ d.setMonth(d.getMonth() +
346
+ tickSize * (unit == "quarter" ? 3 : 1));
347
+ }
348
+ } else if (unit == "year") {
349
+ d.setFullYear(d.getFullYear() + tickSize);
350
+ } else {
351
+ d.setTime(v + step);
352
+ }
353
+ } while (v < axis.max && v != prev);
354
+
355
+ return ticks;
356
+ };
357
+
358
+ axis.tickFormatter = function (v, axis) {
359
+
360
+ var d = dateGenerator(v, axis.options);
361
+
362
+ // first check global format
363
+
364
+ if (opts.timeformat != null) {
365
+ return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
366
+ }
367
+
368
+ // possibly use quarters if quarters are mentioned in
369
+ // any of these places
370
+
371
+ var useQuarters = (axis.options.tickSize &&
372
+ axis.options.tickSize[1] == "quarter") ||
373
+ (axis.options.minTickSize &&
374
+ axis.options.minTickSize[1] == "quarter");
375
+
376
+ var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
377
+ var span = axis.max - axis.min;
378
+ var suffix = (opts.twelveHourClock) ? " %p" : "";
379
+ var hourCode = (opts.twelveHourClock) ? "%I" : "%H";
380
+ var fmt;
381
+
382
+ if (t < timeUnitSize.minute) {
383
+ fmt = hourCode + ":%M:%S" + suffix;
384
+ } else if (t < timeUnitSize.day) {
385
+ if (span < 2 * timeUnitSize.day) {
386
+ fmt = hourCode + ":%M" + suffix;
387
+ } else {
388
+ fmt = "%b %d " + hourCode + ":%M" + suffix;
389
+ }
390
+ } else if (t < timeUnitSize.month) {
391
+ fmt = "%b %d";
392
+ } else if ((useQuarters && t < timeUnitSize.quarter) ||
393
+ (!useQuarters && t < timeUnitSize.year)) {
394
+ if (span < timeUnitSize.year) {
395
+ fmt = "%b";
396
+ } else {
397
+ fmt = "%b %Y";
398
+ }
399
+ } else if (useQuarters && t < timeUnitSize.year) {
400
+ if (span < timeUnitSize.year) {
401
+ fmt = "Q%q";
402
+ } else {
403
+ fmt = "Q%q %Y";
404
+ }
405
+ } else {
406
+ fmt = "%Y";
407
+ }
408
+
409
+ var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);
410
+
411
+ return rt;
412
+ };
413
+ }
414
+ });
415
+ });
416
+ }
417
+
418
+ $.plot.plugins.push({
419
+ init: init,
420
+ options: options,
421
+ name: 'time',
422
+ version: '1.0'
423
+ });
424
+
425
+ // Time-axis support used to be in Flot core, which exposed the
426
+ // formatDate function on the plot object. Various plugins depend
427
+ // on the function, so we need to re-expose it here.
428
+
429
+ $.plot.formatDate = formatDate;
430
+
431
+ })(jQuery);