React项目实战:用AntV G6打造可折叠组织架构图(附完整代码)
在构建现代企业级后台管理系统时,数据可视化往往是提升管理效率和决策直观性的关键一环。想象一下,当你需要向管理层清晰展示一个拥有数百个节点、层级复杂的组织架构,或者梳理一个大型项目的任务依赖关系时,静态的列表或树形控件就显得力不从心了。这时,一个支持动态交互、可自由缩放与折叠的可视化图表,不仅能清晰呈现全局结构,还能让用户通过点击探索细节,体验上有着质的飞跃。
这正是AntV G6这类专业图可视化引擎的用武之地。它并非一个简单的图表库,而是一个为复杂关系网络和层级结构量身定制的解决方案。结合React的组件化思想,我们可以将复杂的图可视化逻辑封装成清晰、可复用的业务组件,无缝集成到现有的技术栈中。本文将带你超越基础的“Hello World”示例,深入探讨如何在React项目中,利用G6实现一个功能完备、性能优良且具备良好交互体验的可折叠组织架构图。我们会从项目搭建开始,逐步深入到自定义节点、交互逻辑、状态管理以及性能优化等实战层面,并提供可直接用于生产环境的代码模块。
1. 项目环境搭建与核心依赖
在开始编码之前,确保你的开发环境已经就绪。我们假设你已有一个基于Create React App或Vite创建的React项目。如果没有,可以使用以下命令快速初始化一个:
# 使用 Vite (推荐,速度更快)
npm create vite@latest my-g6-project -- --template react
cd my-g6-project
npm install
# 或使用 Create React App
npx create-react-app my-g6-project
cd my-g6-project
接下来,安装本文所需的核心依赖。除了AntV G6本身,我们还会引入一些辅助库来提升开发体验。
npm install @antv/g6
npm install --save-dev @types/antv__g6 # 如果你使用TypeScript
注意:AntV G6的API和功能迭代较快,建议在安装前查阅其官方文档以确认最新版本和兼容性。本文示例基于G6 4.x版本。
一个清晰的项目结构有助于长期维护。建议为G6相关的组件和工具创建独立的目录:
src/
├── components/
│ ├── OrgChart/ # 组织架构图主组件
│ │ ├── index.tsx
│ │ ├── OrgChart.tsx
│ │ ├── customNode.ts # 自定义节点定义
│ │ └── types.ts # TypeScript类型定义
│ └── ...
├── hooks/ # 自定义Hook,如图表实例管理
│ └── useG6Graph.ts
├── utils/ # 数据处理工具函数
│ └── dataTransform.ts
└── App.tsx
2. 数据建模与G6图实例初始化
可视化始于数据。一个典型的组织架构数据是嵌套的树形结构。我们首先定义其TypeScript接口,并准备一份模拟数据。
1. 定义数据结构 在 types.ts 中,我们明确节点的结构:
export interface OrgNode {
id: string; // 唯一标识
label: string; // 显示名称
name?: string; // 真实姓名
title?: string; // 职位
department?: string; // 部门
avatar?: string; // 头像URL
children?: OrgNode[]; // 子节点
collapsed?: boolean; // 是否已折叠(用于内部状态管理)
}
export type OrgChartData = OrgNode;
2. 准备模拟数据 在组件内部或单独的数据文件中,构造一份具有多层嵌套的模拟数据:
const mockData: OrgNode = {
id: 'root',
label: '首席执行官 (CEO)',
name: '张伟',
title: 'CEO',
children: [
{
id: 'tech',
label: '技术部',
department: 'CTO Office',
children: [
{ id: 'fe', label: '前端组', name: '李静', title: '前端负责人' },
{
id: 'be',
label: '后端组',
name: '王强',
title: '后端架构师',
children: [
{ id: 'be-java', label: 'Java服务', name: '赵明' },
{ id: 'be-go', label: 'Go服务', name: '孙丽' }
]
},
{ id: 'qa', label: '测试组', name: '周涛', title: 'QA经理' }
]
},
{
id: 'product',
label: '产品部',
name: '陈曦',
title: '产品总监',
children: [
{ id: 'pm', label: '产品经理组', name: '吴浩' },
{ id: 'design', label: '设计组', name: '郑爽' }
]
}
// ... 更多部门
]
};
3. 初始化G6图实例 这是最核心的一步。我们在React组件的 useEffect 钩子中创建并配置G6实例。关键点在于理解各项配置的作用。
import React, { useEffect, useRef } from 'react';
import G6 from '@antv/g6';
const OrgChart = ({ data }) => {
const containerRef = useRef(null);
const graphRef = useRef(null);
useEffect(() => {
if (!containerRef.current || graphRef.current) return;
const container = containerRef.current;
const width = container.scrollWidth;
const height = container.scrollHeight || 600;
// 1. 注册自定义节点和边(下一节详述)
registerCustomNode();
registerCustomEdge();
// 2. 创建图实例
const graph = new G6.TreeGraph({
container: container,
width,
height,
linkCenter: true, // 连线对准节点中心
modes: {
default: [
'drag-canvas', // 拖拽画布
'zoom-canvas', // 缩放画布
'drag-node', // 拖拽节点
{
type: 'tooltip', // 鼠标悬停提示
formatText: (model) => {
return `姓名: ${model.name || 'N/A'}\n职位: ${model.title || model.label}`;
},
}
],
},
defaultNode: {
type: 'org-node', // 使用我们即将注册的自定义节点类型
size: [180, 80], // 节点默认大小
},
defaultEdge: {
type: 'org-edge', // 自定义边类型
style: {
stroke: '#A3B1BF',
lineWidth: 1.5,
},
},
layout: {
type: 'compactBox', // 紧凑树布局
direction: 'TB', // 从上到下 (Top to Bottom)
getHeight: () => 40,
getWidth: () => 16,
getVGap: () => 50, // 垂直间距
getHGap: () => 100, // 水平间距
radial: false, // 非辐射状
},
fitView: true, // 初始化时自适应视图
animate: true, // 启用布局动画
});
graphRef.current = graph;
// 3. 读取数据并渲染
graph.data(data

&spm=1001.2101.3001.5002&articleId=153323797&d=1&t=3&u=4f81ed055414420bbea77cf7c2925c16)
6333

被折叠的 条评论
为什么被折叠?



