LogicFlow icon indicating copy to clipboard operation
LogicFlow copied to clipboard

fix(extension): 【dynamic-group】修复mousemove和isCollapsed相关问题

Open wbccb opened this issue 1 year ago • 1 comments

fix https://github.com/didi/LogicFlow/issues/1912 fix https://github.com/didi/LogicFlow/issues/1914 fix https://github.com/didi/LogicFlow/issues/1918

#1912

问题发生的原因

下面视频展示的关系为:dynamicGroupA嵌套dynamicGroupB,dynamicGroupB嵌套普通Node

由于dynamicGroupA嵌套dynamicGroupB,在dynamicGroupA进行折叠时,会触发dynamicGroupB的隐藏,从而触发dynamicGroupB的componentWillUnmount()销毁,但是如下面视频所示,dynamicGroupB的componentDidMount()注册了很多事件:

  componentDidMount() {
    super.componentDidMount()
    const { eventCenter } = this.props.graphModel
    // 在 group 旋转时,对组内的所有子节点也进行对应的旋转计算
    eventCenter.on('node:rotate', this.onNodeRotate)
    // 在 group 缩放时,对组内的所有子节点也进行对应的缩放计算
    eventCenter.on('node:resize', this.onNodeResize)
    // 在 group 移动时,对组内的所有子节点也进行对应的移动计算
    eventCenter.on('node:mousemove', this.onNodeMouseMove)
  }

但是忘记执行对应的事件移除,因此导致每一次折叠=>展开的时候,都会重复注册一次事件,因此导致下面视频所展示触发多次 moveNodes,也就是dynamicGroupB移动1px,会触发多次它的children的1px移动,从而造成移动错乱问题

https://github.com/user-attachments/assets/f36d09c0-d750-4c6a-86f6-5e1117949cd1

解决方法

将componentDidMount注册的监听事件方法抽离出来,为后面解除事件监听做准备

提交记录:refactor(extension): 【dynamic-group】将componentDidMount注册的监听事件方法抽离出来,为后面解除事件监听做准备

交互逻辑无变化,只是将注册方法抽离为this.xxxx方法,放在外部

componentWillUnmount移除监听

  componentWillUnmount() {
    super.componentWillUnmount()
    const { eventCenter } = this.props.graphModel
    eventCenter.off('node:rotate', this.onNodeRotate)
    eventCenter.off('node:resize', this.onNodeResize)
    eventCenter.off('node:mousemove', this.onNodeMouseMove)
  }

#1914

问题发生的原因

https://github.com/didi/LogicFlow/pull/1858改变了 group移动时,移动时需要同时移动组内的所有节点的逻辑代码,原来2.0.8版本中的逻辑是:

