mac
5 months ago
4 changed files with 151 additions and 1 deletions
@ -0,0 +1,53 @@ |
|||
import dagre from 'dagre'; |
|||
const edgeType = 'smoothstep'; |
|||
|
|||
export const flattenTree = (tree) => { |
|||
let stack = [tree]; |
|||
let nodes = []; |
|||
let edges = []; |
|||
while (stack.length > 0) { |
|||
let node = stack.pop(); |
|||
nodes.push({ id: node.id, data: { ...node, label: `${node.name}` }, position: node.position }); |
|||
if (node.children && node.children.length > 0) { |
|||
node.children.map(item => { |
|||
edges.push({ source: node.id, target: item.id, id: item.id, type: edgeType, animated: true }); |
|||
stack.unshift(item); |
|||
}); |
|||
}; |
|||
}; |
|||
return { nodes, edges }; |
|||
}; |
|||
|
|||
export const getLayoutedElements = (nodes, edges, direction = 'TB') => { |
|||
const dagreGraph = new dagre.graphlib.Graph(); |
|||
dagreGraph.setDefaultEdgeLabel(() => ({})); |
|||
|
|||
const nodeWidth = 172; |
|||
const nodeHeight = 36; |
|||
const isHorizontal = direction === 'LR'; |
|||
dagreGraph.setGraph({ rankdir: direction }); |
|||
|
|||
nodes.forEach((node: any) => { |
|||
dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight }); |
|||
}); |
|||
|
|||
edges.forEach((edge: any) => { |
|||
dagreGraph.setEdge(edge.source, edge.target); |
|||
}); |
|||
|
|||
dagre.layout(dagreGraph); |
|||
|
|||
nodes.forEach((node: any) => { |
|||
const nodeWithPosition = dagreGraph.node(node.id); |
|||
node.targetPosition = isHorizontal ? 'left' : 'top'; |
|||
node.sourcePosition = isHorizontal ? 'right' : 'bottom'; |
|||
node.position = { |
|||
x: nodeWithPosition.x - nodeWidth / 2, |
|||
y: nodeWithPosition.y - nodeHeight / 2, |
|||
}; |
|||
|
|||
return node; |
|||
}); |
|||
|
|||
return { nodes, edges }; |
|||
}; |
@ -0,0 +1,84 @@ |
|||
import React, { useCallback, FC, useEffect, useState, useRef } from 'react'; |
|||
import ReactFlow, { |
|||
addEdge, |
|||
ConnectionLineType, |
|||
useNodesState, |
|||
useEdgesState, |
|||
Controls |
|||
} from 'react-flow-renderer'; |
|||
import { getLayoutedElements, flattenTree } from './data'; |
|||
import { Button, Form, Input, Modal, notification } from 'antd'; |
|||
import api from '@/api'; |
|||
|
|||
const InviteChart: FC = () => { |
|||
const [nodes, setNodes, onNodesChange] = useNodesState([]); |
|||
const [edges, setEdges, onEdgesChange] = useEdgesState([]); |
|||
const [form] = Form.useForm() |
|||
const buttonRef = useRef(null) |
|||
|
|||
// 获取节点
|
|||
const getNodes = async (email?: string) => { |
|||
const res: any = await api.user_relation({ email: email || '' }); |
|||
if (res.code === 0) { |
|||
let { nodes, edges } = flattenTree(res.data) // 处理节点及连接线
|
|||
let { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges)//计算节点位置
|
|||
setNodes([...layoutedNodes]) |
|||
setEdges([...layoutedEdges]) |
|||
buttonRef.current.click() |
|||
}; |
|||
}; |
|||
|
|||
const onFinish = (values) => { |
|||
form.resetFields() |
|||
getNodes(values.email) |
|||
} |
|||
|
|||
const onLayout = useCallback( |
|||
(direction: any) => { |
|||
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements( |
|||
nodes, |
|||
edges, |
|||
direction |
|||
); |
|||
|
|||
setNodes([...layoutedNodes]); |
|||
setEdges([...layoutedEdges]); |
|||
}, |
|||
[nodes, edges] |
|||
); |
|||
|
|||
|
|||
useEffect(() => { |
|||
getNodes(); |
|||
}, []); |
|||
|
|||
return ( |
|||
<div> |
|||
<Button onClick={() => onLayout('LR')} style={{ display: 'none' }} ref={buttonRef}>123123123</Button> |
|||
<Form layout='inline' form={form} onFinish={onFinish}> |
|||
<Form.Item name="email"> |
|||
<Input placeholder='请输入邮箱' style={{ width: 300 }} /> |
|||
</Form.Item> |
|||
<Form.Item> |
|||
<Button htmlType='submit' type='primary'>搜索</Button> |
|||
</Form.Item> |
|||
</Form> |
|||
|
|||
<div style={{ width: '100%', height: window.innerHeight - 165 }}> |
|||
<ReactFlow |
|||
nodes={nodes} |
|||
edges={edges} |
|||
onNodesChange={onNodesChange} |
|||
onEdgesChange={onEdgesChange} |
|||
connectionLineType={ConnectionLineType.SmoothStep} |
|||
fitView |
|||
> |
|||
<Controls /> |
|||
</ReactFlow> |
|||
</div> |
|||
|
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default InviteChart; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue