diff --git a/website/web/templates/vuln.html b/website/web/templates/vuln.html
index b3982c82..c3136831 100644
--- a/website/web/templates/vuln.html
+++ b/website/web/templates/vuln.html
@@ -908,16 +908,17 @@
Nomenclature
function loadSightingsCorrelations() {
- // Clear any existing graph in the container
- d3.select("#graph-container").selectAll("svg").remove();
-
- // Fetch data from API and create the graph
- fetch("{{ url_for('apiv1.sighting_sightings_list', vuln_id=vulnerability_id) }}&date_from=1970-01-01", {
- method: 'GET',
- headers: {
- 'Accept': 'application/json'
- }
- })
+ // Clear any existing graph in the container
+ d3.select("#graph-container").selectAll("svg").remove();
+ d3.select("#graph-container").selectAll(".zoom-controls").remove();
+
+ // Fetch data from API and create the graph
+ fetch("{{ url_for('apiv1.sighting_sightings_list', vuln_id=vulnerability_id) }}&date_from=1970-01-01", {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ })
.then(response => response.json())
.then(apiData => {
// Extract the central node (vulnerability ID) and sightings
@@ -941,7 +942,12 @@ Nomenclature
.select("#graph-container")
.append("svg")
.attr("width", width)
- .attr("height", height);
+ .attr("height", height)
+ .call(d3.zoom().on("zoom", (event) => {
+ svgGroup.attr("transform", event.transform);
+ }));
+
+ const svgGroup = svg.append("g");
svg.append("defs").append("marker")
.attr("id", "arrow")
@@ -961,9 +967,9 @@ Nomenclature
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2));
- const linkGroup = svg.append("g").attr("class", "links");
- const nodeGroup = svg.append("g").attr("class", "nodes");
- const labelGroup = svg.append("g").attr("class", "labels");
+ const linkGroup = svgGroup.append("g").attr("class", "links");
+ const nodeGroup = svgGroup.append("g").attr("class", "nodes");
+ const labelGroup = svgGroup.append("g").attr("class", "labels");
function updateGraph() {
// Bind data for links
@@ -1046,6 +1052,34 @@ Nomenclature
simulation.alpha(1).restart();
}
+ // Add zoom in and zoom out buttons
+ const zoom = d3.zoom().on("zoom", (event) => {
+ svgGroup.attr("transform", event.transform);
+ });
+
+ svg.call(zoom);
+
+ const zoomControls = d3.select("#graph-container")
+ .append("div")
+ .attr("class", "zoom-controls m-2")
+ .style("position", "relative")
+ .style("top", "10px")
+ .style("right", "10px");
+
+ zoomControls.append("button")
+ .attr("class", "btn btn-primary")
+ .text("+")
+ .on("click", () => {
+ svg.transition().call(zoom.scaleBy, 1.2); // Adjust the zoom behavior
+ });
+
+ zoomControls.append("button")
+ .attr("class", "btn btn-primary m-2")
+ .text("-")
+ .on("click", () => {
+ svg.transition().call(zoom.scaleBy, 0.8); // Adjust the zoom behavior
+ });
+
// Automatically fetch vulnerabilities for all group 2 nodes
const group2Nodes = nodes.filter(node => node.group === 2);
@@ -1068,6 +1102,7 @@ Nomenclature
})
.catch(error => console.error('Error fetching vulnerabilities:', error));
});
+
simulation.on("tick", () => {
linkGroup.selectAll("line")
.attr("x1", d => d.source.x)
@@ -1095,6 +1130,7 @@ Nomenclature
+
document.getElementById("btnThemeSwitch").addEventListener("click",()=>{
if (document.documentElement.getAttribute("data-bs-theme") == "dark") {
Array.from(document.getElementsByClassName("card")).forEach(container => {