vue2-x6-dag自定义vue组件节点

效果如图

在这里插入图片描述

官方案例

人工智能建模 DAG 图
vue2中自定义节点

代码

1.dag.json

[{"id": "1","shape": "dag-node","x": 290,"y": 110,"data": {"label": "读数据","status": "success"},"ports": [{"id": "1-1","group": "bottom"}]},{"id": "2","shape": "dag-node","x": 290,"y": 225,"data": {"label": "逻辑回归","status": "success"},"ports": [{"id": "2-1","group": "top"},{"id": "2-2","group": "bottom"},{"id": "2-3","group": "bottom"}]},{"id": "3","shape": "dag-node","x": 170,"y": 350,"data": {"label": "模型预测","status": "success"},"ports": [{"id": "3-1","group": "top"},{"id": "3-2","group": "bottom"}]},{"id": "4","shape": "dag-node","x": 450,"y": 350,"data": {"label": "读取参数","status": "success"},"ports": [{"id": "4-1","group": "top"},{"id": "4-2","group": "bottom"}]},{"id": "5","shape": "dag-edge","source": {"cell": "1","port": "1-1"},"target": {"cell": "2","port": "2-1"},"zIndex": 0},{"id": "6","shape": "dag-edge","source": {"cell": "2","port": "2-2"},"target": {"cell": "3","port": "3-1"},"zIndex": 0},{"id": "7","shape": "dag-edge","source": {"cell": "2","port": "2-3"},"target": {"cell": "4","port": "4-1"},"zIndex": 0}]

2.index.html

