Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(extension): 【dynamic-group】修复resize和move的冲突问题(#1826) #1858

Merged
merged 2 commits into from
Sep 20, 2024

Conversation

wbccb
Copy link
Contributor

@wbccb wbccb commented Sep 9, 2024

related: #1826

问题出现的原因

注:本次pr建立在rotate=0的情况下,还没涉及到rotate不等于0的适配,因为涉及到bbox的调整,需要后续再优化rotate不等于0的情况....

目前dynamic-groupresize操作存在两个问题:

  1. group里面的item没有按照比例进行缩放
  2. group缩放时,会触发this.xthis.y的改变,同时也会触发group.itemthis.xthis.y改变,然后groupresize再次出发group.itemthis.xthis.y的改变,从而造成了两倍,也就是this.x=this.x+2*deltaX

问题1分析

由于比较简单,因此这里不再做详细分析,如下图所示,应该根据group.item.width在group.width所占的比例进行deltaX的换算
pr-1

问题2分析

class BaseNodeModel {
  resize(resizeInfo: ResizeInfo): ResizeNodeData {
    const { width, height, deltaX, deltaY } = resizeInfo;
    // 移动节点以及文本内容
    this.move(deltaX / 2, deltaY / 2);
    //...
  }
  move(deltaX: number, deltaY: number, isIgnoreRule = false): boolean {
    const { isAllowMoveX, isAllowMoveY } = this.isAllowMoveByXORY(
      deltaX,
      deltaY,
      isIgnoreRule
    );
    //...
  }
  isAllowMoveByXORY(deltaX: number, deltaY: number, isIgnoreRule: boolean) {
    let isAllowMoveX: boolean;
    let isAllowMoveY: boolean;
    if (isIgnoreRule) {
      isAllowMoveX = true;
      isAllowMoveY = true;
    } else {
      const r = this.isAllowMoveNode(deltaX, deltaY);
      //...
    }
    return {
      isAllowMoveX,
      isAllowMoveY,
    };
  }
  isAllowMoveNode(deltaX: number, deltaY: number): boolean | Model.IsAllowMove {
    let isAllowMoveX = true;
    let isAllowMoveY = true;
    const rules = this.moveRules.concat(this.graphModel.nodeMoveRules);
    for (const rule of rules) {
      const r = rule(this, deltaX, deltaY);
      //...
    }
    return {
      x: isAllowMoveX,
      y: isAllowMoveY,
    };
  }
}

而上面的this.graphModel.nodeMoveRules就是在packages/extension/src/dynamic-group/index.ts中增加的移动规则

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

因此group缩放时,会触发this.xthis.y的改变,同时也会触发group.itemthis.xthis.y改变


然后groupresize再次出发group.itemthis.xthis.y的改变,如下面代码所示

eventCenter.on("node:resize", ({ deltaX, deltaY, index, model }) => {
  // TODO: 目前 Resize 的比例值有问题,导致缩放时,节点会变形,需要修复
  if (model.id === curGroup.id) {
    forEach(Array.from(curGroup.children), (childId) => {
      const child = graphModel.getNodeModelById(childId);
      if (child) {
        // child.rotate = model.rotate
        handleResize({
          deltaX,
          deltaY,
          index,
          nodeModel: child,
          graphModel,
          cancelCallback: () => {},
        });
      }
    });
  }
});

从而造成了两倍,也就是this.x=this.x+2*deltaX的现象

解决方法

问题1的解决方法

由于比较简单,因此这里直接贴代码展示,困惑点可能在于如果拿到group.width
pr-2

node:resize触发时,我们从下面代码可以知道,其实已经是调用nodeModel.resize(nextSize)才触发triggerResizeEvent,因此我们在node:resize拿到的nodeModel是已经缩放完成的widthheight,我们需要拿没有resize之前的widthheight去计算比例值,因此我们只能使用preNodeData

const handleResize = ({}) => {
  //...
  const nextSize = recalcResizeInfo(
    index,
    resizeInfo,
    pct,
    isFreezeWidth,
    isFreezeHeight
  );

  //...
  const preNodeData = nodeModel.getData();
  const curNodeData = nodeModel.resize(nextSize);

  // 更新边
  updateEdgePointByAnchors(nodeModel, graphModel);
  // 触发 resize 事件
  triggerResizeEvent(
    preNodeData,
    curNodeData,
    deltaX,
    deltaY,
    index,
    nodeModel,
    graphModel
  );
};

而这里有个奇怪的地方,虽然我们nodeModel.resize的时候(如下面代码所示),是进行了setProperties({width,height}),但是我们如果一开始没有传入properties: {width:xxx, height:xxx},那我们上面代码中获取preNodeData拿到的properties是没有widthheight,也无法从preNodeData拿到widthheight

resize(resizeInfo: ResizeInfo): ResizeNodeData {
    const { width, height, deltaX, deltaY } = resizeInfo
    // 移动节点以及文本内容
    this.move(deltaX / 2, deltaY / 2)
  
    this.width = width
    this.height = height
    this.setProperties({
      width,
      height,
    })
    return this.getData()
}
getData(): NodeData {
    const { x, y, value } = this.text
    let { properties } = this
    if (isObservable(properties)) {
      properties = toJS(properties)
    }
    const data: NodeData = {
      id: this.id,
      type: this.type,
      x: this.x,
      y: this.y,
      properties,
    }
    if (this.rotate) {
      data.rotate = this.rotate
    }
    if (this.graphModel.overlapMode === OverlapMode.INCREASE) {
      data.zIndex = this.zIndex
    }
    if (value) {
      data.text = {
        x,
        y,
        value,
      }
    }
    return data
}

因此为了避免首次preNodeData中拿不到widthheight
pr-3

问题2的解决方法

问题2的核心问题是,在校验是否允许移动时,就进行了group.item的移动操作,因此我觉得应该移除这个逻辑
pr-4

然后将resizemove两种操作分开处理,也就是监听

// 在 group 缩放时,对组内的所有子节点也进行对应的缩放计算`node:mousemove`进行组内的所有子节点的移动
eventCenter.on(
    'node:resize',
    ({ deltaX, deltaY, index, model, preData }) => {
      if (model.id === curGroup.id) {
        //...
      }
    },
  )

// 在 group 移动时,对组内的所有子节点也进行对应的移动计算
eventCenter.on('node:mousemove', ({ deltaX, deltaY, data }) => {
    if (data.id === curGroup.id) {
        const { model: curGroup, graphModel } = this.props
        const nodeIds = this.getNodesInGroup(curGroup, graphModel)
        graphModel.moveNodes(nodeIds, deltaX, deltaY, true)
    }
})

测试效果

pr-5_compressed.mp4

如上面视频所示,resizemove都正常了,但是可以看出,分组缩小并没有限制,与下面两个issues反应的问题应该是一样的,这可能需要再另外进行优化处理

Copy link

changeset-bot bot commented Sep 9, 2024

⚠️ No Changeset found

Latest commit: 10374bf

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

Copy link
Collaborator

@boyongjiong boyongjiong left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏻 respect。思路很清晰了,我没看出来有什么问题,我本地试了也 OK。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants