bp-fnordmetric 1.2.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +6 -0
- data/Rakefile +6 -0
- data/fnordmetric.gemspec +41 -0
- data/lib/fnordmetric.rb +149 -0
- data/lib/fnordmetric/acceptors/acceptor.rb +42 -0
- data/lib/fnordmetric/acceptors/amqp_acceptor.rb +56 -0
- data/lib/fnordmetric/acceptors/fyrehose_acceptor.rb +43 -0
- data/lib/fnordmetric/acceptors/stomp_acceptor.rb +71 -0
- data/lib/fnordmetric/acceptors/tcp_acceptor.rb +58 -0
- data/lib/fnordmetric/acceptors/udp_acceptor.rb +37 -0
- data/lib/fnordmetric/api.rb +46 -0
- data/lib/fnordmetric/cache.rb +20 -0
- data/lib/fnordmetric/context.rb +96 -0
- data/lib/fnordmetric/defaults.rb +22 -0
- data/lib/fnordmetric/enterprise/compatibility_handler.rb +42 -0
- data/lib/fnordmetric/ext.rb +75 -0
- data/lib/fnordmetric/gauge.rb +98 -0
- data/lib/fnordmetric/gauge_calculations.rb +106 -0
- data/lib/fnordmetric/gauge_modifiers.rb +144 -0
- data/lib/fnordmetric/gauge_rendering.rb +40 -0
- data/lib/fnordmetric/gauge_validations.rb +15 -0
- data/lib/fnordmetric/gauges/distribution_gauge.rb +87 -0
- data/lib/fnordmetric/gauges/server_health_gauge.rb +13 -0
- data/lib/fnordmetric/gauges/timeseries_gauge.rb +138 -0
- data/lib/fnordmetric/gauges/toplist_gauge.rb +44 -0
- data/lib/fnordmetric/histogram.rb +64 -0
- data/lib/fnordmetric/logger.rb +63 -0
- data/lib/fnordmetric/namespace.rb +208 -0
- data/lib/fnordmetric/session.rb +139 -0
- data/lib/fnordmetric/standalone.rb +20 -0
- data/lib/fnordmetric/timeseries.rb +79 -0
- data/lib/fnordmetric/toplist.rb +61 -0
- data/lib/fnordmetric/udp_client.rb +22 -0
- data/lib/fnordmetric/util.rb +25 -0
- data/lib/fnordmetric/version.rb +3 -0
- data/lib/fnordmetric/web/app.rb +63 -0
- data/lib/fnordmetric/web/app_helpers.rb +42 -0
- data/lib/fnordmetric/web/dashboard.rb +40 -0
- data/lib/fnordmetric/web/event.rb +99 -0
- data/lib/fnordmetric/web/reactor.rb +127 -0
- data/lib/fnordmetric/web/web.rb +59 -0
- data/lib/fnordmetric/web/websocket.rb +41 -0
- data/lib/fnordmetric/widget.rb +82 -0
- data/lib/fnordmetric/widgets/bars_widget.rb +44 -0
- data/lib/fnordmetric/widgets/html_widget.rb +28 -0
- data/lib/fnordmetric/widgets/numbers_widget.rb +80 -0
- data/lib/fnordmetric/widgets/pie_widget.rb +23 -0
- data/lib/fnordmetric/widgets/timeseries_widget.rb +65 -0
- data/lib/fnordmetric/widgets/toplist_widget.rb +68 -0
- data/lib/fnordmetric/worker.rb +89 -0
- data/lib/fnordmetric/zero_config_gauge.rb +138 -0
- data/run_specs.sh +11 -0
- data/spec/api_spec.rb +49 -0
- data/spec/context_spec.rb +42 -0
- data/spec/dashboard_spec.rb +38 -0
- data/spec/event_spec.rb +170 -0
- data/spec/ext_spec.rb +14 -0
- data/spec/fnordmetric_spec.rb +56 -0
- data/spec/gauge_like_shared.rb +56 -0
- data/spec/gauge_modifiers_spec.rb +583 -0
- data/spec/gauge_spec.rb +230 -0
- data/spec/namespace_spec.rb +114 -0
- data/spec/session_spec.rb +231 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/tcp_acceptor_spec.rb +35 -0
- data/spec/timeseries_gauge_spec.rb +56 -0
- data/spec/udp_acceptor_spec.rb +35 -0
- data/spec/util_spec.rb +46 -0
- data/spec/widget_spec.rb +113 -0
- data/spec/worker_spec.rb +40 -0
- data/web/.gitignore +4 -0
- data/web/build.sh +34 -0
- data/web/css/fnordmetric.core.css +868 -0
- data/web/haml/app.haml +20 -0
- data/web/haml/distribution_gauge.haml +118 -0
- data/web/haml/timeseries_gauge.haml +80 -0
- data/web/haml/toplist_gauge.haml +194 -0
- data/web/img/head.png +0 -0
- data/web/img/list.png +0 -0
- data/web/img/list_active.png +0 -0
- data/web/img/list_hover.png +0 -0
- data/web/img/loader.gif +0 -0
- data/web/img/loader_white.gif +0 -0
- data/web/img/navbar.png +0 -0
- data/web/img/navbar_btn.png +0 -0
- data/web/img/picto_gauge.png +0 -0
- data/web/js/fnordmetric.bars_widget.js +178 -0
- data/web/js/fnordmetric.dashboard_view.js +99 -0
- data/web/js/fnordmetric.gauge_explorer.js +173 -0
- data/web/js/fnordmetric.gauge_view.js +260 -0
- data/web/js/fnordmetric.html_widget.js +21 -0
- data/web/js/fnordmetric.js +315 -0
- data/web/js/fnordmetric.numbers_widget.js +122 -0
- data/web/js/fnordmetric.overview_view.js +35 -0
- data/web/js/fnordmetric.pie_widget.js +118 -0
- data/web/js/fnordmetric.realtime_timeline_widget.js +175 -0
- data/web/js/fnordmetric.session_view.js +342 -0
- data/web/js/fnordmetric.timeline_widget.js +333 -0
- data/web/js/fnordmetric.timeseries_widget.js +405 -0
- data/web/js/fnordmetric.toplist_widget.js +119 -0
- data/web/js/fnordmetric.ui.js +91 -0
- data/web/js/fnordmetric.util.js +248 -0
- data/web/vendor/font-awesome/css/font-awesome-ie7.min.css +22 -0
- data/web/vendor/font-awesome/css/font-awesome.css +540 -0
- data/web/vendor/font-awesome/css/font-awesome.min.css +33 -0
- data/web/vendor/font-awesome/font/FontAwesome.otf +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.eot +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.svg +284 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.ttf +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.woff +0 -0
- data/web/vendor/jquery-1.6.2.min.js +18 -0
- data/web/vendor/jquery-ui.min.js +6 -0
- data/web/vendor/jquery.combobox.js +129 -0
- data/web/vendor/jquery.maskedinput.js +252 -0
- metadata +438 -0
@@ -0,0 +1,333 @@
|
|
1
|
+
FnordMetric.widgets.timelineWidget = function(){
|
2
|
+
|
3
|
+
var widget_uid = FnordMetric.util.getNextWidgetUID();
|
4
|
+
var width, height, canvas, series, opts, xtick;
|
5
|
+
var xticks = 100;
|
6
|
+
var running_request = false;
|
7
|
+
|
8
|
+
var series_paths = {};
|
9
|
+
var series_values = {};
|
10
|
+
|
11
|
+
var xpadding = 30;
|
12
|
+
|
13
|
+
function render(_opts){
|
14
|
+
opts = _opts;
|
15
|
+
//if(!silent){ $(opts.elem).css('opacity', 0.5); }
|
16
|
+
|
17
|
+
if(opts.xticks){ xticks = opts.xticks; }
|
18
|
+
if(!opts.draw_points){ opts.draw_points = true; }
|
19
|
+
if(!opts.draw_path){ opts.draw_path = true; }
|
20
|
+
if(!opts.draw_ygrid){ opts.draw_ygrid = true; }
|
21
|
+
if(!opts.draw_xgrid){ opts.draw_xgrid = true; }
|
22
|
+
|
23
|
+
drawLayout(opts);
|
24
|
+
|
25
|
+
width = opts.elem.width() - (xpadding * 2) - 15;
|
26
|
+
height = opts.height || 240;
|
27
|
+
xtick = width / (xticks - 1);
|
28
|
+
|
29
|
+
canvas = d3.select('#container-'+widget_uid)
|
30
|
+
.append("svg:svg")
|
31
|
+
.attr("width", width+(2*xpadding))
|
32
|
+
.attr("height", height+30);
|
33
|
+
|
34
|
+
canvas.selectAll("*").remove();
|
35
|
+
|
36
|
+
for (ind in opts.series){
|
37
|
+
series_values[opts.series[ind]] = {};
|
38
|
+
}
|
39
|
+
|
40
|
+
updateRange();
|
41
|
+
updateChart();
|
42
|
+
|
43
|
+
if(opts.autoupdate){
|
44
|
+
var secs = parseInt(opts.autoupdate);
|
45
|
+
if(secs > 0){
|
46
|
+
var autoupdate_interval = window.setInterval(function(){
|
47
|
+
updateRange(true); updateChart(); // FIXPAUL: only update if not scrolled
|
48
|
+
}, secs*1000);
|
49
|
+
|
50
|
+
$('body').bind('fm_dashboard_close', function(){
|
51
|
+
window.clearInterval(autoupdate_interval);
|
52
|
+
});
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
//canvas.drawGrid(0, 0, width+(2*xpadding), height, 1, 6, "#ececec");
|
57
|
+
}
|
58
|
+
|
59
|
+
function announce(evt){
|
60
|
+
if(evt.widget_key == opts.widget_key){
|
61
|
+
if((evt.type == "widget_response") && (evt.cmd == "values_at")){
|
62
|
+
running_request = false;
|
63
|
+
updateSeriesData(evt.tick, evt.values);
|
64
|
+
updateChart();
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
function requestValues(_tick, times){
|
70
|
+
if(times.length > 0){
|
71
|
+
if(!running_request){
|
72
|
+
running_request = (new Date).getTime();
|
73
|
+
requestValuesAsync(_tick, times);
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
function requestValuesAsync(_tick, times){
|
79
|
+
FnordMetric.publish({
|
80
|
+
"_class": "widget_request",
|
81
|
+
"_channel": opts.channel,
|
82
|
+
"cmd": "values_at",
|
83
|
+
"tick": _tick,
|
84
|
+
"ticks": times,
|
85
|
+
"widget_key": opts.widget_key
|
86
|
+
})
|
87
|
+
}
|
88
|
+
|
89
|
+
|
90
|
+
function changeTick(){
|
91
|
+
opts.tick = parseInt($(this).attr('data-tick'));
|
92
|
+
opts.start_timestamp = null;
|
93
|
+
opts.end_timestamp = null;
|
94
|
+
updateRange();
|
95
|
+
redrawDatepicker();
|
96
|
+
updateChart();
|
97
|
+
}
|
98
|
+
|
99
|
+
function updateSeriesData(_tick, values){
|
100
|
+
for(_series in values){
|
101
|
+
for(_t in values[_series]){
|
102
|
+
series_values[_series][_tick+"+"+_t] = values[_series][_t];
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
function updateChart(){
|
108
|
+
var _ticks = [];
|
109
|
+
var _miss = [];
|
110
|
+
var _max = [];
|
111
|
+
var _rndr = [];
|
112
|
+
|
113
|
+
for(sind in opts.series){
|
114
|
+
var _last = opts.start_timestamp + opts.tick;
|
115
|
+
var _delta = (opts.end_timestamp - _last) / xticks;
|
116
|
+
var _sdata = [];
|
117
|
+
|
118
|
+
for(var n=0; n < xticks; n++){
|
119
|
+
var _t = (parseInt(_last / opts.tick) * opts.tick);
|
120
|
+
var _v = series_values[opts.series[sind]][opts.tick+"+"+_t];
|
121
|
+
if((_v === undefined) && (_miss.indexOf(_t) == -1)){ _miss.push(_t); }
|
122
|
+
_sdata.push(_v || 0);
|
123
|
+
_last += _delta;
|
124
|
+
}
|
125
|
+
|
126
|
+
_max.push(Math.max.apply(Math, _sdata));
|
127
|
+
_rndr.push([opts.series[sind], _sdata]);
|
128
|
+
}
|
129
|
+
|
130
|
+
_max = Math.max.apply(Math, _max)*1.1;
|
131
|
+
if(_max == 0){ _max = 1; }
|
132
|
+
|
133
|
+
for(rind in _rndr){
|
134
|
+
drawSeries(_rndr[rind][0], _rndr[rind][1], _max);
|
135
|
+
}
|
136
|
+
|
137
|
+
if(_miss.length > 0)
|
138
|
+
requestValues(opts.tick, _miss);
|
139
|
+
|
140
|
+
redrawDatepicker();
|
141
|
+
}
|
142
|
+
|
143
|
+
function refreshChart(){
|
144
|
+
for(_series in series_values){
|
145
|
+
series_values[_series] = {};
|
146
|
+
}
|
147
|
+
|
148
|
+
updateRange();
|
149
|
+
updateChart();
|
150
|
+
}
|
151
|
+
|
152
|
+
function drawSeries(series, series_data, _max){
|
153
|
+
|
154
|
+
//var path_string = "M0,"+height;
|
155
|
+
var path_string = "";
|
156
|
+
var _color = '0066CC';
|
157
|
+
|
158
|
+
if (series_paths[series]){
|
159
|
+
for(ind in series_paths[series]){
|
160
|
+
series_paths[series][ind].remove();
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
series_paths[series] = [];
|
165
|
+
|
166
|
+
if(!_max){ _max = Math.max.apply(Math, series_data)*1.1; }
|
167
|
+
if(_max < 1){ _max = 1; }
|
168
|
+
|
169
|
+
$(series_data).each(function(i,v){
|
170
|
+
|
171
|
+
var p_x = xpadding+(i*xtick);
|
172
|
+
var p_y = (height-((v/_max)*height));
|
173
|
+
|
174
|
+
path_string += ( ( i == 0 ? "M" : "L" ) + p_x + ',' + p_y );
|
175
|
+
|
176
|
+
// if(i%label_mod==0){
|
177
|
+
// canvas.text(p_x, height+10, labels[i]).attr({
|
178
|
+
// font: '10px Helvetica, Arial',
|
179
|
+
// fill: "#777"
|
180
|
+
// });
|
181
|
+
// }
|
182
|
+
|
183
|
+
if(opts.draw_points){
|
184
|
+
series_paths[series].push(canvas
|
185
|
+
.append("svg:circle")
|
186
|
+
.attr("cx", p_x)
|
187
|
+
.attr("cy", p_y)
|
188
|
+
.attr("stroke-width", "1px")
|
189
|
+
.attr("stroke", "#fff")
|
190
|
+
.attr("fill", _color)
|
191
|
+
.attr("fill-opacity", 1)
|
192
|
+
.attr("r", 4)
|
193
|
+
);
|
194
|
+
}
|
195
|
+
|
196
|
+
// var htrgt = canvas.rect(p_x - 20, p_y - 20, 40, 40).attr({
|
197
|
+
// stroke: "none",
|
198
|
+
// fill: "#fff",
|
199
|
+
// opacity: 0
|
200
|
+
// }).toFront();
|
201
|
+
|
202
|
+
//series_paths[series].push(htrgt);
|
203
|
+
|
204
|
+
// (function(htrgt, series_paths){
|
205
|
+
|
206
|
+
// var t_y = p_y + 9;
|
207
|
+
// var ttt = canvas.text(p_x, t_y+10, v).attr({
|
208
|
+
// font: '12px Helvetica, Arial',
|
209
|
+
// fill: "#fff",
|
210
|
+
// opacity: 0
|
211
|
+
// });
|
212
|
+
|
213
|
+
// var tttb = ttt.getBBox();
|
214
|
+
// var ttw = tttb.width+20;
|
215
|
+
// var tt = canvas.rect(p_x-(ttw/2), t_y, ttw, 22, 5).attr({
|
216
|
+
// stroke: "none",
|
217
|
+
// fill: "#000",
|
218
|
+
// opacity: 0
|
219
|
+
// }).toBack();
|
220
|
+
|
221
|
+
// series_paths[series].push(tt);
|
222
|
+
// series_paths[series].push(ttt);
|
223
|
+
|
224
|
+
// $(htrgt[0]).hover(function(){
|
225
|
+
// tt.animate({ opacity: 0.8 }, 300);
|
226
|
+
// ttt.animate({ opacity: 0.8 }, 300);
|
227
|
+
// }, function(){
|
228
|
+
// tt.animate({ opacity: 0 }, 300);
|
229
|
+
// ttt.animate({ opacity: 0 }, 300);
|
230
|
+
// });
|
231
|
+
|
232
|
+
// })(htrgt, series_paths);
|
233
|
+
|
234
|
+
});
|
235
|
+
|
236
|
+
if(opts.draw_path){
|
237
|
+
series_paths[series].push(canvas.append("svg:path")
|
238
|
+
.attr("fill", "none")
|
239
|
+
.attr("stroke", "steelblue")
|
240
|
+
.attr("stroke-width", 3)
|
241
|
+
.attr("d", path_string)
|
242
|
+
);
|
243
|
+
}
|
244
|
+
|
245
|
+
if(opts.draw_area){
|
246
|
+
// path_string += "L"+(width+xpadding)+","+height+" L"+xpadding+","+height+" Z";
|
247
|
+
|
248
|
+
// series_paths[series].push(
|
249
|
+
// canvas.path(path_string).attr({
|
250
|
+
// stroke: "none",
|
251
|
+
// fill: _color,
|
252
|
+
// opacity: 0.1
|
253
|
+
// }).toBack()
|
254
|
+
// );
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
function drawLayout(opts){
|
259
|
+
$(opts.elem).append( $('<div></div>').attr('class', 'headbar').append(
|
260
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('refresh')).click(
|
261
|
+
function(){ refreshChart(); }
|
262
|
+
)
|
263
|
+
).append(
|
264
|
+
$('<div></div>').attr('class', 'button mr').append($('<span></span>').html('→')).click(
|
265
|
+
function(){ moveRange(1); }
|
266
|
+
)
|
267
|
+
).append(
|
268
|
+
$('<div></div>').attr('class', 'datepicker')
|
269
|
+
).append(
|
270
|
+
$('<div></div>').attr('class', 'button ml').append($('<span></span>').html('←')).click(
|
271
|
+
function(){ moveRange(-1); }
|
272
|
+
)
|
273
|
+
).append(
|
274
|
+
$('<h2></h2>').html(opts.title)
|
275
|
+
) ).append(
|
276
|
+
$('<div></div>').attr('id', 'container-'+widget_uid).css({
|
277
|
+
height: opts.height + 6,
|
278
|
+
marginBottom: 20,
|
279
|
+
overflow: 'hidden'
|
280
|
+
})
|
281
|
+
);
|
282
|
+
|
283
|
+
if(opts.ticks){
|
284
|
+
$('.headbar', opts.elem).append('<div class="tick_btns btn_group"></div>');
|
285
|
+
for(__tick in opts.ticks){
|
286
|
+
var _tick = opts.ticks[__tick];
|
287
|
+
$('.tick_btns', opts.elem).append(
|
288
|
+
$('<div></div>').attr('class', 'button tick').append($('<span></span>')
|
289
|
+
.html(FnordMetric.util.formatTimeRange(_tick)))
|
290
|
+
.attr('data-tick', _tick)
|
291
|
+
.click(changeTick)
|
292
|
+
);
|
293
|
+
}
|
294
|
+
}
|
295
|
+
}
|
296
|
+
|
297
|
+
function redrawDatepicker(){
|
298
|
+
$('.datepicker', opts.elem).html(
|
299
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(opts.start_timestamp)*1000) +
|
300
|
+
' ‐ ' +
|
301
|
+
Highcharts.dateFormat('%d.%m.%y %H:%M', parseInt(opts.end_timestamp)*1000)
|
302
|
+
);
|
303
|
+
}
|
304
|
+
|
305
|
+
function updateRange(force){
|
306
|
+
if(!opts.tick){
|
307
|
+
opts.tick = opts.ticks[0];
|
308
|
+
}
|
309
|
+
|
310
|
+
if(!opts.start_timestamp || !opts.end_timestamp || !!force){
|
311
|
+
opts.end_timestamp = parseInt(new Date().getTime() / 1000);
|
312
|
+
opts.start_timestamp = opts.end_timestamp - (opts.tick * xticks);
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
function moveRange(direction){
|
317
|
+
v = opts.tick*direction*8;
|
318
|
+
|
319
|
+
if(((opts.end_timestamp + v)*1000) < new Date().getTime()){
|
320
|
+
opts.start_timestamp += v;
|
321
|
+
opts.end_timestamp += v;
|
322
|
+
}
|
323
|
+
|
324
|
+
updateChart();
|
325
|
+
}
|
326
|
+
|
327
|
+
|
328
|
+
return {
|
329
|
+
render: render,
|
330
|
+
announce: announce
|
331
|
+
}
|
332
|
+
|
333
|
+
};
|
@@ -0,0 +1,405 @@
|
|
1
|
+
FnordMetric.widgets.timeseriesWidget = function(){
|
2
|
+
|
3
|
+
/*
|
4
|
+
options:
|
5
|
+
height: 430
|
6
|
+
default_cardinal: true/false
|
7
|
+
default_style: line/area/stack/flow
|
8
|
+
series
|
9
|
+
*/
|
10
|
+
|
11
|
+
var widget_uid = "fnord-" + parseInt(Math.random()*99990000);
|
12
|
+
var width, height, opts, graph, gconfig, legend, hoverDetail, shelving, highlighter, resolution;
|
13
|
+
|
14
|
+
var cardinal = true;
|
15
|
+
var xticks = 30;
|
16
|
+
|
17
|
+
function render(_opts){
|
18
|
+
opts = _opts;
|
19
|
+
|
20
|
+
if(opts.default_style == "areaspline"){ opts.default_style = 'area'; }
|
21
|
+
if(!opts.default_style){ opts.default_style = 'line'; }
|
22
|
+
if(!opts.default_cardinal){ opts.default_cardinal = false; }
|
23
|
+
if(opts.xticks){ xticks = opts.xticks; }
|
24
|
+
|
25
|
+
draw_layout();
|
26
|
+
|
27
|
+
gconfig = {
|
28
|
+
element: $('.container', opts.elem)[0],
|
29
|
+
interpolation: (opts.default_cardinal ? 'cardinal' : 'linear'),
|
30
|
+
stroke: true,
|
31
|
+
series: opts.series,
|
32
|
+
padding: { top: 0.1, bottom: 0 }
|
33
|
+
}
|
34
|
+
|
35
|
+
$(opts.elem)
|
36
|
+
.addClass('resize_listener')
|
37
|
+
.bind('fm_resize', renderChart);
|
38
|
+
|
39
|
+
apply_style(opts.default_style);
|
40
|
+
|
41
|
+
if(opts.async_chart){
|
42
|
+
updateChart();
|
43
|
+
} else {
|
44
|
+
renderChart();
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
function toggle_cardinal(){
|
49
|
+
if($(this).hasClass('active')){ return false; }
|
50
|
+
$(this).addClass('active').siblings().removeClass('active');
|
51
|
+
|
52
|
+
if(cardinal === true){
|
53
|
+
cardinal = false;
|
54
|
+
gconfig.interpolation = 'linear';
|
55
|
+
} else {
|
56
|
+
cardinal = true;
|
57
|
+
gconfig.interpolation = 'cardinal';
|
58
|
+
}
|
59
|
+
|
60
|
+
graph.configure(gconfig);
|
61
|
+
graph.render();
|
62
|
+
}
|
63
|
+
|
64
|
+
function change_style(){
|
65
|
+
$(this).addClass('active').siblings().removeClass('active');
|
66
|
+
|
67
|
+
apply_style($(this).attr('data'));
|
68
|
+
//graph.configure(gconfig);
|
69
|
+
//graph.render();
|
70
|
+
|
71
|
+
renderChart();
|
72
|
+
}
|
73
|
+
|
74
|
+
function apply_style(style){
|
75
|
+
if(style == 'line'){
|
76
|
+
gconfig.renderer = 'line';
|
77
|
+
gconfig.offset = 'zero';
|
78
|
+
}
|
79
|
+
|
80
|
+
if(style == 'area'){
|
81
|
+
gconfig.renderer = 'area';
|
82
|
+
gconfig.offset = 'zero';
|
83
|
+
}
|
84
|
+
|
85
|
+
if(style == 'flow'){
|
86
|
+
gconfig.renderer = 'stack';
|
87
|
+
gconfig.offset = 'silhouette';
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
function apply_resolution(){
|
92
|
+
if(!resolution){
|
93
|
+
var trgt_resolution = 50;
|
94
|
+
var best_resolution = false;
|
95
|
+
|
96
|
+
for(ind in opts.series_resolutions){
|
97
|
+
var _diff = Math.abs(
|
98
|
+
trgt_resolution -
|
99
|
+
(opts.timespan / opts.series_resolutions[ind])
|
100
|
+
);
|
101
|
+
|
102
|
+
if((!best_resolution) || (_diff < best_resolution)){
|
103
|
+
best_resolution = opts.series_resolutions[ind];
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
resolution = best_resolution;
|
108
|
+
}
|
109
|
+
|
110
|
+
for(ind in gconfig.series){
|
111
|
+
gconfig.series[ind].data = gconfig.series[ind]["data"+resolution];
|
112
|
+
}
|
113
|
+
|
114
|
+
$('.button.tick', opts.elem)
|
115
|
+
.removeClass('active')
|
116
|
+
.filter('[data-tick="'+resolution+'"]')
|
117
|
+
.addClass('active');
|
118
|
+
}
|
119
|
+
|
120
|
+
function draw_layout(){
|
121
|
+
if(!opts.ext && !opts.no_headbar){
|
122
|
+
$(opts.elem).append(
|
123
|
+
$('<div></div>')
|
124
|
+
.addClass('headbar')
|
125
|
+
.append($('<h2></h2>').html(opts.title))
|
126
|
+
.append(
|
127
|
+
$('<div class="btn_group mr"></div>')
|
128
|
+
.append(
|
129
|
+
$('<div></div>')
|
130
|
+
.addClass('button')
|
131
|
+
.append($('<span>').html('Flow'))
|
132
|
+
.attr('data', 'flow')
|
133
|
+
.click(change_style)
|
134
|
+
)
|
135
|
+
.append(
|
136
|
+
$('<div></div>')
|
137
|
+
.addClass('button')
|
138
|
+
.append($('<span>').html('Area'))
|
139
|
+
.attr('data', 'area')
|
140
|
+
.click(change_style)
|
141
|
+
)
|
142
|
+
.append(
|
143
|
+
$('<div></div>')
|
144
|
+
.addClass('button')
|
145
|
+
.append($('<span>').html('Line'))
|
146
|
+
.attr('data', 'line')
|
147
|
+
.click(change_style)
|
148
|
+
)
|
149
|
+
)
|
150
|
+
.append(
|
151
|
+
$('<div class="btn_group mr"></div>')
|
152
|
+
.append(
|
153
|
+
$('<div></div>')
|
154
|
+
.addClass('button mr')
|
155
|
+
.addClass(opts.default_cardinal ? '' : 'active')
|
156
|
+
.append($('<span>').html('Off'))
|
157
|
+
.attr('data', 'cardinal-off')
|
158
|
+
.click(toggle_cardinal)
|
159
|
+
)
|
160
|
+
.append(
|
161
|
+
$('<div></div>')
|
162
|
+
.addClass('button ml')
|
163
|
+
.addClass(opts.default_cardinal ? 'active' : '')
|
164
|
+
.append($('<span>').html('On'))
|
165
|
+
.attr('data', 'cardinal-on')
|
166
|
+
.click(toggle_cardinal)
|
167
|
+
)
|
168
|
+
)
|
169
|
+
)
|
170
|
+
}
|
171
|
+
|
172
|
+
$(opts.elem)
|
173
|
+
.append(
|
174
|
+
$('<div></div>')
|
175
|
+
.addClass('legend')
|
176
|
+
.css({
|
177
|
+
margin: '10px 30px 0 30px',
|
178
|
+
})
|
179
|
+
)
|
180
|
+
.append(
|
181
|
+
$('<div></div>')
|
182
|
+
.addClass('container')
|
183
|
+
.css({
|
184
|
+
height: opts.height,
|
185
|
+
margin: '0 23px 25px 23px',
|
186
|
+
})
|
187
|
+
);
|
188
|
+
|
189
|
+
if(!opts.ext && opts.async_chart && !opts.no_datepicker){
|
190
|
+
$('.headbar', opts.elem).prepend(
|
191
|
+
$('<div></div>')
|
192
|
+
.addClass('button ml')
|
193
|
+
.append($('<span></span>').html('←'))
|
194
|
+
.click(function(){ moveRange(-1); })
|
195
|
+
).prepend(
|
196
|
+
$('<div></div>')
|
197
|
+
.addClass('datepicker')
|
198
|
+
).prepend(
|
199
|
+
$('<div></div>')
|
200
|
+
.addClass('button')
|
201
|
+
.append($('<span></span>').html('→'))
|
202
|
+
.click(function(){ moveRange(1); })
|
203
|
+
).prepend(
|
204
|
+
$('<div class="refresh_btn"></div>')
|
205
|
+
.addClass('button ml')
|
206
|
+
.append($('<span></span>').html('refresh'))
|
207
|
+
.click(function(){ requestValuesAsync(); })
|
208
|
+
);
|
209
|
+
}
|
210
|
+
|
211
|
+
if(opts.series_resolutions){
|
212
|
+
$('.headbar', opts.elem).append('<div class="tick_btns btn_group"></div>');
|
213
|
+
for(ind in opts.series_resolutions){
|
214
|
+
var _tick = opts.series_resolutions[ind];
|
215
|
+
$('.tick_btns', opts.elem).append(
|
216
|
+
$('<div></div>').attr('class', 'button tick').append($('<span></span>')
|
217
|
+
.html(FnordMetric.util.formatTimeRange(_tick)))
|
218
|
+
.attr('data-tick', _tick)
|
219
|
+
.click(function(){
|
220
|
+
resolution = $(this).attr('data-tick');
|
221
|
+
renderChart();
|
222
|
+
})
|
223
|
+
);
|
224
|
+
}
|
225
|
+
}
|
226
|
+
|
227
|
+
if((opts.autoupdate) && (opts.async_chart)){
|
228
|
+
var secs = parseInt(opts.autoupdate);
|
229
|
+
if(secs > 0){
|
230
|
+
var autoupdate_interval = window.setInterval(function(){
|
231
|
+
updateChart(false, true);
|
232
|
+
}, secs*1000);
|
233
|
+
|
234
|
+
$('body').bind('fm_dashboard_close', function(){
|
235
|
+
window.clearInterval(autoupdate_interval);
|
236
|
+
});
|
237
|
+
}
|
238
|
+
}
|
239
|
+
}
|
240
|
+
|
241
|
+
function renderChart(){
|
242
|
+
width = opts.elem.width() - 50;
|
243
|
+
height = opts.height || 240;
|
244
|
+
|
245
|
+
gconfig.width = width;
|
246
|
+
gconfig.height = height;
|
247
|
+
|
248
|
+
$(gconfig.element).html("");
|
249
|
+
$(".fnordmetric_legend", opts.elem).html("");
|
250
|
+
|
251
|
+
if(opts.series_resolutions){
|
252
|
+
apply_resolution();
|
253
|
+
}
|
254
|
+
|
255
|
+
graph = new FnordMetric.rickshaw.Graph(gconfig);
|
256
|
+
|
257
|
+
legend = new FnordMetric.rickshaw.Graph.Legend({
|
258
|
+
graph: graph,
|
259
|
+
element: $('.legend', opts.elem)[0]
|
260
|
+
});
|
261
|
+
|
262
|
+
hoverDetail = new FnordMetric.rickshaw.Graph.HoverDetail( {
|
263
|
+
graph: graph
|
264
|
+
});
|
265
|
+
|
266
|
+
shelving = new FnordMetric.rickshaw.Graph.Behavior.Series.Toggle({
|
267
|
+
graph: graph,
|
268
|
+
legend: legend
|
269
|
+
});
|
270
|
+
|
271
|
+
highlighter = new FnordMetric.rickshaw.Graph.Behavior.Series.Highlight({
|
272
|
+
graph: graph,
|
273
|
+
legend: legend
|
274
|
+
});
|
275
|
+
|
276
|
+
new FnordMetric.rickshaw.Graph.Axis.Time({
|
277
|
+
graph: graph,
|
278
|
+
}).render();
|
279
|
+
|
280
|
+
new FnordMetric.rickshaw.Graph.Axis.Y({
|
281
|
+
graph: graph,
|
282
|
+
}).render();
|
283
|
+
|
284
|
+
if(!gconfig.renderer){
|
285
|
+
gconfig.renderer = "line";
|
286
|
+
}
|
287
|
+
|
288
|
+
graph.configure(gconfig);
|
289
|
+
graph.render();
|
290
|
+
}
|
291
|
+
|
292
|
+
|
293
|
+
function announce(evt){
|
294
|
+
if(evt.widget_key == opts.widget_key){
|
295
|
+
if((evt.type == "widget_response") && (evt.cmd == "values_at")){
|
296
|
+
running_request = false;
|
297
|
+
$(opts.elem).css('opacity', 1);
|
298
|
+
updateSeriesData(evt.gauges);
|
299
|
+
}
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
function requestValuesAsync(){
|
304
|
+
FnordMetric.publish({
|
305
|
+
"type": "widget_request",
|
306
|
+
"klass": "generic",
|
307
|
+
"gauges": opts.gauges,
|
308
|
+
"cmd": "values_at",
|
309
|
+
"tick": opts.tick,
|
310
|
+
"since": opts.start_timestamp,
|
311
|
+
"until": opts.end_timestamp,
|
312
|
+
"widget_key": opts.widget_key
|
313
|
+
});
|
314
|
+
}
|
315
|
+
|
316
|
+
function updateSeriesData(dgauges){
|
317
|
+
gconfig.series = [];
|
318
|
+
|
319
|
+
for(var ind = 0; ind < dgauges.length; ind++){
|
320
|
+
|
321
|
+
gconfig.series.push({
|
322
|
+
name: dgauges[ind].title,
|
323
|
+
color: opts.series[ind].color,
|
324
|
+
data: []
|
325
|
+
});
|
326
|
+
|
327
|
+
for(_time in dgauges[ind].vals){
|
328
|
+
gconfig.series[ind].data.push(
|
329
|
+
{ x: parseInt(_time), y: parseInt(dgauges[ind].vals[_time] || 0) }
|
330
|
+
);
|
331
|
+
}
|
332
|
+
|
333
|
+
}
|
334
|
+
|
335
|
+
renderChart();
|
336
|
+
}
|
337
|
+
|
338
|
+
function updateChart(first_time, silent){
|
339
|
+
if(!silent){ $(opts.elem).css('opacity', 0.7); }
|
340
|
+
updateRange();
|
341
|
+
redrawDatepicker();
|
342
|
+
requestValuesAsync();
|
343
|
+
}
|
344
|
+
|
345
|
+
function redrawDatepicker(){
|
346
|
+
$('.datepicker', opts.elem).html(
|
347
|
+
FnordMetric.util.dateFormat(opts.start_timestamp) +
|
348
|
+
' ‐ ' +
|
349
|
+
FnordMetric.util.dateFormat(opts.end_timestamp)
|
350
|
+
);
|
351
|
+
}
|
352
|
+
|
353
|
+
function updateRange(force){
|
354
|
+
var _now = parseInt(new Date().getTime() / 1000);
|
355
|
+
|
356
|
+
if (opts.no_update_range)
|
357
|
+
return;
|
358
|
+
|
359
|
+
if (opts.ext) {
|
360
|
+
opts.end_timestamp = _now;
|
361
|
+
opts.start_timestamp = _now - opts.trange;
|
362
|
+
return;
|
363
|
+
}
|
364
|
+
|
365
|
+
if(!opts.tick){
|
366
|
+
opts.tick = opts.ticks[0];
|
367
|
+
}
|
368
|
+
|
369
|
+
if((opts.autoupdate) &&
|
370
|
+
((_now - opts.end_timestamp) < ((opts.tick*(opts.autoupdate+1)) + 5))){
|
371
|
+
force = true;
|
372
|
+
}
|
373
|
+
|
374
|
+
if(!opts.start_timestamp || !opts.end_timestamp || !!force){
|
375
|
+
opts.end_timestamp = _now + opts.tick;
|
376
|
+
opts.start_timestamp = opts.end_timestamp - (opts.tick * xticks);
|
377
|
+
}
|
378
|
+
}
|
379
|
+
|
380
|
+
function moveRange(direction){
|
381
|
+
v = opts.tick*direction*8;
|
382
|
+
|
383
|
+
if(((opts.end_timestamp + v)*1000) < new Date().getTime()){
|
384
|
+
opts.start_timestamp += v;
|
385
|
+
opts.end_timestamp += v;
|
386
|
+
}
|
387
|
+
|
388
|
+
redrawDatepicker();
|
389
|
+
requestValuesAsync();
|
390
|
+
}
|
391
|
+
|
392
|
+
function set_timerange(s, e){
|
393
|
+
opts.start_timestamp = s;
|
394
|
+
opts.end_timestamp = e;
|
395
|
+
redrawDatepicker();
|
396
|
+
requestValuesAsync();
|
397
|
+
}
|
398
|
+
|
399
|
+
return {
|
400
|
+
render: render,
|
401
|
+
announce: announce,
|
402
|
+
set_timerange: set_timerange
|
403
|
+
}
|
404
|
+
|
405
|
+
};
|