rrd-grapher 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/.gitignore +9 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +11 -0
  4. data/Guardfile +123 -0
  5. data/README.md +91 -0
  6. data/Rakefile +42 -0
  7. data/example_app/Gemfile +9 -0
  8. data/example_app/Guardfile +18 -0
  9. data/example_app/app.rb +38 -0
  10. data/example_app/assets/javascripts/available_rrds.coffee +13 -0
  11. data/example_app/assets/javascripts/collectd.coffee +48 -0
  12. data/example_app/config.ru +9 -0
  13. data/example_app/public/.gitignore +1 -0
  14. data/example_app/public/chosen/chosen-sprite.png +0 -0
  15. data/example_app/public/chosen/chosen.css +340 -0
  16. data/example_app/public/chosen/chosen.jquery.js +786 -0
  17. data/example_app/public/chosen/chosen.jquery.min.js +10 -0
  18. data/example_app/public/javascripts/available_rrds.js +16 -0
  19. data/example_app/public/javascripts/collectd.js +64 -0
  20. data/example_app/public/javascripts/jquery.timeago.js +148 -0
  21. data/example_app/public/stylesheets/Aristo/images/bg_fallback.png +0 -0
  22. data/example_app/public/stylesheets/Aristo/images/icon_sprite.png +0 -0
  23. data/example_app/public/stylesheets/Aristo/images/progress_bar.gif +0 -0
  24. data/example_app/public/stylesheets/Aristo/images/slider_handles.png +0 -0
  25. data/example_app/public/stylesheets/Aristo/images/ui-icons_222222_256x240.png +0 -0
  26. data/example_app/public/stylesheets/Aristo/images/ui-icons_454545_256x240.png +0 -0
  27. data/example_app/public/stylesheets/Aristo/theme.css +738 -0
  28. data/example_app/views/available_rrds.haml +26 -0
  29. data/example_app/views/collectd.haml +30 -0
  30. data/example_app/views/layout.haml +19 -0
  31. data/example_app/views/stylesheets/available_rrds.scss +7 -0
  32. data/example_notifier/Gemfile +2 -0
  33. data/example_notifier/notifier.rb +25 -0
  34. data/lib/rrd-grapher/assets/javascripts/app-dev.js +20 -0
  35. data/lib/rrd-grapher/assets/javascripts/app.js +20 -0
  36. data/lib/rrd-grapher/assets/javascripts/classes/format.coffee +35 -0
  37. data/lib/rrd-grapher/assets/javascripts/classes/graph.coffee +306 -0
  38. data/lib/rrd-grapher/assets/javascripts/classes/graph_definition.coffee +216 -0
  39. data/lib/rrd-grapher/assets/javascripts/classes/serie.coffee +13 -0
  40. data/lib/rrd-grapher/assets/javascripts/classes/size.coffee +5 -0
  41. data/lib/rrd-grapher/assets/javascripts/classes/static_line.coffee +44 -0
  42. data/lib/rrd-grapher/assets/javascripts/classes/time.coffee +17 -0
  43. data/lib/rrd-grapher/notifier/alarm_manager.rb +190 -0
  44. data/lib/rrd-grapher/notifier/alarm_trigger.rb +187 -0
  45. data/lib/rrd-grapher/notifier/alarms.rb +79 -0
  46. data/lib/rrd-grapher/notifier/collectdrb.rb +86 -0
  47. data/lib/rrd-grapher/notifier/data_struct.rb +46 -0
  48. data/lib/rrd-grapher/notifier/default_user_handler.rb +36 -0
  49. data/lib/rrd-grapher/notifier/parsers/bindata_parser.rb +144 -0
  50. data/lib/rrd-grapher/notifier/parsers/ruby_parser.rb +134 -0
  51. data/lib/rrd-grapher/notifier/structures.rb +80 -0
  52. data/lib/rrd-grapher/notifier.rb +87 -0
  53. data/lib/rrd-grapher/public/favicon.ico +0 -0
  54. data/lib/rrd-grapher/public/javascripts/app-dev.js +13709 -0
  55. data/lib/rrd-grapher/public/javascripts/app.js +4057 -0
  56. data/lib/rrd-grapher/public/javascripts/backbone/backbone.js +1155 -0
  57. data/lib/rrd-grapher/public/javascripts/backbone/backbone.min.js +32 -0
  58. data/lib/rrd-grapher/public/javascripts/backbone/underscore.js +841 -0
  59. data/lib/rrd-grapher/public/javascripts/backbone/underscore.min.js +27 -0
  60. data/lib/rrd-grapher/public/javascripts/classes/format.js +42 -0
  61. data/lib/rrd-grapher/public/javascripts/classes/graph.js +360 -0
  62. data/lib/rrd-grapher/public/javascripts/classes/graph_definition.js +298 -0
  63. data/lib/rrd-grapher/public/javascripts/classes/serie.js +32 -0
  64. data/lib/rrd-grapher/public/javascripts/classes/size.js +7 -0
  65. data/lib/rrd-grapher/public/javascripts/classes/static_line.js +48 -0
  66. data/lib/rrd-grapher/public/javascripts/classes/time.js +17 -0
  67. data/lib/rrd-grapher/public/javascripts/flot/.gitignore +4 -0
  68. data/lib/rrd-grapher/public/javascripts/flot/excanvas.min.js +1 -0
  69. data/lib/rrd-grapher/public/javascripts/flot/jquery.colorhelpers.min.js +1 -0
  70. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.crosshair.min.js +1 -0
  71. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.fillbetween.min.js +1 -0
  72. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.image.min.js +1 -0
  73. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.js +2604 -0
  74. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.navigate.min.js +1 -0
  75. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.pie.min.js +1 -0
  76. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.resize.min.js +1 -0
  77. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.selection.js +345 -0
  78. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.selection.min.js +1 -0
  79. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.stack.min.js +1 -0
  80. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.symbol.min.js +1 -0
  81. data/lib/rrd-grapher/public/javascripts/flot/jquery.flot.threshold.min.js +1 -0
  82. data/lib/rrd-grapher/public/javascripts/jquery/jquery-1.6.2.js +8981 -0
  83. data/lib/rrd-grapher/public/javascripts/jquery/jquery-1.6.2.min.js +18 -0
  84. data/lib/rrd-grapher/public/javascripts/jquery/jquery-ui-1.8.11.min.js +783 -0
  85. data/lib/rrd-grapher/public/javascripts/jquery/jquery.showtime.js +63 -0
  86. data/lib/rrd-grapher/public/javascripts/jquery/jquery.tpl.min.js +10 -0
  87. data/lib/rrd-grapher/resources.rb +14 -0
  88. data/lib/rrd-grapher/rrd.rb +238 -0
  89. data/lib/rrd-grapher/rrd_server.rb +78 -0
  90. data/lib/rrd-grapher/version.rb +4 -0
  91. data/lib/rrd-grapher/views/stylesheets/app.scss +111 -0
  92. data/lib/rrd-grapher.rb +12 -0
  93. data/rrd-grapher.gemspec +47 -0
  94. data/spec/common.rb +70 -0
  95. data/spec/data/myrouter.rrd +0 -0
  96. data/spec/data/subdata.rrd +0 -0
  97. data/spec/data/test.rrd +0 -0
  98. data/spec/factories.rb +23 -0
  99. data/spec/javascripts/helpers/jasmine-jquery-1.3.0.js +283 -0
  100. data/spec/javascripts/source/format_spec.coffee +18 -0
  101. data/spec/javascripts/source/graph_def_spec.coffee +27 -0
  102. data/spec/javascripts/source/graph_spec.coffee +63 -0
  103. data/spec/javascripts/source/serie_spec.coffee +28 -0
  104. data/spec/javascripts/source/static_line_spec.coffee +13 -0
  105. data/spec/javascripts/source/time_spec.coffee +26 -0
  106. data/spec/javascripts/support/jasmine.yml +78 -0
  107. data/spec/javascripts/support/jasmine_config.rb +23 -0
  108. data/spec/javascripts/support/jasmine_runner.rb +32 -0
  109. data/spec/unit/alarm_manager_spec.rb +252 -0
  110. data/spec/unit/alarm_trigger_spec.rb +26 -0
  111. data/spec/unit/data_struct_spec.rb +55 -0
  112. data/spec/unit/notifier_spec.rb +45 -0
  113. data/spec/unit/parsers/bindata_parser_spec.rb +184 -0
  114. data/spec/unit/parsers/ruby_parser_spec.rb +184 -0
  115. data/spec/unit/rrd_spec.rb +50 -0
  116. data/spec/unit/structures_spec.rb +28 -0
  117. data/tests/4series.rrd +0 -0
  118. data/tests/analyze_rrd.rb +62 -0
  119. data/tests/exact.rrd +0 -0
  120. data/tests/exact2.rrd +0 -0
  121. data/tests/filler.rb +46 -0
  122. metadata +414 -0
