pulse-meter 0.2.1 → 0.2.2

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 (82) hide show
  1. data/.travis.yml +4 -0
  2. data/examples/basic.ru +23 -5
  3. data/examples/basic_sensor_data.rb +15 -2
  4. data/examples/full/server.ru +2 -3
  5. data/examples/minimal/server.ru +3 -2
  6. data/lib/pulse-meter/sensor.rb +2 -1
  7. data/lib/pulse-meter/sensor/configuration.rb +3 -1
  8. data/lib/pulse-meter/sensor/hashed_indicator.rb +22 -0
  9. data/lib/pulse-meter/sensor/timeline.rb +13 -1
  10. data/lib/pulse-meter/version.rb +1 -1
  11. data/lib/pulse-meter/visualize/app.rb +6 -2
  12. data/lib/pulse-meter/visualize/base.rb +15 -0
  13. data/lib/pulse-meter/visualize/dsl/base.rb +131 -0
  14. data/lib/pulse-meter/visualize/dsl/errors.rb +0 -6
  15. data/lib/pulse-meter/visualize/dsl/layout.rb +12 -41
  16. data/lib/pulse-meter/visualize/dsl/page.rb +15 -41
  17. data/lib/pulse-meter/visualize/dsl/sensor.rb +9 -10
  18. data/lib/pulse-meter/visualize/dsl/widget.rb +18 -65
  19. data/lib/pulse-meter/visualize/dsl/widget_old.rb +95 -0
  20. data/lib/pulse-meter/visualize/dsl/widgets/area.rb +20 -0
  21. data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +12 -0
  22. data/lib/pulse-meter/visualize/dsl/widgets/line.rb +21 -0
  23. data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +16 -0
  24. data/lib/pulse-meter/visualize/dsl/widgets/table.rb +19 -0
  25. data/lib/pulse-meter/visualize/layout.rb +7 -16
  26. data/lib/pulse-meter/visualize/page.rb +5 -10
  27. data/lib/pulse-meter/visualize/public/favicon.ico +0 -0
  28. data/lib/pulse-meter/visualize/public/js/application.coffee +156 -107
  29. data/lib/pulse-meter/visualize/public/js/application.js +283 -122
  30. data/lib/pulse-meter/visualize/sensor.rb +7 -13
  31. data/lib/pulse-meter/visualize/views/main.haml +8 -52
  32. data/lib/pulse-meter/visualize/views/widgets/area.haml +31 -0
  33. data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +11 -0
  34. data/lib/pulse-meter/visualize/views/widgets/gauge.haml +13 -0
  35. data/lib/pulse-meter/visualize/views/widgets/line.haml +31 -0
  36. data/lib/pulse-meter/visualize/views/widgets/pie.haml +13 -0
  37. data/lib/pulse-meter/visualize/views/widgets/table.haml +23 -0
  38. data/lib/pulse-meter/visualize/widget.rb +17 -87
  39. data/lib/pulse-meter/visualize/widgets/gauge.rb +47 -0
  40. data/lib/pulse-meter/visualize/widgets/pie.rb +36 -0
  41. data/lib/pulse-meter/visualize/widgets/timeline.rb +90 -0
  42. data/lib/pulse-meter/visualizer.rb +18 -8
  43. data/perl/PulseMeter/Sensor/Base.pm +42 -0
  44. data/perl/PulseMeter/Sensor/Counter.pm +19 -0
  45. data/perl/PulseMeter/Sensor/HashedIndicator.pm +12 -0
  46. data/perl/PulseMeter/Sensor/Indicator.pm +17 -0
  47. data/perl/PulseMeter/Sensor/Timeline.pm +51 -0
  48. data/perl/PulseMeter/Sensor/Timelined/Average.pm +13 -0
  49. data/perl/PulseMeter/Sensor/Timelined/Counter.pm +12 -0
  50. data/perl/PulseMeter/Sensor/Timelined/HashedCounter.pm +12 -0
  51. data/perl/PulseMeter/Sensor/Timelined/Max.pm +18 -0
  52. data/perl/PulseMeter/Sensor/Timelined/Median.pm +8 -0
  53. data/perl/PulseMeter/Sensor/Timelined/Min.pm +18 -0
  54. data/perl/PulseMeter/Sensor/Timelined/Percentile.pm +17 -0
  55. data/perl/PulseMeter/Sensor/Timelined/UniqCounter.pm +13 -0
  56. data/perl/PulseMeter/Sensor/UniqCounter.pm +12 -0
  57. data/pulse-meter.gemspec +1 -0
  58. data/spec/pulse_meter/sensor/configuration_spec.rb +10 -2
  59. data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +39 -0
  60. data/spec/pulse_meter/visualize/dsl/layout_spec.rb +8 -8
  61. data/spec/pulse_meter/visualize/dsl/page_spec.rb +29 -42
  62. data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +5 -5
  63. data/spec/pulse_meter/visualize/dsl/widget_spec.rb +1 -122
  64. data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +44 -0
  65. data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +22 -0
  66. data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +44 -0
  67. data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +35 -0
  68. data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +36 -0
  69. data/spec/pulse_meter/visualize/layout_spec.rb +3 -3
  70. data/spec/pulse_meter/visualize/page_spec.rb +2 -2
  71. data/spec/pulse_meter/visualize/sensor_spec.rb +4 -4
  72. data/spec/pulse_meter/visualize/series_extractor_spec.rb +3 -3
  73. data/spec/pulse_meter/visualize/widgets/area_spec.rb +78 -0
  74. data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +63 -0
  75. data/spec/pulse_meter/visualize/widgets/line_spec.rb +77 -0
  76. data/spec/pulse_meter/visualize/widgets/pie_spec.rb +73 -0
  77. data/spec/pulse_meter/visualize/widgets/table_spec.rb +78 -0
  78. data/spec/shared_examples/dsl_widget.rb +106 -0
  79. data/spec/shared_examples/timeline_sensor.rb +32 -2
  80. metadata +75 -6
  81. data/lib/pulse-meter/visualize/dsl.rb +0 -0
  82. data/spec/pulse_meter/visualize/widget_spec.rb +0 -122
