fnordmetric 0.7.5 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/V1.0-ROADMAP +97 -0
- data/doc/full_example.rb +95 -511
- data/doc/legacy_example.rb +640 -0
- data/doc/minimal_example.rb +26 -0
- data/doc/preview3.png +0 -0
- data/fnordmetric.gemspec +3 -2
- data/lib/fnordmetric/acceptors/acceptor.rb +29 -0
- data/lib/fnordmetric/{inbound_stream.rb → acceptors/tcp_acceptor.rb} +8 -5
- data/lib/fnordmetric/{inbound_datagram.rb → acceptors/udp_acceptor.rb} +9 -8
- data/lib/fnordmetric/api.rb +2 -2
- data/lib/fnordmetric/context.rb +37 -18
- data/lib/fnordmetric/defaults.rb +9 -0
- data/lib/fnordmetric/ext.rb +72 -0
- data/lib/fnordmetric/gauge.rb +37 -10
- data/lib/fnordmetric/gauge_calculations.rb +38 -16
- data/lib/fnordmetric/gauge_modifiers.rb +67 -0
- data/lib/fnordmetric/gauge_rendering.rb +40 -0
- data/lib/fnordmetric/gauge_validations.rb +15 -0
- data/lib/fnordmetric/gauges/distribution_gauge.rb +85 -0
- data/lib/fnordmetric/gauges/timeseries_gauge.rb +143 -0
- data/lib/fnordmetric/gauges/toplist_gauge.rb +44 -0
- data/lib/fnordmetric/histogram.rb +57 -0
- data/lib/fnordmetric/logger.rb +42 -36
- data/lib/fnordmetric/namespace.rb +47 -23
- data/lib/fnordmetric/session.rb +6 -6
- data/lib/fnordmetric/standalone.rb +15 -35
- data/lib/fnordmetric/timeseries.rb +79 -0
- data/lib/fnordmetric/toplist.rb +61 -0
- data/lib/fnordmetric/version.rb +1 -1
- data/lib/fnordmetric/web/app.rb +122 -0
- data/lib/fnordmetric/web/app_helpers.rb +42 -0
- data/lib/fnordmetric/{dashboard.rb → web/dashboard.rb} +4 -0
- data/lib/fnordmetric/{event.rb → web/event.rb} +7 -2
- data/lib/fnordmetric/web/reactor.rb +87 -0
- data/lib/fnordmetric/web/web.rb +53 -0
- data/lib/fnordmetric/web/websocket.rb +38 -0
- data/lib/fnordmetric/widgets/bars_widget.rb +44 -0
- data/lib/fnordmetric/{html_widget.rb → widgets/html_widget.rb} +0 -0
- data/lib/fnordmetric/widgets/numbers_widget.rb +56 -0
- data/lib/fnordmetric/{pie_widget.rb → widgets/pie_widget.rb} +0 -0
- data/lib/fnordmetric/widgets/timeseries_widget.rb +55 -0
- data/lib/fnordmetric/widgets/toplist_widget.rb +64 -0
- data/lib/fnordmetric/worker.rb +26 -25
- data/lib/fnordmetric.rb +85 -115
- data/readme.md +362 -0
- data/spec/gauge_like_shared.rb +54 -0
- data/spec/gauge_spec.rb +2 -36
- data/spec/namespace_spec.rb +25 -11
- data/spec/spec_helper.rb +4 -0
- data/spec/{inbound_stream_spec.rb → tcp_acceptor_spec.rb} +3 -3
- data/spec/timeseries_gauge_spec.rb +54 -0
- data/spec/{inbound_datagram_spec.rb → udp_acceptor_spec.rb} +3 -3
- data/web/fnordmetric.css +786 -0
- data/web/haml/app.haml +38 -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_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_view.js +260 -0
- data/web/js/fnordmetric.html_widget.js +21 -0
- data/web/js/fnordmetric.js +255 -0
- data/web/js/fnordmetric.numbers_widget.js +121 -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 +343 -0
- data/web/js/fnordmetric.timeline_widget.js +333 -0
- data/web/js/fnordmetric.timeseries_widget.js +388 -0
- data/web/js/fnordmetric.toplist_widget.js +112 -0
- data/web/js/fnordmetric.ui.js +91 -0
- data/web/js/fnordmetric.util.js +244 -0
- data/{pub → web}/loader.gif +0 -0
- data/web/vendor/d3.v2.js +9382 -0
- data/web/vendor/font-awesome/css/font-awesome.css +239 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.eot +0 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.svg +175 -0
- data/web/vendor/font-awesome/font/fontawesome-webfont.svgz +0 -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 +413 -0
- data/web/vendor/jquery.maskedinput.js +252 -0
- data/web/vendor/rickshaw.css +286 -0
- data/web/vendor/rickshaw.fnordmetric.js +2676 -0
- metadata +129 -79
- data/Gemfile +0 -6
- data/README.md +0 -404
- data/Rakefile +0 -6
- data/doc/version +0 -1
- data/haml/app.haml +0 -79
- data/haml/widget.haml +0 -9
- data/lib/fnordmetric/app.rb +0 -163
- data/lib/fnordmetric/average_metric.rb +0 -7
- data/lib/fnordmetric/bars_widget.rb +0 -26
- data/lib/fnordmetric/combine_metric.rb +0 -7
- data/lib/fnordmetric/count_metric.rb +0 -13
- data/lib/fnordmetric/funnel_widget.rb +0 -2
- data/lib/fnordmetric/metric.rb +0 -80
- data/lib/fnordmetric/metric_api.rb +0 -37
- data/lib/fnordmetric/numbers_widget.rb +0 -26
- data/lib/fnordmetric/report.rb +0 -29
- data/lib/fnordmetric/sum_metric.rb +0 -13
- data/lib/fnordmetric/timeline_widget.rb +0 -30
- data/lib/fnordmetric/toplist_widget.rb +0 -25
- data/pub/fnordmetric.css +0 -145
- data/pub/fnordmetric.js +0 -1179
- data/pub/vendor/highcharts.js +0 -170
- data/pub/vendor/jquery-1.6.1.min.js +0 -18
@@ -0,0 +1,343 @@
|
|
1
|
+
FnordMetric.views.sessionView = (function(){
|
2
|
+
|
3
|
+
var listElem = $('<ul class="session_list"></ul>');
|
4
|
+
var feedInnerElem = $('<ul class="feed_inner"></ul>');
|
5
|
+
var typeListElem = $('<ul class="event_type_list"></ul>');
|
6
|
+
|
7
|
+
var filterElem = $('<div class="events_sidebar"></div>')
|
8
|
+
.append("<div class='headbar small'>Event Types</div>")
|
9
|
+
.append(typeListElem);
|
10
|
+
|
11
|
+
var feedElem = $('<div class="sessions_feed"></div>').append(feedInnerElem);
|
12
|
+
var sideElem = $('<div class="sessions_sidebar"></div>').append(listElem);
|
13
|
+
|
14
|
+
var eventsPolledUntil = false;
|
15
|
+
var eventsFilter = {uncheckedTypes: [], checkedSessions: []};
|
16
|
+
var sessionData = {};
|
17
|
+
var pollRunning = true;
|
18
|
+
var first_poll = true;
|
19
|
+
|
20
|
+
function load(elem){
|
21
|
+
eventsPolledUntil = parseInt(new Date().getTime()/10000);
|
22
|
+
|
23
|
+
elem.html('')
|
24
|
+
.append('<div class="navbar"></div>');
|
25
|
+
|
26
|
+
FnordMetric.ui.navbar($('.navbar', viewport), {
|
27
|
+
breadcrumb: [
|
28
|
+
["Fnord", "/group/fnord"],
|
29
|
+
["Active Users", "/active_users"]
|
30
|
+
],
|
31
|
+
buttons: [
|
32
|
+
["<i class='icon-refresh'></i>Refresh", function(){ }]
|
33
|
+
]
|
34
|
+
});
|
35
|
+
|
36
|
+
elem
|
37
|
+
.append(filterElem.css('marginTop', '47px'))
|
38
|
+
.append(feedElem)
|
39
|
+
.append(sideElem);
|
40
|
+
|
41
|
+
startPoll();
|
42
|
+
loadEventTypes();
|
43
|
+
};
|
44
|
+
|
45
|
+
function resize(_width, _height){
|
46
|
+
$('.sessions_feed').width(_width-452);
|
47
|
+
};
|
48
|
+
|
49
|
+
function startPoll(){
|
50
|
+
(doSessionPoll())();
|
51
|
+
(doEventsPoll())();
|
52
|
+
FnordMetric.views.sessionView.session_poll = window.setInterval(doSessionPoll(), 1000);
|
53
|
+
};
|
54
|
+
|
55
|
+
function stopPoll(){
|
56
|
+
pollRunning = false;
|
57
|
+
window.clearInterval(FnordMetric.views.sessionView.session_poll);
|
58
|
+
}
|
59
|
+
|
60
|
+
function doSessionPoll(){
|
61
|
+
return (function(){
|
62
|
+
/*$.ajax({
|
63
|
+
url: FnordMetric.p + '/' + FnordMetric.currentNamespace+'/sessions',
|
64
|
+
success: callbackSessionPoll()
|
65
|
+
});*/
|
66
|
+
sortSessions();
|
67
|
+
});
|
68
|
+
};
|
69
|
+
|
70
|
+
function loadEventHistory(params){
|
71
|
+
feedInnerElem.html('');
|
72
|
+
/*$.ajax({
|
73
|
+
url: FnordMetric.p + '/' + FnordMetric.currentNamespace+'/events',
|
74
|
+
data: params,
|
75
|
+
success: function(_data, _status){
|
76
|
+
var data = JSON.parse(_data).events;
|
77
|
+
for(var n=data.length; n >= 0; n--){
|
78
|
+
if(data[n]){ renderEvent(data[n]); }
|
79
|
+
}
|
80
|
+
}
|
81
|
+
});*/
|
82
|
+
}
|
83
|
+
|
84
|
+
function callbackSessionPoll(){
|
85
|
+
return (function(_data, _status){
|
86
|
+
$.each(JSON.parse(_data).sessions, function(i,v){
|
87
|
+
updateSession(v);
|
88
|
+
});
|
89
|
+
sortSessions();
|
90
|
+
});
|
91
|
+
};
|
92
|
+
|
93
|
+
function loadEventTypes(data){
|
94
|
+
typeListElem.html('');
|
95
|
+
$(data).each(function(i,v){
|
96
|
+
if((v.length > 0) && (v.slice(0,5)!='_set_')){
|
97
|
+
addEventType(v,v);
|
98
|
+
}
|
99
|
+
});
|
100
|
+
};
|
101
|
+
|
102
|
+
function setCheckboxesCheckedState(types_state, sessions_state) {
|
103
|
+
$('.event_type_list .event_type input').attr('checked', types_state);
|
104
|
+
$('.session_list .session input').attr('checked', sessions_state);
|
105
|
+
}
|
106
|
+
|
107
|
+
function addEventType(type, display){
|
108
|
+
typeListElem.append(
|
109
|
+
$('<li class="event_type"></li>').append(
|
110
|
+
$('<span class="history"></span>').html('history')
|
111
|
+
.click(function(){
|
112
|
+
setCheckboxesCheckedState(true, true);
|
113
|
+
$('input', $(this).parent()).attr('checked', true);
|
114
|
+
updateEventFilter(); loadEventHistory({type: type});
|
115
|
+
})
|
116
|
+
).append(
|
117
|
+
$('<input type="checkbox" />').attr('checked', true)
|
118
|
+
.click(function(){ updateEventFilter(); })
|
119
|
+
).append(
|
120
|
+
$('<span></span>').html(display)
|
121
|
+
).attr('rel', type)
|
122
|
+
);
|
123
|
+
}
|
124
|
+
|
125
|
+
function updateEventFilter(){
|
126
|
+
var _unchecked_types = [];
|
127
|
+
$('ul.event_type_list li.event_type').each(function(i,v){
|
128
|
+
if(!$('input', v).attr('checked')){
|
129
|
+
_unchecked_types.push($(v).attr('rel'));
|
130
|
+
}
|
131
|
+
});
|
132
|
+
eventsFilter.uncheckedTypes = _unchecked_types;
|
133
|
+
|
134
|
+
var _checked_sessions = [];
|
135
|
+
$('ul.session_list li.session').each(function(i,v){
|
136
|
+
if($('input', v).attr('checked')){
|
137
|
+
_checked_sessions.push($(v).data().session);
|
138
|
+
}
|
139
|
+
});
|
140
|
+
eventsFilter.checkedSessions = _checked_sessions;
|
141
|
+
}
|
142
|
+
|
143
|
+
function doEventsPoll(){
|
144
|
+
return (function(){
|
145
|
+
|
146
|
+
/*$.ajax({
|
147
|
+
url: FnordMetric.p + '/' + FnordMetric.currentNamespace+'/events?since='+eventsPolledUntil,
|
148
|
+
success: callbackEventsPoll()
|
149
|
+
});*/
|
150
|
+
|
151
|
+
FnordMetric.publish({
|
152
|
+
"type": "active_users_request",
|
153
|
+
"first_poll": first_poll,
|
154
|
+
"since": eventsPolledUntil
|
155
|
+
});
|
156
|
+
|
157
|
+
first_poll = false;
|
158
|
+
|
159
|
+
});
|
160
|
+
};
|
161
|
+
|
162
|
+
function announce(evt){
|
163
|
+
if (evt.type == "active_users_response"){
|
164
|
+
callbackEventsPoll(evt);
|
165
|
+
$(evt.sessions).each(function(){ updateSession(this); });
|
166
|
+
if(evt.types.length > 0){ loadEventTypes(evt.types); }
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
function callbackEventsPoll(data){
|
171
|
+
var events = data.events;
|
172
|
+
var timeout = 1000;
|
173
|
+
var maxevents = 200;
|
174
|
+
var passesFiltering = function(event_data) {
|
175
|
+
var passes_type_filtering = false;
|
176
|
+
var passes_session_filtering = false;
|
177
|
+
if(eventsFilter.uncheckedTypes.indexOf(event_data._type) == -1) {
|
178
|
+
if(parseInt(v._time)<=eventsPolledUntil) {
|
179
|
+
passes_type_filtering = true;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
if(!passes_type_filtering) return false;
|
183
|
+
|
184
|
+
if(eventsFilter.checkedSessions.length == 0){
|
185
|
+
return true; // No filter set - show all events
|
186
|
+
} else {
|
187
|
+
if(event_data._session_key){
|
188
|
+
if(eventsFilter.checkedSessions.indexOf(event_data._session_key) >= 0){
|
189
|
+
return true; // Filter set and match
|
190
|
+
} else {
|
191
|
+
return false; // Filter set but no match
|
192
|
+
}
|
193
|
+
} else {
|
194
|
+
return false; // Filter set but event is not associated with session
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
|
199
|
+
if(events.length > 0){
|
200
|
+
eventsPolledUntil = parseInt(events[0]._time)-1;
|
201
|
+
}
|
202
|
+
for(var n=events.length-1; n >= 0; n--){
|
203
|
+
var v = events[n];
|
204
|
+
if(passesFiltering(v)) {
|
205
|
+
renderEvent(v);
|
206
|
+
}
|
207
|
+
};
|
208
|
+
var elems = $("p", feedInnerElem);
|
209
|
+
for(var n=maxevents; n < elems.length; n++){
|
210
|
+
$(elems[n]).remove();
|
211
|
+
}
|
212
|
+
if(pollRunning){
|
213
|
+
window.setTimeout(doEventsPoll(), timeout);
|
214
|
+
}
|
215
|
+
};
|
216
|
+
|
217
|
+
function updateSession(session_data){
|
218
|
+
var session_key = session_data.session_key;
|
219
|
+
if(!sessionData[session_key]){
|
220
|
+
updateEventFilter()
|
221
|
+
}
|
222
|
+
sessionData[session_key] = session_data;
|
223
|
+
renderSession(session_data);
|
224
|
+
}
|
225
|
+
|
226
|
+
function sortSessions(){
|
227
|
+
console.log("fixpaul: sort and splice to 100");
|
228
|
+
}
|
229
|
+
|
230
|
+
function renderSession(session_data){
|
231
|
+
|
232
|
+
var session_name = session_data["_name"];
|
233
|
+
var session_time = FnordMetric.util.formatTimeSince(session_data["_updated_at"]);
|
234
|
+
var session_elem = $('li[data-session='+session_data["session_key"]+']:first');
|
235
|
+
|
236
|
+
if(session_elem.length>0){
|
237
|
+
|
238
|
+
if(session_data["_picture"] && (session_data["_picture"].length > 1)){
|
239
|
+
$('.picture img', session_elem).attr('src', session_data["_picture"])
|
240
|
+
}
|
241
|
+
|
242
|
+
if(session_name){
|
243
|
+
$('.name', session_elem).html(session_name);
|
244
|
+
}
|
245
|
+
|
246
|
+
$('.time', session_elem).html(session_time);
|
247
|
+
|
248
|
+
} else {
|
249
|
+
|
250
|
+
var session_picture = $('<img width="25" />');
|
251
|
+
|
252
|
+
if(!session_name){
|
253
|
+
session_name = session_data["session_key"].substr(0,15)
|
254
|
+
};
|
255
|
+
|
256
|
+
if(session_data["_picture"]){
|
257
|
+
session_picture.attr('src', session_data["_picture"]);
|
258
|
+
};
|
259
|
+
|
260
|
+
listElem.append(
|
261
|
+
$('<li class="session"></li>').append(
|
262
|
+
$('<div class="picture"></div>').html(session_picture)
|
263
|
+
).append(
|
264
|
+
$('<span class="name"></span>').html(session_name)
|
265
|
+
).append(
|
266
|
+
$('<span class="time"></span>').html(session_time)
|
267
|
+
).append(
|
268
|
+
$('<span class="history"></span>').html('history')
|
269
|
+
.click(function(){
|
270
|
+
setCheckboxesCheckedState(true, false);
|
271
|
+
updateEventFilter();
|
272
|
+
loadEventHistory({session_key: session_data["session_key"]});
|
273
|
+
})
|
274
|
+
).attr('data-session', session_data["session_key"])
|
275
|
+
);
|
276
|
+
|
277
|
+
}
|
278
|
+
};
|
279
|
+
|
280
|
+
function renderEvent(event_data){
|
281
|
+
var event_time = $('<span class="time"></span>');
|
282
|
+
var event_message = $('<span class="message"></span>');
|
283
|
+
var event_props = $('<span class="properties"></span>');
|
284
|
+
var event_picture = $('<div class="picture"></picture>');
|
285
|
+
|
286
|
+
var event_type = event_data._type;
|
287
|
+
|
288
|
+
if(!event_type){ return true; }
|
289
|
+
|
290
|
+
if(event_data._message){
|
291
|
+
event_message.html(event_data._message);
|
292
|
+
} else if(event_type=="_pageview"){
|
293
|
+
event_message.html("Pageview: " + event_data.url);
|
294
|
+
} else if(event_type.substr(0,5) == '_set_'){
|
295
|
+
return true; /* dont render */
|
296
|
+
} else {
|
297
|
+
event_message.html(event_type);
|
298
|
+
}
|
299
|
+
|
300
|
+
event_time.html(FnordMetric.util.formatTimeOfDay(event_data._time));
|
301
|
+
|
302
|
+
if(event_data._session_key && event_data._session_key.length > 0){
|
303
|
+
var __session_key = event_data._session_key;
|
304
|
+
var load_usersession = (function(){
|
305
|
+
loadEventHistory({session_key: __session_key});
|
306
|
+
});
|
307
|
+
if(session_data=sessionData[event_data._session_key]){
|
308
|
+
if(session_data._name){
|
309
|
+
event_props.append(
|
310
|
+
$('<strong></strong>').html(session_data._name).css({
|
311
|
+
'cursor': 'pointer'
|
312
|
+
}).click(load_usersession)
|
313
|
+
);
|
314
|
+
}
|
315
|
+
if(session_data._picture){
|
316
|
+
event_picture.append(
|
317
|
+
$('<img width="40" />').attr('src', session_data._picture)
|
318
|
+
).click(load_usersession);
|
319
|
+
}
|
320
|
+
}
|
321
|
+
}
|
322
|
+
|
323
|
+
feedInnerElem.prepend(
|
324
|
+
$('<li class="feed_event"></li>')
|
325
|
+
.append(event_time)
|
326
|
+
.append(event_picture)
|
327
|
+
.append(event_message)
|
328
|
+
.append(event_props)
|
329
|
+
);
|
330
|
+
}
|
331
|
+
|
332
|
+
function close(){
|
333
|
+
stopPoll();
|
334
|
+
};
|
335
|
+
|
336
|
+
return {
|
337
|
+
load: load,
|
338
|
+
resize: resize,
|
339
|
+
announce: announce,
|
340
|
+
close: close
|
341
|
+
};
|
342
|
+
|
343
|
+
});
|
@@ -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._class == "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
|
+
};
|