「AntV」X6开发实践:踩过的坑与解决方案

这篇具有很好参考价值的文章主要介绍了「AntV」X6开发实践:踩过的坑与解决方案。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

长期更新版文档请移步语雀(「AntV」X6开发实践:踩过的坑与解决方案 (yuque.com)) --Recent update:2024-01-05

🖼️ | 如何自定义拖拽源?

相信你们在开发中更多的需求是需要自定义拖拽源,毕竟自定义的功能扩展性高一些,而且可以根据你的业务需求灵活设置。自定义拖拽的优点就是:万物皆可成为拖拽源,不管你使用的是html标签,还是第三方的ui框架,或者树形列表,……这些都可以设置成拖拽源,只有你想不到的,没有官方做不到的,来吧,开整。

官方提供的拖拽

「AntV」X6开发实践:踩过的坑与解决方案

自定义的拖拽

「AntV」X6开发实践:踩过的坑与解决方案

解决方案

这里使用的是Dnd插件,因为我看官方介绍说Stencil插件内部也是依靠Dnd实现的,索性就直接使用Dnd来搞吧

步骤1:初始化Dnd

// 先定义个全局的dnd变量
let dnd = null;
// 在mounted中对dnd进行初始化(在graph之后初始化)
dnd = new Dnd({
  target: graph,
  scaled: false,
  dndContainer: proxy.$refs.dndContainer
});

步骤2:定义拖拽事件

/**
 * 自定义拖拽源事件
 * @param {*} e
 * @param {*} treeNode 根据需要传入要添加的参数
 * @param {*} data 根据需要传入要添加的参数
 * 这里使用的是elementPlus的tree组件
 */
const startDrag = (e, treeNode, data) => {
  console.log('eee', e);
  console.log('treeNode', treeNode);
  console.log('data', data);
  const node = graph.createNode({
    shape: 'cu-data-node',
    width: 150,
    height: 104,
    label: data?.label,
	// 传递给自定义节点的数据
    data: {
      label: data?.label,
      img: data?.img,
      desc: data?.desc
    },
    ports: {
      ...port,
      items: [
        {
          group: 'top'
        }
      ]
    }
  });
  dnd.start(node, e);
};

步骤3:自定义html节点

  // 注册自定义节点 图标+标题+描述
  Shape.HTML.register({
    shape: 'cu-data-node',
    width: 'auto',
    height: 104,
    effect: ['data'],
    html(cell) {
      // 获取节点传递过来的数据
      const { label, img, desc } = cell.getData();
      // 创建自定义的节点容器
      const container = document.createElement('div');
      container.setAttribute('class', 'cu-container');
      // 图片根据不同的类型进行切换,可以是后端返回的图标,也可以是自己本地的图标,如果是后端返回就通过节点的data传进来
      const container_img = document.createElement('img');
      container_img.src = currentTab.value === 0 ? '/src/assets/images/operator/datasouce.png' : img;
      container_img.setAttribute('class', 'cu-container-img');


      const container_title = document.createElement('div');
      container_title.innerText = label;
      container_title.setAttribute('class', 'cu-container-title');


      const container_desc = document.createElement('div');
      container_desc.setAttribute('class', 'cu-container-desc');
      container_desc.innerText = desc || '描述信息';


      container.appendChild(container_img);
      container.appendChild(container_title);
      container.appendChild(container_desc);


      return container;
    }
  });

步骤4:元素绑定拖拽事件

<!-- $event必传,后面的参数根据你的业务需求动态添加 -->
<div  @mousedown="startDrag($event, node, data)">拖拽的节点</div>

🖼️ | 本地图片导出后不显示?

先看看官方的导出文档:
图片导出

由于业务需要,需要把画布上的节点保存成图片供其它模块展示,如果你的后端返回的数据格式是前端想要的,那么大不必搞图片的形式,直接把官网的快速上手代码拿过来循环一下就好了……,这里就拿toPng的方法来讲解

问题梳理

  • 调用toPng拿到画布的base64数据
  • 把base64的数据传给后端
  • 后端把base64的数据转存后生成可访问的图片地址再返回给前端
  • 前端开始展示

然而事情却没有这么简单,第一步就遇到了一堆的坑,由于官网上导出的都是它内置的节点,所以导出都没啥问题,但是我使用的是html节点,导出的时候,我节点的图片就死活导不出来,而且导出的样式也是乱的(样式错乱问题)