@@ -1,5 +1,8 @@
1
- $ ->
1
+ document.startApp = ->
2
2
  globalOptions = gon.options
3
+
4
+ String::capitalize = ->
5
+ @charAt(0).toUpperCase() + @slice(1)
3
6
 
4
7
  PageInfo = Backbone.Model.extend {
5
8
  }
@@ -10,7 +13,6 @@ $ ->
10
13
  @find (m) ->
11
14
  m.get 'selected'
12
15
 
13
-
14
16
  selectFirst: ->
15
17
  @at(0).set('selected', true) if @length > 0
16
18
 
@@ -55,155 +57,205 @@ $ ->
55
57
  }
56
58
 
57
59
  pageTitlesApp = new PageTitlesView
58
-
59
60
  pageInfos.reset gon.pageInfos
60
61
 
61
- Widget = Backbone.Model.extend {
62
- initialize: ->
63
- @needRefresh = true
64
- @setNextFetch()
65
- @timespanInc = 0
66
-
67
- increaseTimespan: (inc) ->
68
- @timespanInc = @timespanInc + inc
69
- @forceUpdate()
70
-
71
- resetTimespan: ->
72
- @timespanInc = 0
73
- @forceUpdate()
74
-
75
- url: ->
76
- "#{@collection.url()}/#{@get('id')}?timespan=#{@get('timespan') + @timespanInc}"
77
62
 
78
- time: -> (new Date()).getTime()
63
+ class WidgetPresenter
64
+ constructor: (model, el) ->
65
+ @model = model
66
+ chartClass = @chartClass()
67
+ @chart = new chartClass(el)
68
+ @draw()
79
69
 
80
- setNextFetch: ->
81
- @nextFetch = @time() + @get('interval') * 1000
70
+ get: (arg) -> @model.get(arg)
71
+
72
+ dateOffset: ->
73
+ if globalOptions.useUtc
74
+ (new Date).getTimezoneOffset() * 60000
75
+ else
76
+ 0
77
+
78
+ options: ->
79
+ {
80
+ title: @get('title')
81
+ height: 300
82
+ }
82
83
 
83
- setRefresh: (needRefresh) ->
84
- @needRefresh = needRefresh
84
+ mergedOptions: -> $.extend(true,
85
+ @options(),
86
+ globalOptions.gchartOptions,
87
+ pageInfos.selected().get('gchartOptions')
88
+ @get('gchartOptions')
89
+ )
85
90
 
86
- needFetch: ->
87
- interval = @get('interval')
88
- @time() > @nextFetch && @needRefresh && interval? && interval > 0
91
+ data: -> new google.visualization.DataTable
89
92
 
90
- refetch: ->
91
- if @needFetch()
92
- @forceUpdate()
93
- @setNextFetch()
93
+ chartClass: -> google.visualization[@visualization]
94
94
 
95
+ cutoff: ->
96
+
95
97
  cutoffValue: (v, min, max) ->
96
- if v isnt null
97
- if min isnt null && v < min
98
+ if v?
99
+ if min? && v < min
98
100
  min
99
- else if max isnt null && v > max
101
+ else if max? && v > max
100
102
  max
101
103
  else
102
104
  v
103
105
  else
104
106
  0
105
107
 
106
- cutoff: (min, max) ->
107
- _.each(@get('series').rows, (row) ->
108
- for i in [1 .. row.length - 1]
109
- row[i] = @cutoffValue(row[i], min, max)
110
- , this)
111
-
112
- forceUpdate: ->
113
- @fetch {
114
- success: (model, response) ->
115
- model.trigger('redraw')
116
- }
117
-
118
- pieData: ->
119
- data = new google.visualization.DataTable()
108
+ draw: (min, max) ->
109
+ @cutoff(min, max)
110
+ @chart.draw(@data(), @mergedOptions())
111
+
112
+ WidgetPresenter.create = (model, el) ->
113
+ type = model.get('type')
114
+ if type? && type.match(/^\w+$/)
115
+ presenterClass = eval("#{type.capitalize()}Presenter")
116
+ new presenterClass(model, el)
117
+ else
118
+ null
119
+
120
+ class PiePresenter extends WidgetPresenter
121
+ visualization: 'PieChart'
122
+
123
+ cutoff: ->
124
+
125
+ data: ->
126
+ data = super()
120
127
  data.addColumn('string', 'Title')
121
128
  data.addColumn('number', @get('valuesTitle'))
122
129
  data.addRows(@get('series').data)
123
130
  data
124
131
 
125
- dateOffset: ->
126
- if globalOptions.useUtc
127
- (new Date).getTimezoneOffset() * 60000
128
- else
129
- 0
132
+ options: ->
133
+ $.extend true, super(), {
134
+ slices: @get('series').options
135
+ legend: {
136
+ position: 'bottom'
137
+ }
138
+ }
130
139
 
131
- lineData: ->
132
- title = @get('title')
133
- data = new google.visualization.DataTable()
140
+ class TimelinePresenter extends WidgetPresenter
141
+ data: ->
142
+ data = super()
134
143
  data.addColumn('datetime', 'Time')
135
144
  dateOffset = @dateOffset()
136
145
  series = @get('series')
137
146
  _.each series.titles, (t) ->
138
147
  data.addColumn('number', t)
139
148
 
140
- console.log series
141
149
  _.each series.rows, (row) ->
142
150
  row[0] = new Date(row[0] + dateOffset)
143
151
  data.addRow(row)
144
152
  data
145
153
 
154
+ class SeriesPresenter extends TimelinePresenter
146
155
  options: ->
147
- {
148
- title: @get('title')
156
+ format = if @model.timespan() > 24 * 60 * 60
157
+ 'yyyy.MM.dd HH:mm:ss'
158
+ else
159
+ 'HH:mm:ss'
160
+
161
+ $.extend true, super(), {
149
162
  lineWidth: 1
150
163
  chartArea: {
151
164
  left: 40
152
165
  width: '100%'
153
166
  }
154
- height: 300
155
167
  legend: {
156
168
  position: 'bottom'
157
169
  }
158
170
  vAxis: {
159
171
  title: @get('valuesTitle')
160
172
  }
161
- axisTitlesPosition: 'in'
162
- }
163
-
164
- pieOptions: ->
165
- $.extend true, @options(), {
166
- slices: @get('series').options
167
- }
168
-
169
- lineOptions: ->
170
- $.extend true, @options(), {
171
173
  hAxis: {
172
- format: 'yyyy.MM.dd HH:mm:ss'
174
+ format: format
173
175
  }
174
176
  series: @get('series').options
177
+ axisTitlesPosition: 'in'
175
178
  }
179
+
180
+ cutoff: (min, max) ->
181
+ _.each(@get('series').rows, (row) ->
182
+ for i in [1 .. row.length - 1]
183
+ value = row[i]
184
+ value = 0 unless value?
185
+ row[i] = @cutoffValue(value, min, max)
186
+ , this)
187
+
188
+
189
+ class LinePresenter extends SeriesPresenter
190
+ visualization: 'LineChart'
191
+
192
+ class AreaPresenter extends SeriesPresenter
193
+ visualization: 'AreaChart'
194
+
195
+ class TablePresenter extends TimelinePresenter
196
+ visualization: 'Table'
197
+
198
+ cutoff: ->
176
199
 
177
- tableOptions: ->
178
- $.extend true, @lineOptions(), {
200
+ options: ->
201
+ $.extend true, super(), {
179
202
  sortColumn: 0
180
203
  sortAscending: false
181
204
  }
182
205
 
183
- chartOptions: ->
184
- opts = if @get('type') == 'pie'
185
- @pieOptions()
186
- else if @get('type') == 'table'
187
- @tableOptions()
188
- else
189
- @lineOptions()
190
- $.extend true, opts, globalOptions.gchartOptions, pageInfos.selected().get('gchartOptions')
206
+ class GaugePresenter extends WidgetPresenter
207
+ visualization: 'Gauge'
191
208
 
192
- chartData: ->
193
- if @get('type') == 'pie'
194
- @pieData()
195
- else
196
- @lineData()
197
-
198
- chartClass: ->
199
- if @get('type') == 'pie'
200
- google.visualization.PieChart
201
- else if @get('type') == 'area'
202
- google.visualization.AreaChart
203
- else if @get('type') == 'table'
204
- google.visualization.Table
205
- else
206
- google.visualization.LineChart
209
+ cutoff: ->
210
+
211
+ data: ->
212
+ data = super()
213
+ data.addColumn('string', 'Label')
214
+ data.addColumn('number', @get('valuesTitle'))
215
+ data.addRows(@get('series'))
216
+ data
217
+
218
+ Widget = Backbone.Model.extend {
219
+ initialize: ->
220
+ @needRefresh = true
221
+ @setNextFetch()
222
+ @timespanInc = 0
223
+
224
+ increaseTimespan: (inc) ->
225
+ @timespanInc = @timespanInc + inc
226
+ @forceUpdate()
227
+
228
+ resetTimespan: ->
229
+ @timespanInc = 0
230
+ @forceUpdate()
231
+
232
+ timespan: -> @get('timespan') + @timespanInc
233
+
234
+ url: ->
235
+ "#{@collection.url()}/#{@get('id')}?timespan=#{@timespan()}"
236
+
237
+ time: -> (new Date()).getTime()
238
+
239
+ setNextFetch: ->
240
+ @nextFetch = @time() + @get('redrawInterval') * 1000
241
+
242
+ setRefresh: (needRefresh) ->
243
+ @needRefresh = needRefresh
244
+
245
+ needFetch: ->
246
+ interval = @get('redrawInterval')
247
+ @time() > @nextFetch && @needRefresh && interval? && interval > 0
248
+
249
+ refetch: ->
250
+ if @needFetch()
251
+ @forceUpdate()
252
+ @setNextFetch()
253
+
254
+ forceUpdate: ->
255
+ @fetch {
256
+ success: (model, response) ->
257
+ model.trigger('redraw')
258
+ }
207
259
 
208
260
  }
209
261
 
@@ -220,20 +272,17 @@ $ ->
220
272
  @model.bind 'destroy', @remove, this
221
273
 
222
274
  updateData: (min, max) ->
223
- @model.cutoff(min, max)
224
- @chart.draw(@model.chartData(), @model.chartOptions())
275
+ @presenter.draw(min, max)
225
276
 
226
277
  render: ->
227
- chartClass = @model.chartClass()
228
- @chart = new chartClass(@el)
229
- @updateData()
230
-
278
+ @presenter = WidgetPresenter.create(@model, @el)
231
279
  }
232
280
 
233
281
  WidgetView = Backbone.View.extend {
234
282
  tagName: 'div'
235
283
 
236
- template: _.template($('#widget-template').html())
284
+ template: ->
285
+ _.template($(".widget-template[data-widget-type=\"#{@model.get('type')}\"]").html())
237
286
 
238
287
  initialize: ->
239
288
  @model.bind('destroy', @remove, this)
@@ -271,10 +320,10 @@ $ ->
271
320
  render: ->
272
321
  @$el.html @template(@model.toJSON())
273
322
  @chartView = new WidgetChartView {
274
- model: @model
275
- }
276
- @$el.find("#plotarea").append(@chartView.el)
277
- @$el.addClass "span#{@model.get('width')}"
323
+ model: @model
324
+ }
325
+ @$el.find("#plotarea").append(@chartView.el)
326
+ @$el.addClass("span#{@model.get('width')}")
278
327
 
279
328
  cutoffMin: ->
280
329
  val = parseFloat(@controlValue('#cutoff-min'))
@@ -1,9 +1,14 @@
1
1
  // Generated by CoffeeScript 1.2.1-pre
2
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; };
3
5
 
4
- $(function() {
5
- var AppRouter, PageInfo, PageInfoList, PageTitleView, PageTitlesView, Widget, WidgetChartView, WidgetList, WidgetListView, WidgetView, appRouter, globalOptions, pageInfos, pageTitlesApp, widgetList, widgetListApp;
6
+ document.startApp = function() {
7
+ var AppRouter, AreaPresenter, GaugePresenter, LinePresenter, PageInfo, PageInfoList, PageTitleView, PageTitlesView, PiePresenter, SeriesPresenter, TablePresenter, TimelinePresenter, Widget, WidgetChartView, WidgetList, WidgetListView, WidgetPresenter, WidgetView, appRouter, globalOptions, pageInfos, pageTitlesApp, widgetList, widgetListApp;
6
8
  globalOptions = gon.options;
9
+ String.prototype.capitalize = function() {
10
+ return this.charAt(0).toUpperCase() + this.slice(1);
11
+ };
7
12
  PageInfo = Backbone.Model.extend({});
8
13
  PageInfoList = Backbone.Collection.extend({
9
14
  model: PageInfo,
@@ -57,48 +62,56 @@
57
62
  });
58
63
  pageTitlesApp = new PageTitlesView;
59
64
  pageInfos.reset(gon.pageInfos);
60
- Widget = Backbone.Model.extend({
61
- initialize: function() {
62
- this.needRefresh = true;
63
- this.setNextFetch();
64
- return this.timespanInc = 0;
65
- },
66
- increaseTimespan: function(inc) {
67
- this.timespanInc = this.timespanInc + inc;
68
- return this.forceUpdate();
69
- },
70
- resetTimespan: function() {
71
- this.timespanInc = 0;
72
- return this.forceUpdate();
73
- },
74
- url: function() {
75
- return "" + (this.collection.url()) + "/" + (this.get('id')) + "?timespan=" + (this.get('timespan') + this.timespanInc);
76
- },
77
- time: function() {
78
- return (new Date()).getTime();
79
- },
80
- setNextFetch: function() {
81
- return this.nextFetch = this.time() + this.get('interval') * 1000;
82
- },
83
- setRefresh: function(needRefresh) {
84
- return this.needRefresh = needRefresh;
85
- },
86
- needFetch: function() {
87
- var interval;
88
- interval = this.get('interval');
89
- return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0;
90
- },
91
- refetch: function() {
92
- if (this.needFetch()) {
93
- this.forceUpdate();
94
- return this.setNextFetch();
65
+ WidgetPresenter = (function() {
66
+
67
+ WidgetPresenter.name = 'WidgetPresenter';
68
+
69
+ function WidgetPresenter(model, el) {
70
+ var chartClass;
71
+ this.model = model;
72
+ chartClass = this.chartClass();
73
+ this.chart = new chartClass(el);
74
+ this.draw();
75
+ }
76
+
77
+ WidgetPresenter.prototype.get = function(arg) {
78
+ return this.model.get(arg);
79
+ };
80
+
81
+ WidgetPresenter.prototype.dateOffset = function() {
82
+ if (globalOptions.useUtc) {
83
+ return (new Date).getTimezoneOffset() * 60000;
84
+ } else {
85
+ return 0;
95
86
  }
96
- },
97
- cutoffValue: function(v, min, max) {
98
- if (v !== null) {
99
- if (min !== null && v < min) {
87
+ };
88
+
89
+ WidgetPresenter.prototype.options = function() {
90
+ return {
91
+ title: this.get('title'),
92
+ height: 300
93
+ };
94
+ };
95
+
96
+ WidgetPresenter.prototype.mergedOptions = function() {
97
+ return $.extend(true, this.options(), globalOptions.gchartOptions, pageInfos.selected().get('gchartOptions'), this.get('gchartOptions'));
98
+ };
99
+
100
+ WidgetPresenter.prototype.data = function() {
101
+ return new google.visualization.DataTable;
102
+ };
103
+
104
+ WidgetPresenter.prototype.chartClass = function() {
105
+ return google.visualization[this.visualization];
106
+ };
107
+
108
+ WidgetPresenter.prototype.cutoff = function() {};
109
+
110
+ WidgetPresenter.prototype.cutoffValue = function(v, min, max) {
111
+ if (v != null) {
112
+ if ((min != null) && v < min) {
100
113
  return min;
101
- } else if (max !== null && v > max) {
114
+ } else if ((max != null) && v > max) {
102
115
  return max;
103
116
  } else {
104
117
  return v;
@@ -106,115 +119,265 @@
106
119
  } else {
107
120
  return 0;
108
121
  }
109
- },
110
- cutoff: function(min, max) {
111
- return _.each(this.get('series').rows, function(row) {
112
- var i, _i, _ref, _results;
113
- _results = [];
114
- for (i = _i = 1, _ref = row.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
115
- _results.push(row[i] = this.cutoffValue(row[i], min, max));
116
- }
117
- return _results;
118
- }, this);
119
- },
120
- forceUpdate: function() {
121
- return this.fetch({
122
- success: function(model, response) {
123
- return model.trigger('redraw');
124
- }
125
- });
126
- },
127
- pieData: function() {
122
+ };
123
+
124
+ WidgetPresenter.prototype.draw = function(min, max) {
125
+ this.cutoff(min, max);
126
+ return this.chart.draw(this.data(), this.mergedOptions());
127
+ };
128
+
129
+ return WidgetPresenter;
130
+
131
+ })();
132
+ WidgetPresenter.create = function(model, el) {
133
+ var presenterClass, type;
134
+ type = model.get('type');
135
+ if ((type != null) && type.match(/^\w+$/)) {
136
+ presenterClass = eval("" + (type.capitalize()) + "Presenter");
137
+ return new presenterClass(model, el);
138
+ } else {
139
+ return null;
140
+ }
141
+ };
142
+ PiePresenter = (function(_super) {
143
+
144
+ __extends(PiePresenter, _super);
145
+
146
+ PiePresenter.name = 'PiePresenter';
147
+
148
+ function PiePresenter() {
149
+ return PiePresenter.__super__.constructor.apply(this, arguments);
150
+ }
151
+
152
+ PiePresenter.prototype.visualization = 'PieChart';
153
+
154
+ PiePresenter.prototype.cutoff = function() {};
155
+
156
+ PiePresenter.prototype.data = function() {
128
157
  var data;
129
- data = new google.visualization.DataTable();
158
+ data = PiePresenter.__super__.data.call(this);
130
159
  data.addColumn('string', 'Title');
131
160
  data.addColumn('number', this.get('valuesTitle'));
132
161
  data.addRows(this.get('series').data);
133
162
  return data;
134
- },
135
- dateOffset: function() {
136
- if (globalOptions.useUtc) {
137
- return (new Date).getTimezoneOffset() * 60000;
138
- } else {
139
- return 0;
140
- }
141
- },
142
- lineData: function() {
143
- var data, dateOffset, series, title;
144
- title = this.get('title');
145
- data = new google.visualization.DataTable();
163
+ };
164
+
165
+ PiePresenter.prototype.options = function() {
166
+ return $.extend(true, PiePresenter.__super__.options.call(this), {
167
+ slices: this.get('series').options,
168
+ legend: {
169
+ position: 'bottom'
170
+ }
171
+ });
172
+ };
173
+
174
+ return PiePresenter;
175
+
176
+ })(WidgetPresenter);
177
+ TimelinePresenter = (function(_super) {
178
+
179
+ __extends(TimelinePresenter, _super);
180
+
181
+ TimelinePresenter.name = 'TimelinePresenter';
182
+
183
+ function TimelinePresenter() {
184
+ return TimelinePresenter.__super__.constructor.apply(this, arguments);
185
+ }
186
+
187
+ TimelinePresenter.prototype.data = function() {
188
+ var data, dateOffset, series;
189
+ data = TimelinePresenter.__super__.data.call(this);
146
190
  data.addColumn('datetime', 'Time');
147
191
  dateOffset = this.dateOffset();
148
192
  series = this.get('series');
149
193
  _.each(series.titles, function(t) {
150
194
  return data.addColumn('number', t);
151
195
  });
152
- console.log(series);
153
196
  _.each(series.rows, function(row) {
154
197
  row[0] = new Date(row[0] + dateOffset);
155
198
  return data.addRow(row);
156
199
  });
157
200
  return data;
158
- },
159
- options: function() {
160
- return {
161
- title: this.get('title'),
201
+ };
202
+
203
+ return TimelinePresenter;
204
+
205
+ })(WidgetPresenter);
206
+ SeriesPresenter = (function(_super) {
207
+
208
+ __extends(SeriesPresenter, _super);
209
+
210
+ SeriesPresenter.name = 'SeriesPresenter';
211
+
212
+ function SeriesPresenter() {
213
+ return SeriesPresenter.__super__.constructor.apply(this, arguments);
214
+ }
215
+
216
+ SeriesPresenter.prototype.options = function() {
217
+ var format;
218
+ format = this.model.timespan() > 24 * 60 * 60 ? 'yyyy.MM.dd HH:mm:ss' : 'HH:mm:ss';
219
+ return $.extend(true, SeriesPresenter.__super__.options.call(this), {
162
220
  lineWidth: 1,
163
221
  chartArea: {
164
222
  left: 40,
165
223
  width: '100%'
166
224
  },
167
- height: 300,
168
225
  legend: {
169
226
  position: 'bottom'
170
227
  },
171
228
  vAxis: {
172
229
  title: this.get('valuesTitle')
173
230
  },
174
- axisTitlesPosition: 'in'
175
- };
176
- },
177
- pieOptions: function() {
178
- return $.extend(true, this.options(), {
179
- slices: this.get('series').options
180
- });
181
- },
182
- lineOptions: function() {
183
- return $.extend(true, this.options(), {
184
231
  hAxis: {
185
- format: 'yyyy.MM.dd HH:mm:ss'
232
+ format: format
186
233
  },
187
- series: this.get('series').options
234
+ series: this.get('series').options,
235
+ axisTitlesPosition: 'in'
188
236
  });
189
- },
190
- tableOptions: function() {
191
- return $.extend(true, this.lineOptions(), {
237
+ };
238
+
239
+ SeriesPresenter.prototype.cutoff = function(min, max) {
240
+ return _.each(this.get('series').rows, function(row) {
241
+ var i, value, _i, _ref, _results;
242
+ _results = [];
243
+ for (i = _i = 1, _ref = row.length - 1; 1 <= _ref ? _i <= _ref : _i >= _ref; i = 1 <= _ref ? ++_i : --_i) {
244
+ value = row[i];
245
+ if (value == null) value = 0;
246
+ _results.push(row[i] = this.cutoffValue(value, min, max));
247
+ }
248
+ return _results;
249
+ }, this);
250
+ };
251
+
252
+ return SeriesPresenter;
253
+
254
+ })(TimelinePresenter);
255
+ LinePresenter = (function(_super) {
256
+
257
+ __extends(LinePresenter, _super);
258
+
259
+ LinePresenter.name = 'LinePresenter';
260
+
261
+ function LinePresenter() {
262
+ return LinePresenter.__super__.constructor.apply(this, arguments);
263
+ }
264
+
265
+ LinePresenter.prototype.visualization = 'LineChart';
266
+
267
+ return LinePresenter;
268
+
269
+ })(SeriesPresenter);
270
+ AreaPresenter = (function(_super) {
271
+
272
+ __extends(AreaPresenter, _super);
273
+
274
+ AreaPresenter.name = 'AreaPresenter';
275
+
276
+ function AreaPresenter() {
277
+ return AreaPresenter.__super__.constructor.apply(this, arguments);
278
+ }
279
+
280
+ AreaPresenter.prototype.visualization = 'AreaChart';
281
+
282
+ return AreaPresenter;
283
+
284
+ })(SeriesPresenter);
285
+ TablePresenter = (function(_super) {
286
+
287
+ __extends(TablePresenter, _super);
288
+
289
+ TablePresenter.name = 'TablePresenter';
290
+
291
+ function TablePresenter() {
292
+ return TablePresenter.__super__.constructor.apply(this, arguments);
293
+ }
294
+
295
+ TablePresenter.prototype.visualization = 'Table';
296
+
297
+ TablePresenter.prototype.cutoff = function() {};
298
+
299
+ TablePresenter.prototype.options = function() {
300
+ return $.extend(true, TablePresenter.__super__.options.call(this), {
192
301
  sortColumn: 0,
193
302
  sortAscending: false
194
303
  });
304
+ };
305
+
306
+ return TablePresenter;
307
+
308
+ })(TimelinePresenter);
309
+ GaugePresenter = (function(_super) {
310
+
311
+ __extends(GaugePresenter, _super);
312
+
313
+ GaugePresenter.name = 'GaugePresenter';
314
+
315
+ function GaugePresenter() {
316
+ return GaugePresenter.__super__.constructor.apply(this, arguments);
317
+ }
318
+
319
+ GaugePresenter.prototype.visualization = 'Gauge';
320
+
321
+ GaugePresenter.prototype.cutoff = function() {};
322
+
323
+ GaugePresenter.prototype.data = function() {
324
+ var data;
325
+ data = GaugePresenter.__super__.data.call(this);
326
+ data.addColumn('string', 'Label');
327
+ data.addColumn('number', this.get('valuesTitle'));
328
+ data.addRows(this.get('series'));
329
+ return data;
330
+ };
331
+
332
+ return GaugePresenter;
333
+
334
+ })(WidgetPresenter);
335
+ Widget = Backbone.Model.extend({
336
+ initialize: function() {
337
+ this.needRefresh = true;
338
+ this.setNextFetch();
339
+ return this.timespanInc = 0;
195
340
  },
196
- chartOptions: function() {
197
- var opts;
198
- opts = this.get('type') === 'pie' ? this.pieOptions() : this.get('type') === 'table' ? this.tableOptions() : this.lineOptions();
199
- return $.extend(true, opts, globalOptions.gchartOptions, pageInfos.selected().get('gchartOptions'));
341
+ increaseTimespan: function(inc) {
342
+ this.timespanInc = this.timespanInc + inc;
343
+ return this.forceUpdate();
200
344
  },
201
- chartData: function() {
202
- if (this.get('type') === 'pie') {
203
- return this.pieData();
204
- } else {
205
- return this.lineData();
206
- }
345
+ resetTimespan: function() {
346
+ this.timespanInc = 0;
347
+ return this.forceUpdate();
207
348
  },
208
- chartClass: function() {
209
- if (this.get('type') === 'pie') {
210
- return google.visualization.PieChart;
211
- } else if (this.get('type') === 'area') {
212
- return google.visualization.AreaChart;
213
- } else if (this.get('type') === 'table') {
214
- return google.visualization.Table;
215
- } else {
216
- return google.visualization.LineChart;
349
+ timespan: function() {
350
+ return this.get('timespan') + this.timespanInc;
351
+ },
352
+ url: function() {
353
+ return "" + (this.collection.url()) + "/" + (this.get('id')) + "?timespan=" + (this.timespan());
354
+ },
355
+ time: function() {
356
+ return (new Date()).getTime();
357
+ },
358
+ setNextFetch: function() {
359
+ return this.nextFetch = this.time() + this.get('redrawInterval') * 1000;
360
+ },
361
+ setRefresh: function(needRefresh) {
362
+ return this.needRefresh = needRefresh;
363
+ },
364
+ needFetch: function() {
365
+ var interval;
366
+ interval = this.get('redrawInterval');
367
+ return this.time() > this.nextFetch && this.needRefresh && (interval != null) && interval > 0;
368
+ },
369
+ refetch: function() {
370
+ if (this.needFetch()) {
371
+ this.forceUpdate();
372
+ return this.setNextFetch();
217
373
  }
374
+ },
375
+ forceUpdate: function() {
376
+ return this.fetch({
377
+ success: function(model, response) {
378
+ return model.trigger('redraw');
379
+ }
380
+ });
218
381
  }
219
382
  });
220
383
  WidgetList = Backbone.Collection.extend({
@@ -229,19 +392,17 @@
229
392
  return this.model.bind('destroy', this.remove, this);
230
393
  },
231
394
  updateData: function(min, max) {
232
- this.model.cutoff(min, max);
233
- return this.chart.draw(this.model.chartData(), this.model.chartOptions());
395
+ return this.presenter.draw(min, max);
234
396
  },
235
397
  render: function() {
236
- var chartClass;
237
- chartClass = this.model.chartClass();
238
- this.chart = new chartClass(this.el);
239
- return this.updateData();
398
+ return this.presenter = WidgetPresenter.create(this.model, this.el);
240
399
  }
241
400
  });
242
401
  WidgetView = Backbone.View.extend({
243
402
  tagName: 'div',
244
- template: _.template($('#widget-template').html()),
403
+ template: function() {
404
+ return _.template($(".widget-template[data-widget-type=\"" + (this.model.get('type')) + "\"]").html());
405
+ },
245
406
  initialize: function() {
246
407
  this.model.bind('destroy', this.remove, this);
247
408
  return this.model.bind('redraw', this.updateChart, this);
@@ -350,6 +511,6 @@
350
511
  });
351
512
  appRouter = new AppRouter;
352
513
  return Backbone.history.start();
353
- });
514
+ };
354
515
 
355
516
  }).call(this);