首页 前端知识 vue-flow绘制流程图

vue-flow绘制流程图

2024-08-07 00:08:22 前端知识 前端哥 708 941 我要收藏

1. 实现效果

  • 顶端左侧有Tab栏,通过拖拽添加节点
  • 底端左侧有工具栏
  • 底端右侧有MiniMap,显示全局节点样式
    在这里插入图片描述

2. 背景

根据项目需求,需要实现类似Visio的效果,从Tab栏拖拽节点到画布中,绘制不同类型的节点,并连线。

技术调研(仅个人看法)
  1. Antv G6:适合图结构(包括节点布局、节点个数)没有太大变化,比如树图,可以绘制动态线条、多种节点,增加图的动态效果。
  2. Antv X6:适合位置确定、节点确定的流程图,比如DAG图、固定流程的流程图,增加节点状态、边的动画效果,显示图的灵动性。
  3. Echarts:适合折线图、散点图、柱状图等简单图形。
  4. vue-flow:(vue-flow官网):实现类似visio的效果,通过拖拽在画布中添加节点,可整体拖拽、放大和缩小,自动适应画布并居中等功能。
  • 个人使用感受优缺点对比:
    • Antv G6、X6、Echarts技术成熟,适合vue2/3,官方文档是中文的,容易阅读;vue-flow是2022年发布的,只适用vue3,官方文档只有英文版且比较简单,需要结合文档Guide和Example,常常指南中找不到,需要在样例中找类似效果,学习实现方式。
    • Antv G6、X6常常只画一个图就会觉得比较卡顿,而且每次重新绘制都需要清空画布;vue-flow绘图十分流畅,且每次只更新图谱数据,不需要清空画布。
    • Antv G6、X6,vue-flow都允许自定义节点和边,样式灵活多样,更适合开发。

使用心得

1. 快速开始

  1. 依赖安装:
npm install @vue-flow/core
npm install @vue-flow/background //背景
npm install @vue-flow/minimap //小地图
npm install @vue-flow/controls //自带的缩放、居中、加锁功能
npm install @vue-flow/node-toolbar //工具栏
npm install @vue-flow/node-resizer //缩放
复制
  1. 样式导入:全局样式文件style.scss中导入
@import "@vue-flow/core/dist/style.css";
@import "@vue-flow/core/dist/theme-default.css";
@import '@vue-flow/controls/dist/style.css';
@import '@vue-flow/minimap/dist/style.css';
复制

依赖安装后就可以在页面中导入使用了

2. 基本工具栏

template

  • 加载基本组件: Background 、Controls、MiniMap ,分别是背景、左下缩放工具栏、右下地图,这些位置都是默认的。
  • 要在画布上显示的内容,都要放在 <VueFlow>标签内
<template>
<VueFlow>
<Background />
<Controls />
<MiniMap />
</VueFlow>
复制

script

import { VueFlow, Position, Panel, useVueFlow, MarkerType } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import { MiniMap } from '@vue-flow/minimap'
复制

3. 加载节点和边,绘图

(1) 不指定节点和边的样式,就是加载默认节点和边

template

  • nodes绑定节点;edges绑定边
  • nodes中节点属性必须有id唯一标识,position记录位置
  • edges中边的属性必须有id唯一标识,sourcetarget分别记录边的源节点和目的节点
  • fit-view-on-init:默认图居中
  • default-marker-color:修改边的节点颜色
<VueFlow
:nodes="chatNodes"
:edges="chatEdges"
fit-view-on-init
default-marker-color="#409EFF"
class="flowchat-container"
>
</VueFlow>
复制

style:定义vue-flow画布的宽高和位置

.flowchat-container {
width: 100%;
height: calc(100% - 50px);
position: absolute;
top: 50px;
padding: 20px 0;
}
复制

节点数据结构

//节点
const nodes = ref([
{
id: '1',
position: { x: 50, y: 50 },
data: { label: 'Node 1', },
}])
//边
const edges = ref([
{
id: 'e1->2',
source: '1',
target: '2',
}
])
复制
(2)自定义节点(官网Examples/CustomeNode)

index.vue

  • #node-custom#node-后的内容是根据自定义节点页面的名称来定义的,比如如果节点页面命名为ColorSelectorNode,那么这里定义就是#node-color-selector="props"
  • 所以自定义节点页面名称一定是xxxNode.vue,才能根据#node-xxx加载相应页面的效果。
  • @nodeDrag:监听节点的拖拽事件,自动传入参数props,可获取节点拖拽后的位置坐标、位置偏移量等关键信息
  • 边的命名同理
<VueFlow :nodes="chatNodes" :edges="chatEdges" fit-view-on-init @nodeDrag="dragNode">
<template #node-custom="props">
<CustomNode v-bind="props"></CustomNode >
</template>
</VueFlow>
import CustomNode from './CustomNode.vue'
复制

customNode.vue:按照普通vue界面开发即可,自定义节点样式和内容

