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

相关文章

CSS自定义浏览器滚动条样式完整代码

《CSS自定义浏览器滚动条样式完整代码》:本文主要介绍了如何使用CSS自定义浏览器滚动条的样式,包括隐藏滚动条的角落、设置滚动条的基本样式、轨道样式和滑块样式,并提供了完整的CSS代码示例,通过这些技巧,你可以为你的网站添加个性化的滚动条样式,从而提升用户体验,详细内容请阅读本文,希望能对你有所帮助...

SpringBoot 自定义消息转换器使用详解

《SpringBoot自定义消息转换器使用详解》本文详细介绍了SpringBoot消息转换器的知识,并通过案例操作演示了如何进行自定义消息转换器的定制开发和使用,感兴趣的朋友一起看看吧... 目录一、前言二、SpringBoot 内容协商介绍2.1 什么是内容协商2.2 内容协商机制深入理解2.2.1 内容

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float....但有时候我们需要特殊的格式, 如将name定义为(firstname,lastname)的形式,我们想把这个作为一个表的一列看待,这时候就要我们自己定义一个数据类型 格式 :create or repla

HTML5自定义属性对象Dataset

原文转自HTML5自定义属性对象Dataset简介 一、html5 自定义属性介绍 之前翻译的“你必须知道的28个HTML5特征、窍门和技术”一文中对于HTML5中自定义合法属性data-已经做过些介绍,就是在HTML5中我们可以使用data-前缀设置我们需要的自定义属性,来进行一些数据的存放,例如我们要在一个文字按钮上存放相对应的id: <a href="javascript:" d

一步一步将PlantUML类图导出为自定义格式的XMI文件

一步一步将PlantUML类图导出为自定义格式的XMI文件 说明: 首次发表日期:2024-09-08PlantUML官网: https://plantuml.com/zh/PlantUML命令行文档: https://plantuml.com/zh/command-line#6a26f548831e6a8cPlantUML XMI文档: https://plantuml.com/zh/xmi

argodb自定义函数读取hdfs文件的注意点,避免FileSystem已关闭异常

一、问题描述 一位同学反馈,他写的argo存过中调用了一个自定义函数,函数会加载hdfs上的一个文件,但有些节点会报FileSystem closed异常,同时有时任务会成功,有时会失败。 二、问题分析 argodb的计算引擎是基于spark的定制化引擎,对于自定义函数的调用跟hive on spark的是一致的。udf要通过反射生成实例,然后迭代调用evaluate。通过代码分析,udf在

鸿蒙开发中实现自定义弹窗 (CustomDialog)

效果图 #思路 创建带有 @CustomDialog 修饰的组件 ,并且在组件内部定义controller: CustomDialogController 实例化CustomDialogController,加载组件,open()-> 打开对话框 , close() -> 关闭对话框 #定义弹窗 (CustomDialog)是什么? CustomDialog是自定义弹窗,可用于广告、中