首页 > 其他分享 >使用react-flow制作流程图

使用react-flow制作流程图

时间:2023-05-25 11:33:07浏览次数:48  
标签:连接线 流程图 flow label react item import id

1.react-flow

 react-flow是一个用于构建基于节点的应用程序的库。这些可以是简单的静态图或复杂的基于节点的编辑器。同时react-flow支持自定义节点类型和边线类型,并且它附带一些组件,可以查看缩略图的Mini Map和悬浮控制器Controls.

2.react-flow安装  

  npm install react-flow-renderer    # npm
  yarn add react-flow-renderer       # Yarn
3.react-flow基本使用  

  1、每个节点固定格式 里面添加内容

  代码

      index.tsx

import React from 'react';
import ReactFlow, {
  addEdge,
  MiniMap,
  Controls,
  Background,
  useNodesState,
  useEdgesState,
} from 'react-flow-renderer';

import { nodes as initialNodes, edges as initialEdges } from './initial-elements';

const OverviewFlow = () => {
  const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
  const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
  const onConnect = (params) => setEdges((eds) => addEdge(params, eds));

  return (
    <ReactFlow
      nodes={nodes} // 节点
      edges={edges} // 连接线
      onNodesChange={onNodesChange} // 节点拖拽等改变
      onEdgesChange={onEdgesChange} // 连接线拖拽等改变
      onConnect={onConnect} // 节点直接连接
      fitView // 渲染节点数据
      attributionPosition="top-right" // react-flow的位置,类似水印,可以通过css隐藏
    >
      // 背景图 可以配置颜色 方格宽度
      <Background color="#aaa" gap={16} />
    </ReactFlow>
  );
};

export default OverviewFlow;

initial-elements.ts节点与连接线数据

import { MarkerType } from 'react-flow-renderer';

export const nodes = [
  {
    id: '1', // id必须
    type: 'input', // 类型: input开始  default默认  output结束 区别在于连接点不一样
    data: { // 额外的数据
      label: ( // 节点名称
        <>
          Welcome to <strong>React Flow!</strong>
        </>
      ),
      // value: 5, .... // 可以将其他数据放入
    },
    position: { x: 250, y: 0 }, // 节点位置
  },
  {
    id: '2',
    data: {
      label: (
        <>
          This is a <strong>default node</strong>
        </>
      ),
    },
    position: { x: 100, y: 100 },
  },
  {
    id: '3',
    data: {
      label: (
        <>
          This one has a <strong>custom style</strong>
        </>
      ),
    },
    position: { x: 400, y: 100 },
    style: {
      background: '#D6D5E6',
      color: '#333',
      border: '1px solid #222138',
      width: 180,
    },
  },
  {
    id: '4',
    position: { x: 250, y: 200 },
    data: {
      label: 'Another default node',
    },
  },
  {
    id: '5',
    data: {
      label: 'Node id: 5',
    },
    position: { x: 250, y: 325 },
  },
  {
    id: '6',
    type: 'output',
    data: {
      label: (
        <>
          An <strong>output node</strong>
        </>
      ),
    },
    position: { x: 100, y: 480 },
  },
  {
    id: '7',
    type: 'output',
    data: { label: 'Another output node' },
    position: { x: 400, y: 450 },
  },
];