<html>
<head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>vue2-x6-DAG自定义vue组件节点</title><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><script type="text/javascript" src="https://unpkg.com/@antv/x6@1.34.14/dist/x6.js"></script><script type="text/javascript" src="https://unpkg.com/@antv/x6-vue-shape@1.1.4/dist/x6-vue-shape.js"></script><style>.node {display: flex;align-items: center;width: 100%;height: 100%;background-color: #fff;border: 1px solid #c2c8d5;border-left: 4px solid #5F95FF;border-radius: 4px;box-shadow: 0 2px 5px 1px rgba(0, 0, 0, 0.06);}.node img {width: 20px;height: 20px;flex-shrink: 0;margin-left: 8px;}.node .label {display: inline-block;flex-shrink: 0;width: 104px;margin-left: 8px;color: #666;font-size: 12px;}.node .status {flex-shrink: 0;}.node.success {border-left: 4px solid #52c41a;}.node.failed {border-left: 4px solid #ff4d4f;}.node.running .status img {animation: spin 1s linear infinite;}.x6-node-selected .node {border-color: #1890ff;border-radius: 2px;box-shadow: 0 0 0 4px #d4e8fe;}.x6-node-selected .node.success {border-color: #52c41a;border-radius: 2px;box-shadow: 0 0 0 4px #ccecc0;}.x6-node-selected .node.failed {border-color: #ff4d4f;border-radius: 2px;box-shadow: 0 0 0 4px #fedcdc;}.x6-edge:hover path:nth-child(2) {stroke: #1890ff;stroke-width: 1px;}.x6-edge-selected path:nth-child(2) {stroke: #1890ff;stroke-width: 1.5px !important;}@keyframes running-line {to {stroke-dashoffset: -1000;}}@keyframes spin {from {transform: rotate(0deg);}to {transform: rotate(360deg);}}</style>
</head><body><div id="workflow"><h5>注意事项:</h5><h6>1.必须启动前端服务访问,使用hbuilderx运行内置浏览器或者vscode安装Live Server插件,打开文件右键,选择“open with five server”即可,否则跨域!!!</h6><h6>2.cdn或本地引入方式x6-vue-shape版本必须和x6同一个大版本!!!</h6><button @click="add">外部点击Add第一个元素num</button><div id="container"></div></div>
</body></html>
<script>// 自定义vue组件节点const nodeBox = Vue.component('node-box', {template: `<div :class="['node', status]"  @click="nodeDrag()"><img :src="image.logo" /><span class="label">{{label}}内部Add:{{ num }}</span><span class="status"><img v-if="status === 'success'" :src="image.success" /><img v-if="status === 'failed'" :src="image.failed" /><img v-if="status === 'running'" :src="image.running" /></span></div>`,inject: ["getGraph", "getNode"],data() {return {// 自定义测试数字num: 0,// 自定义节点名称label: '',// 自定义节点状态status: '',// 状态数据iconimage: {logo: 'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*evDjT5vjkX0AAAAAAAAAAAAAARQnAQ',success:'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*6l60T6h8TTQAAAAAAAAAAAAAARQnAQ',failed:'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*SEISQ6My-HoAAAAAAAAAAAAAARQnAQ',running:'https://gw.alipayobjects.com/mdn/rms_43231b/afts/img/A*t8fURKfgSOgAAAAAAAAAAAAAARQnAQ',}}},mounted() {const node = this.getNode();// 监听数据改变事件,通过外部控制节点数据node.on("change:data", ({ current }) => {this.num = current.num;this.label = current.label;this.status = current.status;});},methods: {// 内部控制节点数据,节点拖动后触发,拿到x,y数据回传后端nodeDrag() {const node = this.getNode();const { num } = node.getData();node.setData({num: num + 1,});console.log('节点坐标:', node.position())},},})// 父页面const workflow = new Vue({el: '#workflow',data() {return {graph: null,};},mounted() {// 使用 CDN 引入时暴露了 X6 全局变量const { Graph, Path } = X6// 自定义vue节点Graph.registerNode("dag-node", {inherit: "vue-shape",x: 200,y: 150,width: 180,height: 36,component: {template: `<node-box />`,components: {nodeBox,},},ports: {groups: {top: {position: 'top',attrs: {circle: {r: 4,magnet: true,stroke: '#C2C8D5',strokeWidth: 1,fill: '#fff',},},},bottom: {position: 'bottom',attrs: {circle: {r: 4,magnet: true,stroke: '#C2C8D5',strokeWidth: 1,fill: '#fff',},},},},},});// 注册连接线Graph.registerEdge('dag-edge',{inherit: 'edge',attrs: {line: {stroke: '#C2C8D5',strokeWidth: 1,targetMarker: null,},},},true,)// 注册连接线弧度Graph.registerConnector('algo-connector',(s, e) => {const offset = 4const deltaY = Math.abs(e.y - s.y)const control = Math.floor((deltaY / 3) * 2)const v1 = { x: s.x, y: s.y + offset + control }const v2 = { x: e.x, y: e.y - offset - control }return Path.normalize(`M ${s.x} ${s.y}L ${s.x} ${s.y + offset}C ${v1.x} ${v1.y} ${v2.x} ${v2.y} ${e.x} ${e.y - offset}L ${e.x} ${e.y}`,)},true,)// 定义画布const graph = new Graph({container: document.getElementById('container'),// 对齐线snapline: true,width: 800,height: 600,panning: {enabled: true,eventTypes: ['leftMouseDown', 'mouseWheel'],},mousewheel: {enabled: true,modifiers: 'ctrl',factor: 1.1,maxScale: 1.5,minScale: 0.5,},highlighting: {magnetAdsorbed: {name: 'stroke',args: {attrs: {fill: '#fff',stroke: '#31d0c6',strokeWidth: 4,},},},},connecting: {snap: true,allowBlank: false,allowLoop: false,highlight: true,connector: 'algo-connector',connectionPoint: 'anchor',anchor: 'center',validateMagnet({ magnet }) {return magnet.getAttribute('port-group') !== 'top'},createEdge() {return graph.createEdge({shape: 'dag-edge',attrs: {line: {strokeDasharray: '5 5',},},zIndex: -1,})},},selecting: {enabled: true,multiple: true,rubberEdge: true,rubberNode: true,modifiers: 'shift',rubberband: true,},});this.graph = graph// 连接线,连接完成事件graph.on('edge:connected', ({ edge }) => {edge.attr({line: {strokeDasharray: '',},})})// 监听子节点数据改变graph.on('node:change:data', ({ node }) => {const edges = graph.getIncomingEdges(node)const { status } = node.getData()edges?.forEach((edge) => {if (status === 'running') {edge.attr('line/strokeDasharray', 5)edge.attr('line/style/animation', 'running-line 30s infinite linear')} else {edge.attr('line/strokeDasharray', '')edge.attr('line/style/animation', '')}})})// 数据状态const nodeStatusList = [[{id: '1',status: 'running',},{id: '2',status: 'default',},{id: '3',status: 'default',},{id: '4',status: 'default',},],[{id: '1',status: 'success',},{id: '2',status: 'running',},{id: '3',status: 'default',},{id: '4',status: 'default',},],[{id: '1',status: 'success',},{id: '2',status: 'success',},{id: '3',status: 'running',},{id: '4',status: 'running',},],[{id: '1',status: 'success',},{id: '2',status: 'success',},{id: '3',status: 'success',},{id: '4',status: 'failed',},],]// 初始化节点/边const init = (data) => {const cells = []data.forEach((item) => {if (item.shape === 'dag-node') {cells.push(graph.createNode(item))} else {cells.push(graph.createEdge(item))}})graph.resetCells(cells)}// 显示节点状态const showNodeStatus = async (statusList) => {const status = statusList.shift()status?.forEach((item) => {const { id, status } = itemconst node = graph.getCellById(id)const data = node.getData()node.setData({...data,status: status,num: 0,})})setTimeout(() => {showNodeStatus(statusList)}, 3000)}// 模拟数据fetch('./dag.json').then((response) => response.json()).then((data) => {// 加载节点init(data)// 节点状态showNodeStatus(nodeStatusList)// 将画布内容中心与视口中心对齐graph.centerContent()})},methods: {// 控制子组件内部变量add() {const nodes = this.graph.getNodes();console.log(nodes)if (nodes.length) {nodes.forEach((node) => {// 1 为该组件id,正式环境根据传参id来控制具体某个元素内部if (node.id == 1) {const { num } = node.getData();node.setData({num: num + 1,});}});}},}});
</script>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/135457.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【iOS】push与present Controller的区别

文章目录 前言一、push方法二、pop方法三、present方法四、dismiss方法五、dismiss多级的方法举例动画 前言 iOS推出与退出界面有两种方式——push与present&#xff0c;接下来笔者分别介绍这两种方式 一、push方法 SecondViewController *second [[SecondViewController all…

【C++】AVL树

个人主页&#xff1a;&#x1f35d;在肯德基吃麻辣烫 我的gitee&#xff1a;C仓库 个人专栏&#xff1a;C专栏 文章目录 前言一、什么是AVL树&#xff1f;设计AVL树的原因 二、AVL树的性质三、二叉树节点的定义四、AVL树的插入旋转1&#xff09;右单旋2&#xff09;左单旋3&…

目标检测中生成锚框函数详解

%matplotlib inline import torch from d2l import torch as d2l torch.set_printoptions(2) # 让pytorch打印张量时&#xff0c;只打印到小数点后两位将设一张图片&#xff0c;宽和高为2,2 X torch.rand(size(1,3,2,2)) Y generate_anchors(X,sizes[0.75,0.5,0.25],ratios[…

HPC集群自动弹性扩缩的两种实现方式

常青藤 HPC常青园 2023-07-28 19:48 发表于北京 弹性扩缩技术正在成为HPC集群中的一项重要技术。它可以根据实际需求动态调整集群资源&#xff0c;应对用户负载的波动。对于运维团队来说&#xff0c;自动弹性扩缩能够减轻集群运维负担&#xff0c;提高集群资源利用率&#xff0…

小程序Saas平台源码:开启电商小程序新时代,可视化后台自由DIY的无限可能

在当今数字化的时代&#xff0c;小程序已成为各行各业开展业务的重要工具。尤其在电商领域&#xff0c;小程序能有效地缩短消费者与商品之间的距离&#xff0c;提升营销效率。给大家分享一款针对电商行业的小程序Saas平台源码&#xff0c;它具有一键生成电商小程序、可视化后台…

Go基础八股

【Go面试】Go slice深拷贝和浅拷贝_哔哩哔哩_bilibili 基础篇 1.Go方法值接收者和指针接收者的区别 简单言之就是是否会影响调用的结构体&#xff0c;方法接收者是指针会影响 2.返回局部变量的指针 一般来说&#xff0c;局部变量会在函数返回后被销毁&#xff0c;因此被返回…

flink的网络缓冲区

背景 在flink的taskmanager进行数据交互的过程中&#xff0c;网络缓冲区是一个可以提升网络交换速度的设计&#xff0c;此外&#xff0c;flink还通过网络缓冲区实现其基于信用值credit的流量控制&#xff0c;以便尽可能的处理数据倾斜问题 网络缓冲区 在flink中每个taskmana…

C++ 太卷,转 Java?

最近看到知乎、牛客等论坛上关于 C 很多帖子&#xff0c;比如&#xff1a; 2023年大量劝入C 2023年还建议走C方向吗&#xff1f; 看了一圈&#xff0c;基本上都是说 C 这个领域唯一共同点就是都使用 C 语言&#xff0c;其它几乎没有相关性。 的确是这样&#xff0c;比如量化交…

微信小程序遇到的一些问题及解决方法(设备安装)

微信小程序遇到的一些问题及解决方法 1、[js将字符串按照换行符分隔成数组](https://blog.csdn.net/pgzero/article/details/108730175)2、[vue byte数组](https://www.yzktw.com.cn/post/1202765.html)3、使用vant-weapp的文件上传capture"camera" 无法直接调用摄像…

OPC UA协议报文,基础介绍+Hello报文解析

消息主要分为&#xff1a;消息头和附加字段 通讯过程 协议标准第一部分进行总体介绍&#xff1b;协议标准第四部分有详细介绍通讯过程 流程介绍 整体流程 连接套接字》Hello》打开安全信道》创建会话》关闭安全信道》关闭套接字 订阅等事件 服务器审核行为 聚合的服务器审…

基于未知环境碰撞冲突预测的群机器人多目标搜索研究

源自&#xff1a;指挥与控制学报 作者&#xff1a;边晓荟 周少武 张红强 吴亮红 王汐 王茂 刘朝华 陈磊 “人工智能技术与咨询” 发布 摘 要 群机器人在未知动态环境下进行多目标搜索时&#xff0c;存在碰撞预测和搜索效率不高等问题。提出了一种碰撞几何锥和改进惯性权重…

中秋特辑:Java事件监听实现一个猜灯谜小游戏

众所周知&#xff0c;JavaSwing是Java中关于窗口开发的一个工具包&#xff0c;可以开发一些窗口程序&#xff0c;然后由于工具包的一些限制&#xff0c;导致Java在窗口开发商并没有太多优势&#xff08;当然也有一些第三方的工具包也很好用&#xff09;&#xff0c;不过&#x…

一款适用于教培机构的微信CRM系统

在教育培训行业中&#xff0c;有效的客户关系管理&#xff08;CRM&#xff09;系统至关重要。微信作为一种流行的社交媒体平台&#xff0c;具有巨大的潜在价值&#xff0c;可以被用来提升教培机构的客户管理和销售效率。 一些教育培训行业存在的问题 ①每年开班收学员太多&…

二叉树的几个递归问题

我的主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言&#xff1a; 二叉树的递归是二叉树很重要的问题&#xff0c;几乎解决二叉树的问题都要使用递归&#xff0c;接下来我们将解决二叉树几个最基础的递归问题。 目录 前言&#xff1a; 二叉树的前序&#xff0c;中序&…

JDK jps命令复习

之前写过jdk命令工具的博文&#xff0c;下面复习jps命令&#xff1b; jps 是 Java Process Status Tool 的简称,它的作用是为了列出所有正在运行中的 Java 虚拟机进程和相关信息&#xff1b; jps 命令参数 -q 只输出进程 ID,省略主类的名称 -m 输出虚拟机进程启动时传递…

基于Java新枫之谷游戏攻略设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

数据结构---链表(java)

目录 1. 链表 2. 创建Node 3. 增加 4. 获取元素 5. 删除 6. 遍历链表 7. 查找元素是否存在 8. 链栈的实现 9. 链队的实现 1. 链表 数据存放在"Node"结点中 优点&#xff1a;不用考虑扩容和缩容的问题&#xff0c;实现了动态存储数据 缺点&#xff1a;没有…

在Python中 作用域与命名空间的坑

前言&#xff1a; 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 1. 命名空间 1.1 什么是命名空间 Namespace命名空间&#xff0c;也称名字空间&#xff0c;是从名字到对象的映射。 Python中&#xff0c;大…

【多卡训练报错】:The server socket has failed to listen on any local network address.

错误&#xff1a; RuntimeError: The server socket has failed to listen on any local network address. The server socket has failed to bind to [::]:16664 (errno: 98 - Address already in use). The server socket has failed to bind to 0.0.0.0:16664 (errno: 98 -…

JMeter:接口测试基础介绍

一、什么是接口 接口是非常抽象的概念&#xff0c;先来看下中国最大的综合性辞典《辞海》是怎样定义接口的&#xff1a; 两个不同系统或系统中两个不同特性部分的交接部分。一般分硬件接口和软件接口两种。前者是为连接计算机各部分之间、计算机与计算机之间、计算机与外部系统…