graphModel.addNodeMoveRules((model, deltaX, deltaY) => {
    // 判断如果是 group,移动时需要同时移动组内的所有节点
    if (model.isGroup) {
      const nodeIds = this.getNodesInGroup(model as DynamicGroupNodeModel)
      graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
      return true
    }
    //...
}

2.0.9版本中的逻辑是 2 0 9

而为什么会出现问题呢?

是因为

  • onDragging()->会进行坐标的处理,其中包括了SCALE的转化->触发addNodeMoveRules的注册的监听方法,也就是上面的2.0.8版本中的逻辑的graphModel.moveNodes(),此时的deltaXdeltaY是经过SCALE后的数据
  • 而在在2.0.9版本中的mousemove回调是跟 onDragging()同时发生的,拿到的deltaXdeltaY是没有经过SCALE后的数据
handleMouseMove = (e: MouseEvent) => {
    //...
    Promise.resolve().then(() => {
    this.onDragging({
        deltaX,
        deltaY,
        event: e,
    })
    this.eventCenter?.emit(EventType[`${this.eventType}_MOUSEMOVE`], {
        deltaX,
        deltaY,
        e,
        data: this.data || elementData,
    })
    //...
}

解决方法

deltaXdeltaY增加SCALE的转化

#1918

问题发生的原因

packages/extension/src/dynamic-group/model.ts中有这么一段代码

setAttributes() {
    super.setAttributes()

    // 初始化时,如果 this.isCollapsed 为 true,则主动触发一次折叠操作
    if (this.isCollapsed) {
       this.toggleCollapse(true)
    }
}

初始化时主动触发一次折叠操作是没问题的,但是我们从toggleCollapse可以知道,我们是通过elementsModelMap去获取对应的数据,但是存在着group已经初始化完成,但是children还没初始化的情况,这个时候elementsModelMap是找不到children数据的

toggleCollapse(collapse?: boolean) {
    const nextCollapseState = !!collapse
    this.isCollapsed = nextCollapseState
    // step 1
    //...

    // step 2
    const childrenArr = Array.from(this.children)

    forEach(childrenArr, (elementId) => {
      // FIX: 当使用 graphModel.getElement 获取元素时,会因为
      // const model = this.graphModel.getElement(elementId)
      const model = this.graphModel.elementsModelMap.get(elementId)
      //...
    })
    // step 3
    //...
  }

group已经初始化完成,但是children还没初始化的情况是如何发生的呢?

lf.render({
  nodes: [
    {
      type: "dynamic-group",
      x: 400,
      y: 400,
      properties: {
        children: ["rect_2"],
        isCollapsed: true,
      },
    },
    {
      id: "rect_2",
      type: "circle",
      x: 400,
      y: 400,
    },
  ],
});

当我们使用上面的数据进行渲染时,会触发getModelAfterSnapToGrid(),然后触发groupnew Model(),从而触发model.setAttributes()->toggleCollapse()->使用elementsModelMap寻找对应的childrenId对应的Model,此时找不到childrenModel,因为要等待group初始化好了,再执行childrennew Model(),然后将childrenModel放入到elementsModelMap

getModelAfterSnapToGrid(node: NodeConfig) {
    //...
    const nodeModel = new Model(node, this)
    this.nodeModelMap.set(nodeModel.id, nodeModel)
    this.elementsModelMap.set(nodeModel.id, nodeModel)

    return nodeModel
}

因此只要把数据翻转,也就是下面的顺序,先渲染children->group,那么一切就正常了!

lf.render({
  nodes: [
    {
      id: "rect_2",
      type: "circle",
      x: 400,
      y: 400,
    },
    {
      type: "dynamic-group",
      x: 400,
      y: 400,
      properties: {
        children: ["rect_2"],
        isCollapsed: true,
      },
    },
  ],
});

解决方法

将初始化时主动触发一次折叠操作放在全部渲染完成之后再执行,也就是 1918

wbccb avatar Oct 17 '24 11:10 wbccb

⚠️ No Changeset found

Latest commit: 05c801c7a0c13e548a0194745888e927b1614948

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

changeset-bot[bot] avatar Oct 17 '24 11:10 changeset-bot[bot]

大佬也太效率了。

还有点小问题,我这边把 dynamicGroup example 中 group_1 的 isCollapsed 设置为 true,初始化之后,分组没有自动合起来 0.o,你看下你那边有没有这个问题? image

boyongjiong avatar Oct 29 '24 08:10 boyongjiong

oh...失误=_=刚刚提交的@wbccbchore(extension): 【dynamic-group】删除无用的注释代码

image

又引发另一个eslint报错,我修复下

wbccb avatar Oct 29 '24 08:10 wbccb

image "我这边把 dynamicGroup example 中 group_1 的 isCollapsed 设置为 true,初始化之后,分组没有自动合起来"是因为上面截图的原因 @boyongjiong 例子可能得优化下,用的还是旧的Group

需要我把这个代码也提交上去吗?

wbccb avatar Oct 29 '24 08:10 wbccb

image "我这边把 dynamicGroup example 中 group_1 的 isCollapsed 设置为 true,初始化之后,分组没有自动合起来"是因为上面截图的原因 @boyongjiong 例子可能得优化下,用的还是旧的Group

需要我把这个代码也提交上去吗?

哈哈哈,有点好笑了,我之前开发 dynamic-group 用的是 engine-browser-examples 这个项目,然后代码没有同步过来。。

没事,你不管了,我把这个 PR 过了,我去同步代码

boyongjiong avatar Oct 29 '24 08:10 boyongjiong