export const edges = [
  { id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
  { id: 'e1-3', source: '1', target: '3' },
  {
    id: 'e3-4', // id必须
    source: '3', // 连接线起始节点id
    target: '4', // 连接线结束节点id
    animated: true, // 连接线是否有动画
    label: 'animated edge', // 连接线名称
  },
  {
    id: 'e4-5',
    source: '4',
    target: '5',
    label: 'edge with arrow head',
    markerEnd: { // 连接线尾部的箭头
      type: MarkerType.ArrowClosed,
    },
  },
  {
    id: 'e5-6',
    source: '5',
    target: '6',
    type: 'smoothstep', // 连接线类型 default straight step smoothstep
    label: 'smooth step edge',
  },
  {
    id: 'e5-7',
    source: '5',
    target: '7',
    type: 'step',
    style: { stroke: '#f6ab6c' }, // 连接线颜色
    label: 'a step edge',
    animated: true,
    labelStyle: { fill: '#f6ab6c', fontWeight: 700 }, // 连接线名称样式
  },
];

  效果图

 

2、自定义每个节点中的内容和样式 以及连接点

  这个是静态的 展示流程图 想拖动节点 加上1里面的 onNodesChange... 的参数即可

index.tsx

import React, {useEffect} from 'react';

import ReactFlow, {
    useNodesState,
    useEdgesState,
} from 'react-flow-renderer';

import {nodes as initialNodes, edges as initialEdges} from './initial-elements';
import CustomNode from './ResizableNode'; //自定义的渲染每个节点的代码

const nodeTypes = {
    custom: CustomNode, //自定义的内容
};
const OverviewFlow = ({resizeFlag}: any) => {
    const [nodes, setNodes] = useNodesState(initialNodes);
    const [edges] = useEdgesState(initialEdges);

    useEffect(() => {
        setNodes([]);
        setTimeout(() => {
            setNodes(initialNodes);
        }, 50);
    }, [resizeFlag]);

    if (!nodes?.length) {
        return null;
    }

    return (
        <ReactFlow
            nodes={nodes} // 节点
            edges={edges} // 连接线
            panOnDrag={false}
            zoomOnDoubleClick={false}
            zoomOnPinch={false}
            zoomOnScroll={false}
            panOnScroll={false}
            fitView // 渲染节点数据
            nodeTypes={nodeTypes}
            attributionPosition="top-left" // react-flow的位置,类似水印,可以通过css隐藏 =》 .react-flow__attribution.left {display: none};
        >
            {/* <Background color="#aaa" gap={16} /> */}
        </ReactFlow>
    );
};

export default OverviewFlow;

 initial-elements.ts

import {MarkerType, Position} from 'react-flow-renderer';

const styles = {
    color: '#333',
    border: '1px solid #4E8FF0',
    borderRadius: '5px',
    background: 'white',

};
//因为数据太多删除了几个 不过格式都是这样写 export const nodes = [ { id: '0', type: 'custom',//有input,output,default三种,input只有一个输出,output只有一个输入,default输入输出各有一个 或者自定义的 data: { label: '', }, position: {x: -20, y: 40}, // 节点位置 style: { width: 1550, height: 500, border: '1px solid #91caff', borderRadius: '15px', color: '#4585F2', background: '#E2E6F3', zIndex: -2, }, }, { id: '1', // id必须 type: 'custom', // 类型: input开始 default默认 output结束 区别在于连接点不一样 data: { // 额外的数据 label: '任务1', // value: 1 // .... // 可以将其他数据放入 }, position: {x: 200, y: 70}, // 节点位置 style: { width: 200, height: 150, ...styles, }, }, { id: '2', type: 'custom', data: { label: '任务2', }, position: {x: 450, y: 70}, style: { width: 200, height: 150, }, }, { id: '3', type: 'custom', data: { label: ( '任务3' ), }, position: {x: 700, y: 70}, style: { width: 200, height: 150, ...styles, }, } ]; export const edges = [ { id: '1-2', source: '1', target: '2', markerEnd: { // 连接线尾部的箭头 type: MarkerType.ArrowClosed, color: '#4E8FF0', }, style: {stroke: '#4E8FF0'}, // 连接线颜色 labelStyle: {fill: '#4E8FF0', fontWeight: 700}, // 连接线名称样式 }, { id: '2-3', // id必须 source: '2', // 连接线起始节点id target: '3', // 连接线结束节点id markerEnd: { // 连接线尾部的箭头 type: MarkerType.ArrowClosed, color: '#4E8FF0', }, style: {stroke: '#4E8FF0'}, // 连接线颜色 labelStyle: {fill: '#4E8FF0', fontWeight: 700}, // 连接线名称样式 }, { id: '3-4', source: '3', target: '4', style: {stroke: '#4E8FF0'}, // 连接线颜色 labelStyle: {fill: '#4E8FF0', fontWeight: 700}, // 连接线名称样式 markerEnd: { // 连接线尾部的箭头 type: MarkerType.ArrowClosed, color: '#4E8FF0', }, } ];

 

ResizableNode.tsx
import React, {memo} from 'react';
import {Handle, Position} from 'react-flow-renderer';
import className from './home.module.scss';
import newTask from '@/static/newTask.png';
import Operator from '@/static/OperatorConfig.png';
import DeployTask from '@/static/DeploymentTask.png';
import TaskReview from '@/static/TaskReview.png';
import TaskLaunch from '@/static/TaskLaunch.png';
import {Button} from 'antd';

const datadevelopment = [
    {
        id: '0',
    },
    {
        src: newTask,
        id: '1',
        button: '快速开始',
        url: '',
        width: '50px',
        height: '50px',
    },
    {
        src: Operator,
        id: '11',
        button: '配置说明',
        link: '',
        width: '45px',
        height: '45px',
    },
    {
        src: DeployTask,
        id: '3',
        title: '任务基本信息',
        width: '55px',
        height: '55px',
    },

];

export default memo(({data, id, isConnectable}: any) => {

    // console.log(1, data);
    const position = (sum: any) => {
        switch (sum) {
            case '6':
                return Position.Right;
            case '9':
                return Position.Top;
            default:
                return Position.Left;
        }
    };

    const pageButton = (item: any) => {
        if (item.link) {
            return (
                <Button
                    target='_blank'
                    type='link'
                    htmlType='button'
                    href={item.link}
                > {item.button}
                </Button>
            );
        } else {
            return (
                <Button
                    style={{
                        background: 'linear-gradient(90deg,#2468E8,#2C61E4,#4148D0,#5127B8)',
                        border: 'none',
                    }}
                    onClick={e => {
                        e.stopPropagation();
                        window.location.hash = item.url;
                    }}
                    type='primary'
                > {item.button}
                </Button>
            );
        }
    };

    return (
        <div className={className.ResicabelNode}>
            <Handle
                style={{visibility: 'hidden'}}
                type="target"
                position={position(id)}
                isConnectable={isConnectable}
            />
            {
                datadevelopment.filter((item: any) => {
                    return item.id === id;
                }).map((item: any) => {
                    return (
                        +item.id < 12
                            ? <div
                                key={item.id}
                                className={className.nodeContent}
                                style={data.style}
                            >
                                {item.src ? <img style={{width: item.width, height: item.height}} src={item.src} /> : null}
                                <div className={className.nodeRightbox}>
                                    <p className={className.nodelabel}>{data.label}</p>
                                    {item.button
                                        ? pageButton(item)
                                        : <span className={className.nodelabelTitle}>{item.title}</span>}
                                </div>
                            </div>
                            : <div
                                key={item.id}
                                className={className.dataDistribution}
                                style={data.style}
                            >
                                {
                                    item.order
                                        ? <p className={className.circle}>
                                            {item.order}
                                        </p> : null
                                }
                                <p className={className.nodelabel}>{data.label}</p>
                                {
                                    item.button ? pageButton(item) : null
                                }
                            </div>
                    );
                })
            }
            <Handle
                style={{visibility: 'hidden'}}
                type='source'
                position={id === '11'
                || id === '5' ? Position.Bottom : Position.Right}
                id='a'
                className='my_handle'
                isConnectable={isConnectable}
            />
        </div>
    );
});

 

 效果图

 

 收集的一些关于 react-flow 参数讲解链接以及官网地址

  https://www.5axxw.com/wiki/content/obkffc

   https://reactflow.dev/

 

标签:连接线,流程图,flow,label,react,item,import,id
From: https://www.cnblogs.com/qing1224/p/17430652.html

相关文章

  • Graph Normalizing Flows
    目录概符号说明GraphNormalizingFlowsGRevNetsLiuJ.,KumarA.,BaJ.,KirosJ.andSwerskyK.Graphnormalizingflows.NIPS,2019.概基于flows的图的生成模型.符号说明\(\mathcal{G}=(H,\Omega)\),图;\(H=(\mathbf{h}^{(1)},\cdots,\mathbf{h}^{(N)})......
  • 【React工作记录六十四】ant design中rowKey的作用
     目录前言导语核心代码总结前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从头再来歌谣的意志是永恒的放弃很容易但是坚持一定很酷导语antdesign中rowke......
  • 【React工作记录六十五】ant design子组件渲染不能及时渲染
     目录前言导语核心代码总结前言我是歌谣我有个兄弟巅峰的时候排名c站总榜19叫前端小歌谣曾经我花了三年的时间创作了他现在我要用五年的时间超越他今天又是接近兄弟的一天人生难免坎坷大不了从头再来歌谣的意志是永恒的放弃很容易但是坚持一定很酷导语antdesign子组件......
  • 使用 TensorFlow 自动微分和神经网络功能估算线性回归的参数(Estimate parameters for
    大多数的深度学习框架至少都会具备以下功能:(1)张量运算(2)自动微分(3)神经网络及各种神经层TensorFlow框架亦是如此。在《深度学习全书公式+推导+代码+TensorFlow全程案例》——洪锦魁主编清华大学出版社ISBN978-7-302-61030-4这本书第3章《TensorFlow架构与主要功能》这一......
  • APP中RN页面渲染流程-ReactNative源码分析
    在APP启动后,RN框架开始启动。等RN框架启动后,就开始进行RN页面渲染了。RN页面原生侧页面渲染的主要逻辑实现是在RCTUIManager和RCTShadowView完成的。通过看UIMananger的源码可以看到,UIMananger导出给JS端的API接口在对UI的操作上,基本都会同时对View和ShadowView进行操作。......
  • [React Typescript] useRef with HTML Elements
    Reactsetthereftonullinruntime.Itisalimitationnowforreact.import{useRef}from'react';exportconstComponent=()=>{constref=useRef<HTMLDivElement>(null);return<divref={ref}/>;}; ......
  • 解决使用输入法输入在 React input 框中的问题
    问题在使用React绑定input输入框的onChange方法时,如果使用中文输入法(或者其他输入法),会出现一个问题:还在输入拼音的时候,onChange方法已经触发了,如下,即输入过程就已经触发了多次onChange方法。如果onChange方法有较为复杂的逻辑,就可能会带来一些用户体验或者逻辑的问题。......
  • 【836】Cannot import tensorflow_text
    Ref:Cannotimporttensorflow_textSometimesyouneedtoreinstallandupdatetensorflowtheninstalltensorflow_text.(Becauseyouneedyourtensorflow.__version__andtensorflow_text.__version__tohavethesameversion)Makesuretensorflowandtensor......
  • 《workflow跳远》activiti篇——activiti简介入门
    工作流为什么出现最初,开发人员开发一个流程,例如请假流程,员工提出请假申请——领导同意——财务人员记录,一般通过状态字段来跟踪流程变化,设zt=0为初始状态,zt=1为保存状态,zt=2提交到领导,zt=3提交到财务,zt=4财务人员记录完成。员工、领导、财务人员这些不同角色,通过状态字段的取值决......
  • react+mock
    之前写过一篇react项目添加mock的文章,在文章中说的mock代码是打包配置的时候写入的,这种方式导致每次修改mock数据后都需要重新启动服务才能获取到新的mock数据。今天使用另外一种方式来实现开发过程中的数据mock。在项目中安装axios和mock.js两个框架然后在webpack配置文件中......