@@ -0,0 +1,26 @@
1
+ - content_for(:css) do
2
+ %link{:rel => 'stylesheet', :href => '/stylesheets/available_rrds.css', :type => 'text/css'}
3
+
4
+ - content_for(:headers) do
5
+ %script{:type => "text/javascript", :src => "/javascripts/available_rrds.js"}
6
+ %script{:type => "text/javascript", :src => "/javascripts/jquery/jquery.showtime.js"}
7
+ %script{:type => "text/javascript", :src => "/javascripts/jquery.timeago.js"}
8
+
9
+ %table#template.hidden
10
+ %tr
11
+ %td ${short_name}
12
+ %td ${path}
13
+ %td ${sources}
14
+ %td.time{:title => "${last_update}"} ${last_update}
15
+ %td ${step}
16
+
17
+ %table#data_list
18
+ %tr
19
+ %th Name
20
+ %th Path
21
+ %th DS
22
+ %th Last update
23
+ %th Step
24
+
25
+
26
+ / #target
@@ -0,0 +1,30 @@
1
+ - content_for(:css) do
2
+ %link{:rel => 'stylesheet', :href => '/chosen/chosen.css', :type => 'text/css'}
3
+
4
+ - content_for(:headers) do
5
+ %script{:type => "text/javascript", :src => "/chosen/chosen.jquery.js"}
6
+ %script{:type => "text/javascript", :src => "/javascripts/collectd.js"}
7
+
8
+
9
+ #config_panel{:class => "row"}
10
+ .column.grid_4
11
+ .row
12
+ %input.checkbox#autorefresh{:type => "checkbox"}
13
+ %label{:for => "autorefresh"} Auto Refresh
14
+ .row
15
+ %input.checkbox#linkedzoom{:type => "checkbox", :checked => true}
16
+ %label{:for => "linkedzoom"} Linked Zoom
17
+
18
+ .column.grid_4
19
+ %label{:for => "rangeselect"} Interval:
20
+ %select#rangeselect
21
+ %option{:value => 60} 1 minute
22
+ %option{:value => 15*60, :selected => true} 15 minues
23
+ %option{:value => 60*60} 1 hour
24
+ %option{:value => 60*60*24} 1 day
25
+
26
+ .column.grid_4
27
+ %label{:for => "rangeselect"} Show a specific day
28
+ %input#dateselect{:type => "text"}
29
+
30
+ #graphs
@@ -0,0 +1,19 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title RRD Grapher
5
+ %meta{"http-equiv"=>"Content-Type", :content=>"text/html; charset=UTF-8"}
6
+ / %link{:rel => "icon", :type => "image/gif", :href => "/favicon.gif"}
7
+ %link{:rel => 'stylesheet', :href => '/stylesheets/Aristo/theme.css', :type => 'text/css'}
8
+ %link{:rel => 'stylesheet', :href => '/stylesheets/app.css', :type => 'text/css'}
9
+ / %link{:rel => 'stylesheet', :href => '/javascripts/wijmo-open/css/jquery.wijmo-open.1.3.0.css', :type => 'text/css'}
10
+ = yield_content :css
11
+
12
+ %script{:type => "text/javascript", :src => "/javascripts/app.js"}
13
+ = yield_content :headers
14
+
15
+ %body
16
+ %div#wrapper
17
+ %div#content
18
+ = yield
19
+
@@ -0,0 +1,7 @@
1
+
2
+ .rrd {
3
+ display : block;
4
+ border: 1px solid black;
5
+ margin-top: 3px;
6
+ width: 100%;
7
+ }
@@ -0,0 +1,2 @@
1
+
2
+ gem 'rrd-grapher', :path => File.expand_path('../..', __FILE__)
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rrd-grapher/notifier'
4
+
5
+ puts "Notifier started."
6
+
7
+ pool = FiberPool.new(10)
8
+
9
+ EM::run do
10
+
11
+ pool.spawn do
12
+ opts = {
13
+ :fiber_pool => pool
14
+ }
15
+
16
+ RRDNotifier::Server.start(opts) do |s|
17
+ s.register_alarm("*", "ping", "ping_droprate", :max => 5)
18
+ s.register_alarm("*", "uptime", "uptime", :monitor_presence => 2*60)
19
+
20
+ s.register_alarm("*", "load", "load", :max => 0.01, :index => 1)
21
+ s.register_alarm("*", "memory/*", "memory/active", :monitor_presence => 1)
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,20 @@
1
+ //
2
+ // sprockets package recipe (Dev File)
3
+ //
4
+ //= require "../../public/javascripts/jquery/jquery-1.6.2.js"
5
+ //= require "../../public/javascripts/jquery/jquery-ui-1.8.11.min.js"
6
+ //= require "../../public/javascripts/jquery/jquery.tpl.min.js"
7
+ //= require "../../public/javascripts/flot/jquery.flot.js"
8
+ //= require "../../public/javascripts/flot/jquery.flot.selection.js"
9
+ //= require "../../public/javascripts/backbone/underscore.js"
10
+ //= require "../../public/javascripts/backbone/backbone.js"
11
+
12
+ //= require "../../public/javascripts/classes/format.js"
13
+ //= require "../../public/javascripts/classes/graph.js"
14
+ //= require "../../public/javascripts/classes/graph_definition.js"
15
+ //= require "../../public/javascripts/classes/serie.js"
16
+ //= require "../../public/javascripts/classes/size.js"
17
+ //= require "../../public/javascripts/classes/static_line.js"
18
+ //= require "../../public/javascripts/classes/time.js"
19
+
20
+
@@ -0,0 +1,20 @@
1
+ //
2
+ // sprockets package recipe
3
+ //
4
+ //= require "../../public/javascripts/jquery/jquery-1.6.2.min.js"
5
+ //= require "../../public/javascripts/jquery/jquery-ui-1.8.11.min.js"
6
+ //= require "../../public/javascripts/jquery/jquery.tpl.min.js"
7
+ //= require "../../public/javascripts/flot/jquery.flot.js"
8
+ //= require "../../public/javascripts/flot/jquery.flot.selection.min.js"
9
+ //= require "../../public/javascripts/backbone/underscore.min.js"
10
+ //= require "../../public/javascripts/backbone/backbone.min.js"
11
+
12
+ //= require "../../public/javascripts/classes/format.js"
13
+ //= require "../../public/javascripts/classes/graph.js"
14
+ //= require "../../public/javascripts/classes/graph_definition.js"
15
+ //= require "../../public/javascripts/classes/static_line.js"
16
+ //= require "../../public/javascripts/classes/serie.js"
17
+ //= require "../../public/javascripts/classes/size.js"
18
+ //= require "../../public/javascripts/classes/time.js"
19
+
20
+
@@ -0,0 +1,35 @@
1
+
2
+ window.Format =
3
+ speed: (num) ->
4
+ Format._convert(num, 1024, ["B/s", "KB/s", "MB/s", "GB/s"])
5
+
6
+ size: (num) ->
7
+ Format._convert(num, 1024, ["B", "KB", "MB", "GB"])
8
+
9
+ percent: (num) ->
10
+ Format._convert(num, null, ["%"])
11
+
12
+ delay: (num) ->
13
+ if num < 1000
14
+ Format._convert(num, null, ["ms"])
15
+ else
16
+ Format._convert(num/1000, 60, ["s", "m", "h"])
17
+
18
+
19
+ identity: (num) ->
20
+ Format._convert(num)
21
+
22
+ _convert: (num, ref = null, units = [""]) ->
23
+ index = 0
24
+
25
+ sign = if num < 0 then -1 else 1
26
+ abs_num = Math.abs(num)
27
+
28
+ if ref
29
+ while abs_num > ref
30
+ abs_num /= ref
31
+ index+= 1
32
+
33
+ "" + parseFloat(abs_num * sign).toFixed(2) + "&nbsp;" + units[index]
34
+
35
+
@@ -0,0 +1,306 @@
1
+
2
+ class window.Graph extends Backbone.Model
3
+ colors = ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed", "#FF4571", "#FF8ED4", "#FF768C", "#1E74FF"]
4
+
5
+ defaults:
6
+ "formatters" : [Format.identity, Format.identity]
7
+ "limits" : [[null, null], [null, null]]
8
+
9
+ initialize: ->
10
+ # super
11
+ # "formatters" : formatters
12
+ # "limits" : limits
13
+
14
+ @next_color = 0
15
+
16
+ @set "maxrows" : 400
17
+ @set "legend_containers" : []
18
+
19
+ parent_container = @get("parent_container")
20
+ title = @get("title")
21
+
22
+ @set("limits" : @defaults["limits"]) if @get("limits") == null
23
+
24
+ # create graph container
25
+ @master_container = $("<div>").addClass("graph_container").appendTo(parent_container)
26
+
27
+ # @set "graph_title" : $("<div>").addClass("graph_title").appendTo(@master_container)
28
+ # @get("graph_title").text(title)
29
+
30
+ @get("legend_containers")[0] = $("<div>").addClass('legend').appendTo(@master_container)
31
+ $("<h3>").text(title).appendTo(@get("legend_containers")[0])
32
+ $("<div>").appendTo(@get("legend_containers")[0])
33
+
34
+ @set "container" : $("<div>").addClass("graph").appendTo(@master_container)
35
+ # @legend_containers[1] = $("<div>").addClass('legend').appendTo(@master_container)
36
+
37
+ @set "series" : []
38
+ @set "tooltip_point" : null
39
+
40
+ # compute end date (now - 20s)
41
+ to = Math.floor((new Date().getTime() / 1000) - 60)
42
+ @set "to" : to
43
+ @set "from" : to - 15*60
44
+
45
+ @set "plot" : null
46
+ @set "flot_options" :
47
+ "legend" : { show : false }
48
+ "selection" : { mode: 'x' }
49
+ "grid" : { hoverable: true }
50
+ "xaxis" : { mode: "time", show: true }
51
+ "yaxes" : [
52
+ {
53
+ "min" : @get("limits")[0][0]
54
+ "max" : @get("limits")[0][1]
55
+ "tickFormatter" : @get("formatters")[0]
56
+ "labelWidth" : 100
57
+ },
58
+ {
59
+ "min" : @get("limits")[1][0]
60
+ "max" : @get("limits")[1][1]
61
+ "position" : "right"
62
+ "labelWidth" : 100
63
+ "reserveSpace" : true
64
+ "tickFormatter" : @get("formatters")[1]
65
+ }
66
+ ]
67
+
68
+ addSerie: (rrd_path, ds_name, legend, yaxis, formatter) ->
69
+ yaxis = yaxis || 1
70
+ formatter = formatter || @get("formatters")[yaxis - 1]
71
+
72
+ s = new Serie(rrd_path, ds_name, legend, yaxis, formatter)
73
+ s.color = colors[@next_color++]
74
+ @get("series").push(s)
75
+
76
+ addLine: (yvalue, legend, yaxis, formatter) ->
77
+ yaxis = yaxis || 1
78
+ formatter = formatter || @get("formatters")[yaxis - 1]
79
+
80
+ s = new StaticLine(yvalue, legend, yaxis, formatter)
81
+ s.color = colors[@next_color++]
82
+ @get("series").push(s)
83
+
84
+ create: () ->
85
+ this.update_graph(true)
86
+ this
87
+
88
+ _build_query: (s) ->
89
+ query = "/rrd/#{s.rrd_path}/values/#{@get('from')}/#{@get('to')}?maxrows=#{@get('maxrows')}&ds_name=#{s.ds_name}"
90
+ if s.rra
91
+ query += "&rra=#{s.rra}"
92
+
93
+ query
94
+
95
+ update_graph: (first) ->
96
+ if @master_container
97
+ first = first || false
98
+ urls = []
99
+
100
+ urls = $(@get("series")).filter( (i,s) -> s.enabled && !s.static ).map (i, s) =>
101
+ [[@_build_query(s), s]]
102
+
103
+ @multiple_get urls, (data_array) =>
104
+ $(@get("series")).filter( (i,s) -> s.enabled && s.static ).each (i,s) =>
105
+ data_array.push( s.get_definition(@get("from"), @get("to")) )
106
+
107
+ @_update_graph_common(first, data_array)
108
+
109
+
110
+ update_graph_from_cache: ->
111
+ data_array = []
112
+
113
+ $.each @get("series"), (i, s) =>
114
+ if s.enabled
115
+ data_array.push( s.get_definition(@get("from"), @get("to")) )
116
+
117
+ @_update_graph_common(false, data_array)
118
+
119
+ set_interval: (from, to) ->
120
+ @set "from" : from
121
+ @set "to" : to
122
+
123
+ _update_graph_common: (first, data_array) ->
124
+
125
+ if first
126
+ @set "plot" : $.plot(@get("container"), data_array, @get("flot_options"))
127
+ container = @get("container")
128
+ container.bind("plothover", (event, pos, item) => this.show_tooltip(event, pos, item))
129
+ container.bind "plotselected", (event, ranges) =>
130
+ from = Time.client_to_server(ranges.xaxis.from)
131
+ to = Time.client_to_server(ranges.xaxis.to)
132
+ @set_interval(from, to)
133
+
134
+ @trigger("plotselection", from, to)
135
+
136
+ @update_graph()
137
+ @get("plot").clearSelection()
138
+
139
+ container.dblclick =>
140
+ @trigger "dblclick"
141
+
142
+ else
143
+ plot = @get("plot")
144
+ plot.setData( data_array )
145
+ plot.setupGrid()
146
+ plot.draw()
147
+
148
+ options = @get("plot").getOptions()
149
+
150
+ for i in [0...@get("series").length]
151
+ @get("series")[i].color = options.colors[i]
152
+
153
+ # if first
154
+ @create_legend(0)
155
+ # @create_legend(1)
156
+
157
+ multiple_get: (urls, when_done_cb) ->
158
+ urls = $.makeArray(urls)
159
+ left = urls.length
160
+ ret = []
161
+
162
+ $(urls).each (i, el) =>
163
+ url = el[0]
164
+ serie = el[1]
165
+
166
+ $.ajax
167
+ url: url
168
+ dataType: 'json'
169
+ complete: ->
170
+ left -= 1
171
+ when_done_cb(ret) if left == 0
172
+
173
+ success: (data) ->
174
+ serie.set_data(data)
175
+ ret.push( serie.get_definition() )
176
+
177
+ error: (xhr, errText, err) =>
178
+ if (xhr.status == 404) && @master_container
179
+ @master_container.remove()
180
+ @master_container = null
181
+
182
+ avg: (s) ->
183
+ ret = 0
184
+ count = 0
185
+
186
+ $.each s.data, (i, pair) ->
187
+ # ignore null values
188
+ val = pair[1]
189
+ if val != null
190
+ ret += val
191
+ count++
192
+
193
+ ret / count
194
+
195
+ min: (s) ->
196
+ ret = null
197
+ $.each s.data, (i, pair) ->
198
+ val = pair[1]
199
+ if (val != null) && !isNaN(val) && (!ret || (val < ret))
200
+ ret = val
201
+
202
+ ret
203
+
204
+ max: (s) ->
205
+ ret = null
206
+ $.each s.data, (i, pair) ->
207
+ val = pair[1]
208
+ if (val != null) && !isNaN(val) && (!ret || (val > ret))
209
+ ret = val
210
+
211
+ ret
212
+
213
+ lpad = (str, length, padString = " ") ->
214
+ str = String(str)
215
+ len = length - str.length
216
+ str = Array(len).join(padString) + str
217
+
218
+ show_tooltip: (event, pos, item) ->
219
+ if item
220
+ id = "" + item.seriesIndex + ":" + item.dataIndex
221
+ if @get("tooltip_point") != id
222
+ @set "tooltip_point" : id
223
+ # var s = @series[item.seriesIndex];
224
+ s = $(@get("series")).filter((i, s) -> s.legend == item.series.label ).first()
225
+
226
+ if s.length > 0
227
+ s = s[0]
228
+ $("#tooltip").remove()
229
+ y = item.datapoint[1]
230
+ item_date = new Date( item.datapoint[0] - (Time.tz_offset * 1000) )
231
+ date_str = lpad(item_date.getHours(), 2, '0') + ":" + lpad(item_date.getMinutes(), 2, '0')
232
+
233
+ content = s.format(y) + '<br/>' + date_str + "<br/>" + s.legend;
234
+
235
+ $('<div id="tooltip">' + content + '</div>').css( {
236
+ position: 'absolute',
237
+ display: 'none',
238
+ top: item.pageY - 5,
239
+ left: item.pageX + 15,
240
+ border: '1px solid #fdd',
241
+ padding: '2px',
242
+ 'background-color': '#fee',
243
+ opacity: 0.80
244
+ }).appendTo("body").fadeIn(200)
245
+
246
+ else
247
+ $("#tooltip").remove()
248
+ @set "tooltip_point" : null
249
+
250
+ create_legend: (index) ->
251
+ # placeholder.find(".legend").remove();
252
+ # series_data = @plot.getData();
253
+ series = @get("series")
254
+
255
+ fragments = []
256
+ rowStarted = false
257
+
258
+ fragments.push("<tr><th></th><th>label</th><th>Avg</th><th>Min</th><th>Max</th></tr>")
259
+
260
+ for i in [0...series.length]
261
+ s = series[i]
262
+ label = s.legend
263
+
264
+ if !label # || (s.yaxis != (index + 1))
265
+ continue
266
+
267
+ if i % 1 == 0
268
+ fragments.push('</tr>') if rowStarted
269
+ fragments.push('<tr>')
270
+ rowStarted = true;
271
+
272
+ # label = lf(label, s) if lf
273
+ fragments.push(
274
+ '<td data-serie="' + i + '" class="legendColorBox"><div class="outerBorder"><div style="width:4px;height:0;border:5px solid ' + s.color + ';overflow:hidden"></div></div></td>')
275
+
276
+ fragments.push('<td class="legendLabel">' + label + '</td>')
277
+ fragments.push("<td>#{s.format( @avg(s) )}</td>")
278
+ fragments.push("<td>#{s.format( @min(s) )}</td>")
279
+ fragments.push("<td>#{s.format( @max(s) )}</td>")
280
+
281
+
282
+ fragments.push('</tr>') if rowStarted
283
+
284
+ return if fragments.length == 0
285
+
286
+ table = '<table style="font-size:smaller;color:#545454">' + fragments.join("") + '</table>'
287
+ @get("legend_containers")[index].find("div").html(table)
288
+
289
+ legend_lines = $(".legendColorBox", @get("legend_containers")[index])
290
+
291
+
292
+ $.each legend_lines, (i, el) =>
293
+ id = $(el).attr("data-serie")
294
+ s = @get("series")[id]
295
+ s.set_legend_color( el )
296
+
297
+ # $(@legend_containers[index]).find(".legendColorBox").click () ->
298
+ legend_lines.click (event) =>
299
+ target = event.currentTarget
300
+ id = $(target).attr("data-serie")
301
+ s = @get("series")[id]
302
+
303
+ s.toggle_enabled()
304
+ s.set_legend_color(target)
305
+ @update_graph_from_cache()
306
+