async function drawLineChart(dataset) { var diagram = document.getElementById('wtotem_chart_diagram'); var days = diagram.dataset.days; const attacksAccessor = (d) => d.attacks; const blockedAccessor = (d) => d.blocked; const biggerAccessor = (d) => d.attacks > d.blocked ? d.attacks : d.blocked; const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d"); const xAccessor = (d) => dateParser(d.date); const chartWrapper = document.getElementById('line-chart') let dimensions = { width: chartWrapper.offsetWidth, height: 251, margin: { top: 15, right: 15, bottom: 40, left: 60, }, }; dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right; dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom; const wrapper = d3 .select("#line-chart") .append("svg") .attr("width", dimensions.width) .attr("height", dimensions.height); const bounds = wrapper .append("g") .style( "transform", `translate(${dimensions.margin.left - 10}px, ${ dimensions.margin.top }px)` ); const yScale = d3 .scaleLinear() .domain(d3.extent(dataset, biggerAccessor)) .range([dimensions.boundedHeight, 0]); const xScale = d3 .scaleTime() .domain(d3.extent(dataset, xAccessor)) .range([0, dimensions.boundedWidth]); function make_y_gridlines() { return d3.axisLeft(yScale).ticks(5); } bounds .append("g") .attr("class", "grid") .call( make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("") ); const area1 = d3 .area() .x((d) => xScale(xAccessor(d))) .y0(dimensions.height) .y1((d) => yScale(attacksAccessor(d))); const area2 = d3 .area() .x((d) => xScale(xAccessor(d))) .y0(dimensions.height) .y1((d) => yScale(blockedAccessor(d))); bounds .append("linearGradient") .attr("id", "area-gradient1") .attr("gradientUnits", "userSpaceOnUse") .attr("x1", 0) .attr("y1", yScale(0)) .attr("x2", 0) .attr("y2", yScale(100)) .selectAll("stop") .data([ { offset: "0%", color: "#d46c6a", opacity: 0.04 }, { offset: "100%", color: "#d46c6a", opacity: 1 }, ]) .enter() .append("stop") .attr("offset", function (d) { return d.offset; }) .attr("stop-color", function (d) { return d.color; }) .attr("stop-opacity", function (d) { return d.opacity; }); bounds .append("linearGradient") .attr("id", "area-gradient2") .attr("gradientUnits", "userSpaceOnUse") .attr("x1", 0) .attr("y1", yScale(0)) .attr("x2", 0) .attr("y2", yScale(100)) .selectAll("stop") .data([ { offset: "0%", color: "#bace3d", opacity: 0.02 }, { offset: "100%", color: "#bace3d", opacity: 1 }, ]) .enter() .append("stop") .attr("offset", function (d) { return d.offset; }) .attr("stop-color", function (d) { return d.color; }) .attr("stop-opacity", function (d) { return d.opacity; }); const lineGenerator1 = d3 .line() .x((d) => xScale(xAccessor(d))) .y((d) => yScale(attacksAccessor(d))); const lineGenerator2 = d3 .line() .x((d) => xScale(xAccessor(d))) .y((d) => yScale(attacksAccessor(d))); const line1 = bounds .append("path") .datum(dataset) .attr("d", lineGenerator1(dataset)) .attr("class", "area") .attr("d", area1) .style("fill", "url(#area-gradient1)"); const line2 = bounds .append("path") .datum(dataset) .attr("d", lineGenerator2(dataset)) .attr("class", "area") .attr("d", area2) .style("fill", "url(#area-gradient2)"); const yAxisGenerator = d3.axisLeft().scale(yScale); // const xAxisGenerator = d3.axisBottom().scale(xScale); let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d"); const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) : (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) : (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) : d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat); //const xAxisGenerator = d3.axisBottom().scale(xScale).ticks(ticks).tickFormat(dateFormat); const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator); const xAxis = bounds .append("g") .call(xAxisGenerator) .attr("class", "axis chart-date") .style("transform", `translateY(${dimensions.boundedHeight}px)`); const listeningRect = bounds .append("rect") .attr("class", "listening-rect") .attr("width", dimensions.boundedWidth) .attr("height", dimensions.boundedHeight) .on("mousemove", onMouseMove) .on("mouseleave", onMouseLeave); const tooltipAttacks = d3.select("#tooltipAttacks"); const tooltipBlocked = d3.select("#tooltipBlocked"); const tooltipCircle1 = bounds .append("circle") .attr("class", "tooltip-circle") .attr("r", 4) .attr("stroke", "#F3F5F6") .attr("fill", "#1D293F") .attr("stroke-width", 2) .style("opacity", 0); const tooltipCircle2 = bounds .append("circle") .attr("class", "tooltip-circle") .attr("r", 4) .attr("stroke", "#F3F5F6") .attr("fill", "#1D293F") .attr("stroke-width", 2) .style("opacity", 0); function onMouseMove() { const mousePosition = d3.mouse(this); const hoveredDate = xScale.invert(mousePosition[0]); const getDistanceFromHoveredDate = (d) => Math.abs(xAccessor(d) - hoveredDate); const closestIndex = d3.scan( dataset, (a, b) => getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b) ); const closestDataPoint = dataset[closestIndex]; const closestXValue = xAccessor(closestDataPoint); const closestAttacksValue = attacksAccessor(closestDataPoint); const closestBlockedValue = blockedAccessor(closestDataPoint); const x = xScale(closestXValue) + dimensions.margin.left + 8; const yAttacks = yScale(closestAttacksValue) + dimensions.margin.top + 10; const yBlocked = yScale(closestBlockedValue) + dimensions.margin.top + 10; tooltipAttacks.style( "transform", `translate(` + `calc( -50% + ${x}px),` + `calc(-100% + ${yAttacks}px)` + `)` ); tooltipBlocked.style( "transform", `translate(` + `calc( -50% + ${x}px),` + `calc(-100% + ${yBlocked}px)` + `)` ); tooltipAttacks.style("opacity", 1); tooltipBlocked.style("opacity", 1); tooltipAttacks.select("#countAttacks").html(closestAttacksValue); tooltipBlocked.select("#countBlocked").html(closestBlockedValue); tooltipCircle1 .attr("cx", xScale(closestXValue)) .attr("cy", yScale(closestAttacksValue)) .style("opacity", 1); tooltipCircle2 .attr("cx", xScale(closestXValue)) .attr("cy", yScale(closestBlockedValue)) .style("opacity", 1); } function onMouseLeave() { tooltipAttacks.style("opacity", 0); tooltipBlocked.style("opacity", 0); tooltipCircle1.style("opacity", 0); tooltipCircle2.style("opacity", 0); } } const drawWafChart = (data) => { drawLineChart(data); }; if(typeof waf_chart == "object"){ drawWafChart(waf_chart); } var resizeTimerFirewallChart; window.onresize = function (event) { clearTimeout(resizeTimerFirewallChart); resizeTimerFirewallChart = setTimeout(function () { var s = d3.select("#line-chart").selectAll("svg") s = s.remove(); drawLineChart(waf_chart); }, 10); }; // server-status async function drawServerStatusChart(id, elementSelector, tooltipSelector, tooltipValueSelector, color, dataset) { const dataAccessor = (d) => d.value; let diagram = document.querySelector(elementSelector); let days = diagram.dataset.days; const dateParser = (days <= 1) ? d3.timeParse("%Y-%m-%d %H:%m:%M"): d3.timeParse("%Y-%m-%d"); const xAccessor = (d) => dateParser(d.date); const chartWrapper = document.querySelector(elementSelector); let dimensions = { width: chartWrapper.offsetWidth, height: 251, margin: { top: 15, right: 15, bottom: 40, left: 60, }, }; dimensions.boundedWidth = dimensions.width - dimensions.margin.left - dimensions.margin.right; dimensions.boundedHeight = dimensions.height - dimensions.margin.top - dimensions.margin.bottom; const wrapper = d3 .select(elementSelector) .append("svg") .attr("width", dimensions.width) .attr("height", dimensions.height); const bounds = wrapper .append("g") .style( "transform", `translate(${dimensions.margin.left - 10}px, ${ dimensions.margin.top }px)` ); const yScale = d3 .scaleLinear() .domain(d3.extent(dataset, dataAccessor)) .range([dimensions.boundedHeight, 0]); const xScale = d3 .scaleTime() .domain(d3.extent(dataset, xAccessor)) .range([0, dimensions.boundedWidth]); function make_y_gridlines() { return d3.axisLeft(yScale).ticks(5); } bounds .append("g") .attr("class", "grid") .call( make_y_gridlines().tickSize(-dimensions.boundedWidth).tickFormat("") ); const area1 = d3 .area() .x((d) => xScale(xAccessor(d))) .y0(dimensions.height) .y1((d) => yScale(dataAccessor(d))); const gradientAreaId = "area-gradient-" + id; bounds .append("linearGradient") .attr("id", gradientAreaId) .attr("gradientUnits", "userSpaceOnUse") .attr("x1", 0) .attr("y1", yScale(0)) .attr("x2", 0) .attr("y2", yScale(100)) .selectAll("stop") .data([ { offset: "0%", color: color, opacity: 0 }, { offset: "100%", color: color, opacity: 0.6 }, ]) .enter() .append("stop") .attr("offset", function (d) { return d.offset; }) .attr("stop-color", function (d) { return d.color; }) .attr("stop-opacity", function (d) { return d.opacity; }); const lineGenerator1 = d3 .line() .x((d) => xScale(xAccessor(d))) .y((d) => yScale(dataAccessor(d))); const line1 = bounds .append("path") .datum(dataset) .attr("d", lineGenerator1(dataset)) .attr("class", "area") .attr("d", area1) .style("fill", "url(#"+gradientAreaId+")"); const yAxisGenerator = d3.axisLeft().scale(yScale); // const xAxisGenerator = d3.axisBottom().scale(xScale); let dateFormat = (days <= 1) ? d3.timeFormat("%H:%M") : (days > 31) ? d3.timeFormat("%b %Y") : d3.timeFormat("%b %d"); const xAxisGenerator = (days <= 1) ? d3.axisBottom().scale(xScale).ticks(d3.timeHour.every(2)).tickFormat(dateFormat) : (days > 31) ? d3.axisBottom().scale(xScale).ticks(d3.timeMonth.every(1)).tickFormat(dateFormat) : (days <= 7) ? d3.axisBottom().scale(xScale).ticks(d3.timeDay.every(1)).tickFormat(dateFormat) : d3.axisBottom().scale(xScale).ticks(9).tickFormat(dateFormat); const yAxis = bounds.append("g").attr("class", "axis").call(yAxisGenerator); const xAxis = bounds .append("g") .call(xAxisGenerator) .attr("class", "axis") .style("transform", `translateY(${dimensions.boundedHeight}px)`); const listeningRect = bounds .append("rect") .attr("class", "listening-rect") .attr("width", dimensions.boundedWidth) .attr("height", dimensions.boundedHeight) .on("mousemove", onMouseMove) .on("mouseleave", onMouseLeave); const tooltipData = d3.select(tooltipSelector); const tooltipCircle1 = bounds .append("circle") .attr("class", "tooltip-circle") .attr("r", 4) .attr("stroke", "#F3F5F6") .attr("fill", "#1D293F") .attr("stroke-width", 2) .style("opacity", 0); function onMouseMove() { const mousePosition = d3.mouse(this); const hoveredDate = xScale.invert(mousePosition[0]); const getDistanceFromHoveredDate = (d) => Math.abs(xAccessor(d) - hoveredDate); const closestIndex = d3.scan( dataset, (a, b) => getDistanceFromHoveredDate(a) - getDistanceFromHoveredDate(b) ); const closestDataPoint = dataset[closestIndex]; const closestXValue = xAccessor(closestDataPoint); const closestValue = dataAccessor(closestDataPoint); const x = xScale(closestXValue) + dimensions.margin.left + 8; const yAttacks = yScale(closestValue) + dimensions.margin.top + 10; tooltipData.style( "transform", `translate(` + `calc( -50% + ${x}px),` + `calc(-100% + ${yAttacks}px)` + `)` ); tooltipData.style("opacity", 1); tooltipData.select(tooltipValueSelector).html(closestValue); tooltipCircle1 .attr("cx", xScale(closestXValue)) .attr("cy", yScale(closestValue)) .style("opacity", 1); } function onMouseLeave() { tooltipData.style("opacity", 0); tooltipCircle1.style("opacity", 0); } } const ramChartSelector = "#ram-chart"; const drawRamChart = (data) => { const ramTooltipSelector = "#tooltipRam"; const ramTooltipValueSelector = "#countRam"; const ramChartColor = "#3d50df"; drawServerStatusChart("ram", ramChartSelector, ramTooltipSelector, ramTooltipValueSelector, ramChartColor, data); } if(typeof serverStatusRam == "object"){ drawRamChart(serverStatusRam); } const cpuChartSelector = "#cpu-chart"; const drawCpuChart = (data) => { const cpuTooltipSelector = "#tooltipCpu"; const cpuTooltipValueSelector = "#countCpu"; const cpuChartColor = "#6d3594"; drawServerStatusChart("cpu", cpuChartSelector, cpuTooltipSelector, cpuTooltipValueSelector, cpuChartColor, data); } if(typeof serverStatusCpu == "object") { drawCpuChart(serverStatusCpu); } var resizeTimerRamChart; var resizeTimerCpuChart; window.onresize = function (event) { if (document.querySelector("#ram-chart") !== null) { clearTimeout(resizeTimerRamChart); resizeTimerRamChart = setTimeout(function () { var s1 = d3.select("#ram-chart").selectAll("svg") s1 = s1.remove(); drawRamChart(serverStatusRam); }, 10); }; if (document.querySelector("#cpu-chart") !== null) { clearTimeout(resizeTimerCpuChart); resizeTimerCpuChart = setTimeout(function () { var s2 = d3.select("#cpu-chart").selectAll("svg") s2 = s2.remove(); drawCpuChart(serverStatusCpu); }, 10); }; } // disk-chart async function drawDiskChart_(elementSelector, data) { // set the dimensions and margins of the graph var width = 150 height = 150 margin = 1 // The radius of the pieplot is half the width or half the height (smallest one). I subtract a bit of margin. var radius = Math.min(width, height) / 2 - margin // append the svg object to the div called 'my_dataviz' var svg = d3.select(elementSelector) .append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); // Create dummy data // var data = {a: 9, b: 20, c:30, d:8, e:12} // set the color scale var color = d3.scaleOrdinal() .domain(data) .range(["#5E6977", "#3D50DF"]) // Compute the position of each group on the pie: var pie = d3.pie() .value(function(d) {return d.value; }) var data_ready = pie(d3.entries(data)) // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function. svg .selectAll('whatever') .data(data_ready) .enter() .append('path') .attr('d', d3.arc() .innerRadius(30) // This is the size of the donut hole .outerRadius(radius) ) .attr('fill', function(d){ return(color(d.data.key)) }) .attr("stroke", "white") .style("stroke-width", "15px") .style("opacity", 1) } const drawDiskChart = (data) => { const diskData = {use: data['use'], free: data['free']}; const discChartSelector = "#disk-chart"; drawDiskChart_(discChartSelector, diskData); }; if(typeof serverStatusDiscUsage == "object") { drawDiskChart(serverStatusDiscUsage); }