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

相关文章

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

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

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

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

如何自定义一个log适配器starter

《如何自定义一个log适配器starter》:本文主要介绍如何自定义一个log适配器starter的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录需求Starter 项目目录结构pom.XML 配置LogInitializer实现MDCInterceptor

Python使用Code2flow将代码转化为流程图的操作教程

《Python使用Code2flow将代码转化为流程图的操作教程》Code2flow是一款开源工具,能够将代码自动转换为流程图,该工具对于代码审查、调试和理解大型代码库非常有用,在这篇博客中,我们将深... 目录引言1nVflRA、为什么选择 Code2flow?2、安装 Code2flow3、基本功能演示

Druid连接池实现自定义数据库密码加解密功能

《Druid连接池实现自定义数据库密码加解密功能》在现代应用开发中,数据安全是至关重要的,本文将介绍如何在​​Druid​​连接池中实现自定义的数据库密码加解密功能,有需要的小伙伴可以参考一下... 目录1. 环境准备2. 密码加密算法的选择3. 自定义 ​​DruidDataSource​​ 的密码解密3

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

Spring Security自定义身份认证的实现方法

《SpringSecurity自定义身份认证的实现方法》:本文主要介绍SpringSecurity自定义身份认证的实现方法,下面对SpringSecurity的这三种自定义身份认证进行详细讲解,... 目录1.内存身份认证(1)创建配置类(2)验证内存身份认证2.JDBC身份认证(1)数据准备 (2)配置依

使用Sentinel自定义返回和实现区分来源方式

《使用Sentinel自定义返回和实现区分来源方式》:本文主要介绍使用Sentinel自定义返回和实现区分来源方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Sentinel自定义返回和实现区分来源1. 自定义错误返回2. 实现区分来源总结Sentinel自定

如何自定义Nginx JSON日志格式配置

《如何自定义NginxJSON日志格式配置》Nginx作为最流行的Web服务器之一,其灵活的日志配置能力允许我们根据需求定制日志格式,本文将详细介绍如何配置Nginx以JSON格式记录访问日志,这种... 目录前言为什么选择jsON格式日志?配置步骤详解1. 安装Nginx服务2. 自定义JSON日志格式各

Android自定义Scrollbar的两种实现方式

《Android自定义Scrollbar的两种实现方式》本文介绍两种实现自定义滚动条的方法,分别通过ItemDecoration方案和独立View方案实现滚动条定制化,文章通过代码示例讲解的非常详细,... 目录方案一:ItemDecoration实现(推荐用于RecyclerView)实现原理完整代码实现