@antv/x6 自定义节点Safari兼容问题处理

背景

  1. 为什么选择@antv/x6?
    由于x6提供了一套强大友好的流程图API,并且支持使用 React、Vue 组件来渲染节点。这样可以使用组件开发的方式去快速完成卡片开发,并实现更加复杂的业务逻辑。
  2. 遇到了Safari的兼容问题
    由于x6自定义节点基于SVG foreignObject节点去实现的,但是Safari对foreignObject的实现不够完整,这就出现了在safari上出现了无法设置节点的位置,有些内容展示不出来的问题。
    以下是x6官网上Vue使用案例在Chrome和Safari上的展示对比:
    Chrome 效果

    Safari 效果

    卡片跑到了左上角位置,设置的卡片位置完成无效了

参考:

Safari上SVG foreignObject中<video>元素的位置错误

解决Safari浏览器使用SVG foreignObject 不生效,错位的问题

解决方式

一开始想的是有没有对应的polyfill去解决foreignObject的兼容问题,但是没有找到。后面发现了x6-html-shape这个库,采用了html节点的方式,避开了foreignObject。

x6-html-shape原理解析

  1. 节点绘制
    x6-html-shape通过创建一个html容器节点覆盖在svg画布的上层,使用绝对定位+transform将自定义节点绘制到这个html容器内,在每个节点的下层会对应相关的svg空节点。这样避免了使用Svg foreignObject的方式。
  2. 事件处理
    对于画布上的事件通过添加pointer-events:none样式,使事件透传。卡片上事件通过监听直接转发到下层的svg节点。核心代码如下:
ts 复制代码
Dom.css(htmlContainer, {
    position: "absolute",
    width: "100%",
    height: "100%",
    "touch-action": "none",
    "user-select": "none",
    "pointer-events": "none",
    'z-index': 0,
    'transform-origin': 'left top',
});
htmlContainer.classList.add("x6-html-shape-container");
ts 复制代码
Dom.css(container, {
    "pointer-events": "auto",
    "touch-action": "none",
    "user-select": "none",
    "transform-origin": "center",
    position: "absolute",
})
container.classList.add("x6-html-shape-node");
      // forward events
const events = "click,dblclick,contextmenu,mousedown,mousemove,mouseup,mouseover,mouseout,mouseenter,mouseleave".split(",");
events.forEach((eventType) =>
    forwardEvent(eventType, container, this.container)
);
this.graph.htmlContainer.append(container);

container 就是自定义的卡片容器,卡片内容将放在里面, this.container能获取到对应的svg节点。这里container的pointer-events设置成了auto保证了卡片上的事件能正常触发。

ts 复制代码
export function forwardEvent(eventType, fromElement, toElement) {
  fromElement.addEventListener(eventType, function (event) {
    toElement.dispatchEvent(new event.constructor(event.type, event));
    event.preventDefault();
    event.stopPropagation();
  });
}

通过调用forwardEvent将自定义卡片上的事件转发到svg节点上。

使用中的问题

可能由于这个库,使用的人并不多,很多问题没有被发现,我在实际使用的时候也遇到了以下的问题:

  1. 缩放后节点错位,节点并没有合理缩放
  2. 卡片上不能滚动问题
  3. 节点删除后,下层对应的svg节点未删除
  4. 无法显示或隐藏节点问题
  5. 节点较多时缩放失效问题
  6. 卡片上点击功能按钮el-popover不展示问题(开发卡片时阻止按钮的事件冒泡行为即可)
    由于原作者精力有限,忙于其他事情。我就自己主动提交了PR,参与到了这个项目的贡献。后续作者也给开通了github代码提交权限和npm包的发布权限,以上问题都得到了解决。

总结

总体来说,x6-html-shape很好的解决了x6使用SVG foreignObject绘制自定义节点在Safari上的兼容问题。这个库的解决思路非常不错,希望能帮助到更多的人。当然如果Safari能把foreignObject的功能给完善一下就更好了。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试