antv g6实现系统拓扑图

2024-06-21 00:20
文章标签 实现 系统 antv g6 拓扑图

本文主要是介绍antv g6实现系统拓扑图,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1 背景

为例描述各个服务、redis、mysql等之间的联系及其健康状态,构建系统拓扑图,考虑 g6 更适合处理大量数据之间的关系,所以我们采用g6来绘制前端的图形。

g6提供的支持:

  • 节点/边类型多样,同样支持自定义
  • 对于节点的样式可以直接配置化处理
  • 丰富的事件体系,包括对节点/边/画布,以及时机事件的监听
  • 多种布局算法
  • 节点/边的数据,都是可以配置化的json对象

在线工具:g6示例

2 功能列表

节点:

  • 添加节点:除了id、style、type外,还包括一些业务需要的数据
  • 删除节点:除了删除该节点相对于画布的id外,还包括与之相关的业务数据
  • 节点状态:比如错误节点需要标红;非活跃节点需要标灰

边:

  • 添加边:除了id、style、type外,还包括一些业务需要的数据
  • 删除变:除了删除该边相对于画布的id外,还包括与之相关的业务数据
  • 修改边:主要是修改边所代表的业务信息,如果没有业务信息的话,这条边应该被删除

画布:

  • 用户自定义布局,比如需要保存用户拖拽节点后的节点位置坐标信息
  • dagre层次布局
  • 工具栏
  • 图例
  • 小地图
  • 触摸板放大缩小
  • 节点搜索

3 节点

3.1 渲染节点

渲染节点,包括自定义节点类型和样式。

自定义节点,该节点由rect和image组成,类似于矩形里面有icon:

