How to Add a Scrollbar to a Large Org Chart Created with react-d3-tree

121 Views Asked by At

I'm using the react-d3-tree library to create an organizational chart (org chart) in my React application. The org chart works great for smaller datasets, but as the organization grows larger, I'm faced with the challenge of enabling scrolling to view the entire org chart.

I've already integrated the library, and my org chart is rendering correctly. However, when the chart becomes too large to fit within the viewport, it gets cut off, and I can drag the whole org chart and view it but it's inconvenience.

I'd like to add a scrollbar to the org chart or the containing element so that users can scroll vertically or horizontally to explore the entire org chart, especially when it becomes larger.

This is the orgchart.tsx file,

import React, { useRef, useState } from "react";
import { Tree, RawNodeDatum } from "react-d3-tree";
import OrgData from "./orgData";
import {
  TreeData,
  updateStateMessage,
} from "../../../slices/treeSlice/treeData";
import { useSelector } from "react-redux";
import {Box, Button} from "@mui/material";
import { useAppSelector } from "../../../slices/store";

const OrgChart = ({}) => {
  const nodeSize = { x: 400, y: 120 };
  const foreignObjectProps = {
    width: 350,
    height: 300,
    x: -200,
    y: -50,
  };


  const treeData = useAppSelector((state) => state.tree);
  const [firstTreeData, setFirstTreeData] = useState<TreeData | null>(null);

  const restructureTreeData = (node: TreeData): RawNodeDatum => {
    const data: RawNodeDatum = {
      name: node.firstName,
      attributes: {
        profile_pic: node.employeeThumbnail,
        employee_name: node.firstName + " " + node.lastName,
        designation: node.jobRole,
        email: node.workEmail,
        team: node.team,
        managerEmail: node.managerEmail,
        subTeam: node.subTeam,
        businessUnit: node.businessUnit,
        location: node.location,
      },
      children: [],
    };

    if (node.children && node.children.length > 0) {
      data.children = node.children.map((childNode) =>
        restructureTreeData(childNode)
      );
    }
    return data;
  };

  const renderForeignObjectNode = ({ nodeDatum, foreignObjectProps }: any) => {
    return (
      <g>
        <circle r={12}></circle>
        {/* Node data */}
        <foreignObject {...foreignObjectProps}>
          <OrgData
            profile_pic={nodeDatum.attributes.profile_pic}
            name={nodeDatum.attributes.employee_name}
            designation={nodeDatum.attributes.designation}
            email={nodeDatum.attributes.email}
            subTeam={nodeDatum.attributes.subTeam}
            businessUnit={nodeDatum.attributes.businessUnit}
            location={nodeDatum.attributes.location}
            team={nodeDatum.attributes.team}
            department={nodeDatum.attributes.department}
            zoomLevel= {0.3}
            selectedEmployee={firstTreeData?.workEmail}
          />
        </foreignObject>
      </g>
    );
  };

  const treeConfig = {
    pathFunc: "step",
    translate: { x: 100, y: window.innerHeight/2},
    transitionDuration: 1000,
    separation: { siblings: 1, nonSiblings: 1 }
  };
  const transformedTreeData: RawNodeDatum = restructureTreeData(treeData);
  const printableRef = useRef(null);

  return (
    <div>
      <Box style={{ height: '100vh'}} ref={printableRef}>
            <Tree
              data={transformedTreeData}
              orientation= "horizontal"
              translate={treeConfig.translate}
              nodeSize={nodeSize}
              separation={treeConfig.separation}
              pathFunc="step"
              scaleExtent={{ max: 1.0, min: 0.1 }}
              zoomable={false}
              zoom={0.45}
              transitionDuration={treeConfig.transitionDuration}
              enableLegacyTransitions={true}
              renderCustomNodeElement={(rd3tProps) =>
                renderForeignObjectNode({ ...rd3tProps, foreignObjectProps })
              }
            />
        </Box>
    </div>
  );
};

export default OrgChart;
1

There are 1 best solutions below

1
vvv On

Feel like you can add smth like this in the box component

sx={{ maxWidth: '100%', // Set your desired maximum width overflowX: 'auto', // Add horizontal scrollbar when content exceeds max-width }}