pulse-meter 0.2.11 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.rbenv-version +1 -1
  2. data/README.md +32 -16
  3. data/Rakefile +29 -10
  4. data/examples/basic.ru +1 -1
  5. data/examples/full/server.ru +1 -1
  6. data/examples/minimal/server.ru +1 -1
  7. data/lib/pulse-meter.rb +1 -0
  8. data/lib/pulse-meter/observer.rb +117 -0
  9. data/lib/pulse-meter/sensor.rb +1 -0
  10. data/lib/pulse-meter/sensor/timeline.rb +3 -2
  11. data/lib/pulse-meter/sensor/timelined/multi_percentile.rb +43 -0
  12. data/lib/pulse-meter/version.rb +1 -1
  13. data/lib/pulse-meter/visualize/app.rb +28 -12
  14. data/lib/pulse-meter/visualize/coffee/application.coffee +40 -0
  15. data/lib/pulse-meter/visualize/coffee/collections/page_info_list.coffee +17 -0
  16. data/lib/pulse-meter/visualize/coffee/collections/sensor_info_list.coffee +4 -0
  17. data/lib/pulse-meter/visualize/coffee/collections/widget_list.coffee +14 -0
  18. data/lib/pulse-meter/visualize/coffee/extensions.coffee +26 -0
  19. data/lib/pulse-meter/visualize/coffee/models/dinamic_widget.coffee +34 -0
  20. data/lib/pulse-meter/visualize/coffee/models/page_info.coffee +2 -0
  21. data/lib/pulse-meter/visualize/coffee/models/sensor_info.coffee +2 -0
  22. data/lib/pulse-meter/visualize/coffee/models/widget.coffee +54 -0
  23. data/lib/pulse-meter/visualize/coffee/presenters/area.coffee +2 -0
  24. data/lib/pulse-meter/visualize/coffee/presenters/gauge.coffee +11 -0
  25. data/lib/pulse-meter/visualize/coffee/presenters/line.coffee +2 -0
  26. data/lib/pulse-meter/visualize/coffee/presenters/pie.coffee +20 -0
  27. data/lib/pulse-meter/visualize/coffee/presenters/series.coffee +44 -0
  28. data/lib/pulse-meter/visualize/coffee/presenters/table.coffee +10 -0
  29. data/lib/pulse-meter/visualize/coffee/presenters/timeline.coffee +13 -0
  30. data/lib/pulse-meter/visualize/coffee/presenters/widget.coffee +65 -0
  31. data/lib/pulse-meter/visualize/coffee/router.coffee +21 -0
  32. data/lib/pulse-meter/visualize/coffee/views/dynamic_chart.coffee +91 -0
  33. data/lib/pulse-meter/visualize/coffee/views/dynamic_widget.coffee +58 -0
  34. data/lib/pulse-meter/visualize/coffee/views/page_title.coffee +17 -0
  35. data/lib/pulse-meter/visualize/coffee/views/page_titles.coffee +15 -0
  36. data/lib/pulse-meter/visualize/coffee/views/sensor_info_list.coffee +19 -0
  37. data/lib/pulse-meter/visualize/coffee/views/widget.coffee +99 -0
  38. data/lib/pulse-meter/visualize/coffee/views/widget_chart.coffee +13 -0
  39. data/lib/pulse-meter/visualize/coffee/views/widget_list.coffee +15 -0
  40. data/lib/pulse-meter/visualize/layout.rb +4 -4
  41. data/lib/pulse-meter/visualize/public/css/application.css +13 -4
  42. data/lib/pulse-meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  43. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  44. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  45. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  46. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  47. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
  48. data/lib/pulse-meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  49. data/lib/pulse-meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
  50. data/lib/pulse-meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
  51. data/lib/pulse-meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
  52. data/lib/pulse-meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
  53. data/lib/pulse-meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
  54. data/lib/pulse-meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
  55. data/lib/pulse-meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
  56. data/lib/pulse-meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +1320 -0
  57. data/lib/pulse-meter/visualize/public/js/application.js +900 -691
  58. data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +791 -0
  59. data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +21 -0
  60. data/lib/pulse-meter/visualize/public/js/jquery-ui-timepicker-addon.js +1687 -0
  61. data/lib/pulse-meter/visualize/sensor.rb +2 -2
  62. data/lib/pulse-meter/visualize/views/main.haml +2 -3
  63. data/lib/pulse-meter/visualize/views/sensors.haml +14 -1
  64. data/lib/pulse-meter/visualize/views/widgets/area.haml +46 -24
  65. data/lib/pulse-meter/visualize/views/widgets/line.haml +46 -23
  66. data/lib/pulse-meter/visualize/views/widgets/table.haml +37 -15
  67. data/lib/pulse-meter/visualize/widgets/timeline.rb +20 -5
  68. data/pulse-meter.gemspec +4 -0
  69. data/spec/pulse_meter/observer_spec.rb +252 -0
  70. data/spec/pulse_meter/sensor/timelined/multi_percentile_spec.rb +21 -0
  71. data/spec/pulse_meter/visualize/sensor_spec.rb +5 -5
  72. data/spec/pulse_meter/visualize/widgets/area_spec.rb +1 -74
  73. data/spec/pulse_meter/visualize/widgets/line_spec.rb +1 -73
  74. data/spec/pulse_meter/visualize/widgets/table_spec.rb +1 -73
  75. data/spec/shared_examples/timeline_sensor.rb +10 -0
  76. data/spec/shared_examples/widget.rb +97 -0
  77. data/spec/spec_helper.rb +1 -0
  78. metadata +120 -5
  79. data/lib/pulse-meter/visualize/public/js/application.coffee +0 -616
@@ -1,764 +1,973 @@
1
- // Generated by CoffeeScript 1.2.1-pre
2
- (function() {
3
- var __hasProp = {}.hasOwnProperty,
4
- __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
5
-
6
- document.startApp = function() {
7
- var AppRouter, AreaPresenter, DynamicChartView, DynamicWidget, DynamicWidgetView, GaugePresenter, LinePresenter, PageInfo, PageInfoList, PageTitleView, PageTitlesView, PiePresenter, SensorInfo, SensorInfoList, SensorInfoListView, SeriesPresenter, TablePresenter, TimelinePresenter, Widget, WidgetChartView, WidgetList, WidgetListView, WidgetPresenter, WidgetView, appRouter, globalOptions, pageInfos, pageTitlesApp, widgetList, widgetListApp;
8
- globalOptions = gon.options;
9
- String.prototype.capitalize = function() {
10
- return this.charAt(0).toUpperCase() + this.slice(1);
11
- };
12
- String.prototype.strip = function() {
13
- if (String.prototype.trim != null) {
14
- return this.trim();
15
- } else {
16
- return this.replace(/^\s+|\s+$/g, "");
17
- }
18
- };
19
- Number.prototype.humanize = function() {
20
- var d, h, interval, m, res, s;
21
- interval = this;
22
- res = "";
23
- s = interval % 60;
24
- if (s > 0) res = "" + s + " s";
25
- interval = (interval - s) / 60;
26
- if (!(interval > 0)) return res;
27
- m = interval % 60;
28
- if (m > 0) res = ("" + m + " m " + res).strip();
29
- interval = (interval - m) / 60;
30
- if (!(interval > 0)) return res;
31
- h = interval % 24;
32
- if (h > 0) res = ("" + h + " h " + res).strip();
33
- d = (interval - h) / 24;
34
- if (d > 0) {
35
- return ("" + d + " d " + res).strip();
36
- } else {
37
- return res;
38
- }
39
- };
40
- PageInfo = Backbone.Model.extend({});
41
- PageInfoList = Backbone.Collection.extend({
42
- model: PageInfo,
43
- selected: function() {
44
- return this.find(function(m) {
45
- return m.get('selected');
46
- });
47
- },
48
- selectFirst: function() {
49
- if (this.length > 0) return this.at(0).set('selected', true);
50
- },
51
- selectNone: function() {
52
- return this.each(function(m) {
53
- return m.set('selected', false);
54
- });
55
- },
56
- selectPage: function(id) {
57
- return this.each(function(m) {
58
- return m.set('selected', m.id === id);
59
- });
1
+
2
+ String.prototype.capitalize = function() {
3
+ return this.charAt(0).toUpperCase() + this.slice(1);
4
+ };
5
+
6
+ String.prototype.strip = function() {
7
+ if (String.prototype.trim != null) {
8
+ return this.trim();
9
+ } else {
10
+ return this.replace(/^\s+|\s+$/g, "");
11
+ }
12
+ };
13
+
14
+ Number.prototype.humanize = function() {
15
+ var d, h, interval, m, res, s;
16
+ interval = this;
17
+ res = "";
18
+ s = interval % 60;
19
+ if (s > 0) {
20
+ res = "" + s + " s";
21
+ }
22
+ interval = (interval - s) / 60;
23
+ if (!(interval > 0)) {
24
+ return res;
25
+ }
26
+ m = interval % 60;
27
+ if (m > 0) {
28
+ res = ("" + m + " m " + res).strip();
29
+ }
30
+ interval = (interval - m) / 60;
31
+ if (!(interval > 0)) {
32
+ return res;
33
+ }
34
+ h = interval % 24;
35
+ if (h > 0) {
36
+ res = ("" + h + " h " + res).strip();
37
+ }
38
+ d = (interval - h) / 24;
39
+ if (d > 0) {
40
+ return ("" + d + " d " + res).strip();
41
+ } else {
42
+ return res;
43
+ }
44
+ };
45
+ var PageInfo;
46
+
47
+ PageInfo = Backbone.Model.extend({});
48
+ var Widget;
49
+
50
+ Widget = Backbone.Model.extend({
51
+ initialize: function() {
52
+ this.needRefresh = true;
53
+ this.setNextFetch();
54
+ return this.timespanInc = 0;
55
+ },
56
+ setStartTime: function(startTime) {
57
+ this.startTime = startTime;
58
+ },
59
+ setEndTime: function(endTime) {
60
+ this.endTime = endTime;
61
+ },
62
+ increaseTimespan: function(inc) {
63
+ this.timespanInc = this.timespanInc + inc;
64
+ return this.forceUpdate();
65
+ },
66
+ resetTimespan: function() {
67
+ this.timespanInc = 0;
68
+ this.startTime = null;
69
+ this.endTime = null;
70
+ return this.forceUpdate();
71
+ },
72
+ timespan: function() {
73
+ return this.get('timespan') + this.timespanInc;
74
+ },
75
+ url: function() {
76
+ var timespan, url;
77
+ timespan = this.timespan();
78
+ url = "" + (this.collection.url()) + "/" + (this.get('id')) + "?";
79
+ if (!_.isNaN(timespan)) {
80
+ url += "&timespan=" + timespan;
81
+ }
82
+ if (this.startTime) {
83
+ url += "&startTime=" + this.startTime;
84
+ }
85
+ if (this.endTime) {
86
+ url += "&endTime=" + this.endTime;
87
+ }
88
+ return url;
89
+ },
90
+ time: function() {
91
+ return (new Date()).getTime();
92
+ },
93
+ setNextFetch: function() {
94
+ return this.nextFetch = this.time() + this.get('redrawInterval') * 1000;
95
+ },
96
+ setRefresh: function(needRefresh) {
97
+ return this.needRefresh = needRefresh;
98
+ },
99
+ needFetch: function() {
100
+ var interval;
101
+ interval = this.get('redrawInterval');
102
+ return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0;
103
+ },
104
+ refetch: function() {
105
+ if (this.needFetch()) {
106
+ this.forceUpdate();
107
+ return this.setNextFetch();
108
+ }
109
+ },
110
+ forceUpdate: function() {
111
+ return this.fetch({
112
+ success: function(model, response) {
113
+ return model.trigger('redraw');
60
114
  }
61
115
  });
62
- pageInfos = new PageInfoList;
63
- PageTitleView = Backbone.View.extend({
64
- tagName: 'li',
65
- template: _.template('<a href="#/pages/<%= id %>"><%= title %></a>'),
66
- initialize: function() {
67
- this.model.bind('change', this.render, this);
68
- return this.model.bind('destroy', this.remove, this);
69
- },
70
- render: function() {
71
- this.$el.html(this.template(this.model.toJSON()));
72
- if (this.model.get('selected')) {
73
- return this.$el.addClass('active');
74
- } else {
75
- return this.$el.removeClass('active');
76
- }
116
+ }
117
+ });
118
+ var DynamicWidget;
119
+
120
+ DynamicWidget = Backbone.Model.extend({
121
+ setStartTime: function(startTime) {
122
+ this.startTime = startTime;
123
+ },
124
+ setEndTime: function(endTime) {
125
+ this.endTime = endTime;
126
+ },
127
+ increaseTimespan: function(inc) {
128
+ return this.set('timespan', this.timespan() + inc);
129
+ },
130
+ resetTimespan: function() {
131
+ this.startTime = null;
132
+ this.endTime = null;
133
+ return this.set('timespan', null);
134
+ },
135
+ timespan: function() {
136
+ return this.get('timespan');
137
+ },
138
+ sensorArgs: function() {
139
+ return _.map(this.get('sensorIds'), function(name) {
140
+ return "sensor[]=" + name;
141
+ }).join('&');
142
+ },
143
+ url: function() {
144
+ var timespan, url;
145
+ timespan = this.timespan();
146
+ url = "" + ROOT + "dynamic_widget?" + (this.sensorArgs()) + "&type=" + (this.get('type'));
147
+ if ((timespan != null) && !_.isNaN(timespan)) {
148
+ url += "&timespan=" + timespan;
149
+ }
150
+ if (this.startTime) {
151
+ url += "&startTime=" + this.startTime;
152
+ }
153
+ if (this.endTime) {
154
+ url += "&endTime=" + this.endTime;
155
+ }
156
+ return url;
157
+ },
158
+ forceUpdate: function() {
159
+ return this.fetch({
160
+ success: function(model, response) {
161
+ return model.trigger('redraw');
77
162
  }
78
163
  });
79
- PageTitlesView = Backbone.View.extend({
80
- initialize: function() {
81
- return pageInfos.bind('reset', this.render, this);
82
- },
83
- addOne: function(pageInfo) {
84
- var view;
85
- view = new PageTitleView({
86
- model: pageInfo
87
- });
88
- view.render();
89
- return $('#page-titles').append(view.el);
90
- },
91
- render: function() {
92
- $('#page-titles').empty();
93
- return pageInfos.each(this.addOne);
94
- }
164
+ }
165
+ });
166
+ var SensorInfo;
167
+
168
+ SensorInfo = Backbone.Model.extend({});
169
+ var PageInfoList;
170
+
171
+ PageInfoList = Backbone.Collection.extend({
172
+ model: PageInfo,
173
+ selected: function() {
174
+ return this.find(function(m) {
175
+ return m.get('selected');
176
+ });
177
+ },
178
+ selectFirst: function() {
179
+ if (this.length > 0) {
180
+ return this.at(0).set('selected', true);
181
+ }
182
+ },
183
+ selectNone: function() {
184
+ return this.each(function(m) {
185
+ return m.set('selected', false);
186
+ });
187
+ },
188
+ selectPage: function(id) {
189
+ return this.each(function(m) {
190
+ return m.set('selected', m.id === id);
95
191
  });
96
- pageTitlesApp = new PageTitlesView;
97
- pageInfos.reset(gon.pageInfos);
98
- WidgetPresenter = (function() {
99
-
100
- WidgetPresenter.name = 'WidgetPresenter';
101
-
102
- function WidgetPresenter(model, el) {
103
- var chartClass;
104
- this.model = model;
105
- chartClass = this.chartClass();
106
- this.chart = new chartClass(el);
107
- this.draw();
192
+ }
193
+ });
194
+ var SensorInfoList;
195
+
196
+ SensorInfoList = Backbone.Collection.extend({
197
+ model: SensorInfo,
198
+ url: function() {
199
+ return ROOT + 'sensors';
200
+ }
201
+ });
202
+ var WidgetList;
203
+
204
+ WidgetList = Backbone.Collection.extend({
205
+ model: Widget,
206
+ setContext: function(pageInfos) {
207
+ this.pageInfos = pageInfos;
208
+ },
209
+ url: function() {
210
+ return ROOT + 'pages/' + this.pageInfos.selected().id + '/widgets';
211
+ },
212
+ startPolling: function() {
213
+ var _this = this;
214
+ return setInterval(function() {
215
+ if (_this.pageInfos.selected()) {
216
+ return _this.each(function(w) {
217
+ return w.refetch();
218
+ });
108
219
  }
220
+ }, 200);
221
+ }
222
+ });
223
+ var WidgetPresenter;
224
+
225
+ WidgetPresenter = (function() {
226
+
227
+ function WidgetPresenter(pageInfos, model, el) {
228
+ var chartClass;
229
+ this.pageInfos = pageInfos;
230
+ this.model = model;
231
+ chartClass = this.chartClass();
232
+ this.chart = new chartClass(el);
233
+ this.draw();
234
+ }
235
+
236
+ WidgetPresenter.prototype.get = function(arg) {
237
+ return this.model.get(arg);
238
+ };
109
239
 
110
- WidgetPresenter.prototype.get = function(arg) {
111
- return this.model.get(arg);
112
- };
240
+ WidgetPresenter.prototype.globalOptions = function() {
241
+ return gon.options;
242
+ };
113
243
 
114
- WidgetPresenter.prototype.dateOffset = function() {
115
- if (globalOptions.useUtc) {
116
- return (new Date).getTimezoneOffset() * 60000;
117
- } else {
118
- return 0;
119
- }
120
- };
121
-
122
- WidgetPresenter.prototype.options = function() {
123
- return {
124
- title: this.get('title'),
125
- height: 300
126
- };
127
- };
128
-
129
- WidgetPresenter.prototype.mergedOptions = function() {
130
- var pageOptions;
131
- pageOptions = pageInfos.selected() ? pageInfos.selected().get('gchartOptions') : {};
132
- return $.extend(true, this.options(), globalOptions.gchartOptions, pageOptions, this.get('gchartOptions'));
133
- };
134
-
135
- WidgetPresenter.prototype.data = function() {
136
- return new google.visualization.DataTable;
137
- };
138
-
139
- WidgetPresenter.prototype.chartClass = function() {
140
- return google.visualization[this.visualization];
141
- };
142
-
143
- WidgetPresenter.prototype.cutoff = function() {};
144
-
145
- WidgetPresenter.prototype.cutoffValue = function(v, min, max) {
146
- if (v != null) {
147
- if ((min != null) && v < min) {
148
- return min;
149
- } else if ((max != null) && v > max) {
150
- return max;
151
- } else {
152
- return v;
153
- }
154
- } else {
155
- return 0;
156
- }
157
- };
158
-
159
- WidgetPresenter.prototype.draw = function(min, max) {
160
- this.cutoff(min, max);
161
- return this.chart.draw(this.data(), this.mergedOptions());
162
- };
163
-
164
- return WidgetPresenter;
165
-
166
- })();
167
- WidgetPresenter.create = function(model, el) {
168
- var presenterClass, type;
169
- type = model.get('type');
170
- if ((type != null) && type.match(/^\w+$/)) {
171
- presenterClass = eval("" + (type.capitalize()) + "Presenter");
172
- return new presenterClass(model, el);
173
- } else {
174
- return null;
244
+ WidgetPresenter.prototype.dateOffset = function() {
245
+ if (this.globalOptions.useUtc) {
246
+ return (new Date).getTimezoneOffset() * 60000;
247
+ } else {
248
+ return 0;
249
+ }
250
+ };
251
+
252
+ WidgetPresenter.prototype.options = function() {
253
+ return {
254
+ title: this.get('title'),
255
+ height: 300,
256
+ chartArea: {
257
+ left: 10
175
258
  }
176
259
  };
177
- PiePresenter = (function(_super) {
260
+ };
178
261
 
179
- __extends(PiePresenter, _super);
262
+ WidgetPresenter.prototype.mergedOptions = function() {
263
+ var pageOptions;
264
+ pageOptions = this.pageInfos.selected() ? this.pageInfos.selected().get('gchartOptions') : {};
265
+ return $.extend(true, this.options(), this.globalOptions.gchartOptions, pageOptions, this.get('gchartOptions'));
266
+ };
267
+
268
+ WidgetPresenter.prototype.data = function() {
269
+ return new google.visualization.DataTable;
270
+ };
271
+
272
+ WidgetPresenter.prototype.chartClass = function() {
273
+ return google.visualization[this.visualization];
274
+ };
180
275
 
181
- PiePresenter.name = 'PiePresenter';
276
+ WidgetPresenter.prototype.cutoff = function() {};
182
277
 
183
- function PiePresenter() {
184
- return PiePresenter.__super__.constructor.apply(this, arguments);
278
+ WidgetPresenter.prototype.cutoffValue = function(v, min, max) {
279
+ if (v != null) {
280
+ if ((min != null) && v < min) {
281
+ return min;
282
+ } else if ((max != null) && v > max) {
283
+ return max;
284
+ } else {
285
+ return v;
185
286
  }
287
+ } else {
288
+ return 0;
289
+ }
290
+ };
186
291
 
187
- PiePresenter.prototype.visualization = 'PieChart';
188
-
189
- PiePresenter.prototype.cutoff = function() {};
190
-
191
- PiePresenter.prototype.data = function() {
192
- var data;
193
- data = PiePresenter.__super__.data.call(this);
194
- data.addColumn('string', 'Title');
195
- data.addColumn('number', this.get('valuesTitle'));
196
- data.addRows(this.get('series').data);
197
- return data;
198
- };
199
-
200
- PiePresenter.prototype.options = function() {
201
- return $.extend(true, PiePresenter.__super__.options.call(this), {
202
- slices: this.get('series').options,
203
- legend: {
204
- position: 'bottom'
205
- }
206
- });
207
- };
292
+ WidgetPresenter.prototype.draw = function(min, max) {
293
+ this.cutoff(min, max);
294
+ return this.chart.draw(this.data(), this.mergedOptions());
295
+ };
296
+
297
+ return WidgetPresenter;
208
298
 
209
- return PiePresenter;
299
+ })();
210
300
 
211
- })(WidgetPresenter);
212
- TimelinePresenter = (function(_super) {
301
+ WidgetPresenter.create = function(pageInfos, model, el) {
302
+ var presenterClass, type;
303
+ type = model.get('type');
304
+ if ((type != null) && type.match(/^\w+$/)) {
305
+ presenterClass = eval("" + (type.capitalize()) + "Presenter");
306
+ return new presenterClass(pageInfos, model, el);
307
+ } else {
308
+ return null;
309
+ }
310
+ };
311
+ var PiePresenter,
312
+ __hasProp = {}.hasOwnProperty,
313
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
213
314
 
214
- __extends(TimelinePresenter, _super);
315
+ PiePresenter = (function(_super) {
215
316
 
216
- TimelinePresenter.name = 'TimelinePresenter';
317
+ __extends(PiePresenter, _super);
217
318
 
218
- function TimelinePresenter() {
219
- return TimelinePresenter.__super__.constructor.apply(this, arguments);
319
+ function PiePresenter() {
320
+ return PiePresenter.__super__.constructor.apply(this, arguments);
321
+ }
322
+
323
+ PiePresenter.prototype.visualization = 'PieChart';
324
+
325
+ PiePresenter.prototype.cutoff = function() {};
326
+
327
+ PiePresenter.prototype.data = function() {
328
+ var data;
329
+ data = PiePresenter.__super__.data.call(this);
330
+ data.addColumn('string', 'Title');
331
+ data.addColumn('number', this.get('valuesTitle'));
332
+ data.addRows(this.get('series').data);
333
+ return data;
334
+ };
335
+
336
+ PiePresenter.prototype.options = function() {
337
+ return $.extend(true, PiePresenter.__super__.options.call(this), {
338
+ slices: this.get('series').options,
339
+ legend: {
340
+ position: 'bottom'
220
341
  }
342
+ });
343
+ };
221
344
 
222
- TimelinePresenter.prototype.data = function() {
223
- var data, dateOffset, series;
224
- data = TimelinePresenter.__super__.data.call(this);
225
- data.addColumn('datetime', 'Time');
226
- dateOffset = this.dateOffset() + this.get('interval') * 1000;
227
- series = this.get('series');
228
- _.each(series.titles, function(t) {
229
- return data.addColumn('number', t);
230
- });
231
- _.each(series.rows, function(row) {
232
- row[0] = new Date(row[0] + dateOffset);
233
- return data.addRow(row);
234
- });
235
- return data;
236
- };
345
+ return PiePresenter;
237
346
 
238
- return TimelinePresenter;
347
+ })(WidgetPresenter);
348
+ var TimelinePresenter,
349
+ __hasProp = {}.hasOwnProperty,
350
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
239
351
 
240
- })(WidgetPresenter);
241
- SeriesPresenter = (function(_super) {
352
+ TimelinePresenter = (function(_super) {
242
353
 
243
- __extends(SeriesPresenter, _super);
354
+ __extends(TimelinePresenter, _super);
244
355
 
245
- SeriesPresenter.name = 'SeriesPresenter';
356
+ function TimelinePresenter() {
357
+ return TimelinePresenter.__super__.constructor.apply(this, arguments);
358
+ }
246
359
 
247
- function SeriesPresenter() {
248
- return SeriesPresenter.__super__.constructor.apply(this, arguments);
249
- }
360
+ TimelinePresenter.prototype.data = function() {
361
+ var data, dateOffset, series;
362
+ data = TimelinePresenter.__super__.data.call(this);
363
+ data.addColumn('datetime', 'Time');
364
+ dateOffset = this.dateOffset() + this.get('interval') * 1000;
365
+ series = this.get('series');
366
+ _.each(series.titles, function(t) {
367
+ return data.addColumn('number', t);
368
+ });
369
+ _.each(series.rows, function(row) {
370
+ row[0] = new Date(row[0] + dateOffset);
371
+ return data.addRow(row);
372
+ });
373
+ return data;
374
+ };
250
375
 
251
- SeriesPresenter.prototype.options = function() {
252
- var format, secondPart;
253
- secondPart = this.get('interval') % 60 === 0 ? '' : ':ss';
254
- format = this.model.timespan() > 24 * 60 * 60 ? "yyyy.MM.dd HH:mm" + secondPart : "HH:mm" + secondPart;
255
- return $.extend(true, SeriesPresenter.__super__.options.call(this), {
256
- lineWidth: 1,
257
- chartArea: {
258
- width: '100%'
259
- },
260
- legend: {
261
- position: 'bottom'
262
- },
263
- vAxis: {
264
- title: this.valuesTitle(),
265
- textPosition: 'in'
266
- },
267
- hAxis: {
268
- format: format
269
- },
270
- series: this.get('series').options,
271
- axisTitlesPosition: 'in'
272
- });
273
- };
376
+ return TimelinePresenter;
274
377
 
275
- SeriesPresenter.prototype.valuesTitle = function() {
276
- if (this.get('valuesTitle')) {
277
- return "" + (this.get('valuesTitle')) + " / " + (this.humanizedInterval());
278
- } else {
279
- return this.humanizedInterval();
280
- }
281
- };
378
+ })(WidgetPresenter);
379
+ var SeriesPresenter,
380
+ __hasProp = {}.hasOwnProperty,
381
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
282
382
 
283
- SeriesPresenter.prototype.humanizedInterval = function() {
284
- return this.get('interval').humanize();
285
- };
383
+ SeriesPresenter = (function(_super) {
286
384
 
287
- SeriesPresenter.prototype.cutoff = function(min, max) {
288
- return _.each(this.get('series').rows, function(row) {
289
- var i, value, _i, _ref, _results;
290
- _results = [];
291
- for (i = _i = 1, _ref = row.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
292
- value = row[i];
293
- if (value == null) value = 0;
294
- _results.push(row[i] = this.cutoffValue(value, min, max));
295
- }
296
- return _results;
297
- }, this);
298
- };
385
+ __extends(SeriesPresenter, _super);
299
386
 
300
- return SeriesPresenter;
387
+ function SeriesPresenter() {
388
+ return SeriesPresenter.__super__.constructor.apply(this, arguments);
389
+ }
301
390
 
302
- })(TimelinePresenter);
303
- LinePresenter = (function(_super) {
391
+ SeriesPresenter.prototype.options = function() {
392
+ var format, secondPart;
393
+ secondPart = this.get('interval') % 60 === 0 ? '' : ':ss';
394
+ format = this.model.timespan() > 24 * 60 * 60 ? "yyyy.MM.dd HH:mm" + secondPart : "HH:mm" + secondPart;
395
+ return $.extend(true, SeriesPresenter.__super__.options.call(this), {
396
+ lineWidth: 1,
397
+ chartArea: {
398
+ width: '100%'
399
+ },
400
+ legend: {
401
+ position: 'bottom'
402
+ },
403
+ vAxis: {
404
+ title: this.valuesTitle(),
405
+ textPosition: 'in'
406
+ },
407
+ hAxis: {
408
+ format: format
409
+ },
410
+ series: this.get('series').options,
411
+ axisTitlesPosition: 'in'
412
+ });
413
+ };
304
414
 
305
- __extends(LinePresenter, _super);
415
+ SeriesPresenter.prototype.valuesTitle = function() {
416
+ if (this.get('valuesTitle')) {
417
+ return "" + (this.get('valuesTitle')) + " / " + (this.humanizedInterval());
418
+ } else {
419
+ return this.humanizedInterval();
420
+ }
421
+ };
306
422
 
307
- LinePresenter.name = 'LinePresenter';
423
+ SeriesPresenter.prototype.humanizedInterval = function() {
424
+ return this.get('interval').humanize();
425
+ };
308
426
 
309
- function LinePresenter() {
310
- return LinePresenter.__super__.constructor.apply(this, arguments);
427
+ SeriesPresenter.prototype.cutoff = function(min, max) {
428
+ var _this = this;
429
+ return _.each(this.get('series').rows, function(row) {
430
+ var i, value, _i, _ref, _results;
431
+ _results = [];
432
+ for (i = _i = 1, _ref = row.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
433
+ value = row[i];
434
+ if (value == null) {
435
+ value = 0;
436
+ }
437
+ _results.push(row[i] = _this.cutoffValue(value, min, max));
311
438
  }
439
+ return _results;
440
+ });
441
+ };
312
442
 
313
- LinePresenter.prototype.visualization = 'LineChart';
443
+ return SeriesPresenter;
314
444
 
315
- return LinePresenter;
445
+ })(TimelinePresenter);
446
+ var LinePresenter,
447
+ __hasProp = {}.hasOwnProperty,
448
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
316
449
 
317
- })(SeriesPresenter);
318
- AreaPresenter = (function(_super) {
450
+ LinePresenter = (function(_super) {
319
451
 
320
- __extends(AreaPresenter, _super);
452
+ __extends(LinePresenter, _super);
321
453
 
322
- AreaPresenter.name = 'AreaPresenter';
454
+ function LinePresenter() {
455
+ return LinePresenter.__super__.constructor.apply(this, arguments);
456
+ }
323
457
 
324
- function AreaPresenter() {
325
- return AreaPresenter.__super__.constructor.apply(this, arguments);
326
- }
458
+ LinePresenter.prototype.visualization = 'LineChart';
327
459
 
328
- AreaPresenter.prototype.visualization = 'AreaChart';
460
+ return LinePresenter;
329
461
 
330
- return AreaPresenter;
462
+ })(SeriesPresenter);
463
+ var AreaPresenter,
464
+ __hasProp = {}.hasOwnProperty,
465
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
331
466
 
332
- })(SeriesPresenter);
333
- TablePresenter = (function(_super) {
467
+ AreaPresenter = (function(_super) {
334
468
 
335
- __extends(TablePresenter, _super);
469
+ __extends(AreaPresenter, _super);
336
470
 
337
- TablePresenter.name = 'TablePresenter';
471
+ function AreaPresenter() {
472
+ return AreaPresenter.__super__.constructor.apply(this, arguments);
473
+ }
338
474
 
339
- function TablePresenter() {
340
- return TablePresenter.__super__.constructor.apply(this, arguments);
341
- }
475
+ AreaPresenter.prototype.visualization = 'AreaChart';
342
476
 
343
- TablePresenter.prototype.visualization = 'Table';
477
+ return AreaPresenter;
344
478
 
345
- TablePresenter.prototype.cutoff = function() {};
479
+ })(SeriesPresenter);
480
+ var TablePresenter,
481
+ __hasProp = {}.hasOwnProperty,
482
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
346
483
 
347
- TablePresenter.prototype.options = function() {
348
- return $.extend(true, TablePresenter.__super__.options.call(this), {
349
- sortColumn: 0,
350
- sortAscending: false
351
- });
352
- };
484
+ TablePresenter = (function(_super) {
353
485
 
354
- return TablePresenter;
486
+ __extends(TablePresenter, _super);
355
487
 
356
- })(TimelinePresenter);
357
- GaugePresenter = (function(_super) {
488
+ function TablePresenter() {
489
+ return TablePresenter.__super__.constructor.apply(this, arguments);
490
+ }
358
491
 
359
- __extends(GaugePresenter, _super);
492
+ TablePresenter.prototype.visualization = 'Table';
360
493
 
361
- GaugePresenter.name = 'GaugePresenter';
494
+ TablePresenter.prototype.cutoff = function() {};
362
495
 
363
- function GaugePresenter() {
364
- return GaugePresenter.__super__.constructor.apply(this, arguments);
365
- }
496
+ TablePresenter.prototype.options = function() {
497
+ return $.extend(true, TablePresenter.__super__.options.call(this), {
498
+ sortColumn: 0,
499
+ sortAscending: false
500
+ });
501
+ };
366
502
 
367
- GaugePresenter.prototype.visualization = 'Gauge';
503
+ return TablePresenter;
368
504
 
369
- GaugePresenter.prototype.cutoff = function() {};
505
+ })(TimelinePresenter);
506
+ var GaugePresenter,
507
+ __hasProp = {}.hasOwnProperty,
508
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
370
509
 
371
- GaugePresenter.prototype.data = function() {
372
- var data;
373
- data = GaugePresenter.__super__.data.call(this);
374
- data.addColumn('string', 'Label');
375
- data.addColumn('number', this.get('valuesTitle'));
376
- data.addRows(this.get('series'));
377
- return data;
378
- };
510
+ GaugePresenter = (function(_super) {
379
511
 
380
- return GaugePresenter;
512
+ __extends(GaugePresenter, _super);
381
513
 
382
- })(WidgetPresenter);
383
- Widget = Backbone.Model.extend({
384
- initialize: function() {
385
- this.needRefresh = true;
386
- this.setNextFetch();
387
- return this.timespanInc = 0;
388
- },
389
- increaseTimespan: function(inc) {
390
- this.timespanInc = this.timespanInc + inc;
391
- return this.forceUpdate();
392
- },
393
- resetTimespan: function() {
394
- this.timespanInc = 0;
395
- return this.forceUpdate();
396
- },
397
- timespan: function() {
398
- return this.get('timespan') + this.timespanInc;
399
- },
400
- url: function() {
401
- var timespan;
402
- timespan = this.timespan();
403
- if (_.isNaN(timespan)) {
404
- return "" + (this.collection.url()) + "/" + (this.get('id'));
405
- } else {
406
- return "" + (this.collection.url()) + "/" + (this.get('id')) + "?timespan=" + timespan;
407
- }
408
- },
409
- time: function() {
410
- return (new Date()).getTime();
411
- },
412
- setNextFetch: function() {
413
- return this.nextFetch = this.time() + this.get('redrawInterval') * 1000;
414
- },
415
- setRefresh: function(needRefresh) {
416
- return this.needRefresh = needRefresh;
417
- },
418
- needFetch: function() {
419
- var interval;
420
- interval = this.get('redrawInterval');
421
- return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0;
422
- },
423
- refetch: function() {
424
- if (this.needFetch()) {
425
- this.forceUpdate();
426
- return this.setNextFetch();
427
- }
428
- },
429
- forceUpdate: function() {
430
- return this.fetch({
431
- success: function(model, response) {
432
- return model.trigger('redraw');
433
- }
434
- });
435
- }
514
+ function GaugePresenter() {
515
+ return GaugePresenter.__super__.constructor.apply(this, arguments);
516
+ }
517
+
518
+ GaugePresenter.prototype.visualization = 'Gauge';
519
+
520
+ GaugePresenter.prototype.cutoff = function() {};
521
+
522
+ GaugePresenter.prototype.data = function() {
523
+ var data;
524
+ data = GaugePresenter.__super__.data.call(this);
525
+ data.addColumn('string', 'Label');
526
+ data.addColumn('number', this.get('valuesTitle'));
527
+ data.addRows(this.get('series'));
528
+ return data;
529
+ };
530
+
531
+ return GaugePresenter;
532
+
533
+ })(WidgetPresenter);
534
+ var PageTitleView;
535
+
536
+ PageTitleView = Backbone.View.extend({
537
+ tagName: 'li',
538
+ template: _.template('<a href="#/pages/<%= id %>"><%= title %></a>'),
539
+ initialize: function() {
540
+ this.model.bind('change', this.render, this);
541
+ return this.model.bind('destroy', this.remove, this);
542
+ },
543
+ render: function() {
544
+ this.$el.html(this.template(this.model.toJSON()));
545
+ if (this.model.get('selected')) {
546
+ return this.$el.addClass('active');
547
+ } else {
548
+ return this.$el.removeClass('active');
549
+ }
550
+ }
551
+ });
552
+ var PageTitlesView;
553
+
554
+ PageTitlesView = Backbone.View.extend({
555
+ initialize: function(pageInfos) {
556
+ this.pageInfos = pageInfos;
557
+ return this.pageInfos.bind('reset', this.render, this);
558
+ },
559
+ addOne: function(pageInfo) {
560
+ var view;
561
+ view = new PageTitleView({
562
+ model: pageInfo
436
563
  });
437
- DynamicWidget = Backbone.Model.extend({
438
- increaseTimespan: function(inc) {
439
- return this.set('timespan', this.timespan() + inc);
440
- },
441
- resetTimespan: function() {
442
- return this.set('timespan', null);
443
- },
444
- timespan: function() {
445
- return this.get('timespan');
446
- },
447
- sensorArgs: function() {
448
- return _.map(this.get('sensorIds'), function(name) {
449
- return "sensor[]=" + name;
450
- }).join('&');
451
- },
452
- url: function() {
453
- var timespan, url;
454
- url = "" + ROOT + "dynamic_widget?" + (this.sensorArgs()) + "&type=" + (this.get('type'));
455
- timespan = this.timespan();
456
- if ((timespan != null) && !_.isNaN(timespan)) {
457
- url = "" + url + "&timespan=" + timespan;
458
- }
459
- return url;
460
- },
461
- forceUpdate: function() {
462
- return this.fetch({
463
- success: function(model, response) {
464
- return model.trigger('redraw');
465
- }
466
- });
467
- }
564
+ view.render();
565
+ return $('#page-titles').append(view.el);
566
+ },
567
+ render: function() {
568
+ $('#page-titles').empty();
569
+ return this.pageInfos.each(this.addOne);
570
+ }
571
+ });
572
+ var SensorInfoListView;
573
+
574
+ SensorInfoListView = Backbone.View.extend({
575
+ tagName: 'div',
576
+ template: function() {
577
+ return _.template($("#sensor-list").html());
578
+ },
579
+ initialize: function(sensorInfo) {
580
+ this.sensorInfo = sensorInfo;
581
+ return this.sensorInfo.bind('reset', this.render, this);
582
+ },
583
+ render: function() {
584
+ return this.$el.html(this.template()({
585
+ sensors: this.sensorInfo.toJSON()
586
+ }));
587
+ },
588
+ selectedSensors: function() {
589
+ var checked, ids, selected;
590
+ checked = _.filter(this.$el.find('.sensor-box'), function(el) {
591
+ return $(el).is(':checked');
468
592
  });
469
- WidgetList = Backbone.Collection.extend({
470
- model: Widget,
471
- url: function() {
472
- return ROOT + 'pages/' + pageInfos.selected().id + '/widgets';
473
- }
593
+ ids = {};
594
+ _.each(checked, function(box) {
595
+ return ids[box.id] = true;
474
596
  });
475
- SensorInfo = Backbone.Model.extend({});
476
- SensorInfoList = Backbone.Collection.extend({
477
- model: SensorInfo,
478
- url: function() {
479
- return ROOT + 'sensors';
480
- }
597
+ return selected = this.sensorInfo.filter(function(sensor) {
598
+ return ids[sensor.id];
481
599
  });
482
- SensorInfoListView = Backbone.View.extend({
483
- tagName: 'div',
484
- template: function() {
485
- return _.template($("#sensor-list").html());
486
- },
487
- initialize: function(sensorInfo) {
488
- this.sensorInfo = sensorInfo;
489
- return this.sensorInfo.bind('reset', this.render, this);
490
- },
491
- render: function() {
492
- return this.$el.html(this.template()({
493
- sensors: this.sensorInfo.toJSON()
494
- }));
495
- },
496
- selectedSensors: function() {
497
- var checked, ids, selected;
498
- checked = _.filter(this.$el.find('.sensor-box'), function(el) {
499
- return $(el).is(':checked');
500
- });
501
- ids = {};
502
- _.each(checked, function(box) {
503
- return ids[box.id] = true;
504
- });
505
- return selected = this.sensorInfo.filter(function(sensor) {
506
- return ids[sensor.id];
507
- });
508
- }
600
+ }
601
+ });
602
+ var DynamicChartView;
603
+
604
+ DynamicChartView = Backbone.View.extend({
605
+ initialize: function(options) {
606
+ this.pageInfos = options['pageInfos'];
607
+ this.sensors = [];
608
+ this.type = 'Area';
609
+ this.widget = new DynamicWidget;
610
+ this.widget.bind('destroy', this.remove, this);
611
+ return this.widget.bind('redraw', this.redrawChart, this);
612
+ },
613
+ tagName: 'div',
614
+ events: {
615
+ "click #refresh-chart": 'update',
616
+ "click #extend-timespan": 'extendTimespan',
617
+ "click #reset-timespan": 'resetTimespan',
618
+ "change #start-time input": 'maybeEnableStopTime',
619
+ "click #set-interval": 'setTimelineInterval'
620
+ },
621
+ template: function() {
622
+ return _.template($("#dynamic-widget-plotarea").html());
623
+ },
624
+ render: function() {
625
+ this.$el.html(this.template()());
626
+ return this.initDatePickers();
627
+ },
628
+ initDatePickers: function() {
629
+ this.$el.find(".datepicker").each(function(i) {
630
+ return $(this).datetimepicker({
631
+ showOtherMonths: true,
632
+ selectOtherMonths: true
633
+ });
509
634
  });
510
- DynamicChartView = Backbone.View.extend({
511
- initialize: function() {
512
- this.sensors = [];
513
- this.type = 'Area';
514
- this.widget = new DynamicWidget;
515
- this.widget.bind('destroy', this.remove, this);
516
- return this.widget.bind('redraw', this.redrawChart, this);
517
- },
518
- tagName: 'div',
519
- events: {
520
- "click #refresh-chart": 'update',
521
- "click #extend-timespan": 'extendTimespan',
522
- "click #reset-timespan": 'resetTimespan'
523
- },
524
- template: function() {
525
- return _.template($("#dynamic-widget-plotarea").html());
526
- },
527
- render: function() {
528
- return this.$el.html(this.template()());
529
- },
530
- extendTimespan: function() {
531
- var select, val;
532
- select = this.$el.find("#extend-timespan-val");
533
- val = select.first().val();
534
- this.widget.increaseTimespan(parseInt(val));
535
- return this.update();
536
- },
537
- resetTimespan: function() {
538
- this.widget.resetTimespan();
539
- return this.update();
540
- },
541
- sensorIds: function() {
542
- return _.map(this.sensors, function(s) {
543
- return s.id;
544
- });
545
- },
546
- redrawChart: function() {
547
- if (this.presenter) {
548
- return this.presenter.draw();
549
- } else {
550
- return this.presenter = WidgetPresenter.create(this.widget, this.chartContainer());
551
- }
552
- },
553
- chartContainer: function() {
554
- return this.$el.find('#chart')[0];
555
- },
556
- update: function() {
557
- if (this.sensors.length > 0) return this.widget.forceUpdate();
558
- },
559
- draw: function(sensors, type) {
560
- this.sensors = sensors;
561
- this.type = type;
562
- this.widget.set('sensorIds', this.sensorIds());
563
- this.widget.set('type', this.type);
564
- this.presenter = null;
565
- $(this.chartContainer()).empty();
566
- return this.widget.forceUpdate();
567
- }
635
+ return this.$el.find("#end-time input").prop("disabled", true);
636
+ },
637
+ setTimelineInterval: function() {
638
+ var end, start;
639
+ start = this.unixtimeFromDatepicker("#start-time input");
640
+ end = this.unixtimeFromDatepicker("#end-time input");
641
+ this.widget.setStartTime(start);
642
+ this.widget.setEndTime(end);
643
+ return this.update();
644
+ },
645
+ dateFromDatepicker: function(id) {
646
+ return this.$el.find(id).datetimepicker("getDate");
647
+ },
648
+ unixtimeFromDatepicker: function(id) {
649
+ var date;
650
+ date = this.dateFromDatepicker(id);
651
+ if (date) {
652
+ return date.getTime() / 1000;
653
+ } else {
654
+ return null;
655
+ }
656
+ },
657
+ maybeEnableStopTime: function() {
658
+ var date, disabled;
659
+ date = this.dateFromDatepicker("#start-time input");
660
+ disabled = date ? false : true;
661
+ return this.$el.find("#end-time input").prop("disabled", disabled);
662
+ },
663
+ extendTimespan: function() {
664
+ var select, val;
665
+ select = this.$el.find("#extend-timespan-val");
666
+ val = select.first().val();
667
+ this.widget.increaseTimespan(parseInt(val));
668
+ return this.update();
669
+ },
670
+ resetTimespan: function() {
671
+ this.widget.resetTimespan();
672
+ return this.update();
673
+ },
674
+ sensorIds: function() {
675
+ return _.map(this.sensors, function(s) {
676
+ return s.id;
568
677
  });
569
- DynamicWidgetView = Backbone.View.extend({
570
- tagName: 'div',
571
- initialize: function() {
572
- this.sensorInfo = new SensorInfoList;
573
- this.sensorListView = new SensorInfoListView(this.sensorInfo);
574
- this.chartView = new DynamicChartView;
575
- this.$el.html(this.template()());
576
- this.$el.find('#sensor-list-area').append(this.sensorListView.el);
577
- this.chartView.render();
578
- return this.$el.find('#dynamic-plotarea').append(this.chartView.el);
579
- },
580
- events: {
581
- "click #sensor-controls #refresh": 'refresh',
582
- "click #sensor-controls #draw": 'drawChart'
583
- },
584
- template: function() {
585
- return _.template($("#dynamic-widget").html());
586
- },
587
- errorTemplate: function() {
588
- return _.template($("#dynamic-widget-error").html());
589
- },
590
- error: function(error) {
591
- return this.$el.find('#errors').append(this.errorTemplate()({
592
- error: error
593
- }));
594
- },
595
- refresh: function() {
596
- return this.sensorInfo.fetch();
597
- },
598
- intervalsEqual: function(sensors) {
599
- var badIntervals, interval;
600
- interval = sensors[0].get('interval');
601
- badIntervals = _.filter(sensors, function(s) {
602
- return s.get('interval') !== interval;
603
- });
604
- return badIntervals.length === 0;
605
- },
606
- drawChart: function() {
607
- var selectedSensors, type;
608
- selectedSensors = this.sensorListView.selectedSensors();
609
- if (!(selectedSensors.length > 0)) return;
610
- if (!this.intervalsEqual(selectedSensors)) {
611
- this.error('Selected sensors have different intervals');
612
- return;
613
- }
614
- type = this.$el.find('#chart-type').val();
615
- return this.chartView.draw(selectedSensors, type);
616
- },
617
- render: function(container) {
618
- container.empty();
619
- container.append(this.$el);
620
- this.sensorInfo.fetch();
621
- return this.chartView.update();
622
- }
678
+ },
679
+ redrawChart: function() {
680
+ if (this.presenter) {
681
+ return this.presenter.draw();
682
+ } else {
683
+ return this.presenter = WidgetPresenter.create(this.pageInfos, this.widget, this.chartContainer());
684
+ }
685
+ },
686
+ chartContainer: function() {
687
+ return this.$el.find('#chart')[0];
688
+ },
689
+ update: function() {
690
+ if (this.sensors.length > 0) {
691
+ return this.widget.forceUpdate();
692
+ }
693
+ },
694
+ draw: function(sensors, type) {
695
+ this.sensors = sensors;
696
+ this.type = type;
697
+ this.widget.set('sensorIds', this.sensorIds());
698
+ this.widget.set('type', this.type);
699
+ this.presenter = null;
700
+ $(this.chartContainer()).empty();
701
+ return this.widget.forceUpdate();
702
+ }
703
+ });
704
+ var DynamicWidgetView;
705
+
706
+ DynamicWidgetView = Backbone.View.extend({
707
+ tagName: 'div',
708
+ initialize: function(options) {
709
+ this.pageInfos = options['pageInfos'];
710
+ this.sensorInfo = new SensorInfoList;
711
+ this.sensorListView = new SensorInfoListView(this.sensorInfo);
712
+ this.chartView = new DynamicChartView({
713
+ pageInfos: this.pageInfos
623
714
  });
624
- WidgetChartView = Backbone.View.extend({
625
- tagName: 'div',
626
- initialize: function() {
627
- return this.model.bind('destroy', this.remove, this);
628
- },
629
- updateData: function(min, max) {
630
- return this.presenter.draw(min, max);
631
- },
632
- render: function() {
633
- return this.presenter = WidgetPresenter.create(this.model, this.el);
634
- }
715
+ this.$el.html(this.template()());
716
+ this.$el.find('#sensor-list-area').append(this.sensorListView.el);
717
+ this.chartView.render();
718
+ return this.$el.find('#dynamic-plotarea').append(this.chartView.el);
719
+ },
720
+ events: {
721
+ "click #sensor-controls #refresh": 'refresh',
722
+ "click #sensor-controls #draw": 'drawChart'
723
+ },
724
+ template: function() {
725
+ return _.template($("#dynamic-widget").html());
726
+ },
727
+ errorTemplate: function() {
728
+ return _.template($("#dynamic-widget-error").html());
729
+ },
730
+ error: function(error) {
731
+ return this.$el.find('#errors').append(this.errorTemplate()({
732
+ error: error
733
+ }));
734
+ },
735
+ refresh: function() {
736
+ return this.sensorInfo.fetch();
737
+ },
738
+ intervalsEqual: function(sensors) {
739
+ var badIntervals, interval;
740
+ interval = sensors[0].get('interval');
741
+ badIntervals = _.filter(sensors, function(s) {
742
+ return s.get('interval') !== interval;
635
743
  });
636
- WidgetView = Backbone.View.extend({
637
- tagName: 'div',
638
- template: function() {
639
- return _.template($(".widget-template[data-widget-type=\"" + (this.model.get('type')) + "\"]").html());
640
- },
641
- initialize: function() {
642
- this.model.bind('destroy', this.remove, this);
643
- return this.model.bind('redraw', this.updateChart, this);
644
- },
645
- events: {
646
- "click #refresh": 'refresh',
647
- "click #need-refresh": 'setRefresh',
648
- "click #extend-timespan": 'extendTimespan',
649
- "click #reset-timespan": 'resetTimespan'
650
- },
651
- refresh: function() {
652
- return this.model.forceUpdate();
653
- },
654
- setRefresh: function() {
655
- var needRefresh;
656
- needRefresh = this.$el.find('#need-refresh').is(":checked");
657
- this.model.setRefresh(needRefresh);
658
- return true;
659
- },
660
- extendTimespan: function() {
661
- var select, val;
662
- select = this.$el.find("#extend-timespan-val");
663
- val = select.first().val();
664
- return this.model.increaseTimespan(parseInt(val));
665
- },
666
- resetTimespan: function() {
667
- return this.model.resetTimespan();
668
- },
669
- renderChart: function() {
670
- return this.chartView.render();
671
- },
672
- updateChart: function() {
673
- return this.chartView.updateData(this.cutoffMin(), this.cutoffMax());
674
- },
675
- render: function() {
676
- this.$el.html(this.template(this.model.toJSON()));
677
- this.chartView = new WidgetChartView({
678
- model: this.model
679
- });
680
- this.$el.find("#plotarea").append(this.chartView.el);
681
- return this.$el.addClass("span" + (this.model.get('width')));
682
- },
683
- cutoffMin: function() {
684
- var val;
685
- val = parseFloat(this.controlValue('#cutoff-min'));
686
- if (_.isNaN(val)) {
687
- return null;
688
- } else {
689
- return val;
690
- }
691
- },
692
- cutoffMax: function() {
693
- var val;
694
- val = parseFloat(this.controlValue('#cutoff-max'));
695
- if (_.isNaN(val)) {
696
- return null;
697
- } else {
698
- return val;
699
- }
700
- },
701
- controlValue: function(id) {
702
- var val;
703
- return val = this.$el.find(id).first().val();
704
- }
744
+ return badIntervals.length === 0;
745
+ },
746
+ drawChart: function() {
747
+ var selectedSensors, type;
748
+ selectedSensors = this.sensorListView.selectedSensors();
749
+ if (!(selectedSensors.length > 0)) {
750
+ return;
751
+ }
752
+ if (!this.intervalsEqual(selectedSensors)) {
753
+ this.error('Selected sensors have different intervals');
754
+ return;
755
+ }
756
+ type = this.$el.find('#chart-type').val();
757
+ return this.chartView.draw(selectedSensors, type);
758
+ },
759
+ render: function(container) {
760
+ container.empty();
761
+ container.append(this.$el);
762
+ this.sensorInfo.fetch();
763
+ return this.chartView.update();
764
+ }
765
+ });
766
+ var WidgetChartView;
767
+
768
+ WidgetChartView = Backbone.View.extend({
769
+ tagName: 'div',
770
+ initialize: function(options) {
771
+ this.pageInfos = options['pageInfos'];
772
+ return this.model.bind('destroy', this.remove, this);
773
+ },
774
+ updateData: function(min, max) {
775
+ return this.presenter.draw(min, max);
776
+ },
777
+ render: function() {
778
+ return this.presenter = WidgetPresenter.create(this.pageInfos, this.model, this.el);
779
+ }
780
+ });
781
+ var WidgetView;
782
+
783
+ WidgetView = Backbone.View.extend({
784
+ tagName: 'div',
785
+ template: function(args) {
786
+ return _.template($(".widget-template[data-widget-type=\"" + (this.model.get('type')) + "\"]").html())(args);
787
+ },
788
+ initialize: function(options) {
789
+ this.pageInfos = options['pageInfos'];
790
+ this.model.bind('destroy', this.remove, this);
791
+ return this.model.bind('redraw', this.updateChart, this);
792
+ },
793
+ events: {
794
+ "click #refresh": 'refresh',
795
+ "click #need-refresh": 'setRefresh',
796
+ "click #extend-timespan": 'extendTimespan',
797
+ "click #reset-timespan": 'resetTimespan',
798
+ "change #start-time input": 'maybeEnableStopTime',
799
+ "click #set-interval": 'setTimelineInterval'
800
+ },
801
+ refresh: function() {
802
+ return this.model.forceUpdate();
803
+ },
804
+ setRefresh: function() {
805
+ var needRefresh;
806
+ needRefresh = this.$el.find('#need-refresh').is(":checked");
807
+ this.model.setRefresh(needRefresh);
808
+ return true;
809
+ },
810
+ extendTimespan: function() {
811
+ var select, val;
812
+ select = this.$el.find("#extend-timespan-val");
813
+ val = select.first().val();
814
+ return this.model.increaseTimespan(parseInt(val));
815
+ },
816
+ setTimelineInterval: function() {
817
+ var end, start;
818
+ start = this.unixtimeFromDatepicker("#start-time input");
819
+ end = this.unixtimeFromDatepicker("#end-time input");
820
+ this.model.setStartTime(start);
821
+ return this.model.setEndTime(end);
822
+ },
823
+ maybeEnableStopTime: function() {
824
+ var date, disabled;
825
+ date = this.dateFromDatepicker("#start-time input");
826
+ disabled = date ? false : true;
827
+ return this.$el.find("#end-time input").prop("disabled", disabled);
828
+ },
829
+ resetTimespan: function() {
830
+ return this.model.resetTimespan();
831
+ },
832
+ renderChart: function() {
833
+ return this.chartView.render();
834
+ },
835
+ updateChart: function() {
836
+ return this.chartView.updateData(this.cutoffMin(), this.cutoffMax());
837
+ },
838
+ setIds: function() {
839
+ this.$el.find('#configure-button').prop('href', "#configure-" + this.model.id);
840
+ this.$el.find('#configure').attr('id', "configure-" + this.model.id);
841
+ this.$el.find('#start-time input').attr('id', "start-time-" + this.model.id);
842
+ return this.$el.find('#end-time input').attr('id', "end-time-" + this.model.id);
843
+ },
844
+ render: function() {
845
+ this.$el.html(this.template(this.model.toJSON()));
846
+ this.setIds();
847
+ this.chartView = new WidgetChartView({
848
+ pageInfos: this.pageInfos,
849
+ model: this.model
705
850
  });
706
- widgetList = new WidgetList;
707
- setInterval(function() {
708
- if (pageInfos.selected()) {
709
- return widgetList.each(function(w) {
710
- return w.refetch();
711
- });
712
- }
713
- }, 200);
714
- WidgetListView = Backbone.View.extend({
715
- initialize: function() {
716
- return widgetList.bind('reset', this.render, this);
717
- },
718
- render: function() {
719
- var container;
720
- container = $('#widgets');
721
- container.empty();
722
- return widgetList.each(function(w) {
723
- var view;
724
- view = new WidgetView({
725
- model: w
726
- });
727
- view.render();
728
- container.append(view.el);
729
- return view.renderChart();
730
- });
731
- }
851
+ this.$el.find("#plotarea").append(this.chartView.el);
852
+ this.$el.addClass("span" + (this.model.get('width')));
853
+ return this.initDatePickers();
854
+ },
855
+ initDatePickers: function() {
856
+ this.$el.find(".datepicker").each(function(i) {
857
+ return $(this).datetimepicker({
858
+ showOtherMonths: true,
859
+ selectOtherMonths: true
860
+ });
732
861
  });
733
- widgetListApp = new WidgetListView;
734
- AppRouter = Backbone.Router.extend({
735
- routes: {
736
- 'pages/:id': 'getPage',
737
- 'custom': 'custom',
738
- '*actions': 'defaultRoute'
739
- },
740
- getPage: function(ids) {
741
- var id;
742
- id = parseInt(ids);
743
- pageInfos.selectPage(id);
744
- return widgetList.fetch();
745
- },
746
- custom: function() {
747
- var dynamicWidget;
748
- pageInfos.selectNone();
749
- dynamicWidget = new DynamicWidgetView;
750
- return dynamicWidget.render($('#widgets'));
751
- },
752
- defaultRoute: function(actions) {
753
- if (pageInfos.length > 0) {
754
- return this.navigate('//pages/1');
755
- } else {
756
- return this.navigate('//custom');
757
- }
758
- }
862
+ return this.$el.find("#end-time input").prop("disabled", true);
863
+ },
864
+ cutoffMin: function() {
865
+ var val;
866
+ val = parseFloat(this.controlValue('#cutoff-min'));
867
+ if (_.isNaN(val)) {
868
+ return null;
869
+ } else {
870
+ return val;
871
+ }
872
+ },
873
+ cutoffMax: function() {
874
+ var val;
875
+ val = parseFloat(this.controlValue('#cutoff-max'));
876
+ if (_.isNaN(val)) {
877
+ return null;
878
+ } else {
879
+ return val;
880
+ }
881
+ },
882
+ controlValue: function(id) {
883
+ var val;
884
+ return val = this.$el.find(id).first().val();
885
+ },
886
+ dateFromDatepicker: function(id) {
887
+ return this.$el.find(id).datetimepicker("getDate");
888
+ },
889
+ unixtimeFromDatepicker: function(id) {
890
+ var date;
891
+ date = this.dateFromDatepicker(id);
892
+ if (date) {
893
+ return date.getTime() / 1000;
894
+ } else {
895
+ return null;
896
+ }
897
+ }
898
+ });
899
+ var WidgetListView;
900
+
901
+ WidgetListView = Backbone.View.extend({
902
+ initialize: function(options) {
903
+ this.widgetList = options['widgetList'];
904
+ this.pageInfos = options['pageInfos'];
905
+ return this.widgetList.bind('reset', this.render, this);
906
+ },
907
+ render: function() {
908
+ var container,
909
+ _this = this;
910
+ container = $('#widgets');
911
+ container.empty();
912
+ return this.widgetList.each(function(w) {
913
+ var view;
914
+ view = new WidgetView({
915
+ pageInfos: _this.pageInfos,
916
+ model: w
917
+ });
918
+ view.render();
919
+ container.append(view.el);
920
+ return view.renderChart();
759
921
  });
760
- appRouter = new AppRouter;
761
- return Backbone.history.start();
762
- };
763
-
764
- }).call(this);
922
+ }
923
+ });
924
+ var AppRouter;
925
+
926
+ AppRouter = Backbone.Router.extend({
927
+ initialize: function(pageInfos, widgetList) {
928
+ this.pageInfos = pageInfos;
929
+ this.widgetList = widgetList;
930
+ },
931
+ routes: {
932
+ 'pages/:id': 'getPage',
933
+ 'custom': 'custom',
934
+ '*actions': 'defaultRoute'
935
+ },
936
+ getPage: function(ids) {
937
+ var id;
938
+ id = parseInt(ids);
939
+ this.pageInfos.selectPage(id);
940
+ return this.widgetList.fetch();
941
+ },
942
+ custom: function() {
943
+ var dynamicWidget;
944
+ this.pageInfos.selectNone();
945
+ dynamicWidget = new DynamicWidgetView({
946
+ pageInfos: this.pageInfos
947
+ });
948
+ return dynamicWidget.render($('#widgets'));
949
+ },
950
+ defaultRoute: function(actions) {
951
+ if (this.pageInfos.length > 0) {
952
+ return this.navigate('//pages/1');
953
+ } else {
954
+ return this.navigate('//custom');
955
+ }
956
+ }
957
+ });
958
+
959
+ document.startApp = function() {
960
+ var appRouter, pageInfos, pageTitlesApp, widgetList, widgetListApp;
961
+ pageInfos = new PageInfoList;
962
+ pageTitlesApp = new PageTitlesView(pageInfos);
963
+ pageInfos.reset(gon.pageInfos);
964
+ widgetList = new WidgetList;
965
+ widgetList.setContext(pageInfos);
966
+ widgetList.startPolling();
967
+ widgetListApp = new WidgetListView({
968
+ widgetList: widgetList,
969
+ pageInfos: pageInfos
970
+ });
971
+ appRouter = new AppRouter(pageInfos, widgetList);
972
+ return Backbone.history.start();
973
+ };