AntV G6自定义流程图Graph

2024-02-01 08:10

本文主要是介绍AntV G6自定义流程图Graph,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

AntV G6自定义流程图Graph

    • AntV G6自定义流程图Graph
      • 一、先看下我的效果图
      • 二、参考官方图表示例地址
      • 三、代码已整合成vue组件
      • 四、这里提供了直接改官方示例数据,简单的参考

AntV G6自定义流程图Graph

前言:自定义流程图节点样式、节点可拖动,节点文字过长省略,文字过长的节点悬浮展示tooltip插件悬浮框,修改tooltip悬浮框样式。

一、先看下我的效果图

整体效果
鼠标悬浮节点样式

二、参考官方图表示例地址

Dagre 流程图

三、代码已整合成vue组件

调用组件传值给mapData,这里只是自己演示设置了假数据a

<template><div style="width: 100%;height: 100%;"><!-- 流程预览图画布 --><div id="containerBox"style="background: #F7F8FA;border-radius: 4px;"></div></div>
</template>
<script>
import G6 from '@antv/g6'
import insertCss from 'insert-css';
// 这个样式是作用于modes里的tooltip
insertCss(`.g6-tooltip {border-radius: 4px;font-size: 12px;color: #fff;background-color: #3C3D42;text-align: left;width: 240px;padding: 6px 12px;}
`);
insertCss(`.g6-component-tooltip {border-radius: 4px;font-size: 12px;color: #fff;background-color: #3C3D42;text-align: left;width: 240px;padding: 6px 12px;}
`);
export default {name: "previewProcess",data () {return {a: {nodes: [{id: '1',dataType: 'start',name: 'alps_file1',},{id: '2',dataType: 'condition',name: 'alps_file2二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二二',},{id: '3',dataType: 'examine',name: 'alps_file3三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三三',},{id: '4',dataType: 'examine',name: 'sql_file4四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四四',},{id: '5',dataType: 'examine',name: 'sql_file5',},{id: '6',dataType: 'end',name: 'feature_etl_1',}],edges: [{source: '1',target: '2',},{source: '1',target: '3',},{source: '2',target: '4',},{source: '3',target: '4',},{source: '4',target: '5',},{source: '5',target: '6',}],}}},props: {mapData: { // 预览数据type: Object,default: () => {return {}}},mapHeight: { // 高度Htype: String,default: '600'},},mounted () {this.customNode()this.createNode(this.a) // 参数名为a,后期正式使用a都改成mapData},activated () {},watch: {},computed: {},methods: {// 文字过长显示...fittingString (str, maxWidth, fontSize) {const ellipsis = '...'const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0]let currentWidth = 0let res = strconst pattern = new RegExp('[\u4E00-\u9FA5]+') // distinguish the Chinese charactors and lettersstr.split('').forEach((letter, i) => {if (currentWidth > maxWidth - ellipsisLength) returnif (pattern.test(letter)) {// Chinese charactorscurrentWidth += fontSize} else {// get the width of single letter according to the fontSizecurrentWidth += G6.Util.getLetterWidth(letter, fontSize)}if (currentWidth > maxWidth - ellipsisLength) {res = `${str.substr(0, i)}${ellipsis}`}})return res},// 自定义节点方法customNode () {const _that = thisG6.registerNode('sql',{drawShape (cfg, group) {let index = _that.a.nodes.length - 1// 判断为开始、结束节点if (cfg.id === _that.a.nodes[0].id || cfg.id === _that.a.nodes[index].id) {const startEnd = group.addShape('rect', {attrs: {x: -10,y: -25,width: 100,height: 36,stroke: '#C3C5D9',radius: 18,fill: '#fff',},name: 'main-box',draggable: true,});group.addShape('text', {attrs: {text: cfg.id === _that.a.nodes[0].id ? '发起节点' : '结束',x: 40,y: -6,textAlign: 'center',textBaseline: 'middle',fill: '#202340',fontSize: 14,fontWeight: 500,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 20,},name: 'text-shape',});return startEnd;} else {// 判断是条件还是审核人展示不同样式if (cfg.dataType === 'condition') {// 条件:整个节点矩形const rect = group.addShape('rect', {attrs: {x: -75,y: -25,width: 230,height: 86,radius: 4,stroke: '#C3C5D9',fill: '#F7F8FA',lineWidth: 1,},name: 'rect-shape',});// 条件:上面标题矩形const titleRect = group.addShape('rect', {attrs: {x: -74.5,y: -24.5,width: 229,height: 35,radius: [4, 4, 0, 0],stroke: '#C3C5D9',fill: '#E2E3EE',lineWidth: 0,},name: 'rect-title',});// 条件:上面矩形标题文字const title = group.addShape('text', {attrs: {text: _that.fittingString(cfg.dataType + '标题', 198, 14),x: -58,y: -8,textAlign: 'left',textBaseline: 'middle',fill: '#565B85',fontSize: 14,fontWeight: 500,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 20,},name: 'title-box',});// 条件:矩形下面的文本文字const text = group.addShape('text', {attrs: {text: _that.fittingString(cfg.name + '文本', 198, 14),x: -58,y: 35,textAlign: 'left',textBaseline: 'middle',fill: '#202340',fontSize: 14,fontWeight: 500,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 20,},name: 'text-box',});return rect;} else { // 审核人展示的样式// 审核人:整个节点矩形const rect = group.addShape('rect', {attrs: {x: -75,y: -25,width: 230,height: 86,radius: 4,stroke: '#FFCA80',fill: '#FFF9F2',lineWidth: 1,},name: 'rect-shape',});// 审核人:上面标题矩形const titleRect = group.addShape('rect', {attrs: {x: -74.5,y: -24.5,width: 229,height: 35,radius: [4, 4, 0, 0],stroke: '#C3C5D9',fill: '#FFDFB2',lineWidth: 0,},name: 'rect-title',});// 审核人:上面矩形标题文字const title = group.addShape('text', {attrs: {text: _that.fittingString(cfg.dataType + '标题', 198, 14),x: -58,y: -8,textAlign: 'left',textBaseline: 'middle',fill: '#D97F00',fontSize: 14,fontWeight: 500,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 20,},name: 'title-box',});// 审核人:矩形下面的文本文字const text = group.addShape('text', {attrs: {text: _that.fittingString(cfg.name + '文本', 198, 14),x: -58,y: 35,textAlign: 'left',textBaseline: 'middle',fill: '#202340',fontSize: 14,fontWeight: 500,fontFamily: 'PingFangSC-Regular, PingFang SC',lineHeight: 20,},name: 'text-box',});return rect;}}},},'single-node',);},// 根据数据创建树状图节点createNode (mapData) {let tooltip = new G6.Tooltip({offsetX: 0,offsetY: 30,// 固定tooltip位置// fixToNode: [0, 1],// 允许出现 tooltip 的 item 类型itemTypes: ['node'],// 自定义 tooltip 内容getContent: (e) => {console.log('e=======', e.item);const outDiv = document.createElement('div');outDiv.style.width = '100%';// outDiv.style.background = 'red';outDiv.innerHTML = `<div>${e.item._cfg.model.name}</div>`;return outDiv;},shouldBegin: (e) => {let str = this.fittingString(e.item._cfg.model.name, 198, 14)let index = str.indexOf('.')if (index > -1) {return true}return false},});const container = document.getElementById('containerBox');const width = container.scrollWidth;const height = container.scrollHeight || this.mapHeight;const graph = new G6.Graph({container: 'containerBox',width,height,plugins: [tooltip],layout: {type: 'dagre',nodesepFunc: (d) => { // 节点左右边距if (d.id === '3') {return 500;}return 50;},ranksep: 60,  // 节点上下边距},defaultNode: {type: 'sql',anchorPoints: [[0.5, 1],[0.5, 0]]},defaultEdge: { // 连接线样式type: 'polyline',style: {radius: 0,offset: 45,// 这个字段默认是true// endArrow: true,lineWidth: 2,stroke: '#C3C5D9',endArrow: {path: 'M 0,0 L 8,4 L 8,-4 Z',fill: '#C3C5D9',},},},nodeStateStyles: {selected: {stroke: '#d9d9d9',fill: '#5394ef',},},modes: {default: ['drag-canvas','zoom-canvas','drag-node',// {//   type: 'tooltip',//   formatText (model) {//     const cfg = model.name;//     return cfg//   },//   shouldBegin: (e) => {//     let str = this.fittingString(e.item._cfg.model.name, 198, 14)//     let index = str.indexOf('.')//     if (index > -1) {//       return true//     }//     return false//   },//   offset: 30// },],},fitView: true,});graph.data(mapData);graph.render();// 这里是用于判断连接线是否有箭头//  mapData.nodes.forEach((node) => {//    if (node.dataType === 'condition') {//      mapData.edges.forEach((edge) => {//        if (edge.target === node.id) {//          edge.style.endArrow = false;//       }//     })//   }// });if (typeof window !== 'undefined')window.onresize = () => {if (!graph || graph.get('destroyed')) return;if (!container || !container.scrollWidth || !container.scrollHeight) return;graph.changeSize(container.scrollWidth, container.scrollHeight);};}}
}
</script>

四、这里提供了直接改官方示例数据,简单的参考

在官方图表示例找到Dagre 流程图

import G6 from '@antv/g6';
import insertCss from 'insert-css';insertCss(`.g6-tooltip {border-radius: 6px;font-size: 12px;color: #fff;background-color: #000;padding: 2px 8px;text-align: center;}
`);const data = {nodes: [{id: '1',dataType: 'alps',name: 'alps_file1',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],},{id: '2',dataType: 'alps',name: 'alps_file2',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],},{id: '3',dataType: 'alps',name: '11111',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],},{id: '4',dataType: 'sql',name: 'sql_file1',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],},{id: '5',dataType: 'sql',name: 'sql_file2',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],},{id: '6',dataType: 'feature_etl',name: 'feature_etl_1',conf: [{label: 'conf',value: 'pai_graph.conf',},{label: 'dot',value: 'pai_graph.dot',},{label: 'init',value: 'init.rc',},],}],edges: [{source: '1',target: '2',},{source: '1',target: '3',},{source: '2',target: '4',},{source: '3',target: '4',},{source: '4',target: '5',},{source: '5',target: '6',}],
};G6.registerNode('sql',{drawShape(cfg, group) {const rect = group.addShape('rect', {attrs: {x: -75,y: -25,width: 150,height: 50,radius: 10,stroke: '#5B8FF9',fill: '#C6E5FF',lineWidth: 3,},name: 'rect-shape',});if (cfg.name) {group.addShape('text', {attrs: {text: cfg.name,x: 0,y: 0,fill: '#00287E',fontSize: 14,textAlign: 'center',textBaseline: 'middle',fontWeight: 'bold',},name: 'text-shape',});}return rect;},},'single-node',
);const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.Graph({container: 'container',width,height,layout: {type: 'dagre',nodesepFunc: (d) => {if (d.id === '3') {return 500;}return 50;},ranksep: 70,},defaultNode: {type: 'sql',anchorPoints: [[0.5, 1],[0.5, 0]]},defaultEdge: {type: 'polyline',style: {radius: 0,offset: 45,endArrow: true,lineWidth: 2,stroke: '#C2C8D5',endArrow: {path: 'M 0,0 L 8,4 L 8,-4 Z',fill: '#C2C8D5',},},},nodeStateStyles: {selected: {stroke: '#d9d9d9',fill: '#5394ef',},},modes: {default: ['drag-canvas','zoom-canvas','drag-node',// 'click-select',// {//   type: 'tooltip',//   formatText(model) {//     const cfg = model.conf;//     const text = [];//     cfg.forEach((row) => {//       text.push(row.label + ':' + row.value + '<br>');//     });//     return text.join('\n');//   },//   offset: 30,// },],},fitView: true,
});
graph.data(data);
graph.render();if (typeof window !== 'undefined')window.onresize = () => {if (!graph || graph.get('destroyed')) return;if (!container || !container.scrollWidth || !container.scrollHeight) return;graph.changeSize(container.scrollWidth, container.scrollHeight);};

这篇关于AntV G6自定义流程图Graph的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

聊聊springboot中如何自定义消息转换器

《聊聊springboot中如何自定义消息转换器》SpringBoot通过HttpMessageConverter处理HTTP数据转换,支持多种媒体类型,接下来通过本文给大家介绍springboot中... 目录核心接口springboot默认提供的转换器如何自定义消息转换器Spring Boot 中的消息

Python自定义异常的全面指南(入门到实践)

《Python自定义异常的全面指南(入门到实践)》想象你正在开发一个银行系统,用户转账时余额不足,如果直接抛出ValueError,调用方很难区分是金额格式错误还是余额不足,这正是Python自定义异... 目录引言:为什么需要自定义异常一、异常基础:先搞懂python的异常体系1.1 异常是什么?1.2

Linux中的自定义协议+序列反序列化用法

《Linux中的自定义协议+序列反序列化用法》文章探讨网络程序在应用层的实现,涉及TCP协议的数据传输机制、结构化数据的序列化与反序列化方法,以及通过JSON和自定义协议构建网络计算器的思路,强调分层... 目录一,再次理解协议二,序列化和反序列化三,实现网络计算器3.1 日志文件3.2Socket.hpp

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

SpringBoot+EasyExcel实现自定义复杂样式导入导出

《SpringBoot+EasyExcel实现自定义复杂样式导入导出》这篇文章主要为大家详细介绍了SpringBoot如何结果EasyExcel实现自定义复杂样式导入导出功能,文中的示例代码讲解详细,... 目录安装处理自定义导出复杂场景1、列不固定,动态列2、动态下拉3、自定义锁定行/列,添加密码4、合并

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam