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

相关文章

Spring Boot配置和使用两个数据源的实现步骤

《SpringBoot配置和使用两个数据源的实现步骤》本文详解SpringBoot配置双数据源方法,包含配置文件设置、Bean创建、事务管理器配置及@Qualifier注解使用,强调主数据源标记、代... 目录Spring Boot配置和使用两个数据源技术背景实现步骤1. 配置数据源信息2. 创建数据源Be

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

linux批量替换文件内容的实现方式

《linux批量替换文件内容的实现方式》本文总结了Linux中批量替换文件内容的几种方法,包括使用sed替换文件夹内所有文件、单个文件内容及逐行字符串,强调使用反引号和绝对路径,并分享个人经验供参考... 目录一、linux批量替换文件内容 二、替换文件内所有匹配的字符串 三、替换每一行中全部str1为st

SpringBoot集成MyBatis实现SQL拦截器的实战指南

《SpringBoot集成MyBatis实现SQL拦截器的实战指南》这篇文章主要为大家详细介绍了SpringBoot集成MyBatis实现SQL拦截器的相关知识,文中的示例代码讲解详细,有需要的小伙伴... 目录一、为什么需要SQL拦截器?二、MyBATis拦截器基础2.1 核心接口:Interceptor

SpringBoot集成EasyPoi实现Excel模板导出成PDF文件

《SpringBoot集成EasyPoi实现Excel模板导出成PDF文件》在日常工作中,我们经常需要将数据导出成Excel表格或PDF文件,本文将介绍如何在SpringBoot项目中集成EasyPo... 目录前言摘要简介源代码解析应用场景案例优缺点分析类代码方法介绍测试用例小结前言在日常工作中,我们经

基于Python实现简易视频剪辑工具

《基于Python实现简易视频剪辑工具》这篇文章主要为大家详细介绍了如何用Python打造一个功能完备的简易视频剪辑工具,包括视频文件导入与格式转换,基础剪辑操作,音频处理等功能,感兴趣的小伙伴可以了... 目录一、技术选型与环境搭建二、核心功能模块实现1. 视频基础操作2. 音频处理3. 特效与转场三、高

Python实现中文文本处理与分析程序的示例详解

《Python实现中文文本处理与分析程序的示例详解》在当今信息爆炸的时代,文本数据的处理与分析成为了数据科学领域的重要课题,本文将使用Python开发一款基于Python的中文文本处理与分析程序,希望... 目录一、程序概述二、主要功能解析2.1 文件操作2.2 基础分析2.3 高级分析2.4 可视化2.5

Java实现预览与打印功能详解

《Java实现预览与打印功能详解》在Java中,打印功能主要依赖java.awt.print包,该包提供了与打印相关的一些关键类,比如PrinterJob和PageFormat,它们构成... 目录Java 打印系统概述打印预览与设置使用 PageFormat 和 PrinterJob 类设置页面格式与纸张

使用Go实现文件复制的完整流程

《使用Go实现文件复制的完整流程》本案例将实现一个实用的文件操作工具:将一个文件的内容完整复制到另一个文件中,这是文件处理中的常见任务,比如配置文件备份、日志迁移、用户上传文件转存等,文中通过代码示例... 目录案例说明涉及China编程知识点示例代码代码解析示例运行练习扩展小结案例说明我们将通过标准库 os

Python实现终端清屏的几种方式详解

《Python实现终端清屏的几种方式详解》在使用Python进行终端交互式编程时,我们经常需要清空当前终端屏幕的内容,本文为大家整理了几种常见的实现方法,有需要的小伙伴可以参考下... 目录方法一:使用 `os` 模块调用系统命令方法二:使用 `subprocess` 模块执行命令方法三:打印多个换行符模拟