解决方案

一句话:图片必须得是base64格式的导出才会有图片,不然无法导出节点的图片

  1. 自定义html节点中把图片转换成base格式的

需要调用 imageToDataUri把图片地址转成base64的数据,这个方法我也是摸索了好久才找到的,官方文档完全没有提及这个方法,如果需要查看其它方法,请打印 DataUri这个对象

DataUri.imageToDataUri('/images/operator/datasouce.png',
  function (nu, url) {
    // 第一个参数无效,用的只是第二个参数,但是第一个参数不写不行
    container_img.src = url; // 给图片标签赋值
  }
);
  1. 调用toPng生成base64数据

这个步骤中要处理的问题:导出后样式不正确,导出的时候页面闪动

graph.toPNG(
  dataUri => {
    console.log('dataUri >>>>', dataUri); // 这个就是base的图片地址
  },
  {
    width: 526,
    height: 268,
    backgroundColor: 'rgba(25, 87, 121, 0.18)',
    quality: 1, // 图片质量 取值范围:0-1,默认0.92
    // copyStyles: false,
    // 自定义样式表,为了解决导出后节点样式丢失的问题,暂时官方还没有修复这个bug
    stylesheet: `
      .cu-container {
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      }
      .cu-container-title {
      color: #d3e6f3;
      }
      .cu-container-img {
      width: 53px;
      height: 53px;
      margin-bottom: 4px;
      }
      .cu-container-desc {
      color: rgba(211, 230, 243, 0.7);
      margin-top: 3px;
      }
      .cu-container-title,
      .cu-container-desc {
      font-size: 14px;
      font-weight: 400;
      line-height: 20px;
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 1;
      }
    `
  }
);

:::warning
Tip:图片导出样式和原节点的样式不一致问题:如果你遇到了这个问题,目前最好的方法是不断调整stylesheet中的样式,直到导出的样式和原节点的样式几乎一致即可。当然,如果你的甲方不重视页面交互,咱们完全可以使用copyStyles:true这个属性就行了,这样就不用设置 stylesheet
:::


🖼️ | 神奇的图片边框

:::tips
昨天才把html节点中的图片转成base格式的,今天就发现一个用户体验的问题;那么是啥呢?就是我从左侧的树形菜单中拖拽节点的时候(鼠标按下也是同样问题),发现节点的图片区域那里会出现一个边框,持续时间不是很长,就几毫秒的时间,但是当你连续拖拽几个不同节点的时候就会发现这个边框竟然又消失不见了,如果此时重新进入页面,再开始拖动节点,图片的边框又出现了。
:::

问题梳理

  • 是否是官方节点自带的边框?如果是,配置项是什么?
  • 图片的默认边框是否被清除?还是外围元素的边框导致?
  • 图片的加载时机?
  • 是否是转base64的问题,毕竟在这之前没有这个情况发生……
    :::tips
    带着这些问题,第一时间去翻阅了官方文档,发现没有和这个问题相关的配置项,即使有设置了也不管用;然后就把问题抛到了交流群里面,发现压根没人回答……,那就只能开始第二个方案了:把图片的默认边框都去除掉,比如border,box-shadow,outline这些属性都去除掉了,发现还是没用;好吧,开始第三套方案:使用new Image处理图片的加载时机问题,嗯!不出意外的话,这个方法还是不行
    :::

定位问题

经过上面四个方案的尝试后,我大概知道了问题的源头在哪边了,那就是我自定义html节点中图片地址赋值的地方,由于DataUri.imageToDataUri 这个方法是个异步执行的,所以才会导致在渲染的时候会出现短暂的视觉差

解决方案

  • 先给图片赋值个普通的地址(非base64的地址)
  • DataUri.imageToDataUri('随便写个参数名',url)的回调中再把图片的src替换成base64的
const container_img = document.createElement('img');
container_img.setAttribute('class', 'cu-container-img');
container_img.setAttribute('alt', '节点ico');
container_img.style.cursor = 'pointer';
// 先用远程图片地址给图片的src赋值,然后再重新赋值成base64的格式;这么做的目的就是解决节点拖拽到画布上会出现短暂的边框闪动问题,如果你要复现这个边框,可以把下面这一行代码注掉(不是必现)
container_img.src = img;
// 把图片转成base64方便存储到后端
DataUri.imageToDataUri(img, function (nu, url) {
// 第一个参数无效,用的只是第二个参数,但是第一个参数不写由不行
container_img.src = url;
});

