antvx6鼠标按下过程中无法触发其他事件的问题

374 阅读2分钟

想要的效果

在react中使用antvx6制作一个可以绘制流程图的组件

连接桩.png

上图中,想实现从左侧圆拉出一条箭头连接到右侧圆,当箭头到达右侧圆范围内才显示连接桩(大圆四周的小圆圈),否则不显示。

遇到的问题

想要实现以上效果需要拖住箭头(鼠标左键按下),如果此时我们使用antvx6自带的node:mouseenter事件检测鼠标是否进入到圆的范围内,由于此时鼠标是按下状态,会有一个拖拽事件,所以node:mouseenter事件无法触发。也就是说,当拖拽箭头进入到监听的圆中,无法触发,但是不拖拽箭头是可以的。

如何解决

由于antvx6暂时提供的api无法直接实现当前效果,但是其提供了edge:change:target这个检测属性,当拖拽箭头时可以获取箭头的坐标,同时,node(圆)中也提供了position(位置)与size(长宽)方法,我们则可以根据position的x,y坐标与size提供的width与height属性计算出圆的圆心位置和半径,如圆心为(x1,y1),半径为radius,箭头的位置为(x2,y2)。则可以根据Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2))计算出箭头位置与圆心的距离,并与半径进行比较,如果符合判定条件就可以设置连接桩的属性来控制连接桩的显隐。

但是如何知道用户要将箭头连向哪个圆呢,我这里采取比较暴力的做法,每当向画布中添加圆时,将所有圆的node对象存在一个大的对象中,此大的对象包含所有的圆(node对象),每当拖动箭头时,则会遍历整个大的对象执行上述的计算。

注:若页面中圆过多,可能会过于占用资源。

代码

以下是控制链接桩显隐的函数。

const showPorts = (node: any, ports: any, visible: boolean) => {
    ports.forEach((port: any) => {
        //设置连接桩属性
        node.setPortProp(
                port.id,
                'attrs/circle/style/visibility',
                visible ? 'visible' : 'hidden',
        )
    })
}

判断两点距离与半径相比较的代码

const calueCirclePendingScope = (node: any, current: any) => {
        //半径
        const radius = node.size().width / 2;
        const { x, y } = node.position();
        const x2 = x + radius;
        const y2 = y + radius;
        const x1 = current.x;
        const y1 = current.y;

        const dis = Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
        if (dis < radius + 10) {
                showPorts(node, node.getPorts(), true);
        } else {
                showPorts(node, node.getPorts(), false);
        }
}