sufia 7.0.0.beta1 → 7.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/sufia.js +3 -4
  3. data/app/assets/stylesheets/sufia/_styles.scss +2 -1
  4. data/app/controllers/concerns/sufia/transfers_controller_behavior.rb +1 -0
  5. data/app/controllers/errors_controller.rb +1 -1
  6. data/app/indexers/sufia/work_indexer.rb +1 -0
  7. data/app/presenters/sufia/admin_stats_presenter.rb +17 -11
  8. data/app/search_builders/sufia/catalog_search_builder.rb +29 -0
  9. data/app/search_builders/sufia/my_collections_search_builder.rb +7 -0
  10. data/app/search_builders/sufia/my_highlights_search_builder.rb +9 -3
  11. data/app/search_builders/sufia/my_shares_search_builder.rb +8 -1
  12. data/app/search_builders/sufia/search_builder.rb +0 -59
  13. data/app/services/sufia/analytics.rb +25 -8
  14. data/app/services/sufia/query_service.rb +1 -1
  15. data/app/services/sufia/statistics/collections/over_time.rb +13 -0
  16. data/app/services/sufia/statistics/depositors/summary.rb +54 -0
  17. data/app/services/sufia/statistics/file_sets/by_format.rb +14 -0
  18. data/app/services/sufia/statistics/over_time.rb +11 -3
  19. data/app/services/sufia/statistics/system_stats.rb +61 -0
  20. data/app/services/sufia/statistics/term_query.rb +65 -0
  21. data/app/services/sufia/statistics/works/by_depositor.rb +13 -0
  22. data/app/services/sufia/statistics/works/by_resource_type.rb +13 -0
  23. data/app/services/sufia/statistics/works/count.rb +49 -0
  24. data/app/services/sufia/statistics/works/over_time.rb +13 -0
  25. data/app/views/admin/stats/_stats_by_date.html.erb +1 -1
  26. data/app/views/admin/stats/_top_data.html.erb +4 -4
  27. data/app/views/admin/stats/_works.html.erb +8 -0
  28. data/app/views/collections/_form.html.erb +1 -1
  29. data/app/views/curation_concerns/base/_attribute_rows.html.erb +10 -10
  30. data/app/views/curation_concerns/base/_metadata.html.erb +1 -1
  31. data/app/views/curation_concerns/base/_relationships.html.erb +1 -1
  32. data/app/views/curation_concerns/file_sets/_descriptions.html.erb +1 -1
  33. data/app/views/error/404.html.erb +8 -19
  34. data/app/views/layouts/error.html.erb +3 -3
  35. data/app/views/layouts/homepage.html.erb +1 -1
  36. data/app/views/layouts/sufia-dashboard.html.erb +1 -1
  37. data/app/views/layouts/sufia-one-column.html.erb +1 -1
  38. data/app/views/{_footer.html.erb → shared/_footer.html.erb} +1 -1
  39. data/app/views/stats/file.html.erb +0 -1
  40. data/app/views/stats/work.html.erb +0 -2
  41. data/lib/generators/sufia/install_generator.rb +6 -0
  42. data/lib/sufia/engine.rb +1 -0
  43. data/lib/sufia/version.rb +1 -1
  44. data/spec/controllers/my/shares_controller_spec.rb +6 -7
  45. data/spec/controllers/transfers_controller_spec.rb +10 -0
  46. data/spec/features/batch_edit_spec.rb +1 -1
  47. data/spec/lib/sufia/analytics_spec.rb +18 -10
  48. data/spec/presenters/sufia/admin_stats_presenter_spec.rb +21 -14
  49. data/spec/search_builder/{sufia_search_builder_spec.rb → sufia/catalog_search_builder_spec.rb} +1 -1
  50. data/spec/search_builder/sufia/my_shares_search_builder_spec.rb +18 -0
  51. data/spec/services/statistics/{collections_spec.rb → collections/over_time_spec.rb} +1 -1
  52. data/spec/services/{sufia/admin/depositor_stats_spec.rb → statistics/depositors/summary_spec.rb} +5 -7
  53. data/spec/services/statistics/file_sets/by_format_spec.rb +30 -0
  54. data/spec/services/statistics/system_stats_spec.rb +54 -0
  55. data/spec/services/statistics/works/by_depositor_spec.rb +25 -0
  56. data/spec/services/statistics/works/by_resource_type_spec.rb +21 -0
  57. data/spec/services/statistics/works/count_spec.rb +42 -0
  58. data/spec/services/statistics/{works_spec.rb → works/over_time_spec.rb} +1 -1
  59. data/spec/views/admin/stats/index.html.erb_spec.rb +3 -6
  60. data/spec/views/curation_concerns/base/_relationships.html.erb_spec.rb +4 -1
  61. data/sufia.gemspec +2 -1
  62. metadata +49 -25
  63. data/app/services/sufia/admin/depositor_stats.rb +0 -48
  64. data/app/services/sufia/statistics/collections.rb +0 -12
  65. data/app/services/sufia/statistics/works.rb +0 -12
  66. data/app/services/sufia/system_stats.rb +0 -120
  67. data/app/views/admin/stats/_files.html.erb +0 -8
  68. data/lib/generators/sufia/fulltext_generator.rb +0 -26
  69. data/spec/services/sufia/system_stats_spec.rb +0 -224
  70. data/vendor/assets/javascripts/flot/excanvas.js +0 -1428
  71. data/vendor/assets/javascripts/flot/jquery.flot.js +0 -3168
  72. data/vendor/assets/javascripts/flot/jquery.flot.selection.js +0 -360
  73. data/vendor/assets/javascripts/flot/jquery.flot.time.js +0 -432
