Project

General

Profile

Download (9.05 KB) Statistics
| Branch: | Tag: | Revision:
1
/*
2
 * part of pfSense (https://www.pfsense.org)
3
 * Copyright (c) 2016-2018 Rubicon Communications, LLC (Netgate)
4
 * All rights reserved.
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 * http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18

    
19
function graph_init() {
20

    
21
	window.charts = {};
22
    window.myData = {};
23
    window.updateIds = 0;
24
    window.updateTimerIds = 0;
25
    window.latest = [];
26
    //TODO make it fall on a second value so it increments better
27
    var now = then = new Date(Date.now());
28

    
29
    var nowTime = now.getTime();
30

    
31
	$.each(window.interfaces, function( key, value ) {
32

    
33
		myData[value] = [];
34
		updateIds = 0;
35
		updateTimerIds = 0;
36

    
37
		var itemIn = new Object();
38
		var itemOut = new Object();
39

    
40
		itemIn.key = value + " (in)";
41
		if (window.invert) {
42
			itemIn.area = true;
43
		}
44
		itemIn.first = true;
45
		itemIn.values = [{x: nowTime, y: 0}];
46
		myData[value].push(itemIn);
47

    
48
		itemOut.key = value + " (out)";
49
		if (window.invert) {
50
			itemOut.area = true;
51
		}
52
		itemOut.first = true;
53
		itemOut.values = [{x: nowTime, y: 0}];
54
		myData[value].push(itemOut);
55

    
56
	});
57

    
58
	if (window.interfaces.length > 0) {
59
		draw_graph(then);
60
	}
61
}
62

    
63
function graph_visibilitycheck() {
64
	//re-draw graph when the page goes from inactive (in it's window) to active
65
	Visibility.change(function (e, state) {
66
		if (window.graph_backgroundupdate) {
67
			return;
68
		}
69
		if (state === "visible") {
70

    
71
			now = then = new Date(Date.now());
72

    
73
			var nowTime = now.getTime();
74

    
75
			$.each(window.interfaces, function( key, value ) {
76

    
77
				Visibility.stop(updateIds);
78
				clearInterval(updateTimerIds);
79

    
80
				myData[value] = [];
81

    
82
				var itemIn = new Object();
83
				var itemOut = new Object();
84

    
85
				itemIn.key = value + " (in)";
86
				if (window.invert) {
87
					itemIn.area = true;
88
				}
89
				itemIn.first = true;
90
				itemIn.values = [{x: nowTime, y: 0}];
91
				myData[value].push(itemIn);
92

    
93
				itemOut.key = value + " (out)";
94
				if (window.invert) {
95
					itemOut.area = true;
96
				}
97
				itemOut.first = true;
98
				itemOut.values = [{x: nowTime, y: 0}];
99
				myData[value].push(itemOut);
100

    
101
			});
102

    
103
			if (window.interfaces.length > 0) {
104
				draw_graph(then);
105
			}
106

    
107
		}
108
	});
109
}
110

    
111
function draw_graph(then) {
112

    
113
	d3.select("div[id^=nvtooltip-]").remove();
114
	d3.select(".interface-label").remove();
115

    
116
	var invert = window.invert;
117
	var size = window.size;
118
	var refreshInterval = window.interval;
119
	var lasttime = 0;
120
	// This is a moving average to average the previous 'x' points to the current
121
	var smoothing = window.smoothing;
122
	var smoothCount = 0;
123
	// hold previous data
124
	var priorIn = new Array();
125
	var priorOut = new Array();
126
	// If the put smoothing == 0 don't initialize first element
127
	var interfaceSize = window.interfaces.length;
128
	for(var i = 0; i < interfaceSize; i ++){
129
		priorIn[i] = new Array();
130
		priorOut[i] = new Array();
131
		if( smoothing > 0 ){
132
			priorIn[i][0] = 0;
133
			priorOut[i][0] = 0;
134
		}
135
	}
136
	startTime = 120 * refreshInterval;
137
	then.setSeconds(then.getSeconds() - startTime);
138
	var thenTime = then.getTime();
139
	var refreshGraphFunction_running = false;
140

    
141
	$.each( window.interfaces, function( key, value ) {
142
		myData[value]['interfacename'] = graph_interfacenames[value];
143
		latest[value + 'in'] = 0;
144
		latest[value + 'out'] = 0;
145

    
146
		var stepTime = thenTime;
147

    
148
		//initialize first 120 graph points to zero
149
		for (i = 1; i < 120; i++) {
150

    
151
			stepTime = stepTime + (1000 * refreshInterval);
152

    
153
			myData[value].forEach(function(entry) {
154
				entry.values.push({
155
					x: stepTime,
156
					y: 0
157
				});
158
			});
159

    
160
		}
161

    
162
		nv.addGraph(function() {
163

    
164
			charts[value] = nv.models.lineChart()
165
						.useInteractiveGuideline(true)
166
						.color(d3.scale.category10().range())
167
						.rightAlignYAxis(true)
168
						.margin({top: 0, left:25, bottom: 30, right: 45});
169

    
170
			charts[value]
171
				.x(function(d,i) { return d.x });
172

    
173
			charts[value].xAxis
174
				.tickFormat(function (d) {
175
					return d3.time.format('%M:%S')(new Date(d));
176
				});
177

    
178
			var sizeLabel = $( "#traffic-graph-size option:selected" ).text();
179

    
180
			d3.select('#traffic-chart-' + value + ' svg')
181
				.append("text")
182
				.attr('class', 'interface-label')
183
				.attr("x", 20)
184
				.attr("y", 20)
185
				.attr("font-size", 18)
186
				.text(myData[value]['interfacename']);
187

    
188
			charts[value].yAxis
189
		    	.tickFormat(d3.format('.2s'))
190
		    	.showMaxMin(false);
191

    
192
			d3.select('#traffic-chart-' + value + ' svg')
193
				.datum(myData[value])
194
		    	.transition().duration(500)
195
		    	.call(charts[value]);
196

    
197
			nv.utils.windowResize(charts[value].update);
198

    
199
			//custom tooltip contents
200
			charts[value].interactiveLayer.tooltip.contentGenerator(function(data) {
201

    
202
				var units = 'b/s';
203
				if(window.size === 1) {
204
					units = 'B/s'
205
				}
206

    
207
				var content = '<h3>' + d3.time.format('%Y-%m-%d %H:%M:%S')(new Date(data.value)) + '</h3><table><tbody>';
208

    
209
				for ( var v = 0; v < data.series.length; v++ ){
210

    
211
					var rawValue = data.series[v].value;
212

    
213
					if(invert && data.series[v].key.includes("(out)")) {
214
						rawValue = 0 - rawValue;
215
					}
216

    
217
					var sValue = d3.formatPrefix(rawValue);
218

    
219
					//TODO change unit based on unit size
220
					var formattedVal = sValue.scale(rawValue).toFixed(2) + ' ' + sValue.symbol + units;
221

    
222
					content += '<tr><td class="legend-color-guide"><div style="background-color: ' + data.series[v].color + '"></div></td><td>' + data.series[v].key + '</td><td class="value"><strong>' + formattedVal + '</strong></td></tr>';
223

    
224
				}
225

    
226
				content += '</tbody></table>';
227

    
228
				return content;
229

    
230
			});
231

    
232
			return charts[value];
233
		});
234

    
235
	});
236

    
237
	var refreshGraphFunction = function(){
238
		if (refreshGraphFunction_running) {
239
			return;
240
		}
241
		refreshGraphFunction_running = true;
242
		d3.json("ifstats.php")
243
		.header("Content-Type", "application/x-www-form-urlencoded")
244
		.post('if='+window.interfaces.join('|')+'&realif='+window.realinterfaces.join('|'), function(error, json) { //TODO all ifs again
245

    
246
			if (error) {
247

    
248
				//Visibility.stop(updateIds);
249
				clearInterval(updateTimerIds);
250
				//$(".traffic-widget-chart").remove();
251
				//$("#traffic-chart-error").show().html('<strong>Error</strong>: ' + error);
252
				return console.warn("Caught: " + error);
253

    
254

    
255
			}
256

    
257
			if (json.error) {
258

    
259
				Visibility.stop(updateIds);
260
				clearInterval(updateTimerIds);
261
				$(".traffic-widget-chart").remove();
262
				$("#traffic-chart-error").show().html('<strong>Error</strong>: ' + json.error);
263
				return console.warn(json.error);
264

    
265
			}
266

    
267
			var setTime = true;
268
			var xtime = 0;
269
			var timeDiff = 0;
270
			var interfaceCount = 0;
271
			$.each(json, function( key, ifVals ) {
272
				if (setTime == true) {
273
					var valueTime = ifVals[0].values[0];
274
					timeDiff = valueTime - lasttime;
275
					lasttime = valueTime;
276
					xtime = valueTime * 1000;
277
					setTime = false;
278
				}
279

    
280
				label = $('#traffic-chart-' + key + ' svg > .interface-label');
281
				$(label).text(ifVals.name);
282
				if(!myData[key][0].first) {
283
					var currentIn = ((ifVals[0].values[1] * size) - latest[ifVals[0].key]) / timeDiff;
284
					var currentOut = ((ifVals[1].values[1] * size) - latest[ifVals[1].key]) / timeDiff;
285
					var trafficIn = ( priorIn[interfaceCount].reduce(function(a, b){ return a + b; },0) + currentIn)/(1 + priorIn[interfaceCount].length);
286
					var trafficOut = ( priorOut[interfaceCount].reduce(function(a, b){ return a + b; },0) + currentOut) /(1 + priorOut[interfaceCount].length);
287
					// circular array to keep track of 'x' amount of data points
288
					priorIn[interfaceCount][smoothCount] = currentIn;
289
					priorOut[interfaceCount][smoothCount] = currentOut;
290
					if(window.invert) {
291
						trafficOut = 0 - trafficOut;
292
					}
293

    
294
					myData[key][0].values.push({
295
						x: xtime,
296
						y: trafficIn
297
					});
298

    
299
					myData[key][1].values.push({
300
						x: xtime,
301
						y: trafficOut
302
					});
303

    
304
				} else {
305
					myData[key][0].values.push({
306
						x: xtime,
307
						y: 0
308
					});
309

    
310
					myData[key][1].values.push({
311
						x: xtime,
312
						y: 0
313
					});
314
				}
315

    
316
				latest[ifVals[0].key] = ifVals[0].values[1] * size;
317
				latest[ifVals[1].key] = ifVals[1].values[1] * size;
318

    
319
				myData[key][0].first = false;
320
				myData[key][1].first = false;
321

    
322
				myData[key][0].values.shift();
323
				myData[key][1].values.shift();
324

    
325
				if (!Visibility.hidden()) {
326
					/*
327
					 * don't draw graph when tab is not
328
					 * visible. This also prevents lots of
329
					 * timers stacking up waiting for a
330
					 * frame update.
331
					 */
332
					charts[key].update();
333
				}
334
				interfaceCount++;
335
				interfaceCount = interfaceCount % interfaceSize;
336
			});
337
			// increment the circular array
338
			smoothCount ++;
339
			smoothCount = smoothCount % smoothing;
340
			refreshGraphFunction_running = false;
341
		});
342

    
343
	}
344

    
345
	if(window.graph_backgroundupdate) {
346
		updateTimerIds = setInterval(refreshGraphFunction, refreshInterval * 1000);
347
	} else {
348
		//only update the graphs when tab is active in window to save resources and prevent build up
349
		updateIds = Visibility.every(refreshInterval * 1000, refreshGraphFunction);
350
	}
351
}
(4-4/4)