New file |
| | |
| | | import React from 'react' |
| | | import { createGraphConfig } from '@antv/xflow' |
| | | /** 自定义React节点/边 */ |
| | | import Node1 from './react-node/node1' |
| | | import Node2 from './react-node/node2' |
| | | import Edge1 from './react-edge/edge1' |
| | | import Edge2 from './react-edge/edge2' |
| | | |
| | | export const useGraphConfig = createGraphConfig(config => { |
| | | /** 设置XFlow画布配置项 */ |
| | | config.setX6Config({ |
| | | /** 画布网格 */ |
| | | grid: true, |
| | | /** 画布缩放等级 */ |
| | | scaling: { |
| | | min: 0.2, |
| | | max: 3, |
| | | }, |
| | | /** 画布滚轮缩放 */ |
| | | // mousewheel: { |
| | | // enabled: true, |
| | | // /** 将鼠标位置作为中心缩放 */ |
| | | // zoomAtMousePosition: true, |
| | | // }, |
| | | }) |
| | | |
| | | /** 设置XFlow画布需要渲染的React节点/边 */ |
| | | config.setNodeRender('NODE1', props => <Node1 {...props} />) |
| | | config.setNodeRender('NODE2', Node2) |
| | | config.setEdgeRender('EDGE1', props => <Edge1 {...props} />) |
| | | config.setEdgeRender('EDGE2', props => <Edge2 {...props} />) |
| | | }) |
New file |
| | |
| | | .quick-start .__dumi-default-previewer-demo { |
| | | padding: 0 0; |
| | | } |
| | | |
| | | .quick-start .xflow-user-container { |
| | | position: relative; |
| | | width: 100%; |
| | | height: 320px; |
| | | overflow: scroll; |
| | | /** 覆盖节点默认选中色 */ |
| | | /** 覆盖连线默认选中色 */ |
| | | } |
| | | |
| | | .quick-start .xflow-user-container .x6-node-selected rect { |
| | | stroke: #dd4a68; |
| | | stroke-width: 3px; |
| | | } |
| | | |
| | | .quick-start .xflow-user-container .x6-edge-selected path { |
| | | stroke: #873bf4; |
| | | stroke-width: 2px; |
| | | } |
| | | |
| | | .quick-start .xflow-user-container .xflow-workspace-toolbar-top { |
| | | border-bottom: 1px solid #d9d9d9; |
| | | } |
| | | |
| | | .quick-start .xflow-user-container .xflow-custom-minimap { |
| | | border: 1px solid rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .quick-start .xflow-user-container .xflow-custom-minimap .x6-widget-minimap-viewport { |
| | | border: 1px solid rgba(0, 0, 0, 0.3); |
| | | } |
| | |
| | | import ProSkeleton from '@ant-design/pro-skeleton'; |
| | | import React, { useState } from 'react' |
| | | import { XFlow, XFlowCanvas } from '@antv/xflow' |
| | | /** 图的各种扩展交互组件 */ |
| | | import { CanvasMiniMap, CanvasScaleToolbar, CanvasSnapline } from '@antv/xflow' |
| | | /** 图的配置项 */ |
| | | import { useGraphConfig } from './config-graph' |
| | | import { message } from 'antd' |
| | | |
| | | export default () => ( |
| | | <div |
| | | style={{ |
| | | padding: 24, |
| | | }} |
| | | > |
| | | <ProSkeleton type="list" /> |
| | | </div> |
| | | ); |
| | | import './index.css' |
| | | |
| | | const Demo = () => { |
| | | /** 画布配置 */ |
| | | const graphConfig = useGraphConfig() |
| | | |
| | | /** 画布渲染数据 */ |
| | | const [graphData, setGraphData] = useState() |
| | | |
| | | /** XFlow初始化完成的回调 */ |
| | | const onLoad = async app => { |
| | | const node = [ |
| | | { id: 'root1', width: 150, height: 40, renderKey: 'NODE1', info: { text: 'root1' } }, |
| | | { id: 'down1', width: 150, height: 40, renderKey: 'NODE2', info: { text: 'down1' } }, |
| | | { id: 'down2', width: 150, height: 40, renderKey: 'NODE2', info: { text: 'down2' } }, |
| | | { id: 'down3', width: 150, height: 40, renderKey: 'NODE2', info: { text: 'down3' } }, |
| | | ] |
| | | const edges = [ |
| | | { |
| | | id: 'root1-down1', |
| | | source: 'root1', |
| | | target: 'down1', |
| | | renderKey: 'EDGE1', |
| | | edgeContentWidth: 60, |
| | | edgeContentHeight: 30, |
| | | info: { line: 'root1-down1' }, |
| | | }, |
| | | { |
| | | id: 'root1-down2', |
| | | source: 'root1', |
| | | target: 'down2', |
| | | renderKey: 'EDGE2', |
| | | edgeContentWidth: 60, |
| | | edgeContentHeight: 30, |
| | | info: { line: 'root1-down2' }, |
| | | }, |
| | | { |
| | | id: 'root1-down3', |
| | | source: 'root1', |
| | | target: 'down3', |
| | | label: '1:N(纯文本)', |
| | | info: { line: 'root1-down3' }, |
| | | }, |
| | | ] |
| | | const newGraphData = { nodes, edges } |
| | | setGraphData(newGraphData) |
| | | |
| | | const graph = await app.getGraphInstance() |
| | | graph.on('node:click', ({ node }) => { |
| | | const nodeData = node.getData() |
| | | message.success(`${nodeData.id}节点被点击了`) |
| | | }) |
| | | graph.on('edge:click', ({ edge }) => { |
| | | edge.toFront() |
| | | const edgeData = edge.getData() |
| | | message.success(`${edgeData.id}连线被点击了`) |
| | | }) |
| | | } |
| | | |
| | | return ( |
| | | <XFlow |
| | | className="xflow-user-container" |
| | | graphData={graphData} |
| | | graphLayout={{ |
| | | layoutType: 'dagre', |
| | | layoutOptions: { |
| | | type: 'dagre', |
| | | rankdir: 'TB', |
| | | nodesep: 60, |
| | | ranksep: 40, |
| | | }, |
| | | }} |
| | | onLoad={onLoad} |
| | | isAutoCenter={true} |
| | | > |
| | | <XFlowCanvas config={graphConfig}> |
| | | <CanvasScaleToolbar position={{ top: 12, left: 12 }} /> |
| | | <CanvasMiniMap |
| | | miniMapClz="xflow-custom-minimap" |
| | | nodeFillColor="#ccc" |
| | | minimapOptions={{ |
| | | width: 200, |
| | | height: 120, |
| | | }} |
| | | position={{ top: 12, right: 12 }} |
| | | /> |
| | | <CanvasSnapline color="#1890ff" /> |
| | | </XFlowCanvas> |
| | | </XFlow> |
| | | ) |
| | | } |
| | | |
| | | export default Demo |
New file |
| | |
| | | .edge1-container { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 14px; |
| | | background-color: #fff; |
| | | border: 1px solid #690; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | } |
| | | |
New file |
| | |
| | | import React from 'react' |
| | | import { useAppContext } from '@antv/xflow' |
| | | import { Tooltip } from 'antd' |
| | | import './edge1.css' |
| | | |
| | | const Edge1 = props => { |
| | | const ctx = useAppContext() |
| | | // console.log('edge useAppContext', ctx); |
| | | // console.log('edge props:', props); |
| | | return ( |
| | | <div className="edge1-container"> |
| | | <Tooltip |
| | | title="这是连线上渲染的React内容" |
| | | // defaultVisible={true} |
| | | > |
| | | <div>hover我</div> |
| | | </Tooltip> |
| | | </div> |
| | | ) |
| | | } |
| | | export default Edge1 |
New file |
| | |
| | | .edge2-container { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 14px; |
| | | background-color: #fff; |
| | | border: 1px solid #690; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | } |
New file |
| | |
| | | import React from 'react' |
| | | import { useAppContext } from '@antv/xflow' |
| | | import './edge2.css' |
| | | |
| | | const Edge2 = props => { |
| | | return <div className="edge2-container">React2</div> |
| | | } |
| | | export default Edge2 |
New file |
| | |
| | | .node1-container { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | font-weight: 600; |
| | | background-color: #fff; |
| | | border: 1px solid #873bf4; |
| | | border-radius: 4px; |
| | | } |
New file |
| | |
| | | import React from 'react' |
| | | import './node1.css' |
| | | |
| | | const Node1 = props => { |
| | | /** |
| | | * 1. 节点的数据、位置信息通过props取 |
| | | * 2. 当节点被触发更新时, props返回的数据也会动态更新, 触发节点重新渲染 |
| | | */ |
| | | return ( |
| | | <div className="node1-container"> |
| | | <div>{'React节点1'}</div> |
| | | </div> |
| | | ) |
| | | } |
| | | export default Node1 |
New file |
| | |
| | | .node2-container { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 100%; |
| | | height: 100%; |
| | | font-weight: 600; |
| | | background-color: #fff; |
| | | border: 1px solid #dd4a68; |
| | | border-radius: 4px; |
| | | } |
New file |
| | |
| | | import React from 'react' |
| | | import { useAppContext } from '@antv/xflow' |
| | | import './node2.css' |
| | | |
| | | const Node2 = props => { |
| | | const ctx = useAppContext() |
| | | |
| | | return ( |
| | | <div className="node2-container"> |
| | | <div>{'React节点2'}</div> |
| | | </div> |
| | | ) |
| | | } |
| | | export default Node2 |
New file |
| | |
| | | import ProSkeleton from '@ant-design/pro-skeleton'; |
| | | |
| | | export default () => ( |
| | | <div |
| | | style={{ |
| | | padding: 24, |
| | | }} |
| | | > |
| | | <ProSkeleton type="list" /> |
| | | </div> |
| | | ); |