🖼️ | 画布内容从接口获取数据后无法居中?

场景

前端需要把画布上的节点保存到后端,然后前端在获取详情接口的时候要把节点进行居中处理

问题梳理

在不调用后端接口的情况下使用centerContent()是没得问题的;但是在动态获取节点数据后就会存在异步加载的问题,也就是先将内容居中了,之后再设置节点到画布中去,此时centerContent的时机已经过去了,节点还是更具自身的位置进行排列

解决方案

由于作者用的vue技术栈,所以这里的解决方法主要以vue为主

方案1:使用nextTick等待dom全部渲染完成

nextTick(() => {
	graph.centerContent();
});

方案2:直接在接口中使用

getDataView({ size: -1, name: item.tableMetaName }).then(res => {
    if (res.code === 0) {
      // 缩放
      graph.zoom(-0.1);
      // 画布居中
      graph.centerContent();
    }
});

🖼️ | 自定义右键菜单坐标不准确?

问题梳理

原本的写法是节点右键的时候通过node.position()的方法获取节点的坐标,然后再把节点的坐标绑到右键菜单的dom上,但是发现对画布进行平移的时候,右键菜单的位置还停留在第一次的位置,原因就是画布平移和节点没啥关系,节点的坐标并不会因为画布平移了就自动更改自身的坐标

解决方案

对鼠标的坐标进行转换,这也是1.9版本中新增的一个方法,关键是在官方文档中还找不到这个方法,只能死马当活马医了 坐标转换,果然问题解决了

graph.on('node:contextmenu', ({ e, node }) => {
  const pos = graph.clientToGraph(e.clientX, e.clientY);// 核心代码就是这一行
  createMenuDom({ x: pos.x, y: pos.y, node, type: 0 });
});

附:自定义右键菜单完整代码

这里需要对javascript的dom有点基础,不过这只是我创建dom的方法,如果你们想用其它的方法也是可以的哈

let divMenuContainer = null;
const createMenuDom = ({ x, y, node, edge, type }) => {
  if (divMenuContainer) {
    // 如果存在了菜单,就先移除再创建,不然你的页面上会多出来好多菜单的
    document.getElementById('container').removeChild(divMenuContainer);
  }
  divMenuContainer = document.createElement('div');
  divMenuContainer.setAttribute('class', 'div-menu-container');
  divMenuContainer.style.left = x + 30 + 'px';
  divMenuContainer.style.top = y + 'px';
  const divMenuItem = document.createElement('div');
  divMenuItem.setAttribute('class', 'div-menu-item');
  divMenuItem.innerText = type === 0 ? '删除节点' : '删除边';
  divMenuItem.addEventListener('click', () => {
    type === 0 ? graph.removeNode(node) : graph.removeEdge(edge);
    divMenuContainer.style.display = 'none';
  });
  divMenuContainer.appendChild(divMenuItem);
  document.getElementById('container').appendChild(divMenuContainer);
  document.body.addEventListener('click', () => {
    if (divMenuContainer) {
      divMenuContainer.style.display = 'none';
    }
  });
};
graph.on('node:contextmenu', ({ e, node }) => {
  // 坐标转换
  const pos = graph.clientToGraph(e.clientX, e.clientY);
  // 调用创建dom的方法,把坐标和节点信息传递进去
  createMenuDom({ x: pos.x, y: pos.y, node, type: 0 });
});

效果图

「AntV」X6开发实践:踩过的坑与解决方案


🖼️ | 在历史记录中忽略某个属性的修改

常见问题
也是下面这个问题的解决方案
「AntV」X6开发实践:踩过的坑与解决方案
这是官方的demo
连线 undo - CodeSandbox

history插件配置

new Graph({
  history: {
    enabled: true,
    beforeAddCommand(event, args: any) {
      // 忽略历史变更
      if (args.options.ignoreHistory) {
        return false
      }
    },
  },
})

边的写法

graph.on('edge:connected', ({ edge }) => {
   // 传入自定义的 ignoreHistory 选项来忽略历史变更
   edge.attr('line/strokeDasharray', null, { ignoreHistory: true })
})

节点的写法

new History({
  enabled: true,
  beforeAddCommand(event, args) {
    if (args.options.ignoreHistory) {
      return false;
    }
  }
})
node.setData({ tableMeta: res.data.records, desc: res?.data?.records?.length || 0 }, { ignoreHistory: true });

🖼️ | x和y坐标为字符串报错问题

解决方案

直接把x,y坐标转成纯数字的即可,不然拖动节点的时候会报错的


🖼️ | 设置节点移动范围在画布内

Transform

new Graph({
  translating: {
  restrict: true
}
})

🖼️ | 获取当前节点的所有父级节点

此方法会返回所有的输入和输出边,如果只要输入边的节点或者输出边的节点信息,请看这里链接

const getParentNodes = node => {
  const nodeId = node.id;
  const connectedNodes = [];
  // 如果需要其他方法,请看下方的具体配置,根据自己的需要修改这里的代码即可
  const edges = graph.getConnectedEdges(node, { deep: true });
  for (const edge of edges) {
    const sourceNode = edge.getSourceNode();
    const targetNode = edge.getTargetNode();
    if (sourceNode.id !== nodeId) {
      connectedNodes.push(sourceNode);
    }
    if (targetNode.id !== nodeId) {
      connectedNodes.push(targetNode);
    }
  }
  return connectedNodes;
};

// 具体的配置
const edges = graph.getConnectedEdges(node) // 返回输入和输出边
const edges = graph.getConnectedEdges(node, { incoming: true, outgoing: true }) // 返回输入和输出边

const edges = graph.getConnectedEdges(node, { incoming: true }) // 返回输入边
const edges = graph.getConnectedEdges(node, { incoming: true, outgoing: false }) // 返回输入边

const edges = graph.getConnectedEdges(node, { outgoing: true }) // 返回输出边
const edges = graph.getConnectedEdges(node, { incoming:false, outgoing: true }) // 返回输出边

const edges = graph.getConnectedEdges(node, { deep: true }) // 返回输入和输出边,包含链接到所有子孙节点/边的输入和输出边
const edges = graph.getConnectedEdges(node, { deep: true, incoming: true }) // 返回输入边,包含链接到所有子孙节点/边的输入边
const edges = graph.getConnectedEdges(node, { deep: true, enclosed: true }) // 返回输入和输出边,同时包含子孙节点/边之间相连的边

const edges = graph.getConnectedEdges(node, { indirect: true }) // 返回输入和输出边,包含间接连接的边

🖼️ | 注册自定义节点报错?

报错信息

(in promise) Error: Node with name 'cu-port' already registered.

下面这个报错是群友发的,但是问题和我之前遇到的是一类问题,所以就直接告诉群友问题所在了😀
「AntV」X6开发实践:踩过的坑与解决方案

错误代码

Graph.registerNode(name,options)

正确代码

Graph.registerNode(name,options,true)


🖼️ | 常用方法集锦

  1. 清空画布:graph.clearCells()
  2. 画布缩小:graph.zoom(-0.5)
  3. 获取画布缩放比例:graph.zoom()
  4. 获取画布上所有节点:graph.getNodes()
  5. 获取画布上所有边:graph.getEdges()
  6. 设置节点移动范围在画布内链接
translating: {
  restrict: true
},
  1. 动态设置节点位置链接:node.position(x,y)
  2. 节点只能被相同的源节点连接一次链接:allowMulti: false
  3. 两个节点连接的时候获取目标节点的数据链接
graph.on('edge:connected', ({ isNew, edge, currentCell }) => {
  // 回调的参数:https://antv-x6.gitee.io/zh/docs/tutorial/intermediate/events/#%E8%BE%B9%E8%BF%9E%E6%8E%A5%E5%8F%96%E6%B6%88%E8%BF%9E%E6%8E%A5
  console.log('被连接的节点详细参数', currentCell);
  if (currentCell.data['type'] === 0) {
    proxy.$modal.msgError('数据源无法作为输出节点');
    // 移除连接的边
    graph.removeEdge(edge?.id);
  }
});
  1. 判断当前节点是否被连接链接
const node = graph.getCellById('node1')
const connectedEdges = graph.getConnectedEdges(node)

附:参考文档
Dnd插件
Stencil插件
图片导出
1.x常见问题
坐标转换
Transform
Model文章来源地址https://www.toymoban.com/news/detail-474451.html

