1
概述
在进行函数计算开发时,函数资源关联关系错综复杂,为了方便用户对资源信息的全量感知,决定把函数所有资源信息用关系图的方式进行呈现。同时可灵活操作实现对资源的管控,从而提升用户体验,下面为大家介绍如何实现。
主要技术使用了Reactflow 图形库进行节点与边的绘制渲染,并结合Dagre 层次布局计算各节点的位置,从而实现最优布局。
本文将依据下图,从数据处理、布局算法、图形绘制三个方面分别阐述,并将重点介绍Dagre布局算法与Reactflow的画布绘制。
2
数据处理
当数据有一定层级结构或先后顺序时,经常会用到层次(Hierarchy)布局。函数下的资源则是以版本为维度,进行资源的关联。
-
获取数据:考虑到REST API接口的数据特征,使用Promise.all() 来批量处理从 REST API 获取的数据。
-
处理数据:根据实际需求对数据重新整合。如增加数据条目、合并资源信息等操作。
数据核心点:增加虚拟节点
【虚拟节点优点】:合理地增加虚拟节点,可以优化 dagre 布局的效果,使图更加美观和易于理解。
【虚拟节点适用情况】:
-
长边分割:当一条边跨越多个层次时,可以通过增加虚拟节点将其分割成多条短边,保证每条边只连接相邻的两层,从而优化布局。
-
对齐节点:通过增加虚拟节点,可以确保某些节点在同一层次上对齐。
-
控制边的弯曲:虚拟节点可以帮助控制边的弯曲程度,使图的布局更加美观。
-
3
Reactflow图形库
Reactflow 是一个用于构建交互式图表和流程图的 React 库。它提供了一个强大的 API 和丰富的功能,使开发者能够轻松地创建、编辑和管理复杂的图表和流程图。它支持拖放、缩放、节点和边的自定义等功能,非常适合用于构建工作流编辑器、数据流图、流程图等应用。
官网基础节点/边样式:
自定义节点/边样式:
实现功能:
(1)自定义节点
Reactflow提供了基础节点,如上图的Node A 与 Node B,同时提供了nodeType属性用于自定义节点。
对于函数资源,需要考虑版本、别名、触发器、域名四种节点展开与收起状态的绘制。
(2)自定义边
Reactflow提供了多种边的绘制,如贝塞尔曲线,SmoothStep平滑曲线、曲线是否动态等功能。
对于函数资源关系图的绘制,也需要自定义边的样式。
-
对于别名与版本的关联涉及到了别名所关联版本(即主版本和灰度版本)的关系比例,需在别名被选中时,显示与之对应版本的占比数据。
-
边(正向和反向)上的文案位置及方向。
-
边是否选中时的明暗渲染。
(3)句柄
所谓句柄,即上图中的实心黑点,用于连接节点和边。句柄方向需要根据关系图的延展方向(如上下或左右)确定。
typescript
<Handle type="source" position="bottom" /> // 定义下方句柄,如触发器/域名节点可使用,用于下一层数据的连接。
<Handle type="target" position="top" /> // 定义上方句柄,如版本可使用,用于上一层数据的连接。
(4)节点的自定义悬浮文案:
自定义悬浮文案(Tooltip)可以通过使用 Reactflow 提供的 useReactFlow 钩子和自定义组件来实现。需保证悬浮文本框需跟随文案滚动,且不被临近节点遮挡。
问题:reactflow库限制了节点在画布中层级最高,若将自定义悬浮文案放于画布中,则会存在悬浮文案始终会被其他邻近节点遮挡的情况。
解决:考虑使用
ReactDom.CreactPortal(children, document.body)
,将其放在与 body 同级的 Dom 中,来保证层级最高。问题:继上一步解决后,随之而带来的问题是对于可移动的画布,需要保证无论画布如何移动,其悬浮位置总是能够在节点的下方显示,即跟随滚动。
解决:实际位置 = 画布距离视口左侧的距离+节点的初始位置+节点拖动的距离。其中节点拖动的距离可使用 useReactflow() 钩子提供的 getViewport()方法来获取。
javascript
const { getViewport } = useReactFlow();
const { x: viewX, y: viewY} = getViewport(); // x, y 即为画布拖动时节点在x,y 方向上的移动距离
文案跟随滚动效果如下:
4
Dagre的层次布局
在数据有一定层级结构或先后顺序时,经常会用到层次布局来展现,一般对应的数据结构是DAG(Directed Acyclic Graph,即有向无环图),使用dagre布局更贴合业务场景。
Dagre常用的场景包括:流程图、组织架构图、状态转移图等。
综合考虑,选择使用antv的布局算法所继承的DagreLayout布局算法。该算法是对有向无环图进行层次布局的实现。
基本概念:
(1)rankDir:图的延展方向。包括由上到下(TB)、由下到上(BT)、由左到右(LR)、由右到左(RL)四种延展方向。
(2)rank:图的层次划分。即沿着图的延展方向划分的层级。每个顶点都存在于某个层级上,一个层级可能有多个顶点。
(3)level:每一层节点的级别顺序。
实现流程:
整个算法实现布局的计算流程分为去环、节点分层、同层节点排序、绘制。
-
去环:Dagre使用了DFS和贪心算法确保得到完整的有向无环图;
DFS 算法:使用 DFS 进行遍历,若在一条通路中,同一个节点被访问了多次,则该通路上存在环路,去掉成环的通路上最后一条边即可。
贪心算法:优先反转同时存在于多个环的边,尽量减少需要反转的边。
-
节点分层:进行图的层次划分。选择采用紧凑树(tight-tree)的布局方式,即在最长路径树的基础上,遍历并移动各个节点,使得每个边都达到它需要的最短长度,即目的是减少长边的数量,其特点是排列紧凑,复杂度中等;
**紧凑树算法:**首先每条边需要给定一个最小长度,比如1。然后计算松弛度delta(即边的长度 - 最小长度)。如果松弛度为0,则为紧致边。把所有紧致边和节点加入紧致生成树,每次取松弛度最小的边;如果source节点已在紧致树中,把target节点向上移delta层级;如果source节点不在紧致树中,把source节点向下移delta层级,循环直到紧致树中已经包含了所有的节点。
**其它算法:**Dagre还提供了最长路径(long-path)和网络网格单纯形(network-simplex)两种算法,但考虑到算法复杂度和实现效果,紧凑树为最优。
-
同层节点排序:图中的节点已经按照 rank 分好层级,但Dagre布局比较灵活,为了计算布局最优,会出现节点顺序改变、边交叉、节点重叠的情况。所以每一个层级中的节点先后顺序仍然需要调整,以达到减少边的交叉的目的。算法会自动帮忙进行排序,若仍然出现,可自行进行节点排序,如函数下所有资源都是根据版本为维度进行数据扩展的,所以可通过"版本"层的资源节点排序,来避免这些问题。
-
绘制:计算出最终的节点坐标,将其输入到reactflow中进行画布节点绘制。
基于以上特征,使用@antv/layout包中的Dagre布局实现。该算法的包相对较小,直接提供了自定义节点的指定层次,初始节点的位置,且其提供了updateNodeCfg()来实现节点的预制信息,如上一次布局的位置。综合所有的布局算法,这个布局明显更符合业务需求。
如内存太大,可设置 NODE_OPTIONS 环境变量,将 Node.js 的最大旧生代内存设置为 2048 MB,以防止内存不足的问题。(export NODE_OPTIONS=--max_old_space_size=2048)
5
实践
可参考官网dagre布局的简单实现:https://v10.reactflow.dev/docs/examples/layout/dagre/
1、数据处理:增加虚拟节点类型,例如对于版本而言,版本上没有别名也没有触发器和域名,需增加一个虚拟节点。同理,对于别名列表而言,别名上没有触发器和域名,也需要增加虚拟节点来优化布局。
2、自定义节点,将其处理为dagre布局所能识别的参数
重要参数说明:layer:定义该节点的层次;layout:节点是否参与布局;size:节点的大小;type:自定义节点的类型。
节点的sourcePosition和targetPosition需要根据图的延展方向进行选择。dagre布局会根据这些数据的设置进行最优的位置计算。
3、dagre布局
配置Dagre相关参数。
重点是可通过updateCfg()进行一些信息预置,如初始位置,节点顺序。尤其是增量布局,在图新增节点和边时,尽量保持原有的布局不变,在@antv/layout中的Dagre算法实现中,有nodeOrder、preset等相关参数,可使用上一次布局的结果数据作为输入,可以进行增量布局、保证重新布局的连续性。
布局结束后,通过reactflow提供的setNode()方法,将节点位置更新。
4、绘制渲染
Reactflow提供了nodeTypes和edgeTypes进行自定义节点和自定义边的数据接口。当节点选中时,方法onNodesChange和onEdgesChange可处理节点和边的一些业务逻辑和UI更新及其它功能(如自定义画布的是否拖动、是否允许滚轮缩放等等)
6
效果
如gif图所示:
7
总结
本文对Dagre布局算法进行了有业务场景的分享,其中涉及到一些遇到的困难及解决方法,如使用增量布局来保持原布局、节点分层、减少边交叉的方法、悬浮提示框始终跟随画布的位置等等,旨在这里分享给有同样场景或感兴趣的各位同学。
推荐阅读
函数计算------文档与网页数据提取工具(MinerU)应用实践
更多技术和产品文章,请关注👆
如果您对哪个产品感兴趣,欢迎留言给我们,我们会定向邀文~
go
360智汇云是以"汇聚数据价值,助力智能未来"为目标的企业应用开放服务平台,融合360丰富的产品、技术力量,为客户提供平台服务。
目前,智汇云提供数据库、中间件、存储、大数据、人工智能、计算、网络、视联物联与通信等多种产品服务以及一站式解决方案,助力客户降本增效,累计服务业务1000+。
智汇云致力于为各行各业的业务及应用提供强有力的产品、技术服务,帮助企业和业务实现更大的商业价值。
官网:https://zyun.360.cn 或搜索"360智汇云"
客服电话:4000052360