位置: IT常识 - 正文

使用antv/G6在vue项目中开发较复杂样式流程图(antv g6 node 嵌套)

编辑:rootadmin
使用antv/G6在vue项目中开发较复杂样式流程图 使用antv/G6开发流程图前言一、什么是 G6?二、使用步骤1.安装依赖并导入2.初始化数据3.树图实现(1)首先配置自定义节点(2)自定义带箭头的贝塞尔曲线(连接线)(3)设置默认样式(4)配置树图并渲染(6)小地图插件4.一般图实现(1)自定义节点(2)配置图属性并渲染(3)自定义tooltip5.插件三、注意事项总结前言

推荐整理分享使用antv/G6在vue项目中开发较复杂样式流程图(antv g6 node 嵌套),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:ant-vue,antv g2 vue,ant vue3,antdv vue,ant vue3,antv g6 node 嵌套,antdv vue,antdv vue,内容如对您有帮助,希望把文章链接给更多的朋友!

设计师提供了一版样式较复杂的流程图,我搜了一些常用的vue-super-flow和vue-x6-flow等都只支持简单的样式。之前自己写过纯展示流程图不涉及太多交互,感觉还是找一个成熟的插件开发更适合,也方便其他同事参考,所以最后选择了用antv/G6自己个性化开发,总结了使用antv/G6在vue项目中开发常见流程图的过程。

示例如下:

一、什么是 G6?

G6官方文档链接 https://g6.antv.vision/zh/docs/manual/introduction G6 是一个图可视化引擎。它提供了图的绘制、布局、分析、交互、动画等图可视化的基础能力。旨在让关系变得透明,简单。让用户获得关系数据的 Insight。

基于 G6,用户可以快速搭建自己的 图分析 或 图编辑 应用。

G6 作为一款专业的图可视化引擎,具有以下特性: 优秀的性能:支持大规模图数据的交互与探索; 丰富的元素:内置丰富的节点与边元素,自由配置,支持自定义; 可控的交互:内置 10+ 交互行为,支持自定义交互; 强大的布局:内置了 10+ 常用的图布局,支持自定义布局; 便捷的组件:优化内置组件功能及性能; 友好的体验:根据用户需求分层梳理文档,支持 TypeScript 类型推断。 除了默认好用、配置自由的内置功能,元素、交互、布局均具有高可扩展的自定义机制。

二、使用步骤1.安装依赖并导入npm install --save @antv/g6import G6 from '@antv/g6';2.初始化数据

常用的主要是两大类,一般图和树图。

一般图的数据结构是:

data:{//节点nodes:[{id: 'XXX', label: 'XXX', key: 'XXX', text: 'XXX', img: require('XXX'),},...],// 连接线edges:[{ source: '起始id', target: '到达id',},...]}使用antv/G6在vue项目中开发较复杂样式流程图(antv g6 node 嵌套)

树图的数据结构是:

data:{id:'XXX',label: 'XXX', children: [ { id: 'XXX', label: 'XXX', children: [ { id: 'XXX', label: 'XXX', children: [] }, ...] }, ...],}

我一开始选定了用树图实现,实现了样式以后发现没有办法满足产品要求的能够隐藏/显示不同层级并且重新渲染层级关系的功能,最后又更换成了一般图的布局方式。

3.树图实现(1)首先配置自定义节点 G6.registerNode( 'icon-node', { options: { size: [90, 50], // 设置节点大小 stroke: '#91d5ff', // 设置节点边框颜色 fill: '#91d5ff', // 设置节点背景颜色 }, draw(cfg, group) { const styles = this.getShapeStyle(cfg); const { labelCfg = {} } = cfg; const w = styles.width; const h = styles.height; // 我的项目里需要区分多个节点显示不同的样式,我用key来区分 if (cfg.key != "ACTION") { const keyShape = group.addShape('rect', { attrs: { ...styles, x: -w / 2, y: -h / 2, }, }); /** * leftIcon 格式如下: * { * style: ShapeStyle; * img: '' * } */ if (cfg.leftIcon) { const { style, img } = cfg.leftIcon; // addShape是添加图形,可以添加不同的属性,具体配置可以看官方文档 group.addShape('rect', { attrs: { x: 1 - w / 2, y: 1 - h / 2, width: 38, height: styles.height - 2, fill: '#8c8c8c', ...style, }, }); group.addShape('image', { attrs: { x: 8 - w / 2, y: 8 - h / 2, width: 24, height: 24, img: img || 'https://www.yuucn.com/wp-content/uploads/2023/04/1682801894-8d347f4f69dd15b.png', }, name: 'image-shape', }); } if (cfg.label) { group.addShape('text', { attrs: { ...labelCfg.style, text: cfg.label, x: 50 - w / 2, y: 28 - h / 2, }, }); } return keyShape; } else { var keyShape = group.addShape('image', { attrs: { x: 8 - w / 2, y: 8 - h / 2, width: 24, height: 24, img: 'https://www.yuucn.com/wp-content/uploads/2023/04/1682801894-8d347f4f69dd15b.png', }, name: 'image-shape', }); group.addShape('text', { attrs: { fill: '#2f6bff', fontSize: 24, text: cfg.label, x: 8 - w / 2, y: 8 - h / 2, }, }); group.addShape('text', { attrs: { fill: '#333333', fontSize: 14, text: '项目', x: 8 - w / 2, y: h - 4, }, }); group.addShape('image', { attrs: { x: 40 - w / 2, y: h - 20, width: 14, height: 14, img: 'https://www.yuucn.com/wp-content/uploads/2023/04/1682801894-8d347f4f69dd15b.png', }, }); return keyShape; } }, update: undefined, // 自定义锚点,方便连线 getAnchorPoints: () => { return [ [0, 0.5], // 左侧中间 [1, 0.5], // 右侧中间 ]; }, }, 'single-shape', );(2)自定义带箭头的贝塞尔曲线(连接线) G6.registerEdge('flow-line', { draw(cfg, group) { const startPoint = cfg.startPoint; const endPoint = cfg.endPoint; const { style } = cfg; const shape = group.addShape('path', { attrs: { stroke: style.stroke, // endArrow: style.endArrow, // 需要箭头可以自己配置箭头 有开始箭头和结束箭头 path: [ // 用path路径配置带折点的连接线 M表示开始的坐标,L表示拐点的坐标 ['M', startPoint.x, startPoint.y], ['L', (startPoint.x + endPoint.x) / 2, (startPoint.y)], ['L', (startPoint.x + endPoint.x) / 2, endPoint.y], ['L', endPoint.x, endPoint.y], ], }, }); return shape; }, afterDraw(cfg, group) { const shape = group.get('children')[0]; const startPoint = shape.getPoint(0); //创建节点之间的圆圈,并为每一个设置样式 const circle = group.addShape('circle', { attrs: { x: startPoint.x + 92, y: startPoint.y, fill: '#cbdaff', r: 4, //圆圈大小 }, name: 'circle-shape', }); // 实现动态效果,从线的开始滑到结束 circle.animate( ratio => { const tmpPoint = shape.getPoint(ratio); return { x: tmpPoint.x, y: tmpPoint.y, }; }, { repeat: 1, //动画是否重复 duration: 3000, //一次动画持续时长 }, ); }, }, );(3)设置默认样式 // 设置默认开启状态样式 const defaultStateStyles = { hover: { stroke: '#2f6bff', }, };// 设置默认节点样式 const defaultNodeStyle = { fill: '#fff', stroke: '#cbdaff', radius: 5, shadowColor: '#cbdaff', // 阴影颜色 shadowBlur: 10, // 阴影范围 shadowOffsetX: 0, // 阴影偏移位置 shadowOffsetY: 5, cursor: 'pointer', // 鼠标移动到节点上的样式 };// 设置默认链接线样式 const defaultEdgeStyle = { stroke: '#cbdaff', // 结尾箭头样式 endArrow: { path: 'M 0,0 L 12, 6 L 9,0 L 12, -6 Z', fill: '#91d5ff', d: -60, // x轴上的偏移量 }, }; // 设置默认节点名称样式 const defaultLabelCfg = { style: { fill: '#333', fontSize: 14, }, };(4)配置树图并渲染const graph = new G6.TreeGraph({ container: 'html元素的id', width: XXX, // 渲染的宽度 height: XXX, // 渲染的高度 linkCenter: true, plugins: [minimap], // 配置插件 modes: { default: ['drag-canvas', 'zoom-canvas'], // 常用的拖拽和缩放 }, defaultNode: { type: 'icon-node', // 自定义节点名称,记得保持一致 size: [120, 40], //设置节点大小 style: defaultNodeStyle, // 配置过的默认样式,直接写在这里也可以 labelCfg: defaultLabelCfg, // 配置过的默认样式,直接写在这里也可以 }, defaultEdge: { type: 'flow-line', // 自定义连接线名称,记得保持一致 style: defaultEdgeStyle, // 配置过的默认样式,直接写在这里也可以 }, nodeStateStyles: defaultStateStyles, // 配置过的默认样式,直接写在这里也可以 edgeStateStyles: defaultStateStyles, // 配置过的默认样式,直接写在这里也可以 // 若数据中不存在节点位置,则默认为随机布局。配置布局类型及其参数。 layout: { // 类型 总共三种:径向:radial 有向分层:dagre 力导:force type: 'dagre', rankdir: 'LR', // 可选值:'TB' | 'BT' | 'LR' | 'RL',默认为图的中心 TB T,B,L,R 代表top,bottom,left,right },});graph.data(data); // 配置数据graph.render(); // 渲染流程图graph.fitView(); // 让画布内容适应视口,可选参数padding, rules, animate, animateCfg(6)小地图插件// 设置出现一个缩略地图const minimap = new G6.Minimap({ size: [150, 100], });4.一般图实现(1)自定义节点

一般图中获取节点属性获取不到节点的宽高,所以自己设置一个w、h,然后再刚刚的基础上加入一些细节

G6.registerNode( // 该新节点类型名称 'node', // 该新节点类型的定义 // 当有 extendedTypeName (第三个参数)时,没被复写的函数将会继承 extendedTypeName 的定义 { // cfg 节点身上所有的配置:包括label,size,x,y坐标等 // 这个方法,每渲染一个节点,执行一次 drawShape(cfg, group) { const styles = this.getShapeStyle(cfg); // ctg上的id key label 都可以决定当前节点的类型 // 可以根据标题长度设置节点的大小 // cfg.size = (cfg.label.length / 10) * 130; // if (cfg.label.length / 10 < 1) { // widthX = 120; // } else { // widthX = cfg.size; // } let w = 180, h = 50; // 根据设计图第一个节点主要是展示图片和个数,配置对应的形状 if (cfg.key == "0") { w = 100; h = 155; var keyShape = group.addShape('image', { attrs: { x: -w / 2, y: -h / 2, width: w, height: h, img: cfg.img, }, name: 'image-shape', }); group.addShape('circle', { attrs: { x: w / 2, y: 0, r: 2.5, fill: '#fff', stroke: '#cbdaff', lineWidth: 2, }, }); group.addShape('text', { attrs: { fill: '#2f6bff', fontSize: 24, text: cfg.label, textAlign: 'center', x: 0, y: -45, }, }); group.addShape('text', { attrs: { fill: '#333333', fontSize: 14, text: '项目', textAlign: 'center', x: 0, y: h / 2 - 30, }, }); return keyShape; } else { // 根据标题的长度判断节点的高度 var rowNum = 0 for (let i = 0; i < cfg.label.length; i++) { var j = i + rowNum if (i % 8 == 0 && i > 0 && j != cfg.label.length) { var newStr = cfg.label.slice(0, j) + "\n" + cfg.label.slice(j); cfg.label = newStr rowNum++; } } if (rowNum > 1) { h += (rowNum - 1) * 15 } cfg.size = [w, h] const rect = group.addShape('rect', { attrs: { x: -w / 2, y: -h / 2, width: w, height: h, fill: '#fff', stroke: '#a0d4ff', radius: 9, shadowColor: '#a0d4ff', // 阴影颜色 shadowBlur: 10, // 阴影范围 shadowOffsetX: 0, // 阴影偏移位置 shadowOffsetY: 5, cursor: 'pointer', // 鼠标移动 到节点上的样式 }, }); group.addShape('circle', { attrs: { x: 0 - w / 2, y: 0, r: 2.5, fill: '#fff', stroke: '#a0d4ff', lineWidth: 2, }, }); group.addShape('image', { attrs: { x: cfg.key != '1' ? 17 - w / 2 : 12 - w / 2, y: cfg.key != '1' ? -15 : -19, width: cfg.key != '1' ? 30 : 38, height: cfg.key != '1' ? 30 : 38, img: cfg.img, }, }); group.addShape('text', { attrs: { x: 60 - w / 2, y: 0, fill: '#333333', fontSize: 14, text: cfg.label, textBaseline: 'middle', }, }); return rect; } }, /** * 获取锚点(相关边的连入点) * @param {Object} cfg 节点的配置项 * @return {Array|null} 锚点(相关边的连入点)的数组,如果为 null,则没有控制点 */ // 自定义锚点 getAnchorPoints: () => { return [ [0, 0.5], // 左侧中间 [1, 0.5], // 右侧中间 ]; }, }, // 被继承的节点类型,可以是内置节点类型名,也可以是其他自定义节点的类型名。 // extendedTypeName 未指定时代表不继承其他类型的节点; // 例如基类 'single-node',或 'circle', 'rect' 等 'single-shape' );

连接线跟上面树图的配置一样即可,如果想要曲线可以自己修改

(2)配置图属性并渲染 const graph = new G6.Graph({ // 常用配置项 // 类型:Boolean;默认:'false'。图是否自适应画布。 fitView: true, // 类型:Number | Array;默认:0。图自适应画布时的四周留白像素值。fitView 为 true 时生效。 // fitViewPadding : 0 // 类型:Boolean;默认:'false'。是否平移图使其中心对齐到画布中心。v3.5.1 后支持。 fitCenter: true, // bloodView:流程图容器id container: 'projectView', width:'XXX', height:'XXX', //modes 交互行为相关 // 配置多种交互模式及其包含的交互事件的。 modes: { default: [ 'drag-canvas', 'zoom-canvas', // 如果没有特殊的样式可以直接用内置的tooltip // { // type: 'tooltip', // formatText(model) { // console.log(model) // const cfg = model.text; // const text = model.text; // // cfg.forEach((row) => { // // text.push(row.label + ':' + row.value + '<br>'); // // }); // return text; // }, // offsetX: 70, // offsetY: 20, // }, ], }, plugins: [tooltip], // 这次项目悬浮框用了插件 zoom: 1, // 若数据中不存在节点位置,则默认为随机布局。配置布局类型及其参数。 layout: { // 类型 总共三种:径向:radial 有向分层:dagre 力导:force type: 'dagre', // 'LR':从左至右布局; rankdir: 'LR', // 可选可选值:'TB' | 'BT' | 'LR' | 'RL',默认为图的中心 TB nodesep: 20, //节点之间的距离,水平布局时指垂直距离 ranksep: 40, //层级之间的距离,水平布局时指垂直距离 }, // defaultNode类型:Object。默认情况下全局节点的配置项,包括样式属性和其他属性 // G6 的内置节点包括 // circle圆形,rect长方形,ellipse椭圆,diamond菱形,triangle三角形, // star五角星,image图片,modelRect卡片,donut圆形(v4.2.5 起支持)。 defaultNode: { type: 'node', // 这里的type指向自定义节点 // size:300, size: [180, 50], style: defaultNodeStyle, labelCfg: defaultLabelCfg, }, // defaultEdge 类型:Object。默认情况下全局边的配置项,包括样式属性和其他属性 defaultEdge: { type: 'flow-line', style: { endArrow: true, lineWidth: 2, stroke: '#cbdaff', }, }, nodeStateStyles: defaultStateStyles, edgeStateStyles: defaultStateStyles, }); // 动态配置完层级后需要销毁后重新渲染,否则页面上会显示多个渲染的流程图 if (this.graph != null) { this.graph.destroy(); } this.graph = graph graph.data(data); // 渲染 graph.render(); // this.graph.zoomTo(1); // 缩放 参数为缩放的倍数,后面也可跟x,y坐标,将以传入坐标为中心 // this.graph.moveTo(0,height/2); // 采用绝对位移将画布移动到指定坐标(3)自定义tooltip

需求中的悬浮框需要展示该节点下面的所有项目及带有查看详情按钮,所以我使用了插件没有用内置的。

需要注意的一点是在getContent()里的代码一定要严格遵守编写规范,尤其注意后面一定要带';',否则会一直报错而且你找不到原因!!!

const tooltip = new G6.Tooltip({ offsetX: -400, // 偏移距离 offsetY: -850, trigger: 'click', // 触发方式 可选 mouseenter, getContent(e) { const outDiv = document.createElement('div'); outDiv.style.width = '270px'; outDiv.style.padding = '0 10px'; let ulText = ``; if (typeof (e.item.getModel().text) == 'object') { (e.item.getModel().text).map((item, index) => { ulText += `<li style='padding:5px 60px 5px 0; position: relative;word-break: break-all;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;font-size: 12px;'>项目名称:<span style="color:#333">${item.label}</span><span type="text" style="color: #2f6bff;border:none;background:transparent;cursor:pointer; position: absolute;top: 50%;right: 0;transform: translateY(-50%);">查看详情</span></li>`; }); outDiv.innerHTML = `<div style="font-size:14px;color:#333;font-weight:bold;">${e.item.getModel().label}</div><ul style="margin:10px 0 0;padding:0;font-size:12px">` + ulText + `</ul>`; } else { outDiv.innerHTML = `<div style="font-size:14px;color:#333;font-weight:bold;">${e.item.getModel().label}</div>`; } return outDiv }, itemTypes: ['node'] });5.插件

G6 提供了一些可插拔的组件,包括: Legend (v4.3.0 起支持) SnapLine (v4.3.0 起支持) Grid Minimap ImageMinimap Edge Bundling Menu ToolBar TimeBar Tooltip Fisheye EdgeFilterLens

三、注意事项

如何让 IE 支持 G6

对于这类问题,我们在项目中只需要引入 babel-polyfill 即可,具体使用方法如下:

在主入门文件中引入 babel-polyfill ; 在 bable-loader 中加入如下代码:

{ test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('node_modules/@antv/g6')]}

include 表示哪些目录中的 .js 文件需要进行 babel-loader;exclude 表示哪些目录中的 .js 文件不要进行 babel-loader。

总结

以上就是今天要讲的内容,本文仅仅简单介绍了antv/G6的使用,更多的示例及API请移步官方文档。

本文链接地址:https://www.jiuchutong.com/zhishi/297814.html 转载请保留说明!

上一篇:React--》超详细教程——React脚手架的搭建与使用(reactz)

下一篇:java前后端加密解密crypto-js(java前后端加密解密请求)

  • 车辆租赁费发票备注栏怎么写
  • 购入房产计入什么科目
  • 用友t3采购订单怎么录入
  • 退休职工能否扣医保
  • 哪些福利费可以进在建工程
  • 企业转让固定资产使用权的收益应当属于
  • 财产转让所得的纳税义务发生时间
  • 废旧物资回收经营范围
  • 企业股权转让留存收益可以扣除吗
  • 法定预算调整的范围
  • 房地产开发资质管理办法
  • 公司厂房拆迁要交税吗
  • 金蝶软件钩稽怎么操作
  • 计入资本公积的固定资产转出
  • 简易征收电费能不能抵扣
  • 服务行业也有合伙人吗
  • 中标服务费会计科目
  • 单位代缴纳职工个税如何账务处理
  • 暂估冲红的分录怎么写
  • linux系统 推荐
  • 金蝶固定资产减少怎么做
  • 公积金补缴上月算断缴吗
  • win7系统我的电脑图标不见了
  • 合伙企业必须有什么并以其作为企业法律基础
  • linux中nano什么指令
  • 摊销房租怎么做账
  • 一般纳税人做账报税的整个流程详细
  • 应付票据可能涉及的科目
  • flex的几个常用布局
  • vue.js前端开发快速入门与专业应用
  • php-xml
  • php背景图片代码
  • 跨年度收取的发票怎么开
  • 关于猿猴的作文
  • 技术和商业模式怎么写
  • php 银行卡支付
  • 公司是否可以开具在职证明
  • mongodb查看数据库大小
  • 怎么盘存货
  • 费用发票先入账吗
  • 房地产企业根据什么交增值税
  • 利息收入为负数的原因
  • 变动成本法的计算步骤
  • 外经证适用范围
  • 现金付发票再摊销怎么算
  • 收到托收凭证怎么做分录
  • 研发支出费用化和资本化的界定
  • 存货账面价值的确定
  • 融资租赁的固定资产视为企业自有固定资产管理
  • sqlserver获取表结构
  • sql server 用法
  • sql批量修改数据语句
  • mysql安装使用教程
  • Vista 新命令收集整理完整版
  • freebsd怎么样
  • freebsd配置dns
  • 2016年最火的歌曲排行前100首
  • centos和rhel
  • win7如何开机修复系统
  • 系统升级后c盘空间小了
  • Aero glass for Win8.1黑屏/不兼容弹窗的解决方法介绍
  • cocos2dx4.0教程
  • unity3d功能
  • jquery教程w3c
  • 判断一个点在三角形内部
  • kmp算法代码完整实现
  • shell脚本运行linux命令
  • 简单的jquery插件实例
  • scrapy python
  • php curl获取cookie
  • 深入理解新发展理念
  • python socket connect
  • 无序列表html
  • 【Rayeager PX2分享】OpenCV入门之线段检测
  • 汽车购车发票开完票能更改名字吗?
  • 进口lng需要什么资质
  • 江苏电子税务局官网登录入口
  • 税务非正常户要提交什么资料
  • 社保诚信申报怎么取消
  • 代理记账资质办理在哪个网站提交申请
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设