React Flow

// 创建项目
npm create vite@latest my-react-flow-app -- --template react
// 安装插件
npm install reactflow
npm install antd
// 运行项目
npm run dev

1、App.jsx

import { useCallback, useState } from 'react';
import ReactFlow,
{addEdge,ReactFlowProvider,MiniMap,Controls,useNodesState,useEdgesState,useReactFlow,MarkerType,Panel,ConnectionMode
} from 'reactflow';
import 'reactflow/dist/style.css';
import './index.css';import UpdateNode from './components/nodeContent';
import UpdateEdge from './components/edgeContent';
import ResizableNodeSelected from './components/ResizableNodeSelected';
import {nodes as initialNodes1,edges as initialEdges1} from './components/data';const nodeTypes = {ResizableNodeSelected,
};const rfStyle = {backgroundColor: '#B8CEFF',
};const initialNodes = [{id: '1',type: 'ResizableNodeSelected',position: { x: 100, y: 100 },data: { label: '1' },style: {background: "#F3A011",color: "white",border: '1px solid orange',borderRadius: '100%',width: 80,height: 80,},},{id: '2',type: 'ResizableNodeSelected',position: { x: 200, y: 300 },data: { label: '2' },style: {background: "#F3A011",color: "white",border: '1px solid orange',borderRadius: '100%',width: 80,height: 80,},},{id: '3',type: 'ResizableNodeSelected',position: { x: 100, y: 500 },data: { label: '3' },style: {background: "#F3A011",color: "white",border: '1px solid orange',borderRadius: '100%',width: 80,height: 80,},},
];
const initialEdges = [{id: 'e1-2',source: '1',target: '2',style: { stroke: "#116F97" },label: "连接1-2",sourceHandle: 'c',targetHandle: 'a',},{id: "e2-3",source: "2",target: "3",// labelStyle: { fill: "#116F97", fontWeight: 100 }, // 连接线名称样式style: { stroke: "#116F97" }, // 连接线颜色label: "连接2-3",sourceHandle: 'c',targetHandle: 'a',},
];const flowKey = 'flow_test';
const localNodes = JSON.parse(localStorage.getItem(flowKey)).nodes;
const localEdges = JSON.parse(localStorage.getItem(flowKey)).edges;
let nodeId = 1;function App1() {const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes1);const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges1);const [nodeInfo, setNodeInfo] = useState({});const [edgeInfo, setEdgeInfo] = useState({});const [nodeShow, setNodeShow] = useState(true);const onConnect = useCallback((connection) => setEdges((eds) => addEdge(connection, eds)),[setEdges]);// 保存const [rfInstance, setRfInstance] = useState({});const onSave = useCallback(() => {if (rfInstance) {const flow = rfInstance.toObject();localStorage.setItem(flowKey, JSON.stringify(flow));console.log(JSON.stringify(flow));}}, [rfInstance]);// 恢复const { setViewport } = useReactFlow();const onRestore = useCallback(() => {const restoreFlow = async () => {const flow = JSON.parse(localStorage.getItem(flowKey));if (flow) {const { x = 0, y = 0, zoom = 0 } = flow.viewport;setNodes(flow.nodes || []);setEdges(flow.edges || []);setViewport({ x, y, zoom });}};restoreFlow();}, [setNodes, setViewport]);// 清空const onDelete = useCallback(() => {const restoreFlow = async () => {setNodes([] || []);setEdges([] || []);};restoreFlow();}, [setNodes]);// 点击节点const onNodeClick = (e, node) => {setNodeInfo({...node.data,id: node.id,nodeBg: node.style && node.style.background ? node.style.background : '#ffffff',});setNodeShow(true);};// 点击节点连接线const onEdgeClick = (e, edge) => {setEdgeInfo(edges.find((item) => edge.id === item.id));setNodeShow(false);};// 新增节点const reactFlowInstance = useReactFlow();const onAdd = useCallback(() => {const id = `${++nodeId}`;const newNode = {id,type: 'ResizableNodeSelected',position: {x: 100,y: 300,// x: Math.random() * 200,// y: Math.random() * 200,},data: {label: `Node ${id}`,},style: {background: "#F3A011",color: "white",border: '1px solid orange',borderRadius: '100%',width: 80,height: 80,},};reactFlowInstance.addNodes(newNode);}, []);// 改变节点内容const changeNode = (val) => {setNodes((nds) =>nds.map((item) => {if (item.id === val.id) {item.data = val;item.hidden = val.isHidden;item.style = { background: val.nodeBg, width: 80, height: 80, borderRadius: '100%', color: "white", fontSize: 2 };}return item;}),);};// 改变连接线内容const changeEdge = (val) => {setEdges((nds) =>nds.map((item) => {if (item.id === val.id) {item.label = val.label;item.type = val.type;item.hidden = val.isHidden;item.style = { stroke: val.color };}return item;}),);};// 默认edge样式const defaultEdgeOptions = {style: {strokeWidth: 1,stroke: '#116F97'},type: 'default',markerEnd: {type: MarkerType.ArrowClosed,color: '#116F97'} // 连接线尾部的箭头}return (<div style={{ width: '100vw', height: '100vh' }}><ReactFlownodes={nodes} // 节点edges={edges} // 连接线onNodesChange={onNodesChange} // 节点拖拽等改变onEdgesChange={onEdgesChange} // 连接线拖拽等改变onNodeClick={onNodeClick} // 点击节点onEdgeClick={onEdgeClick} // 点击连接线onConnect={onConnect} // 节点直接连接nodeTypes={nodeTypes} // 节点类型// edgeTypes={edgeTypes}fitView // 渲染节点数据style={rfStyle} // 背景色defaultEdgeOptions={defaultEdgeOptions} // 默认连接线样式onInit={setRfInstance} // 初始化保存的数据connectionMode={ConnectionMode.Loose}/>{nodeShow ? (<UpdateNode info={nodeInfo} onChange={changeNode} />) : (<UpdateEdge info={edgeInfo} onChange={changeEdge} />)}<Panel position='top-left'><button onClick={onAdd}>add node</button><button onClick={onSave}>save</button><button onClick={onRestore}>restore</button><button onClick={onDelete}>delete</button></Panel><MiniMap /><Controls /></div>);
}export default function () {return (<ReactFlowProvider><App1 /></ReactFlowProvider>);
}

 2、index.css

