@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节点。核心代码如下:
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");
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保证了卡片上的事件能正常触发。

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的功能给完善一下就更好了。

Vue 3是Vue.js的最新版本,它具有更好的性能、更好的TypeScript支持、更好的开发者体验等特点。Vite是一个轻量级的Web应用程序构建工具,它可以快速地构建Vue项目,同时支持TypeScript。AntV X6是一个强大的图形可视化库,它可以帮助开发人员快速地创建各种类型的图表和流程图。 下面是一个使用Vue 3、Vite、TypeScript和AntV X6自定义节点元素案例代码: ``` <template> <div class="app"> <x6-graph :graph="graph" :width="800" :height="600"> <template #default="{ node }"> <x6-rect v-if="node.data.type === 'rect'" :node="node" :width="node.getSize().width" :height="node.getSize().height" :fill="node.getStyle().fillColor" :stroke="node.getStyle().strokeColor" /> <x6-circle v-else-if="node.data.type === 'circle'" :node="node" :r="node.getSize().width / 2" :fill="node.getStyle().fillColor" :stroke="node.getStyle().strokeColor" /> </template> </x6-graph> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue' import { Graph, Node, Rect, Circle } from '@antv/x6' import { useUndoRedo } from '@antv/x6-vue' export default defineComponent({ setup() { const graph = ref<Graph>() useUndoRedo({ graph }) const nodes = [ { type: 'rect', x: 100, y: 100, width: 100, height: 50, style: { fillColor: '#ffffff', strokeColor: '#000000', }, }, { type: 'circle', x: 300, y: 100, width: 100, height: 100, style: { fillColor: '#ffffff', strokeColor: '#000000', }, }, ] graph.value = new Graph({ container: document.querySelector('.app')!, }) nodes.forEach((node) => { const shape = node.type === 'rect' ? Rect : Circle const newNode = new Node({ x: node.x, y: node.y, width: node.width, height: node.height, shape, data: node, }) newNode.setStyle(node.style) graph.value.addNode(newNode) }) return { graph } }, }) </script> ``` 此代码演示了如何在Vue 3项目中使用AntV X6创建自定义节点元素。在这个示例中,我们创建了两个不同类型的节点:一个矩形和一个圆形。我们通过给每个节点添加一个"type"属性来区分它们的类型。然后,我们在Vue模板中使用了`x6-rect`和`x6-circle`组件来渲染节点元素,这些组件分别对应于`Rect`和`Circle`节点形状。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值