当前位置:   article > 正文

React Flow_reactflow

reactflow
  1. // 创建项目
  2. npm create vite@latest my-react-flow-app -- --template react
  3. // 安装插件
  4. npm install reactflow
  5. npm install antd
  6. // 运行项目
  7. npm run dev

https://reactflow.dev/

1、App.jsx

  1. import { useCallback, useState } from 'react';
  2. import ReactFlow,
  3. {
  4. addEdge,
  5. ReactFlowProvider,
  6. MiniMap,
  7. Controls,
  8. useNodesState,
  9. useEdgesState,
  10. useReactFlow,
  11. MarkerType,
  12. Panel,
  13. ConnectionMode
  14. } from 'reactflow';
  15. import 'reactflow/dist/style.css';
  16. import './index.css';
  17. import UpdateNode from './components/nodeContent';
  18. import UpdateEdge from './components/edgeContent';
  19. import ResizableNodeSelected from './components/ResizableNodeSelected';
  20. import {nodes as initialNodes1,edges as initialEdges1} from './components/data';
  21. const nodeTypes = {
  22. ResizableNodeSelected,
  23. };
  24. const rfStyle = {
  25. backgroundColor: '#B8CEFF',
  26. };
  27. const initialNodes = [
  28. {
  29. id: '1',
  30. type: 'ResizableNodeSelected',
  31. position: { x: 100, y: 100 },
  32. data: { label: '1' },
  33. style: {
  34. background: "#F3A011",
  35. color: "white",
  36. border: '1px solid orange',
  37. borderRadius: '100%',
  38. width: 80,
  39. height: 80,
  40. },
  41. },
  42. {
  43. id: '2',
  44. type: 'ResizableNodeSelected',
  45. position: { x: 200, y: 300 },
  46. data: { label: '2' },
  47. style: {
  48. background: "#F3A011",
  49. color: "white",
  50. border: '1px solid orange',
  51. borderRadius: '100%',
  52. width: 80,
  53. height: 80,
  54. },
  55. },
  56. {
  57. id: '3',
  58. type: 'ResizableNodeSelected',
  59. position: { x: 100, y: 500 },
  60. data: { label: '3' },
  61. style: {
  62. background: "#F3A011",
  63. color: "white",
  64. border: '1px solid orange',
  65. borderRadius: '100%',
  66. width: 80,
  67. height: 80,
  68. },
  69. },
  70. ];
  71. const initialEdges = [
  72. {
  73. id: 'e1-2',
  74. source: '1',
  75. target: '2',
  76. style: { stroke: "#116F97" },
  77. label: "连接1-2",
  78. sourceHandle: 'c',
  79. targetHandle: 'a',
  80. },
  81. {
  82. id: "e2-3",
  83. source: "2",
  84. target: "3",
  85. // labelStyle: { fill: "#116F97", fontWeight: 100 }, // 连接线名称样式
  86. style: { stroke: "#116F97" }, // 连接线颜色
  87. label: "连接2-3",
  88. sourceHandle: 'c',
  89. targetHandle: 'a',
  90. },
  91. ];
  92. const flowKey = 'flow_test';
  93. const localNodes = JSON.parse(localStorage.getItem(flowKey)).nodes;
  94. const localEdges = JSON.parse(localStorage.getItem(flowKey)).edges;
  95. let nodeId = 1;
  96. function App1() {
  97. const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes1);
  98. const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges1);
  99. const [nodeInfo, setNodeInfo] = useState({});
  100. const [edgeInfo, setEdgeInfo] = useState({});
  101. const [nodeShow, setNodeShow] = useState(true);
  102. const onConnect = useCallback(
  103. (connection) => setEdges((eds) => addEdge(connection, eds)),
  104. [setEdges]
  105. );
  106. // 保存
  107. const [rfInstance, setRfInstance] = useState({});
  108. const onSave = useCallback(() => {
  109. if (rfInstance) {
  110. const flow = rfInstance.toObject();
  111. localStorage.setItem(flowKey, JSON.stringify(flow));
  112. console.log(JSON.stringify(flow));
  113. }
  114. }, [rfInstance]
  115. );
  116. // 恢复
  117. const { setViewport } = useReactFlow();
  118. const onRestore = useCallback(() => {
  119. const restoreFlow = async () => {
  120. const flow = JSON.parse(localStorage.getItem(flowKey));
  121. if (flow) {
  122. const { x = 0, y = 0, zoom = 0 } = flow.viewport;
  123. setNodes(flow.nodes || []);
  124. setEdges(flow.edges || []);
  125. setViewport({ x, y, zoom });
  126. }
  127. };
  128. restoreFlow();
  129. }, [setNodes, setViewport]
  130. );
  131. // 清空
  132. const onDelete = useCallback(() => {
  133. const restoreFlow = async () => {
  134. setNodes([] || []);
  135. setEdges([] || []);
  136. };
  137. restoreFlow();
  138. }, [setNodes]
  139. );
  140. // 点击节点
  141. const onNodeClick = (e, node) => {
  142. setNodeInfo({
  143. ...node.data,
  144. id: node.id,
  145. nodeBg: node.style && node.style.background ? node.style.background : '#ffffff',
  146. });
  147. setNodeShow(true);
  148. };
  149. // 点击节点连接线
  150. const onEdgeClick = (e, edge) => {
  151. setEdgeInfo(edges.find((item) => edge.id === item.id));
  152. setNodeShow(false);
  153. };
  154. // 新增节点
  155. const reactFlowInstance = useReactFlow();
  156. const onAdd = useCallback(() => {
  157. const id = `${++nodeId}`;
  158. const newNode = {
  159. id,
  160. type: 'ResizableNodeSelected',
  161. position: {
  162. x: 100,
  163. y: 300,
  164. // x: Math.random() * 200,
  165. // y: Math.random() * 200,
  166. },
  167. data: {
  168. label: `Node ${id}`,
  169. },
  170. style: {
  171. background: "#F3A011",
  172. color: "white",
  173. border: '1px solid orange',
  174. borderRadius: '100%',
  175. width: 80,
  176. height: 80,
  177. },
  178. };
  179. reactFlowInstance.addNodes(newNode);
  180. }, []);
  181. // 改变节点内容
  182. const changeNode = (val) => {
  183. setNodes((nds) =>
  184. nds.map((item) => {
  185. if (item.id === val.id) {
  186. item.data = val;
  187. item.hidden = val.isHidden;
  188. item.style = { background: val.nodeBg, width: 80, height: 80, borderRadius: '100%', color: "white", fontSize: 2 };
  189. }
  190. return item;
  191. }),
  192. );
  193. };
  194. // 改变连接线内容
  195. const changeEdge = (val) => {
  196. setEdges((nds) =>
  197. nds.map((item) => {
  198. if (item.id === val.id) {
  199. item.label = val.label;
  200. item.type = val.type;
  201. item.hidden = val.isHidden;
  202. item.style = { stroke: val.color };
  203. }
  204. return item;
  205. }),
  206. );
  207. };
  208. // 默认edge样式
  209. const defaultEdgeOptions = {
  210. style: {
  211. strokeWidth: 1,
  212. stroke: '#116F97'
  213. },
  214. type: 'default',
  215. markerEnd: {
  216. type: MarkerType.ArrowClosed,
  217. color: '#116F97'
  218. } // 连接线尾部的箭头
  219. }
  220. return (
  221. <div style={{ width: '100vw', height: '100vh' }}>
  222. <ReactFlow
  223. nodes={nodes} // 节点
  224. edges={edges} // 连接线
  225. onNodesChange={onNodesChange} // 节点拖拽等改变
  226. onEdgesChange={onEdgesChange} // 连接线拖拽等改变
  227. onNodeClick={onNodeClick} // 点击节点
  228. onEdgeClick={onEdgeClick} // 点击连接线
  229. onConnect={onConnect} // 节点直接连接
  230. nodeTypes={nodeTypes} // 节点类型
  231. // edgeTypes={edgeTypes}
  232. fitView // 渲染节点数据
  233. style={rfStyle} // 背景色
  234. defaultEdgeOptions={defaultEdgeOptions} // 默认连接线样式
  235. onInit={setRfInstance} // 初始化保存的数据
  236. connectionMode={ConnectionMode.Loose}
  237. />
  238. {nodeShow ? (
  239. <UpdateNode info={nodeInfo} onChange={changeNode} />
  240. ) : (
  241. <UpdateEdge info={edgeInfo} onChange={changeEdge} />
  242. )}
  243. <Panel position='top-left'>
  244. <button onClick={onAdd}>add node</button>
  245. <button onClick={onSave}>save</button>
  246. <button onClick={onRestore}>restore</button>
  247. <button onClick={onDelete}>delete</button>
  248. </Panel>
  249. <MiniMap />
  250. <Controls />
  251. </div>
  252. );
  253. }
  254. export default function () {
  255. return (
  256. <ReactFlowProvider>
  257. <App1 />
  258. </ReactFlowProvider>
  259. );
  260. }

 2、index.css

  1. :root {
  2. font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  3. /* line-height: 2; */
  4. font-weight: 400;
  5. /* color-scheme: light dark; */
  6. color: rgba(255, 255, 255, 0.87);
  7. background-color: #242424;
  8. font-synthesis: none;
  9. text-rendering: optimizeLegibility;
  10. -webkit-font-smoothing: antialiased;
  11. -moz-osx-font-smoothing: grayscale;
  12. /* -webkit-text-size-adjust: 100%; */
  13. }
  14. a {
  15. font-weight: 500;
  16. color: #646cff;
  17. text-decoration: inherit;
  18. }
  19. a:hover {
  20. color: #535bf2;
  21. }
  22. body {
  23. margin: 0;
  24. display: flex;
  25. place-items: center;
  26. min-width: 320px;
  27. min-height: 100vh;
  28. }
  29. h1 {
  30. font-size: 3.2em;
  31. line-height: 1.1;
  32. }
  33. button {
  34. border-radius: 8px;
  35. border: 1px solid transparent;
  36. padding: 0.6em 1.2em;
  37. font-size: 1em;
  38. font-weight: 500;
  39. font-family: inherit;
  40. background-color: #1a1a1a;
  41. cursor: pointer;
  42. transition: border-color 0.25s;
  43. }
  44. button:hover {
  45. border-color: #646cff;
  46. }
  47. button:focus,
  48. button:focus-visible {
  49. outline: 4px auto -webkit-focus-ring-color;
  50. }
  51. @media (prefers-color-scheme: light) {
  52. :root {
  53. color: #213547;
  54. background-color: #ffffff;
  55. }
  56. a:hover {
  57. color: #116F97;
  58. }
  59. button {
  60. background-color: #f9f9f9;
  61. }
  62. }
  63. /* edge颜色 */
  64. .react-flow__handle{
  65. color: #116F97;
  66. background-color: #116F97;
  67. border:0;
  68. border-radius: 100%;
  69. min-width: 1px;
  70. min-height: 1px;
  71. }
  72. .react-flow__edge-textbg{
  73. fill:#3a94BB;
  74. }
  75. .react-flow__handle.connectionindicator{
  76. width: 1;
  77. height: 1;
  78. }
  79. .react-flow__node{
  80. width: 50;
  81. height: 50;
  82. }
  83. /* 4个连接点样式 */
  84. .simple-floatingedges {
  85. flex-direction: column;
  86. display: flex;
  87. flex-grow: 1;
  88. height: 100%;
  89. }
  90. .simple-floatingedges .react-flow__handle {
  91. width: 8px;
  92. height: 8px;
  93. background-color: #bbb;
  94. }
  95. .simple-floatingedges .react-flow__handle-top {
  96. top: -5px;
  97. }
  98. .simple-floatingedges .react-flow__handle-bottom {
  99. bottom: -5px;
  100. }
  101. .simple-floatingedges .react-flow__handle-left {
  102. left: -5px;
  103. }
  104. .simple-floatingedges .react-flow__handle-right {
  105. right: -5px;
  106. }
  107. .simple-floatingedges .react-flow__node-custom {
  108. background: #fff;
  109. border: 1px solid #1a192b;
  110. border-radius: 3px;
  111. color: #222;
  112. font-size: 12px;
  113. padding: 10px;
  114. text-align: center;
  115. width: 150px;
  116. }
  117. /* node与wdge编辑样式 */
  118. .dndflow {
  119. display: flex;
  120. flex-direction: column;
  121. flex-grow: 1;
  122. height: 70vh;
  123. }
  124. .react-flow__attribution {
  125. display: none;
  126. }
  127. .dndflow aside {
  128. padding: 15px 10px;
  129. font-size: 12px;
  130. background: #fcfcfc;
  131. border-right: 1px solid #eee;
  132. }
  133. .dndflow aside .description {
  134. margin-bottom: 10px;
  135. }
  136. .dndflow .dndnode {
  137. display: flex;
  138. align-items: center;
  139. justify-content: center;
  140. height: 20px;
  141. margin-bottom: 10px;
  142. padding: 4px;
  143. border: 1px solid #1a192b;
  144. border-radius: 2px;
  145. cursor: grab;
  146. }
  147. .dndflow .dndnode.input {
  148. border-color: #0041d0;
  149. }
  150. .dndflow .dndnode.output {
  151. border-color: #ff0072;
  152. }
  153. .dndflow .reactflow-wrapper {
  154. flex-grow: 1;
  155. height: 100%;
  156. }
  157. .dndflow .selectall {
  158. margin-top: 10px;
  159. }
  160. @media screen and (min-width: 768px) {
  161. .dndflow {
  162. flex-direction: row;
  163. }
  164. .dndflow aside {
  165. width: 20%;
  166. max-width: 250px;
  167. }
  168. }
  169. .my_handle {
  170. z-index: 99;
  171. }
  172. .nodeContent {
  173. position: relative;
  174. color: #222;
  175. font-size: 12px;
  176. line-height: 10px;
  177. text-align: center;
  178. background-color: #fff;
  179. border: 1px solid #1a192b;
  180. border-radius: 3px;
  181. }
  182. .nodeStyle {
  183. width: 110px;
  184. height: 30px;
  185. line-height: 10px;
  186. }
  187. .updatenode__controls {
  188. position: absolute;
  189. top: 10px;
  190. right: 10px;
  191. z-index: 4;
  192. padding: 16px;
  193. font-size: 12px;
  194. background-color: #fff;
  195. }
  196. .updatenode__controls label {
  197. display: block;
  198. }
  199. .updatenode__bglabel {
  200. margin-top: 10px;
  201. }
  202. .updatenode__checkboxwrapper {
  203. display: flex;
  204. align-items: center;
  205. margin-top: 10px;
  206. }

3、nodeContent.tsx

  1. import React, { useState, useEffect } from 'react';
  2. import { Input, Switch } from 'antd';
  3. export type nodeProps = {
  4. info: any;
  5. onChange: (val: any) => void;
  6. };
  7. export default ({ info, onChange }: nodeProps) => {
  8. const [nodeInfo, setNodeInfo] = useState<any>({});
  9. useEffect(() => {
  10. if (info.id) {
  11. if (!info.isHidden) {
  12. info.isHidden = false;
  13. }
  14. setNodeInfo(info);
  15. }
  16. }, [info.id]);
  17. // 改变名称
  18. const setNodeName = (value: string) => {
  19. setNodeInfo({
  20. ...nodeInfo,
  21. label: value,
  22. });
  23. onChange({
  24. ...nodeInfo,
  25. label: value,
  26. });
  27. };
  28. // 改变背景色
  29. const setNodeBg = (value: string) => {
  30. setNodeInfo({
  31. ...nodeInfo,
  32. nodeBg: value,
  33. });
  34. onChange({
  35. ...nodeInfo,
  36. nodeBg: value,
  37. });
  38. };
  39. // 是否隐藏
  40. const setNodeHidden = (value: boolean) => {
  41. setNodeInfo({
  42. ...nodeInfo,
  43. isHidden: value,
  44. });
  45. onChange({
  46. ...nodeInfo,
  47. isHidden: value,
  48. });
  49. };
  50. return nodeInfo.id ? (
  51. <div className="updatenode__controls">
  52. <label>名称:</label>
  53. <Input
  54. placeholder=""
  55. value={nodeInfo.label}
  56. onChange={(evt) => setNodeName(evt.target.value)}
  57. />
  58. <label className="updatenode__bglabel">背景色:</label>
  59. <Input type="color" value={nodeInfo.nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} />
  60. <div className="updatenode__checkboxwrapper">
  61. <label>是否隐藏:</label>
  62. {/* <Switch checked={nodeInfo.isHidden} onChange={setNodeHidden} /> */}
  63. <input type='checkbox' checked={nodeInfo.isHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} />
  64. </div>
  65. </div>
  66. ) : (
  67. <></>
  68. );
  69. };