@@ -1,360 +0,0 @@
1
- /* Flot plugin for selecting regions of a plot.
2
-
3
- Copyright (c) 2007-2014 IOLA and Ole Laursen.
4
- Licensed under the MIT license.
5
-
6
- The plugin supports these options:
7
-
8
- selection: {
9
- mode: null or "x" or "y" or "xy",
10
- color: color,
11
- shape: "round" or "miter" or "bevel",
12
- minSize: number of pixels
13
- }
14
-
15
- Selection support is enabled by setting the mode to one of "x", "y" or "xy".
16
- In "x" mode, the user will only be able to specify the x range, similarly for
17
- "y" mode. For "xy", the selection becomes a rectangle where both ranges can be
18
- specified. "color" is color of the selection (if you need to change the color
19
- later on, you can get to it with plot.getOptions().selection.color). "shape"
20
- is the shape of the corners of the selection.
21
-
22
- "minSize" is the minimum size a selection can be in pixels. This value can
23
- be customized to determine the smallest size a selection can be and still
24
- have the selection rectangle be displayed. When customizing this value, the
25
- fact that it refers to pixels, not axis units must be taken into account.
26
- Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
27
- minute, setting "minSize" to 1 will not make the minimum selection size 1
28
- minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
29
- "plotunselected" events from being fired when the user clicks the mouse without
30
- dragging.
31
-
32
- When selection support is enabled, a "plotselected" event will be emitted on
33
- the DOM element you passed into the plot function. The event handler gets a
34
- parameter with the ranges selected on the axes, like this:
35
-
36
- placeholder.bind( "plotselected", function( event, ranges ) {
37
- alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
38
- // similar for yaxis - with multiple axes, the extra ones are in
39
- // x2axis, x3axis, ...
40
- });
41
-
42
- The "plotselected" event is only fired when the user has finished making the
43
- selection. A "plotselecting" event is fired during the process with the same
44
- parameters as the "plotselected" event, in case you want to know what's
45
- happening while it's happening,
46
-
47
- A "plotunselected" event with no arguments is emitted when the user clicks the
48
- mouse to remove the selection. As stated above, setting "minSize" to 0 will
49
- destroy this behavior.
50
-
51
- The plugin allso adds the following methods to the plot object:
52
-
53
- - setSelection( ranges, preventEvent )
54
-
55
- Set the selection rectangle. The passed in ranges is on the same form as
56
- returned in the "plotselected" event. If the selection mode is "x", you
57
- should put in either an xaxis range, if the mode is "y" you need to put in
58
- an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
59
- this:
60
-
61
- setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
62
-
63
- setSelection will trigger the "plotselected" event when called. If you don't
64
- want that to happen, e.g. if you're inside a "plotselected" handler, pass
65
- true as the second parameter. If you are using multiple axes, you can
66
- specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
67
- xaxis, the plugin picks the first one it sees.
68
-
69
- - clearSelection( preventEvent )
70
-
71
- Clear the selection rectangle. Pass in true to avoid getting a
72
- "plotunselected" event.
73
-
74
- - getSelection()
75
-
76
- Returns the current selection in the same format as the "plotselected"
77
- event. If there's currently no selection, the function returns null.
78
-
79
- */
80
-
81
- (function ($) {
82
- function init(plot) {
83
- var selection = {
84
- first: { x: -1, y: -1}, second: { x: -1, y: -1},
85
- show: false,
86
- active: false
87
- };
88
-
89
- // FIXME: The drag handling implemented here should be
90
- // abstracted out, there's some similar code from a library in
91
- // the navigation plugin, this should be massaged a bit to fit
92
- // the Flot cases here better and reused. Doing this would
93
- // make this plugin much slimmer.
94
- var savedhandlers = {};
95
-
96
- var mouseUpHandler = null;
97
-
98
- function onMouseMove(e) {
99
- if (selection.active) {
100
- updateSelection(e);
101
-
102
- plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
103
- }
104
- }
105
-
106
- function onMouseDown(e) {
107
- if (e.which != 1) // only accept left-click
108
- return;
109
-
110
- // cancel out any text selections
111
- document.body.focus();
112
-
113
- // prevent text selection and drag in old-school browsers
114
- if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
115
- savedhandlers.onselectstart = document.onselectstart;
116
- document.onselectstart = function () { return false; };
117
- }
118
- if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
119
- savedhandlers.ondrag = document.ondrag;
120
- document.ondrag = function () { return false; };
121
- }
122
-
123
- setSelectionPos(selection.first, e);
124
-
125
- selection.active = true;
126
-
127
- // this is a bit silly, but we have to use a closure to be
128
- // able to whack the same handler again
129
- mouseUpHandler = function (e) { onMouseUp(e); };
130
-
131
- $(document).one("mouseup", mouseUpHandler);
132
- }
133
-
134
- function onMouseUp(e) {
135
- mouseUpHandler = null;
136
-
137
- // revert drag stuff for old-school browsers
138
- if (document.onselectstart !== undefined)
139
- document.onselectstart = savedhandlers.onselectstart;
140
- if (document.ondrag !== undefined)
141
- document.ondrag = savedhandlers.ondrag;
142
-
143
- // no more dragging
144
- selection.active = false;
145
- updateSelection(e);
146
-
147
- if (selectionIsSane())
148
- triggerSelectedEvent();
149
- else {
150
- // this counts as a clear
151
- plot.getPlaceholder().trigger("plotunselected", [ ]);
152
- plot.getPlaceholder().trigger("plotselecting", [ null ]);
153
- }
154
-
155
- return false;
156
- }
157
-
158
- function getSelection() {
159
- if (!selectionIsSane())
160
- return null;
161
-
162
- if (!selection.show) return null;
163
-
164
- var r = {}, c1 = selection.first, c2 = selection.second;
165
- $.each(plot.getAxes(), function (name, axis) {
166
- if (axis.used) {
167
- var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
168
- r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
169
- }
170
- });
171
- return r;
172
- }
173
-
174
- function triggerSelectedEvent() {
175
- var r = getSelection();
176
-
177
- plot.getPlaceholder().trigger("plotselected", [ r ]);
178
-
179
- // backwards-compat stuff, to be removed in future
180
- if (r.xaxis && r.yaxis)
181
- plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
182
- }
183
-
184
- function clamp(min, value, max) {
185
- return value < min ? min: (value > max ? max: value);
186
- }
187
-
188
- function setSelectionPos(pos, e) {
189
- var o = plot.getOptions();
190
- var offset = plot.getPlaceholder().offset();
191
- var plotOffset = plot.getPlotOffset();
192
- pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
193
- pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
194
-
195
- if (o.selection.mode == "y")
196
- pos.x = pos == selection.first ? 0 : plot.width();
197
-
198
- if (o.selection.mode == "x")
199
- pos.y = pos == selection.first ? 0 : plot.height();
200
- }
201
-
202
- function updateSelection(pos) {
203
- if (pos.pageX == null)
204
- return;
205
-
206
- setSelectionPos(selection.second, pos);
207
- if (selectionIsSane()) {
208
- selection.show = true;
209
- plot.triggerRedrawOverlay();
210
- }
211
- else
212
- clearSelection(true);
213
- }
214
-
215
- function clearSelection(preventEvent) {
216
- if (selection.show) {
217
- selection.show = false;
218
- plot.triggerRedrawOverlay();
219
- if (!preventEvent)
220
- plot.getPlaceholder().trigger("plotunselected", [ ]);
221
- }
222
- }
223
-
224
- // function taken from markings support in Flot
225
- function extractRange(ranges, coord) {
226
- var axis, from, to, key, axes = plot.getAxes();
227
-
228
- for (var k in axes) {
229
- axis = axes[k];
230
- if (axis.direction == coord) {
231
- key = coord + axis.n + "axis";
232
- if (!ranges[key] && axis.n == 1)
233
- key = coord + "axis"; // support x1axis as xaxis
234
- if (ranges[key]) {
235
- from = ranges[key].from;
236
- to = ranges[key].to;
237
- break;
238
- }
239
- }
240
- }
241
-
242
- // backwards-compat stuff - to be removed in future
243
- if (!ranges[key]) {
244
- axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
245
- from = ranges[coord + "1"];
246
- to = ranges[coord + "2"];
247
- }
248
-
249
- // auto-reverse as an added bonus
250
- if (from != null && to != null && from > to) {
251
- var tmp = from;
252
- from = to;
253
- to = tmp;
254
- }
255
-
256
- return { from: from, to: to, axis: axis };
257
- }
258
-
259
- function setSelection(ranges, preventEvent) {
260
- var axis, range, o = plot.getOptions();
261
-
262
- if (o.selection.mode == "y") {
263
- selection.first.x = 0;
264
- selection.second.x = plot.width();
265
- }
266
- else {
267
- range = extractRange(ranges, "x");
268
-
269
- selection.first.x = range.axis.p2c(range.from);
270
- selection.second.x = range.axis.p2c(range.to);
271
- }
272
-
273
- if (o.selection.mode == "x") {
274
- selection.first.y = 0;
275
- selection.second.y = plot.height();
276
- }
277
- else {
278
- range = extractRange(ranges, "y");
279
-
280
- selection.first.y = range.axis.p2c(range.from);
281
- selection.second.y = range.axis.p2c(range.to);
282
- }
283
-
284
- selection.show = true;
285
- plot.triggerRedrawOverlay();
286
- if (!preventEvent && selectionIsSane())
287
- triggerSelectedEvent();
288
- }
289
-
290
- function selectionIsSane() {
291
- var minSize = plot.getOptions().selection.minSize;
292
- return Math.abs(selection.second.x - selection.first.x) >= minSize &&
293
- Math.abs(selection.second.y - selection.first.y) >= minSize;
294
- }
295
-
296
- plot.clearSelection = clearSelection;
297
- plot.setSelection = setSelection;
298
- plot.getSelection = getSelection;
299
-
300
- plot.hooks.bindEvents.push(function(plot, eventHolder) {
301
- var o = plot.getOptions();
302
- if (o.selection.mode != null) {
303
- eventHolder.mousemove(onMouseMove);
304
- eventHolder.mousedown(onMouseDown);
305
- }
306
- });
307
-
308
-
309
- plot.hooks.drawOverlay.push(function (plot, ctx) {
310
- // draw selection
311
- if (selection.show && selectionIsSane()) {
312
- var plotOffset = plot.getPlotOffset();
313
- var o = plot.getOptions();
314
-
315
- ctx.save();
316
- ctx.translate(plotOffset.left, plotOffset.top);
317
-
318
- var c = $.color.parse(o.selection.color);
319
-
320
- ctx.strokeStyle = c.scale('a', 0.8).toString();
321
- ctx.lineWidth = 1;
322
- ctx.lineJoin = o.selection.shape;
323
- ctx.fillStyle = c.scale('a', 0.4).toString();
324
-
325
- var x = Math.min(selection.first.x, selection.second.x) + 0.5,
326
- y = Math.min(selection.first.y, selection.second.y) + 0.5,
327
- w = Math.abs(selection.second.x - selection.first.x) - 1,
328
- h = Math.abs(selection.second.y - selection.first.y) - 1;
329
-
330
- ctx.fillRect(x, y, w, h);
331
- ctx.strokeRect(x, y, w, h);
332
-
333
- ctx.restore();
334
- }
335
- });
336
-
337
- plot.hooks.shutdown.push(function (plot, eventHolder) {
338
- eventHolder.unbind("mousemove", onMouseMove);
339
- eventHolder.unbind("mousedown", onMouseDown);
340
-
341
- if (mouseUpHandler)
342
- $(document).unbind("mouseup", mouseUpHandler);
343
- });
344
-
345
- }
346
-
347
- $.plot.plugins.push({
348
- init: init,
349
- options: {
350
- selection: {
351
- mode: null, // one of null, "x", "y" or "xy"
352
- color: "#e8cfac",
353
- shape: "round", // one of "round", "miter", or "bevel"
354
- minSize: 5 // minimum number of pixels
355
- }
356
- },
357
- name: 'selection',
358
- version: '1.1'
359
- });
360
- })(jQuery);
@@ -1,432 +0,0 @@
1
- /* Pretty handling of time axes.
2
-
3
- Copyright (c) 2007-2014 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
- $.plot.dateGenerator = dateGenerator;
431
-
432
- })(jQuery);