pulse_meter-dygraphs_visualizer 0.4.15

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 (109) hide show
  1. data/.gitignore +19 -0
  2. data/.rbenv-version +1 -0
  3. data/.rspec +1 -0
  4. data/.rvmrc +1 -0
  5. data/.travis.yml +9 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +22 -0
  8. data/Procfile +3 -0
  9. data/README.md +40 -0
  10. data/Rakefile +54 -0
  11. data/examples/basic.ru +125 -0
  12. data/examples/basic_sensor_data.rb +97 -0
  13. data/lib/pulse_meter/dygraphs_visualize/app.rb +78 -0
  14. data/lib/pulse_meter/dygraphs_visualize/base.rb +15 -0
  15. data/lib/pulse_meter/dygraphs_visualize/coffee/application.coffee +37 -0
  16. data/lib/pulse_meter/dygraphs_visualize/coffee/collections/page_info_list.coffee +17 -0
  17. data/lib/pulse_meter/dygraphs_visualize/coffee/collections/sensor_info_list.coffee +4 -0
  18. data/lib/pulse_meter/dygraphs_visualize/coffee/collections/widget_list.coffee +14 -0
  19. data/lib/pulse_meter/dygraphs_visualize/coffee/extensions.coffee +26 -0
  20. data/lib/pulse_meter/dygraphs_visualize/coffee/models/dinamic_widget.coffee +34 -0
  21. data/lib/pulse_meter/dygraphs_visualize/coffee/models/page_info.coffee +2 -0
  22. data/lib/pulse_meter/dygraphs_visualize/coffee/models/sensor_info.coffee +2 -0
  23. data/lib/pulse_meter/dygraphs_visualize/coffee/models/widget.coffee +63 -0
  24. data/lib/pulse_meter/dygraphs_visualize/coffee/presenters/line.coffee +1 -0
  25. data/lib/pulse_meter/dygraphs_visualize/coffee/presenters/series.coffee +26 -0
  26. data/lib/pulse_meter/dygraphs_visualize/coffee/presenters/stack.coffee +1 -0
  27. data/lib/pulse_meter/dygraphs_visualize/coffee/presenters/timeline.coffee +13 -0
  28. data/lib/pulse_meter/dygraphs_visualize/coffee/presenters/widget.coffee +48 -0
  29. data/lib/pulse_meter/dygraphs_visualize/coffee/router.coffee +21 -0
  30. data/lib/pulse_meter/dygraphs_visualize/coffee/views/dynamic_chart.coffee +92 -0
  31. data/lib/pulse_meter/dygraphs_visualize/coffee/views/dynamic_widget.coffee +58 -0
  32. data/lib/pulse_meter/dygraphs_visualize/coffee/views/page_title.coffee +17 -0
  33. data/lib/pulse_meter/dygraphs_visualize/coffee/views/page_titles.coffee +15 -0
  34. data/lib/pulse_meter/dygraphs_visualize/coffee/views/sensor_info_list.coffee +19 -0
  35. data/lib/pulse_meter/dygraphs_visualize/coffee/views/widget.coffee +91 -0
  36. data/lib/pulse_meter/dygraphs_visualize/coffee/views/widget_chart.coffee +15 -0
  37. data/lib/pulse_meter/dygraphs_visualize/coffee/views/widget_list.coffee +15 -0
  38. data/lib/pulse_meter/dygraphs_visualize/dsl/base.rb +131 -0
  39. data/lib/pulse_meter/dygraphs_visualize/dsl/errors.rb +40 -0
  40. data/lib/pulse_meter/dygraphs_visualize/dsl/layout.rb +27 -0
  41. data/lib/pulse_meter/dygraphs_visualize/dsl/page.rb +26 -0
  42. data/lib/pulse_meter/dygraphs_visualize/dsl/sensor.rb +20 -0
  43. data/lib/pulse_meter/dygraphs_visualize/dsl/widget.rb +37 -0
  44. data/lib/pulse_meter/dygraphs_visualize/dsl/widgets/line.rb +22 -0
  45. data/lib/pulse_meter/dygraphs_visualize/dsl/widgets/stack.rb +29 -0
  46. data/lib/pulse_meter/dygraphs_visualize/layout.rb +79 -0
  47. data/lib/pulse_meter/dygraphs_visualize/page.rb +25 -0
  48. data/lib/pulse_meter/dygraphs_visualize/public/css/application.css +61 -0
  49. data/lib/pulse_meter/dygraphs_visualize/public/css/bootstrap.css +4883 -0
  50. data/lib/pulse_meter/dygraphs_visualize/public/css/bootstrap.min.css +729 -0
  51. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  52. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  53. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  54. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  55. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  56. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
  57. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  58. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
  59. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
  60. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
  61. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
  62. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
  63. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
  64. data/lib/pulse_meter/dygraphs_visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
  65. data/lib/pulse_meter/dygraphs_visualize/public/css/jquery-ui-1.8.16.bootstrap.css +1320 -0
  66. data/lib/pulse_meter/dygraphs_visualize/public/favicon.ico +208 -0
  67. data/lib/pulse_meter/dygraphs_visualize/public/img/glyphicons-halflings-white.png +0 -0
  68. data/lib/pulse_meter/dygraphs_visualize/public/img/glyphicons-halflings.png +0 -0
  69. data/lib/pulse_meter/dygraphs_visualize/public/js/application.js +833 -0
  70. data/lib/pulse_meter/dygraphs_visualize/public/js/backbone-min.js +38 -0
  71. data/lib/pulse_meter/dygraphs_visualize/public/js/bootstrap.js +1835 -0
  72. data/lib/pulse_meter/dygraphs_visualize/public/js/dygraph-combined.js +2 -0
  73. data/lib/pulse_meter/dygraphs_visualize/public/js/jquery-1.7.2.min.js +4 -0
  74. data/lib/pulse_meter/dygraphs_visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +791 -0
  75. data/lib/pulse_meter/dygraphs_visualize/public/js/jquery-ui-1.8.23.custom.min.js +21 -0
  76. data/lib/pulse_meter/dygraphs_visualize/public/js/jquery-ui-timepicker-addon.js +1687 -0
  77. data/lib/pulse_meter/dygraphs_visualize/public/js/json2.js +487 -0
  78. data/lib/pulse_meter/dygraphs_visualize/public/js/underscore-min.js +32 -0
  79. data/lib/pulse_meter/dygraphs_visualize/sensor.rb +63 -0
  80. data/lib/pulse_meter/dygraphs_visualize/series_color.rb +39 -0
  81. data/lib/pulse_meter/dygraphs_visualize/series_extractor.rb +107 -0
  82. data/lib/pulse_meter/dygraphs_visualize/views/main.haml +30 -0
  83. data/lib/pulse_meter/dygraphs_visualize/views/sensors.haml +75 -0
  84. data/lib/pulse_meter/dygraphs_visualize/views/widgets/extend_options.haml +11 -0
  85. data/lib/pulse_meter/dygraphs_visualize/views/widgets/line.haml +43 -0
  86. data/lib/pulse_meter/dygraphs_visualize/views/widgets/stack.haml +43 -0
  87. data/lib/pulse_meter/dygraphs_visualize/widget.rb +38 -0
  88. data/lib/pulse_meter/dygraphs_visualize/widgets/timeline.rb +107 -0
  89. data/lib/pulse_meter/dygraphs_visualizer.rb +34 -0
  90. data/lib/pulse_meter_dygraphs_visualizer.rb +2 -0
  91. data/pulse_meter-dygraphs_visualizer.gemspec +41 -0
  92. data/spec/pulse_meter/dygraphs_visualize/app_spec.rb +27 -0
  93. data/spec/pulse_meter/dygraphs_visualize/dsl/layout_spec.rb +64 -0
  94. data/spec/pulse_meter/dygraphs_visualize/dsl/page_spec.rb +62 -0
  95. data/spec/pulse_meter/dygraphs_visualize/dsl/sensor_spec.rb +30 -0
  96. data/spec/pulse_meter/dygraphs_visualize/dsl/widget_spec.rb +6 -0
  97. data/spec/pulse_meter/dygraphs_visualize/dsl/widgets/line_spec.rb +44 -0
  98. data/spec/pulse_meter/dygraphs_visualize/dsl/widgets/stack_spec.rb +55 -0
  99. data/spec/pulse_meter/dygraphs_visualize/layout_spec.rb +54 -0
  100. data/spec/pulse_meter/dygraphs_visualize/page_spec.rb +145 -0
  101. data/spec/pulse_meter/dygraphs_visualize/sensor_spec.rb +120 -0
  102. data/spec/pulse_meter/dygraphs_visualize/series_extractor_spec.rb +80 -0
  103. data/spec/pulse_meter/dygraphs_visualize/widgets/line_spec.rb +6 -0
  104. data/spec/pulse_meter/dygraphs_visualize/widgets/stack_spec.rb +6 -0
  105. data/spec/pulse_meter/dygraphs_visualizer_spec.rb +42 -0
  106. data/spec/shared_examples/dsl_widget.rb +106 -0
  107. data/spec/shared_examples/widget.rb +97 -0
  108. data/spec/spec_helper.rb +36 -0
  109. metadata +497 -0
@@ -0,0 +1,15 @@
1
+ module PulseMeter
2
+ module DygraphsVisualize
3
+ class Base
4
+ def initialize(opts)
5
+ @opts = opts
6
+ end
7
+
8
+ def method_missing(name, *args)
9
+ @opts[name.to_sym]
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+
@@ -0,0 +1,37 @@
1
+ #= require extensions
2
+ #= require models/page_info
3
+ #= require models/widget
4
+ #= require models/dinamic_widget
5
+ #= require models/sensor_info
6
+ #= require collections/page_info_list
7
+ #= require collections/sensor_info_list
8
+ #= require collections/widget_list
9
+ #= require presenters/widget
10
+ #= require presenters/timeline
11
+ #= require presenters/series
12
+ #= require presenters/line
13
+ #= require presenters/stack
14
+ #= require views/page_title
15
+ #= require views/page_titles
16
+ #= require views/sensor_info_list
17
+ #= require views/dynamic_chart
18
+ #= require views/dynamic_widget
19
+ #= require views/widget_chart
20
+ #= require views/widget
21
+ #= require views/widget_list
22
+ #= require router
23
+
24
+ document.startApp = ->
25
+ pageInfos = new PageInfoList
26
+ pageTitlesApp = new PageTitlesView(pageInfos)
27
+ pageInfos.reset gon.pageInfos
28
+
29
+ widgetList = new WidgetList
30
+ widgetList.setContext(pageInfos)
31
+ widgetList.startPolling()
32
+
33
+ widgetListApp = new WidgetListView {widgetList: widgetList, pageInfos: pageInfos}
34
+
35
+ appRouter = new AppRouter(pageInfos, widgetList)
36
+
37
+ Backbone.history.start()
@@ -0,0 +1,17 @@
1
+ PageInfoList = Backbone.Collection.extend {
2
+ model: PageInfo
3
+ selected: ->
4
+ @find (m) ->
5
+ m.get 'selected'
6
+
7
+ selectFirst: ->
8
+ @at(0).set('selected', true) if @length > 0
9
+
10
+ selectNone: ->
11
+ @each (m) ->
12
+ m.set 'selected', false
13
+
14
+ selectPage: (id) ->
15
+ @each (m) ->
16
+ m.set 'selected', m.id == id
17
+ }
@@ -0,0 +1,4 @@
1
+ SensorInfoList = Backbone.Collection.extend {
2
+ model: SensorInfo
3
+ url: -> ROOT + 'sensors'
4
+ }
@@ -0,0 +1,14 @@
1
+ WidgetList = Backbone.Collection.extend {
2
+ model: Widget
3
+
4
+ setContext: (@pageInfos) ->
5
+
6
+ url: -> ROOT + 'pages/' + @pageInfos.selected().id + '/widgets'
7
+
8
+ startPolling: ->
9
+ setInterval( =>
10
+ if @pageInfos.selected()
11
+ @each (w) ->
12
+ w.refetch()
13
+ , 200)
14
+ }
@@ -0,0 +1,26 @@
1
+ String::capitalize = ->
2
+ @charAt(0).toUpperCase() + @slice(1)
3
+ String::strip = ->
4
+ if String::trim? then @trim() else @replace /^\s+|\s+$/g, ""
5
+
6
+ Number::humanize = ->
7
+ interval = this
8
+ res = ""
9
+ s = interval % 60
10
+ res = "#{s} s" if s > 0
11
+ interval = (interval - s) / 60
12
+ return res unless interval > 0
13
+
14
+ m = interval % 60
15
+ res = "#{m} m #{res}".strip() if m > 0
16
+ interval = (interval - m) / 60
17
+ return res unless interval > 0
18
+
19
+ h = interval % 24
20
+ res = "#{h} h #{res}".strip() if h > 0
21
+ d = (interval - h) / 24
22
+ if d > 0
23
+ "#{d} d #{res}".strip()
24
+ else
25
+ res
26
+
@@ -0,0 +1,34 @@
1
+ DynamicWidget = Backbone.Model.extend {
2
+
3
+ setStartTime: (@startTime) ->
4
+
5
+ setEndTime: (@endTime) ->
6
+
7
+ increaseTimespan: (inc) ->
8
+ @set('timespan', @timespan() + inc)
9
+
10
+ resetTimespan: ->
11
+ @startTime = null
12
+ @endTime = null
13
+ @set('timespan', null)
14
+
15
+ timespan: -> @get('timespan')
16
+
17
+ sensorArgs: ->
18
+ _.map(@get('sensorIds'), (name) -> "sensor[]=#{name}").join('&')
19
+
20
+ url: ->
21
+ timespan = @timespan()
22
+ url = "#{ROOT}dynamic_widget?#{@sensorArgs()}&type=#{@get('type')}"
23
+ url += "&timespan=#{timespan}" if timespan? && !_.isNaN(timespan)
24
+ url += "&startTime=#{@startTime}" if @startTime
25
+ url += "&endTime=#{@endTime}" if @endTime
26
+ url
27
+
28
+
29
+ forceUpdate: ->
30
+ @fetch {
31
+ success: (model, response) ->
32
+ model.trigger('redraw')
33
+ }
34
+ }
@@ -0,0 +1,2 @@
1
+ PageInfo = Backbone.Model.extend {
2
+ }
@@ -0,0 +1,2 @@
1
+ SensorInfo = Backbone.Model.extend {
2
+ }
@@ -0,0 +1,63 @@
1
+ Widget = Backbone.Model.extend {
2
+ initialize: ->
3
+ @updating = false
4
+ @needRefresh = true
5
+ @setNextFetch()
6
+ @timespanInc = 0
7
+
8
+ setStartTime: (@startTime) ->
9
+
10
+ setEndTime: (@endTime) ->
11
+
12
+ increaseTimespan: (inc) ->
13
+ @timespanInc = @timespanInc + inc
14
+ @forceUpdate()
15
+
16
+ resetTimespan: ->
17
+ @timespanInc = 0
18
+ @startTime = null
19
+ @endTime = null
20
+ @forceUpdate()
21
+
22
+ timespan: -> @get('timespan') + @timespanInc
23
+
24
+ url: ->
25
+ timespan = @timespan()
26
+ url = "#{@collection.url()}/#{@get('id')}?"
27
+ url += "&timespan=#{timespan}" unless _.isNaN(timespan)
28
+ url += "&startTime=#{@startTime}" if @startTime
29
+ url += "&endTime=#{@endTime}" if @endTime
30
+ url
31
+
32
+ time: -> (new Date()).getTime()
33
+
34
+ setNextFetch: ->
35
+ @nextFetch = @time() + @get('redrawInterval') * 1000
36
+
37
+ setRefresh: (needRefresh) ->
38
+ @needRefresh = needRefresh
39
+
40
+ needFetch: ->
41
+ interval = @get('redrawInterval')
42
+ @time() > @nextFetch && @needRefresh && interval? && interval > 0
43
+
44
+ refetch: ->
45
+ if @needFetch()
46
+ @forceUpdate()
47
+ @setNextFetch()
48
+
49
+ setUpdated: ->
50
+ @updating = false
51
+
52
+ forceUpdate: ->
53
+ return if @updating
54
+ @updating = true
55
+ xhr = @fetch {
56
+ success: (model, response) =>
57
+ @trigger('redraw')
58
+ }
59
+ xhr.always () =>
60
+ @updating = false
61
+ xhr.fail (xhr, textStatus, errorThrown) =>
62
+ console.log "xhr fail", @get('id'), textStatus, errorThrown
63
+ }
@@ -0,0 +1 @@
1
+ class LinePresenter extends SeriesPresenter
@@ -0,0 +1,26 @@
1
+ class SeriesPresenter extends TimelinePresenter
2
+ options: ->
3
+ $.extend(true,
4
+ super(),
5
+ {
6
+ title: @get('title')
7
+ legend: 'always'
8
+ height: 300
9
+ ylabel: @valuesTitle()
10
+ colors: @colors()
11
+ }
12
+ )
13
+
14
+ valuesTitle: ->
15
+ if @get('valuesTitle')
16
+ "#{@get('valuesTitle')} / #{@humanizedInterval()}"
17
+ else
18
+ @humanizedInterval()
19
+
20
+ colors: ->
21
+ _.map @get('series').options, (o) -> o.color
22
+
23
+
24
+ humanizedInterval: ->
25
+ @get('interval').humanize()
26
+
@@ -0,0 +1 @@
1
+ class StackPresenter extends SeriesPresenter
@@ -0,0 +1,13 @@
1
+ class TimelinePresenter extends WidgetPresenter
2
+ data: ->
3
+ data = super()
4
+ data.addColumn('datetime', 'Time')
5
+ dateOffset = @dateOffset() + @get('interval') * 1000
6
+ series = @get('series')
7
+ _.each series.titles, (t) ->
8
+ data.addColumn('number', t)
9
+
10
+ _.each series.rows, (row) ->
11
+ row[0] = new Date(row[0] + dateOffset)
12
+ data.addRow(row)
13
+ data
@@ -0,0 +1,48 @@
1
+ class WidgetPresenter
2
+ constructor: (@pageInfos, @model, @el) ->
3
+ @chartEl = @el.find('#chart')[0]
4
+ @legendEl = @el.find('#legend')[0]
5
+ @chart = new Dygraph.GVizChart(@chartEl)
6
+ @draw()
7
+
8
+ get: (arg) -> @model.get(arg)
9
+
10
+ globalOptions: -> gon.options
11
+
12
+ dateOffset: ->
13
+ if @globalOptions.useUtc
14
+ (new Date).getTimezoneOffset() * 60000
15
+ else
16
+ 0
17
+
18
+ options: -> {
19
+ labelsDiv: @legendEl
20
+ labelsSeparateLines: false
21
+ rightGap: 30
22
+ }
23
+
24
+ mergedOptions: ->
25
+ pageOptions = if @pageInfos.selected()
26
+ @pageInfos.selected().get('dygraphsOptions')
27
+ else
28
+ {}
29
+
30
+ $.extend(true,
31
+ @options(),
32
+ @globalOptions.dygraphsOptions,
33
+ pageOptions,
34
+ @get('dygraphsOptions')
35
+ )
36
+
37
+ data: -> new google.visualization.DataTable
38
+
39
+ draw: ->
40
+ @chart.draw @data(), @mergedOptions()
41
+
42
+ WidgetPresenter.create = (pageInfos, model, el) ->
43
+ type = model.get('type')
44
+ if type? && type.match(/^\w+$/)
45
+ presenterClass = eval("#{type.capitalize()}Presenter")
46
+ new presenterClass(pageInfos, model, el)
47
+ else
48
+ null
@@ -0,0 +1,21 @@
1
+ AppRouter = Backbone.Router.extend {
2
+ initialize: (@pageInfos, @widgetList) ->
3
+ routes: {
4
+ 'pages/:id': 'getPage'
5
+ 'custom': 'custom'
6
+ '*actions': 'defaultRoute'
7
+ }
8
+ getPage: (ids) ->
9
+ id = parseInt(ids)
10
+ @pageInfos.selectPage(id)
11
+ @widgetList.fetch()
12
+ custom: ->
13
+ @pageInfos.selectNone()
14
+ dynamicWidget = new DynamicWidgetView {pageInfos: @pageInfos}
15
+ dynamicWidget.render($('#widgets'))
16
+ defaultRoute: (actions) ->
17
+ if @pageInfos.length > 0
18
+ @navigate('//pages/1')
19
+ else
20
+ @navigate('//custom')
21
+ }
@@ -0,0 +1,92 @@
1
+ DynamicChartView = Backbone.View.extend {
2
+ initialize: (options) ->
3
+ @pageInfos = options['pageInfos']
4
+ @sensors = []
5
+ @type = 'Area'
6
+ @widget = new DynamicWidget
7
+
8
+ @widget.bind('destroy', @remove, this)
9
+ @widget.bind('redraw', @redrawChart, this)
10
+
11
+ tagName: 'div'
12
+
13
+ events: {
14
+ "click #refresh-chart": 'update'
15
+ "click #extend-timespan": 'extendTimespan'
16
+ "click #reset-timespan": 'resetTimespan'
17
+ "change #start-time input": 'maybeEnableStopTime'
18
+ "click #set-interval": 'setTimelineInterval'
19
+ }
20
+
21
+ template: -> _.template($("#dynamic-widget-plotarea").html())
22
+ chartContainerTemplate: '<div id="chart"></div><div id="legend"></div>'
23
+
24
+ render: ->
25
+ @$el.html(@template()())
26
+ @initDatePickers()
27
+
28
+ initDatePickers: ->
29
+ @$el.find(".datepicker").each (i) ->
30
+ $(this).datetimepicker
31
+ showOtherMonths: true
32
+ selectOtherMonths: true
33
+ @$el.find("#end-time input").prop("disabled", true)
34
+
35
+ setTimelineInterval: ->
36
+ start = @unixtimeFromDatepicker("#start-time input")
37
+ end = @unixtimeFromDatepicker("#end-time input")
38
+ @widget.setStartTime(start)
39
+ @widget.setEndTime(end)
40
+ @update()
41
+
42
+ dateFromDatepicker: (id) ->
43
+ @$el.find(id).datetimepicker("getDate")
44
+
45
+ unixtimeFromDatepicker: (id) ->
46
+ date = @dateFromDatepicker(id)
47
+ if date
48
+ date.getTime() / 1000
49
+ else
50
+ null
51
+
52
+ maybeEnableStopTime: ->
53
+ date = @dateFromDatepicker("#start-time input")
54
+ disabled = if date then false else true
55
+ @$el.find("#end-time input").prop("disabled", disabled)
56
+
57
+ extendTimespan: ->
58
+ select = @$el.find("#extend-timespan-val")
59
+ val = select.first().val()
60
+ @widget.increaseTimespan(parseInt(val))
61
+ @update()
62
+
63
+ resetTimespan: ->
64
+ @widget.resetTimespan()
65
+ @update()
66
+
67
+ sensorIds: -> _.map(@sensors, (s) -> s.id)
68
+
69
+ redrawChart: ->
70
+ if @presenter
71
+ @presenter.draw()
72
+ else
73
+ @presenter = WidgetPresenter.create(@pageInfos, @widget, @chartContainer())
74
+
75
+
76
+ chartContainer: ->
77
+ $(@$el.find('#chart-widget')[0])
78
+
79
+ update: ->
80
+ @widget.forceUpdate() if @sensors.length > 0
81
+
82
+ draw: (sensors, type) ->
83
+ @sensors = sensors
84
+ @type = type
85
+
86
+ @widget.set('sensorIds', @sensorIds())
87
+ @widget.set('type', @type)
88
+
89
+ @presenter = null
90
+ @chartContainer().html(@chartContainerTemplate)
91
+ @widget.forceUpdate()
92
+ }