react-flow基础使用及dagre库的使用

news/2024/10/23 5:51:40/

前言

最近项目中需要用到拓扑图的展示,最开始选用的是antv的拓扑图组件。antv组件虽然此很方便,但是在布局的时候总是会有莫名其妙的bug,然后自己也想法去解决(看前辈经验、官方issue),最后还是不能解决。于是更换了组件库,也就是我们今天的主角:react-flow。

react-flow简介

React Flow 是一个基于 React 的用于构建可视化流程图和图形编辑器的库。它提供了一个灵活的、可扩展的组件集合,使开发者可以轻松地创建交互式的流程图和图形编辑器应用。

react-flow特点

  1. 可视化流程图: React Flow 提供了一个易于使用的组件集合,用于创建流程图和图形编辑器。您可以使用这些组件来构建节点、边缘和连接线,以及定义它们之间的关系。
  2. 拖放支持: React Flow 支持节点和边缘的拖放操作,使用户可以方便地调整它们的位置和连接关系。您可以自定义节点和边缘的外观和行为,以适应您的应用需求。
  3. 布局算法: React Flow 内置了多种布局算法(部分收费),例如树形布局、网格布局和自由布局,可以帮助您自动排列和布局图形元素。这些算法可以根据图形的结构和属性自动调整节点的位置,使图形看起来更整齐和美观。
  4. 交互性: React Flow 提供了丰富的交互功能,包括缩放、平移、选择、多选、编辑和删除等。您可以根据需要启用或禁用这些交互功能,以创建符合用户需求的可交互图形编辑器。
  5. 事件处理: React Flow 提供了事件处理机制,允许您监听和响应图形元素的各种事件,例如节点的拖动、边缘的创建和删除等。您可以根据这些事件来实现自定义的业务逻辑和交互行为。
  6. 可定制性: React Flow 具有高度可定制性,您可以通过自定义组件、样式和配置选项来调整其外观和行为。这使得您可以根据自己的设计和需求来创建独特的图形编辑器应用。

react-flow例子

安装

tyarn add react-flow-renderer

使用

import React, { useCallback } from "react";
import ReactFlow, { useNodesState, useEdgesState, updateEdge } from "reactflow";import { TrialCmdWrapper } from "@/pages/trial/style";
import { FlowContent } from "./style";import "reactflow/dist/style.css";
import { useMemo } from "react";
import CuFlowNode from "@/components/Home/resTopo/topo/node";const initialNodes = [{id: "root",type: "input",data: { label: "全局节点" },position: { x: 0, y: 0 }},{id: "horizontal-2",sourcePosition: "right",targetPosition: "left",data: { label: "A Node" },position: { x: 250, y: 0 }},{id: "horizontal-3",sourcePosition: "right",targetPosition: "left",data: { label: "Node 3" },position: { x: 250, y: 160 }},{id: "horizontal-4",sourcePosition: "right",targetPosition: "left",data: { label: "Node 4" },position: { x: 500, y: 0 }},{id: "horizontal-5",sourcePosition: "top",targetPosition: "bottom",data: { label: "Node 5" },position: { x: 500, y: 100 }},{id: "horizontal-6",sourcePosition: "bottom",targetPosition: "top",data: { label: "Node 6" },position: { x: 500, y: 230 }},{id: "horizontal-7",sourcePosition: "right",targetPosition: "left",data: { label: "Node 7" },position: { x: 750, y: 50 }},{id: "horizontal-8",sourcePosition: "right",targetPosition: "left",data: { label: "Node 8" },position: { x: 750, y: 300 }}
];const initialEdges = [{id: "horizontal-e1-2",source: "root",type: "smoothstep",target: "horizontal-2",animated: true},{id: "horizontal-e1-3",source: "root",type: "smoothstep",target: "horizontal-3",animated: true},{id: "horizontal-e1-4",source: "horizontal-2",type: "smoothstep",target: "horizontal-4",label: "edge label"},{id: "horizontal-e3-5",source: "horizontal-3",type: "smoothstep",target: "horizontal-5",animated: true},{id: "horizontal-e3-6",source: "horizontal-3",type: "smoothstep",target: "horizontal-6",animated: true},{id: "horizontal-e5-7",source: "horizontal-5",type: "smoothstep",target: "horizontal-7",animated: true},{id: "horizontal-e6-8",source: "horizontal-6",type: "smoothstep",target: "horizontal-8",animated: true}
];export default function TrialFlowContent({ width, height }) {// 图操作const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);const onEdgeUpdate = useCallback((oldEdge, newConnection) => setEdges(els => updateEdge(oldEdge, newConnection, els)), []);// const onConnect = useCallback(params => setEdges(els => addEdge(params, els)), []);const nodeTypes = useMemo(() => ({ textUpdater: CuFlowNode }), []);const onConnect = () => {// 禁止手动连线return;};return (<TrialCmdWrapperheight={height}width={width}style={{padding: 0,float: "left",marginLeft: "15px"}}><FlowContent><ReactFlownodeTypes={nodeTypes}nodes={nodes}edges={edges}onNodesChange={onNodesChange}onEdgesChange={onEdgesChange}onConnect={onConnect}onEdgeUpdate={onEdgeUpdate}></ReactFlow></FlowContent></TrialCmdWrapper>);
}

 效果