到了这里,关于「AntV」X6开发实践:踩过的坑与解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于python的mediapipe库踩过的坑

      大家好,我是csdn的博主: lqj_本人 这是我的个人博客主页: lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主 lqj_本人擅长微信小程序,前端,vue,等方面的知识 https://blog.csdn.net/lbcyllqj?spm=1000.2115.3001.5343 哔哩哔哩欢迎关注: 小淼前端 小淼前端的个人空间_哔哩哔哩_bilibil

    2024年01月17日
    浏览(37)
  • docker+selenium+firefox | 我踩过的坑

    为了实现SSPUBot不在我电脑上部署,我只能将其制成Docker。 要知道SSPUBot在开发的时候用了selenium+Firefox的想法开发,所以Docker里面必须要有Firefox,结果这就让见识到了最顽固的错误 selenium.common.exceptions.WebDriverException: Message: Process unexpectedly closed with status 255 我们还是省略我找的

    2024年01月22日
    浏览(54)
  • Spark搭建日志,记录一些踩过的坑

    本人在Centos中使用三个虚拟机(node1,node2,node3)搭建hadoop与Spark分布式环境(具体见后记中的Hadoop安装),本文记录一些踩过的坑 解决办法:sudo chown -R 用户名 /spark(spark或者hadoop所在目录) 原理:文件的初始所有者不是用户名(如root),要把spark目录的初始所有者更换为自

    2024年03月14日
    浏览(83)
  • hql(hive sql)中的join及踩过的坑

    1 几种join方式 join join 对应于 inner join 内连接。 当多张表进行 join 的时候,所有表中与 on 条件中匹配的数据才会显示。 hql (即 hive sql )的 on 子句中只支持 and ,不支持 or ,也不支持 null 的对比。 left outer join 左外连接,也称为左连接。 以左表为基准,如果右表有条件匹配

    2024年01月21日
    浏览(42)
  • 嵌入式-stm32重要基础知识(及踩过的坑)

    1、固件库: 固件库就是函数的集合,固件库函数的作用是向下负责与寄存器直接打交道, 向上提供用户函数调用的接口(API)。 2、CMSIS标准与固件库的关系 就是对固件库函数的要求。 ARM 公司为了能让不同的芯片公司生产的 Cortex-M3 芯片能在软件上基本兼容,和芯片生产商

    2024年02月04日
    浏览(54)
  • 微信小程序哪些wifi+tcp+udp踩过的坑

    1、wx.startWifi 开启wifi模块 2、如果需要展示wifi列表则调用 wx.getWifiList(Object object) 注意: 请求获取 Wi-Fi 列表。wifiList 数据会在 onGetWifiList 注册的回调中返回。 Android 调用前需要 用户授权 scope.userLocation。 iOS 上将跳转到系统设置中的微信设置页,需要用户手动进入「无线局域网

    2024年02月15日
    浏览(42)
  • vue前端预览pdf并加水印、ofd文件,控制打印、下载、另存,vue-pdf的使用方法以及在开发中所踩过的坑合集

    根据公司的实际项目需求,要求实现对pdf和ofd文件的预览,并且需要限制用户是否可以下载、打印、另存pdf、ofd文件,如果该用户可以打印、下载需要控制每个用户的下载次数以及可打印的次数。正常的预览pdf很简单,直接调用浏览器的预览就可以而且功能也比较全,但是一

    2024年02月16日
    浏览(171)
  • 真人踩过的坑,告诉你避免自动化测试常犯的10个错误

    虽然从自己的错误中学习也不错,但从别人的错误中学习总是更好的。 作为一个自动化测试人员,分享常见的容易犯的10个错误,可以从中吸取教训,引以为鉴。 一、必要时才自动化 新人小王接到为Web应用程序自动化测试脚本的任务时,既高兴又紧张,因为这是他进入团队

    2023年04月08日
    浏览(39)
  • vue h5player.min.js对接海康威视,踩过的坑

    一、播放的视频无法占满全屏 1、JSResize()接口内部做了50ms防抖动,调用不会立即生效,延时50ms获取最新大小设置窗口。 2、h5player内部会在网页缩放的时候自适应父容器大小,但是在单独变更父容器大小的时候无法自适应,需要重新设置大小 3、出现不生效的问题一般是有单

    2024年02月14日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包