<template>
<div>Select a color</div>
<Handle id="a" type="source" :position="Position.Right" />
</template>
复制
(3)自定义边(官网Examples/customEdges)
  • 命名方式同上

  • EdgeWithButton是可以×掉的边,具体实现参考样例中边的实现方式,在样例中给出了多种边的类型,可以根据需求选择不同的效果,多种效果如下
    在这里插入图片描述

  • 在定义边的数据时,需要加一个type: 'button'属性,才能识别出EdgeWithButton定义的边的效果

<VueFlow :nodes="chatNodes" :edges="chatEdges" fit-view-on-init>
<template #edge-button="props">
<EdgeWithButton v-bind="props" />
</template>
</VueFlow>
import EdgeWithButton from './edgeWithButton.vue'
复制

script中添加边

  • id命名方式:按照如下方式定义
  • source/target:源点/终点
  • sourceHandle/targetHandle:源点/终点句柄
  • markerEnd:是否显示箭头
  • type:边的类型,按照官网样例中的写法来写,就能被识别
//新建连接,添加边
onConnect((params) => {
chatEdges.value.push({
id: 'vueflow__edge-' + params.source + params.sourceHandle + '-' + params.target + params.targetHandle,
source: params.source,
sourceHandle: params.sourceHandle,
target: params.target,
targetHandle: params.targetHandle,
markerEnd: MarkerType.ArrowClosed,
type: 'button',
})
})
复制

4. 加载句柄handle,用于节点连线

(1) 加载固定句柄
  • id必须唯一
  • type标记source/target
  • position标记位置,默认四个方位Top、Bottom、Right、Left
import { Position, Handle} from '@vue-flow/core'
<Handle id="source_id_a" type="source" :position="Position.Right" />
<Handle id="target_id_a" type="target" :position="Position.Left" />
复制
(2)动态生成句柄、并计算位置
  • 背景:需要开发分支节点,随着动态添加分支条件,动态添加句柄并定义位置,使得每个分支条件有个与之对齐的handle,效果如下:
    在这里插入图片描述
  • 实现方式
    • template

      1. position指定handle在节点的哪一侧
      2. style动态计算每个handle距离顶部的距离
      3. 每个handledid要唯一,目前发现只有:id="'right_'+index"可以正常显示,比如写成:id="item.name"是显示不出来的,没有找到原因┭┮﹏┭┮
      <Handle
      v-for="(item, index) in conditions"
      :position="Position.Right"
      type="source"
      :id="'right_'+index"
      :style="getDynamicHandlePos(item,index)"
      >
      </Handle>
      复制
    • script实现

      1. 函数中 *16-8这些数值是根据节点高度尝试出来的,不是固定的。
      2. 如果是计算bottom,一定要加上top:auto属性,否则可能会不显示或者是出错。
      3. conditions.length - index计算的原因:第一个条件应该距离底部最远,最后一个距离最近,如果直接index计算,那么if对应的handle在最底部,else对应的handle在最顶部,刚好弄反了。
      import { Position, Handle } from '@vue-flow/core'
      const getDynamicHandlePos = (item, index: number) => {
      return {
      bottom: `${(conditions.length - index) * 16 - 8}px`,
      top: 'auto',
      }
      }
      复制

5. Panel:定义面板

自定义面板显示信息,比如节点详情、菜单栏面板等信息,需要使用<Panel>标签
template:写在<VueFlow>标签内

<template>
<VueFlow>
<Panel position="top-left">
<div class="panel-title">
基础配置
</div>
<div class="icon-text" :draggable="true" @dragstart="onDragStart($event,'HTTP')">
<svg-icon icon-class="cloud" />
<span>HTTP节点</span>
</div>
...... //面板详情信息
</Panel>
</VueFlow>
</template>
复制

style:定义position是生效的。设置animation也是有效的,普通div的css写法完全生效。

.top-left{
position: absolute;
right: 0;
top: 3%;
width: 100px;
}
复制

6. 从面板拖拽,添加节点

拖拽功能,实现参考:节点拖拽

  • 最外层div上绑定@drop
  • VueFlow上绑定@dragover、@dragleave,这些顺序不可以调换
  • 最关键的函数实现在@drop@dragover、@dragleave写法参考官网,基本无需任何改动
<template>
<div class="dnd-flow" @drop="onDrop">
<VueFlow :nodes="nodes" @dragover="onDragOver" @dragleave="onDragLeave">
</VueFlow>
</div>
</template>
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()
复制

script:@drop="onDrop"函数

  • nodeId:可以使用uuid方式,唯一标识节点(百度可查uuid具体函数)
  • event:可以提供节点位置,
  • newNode:结合自己的项目构造节点具体信息,其中type是自己定义的类型,onDragStart 中会有定义,若没有自定义就是默认类型
const onDrop = (event) => {
const position = screenToFlowCoordinate({
x: event.clientX,
y: event.clientY,
})
const nodeId = getId()
const newNode = {
id: nodeId,
type: draggedType.value,
position,
data: { label: nodeId },
}
addNodes(newNode)
}
复制
转载请注明出处或者链接地址:https://www.qianduange.cn//article/14948.html
标签
流程图
评论
还可以输入200
共0条数据,当前/页
发布的文章

安装Nodejs后,npm无法使用

2024-11-30 11:11:38

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!