dagre布局库使用

安装

tyarn add dagre

使用

组件外新增代码

// dagre 数据
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));const nodeWidth = 172;
const nodeHeight = 36;const getLayoutedElements = (nodes, edges, direction = "TB") => {const isHorizontal = direction === "LR";dagreGraph.setGraph({ rankdir: direction });nodes.forEach(node => {dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });});edges.forEach(edge => {dagreGraph.setEdge(edge.source, edge.target);});dagre.layout(dagreGraph);nodes.forEach(node => {const nodeWithPosition = dagreGraph.node(node.id);node.targetPosition = isHorizontal ? "left" : "top";node.sourcePosition = isHorizontal ? "right" : "bottom";// We are shifting the dagre node position (anchor=center center) to the top left// so it matches the React Flow node anchor point (top left).node.position = {x: nodeWithPosition.x - nodeWidth / 2,y: nodeWithPosition.y - nodeHeight / 2};return node;});return { nodes, edges };
};

 组件内部新增方法

const setTreeTopoData = (nodes, edges, direction = "TB") => {const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges, direction);setNodes([...layoutedNodes]);setEdges([...layoutedEdges]);};

使用方法

useEffect(() => {setTreeTopoData(nodes, edges);}, []);

 最终代码

import React, { useCallback } from "react";
import ReactFlow, { useNodesState, useEdgesState, updateEdge } from "reactflow";import { TrialCmdWrapper } from "@/pages/trial/style";
import { FlowContent } from "./style";import "reactflow/dist/style.css";
import { useRef } from "react";
import { useEffect } from "react";
import { useMemo } from "react";
import CuFlowNode from "@/components/Home/resTopo/topo/node";
import dagre from "dagre";const initialNodes = [{id: "root",type: "input",data: { label: "全局节点" },position: { x: 0, y: 0 }},{id: "horizontal-2",sourcePosition: "right",targetPosition: "left",data: { label: "A Node" },position: { x: 250, y: 0 }},{id: "horizontal-3",sourcePosition: "right",targetPosition: "left",data: { label: "Node 3" },position: { x: 250, y: 160 }},{id: "horizontal-4",sourcePosition: "right",targetPosition: "left",data: { label: "Node 4" },position: { x: 500, y: 0 }},{id: "horizontal-5",sourcePosition: "top",targetPosition: "bottom",data: { label: "Node 5" },position: { x: 500, y: 100 }},{id: "horizontal-6",sourcePosition: "bottom",targetPosition: "top",data: { label: "Node 6" },position: { x: 500, y: 230 }},{id: "horizontal-7",sourcePosition: "right",targetPosition: "left",data: { label: "Node 7" },position: { x: 750, y: 50 }},{id: "horizontal-8",sourcePosition: "right",targetPosition: "left",data: { label: "Node 8" },position: { x: 750, y: 300 }}
];const initialEdges = [{id: "horizontal-e1-2",source: "root",type: "smoothstep",target: "horizontal-2",animated: true},{id: "horizontal-e1-3",source: "root",type: "smoothstep",target: "horizontal-3",animated: true},{id: "horizontal-e1-4",source: "horizontal-2",type: "smoothstep",target: "horizontal-4",label: "edge label"},{id: "horizontal-e3-5",source: "horizontal-3",type: "smoothstep",target: "horizontal-5",animated: true},{id: "horizontal-e3-6",source: "horizontal-3",type: "smoothstep",target: "horizontal-6",animated: true},{id: "horizontal-e5-7",source: "horizontal-5",type: "smoothstep",target: "horizontal-7",animated: true},{id: "horizontal-e6-8",source: "horizontal-6",type: "smoothstep",target: "horizontal-8",animated: true}
];// dagre 数据
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));const nodeWidth = 172;
const nodeHeight = 36;const getLayoutedElements = (nodes, edges, direction = "TB") => {const isHorizontal = direction === "LR";dagreGraph.setGraph({ rankdir: direction });nodes.forEach(node => {dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });});edges.forEach(edge => {dagreGraph.setEdge(edge.source, edge.target);});dagre.layout(dagreGraph);nodes.forEach(node => {const nodeWithPosition = dagreGraph.node(node.id);node.targetPosition = isHorizontal ? "left" : "top";node.sourcePosition = isHorizontal ? "right" : "bottom";// We are shifting the dagre node position (anchor=center center) to the top left// so it matches the React Flow node anchor point (top left).node.position = {x: nodeWithPosition.x - nodeWidth / 2,y: nodeWithPosition.y - nodeHeight / 2};return node;});return { nodes, edges };
};export default function TrialFlowContent({ width, height }) {// 拖拽相关const dropDomRef = useRef(null);const setTreeTopoData = (nodes, edges, direction = "TB") => {const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges, direction);setNodes([...layoutedNodes]);setEdges([...layoutedEdges]);};// 图操作const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);const onEdgeUpdate = useCallback((oldEdge, newConnection) => setEdges(els => updateEdge(oldEdge, newConnection, els)), []);// const onConnect = useCallback(params => setEdges(els => addEdge(params, els)), []);const nodeTypes = useMemo(() => ({ textUpdater: CuFlowNode }), []);const onConnect = () => {// 禁止手动连线return;};useEffect(() => {setTreeTopoData(nodes, edges);}, []);return (<TrialCmdWrapperheight={height}width={width}style={{padding: 0,float: "left",marginLeft: "15px"}}><FlowContent ref={dropDomRef}><ReactFlownodeTypes={nodeTypes}nodes={nodes}edges={edges}onNodesChange={onNodesChange}onEdgesChange={onEdgesChange}onConnect={onConnect}onEdgeUpdate={onEdgeUpdate}></ReactFlow></FlowContent></TrialCmdWrapper>);
}

展示效果

通过dagre,实现了自动树形布局的功能

原文地址

react-flow基础使用及dagre库的使用-小何博客前言最近项目中需要用到拓扑图的展示,最开始选用的是antv的拓扑图组件。antv组件虽然此很方便,但是在布局的时候总是会有莫名其妙的bug,然后自己也想法去解决(看前辈经验、官方issue),最后还是不能解决。于…https://ligo100.cn/qianduanjishu/531.html


http://www.ppmy.cn/news/823501.html

相关文章

解决罗技鼠标G403拖动Office时出现的窗口掉帧问题

我们在使用一些像G403这样的鼠标时&#xff0c;有时候会发现打开office编辑&#xff0c;拖动窗口时会出现严重掉帧现象 这是由于中高端鼠标的高回报率造成的&#xff0c;可以打开鼠标驱动程序&#xff0c;将鼠标回报率修改到120HZ&#xff08;较低的回报率&#xff09;&#x…

tf.contrib.training.HParams在tensorflow2.0版本以上失效的解决

tf.contrib.training.HParams在tensorflow2.0版本以上失效的解决_我也想学习的博客-CSDN博客 1. # Copyright 2016 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this fi…

ASPICE软件工具链之Jira教程

Jira使用教程 一、什么是Jira? 二、Jira的使用教程 功能介绍: 创建工作流 工作流方案 设置字段流程 字段配置 界面方案 界面方案创建流程 问题类型界面方案 将项目与预先创建的方案关联 配置总流程 创建项目 设置项目 添加工作流 添加界面配置方案 设置Scrum 看板泳道图 一…

服务器受美国保护网站,该网站服务器受美国保护

裘精 曾子曰&#xff1a;“身也者&#xff0c;父母之遗体也。行父母之遗体&#xff0c;敢不敬乎&#xff1f;居处不庄&#xff0c;非孝也&#xff1b;事君不忠&#xff0c;非孝也&#xff1b;莅官不敬&#xff0c;非孝也&#xff1b;朋友不信&#xff0c;非孝也&#xff1b;战陈…

维护服务器的内容,服务器日常维护的主要内容有哪些?

1.服务器硬件维护: 硬件方面的维护不外乎就是一些增加和卸载设备、更换设备以及设备除尘、防火防潮等工作。 首先一点增加内存和硬盘容量的工作。我们都知道&#xff0c;增加内存是再常见不过的&#xff0c;当服务器安装的应用程序增多时&#xff0c;网络资源提升时&#xff0c…

网站的更新与维护

虽然有些用户也会对网站进行必要的更新维护&#xff0c;但是更新却没有任何规律&#xff0c;这对面向营销的网站来说是致命的。因为让搜索引擎找不到规律&#xff0c;不利于网站内容被搜索引擎及时抓取。对于一些小公司的网站来说&#xff0c;由于自身的权重比较低而且网站内容…

服务器显示屏出现白屏,win10开机白屏不显示桌面怎么办_网站服务器运行维护,win10,白屏,桌面...

win7如何使用自带录制视频软件&#xff1f;_网站服务器运行维护 win7使用自带录制视频软件的方法&#xff1a;首先打开运行窗口输入cmd&#xff1b;然后管理员界面中输入【psr.exe】或者psr回车确定打开&#xff0c;并在工具上点击开始记录&#xff1b;最后点击停止记录并弹出保…

电脑服务器显示过期,win10系统提示你的设备存在过期风险怎么办_网站服务器运行维护,win10...

win7系统安装后无网络适配器怎么办_网站服务器运行维护 win7系统安装后无网络适配器的解决方法是&#xff1a;1、打开控制面板&#xff0c;进入【设备管理器】&#xff1b;2、右键点击异常的驱动程序&#xff0c;选择【更新驱动程序】&#xff1b;3、选择【浏览我的计算机以查找…