canvas22 = {
const width = 1000;
const height = 800;
const margin = { top: 40, right: 80, bottom: 100, left: 150 };
const context = DOM.context2d(width, height);
context.fillStyle = "hsl(216deg 100% 13%)";
context.fillRect(0, 0, width, height);
const uniqueBrowsers = [...new Set(data.map(d => d.browser_type))];
const colorScale = d3.scaleOrdinal()
.domain(uniqueBrowsers)
.range(d3.schemeCategory10);
const xScale = d3.scaleLinear()
.domain([0, Math.max(...data.map(d => d.network_packet_size))])
.range([margin.left, width - margin.right]);
const yScale = d3.scaleLinear()
.domain([0, 100])
.range([height - margin.bottom, margin.top]);
context.beginPath();
context.strokeStyle = "white";
context.lineWidth = 1;
context.moveTo(margin.left, height - margin.bottom);
context.lineTo(width - margin.right, height - margin.bottom);
context.stroke();
context.beginPath();
context.moveTo(margin.left, margin.top);
context.lineTo(margin.left, height - margin.bottom);
context.stroke();
// Add X-axis ticks and labels
const xTicks = xScale.ticks(10);
context.textAlign = "center";
context.textBaseline = "top";
context.fillStyle = "white";
context.font = "20px Verdana";
xTicks.forEach(tick => {
const x = xScale(tick);
context.beginPath();
context.moveTo(x, height - margin.bottom);
context.lineTo(x, height - margin.bottom + 5);
context.stroke();
context.fillText(tick, x, height - margin.bottom + 10);
});
// Add Y-axis ticks and labels with percentage
const yTicks = yScale.ticks(10);
context.textAlign = "right";
context.textBaseline = "middle";
yTicks.forEach(tick => {
const y = yScale(tick);
context.beginPath();
context.moveTo(margin.left - 5, y);
context.lineTo(margin.left, y);
context.stroke();
context.fillText(`${tick}%`, margin.left - 10, y);
});
// Add axis labels
context.save();
context.fillStyle = "white";
context.font = "18px Verdana";
// X-axis label
context.textAlign = "center";
context.fillText("Network Packet Size", width/2, height - 30);
// Y-axis label
context.save();
context.translate(45, height/2);
context.rotate(-Math.PI/2);
context.textAlign = "center";
context.fillText("Chance of IP maliciousness (%)", 0, 0);
context.restore();
// Transform canvas for data points
context.save();
context.translate(0, height);
context.scale(1, -1);
// Process and draw data points
data.forEach(point => {
// X coordinate calculation
const x = xScale(point.network_packet_size);
// Calculate trust score as percentage (normalized to 0-100 range)
const trustScore = (point.ip_reputation_score * 100); // Convert to percentage
const y = height - yScale(trustScore);
const baseColor = d3.color(colorScale(point.browser_type));
// Only draw if the browser is selected
if (browser_selection.includes(point.browser_type)) {
if (point.attack_detected == "1") {
// Draw X with attack toggle control
baseColor.opacity = (toggle_attacked === "Show Malicious" || toggle_attacked === "Show Both") ? 0.8 : 0;
context.strokeStyle = baseColor;
context.lineWidth = use_dynamic_width.includes("Dynamic") ? point.session_duration/100 : 2;
const size = 5;
context.beginPath();
context.moveTo(x - size, y - size);
context.lineTo(x + size, y + size);
context.stroke();
context.beginPath();
context.moveTo(x + size, y - size);
context.lineTo(x - size, y + size);
context.stroke();
} else {
// Draw circle with attack toggle control
baseColor.opacity = (toggle_attacked === "Show Normal" || toggle_attacked === "Show Both") ? 0.8 : 0;
context.strokeStyle = baseColor;
context.lineWidth = use_dynamic_width.includes("Dynamic") ? point.session_duration/100 : 2;
context.beginPath();
context.arc(x, y, 5, 0, Math.PI * 2);
context.stroke();
}
}
});
context.restore();
return context.canvas;
}