4、edgeContent.tsx

  1. import React, { useState, useEffect } from 'react';
  2. import { Input, Select, Switch } from 'antd';
  3. const { Option } = Select;
  4. export type edgeProps = {
  5. info: any;
  6. onChange: (val: any) => void;
  7. };
  8. export default ({ info, onChange }: edgeProps) => {
  9. const [edgeInfo, setEdgeInfo] = useState<any>({});
  10. const edgeTypes = [
  11. { label: '曲线', value: 'default' },
  12. { label: '直线', value: 'straight' },
  13. { label: '直角线', value: 'step' },
  14. { label: '圆滑直角线', value: 'smoothstep' },
  15. ];
  16. useEffect(() => {
  17. if (info.id) {
  18. if (info.style) {
  19. info.color = info.style.stroke;
  20. }
  21. if (!info.isHidden) {
  22. info.isHidden = false;
  23. }
  24. setEdgeInfo(info);
  25. }
  26. }, [info.id]);
  27. // 改变名称
  28. const setNodeName = (value: string) => {
  29. setEdgeInfo({
  30. ...edgeInfo,
  31. label: value,
  32. });
  33. onChange({
  34. ...edgeInfo,
  35. label: value,
  36. });
  37. };
  38. // 改变颜色
  39. const setNodeBg = (value: string) => {
  40. setEdgeInfo({
  41. ...edgeInfo,
  42. color: value,
  43. });
  44. onChange({
  45. ...edgeInfo,
  46. color: value,
  47. });
  48. };
  49. // 改变类型
  50. const changeEdgeType = (value: string) => {
  51. setEdgeInfo({
  52. ...edgeInfo,
  53. type: value,
  54. });
  55. onChange({
  56. ...edgeInfo,
  57. type: value,
  58. });
  59. };
  60. // 是否隐藏
  61. const setEdgeHidden = (value: boolean) => {
  62. setEdgeInfo({
  63. ...edgeInfo,
  64. isHidden: value,
  65. });
  66. onChange({
  67. ...edgeInfo,
  68. isHidden: value,
  69. });
  70. };
  71. return edgeInfo.id ? (
  72. <div className="updatenode__controls">
  73. <label>连接线名称:</label>
  74. <Input
  75. placeholder=""
  76. value={edgeInfo.label}
  77. onChange={(evt) => setNodeName(evt.target.value)}
  78. />
  79. <label className="updatenode__bglabel">连接线颜色:</label>
  80. <Input type="color" value={edgeInfo.color} onChange={(evt) => setNodeBg(evt.target.value)} />
  81. <div className="updatenode__checkboxwrapper">
  82. <label>连接线类型:</label>
  83. <Select defaultValue="曲线 " value={edgeInfo.type} onChange={changeEdgeType}>
  84. {edgeTypes.map((item) => (
  85. <Option value={item.value} key={item.value}>
  86. {item.label}
  87. </Option>
  88. ))}
  89. </Select>
  90. </div>
  91. <div className="updatenode__checkboxwrapper">
  92. <label>是否隐藏:</label>
  93. <Switch checked={edgeInfo.isHidden} onChange={setEdgeHidden} />
  94. </div>
  95. </div>
  96. ) : (
  97. <></>
  98. );
  99. };

5、ResizableNodeSelected.tsx

  1. import { memo } from 'react';
  2. import { Handle, Position, NodeResizer } from 'reactflow';
  3. const ResizableNodeSelected = ({ data, selected }) => {
  4. return (
  5. <>
  6. <NodeResizer color="#F3A011" isVisible={selected} minWidth={80} minHeight={80} />
  7. <div
  8. style={{
  9. // width: 60,
  10. // height: 60,
  11. padding: 10,
  12. // display: "flex",
  13. // justifyContent: "center",
  14. // alignItems: "center",
  15. // fontSize: 2
  16. }}
  17. >
  18. {data.label}
  19. </div>
  20. <Handle style={{ opacity: 0 }} type="source" position={Position.Top} id='a' />
  21. <Handle style={{ opacity: 0 }} type="source" position={Position.Right} id='b' />
  22. <Handle style={{ opacity: 0 }} type="source" position={Position.Bottom} id='c' />
  23. <Handle style={{ opacity: 0 }} type="source" position={Position.Left} id='d' />
  24. </>
  25. );
  26. };
  27. export default memo(ResizableNodeSelected);

6、data.js

  1. export const nodes = [
  2. { "width": 80, "height": 80, "id": "13", "type": "ResizableNodeSelected", "position": { "x": 181.99158953145331, "y": 472.7199877834713 }, "data": { "label": "服务实例JVM堆大小", "id": "13", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 181.99158953145331, "y": 472.7199877834713 }, "dragging": false, "hidden": false },
  3. { "width": 80, "height": 80, "id": "12", "type": "ResizableNodeSelected", "position": { "x": 458.51664737488375, "y": 497.7400344424826 }, "data": { "label": "服务实例JVM线程数", "id": "12", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 458.51664737488375, "y": 497.7400344424826 }, "dragging": false, "hidden": false },
  4. { "width": 80, "height": 80, "id": "11", "type": "ResizableNodeSelected", "position": { "x": 456.86503312460417, "y": 278.4940093032253 }, "data": { "label": "应用服务平均响应时长", "id": "11", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 456.86503312460417, "y": 278.4940093032253 }, "dragging": false, "hidden": false },
  5. { "width": 80, "height": 80, "id": "10", "type": "ResizableNodeSelected", "position": { "x": 188.70901987307826, "y": 316.5335073980088 }, "data": { "label": "存储I/O负载", "id": "10", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 188.70901987307826, "y": 316.5335073980088 }, "dragging": false, "hidden": false },
  6. { "width": 80, "height": 80, "id": "9", "type": "ResizableNodeSelected", "position": { "x": 86.9908194969212, "y": 56.769326529302944 }, "data": { "label": "服务端点平均响应时长", "id": "9", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 86.9908194969212, "y": 56.769326529302944 }, "dragging": false, "hidden": false },
  7. { "width": 80, "height": 80, "id": "8", "type": "ResizableNodeSelected", "position": { "x": 461.40008223448365, "y": 92.49854876752454 }, "data": { "label": "服务实例", "id": "8", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 2 }, "selected": false, "positionAbsolute": { "x": 461.40008223448365, "y": 92.49854876752454 }, "dragging": false, "hidden": false },
  8. { "width": 80, "height": 80, "id": "7", "type": "ResizableNodeSelected", "position": { "x": -87.30759005365732, "y": 133.76253323256137 }, "data": { "label": "端点链路(动态模型)平均响应时长", "id": "7", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "dragging": false, "hidden": false, "positionAbsolute": { "x": -87.30759005365732, "y": 133.76253323256137 } },
  9. { "width": 80, "height": 80, "id": "6", "type": "ResizableNodeSelected", "position": { "x": -11.910201399135396, "y": 485.8445794117532 }, "data": { "label": "主机I/O负载", "id": "6", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "dragging": false, "hidden": false, "positionAbsolute": { "x": -11.910201399135396, "y": 485.8445794117532 }, "resizing": false },
  10. { "width": 80, "height": 80, "id": "5", "type": "ResizableNodeSelected", "position": { "x": -10, "y": 280.5 }, "data": { "label": "Mysql实例慢查询", "id": "5", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "dragging": false, "hidden": false, "positionAbsolute": { "x": -10, "y": 280.5 } },
  11. { "width": 80, "height": 80, "id": "4", "type": "ResizableNodeSelected", "position": { "x": -282.5, "y": 453 }, "data": { "label": "主机内存使用率", "id": "4", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "dragging": false, "hidden": false, "positionAbsolute": { "x": -282.5, "y": 453 } },
  12. { "width": 80, "height": 80, "id": "3", "type": "ResizableNodeSelected", "position": { "x": -275, "y": 283 }, "data": { "label": "主机CPU使用率", "id": "3", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "positionAbsolute": { "x": -275, "y": 283 }, "dragging": false, "hidden": false },
  13. { "width": 80, "height": 80, "id": "2", "type": "ResizableNodeSelected", "position": { "x": -271, "y": 133.5 }, "data": { "label": "消息中间件堆积数", "id": "2", "nodeBg": "#F3A011", "isHidden": false }, "style": { "background": "#F3A011", "width": 80, "height": 80, "borderRadius": "100%", "color": "white", "fontSize": 4 }, "selected": false, "dragging": false, "hidden": false, "positionAbsolute": { "x": -271, "y": 133.5 } }
  14. ];
  15. export const edges = [
  16. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "4", "sourceHandle": "a", "target": "5", "targetHandle": "d", "id": "reactflow__edge-4a-5d", "selected": false, "hidden": true },
  17. { "style": { "stroke": "#116F97" }, "type": "straight", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "4", "sourceHandle": "b", "target": "5", "targetHandle": "c", "id": "reactflow__edge-4b-5c", "selected": false, "hidden": true },
  18. { "style": { "stroke": "#116F97" }, "type": "default", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "5", "sourceHandle": "d", "target": "4", "targetHandle": "a", "id": "reactflow__edge-5d-4a", "selected": false, "hidden": true },
  19. { "style": { "stroke": "#116F97" }, "type": "default", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "2", "sourceHandle": "b", "target": "7", "targetHandle": "d", "id": "reactflow__edge-2b-7d", "selected": false, "label": "模型间接关系", "hidden": false },
  20. { "style": { "stroke": "#116F97" }, "type": "default", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "5", "sourceHandle": "d", "target": "3", "targetHandle": "b", "id": "reactflow__edge-5d-3b", "selected": false, "label": "模型直接关系", "hidden": false },
  21. { "style": { "stroke": "#116F97" }, "type": "default", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "6", "sourceHandle": "a", "target": "5", "targetHandle": "c", "id": "reactflow__edge-6a-5c", "selected": false, "label": "模型直接关系", "hidden": false },
  22. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "5", "sourceHandle": "a", "target": "7", "targetHandle": "c", "id": "reactflow__edge-5a-7c", "selected": false, "label": "模型直接关系", "hidden": false },
  23. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "4", "sourceHandle": "a", "target": "5", "targetHandle": "c", "id": "reactflow__edge-4a-5c", "selected": false, "label": "模型直接关系", "hidden": false },
  24. { "style": { "stroke": "#116F97" }, "type": "step", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "5", "sourceHandle": "b", "target": "7", "targetHandle": "b", "id": "reactflow__edge-5b-7b", "selected": false, "label": "模型直接关系", "hidden": false },
  25. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "7", "sourceHandle": "b", "target": "9", "targetHandle": "d", "id": "reactflow__edge-7b-9d", "selected": false, "hidden": false },
  26. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "10", "sourceHandle": "d", "target": "5", "targetHandle": "b", "id": "reactflow__edge-10d-5b", "selected": false, "label": "模型直接关系", "hidden": false },
  27. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "8", "sourceHandle": "c", "target": "11", "targetHandle": "a", "id": "reactflow__edge-8c-11a", "selected": false, "label": "模型直接关系", "hidden": false },
  28. { "style": { "stroke": "#116F97" }, "type": "straight", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "12", "sourceHandle": "a", "target": "11", "targetHandle": "c", "id": "reactflow__edge-12a-11c", "selected": false, "label": "模型直接关系", "hidden": false },
  29. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "13", "sourceHandle": "b", "target": "11", "targetHandle": "d", "id": "reactflow__edge-13b-11d", "selected": false, "label": "模型直接关系", "hidden": false },
  30. { "style": { "stroke": "#116F97" }, "type": "smoothstep", "markerEnd": { "type": "arrowclosed", "color": "#116F97" }, "source": "9", "sourceHandle": "b", "target": "11", "targetHandle": "d", "id": "reactflow__edge-9b-11d", "selected": false, "label": "模型直接关系", "hidden": false }
  31. ]
  32. // "viewport": { "x": 654.5507940552135, "y": -54.945769269730704, "zoom": 1.6908994642667994 } }

7、package.json

  1. {
  2. "name": "my-react-flow-app",
  3. "private": true,
  4. "version": "0.0.0",
  5. "type": "module",
  6. "scripts": {
  7. "dev": "vite",
  8. "build": "vite build",
  9. "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
  10. "preview": "vite preview"
  11. },
  12. "dependencies": {
  13. "antd": "^5.7.1",
  14. "react": "^18.2.0",
  15. "react-dom": "^18.2.0",
  16. "reactflow": "^11.7.4"
  17. },
  18. "devDependencies": {
  19. "@types/react": "^18.2.14",
  20. "@types/react-dom": "^18.2.6",
  21. "@vitejs/plugin-react": "^4.0.1",
  22. "eslint": "^8.44.0",
  23. "eslint-plugin-react": "^7.32.2",
  24. "eslint-plugin-react-hooks": "^4.6.0",
  25. "eslint-plugin-react-refresh": "^0.4.1",
  26. "vite": "^4.4.0"
  27. }
  28. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/864595
推荐阅读
相关标签
  

闽ICP备14008679号