:root {font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;/* line-height: 2; */font-weight: 400;/* color-scheme: light dark; */color: rgba(255, 255, 255, 0.87);background-color: #242424;font-synthesis: none;text-rendering: optimizeLegibility;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;/* -webkit-text-size-adjust: 100%; */
}a {font-weight: 500;color: #646cff;text-decoration: inherit;
}
a:hover {color: #535bf2;
}body {margin: 0;display: flex;place-items: center;min-width: 320px;min-height: 100vh;
}h1 {font-size: 3.2em;line-height: 1.1;
}button {border-radius: 8px;border: 1px solid transparent;padding: 0.6em 1.2em;font-size: 1em;font-weight: 500;font-family: inherit;background-color: #1a1a1a;cursor: pointer;transition: border-color 0.25s;
}
button:hover {border-color: #646cff;
}
button:focus,
button:focus-visible {outline: 4px auto -webkit-focus-ring-color;
}@media (prefers-color-scheme: light) {:root {color: #213547;background-color: #ffffff;}a:hover {color: #116F97;}button {background-color: #f9f9f9;}
}/* edge颜色 */
.react-flow__handle{color: #116F97;background-color: #116F97;border:0;border-radius: 100%;min-width: 1px;min-height: 1px;
}
.react-flow__edge-textbg{fill:#3a94BB;
}
.react-flow__handle.connectionindicator{width: 1;height: 1;
}
.react-flow__node{width: 50;height: 50;
}/* 4个连接点样式 */
.simple-floatingedges {flex-direction: column;display: flex;flex-grow: 1;height: 100%;
}
.simple-floatingedges .react-flow__handle {width: 8px;height: 8px;background-color: #bbb;
}
.simple-floatingedges .react-flow__handle-top {top: -5px;
}
.simple-floatingedges .react-flow__handle-bottom {bottom: -5px;
}
.simple-floatingedges .react-flow__handle-left {left: -5px;
}
.simple-floatingedges .react-flow__handle-right {right: -5px;
}
.simple-floatingedges .react-flow__node-custom {background: #fff;border: 1px solid #1a192b;border-radius: 3px;color: #222;font-size: 12px;padding: 10px;text-align: center;width: 150px;
}/* node与wdge编辑样式 */
.dndflow {display: flex;flex-direction: column;flex-grow: 1;height: 70vh;
}
.react-flow__attribution {display: none;
}
.dndflow aside {padding: 15px 10px;font-size: 12px;background: #fcfcfc;border-right: 1px solid #eee;
}
.dndflow aside .description {margin-bottom: 10px;
}
.dndflow .dndnode {display: flex;align-items: center;justify-content: center;height: 20px;margin-bottom: 10px;padding: 4px;border: 1px solid #1a192b;border-radius: 2px;cursor: grab;
}
.dndflow .dndnode.input {border-color: #0041d0;
}
.dndflow .dndnode.output {border-color: #ff0072;
}
.dndflow .reactflow-wrapper {flex-grow: 1;height: 100%;
}
.dndflow .selectall {margin-top: 10px;
}
@media screen and (min-width: 768px) {.dndflow {flex-direction: row;}.dndflow aside {width: 20%;max-width: 250px;}
}
.my_handle {z-index: 99;
}
.nodeContent {position: relative;color: #222;font-size: 12px;line-height: 10px;text-align: center;background-color: #fff;border: 1px solid #1a192b;border-radius: 3px;
}
.nodeStyle {width: 110px;height: 30px;line-height: 10px;
}
.updatenode__controls {position: absolute;top: 10px;right: 10px;z-index: 4;padding: 16px;font-size: 12px;background-color: #fff;
}
.updatenode__controls label {display: block;
}
.updatenode__bglabel {margin-top: 10px;
}
.updatenode__checkboxwrapper {display: flex;align-items: center;margin-top: 10px;
}

3、nodeContent.tsx

import React, { useState, useEffect } from 'react';
import { Input, Switch } from 'antd';export type nodeProps = {info: any;onChange: (val: any) => void;
};export default ({ info, onChange }: nodeProps) => {const [nodeInfo, setNodeInfo] = useState<any>({});useEffect(() => {if (info.id) {if (!info.isHidden) {info.isHidden = false;}setNodeInfo(info);}}, [info.id]);// 改变名称const setNodeName = (value: string) => {setNodeInfo({...nodeInfo,label: value,});onChange({...nodeInfo,label: value,});};// 改变背景色const setNodeBg = (value: string) => {setNodeInfo({...nodeInfo,nodeBg: value,});onChange({...nodeInfo,nodeBg: value,});};// 是否隐藏const setNodeHidden = (value: boolean) => {setNodeInfo({...nodeInfo,isHidden: value,});onChange({...nodeInfo,isHidden: value,});};return nodeInfo.id ? (<div className="updatenode__controls"><label>名称:</label><Inputplaceholder=""value={nodeInfo.label}onChange={(evt) => setNodeName(evt.target.value)}/><label className="updatenode__bglabel">背景色:</label><Input type="color" value={nodeInfo.nodeBg} onChange={(evt) => setNodeBg(evt.target.value)} /><div className="updatenode__checkboxwrapper"><label>是否隐藏:</label>{/* <Switch checked={nodeInfo.isHidden} onChange={setNodeHidden} /> */}<input type='checkbox' checked={nodeInfo.isHidden} onChange={(evt) => setNodeHidden(evt.target.checked)} /></div></div>) : (<></>);
};

4、edgeContent.tsx

import React, { useState, useEffect } from 'react';
import { Input, Select, Switch } from 'antd';const { Option } = Select;export type edgeProps = {info: any;onChange: (val: any) => void;
};export default ({ info, onChange }: edgeProps) => {const [edgeInfo, setEdgeInfo] = useState<any>({});const edgeTypes = [{ label: '曲线', value: 'default' },{ label: '直线', value: 'straight' },{ label: '直角线', value: 'step' },{ label: '圆滑直角线', value: 'smoothstep' },];useEffect(() => {if (info.id) {if (info.style) {info.color = info.style.stroke;}if (!info.isHidden) {info.isHidden = false;}setEdgeInfo(info);}}, [info.id]);// 改变名称const setNodeName = (value: string) => {setEdgeInfo({...edgeInfo,label: value,});onChange({...edgeInfo,label: value,});};// 改变颜色const setNodeBg = (value: string) => {setEdgeInfo({...edgeInfo,color: value,});onChange({...edgeInfo,color: value,});};// 改变类型const changeEdgeType = (value: string) => {setEdgeInfo({...edgeInfo,type: value,});onChange({...edgeInfo,type: value,});};// 是否隐藏const setEdgeHidden = (value: boolean) => {setEdgeInfo({...edgeInfo,isHidden: value,});onChange({...edgeInfo,isHidden: value,});};return edgeInfo.id ? (<div className="updatenode__controls"><label>连接线名称:</label><Inputplaceholder=""value={edgeInfo.label}onChange={(evt) => setNodeName(evt.target.value)}/><label className="updatenode__bglabel">连接线颜色:</label><Input type="color" value={edgeInfo.color} onChange={(evt) => setNodeBg(evt.target.value)} /><div className="updatenode__checkboxwrapper"><label>连接线类型:</label><Select defaultValue="曲线 " value={edgeInfo.type} onChange={changeEdgeType}>{edgeTypes.map((item) => (<Option value={item.value} key={item.value}>{item.label}</Option>))}</Select></div><div className="updatenode__checkboxwrapper"><label>是否隐藏:</label><Switch checked={edgeInfo.isHidden} onChange={setEdgeHidden} /></div></div>) : (<></>);
};

5、ResizableNodeSelected.tsx

import { memo } from 'react';
import { Handle, Position, NodeResizer } from 'reactflow';const ResizableNodeSelected = ({ data, selected }) => {return (<><NodeResizer color="#F3A011" isVisible={selected} minWidth={80} minHeight={80} /><divstyle={{// width: 60,// height: 60,padding: 10,// display: "flex",// justifyContent: "center",// alignItems: "center",// fontSize: 2}}>{data.label}</div><Handle style={{ opacity: 0 }} type="source" position={Position.Top} id='a' /><Handle style={{ opacity: 0 }} type="source" position={Position.Right} id='b' /><Handle style={{ opacity: 0 }} type="source" position={Position.Bottom} id='c' /><Handle style={{ opacity: 0 }} type="source" position={Position.Left} id='d' /></>);
};export default memo(ResizableNodeSelected);

6、data.js

export const nodes = [{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 } },{ "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 },{ "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 } },{ "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 } },{ "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 },{ "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 } }
];export const edges = [{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 },{ "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 }
]// "viewport": { "x": 654.5507940552135, "y": -54.945769269730704, "zoom": 1.6908994642667994 } }

7、package.json

{"name": "my-react-flow-app","private": true,"version": "0.0.0","type": "module","scripts": {"dev": "vite","build": "vite build","lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0","preview": "vite preview"},"dependencies": {"antd": "^5.7.1","react": "^18.2.0","react-dom": "^18.2.0","reactflow": "^11.7.4"},"devDependencies": {"@types/react": "^18.2.14","@types/react-dom": "^18.2.6","@vitejs/plugin-react": "^4.0.1","eslint": "^8.44.0","eslint-plugin-react": "^7.32.2","eslint-plugin-react-hooks": "^4.6.0","eslint-plugin-react-refresh": "^0.4.1","vite": "^4.4.0"}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/15519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

享元模式——实现对象的复用

1、简介 1.1、概述 当一个软件系统在运行时产生的对象数量太多&#xff0c;将导致运行代价过高&#xff0c;带来系统性能下降等问题。例如&#xff0c;在一个文本字符串中存在很多重复的字符&#xff0c;如果每个字符都用一个单独的对象来表示&#xff0c;将会占用较多的内存…

39.手机导航

手机导航 html部分 <div class"phone"><div class"content"><img class"active" src"./static/20180529205331_yhGyf.jpeg" alt"" srcset""><img src"./static/20190214214253_hsjqw…

【CNN-BiLSTM-attention】基于高斯混合模型聚类的风电场短期功率预测方法(Pythonmatlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

测试|自动化测试(了解)

测试|自动化测试&#xff08;了解&#xff09; 1.什么是自动化测试☆☆☆☆ 自动化测试相当于把人工测试手段进行转换&#xff0c;让代码执行。 2.自动化测试的分类☆☆☆☆ 注&#xff1a;这里只是常见的自动化测试&#xff0c;并不全部罗列。 1.单元自动化测试 其中Java…

嵌入式硬件系统的基本组成

嵌入式硬件系统的基本组成 嵌入式系统的硬件是以包含嵌入式微处理器的SOC为核心&#xff0c;主要由SOC、总线、存储器、输入/输出接口和设备组成。 嵌入式微处理器 每个嵌入式系统至少包含一个嵌入式微处理器 嵌入式微处理器体系结构可采用冯.诺依曼&#xff08;Von Neumann&…

前后端分离实现博客系统

文章目录 博客系统前言1. 前端1.1 登陆页面1.2 博客列表页面1.3 博客详情页面1.4 博客编辑页面 2. 后端2.1 项目部署2.1.1 创建maven项目2.1.2 引入依赖2.1.3 创建目录结构2.1.4 部署程序 2.2 逻辑设计2.2.1 数据库设计2.2.2 实体类设计2.2.3 Dao层设计2.2.3.1 BlogDao 2.2.4 D…

qt添加图标

1.添加资源 选择QtWidgetsApp.qrc文件打开 添加图标文件路径 添加图标文件 2.按钮添加图标 图标路径为:/res/res/swicth.jpg &#xff08;1&#xff09;代码设置图标 ui.pushButton_OPen->setIcon(QIcon(":/res/res/swicth.jpg")); &#xff08;2&#xff09;属…

apple pencil到底值不值得买?好用的iPad电容笔

随着ipad平板型号版本的不断更新&#xff0c;其的功能越来越多&#xff0c;现在它的性能已经可以和笔记本电脑相媲美了。而现在&#xff0c;随着技术的进步&#xff0c;IPAD已经不再是单纯的娱乐&#xff0c;而是一种功能强大的学习、绘画、工作等等。要增加生产效率&#xff0…

【数据结构与算法】归并排序

归并排序 归并排序&#xff08;MERGE-SORT&#xff09;是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治&#xff08;divide-and-conquer&#xff09;策略&#xff08;分治法将问题分&#xff08;divide&#xff09;成一些小的问题然后递归求解&#xff0c;而…

stm32内存杂记

从上图中可以看出SRAM空间用来存放&#xff1a;1.各个文件中声明和定义的全局变量、静态数据和常量&#xff1b;2.未初始化的全局变量&#xff1b;3.HEAP区&#xff1b;4.STACK区 这是在.map文件中&#xff0c;双击工程target打开 堆栈是处于以0x2000xx地址处的 EQU伪代码&…

学C的第三十一天【通讯录的实现】

相关代码gitee自取&#xff1a;C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十天【自定义类型&#xff1a;结构体、枚举、联合】_高高的胖子的博客-CSDN博客 通讯录需求&#xff1a; 实现一个通讯录&#xff0c; 通讯录中存放保存人的信息&#xff1…

华为鸿蒙4本周发布:官方海报大有玄机!告别“人工智障”!

一年一度的华为开发者大会2023(HDC.Together)将于8月4日至8月6日在东莞松山湖举办。相比去年&#xff0c;今年的华为开发者大会足足提前了三个月&#xff0c;而本次大会主角之一无疑是全新国产操作系统鸿蒙4&#xff08;HarmonyOS 4&#xff09;。 官方之前用了三个词来形容鸿蒙…

C#文件操作从入门到精通(1)——INI文件操作

点击这里:微软官方文档查看writePrivateProfileString函数定义 常见错误: 1、中文路径写入失败,为啥? 2、文件不是全路径,只有文件名也会写入失败: 3、GetLastError怎么使用? GetLastError错误代码含义: (0)-操作成功完成。 (1)-功能错误。 (2)- 系统找不到指定的文件…

3个命令定位CPU飙高

top 指令找出消耗CPU最厉害的那个进程的pid top -H -p 进程pid 找出耗用CPU资源最多的线程pid printf ‘0x%x\n’ 线程pid 将线程pid转换为16进制 结合jstack 找出哪个代码有问题 jstack 进程pid | grep 16进制的线程pid -A 多少行日志 jstack 进程pid | grep 16进制的线程…

C语言指针进阶-1

本篇文章带来 1. 字符指针 2. 数组指针 3. 指针数组的相关知识详细讲解&#xff01; 如果您觉得文章不错&#xff0c;期待你的一键三连哦&#xff0c;你的鼓励是我创作的动力之源&#xff0c;让我们一起加油&#xff0c;一起奔跑&#xff0c;让我们顶峰相见&#xff01;&#…

04 http连接处理(上)

基础知识&#xff1a;epoll、http报文格式、状态码和有限状态机 代码&#xff1a;对服务端处理http请求的全部流程进行简要介绍&#xff0c;然后结合代码对http类及请求接收进行详细分析。 epoll epoll_create函数 #include <sys/epoll.h> int epoll_create(int size)…

【业务功能篇55】Springboot+easyPOI 导入导出

Apache POI是Apache软件基金会的开源项目&#xff0c;POI提供API给Java程序对Microsoft Office格式档案读和写的功能。 Apache POI 代码实现复杂&#xff0c;学习成本较高。 Easypoi 功能如同名字easy,主打的功能就是容易,让一个没见接触过poi的人员 就可以方便的写出Excel导出…

【计算机网络】408统考2014年题36

题目描述 【2014年题36】主机甲与主机乙之间使用后退N帧(GBN)协议传输数据&#xff0c;甲的发送窗口尺寸为1000&#xff0c;数据帧长为1000字节&#xff0c;信道带宽为100Mbps&#xff0c;乙每收到一个数据帧就立即利用一个短帧&#xff08;忽略其传输延迟&#xff09;进行确认…

Banana Pi BPI-KVM – 基于 Rockchip RK3568 SoC 的 KVM over IP 解决方案

Banana Pi 已经开始开发基于 Rockchip RK3568 SoC 的 BPI-KVM 盒&#xff0c;但它不是迷你 PC&#xff0c;而是 KVM over IP 解决方案&#xff0c;旨在远程控制另一台计算机或设备&#xff0c;就像您在现场一样&#xff0c;例如能够打开和关闭连接的设备、访问 BIOS 等。 商业…

eda、gnm、anm究竟是个啥?

安装prody pip install prody -i https://pypi.tuna.tsinghua.edu.cn/simpleeda、anm、gnm eda(essential dynamics analysis) 另一个名字PCA(Principal Component Analysis) 或 NMA(Normal Mode Analysis)。 eda分析可以帮助人们理解生物大分子基本的运动模式和构象变化。…