Project

General

Profile

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

    
20
function graph_init() {
21

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

    
30
    var nowTime = now.getTime();
31

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

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

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

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

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

    
57
	});
58

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

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

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

    
74
			var nowTime = now.getTime();
75

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

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

    
81
				myData[value] = [];
82

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

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

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

    
102
			});
103

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

    
108
		}
109
	});
110
}
111

    
112
function draw_graph(then) {
113

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

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

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

    
147
		var stepTime = thenTime;
148

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

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

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

    
161
		}
162

    
163
		nv.addGraph(function() {
164

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
223
					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>';
224

    
225
				}
226

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

    
229
				return content;
230

    
231
			});
232

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

    
236
	});
237

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

    
247
			if (error) {
248

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

    
255

    
256
			}
257

    
258
			if (json.error) {
259

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

    
266
			}
267

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

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

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

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

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

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

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

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

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

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

    
346
	}
347

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