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.
- data/.travis.yml +4 -0
- data/examples/basic.ru +23 -5
- data/examples/basic_sensor_data.rb +15 -2
- data/examples/full/server.ru +2 -3
- data/examples/minimal/server.ru +3 -2
- data/lib/pulse-meter/sensor.rb +2 -1
- data/lib/pulse-meter/sensor/configuration.rb +3 -1
- data/lib/pulse-meter/sensor/hashed_indicator.rb +22 -0
- data/lib/pulse-meter/sensor/timeline.rb +13 -1
- data/lib/pulse-meter/version.rb +1 -1
- data/lib/pulse-meter/visualize/app.rb +6 -2
- data/lib/pulse-meter/visualize/base.rb +15 -0
- data/lib/pulse-meter/visualize/dsl/base.rb +131 -0
- data/lib/pulse-meter/visualize/dsl/errors.rb +0 -6
- data/lib/pulse-meter/visualize/dsl/layout.rb +12 -41
- data/lib/pulse-meter/visualize/dsl/page.rb +15 -41
- data/lib/pulse-meter/visualize/dsl/sensor.rb +9 -10
- data/lib/pulse-meter/visualize/dsl/widget.rb +18 -65
- data/lib/pulse-meter/visualize/dsl/widget_old.rb +95 -0
- data/lib/pulse-meter/visualize/dsl/widgets/area.rb +20 -0
- data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +12 -0
- data/lib/pulse-meter/visualize/dsl/widgets/line.rb +21 -0
- data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +16 -0
- data/lib/pulse-meter/visualize/dsl/widgets/table.rb +19 -0
- data/lib/pulse-meter/visualize/layout.rb +7 -16
- data/lib/pulse-meter/visualize/page.rb +5 -10
- data/lib/pulse-meter/visualize/public/favicon.ico +0 -0
- data/lib/pulse-meter/visualize/public/js/application.coffee +156 -107
- data/lib/pulse-meter/visualize/public/js/application.js +283 -122
- data/lib/pulse-meter/visualize/sensor.rb +7 -13
- data/lib/pulse-meter/visualize/views/main.haml +8 -52
- data/lib/pulse-meter/visualize/views/widgets/area.haml +31 -0
- data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +11 -0
- data/lib/pulse-meter/visualize/views/widgets/gauge.haml +13 -0
- data/lib/pulse-meter/visualize/views/widgets/line.haml +31 -0
- data/lib/pulse-meter/visualize/views/widgets/pie.haml +13 -0
- data/lib/pulse-meter/visualize/views/widgets/table.haml +23 -0
- data/lib/pulse-meter/visualize/widget.rb +17 -87
- data/lib/pulse-meter/visualize/widgets/gauge.rb +47 -0
- data/lib/pulse-meter/visualize/widgets/pie.rb +36 -0
- data/lib/pulse-meter/visualize/widgets/timeline.rb +90 -0
- data/lib/pulse-meter/visualizer.rb +18 -8
- data/perl/PulseMeter/Sensor/Base.pm +42 -0
- data/perl/PulseMeter/Sensor/Counter.pm +19 -0
- data/perl/PulseMeter/Sensor/HashedIndicator.pm +12 -0
- data/perl/PulseMeter/Sensor/Indicator.pm +17 -0
- data/perl/PulseMeter/Sensor/Timeline.pm +51 -0
- data/perl/PulseMeter/Sensor/Timelined/Average.pm +13 -0
- data/perl/PulseMeter/Sensor/Timelined/Counter.pm +12 -0
- data/perl/PulseMeter/Sensor/Timelined/HashedCounter.pm +12 -0
- data/perl/PulseMeter/Sensor/Timelined/Max.pm +18 -0
- data/perl/PulseMeter/Sensor/Timelined/Median.pm +8 -0
- data/perl/PulseMeter/Sensor/Timelined/Min.pm +18 -0
- data/perl/PulseMeter/Sensor/Timelined/Percentile.pm +17 -0
- data/perl/PulseMeter/Sensor/Timelined/UniqCounter.pm +13 -0
- data/perl/PulseMeter/Sensor/UniqCounter.pm +12 -0
- data/pulse-meter.gemspec +1 -0
- data/spec/pulse_meter/sensor/configuration_spec.rb +10 -2
- data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +39 -0
- data/spec/pulse_meter/visualize/dsl/layout_spec.rb +8 -8
- data/spec/pulse_meter/visualize/dsl/page_spec.rb +29 -42
- data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +5 -5
- data/spec/pulse_meter/visualize/dsl/widget_spec.rb +1 -122
- data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +44 -0
- data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +22 -0
- data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +44 -0
- data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +35 -0
- data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +36 -0
- data/spec/pulse_meter/visualize/layout_spec.rb +3 -3
- data/spec/pulse_meter/visualize/page_spec.rb +2 -2
- data/spec/pulse_meter/visualize/sensor_spec.rb +4 -4
- data/spec/pulse_meter/visualize/series_extractor_spec.rb +3 -3
- data/spec/pulse_meter/visualize/widgets/area_spec.rb +78 -0
- data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +63 -0
- data/spec/pulse_meter/visualize/widgets/line_spec.rb +77 -0
- data/spec/pulse_meter/visualize/widgets/pie_spec.rb +73 -0
- data/spec/pulse_meter/visualize/widgets/table_spec.rb +78 -0
- data/spec/shared_examples/dsl_widget.rb +106 -0
- data/spec/shared_examples/timeline_sensor.rb +32 -2
- metadata +75 -6
- data/lib/pulse-meter/visualize/dsl.rb +0 -0
- data/spec/pulse_meter/visualize/widget_spec.rb +0 -122
|
Binary file
|
|
@@ -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
|
-
|
|
63
|
+
class WidgetPresenter
|
|
64
|
+
constructor: (model, el) ->
|
|
65
|
+
@model = model
|
|
66
|
+
chartClass = @chartClass()
|
|
67
|
+
@chart = new chartClass(el)
|
|
68
|
+
@draw()
|
|
79
69
|
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
84
|
-
@
|
|
84
|
+
mergedOptions: -> $.extend(true,
|
|
85
|
+
@options(),
|
|
86
|
+
globalOptions.gchartOptions,
|
|
87
|
+
pageInfos.selected().get('gchartOptions')
|
|
88
|
+
@get('gchartOptions')
|
|
89
|
+
)
|
|
85
90
|
|
|
86
|
-
|
|
87
|
-
interval = @get('interval')
|
|
88
|
-
@time() > @nextFetch && @needRefresh && interval? && interval > 0
|
|
91
|
+
data: -> new google.visualization.DataTable
|
|
89
92
|
|
|
90
|
-
|
|
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
|
|
97
|
-
if min
|
|
98
|
+
if v?
|
|
99
|
+
if min? && v < min
|
|
98
100
|
min
|
|
99
|
-
else if 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
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
(
|
|
128
|
-
|
|
129
|
-
|
|
132
|
+
options: ->
|
|
133
|
+
$.extend true, super(), {
|
|
134
|
+
slices: @get('series').options
|
|
135
|
+
legend: {
|
|
136
|
+
position: 'bottom'
|
|
137
|
+
}
|
|
138
|
+
}
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
data =
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
178
|
-
$.extend true,
|
|
200
|
+
options: ->
|
|
201
|
+
$.extend true, super(), {
|
|
179
202
|
sortColumn: 0
|
|
180
203
|
sortAscending: false
|
|
181
204
|
}
|
|
182
205
|
|
|
183
|
-
|
|
184
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
@
|
|
224
|
-
@chart.draw(@model.chartData(), @model.chartOptions())
|
|
275
|
+
@presenter.draw(min, max)
|
|
225
276
|
|
|
226
277
|
render: ->
|
|
227
|
-
|
|
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:
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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 =
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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:
|
|
232
|
+
format: format
|
|
186
233
|
},
|
|
187
|
-
series: this.get('series').options
|
|
234
|
+
series: this.get('series').options,
|
|
235
|
+
axisTitlesPosition: 'in'
|
|
188
236
|
});
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
} else {
|
|
205
|
-
return this.lineData();
|
|
206
|
-
}
|
|
345
|
+
resetTimespan: function() {
|
|
346
|
+
this.timespanInc = 0;
|
|
347
|
+
return this.forceUpdate();
|
|
207
348
|
},
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
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.
|
|
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
|
-
|
|
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:
|
|
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);
|