// 其实可以不用自定义节点,可以使用circle类型的icon字段。但是这种方式,点击节点的时候,里面的icon会存在闪缩的情况
// https://g6.antv.antgroup.com/manual/middle/elements/nodes/built-in/circle#%E5%9B%BE%E6%A0%87-icon
G6.registerNode('drag-inner-image-node',{afterDraw(cfg, group) {const size = cfg?.size as number[];const width = size[0] - 20;const height = size[1] - 20;const imageShape = group?.addShape('image', {attrs: {x: -width / 2,y: -height / 2,width,height,img: cfg?.img,cursor: 'move',},// must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item typename: 'image-shape',});// 启用拖拽imageShape?.set('draggable', true);},},'circle',
);

节点样式:

const DefaultNodeSelectedStyle = {lineWidth: 8,'text-shape': {// 点击后的文本样式,保持点击前一致fontWeight: 400,},
};export const NodeStyleMap = {default: {// 正常节点 - 样式设置style: {fill: GlobalLightBlueColor,stroke: GlobalBlueColor,lineWidth: 1,},// 状态样式,比如 selected点击状态stateStyles: {selected: {stroke: GlobalBlueColor,fill: GlobalLightBlueColor,shadowColor: GlobalBlueColor,...DefaultNodeSelectedStyle,},},},error: {// 异常节点style: {stroke: GlobalRedColor,fill: GlobalLightRedColor,lineWidth: 1,},stateStyles: {selected: {stroke: GlobalRedColor,fill: GlobalLightRedColor,shadowColor: GlobalRedColor,...DefaultNodeSelectedStyle,},},},
};

获取节点的渲染数据:

export const formatNodes = (nodes: MttkArchitectureNode[] = []) => {return nodes?.map((node) => {const { component, has_error, coordinates } = node;// 业务逻辑const middlewareType = getMiddlewareType(component) as MttkComponentType;const { id, label, wholeLabelName } = getNodeId(node);// 样式和iconconst nodeStyle = NodeStyleMap[has_error ? 'error' : 'default'];const img = has_error ? ErrorIconImageMap[middlewareType] : IconImageMap[middlewareType];return {...node,img,middlewareType,label,wholeLabelName, // 仅前端展示使用...nodeStyle,id, // 仅前端展示使用x: coordinates?.x, // 节点的位置坐标y: coordinates?.y, // 节点的位置坐标};});
};

3.2 删除节点

3.3 添加节点

4 边

4.1 渲染边

边的样式:

const DefaultEdgeSelectedStyle = {lineWidth: 4,shadowBlur: 10, // 阴影的模糊级别,数值越大越模糊
};export const EdgeStyleMap = {default: {// 正常边 - 样式设置style: {stroke: GlobalBlueColor,lineWidth: 1,lineDash: [0], // 如果[0]表示直线,需要覆盖一下创建边之后的虚线样式},// 状态样式,比如 selected点击状态stateStyles: {selected: {stroke: GlobalBlueColor,shadowColor: GlobalBlueColor,...DefaultEdgeSelectedStyle,},},},error: {// 异常边style: {stroke: GlobalRedColor,lineWidth: 1,},stateStyles: {selected: {stroke: GlobalRedColor,shadowColor: GlobalRedColor,...DefaultEdgeSelectedStyle,},},},
};

边的渲染数据:

export const formatEdges = (edges: MttkArchitectureEdge[] = [], nodes: MttkArchitectureNode[] = []) => {return edges?.map((edge) => {const { has_error } = edge;const edgeStyle = EdgeStyleMap[has_error ? 'error' : 'default'];const { id, fromId, toId } = getEdgeId(nodes, edge);return {...edge,source: fromId,target: toId,...edgeStyle,id,from: fromId, // 前端直接替换掉get接口返回的随机数idto: toId, // 前端直接替换掉get接口返回的随机数id};});
};

4.2 删除边

4.3 添加边

5 画布全局配置


export const LayoutMap = {[LayoutType.LR]: {// 从左到右type: 'dagre',ranksep: 70,controlPoints: true, // 是否保留布局连线的控制点rankdir: 'LR', // 可选,默认为图的中心nodesep: 10, // 可选},[LayoutType.TB]: {// 从上到下// type: 'dagre',// ranksep: 70,// controlPoints: true,rankdir: 'TB',},
};export const DefaultOptions = {layout: LayoutMap.LR,defaultNode: {type: 'drag-inner-image-node',size: [50, 50],style: { cursor: 'move' },label: 'node-label',labelCfg: {position: 'bottom',offset: 2,style: {fill: '#666',fontSize: 14,cursor: 'move',},},},defaultEdge: {type: 'polyline',style: {radius: 20, // 拐弯处的圆角弧度offset: 20, // 拐弯处距离节点最小距离endArrow: true,lineAppendWidth: 20, // 提升边的击中范围},},modes: {default: ['drag-canvas','drag-node',{type: 'create-edge',trigger: 'click', // 'click' by default. options: 'drag', 'click'key: 'shift', // undefined by default, options: 'shift', 'control', 'ctrl', 'meta', 'alt'edgeConfig: {// 有该交互创建出的边的配置项,可以配置边的类型、样式等style: {radius: 20, // 拐弯处的圆角弧度offset: 20, // 拐弯处距离节点最小距离endArrow: true,lineAppendWidth: 20, // 提升边的击中范围...EdgeStyleMap.default.style,lineDash: [5], // 设置线的虚线样式, 如果[0]表示直线},},shouldEnd: (e: any, self: any) => {const { item: toItem } = e;const { source: fromId, graph } = self;const toId = toItem._cfg.id;// 不允许创建自环边if (toId === fromId) {return false;}// 不允许创建已经存在的边const edges = graph.getEdges();if (edges.some((ed: any) => {const { source, target } = ed.getModel();return fromId === source && toId === target;})) {return false;}return true;},},{type: 'click-select',// 不允许节点被该交互选中。如果为true的话,会存在重复点击当前节点闪烁的情况,// 因为 已选中 > 再次点击,会默认给当前节点 selected status设置为false,我们再手动改为true的时候,就会存在闪烁selectNode: false,multiple: false, // 不允许多选},],},fitView: true, // 图是否自适应画布
};

6 图例

g6自带的图例不是很好自定义ui,虽然可以进行与节点/边数据联动的功能,所以考虑直接react实现。

// interface Props {
//   extendLegend?: React.ReactNode; // 扩展图例,比如错误的信息
// }
export const GraphNodeTypeConfigs = [{icon: IconImageMap[MttkComponentType.SERVICE],description: 'Service',key: MttkComponentType.SERVICE,},{icon: IconImageMap[MttkComponentType.MYSQL],description: 'MySQL',key: MttkComponentType.MYSQL,},{icon: IconImageMap[MttkComponentType.KAFKA],description: 'Kafka',key: MttkComponentType.KAFKA,},{icon: IconImageMap[MttkComponentType.REDIS],description: 'Redis',key: MttkComponentType.REDIS,},{icon: IconImageMap[MttkComponentType.UNKNOWN],description: 'Unknown',key: MttkComponentType.UNKNOWN,},
];export function LegendRow() {return (<>{GraphNodeTypeConfigs.map(({ icon, description }) => (<Row justify="start" align="middle" wrap={false} style={{ marginRight: 8 }}><img src={icon} style={{ width: 18, height: 18, marginRight: 4 }} />{description}</Row>))}</>);
}

7 工具栏

跟图例一样,考虑不太好自定义ui,所以直接react实现。

import { ZoomInOutlined, ZoomOutOutlined, FullscreenExitOutlined } from '@ant-design/icons';
import { Col, Row, Button } from 'antd';interface Props {onZoomIn: () => void; // 放大onZoomOut: () => void; // 缩小onFixCenter: () => void; // 回到中间
}export function Toolbar(props: Props) {const { onZoomIn, onZoomOut, onFixCenter } = props;return (<Col style={{ width: 30 }}><Row justify="center"><Button type="link" style={{ padding: 0 }} onClick={onZoomIn}><ZoomInOutlined /></Button></Row><Row justify="center"><Button type="link" style={{ padding: 0 }} onClick={onZoomOut}><ZoomOutOutlined /></Button></Row><Row justify="center"><Button type="link" style={{ padding: 0 }} onClick={onFixCenter}><FullscreenExitOutlined /></Button></Row></Col>);
}

这篇关于antv g6实现系统拓扑图的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1079681

相关文章

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python脚本实现自动删除C盘临时文件夹

《Python脚本实现自动删除C盘临时文件夹》在日常使用电脑的过程中,临时文件夹往往会积累大量的无用数据,占用宝贵的磁盘空间,下面我们就来看看Python如何通过脚本实现自动删除C盘临时文件夹吧... 目录一、准备工作二、python脚本编写三、脚本解析四、运行脚本五、案例演示六、注意事项七、总结在日常使用

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

使用Python实现在Word中添加或删除超链接

《使用Python实现在Word中添加或删除超链接》在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能,本文将为大家介绍一下Python如何实现在Word中添加或... 在Word文档中,超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超

windos server2022里的DFS配置的实现

《windosserver2022里的DFS配置的实现》DFS是WindowsServer操作系统提供的一种功能,用于在多台服务器上集中管理共享文件夹和文件的分布式存储解决方案,本文就来介绍一下wi... 目录什么是DFS?优势:应用场景:DFS配置步骤什么是DFS?DFS指的是分布式文件系统(Distr

NFS实现多服务器文件的共享的方法步骤

《NFS实现多服务器文件的共享的方法步骤》NFS允许网络中的计算机之间共享资源,客户端可以透明地读写远端NFS服务器上的文件,本文就来介绍一下NFS实现多服务器文件的共享的方法步骤,感兴趣的可以了解一... 目录一、简介二、部署1、准备1、服务端和客户端:安装nfs-utils2、服务端:创建共享目录3、服

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma

2.1/5.1和7.1声道系统有什么区别? 音频声道的专业知识科普

《2.1/5.1和7.1声道系统有什么区别?音频声道的专业知识科普》当设置环绕声系统时,会遇到2.1、5.1、7.1、7.1.2、9.1等数字,当一遍又一遍地看到它们时,可能想知道它们是什... 想要把智能电视自带的音响升级成专业级的家庭影院系统吗?那么你将面临一个重要的选择——使用 2.1、5.1 还是