PluginProbe
WebTotem Security / 2.3.32
WebTotem Security v2.3.32
3.0.2 3.0.1 3.0.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 2.0 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.1 2.2.2 2.2.3 All 110 releases
wt-security / htdocs / js / wtsec_Chart.js

wtsec_Chart.js in WebTotem Security 2.3.32, at htdocs/js/wtsec_Chart.js

608 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 const isDarkThemeSet = ()=> {
2 return !!document.querySelector(".wtotem_theme—dark")}
3 ;
4
5 async function drawLineChart(dataset) {
6 var diagram = document.getElementById('wtotem_chart_diagram');
7 var days = diagram.dataset.days;
8
9 const attacksAccessor = (d) => d.attacks;
10 const blockedAccessor = (d) => d.blocked;
11 const biggerAccessor = (d) =>
12 d.attacks > d.blocked ? d.attacks : d.blocked;
13 const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d");
14 const xAccessor = (d) => dateParser(d.date);
15
16
17 const chartWrapper = document.getElementById('line-chart')
18 let dimensions = {
19 width: chartWrapper.offsetWidth,
20 height: 251,
21 margin: {
22 top: 15,
23 right: 15,
24 bottom: 40,
25 left: 60,
26 },
27 };
28 dimensions.boundedWidth =
29 dimensions.width - dimensions.margin.left - dimensions.margin.right;
30 dimensions.boundedHeight =
31 dimensions.height - dimensions.margin.top - dimensions.margin.bottom;
32
33 const wrapper = d3
34 .select("#line-chart")
35 .append("svg")
36 .attr("width", dimensions.width)
37 .attr("height", dimensions.height);
38
39 const bounds = wrapper
40 .append("g")
41 .style(
42 "transform",
43 `translate(${dimensions.margin.left - 10}px, ${
44 dimensions.margin.top
45 }px)`
46 );
47
48 const yScale = d3
49 .scaleLinear()
50 .domain(d3.extent(dataset, biggerAccessor))
51 .range([dimensions.boundedHeight, 0]);
52 const xScale = d3
53 .scaleTime()
54 .domain(d3.extent(dataset, xAccessor))
55 .range([0, dimensions.boundedWidth]);
56
57 function make_y_gridlines() {
58 return d3.axisLeft(yScale).ticks(5);
59 }
60
61 bounds
62 .append("g")
63 .attr("class", "grid")
64 .call(
65 make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("")
66 );
67
68 const area1 = d3
69 .area()
70 .x((d) => xScale(xAccessor(d)))
71 .y0(dimensions.height)
72 .y1((d) => yScale(attacksAccessor(d)));
73
74 const area2 = d3
75 .area()
76 .x((d) => xScale(xAccessor(d)))
77 .y0(dimensions.height)
78 .y1((d) => yScale(blockedAccessor(d)));
79
80 const isDarkTheme = isDarkThemeSet();
81 const minOpacity = isDarkTheme ? 0.2 : 0.1;
82 const maxOpacity = isDarkTheme ? 0.8 : 0.6;
83
84 bounds
85 .append("linearGradient")
86 .attr("id", "area-gradient1")
87 .attr("gradientUnits", "userSpaceOnUse")
88 .attr("x1", 0)
89 .attr("y1", yScale(0))
90 .attr("x2", 0)
91 .attr("y2", yScale(100))
92 .selectAll("stop")
93 .data([
94 { offset: "0%", color: "#d46c6a", opacity: minOpacity},
95 { offset: "100%", color: "#d46c6a", opacity: maxOpacity},
96 ])
97 .enter()
98 .append("stop")
99 .attr("offset", function (d) {
100 return d.offset;
101 })
102 .attr("stop-color", function (d) {
103 return d.color;
104 })
105 .attr("stop-opacity", function (d) {
106 return d.opacity;
107 });
108
109 bounds
110 .append("linearGradient")
111 .attr("id", "area-gradient2")
112 .attr("gradientUnits", "userSpaceOnUse")
113 .attr("x1", 0)
114 .attr("y1", yScale(0))
115 .attr("x2", 0)
116 .attr("y2", yScale(100))
117 .selectAll("stop")
118 .data([
119 { offset: "0%", color: "#bace3d", opacity: minOpacity },
120 { offset: "100%", color: "#bace3d", opacity: maxOpacity},
121 ])
122 .enter()
123 .append("stop")
124 .attr("offset", function (d) {
125 return d.offset;
126 })
127 .attr("stop-color", function (d) {
128 return d.color;
129 })
130 .attr("stop-opacity", function (d) {
131 return d.opacity;
132 });
133
134 const lineGenerator1 = d3
135 .line()
136 .x((d) => xScale(xAccessor(d)))
137 .y((d) => yScale(attacksAccessor(d)));
138 const lineGenerator2 = d3
139 .line()
140 .x((d) => xScale(xAccessor(d)))
141 .y((d) => yScale(attacksAccessor(d)));
142
143 const line1 = bounds
144 .append("path")
145 .datum(dataset)
146 .attr("d", lineGenerator1(dataset))
147 .attr("class", "area")
148 .attr("d", area1)
149 .style("fill", "url(#area-gradient1)");
150
151 const line2 = bounds
152 .append("path")
153 .datum(dataset)
154 .attr("d", lineGenerator2(dataset))
155 .attr("class", "area")
156 .attr("d", area2)
157 .style("fill", "url(#area-gradient2)");
158
159 const yAxisGenerator = d3.axisLeft().scale(yScale);
160 // const xAxisGenerator = d3.axisBottom().scale(xScale);
161
162 let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d");
163 const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) :
164 (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) :
165 (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) :
166 d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat);
167 //const xAxisGenerator = d3.axisBottom().scale(xScale).ticks(ticks).tickFormat(dateFormat);
168
169 const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator);
170 const xAxis = bounds
171 .append("g")
172 .call(xAxisGenerator)
173 .attr("class", "axis chart-date")
174 .style("transform", `translateY(${dimensions.boundedHeight}px)`);
175
176 const listeningRect = bounds
177 .append("rect")
178 .attr("class", "listening-rect")
179 .attr("width", dimensions.boundedWidth)
180 .attr("height", dimensions.boundedHeight)
181 .on("mousemove", onMouseMove)
182 .on("mouseleave", onMouseLeave);
183
184 const tooltipAttacks = d3.select("#tooltipAttacks");
185 const tooltipBlocked = d3.select("#tooltipBlocked");
186 const tooltipCircle1 = bounds
187 .append("circle")
188 .attr("class", "tooltip-circle")
189 .attr("r", 4)
190 .attr("stroke", "#F3F5F6")
191 .attr("fill", "#1D293F")
192 .attr("stroke-width", 2)
193 .style("opacity", 0);
194 const tooltipCircle2 = bounds
195 .append("circle")
196 .attr("class", "tooltip-circle")
197 .attr("r", 4)
198 .attr("stroke", "#F3F5F6")
199 .attr("fill", "#1D293F")
200 .attr("stroke-width", 2)
201 .style("opacity", 0);
202 function onMouseMove() {
203 const mousePosition = d3.mouse(this);
204 const hoveredDate = xScale.invert(mousePosition[0]);
205
206 const getDistanceFromHoveredDate = (d) =>
207 Math.abs(xAccessor(d) - hoveredDate);
208 const closestIndex = d3.scan(
209 dataset,
210 (a, b) =>
211 getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b)
212 );
213 const closestDataPoint = dataset[closestIndex];
214
215 const closestXValue = xAccessor(closestDataPoint);
216 const closestAttacksValue = attacksAccessor(closestDataPoint);
217 const closestBlockedValue = blockedAccessor(closestDataPoint);
218
219 const x = xScale(closestXValue) + dimensions.margin.left + 8;
220 const yAttacks =
221 yScale(closestAttacksValue) + dimensions.margin.top + 10;
222 const yBlocked =
223 yScale(closestBlockedValue) + dimensions.margin.top + 10;
224
225 tooltipAttacks.style(
226 "transform",
227 `translate(` +
228 `calc( -50% + ${x}px),` +
229 `calc(-100% + ${yAttacks}px)` +
230 `)`
231 );
232 tooltipBlocked.style(
233 "transform",
234 `translate(` +
235 `calc( -50% + ${x}px),` +
236 `calc(-100% + ${yBlocked}px)` +
237 `)`
238 );
239
240 tooltipAttacks.style("opacity", 1);
241 tooltipBlocked.style("opacity", 1);
242
243 tooltipAttacks.select("#countAttacks").html(closestAttacksValue);
244 tooltipBlocked.select("#countBlocked").html(closestBlockedValue);
245 tooltipCircle1
246 .attr("cx", xScale(closestXValue))
247 .attr("cy", yScale(closestAttacksValue))
248 .style("opacity", 1);
249 tooltipCircle2
250 .attr("cx", xScale(closestXValue))
251 .attr("cy", yScale(closestBlockedValue))
252 .style("opacity", 1);
253 }
254
255 function onMouseLeave() {
256 tooltipAttacks.style("opacity", 0);
257 tooltipBlocked.style("opacity", 0);
258
259 tooltipCircle1.style("opacity", 0);
260 tooltipCircle2.style("opacity", 0);
261 }
262 }
263
264 const drawWafChart = (data) => {
265 var firewallChart = d3.select("#line-chart").selectAll("svg")
266 firewallChart = firewallChart.remove();
267 drawLineChart(data);
268 };
269
270 if(typeof waf_chart == "object"){
271 drawWafChart(waf_chart);
272 }
273
274 var resizeTimerFirewallChart;
275 window.onresize = function (event) {
276 clearTimeout(resizeTimerFirewallChart);
277 resizeTimerFirewallChart = setTimeout(function () {
278 drawLineChart(waf_chart);
279 }, 10);
280 };
281
282 // server-status
283 async function drawServerStatusChart(id, elementSelector, tooltipSelector, tooltipValueSelector, color, dataset) {
284 const dataAccessor = (d) => d.value;
285
286 let diagram = document.querySelector(elementSelector);
287 let days = diagram.dataset.days;
288
289 const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d");
290
291 const xAccessor = (d) => dateParser(d.date);
292
293 const chartWrapper = document.querySelector(elementSelector);
294 let dimensions = {
295 width: chartWrapper.offsetWidth,
296 height: 251,
297 margin: {
298 top: 15,
299 right: 15,
300 bottom: 40,
301 left: 60,
302 },
303 };
304 dimensions.boundedWidth =
305 dimensions.width - dimensions.margin.left - dimensions.margin.right;
306 dimensions.boundedHeight =
307 dimensions.height - dimensions.margin.top - dimensions.margin.bottom;
308
309 const wrapper = d3
310 .select(elementSelector)
311 .append("svg")
312 .attr("width", dimensions.width)
313 .attr("height", dimensions.height);
314
315 const bounds = wrapper
316 .append("g")
317 .style(
318 "transform",
319 `translate(${dimensions.margin.left - 10}px, ${
320 dimensions.margin.top
321 }px)`
322 );
323
324 const yScale = d3
325 .scaleLinear()
326 .domain(d3.extent(dataset, dataAccessor))
327 .range([dimensions.boundedHeight, 0]);
328 const xScale = d3
329 .scaleTime()
330 .domain(d3.extent(dataset, xAccessor))
331 .range([0, dimensions.boundedWidth]);
332
333 function make_y_gridlines() {
334 return d3.axisLeft(yScale).ticks(5);
335 }
336
337 bounds
338 .append("g")
339 .attr("class", "grid")
340 .call(
341 make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("")
342 );
343
344 const area1 = d3
345 .area()
346 .x((d) => xScale(xAccessor(d)))
347 .y0(dimensions.height)
348 .y1((d) => yScale(dataAccessor(d)));
349
350 const gradientAreaId = "area-gradient-" + id;
351
352 const isDarkTheme = isDarkThemeSet();
353 const minOpacity = isDarkTheme ? 0.2 : 0.1;
354 const maxOpacity = isDarkTheme ? 0.8 : 0.6;
355
356 bounds
357 .append("linearGradient")
358 .attr("id", gradientAreaId)
359 .attr("gradientUnits", "userSpaceOnUse")
360 .attr("x1", 0)
361 .attr("y1", yScale(0))
362 .attr("x2", 0)
363 .attr("y2", yScale(100))
364 .selectAll("stop")
365 .data([
366 { offset: "0%", color: color, opacity: minOpacity },
367 { offset: "100%", color: color, opacity: maxOpacity },
368 ])
369 .enter()
370 .append("stop")
371 .attr("offset", function (d) {
372 return d.offset;
373 })
374 .attr("stop-color", function (d) {
375 return d.color;
376 })
377 .attr("stop-opacity", function (d) {
378 return d.opacity;
379 });
380
381 const lineGenerator1 = d3
382 .line()
383 .x((d) => xScale(xAccessor(d)))
384 .y((d) => yScale(dataAccessor(d)));
385
386 const line1 = bounds
387 .append("path")
388 .datum(dataset)
389 .attr("d", lineGenerator1(dataset))
390 .attr("class", "area")
391 .attr("d", area1)
392 .style("fill", "url(#"+gradientAreaId+")");
393
394 const yAxisGenerator = d3.axisLeft().scale(yScale);
395 // const xAxisGenerator = d3.axisBottom().scale(xScale);
396 let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d");
397 const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) :
398 (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) :
399 (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) :
400 d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat);
401
402 const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator);
403 const xAxis = bounds
404 .append("g")
405 .call(xAxisGenerator)
406 .attr("class", "axis")
407 .style("transform", `translateY(${dimensions.boundedHeight}px)`);
408
409 const listeningRect = bounds
410 .append("rect")
411 .attr("class", "listening-rect")
412 .attr("width", dimensions.boundedWidth)
413 .attr("height", dimensions.boundedHeight)
414 .on("mousemove", onMouseMove)
415 .on("mouseleave", onMouseLeave);
416
417 const tooltipData = d3.select(tooltipSelector);
418 const tooltipCircle1 = bounds
419 .append("circle")
420 .attr("class", "tooltip-circle")
421 .attr("r", 4)
422 .attr("stroke", "#F3F5F6")
423 .attr("fill", "#1D293F")
424 .attr("stroke-width", 2)
425 .style("opacity", 0);
426
427 function onMouseMove() {
428 const mousePosition = d3.mouse(this);
429 const hoveredDate = xScale.invert(mousePosition[0]);
430
431 const getDistanceFromHoveredDate = (d) =>
432 Math.abs(xAccessor(d) - hoveredDate);
433 const closestIndex = d3.scan(
434 dataset,
435 (a, b) =>
436 getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b)
437 );
438 const closestDataPoint = dataset[closestIndex];
439
440 const closestXValue = xAccessor(closestDataPoint);
441 const closestValue = dataAccessor(closestDataPoint);
442
443 const x = xScale(closestXValue) + dimensions.margin.left + 8;
444 const yAttacks =
445 yScale(closestValue) + dimensions.margin.top + 10;
446
447 tooltipData.style(
448 "transform",
449 `translate(` +
450 `calc( -50% + ${x}px),` +
451 `calc(-100% + ${yAttacks}px)` +
452 `)`
453 );
454
455 tooltipData.style("opacity", 1);
456
457 tooltipData.select(tooltipValueSelector).html(closestValue);
458 tooltipCircle1
459 .attr("cx", xScale(closestXValue))
460 .attr("cy", yScale(closestValue))
461 .style("opacity", 1);
462 }
463
464 function onMouseLeave() {
465 tooltipData.style("opacity", 0);
466 tooltipCircle1.style("opacity", 0);
467 }
468 }
469
470 const drawRamChart = (data) => {
471 const ramChartSelector = "#ram-chart";
472 const ramTooltipSelector = "#tooltipRam";
473 const ramTooltipValueSelector = "#countRam";
474 const ramChartColor = "#3d50df";
475
476
477 let chartRam = d3.select(ramChartSelector).selectAll("svg")
478 chartRam = chartRam.remove();
479
480 drawServerStatusChart("ram", ramChartSelector, ramTooltipSelector, ramTooltipValueSelector, ramChartColor, data);
481 }
482
483
484 if(typeof serverStatusRam == "object"){
485 drawRamChart(serverStatusRam);
486 }
487
488
489 const drawCpuChart = (data) => {
490 const cpuChartSelector = "#cpu-chart";
491 const cpuTooltipSelector = "#tooltipCpu";
492 const cpuTooltipValueSelector = "#countCpu";
493 const cpuChartColor = "#6d3594";
494
495 let chartCpu = d3.select(cpuChartSelector).selectAll("svg");
496 chartCpu = chartCpu.remove();
497
498 drawServerStatusChart("cpu", cpuChartSelector, cpuTooltipSelector, cpuTooltipValueSelector, cpuChartColor, data);
499 }
500
501 if(typeof serverStatusCpu == "object") {
502 drawCpuChart(serverStatusCpu);
503 }
504
505
506 var resizeTimerRamChart;
507 var resizeTimerCpuChart;
508
509 window.onresize = function (event) {
510
511 if (document.querySelector("#ram-chart") !== null) {
512 clearTimeout(resizeTimerRamChart);
513 resizeTimerRamChart = setTimeout(function () {
514 if(typeof serverStatusRam == "object") {
515 drawRamChart(serverStatusRam);
516 }
517 }, 10);
518 }
519
520 if (document.querySelector("#cpu-chart") !== null) {
521 clearTimeout(resizeTimerCpuChart);
522 resizeTimerCpuChart = setTimeout(function () {
523 if(typeof serverStatusCpu == "object") {
524 drawCpuChart(serverStatusCpu);
525 }
526 }, 10);
527 }
528 };
529
530
531 const colorModeToggle = document.querySelector("#color_scheme_toggle");
532 if(colorModeToggle){
533 const addThemeChangeEventListener = (callback)=>{
534 colorModeToggle.addEventListener("change", callback)
535 }
536
537 addThemeChangeEventListener(()=>{
538 if(typeof serverStatusCpu == "object") {
539 drawCpuChart(serverStatusCpu);
540 }
541 if(typeof serverStatusRam == "object") {
542 drawRamChart(serverStatusRam);
543 }
544 });
545 }
546
547 // disk-chart
548
549 async function drawDiskChart_(elementSelector, data) {
550 // set the dimensions and margins of the graph
551 var width = 150
552 height = 150
553 margin = 1
554
555 // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin.
556 var radius = Math.min(width, height) / 2 - margin
557
558 // append the svg object to the div called 'my_dataviz'
559 var svg = d3.select(elementSelector)
560 .append("svg")
561 .attr("width", width)
562 .attr("height", height)
563 .append("g")
564 .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
565
566 // Create dummy data
567 // var data = {a: 9, b: 20, c:30, d:8, e:12}
568
569 // set the color scale
570 var color = d3.scaleOrdinal()
571 .domain(data)
572 .range(["#5E6977", "#3D50DF"])
573
574 // Compute the position of each group on the pie:
575 var pie = d3.pie()
576 .value(function(d) {return d.value; })
577 var data_ready = pie(d3.entries(data))
578
579 // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function.
580 svg
581 .selectAll('whatever')
582 .data(data_ready)
583 .enter()
584 .append('path')
585 .attr('d', d3.arc()
586 .innerRadius(30) // This is the size of the donut hole
587 .outerRadius(radius)
588 )
589 .attr('fill', function(d){ return(color(d.data.key)) })
590 .attr("stroke", "white")
591 .style("stroke-width", "15px")
592 .style("opacity", 1)
593
594 }
595
596
597 const drawDiskChart = (data) => {
598 const diskData = {use: data['use'], free: data['free']};
599 const discChartSelector = "#disk-chart";
600 drawDiskChart_(discChartSelector, diskData);
601 };
602
603 if(typeof serverStatusDiscUsage == "object") {
604 drawDiskChart(serverStatusDiscUsage);
605 }
606
607
608