JSFiddle - React, Tailwind, and code Playground

by novillo

HTML

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Grafo interactivo</title>
  <script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
  <svg></svg>

</body>
</html>

CSS

body {
      margin: 0;
      background: #0f172a;
      font-family: Arial, sans-serif;
      overflow: hidden;
    }

    svg {
      display: block;
      width: 100vw;
      height: 100vh;
    }

    .link {
      stroke: rgba(255,255,255,0.25);
      stroke-width: 2;
    }

    .node {
      fill: #ff8300;
      stroke: #fff;
      stroke-width: 2;
      cursor: grab;
      transition: r 0.15s ease, fill 0.15s ease;
    }

    .node.dragging {
      fill: #ffd166;
      cursor: grabbing;
    }

    .label {
      fill: white;
      font-size: 12px;
      text-anchor: middle;
      pointer-events: none;
    }

JavaScript

const width = window.innerWidth;
    const height = window.innerHeight;

    const nodes = [
      { id: "A" },
      { id: "B" },
      { id: "C" },
      { id: "D" },
      { id: "E" },
      { id: "F" }
    ];

    const links = [
      { source: "A", target: "B" },
      { source: "A", target: "C" },
      { source: "B", target: "D" },
      { source: "C", target: "D" },
      { source: "C", target: "E" },
      { source: "D", target: "F" }
    ];

    const svg = d3.select("svg")
      .attr("viewBox", [0, 0, width, height]);

    const link = svg.append("g")
      .selectAll("line")
      .data(links)
      .join("line")
      .attr("class", "link");

    const node = svg.append("g")
      .selectAll("circle")
      .data(nodes)
      .join("circle")
      .attr("class", "node")
      .attr("r", 18);

    const label = svg.append("g")
      .selectAll("text")
      .data(nodes)
      .join("text")
      .attr("class", "label")
      .text(d => d.id);

    const simulation = d3.forceSimulation(nodes)
      .force("link", d3.forceLink(links).id(d => d.id).distance(120).strength(0.8))
      .force("charge", d3.forceManyBody().strength(-450))
      .force("center", d3.forceCenter(width / 2, height / 2))
      .force("collision", d3.forceCollide().radius(35));

    simulation.on("tick", () => {
      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);

      node
        .attr("cx", d => d.x)
        .attr("cy", d => d.y);

      label
        .attr("x", d => d.x)
        .attr("y", d => d.y + 4);
    });

    const drag = d3.drag()
      .on("start", (event, d) => {
        if (!event.active) simulation.alphaTarget(0.3).restart();
        d.fx = d.x;
        d.fy = d.y;

        d3.select(event.sourceEvent.target)
          .classed("dragging", true)
          .transition()
         ...