Skip to content

d3 #151

@dlrandy

Description

@dlrandy
<!DOCTYPE html>
<html>
  <head>
    <title>Org Chart with D3.js Hierarchy</title>
    <style>
      .node circle {
        fill: #fff;
        stroke: steelblue;
        stroke-width: 1.5px;
      }

      .node text {
        font: 12px sans-serif;
      }

      .link {
        fill: none;
        stroke: #ccc;
        stroke-width: 1.5px;
      }

      .sibling-link {
        stroke: #999;
        stroke-width: 1px;
        stroke-dasharray: 5, 5;
        marker-end: url(#arrow); /* Add arrow marker */
      }
    </style>
  </head>
  <body>
    <svg width="960" height="500">
      <defs>
        <marker
          id="arrow"
          markerWidth="10"
          markerHeight="10"
          refX="9"
          refY="3"
          orient="auto"
        >
          <path d="M0,0 L0,6 L9,3 z" fill="#999" />
        </marker>
      </defs>
    </svg>

    <script src="https://d3js.org/d3.v6.min.js"></script>
    <script>
      const data = {
        name: "CEO",
        children: [
          {
            name: "CFO",
            children: [
              {
                name: "Accounting Manager",
                linkCondition: true
              },
              {
                name: "Finance Manager",
                linkCondition: false
              }
            ]
          },
          {
            name: "CTO",
            children: [
              {
                name: "Engineering Manager",
                linkCondition: true
              },
              {
                name: "Software Architect",
                linkCondition: true
              },
              {
                name: "Frontend Developer",
                linkCondition: false
              },
              {
                name: "Backend Developer",
                linkCondition: true
              }
            ]
          },
          {
            name: "COO",
            children: [
              {
                name: "Operations Manager",
                linkCondition: true
              },
              {
                name: "HR Manager",
                linkCondition: true
              },
              {
                name: "Sales Manager",
                linkCondition: true
              }
            ]
          }
        ]
      };

      const svg = d3.select("svg");
      const width = +svg.attr("width");
      const height = +svg.attr("height");
      const g = svg.append("g").attr("transform", "translate(40,0)");

      const tree = d3.tree().size([height, width - 160]);
      const root = d3.hierarchy(data);

      tree(root);

      const link = g
        .selectAll(".link")
        .data(root.links())
        .enter()
        .append("path")
        .attr("class", "link")
        .attr(
          "d",
          d3
            .linkHorizontal()
            .x((d) => d.y)
            .y((d) => d.x)
        );

      // Add conditional sibling links
      root.each((node) => {
        if (node.parent) {
          const siblings = node.parent.children;
          const currentNodeIndex = siblings.findIndex((d) => d === node);
          for (let i = currentNodeIndex + 1; i < siblings.length; i++) {
            const currentSibling = siblings[i];
            if (shouldLinkSiblings(node.data, currentSibling.data)) {
              g.append("path")
                .attr("class", "sibling-link")
                .attr("d", () => {
                  return `M${node.y},${node.x}L${currentSibling.y},${currentSibling.x}`;
                });
            }
          }
        }
      });

      function shouldLinkSiblings(nodeData, siblingData) {
        return nodeData.linkCondition && siblingData.linkCondition;
      }

      const node = g
        .selectAll(".node")
        .data(root.descendants())
        .enter()
        .append("g")
        .attr("class", "node")
        .attr("transform", (d) => `translate(${d.y},${d.x})`);

      node.append("circle").attr("r", 5);

      node
        .append("text")
        .attr("dy", "0.31em")
        .attr("x", (d) => (d.children ? -6 : 6))
        .attr("text-anchor", (d) => (d.children ? "end" : "start"))
        .text((d) => d.data.name);
    </script>
  </body>
</html>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions