text: import * as d3 from "d3";
  import "@fortawesome/fontawesome-free/css/all.min.css";
  import styles from "./forceGraph.module.css";
  import data from "../data/data.json"
  
  export function runForceGraph(container) {
    const links  = data.links;
    const nodes = data.nodes;
  
    const containerRect = container.getBoundingClientRect();
    const height = containerRect.height;
    const width = containerRect.width;
  
    // Controls how the simulation behaves when a node is dragged
    // For the meaning of alphaTarget etc see
    // https://github.com/d3/d3-force#simulation_alphaTarget
    const drag = (simulation) => {
      const dragstarted = (d) => {
        if (!d3.event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;
      };
  
      const dragged = (d) => {
        d.fx = d3.event.x;
        d.fy = d3.event.y;
      };
  
      const dragended = (d) => {
        if (!d3.event.active) simulation.alphaTarget(0);
        d.fx = null;
        d.fy = null;
      };
  
      return d3
        .drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended);
    };
  
    // Add the tooltip element to the graph
    const tooltip = document.querySelector("#graph-tooltip");
    if (!tooltip) {
      const tooltipDiv = document.createElement("div");
      tooltipDiv.classList.add(styles.tooltip);
      tooltipDiv.style.opacity = "0";
      tooltipDiv.id = "graph-tooltip";
      document.body.appendChild(tooltipDiv);
    }
    const div = d3.select("#graph-tooltip");
  
    // Function to add the tooltip over the node on mouseover
    const addTooltip = (d) => {
      div.transition().duration(200).style("opacity", 0.9);
      const html = `<div><b>${d.name}</b></div>`;
      div
        .html(html)
        .style("left", `${d3.event.pageX}px`)
        .style("top", `${d3.event.pageY - 28}px`);
    };
  
    // Function to remove the tooltip after the mouse moves
    // off the node
    const removeTooltip = () => {
      div.transition().duration(200).style("opacity", 0);
    };
  
    // This creates the d3 force simulation
    const simulation = d3
      // Pass the nodes we want it to use
      .forceSimulation(nodes)
      // This sets up the force generated by the links between the nodes
      .force(
        "link",
        d3.forceLink(links).id((d) => d.id)
      )
      // This sets up the force between the nodes themselves
      .force("charge", d3.forceManyBody().strength(-1150))
      // These forces keep the nodes towards the centre of the screen
      .force("x", d3.forceX())
      .force("y", d3.forceY());
  
    const svg = d3
      .select(container)
      .append("svg")
      .attr("viewBox", [-width / 2, -height / 2, width, height])
      .call(
        d3.zoom().on("zoom", function () {
          svg.attr("transform", d3.event.transform);
        })
      );
    
    // Setup the link style
    const link = svg
      .append("g")
      .attr("stroke", "#999")
      .attr("stroke-opacity", 0.6)
      .selectAll("line")
      .data(links)
      .join("line")
      .attr("stroke-width", (d) => Math.sqrt(d.value));
      
    // Setup the node with the side of the nodes
    // their fill colour, text style etc
    const node = svg
      .append("g")
      .attr("stroke", "#fff")
      .attr("stroke-width", 2)
      .selectAll("circle")
      .data(nodes)
      .join("circle")
      // Controls the radius of the node circles
      .attr("r", 32)
      // Set the colour of the node fill
      .attr("fill", "#457b9d")
      .call(drag(simulation));
  
    const label = svg
      .append("g")
      .attr("class", "labels")
      .selectAll("text")
      .data(nodes)
      .enter()
      .append("text")
      .attr("text-anchor", "middle")
      .attr("dominant-baseline", "central")
      .style("fill", "white")
      .style("font", "2vh serif")
      .text((d) => {
        return d.name;
      })
      .call(drag(simulation));
  
    label
      .on("mouseover", (d) => {
        addTooltip(d, d3.event.pageX, d3.event.pageY);
      })
      .on("mouseout", () => {
        removeTooltip();
      });
    
    // A tick is a single iteration of the simulation
    simulation.on("tick", () => {
      // Update link positions
      link
        .attr("x1", (d) => d.source.x)
        .attr("y1", (d) => d.source.y)
        .attr("x2", (d) => d.target.x)
        .attr("y2", (d) => d.target.y);
  
      // Update node positions
      node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
  
      // Update label positions
      label
        .attr("x", (d) => {
          return d.x;
        })
        .attr("y", (d) => {
          return d.y;
        });
    });
  
    return {
      destroy: () => {
        simulation.stop();
      },
      nodes: () => {
        return svg.node();
      },
    };
  }
  