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

feat(extension):【dynamic-group】isRestrict分组缩放限制+transformWidthContainer控制子元素是否需要同时缩放 #1887

Merged

Conversation

wbccb
Copy link
Contributor

@wbccb wbccb commented Sep 25, 2024

related

前言

本次提交是feature,主要复用目前存在的isRestricttransformWithContainer属性,实现分组缩放限制以及控制子元素是否需要同时缩放的功能

由于rotate相关逻辑需要很大工作量进行bbox的调整,因此本次提交仍然只针对rotate=0的情况,后续再进行rotate相关逻辑的优化

提交内容概述

  • New feature:复用isRestrict属性增加resize限制逻辑-根据内容占地位置来限制缩小范围
  • New feature:完善transformWithContainer参数控制子元素是否需要同时缩放的逻辑

提交列表

  • feat:仿造moveRules,增加resizeRules规则进行节点resize限制
  • feat:完善transformWidthContainer参数控制子元素是否需要同时缩放的逻辑
  • chore: transformWidthContainer->transformWithContainer
  • feat:isRestrict模式下增加resize限制逻辑-根据内容占地位置来限制缩小范围
  • docs:增加isRestrict新的限制说明+transformWithContainer的说明

提交具体说明

feat:仿造moveRules,增加resizeRules规则进行节点resize限制

在原来LogicFlow代码逻辑中,有moveRules可以进行移动相关的限制判断,如果不满足条件,则不允许进行移动

而分组缩放限制本质也是一种resize限制相关的需求,因此仿造moveRules,增加resizeRules规则进行节点resize限制

由于resize涉及到rotate相关的变化,可能会导致xywidthheight多种属性变化,因此resize相关逻辑不能像下面isAllowMoveNode()还可以允许x不被允许,y可以被允许移动的情况,它更多是一种整体的变化,比如某一个属性x不被允许resize,那么xywidthheight就应该就不被允许resize

class BaseNodeModel {
  /**
   * 内部方法
   * 是否允许移动节点到新的位置
   */
  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)
      if (!r) return false
      if (typeof r === 'object') {
        const r1 = r as Model.IsAllowMove
        if (!r1.x && !r1.y) {
          return false
        }
        isAllowMoveX = isAllowMoveX && r1.x
        isAllowMoveY = isAllowMoveY && r1.y
      }
    }
    return {
      x: isAllowMoveX,
      y: isAllowMoveY,
    }
  }
}

因此在仿造moveRules的基础上进行方法的精简,去除typeof r === 'object'的相关判断

class BaseNodeModel {
    /**
     * 内部方法
     * 是否允许resize节点到新的位置
     */
    isAllowResizeNode(
        deltaX: number,
        deltaY: number,
        width: number,
        height: number,
    ): boolean {
        const rules = this.resizeRules.concat(this.graphModel.nodeResizeRules)
        for (const rule of rules) {
            const r = rule(this, deltaX, deltaY, width, height)
            if (!r) return false
        }
        return true
    }
}

除了精简返回值只能为true之外,resizeRules的函数还增加了widthheight的传入,因为resize+rotata会导致xywidthheight的变化,我们需要使用xywidthheight重新计算出新的bounds,后面会进行具体的详细分析

feat:完善transformWidthContainer参数控制子元素是否需要同时缩放的逻辑

感觉应该是写错了,应该是transformWithContainer,而不是transformWidthContainer,因此提交了chore:transformWidthContainer->transformWithContainer进行变量名称的修改

在原来LogicFlow代码逻辑中,就有transformWithContainer变量以及对应的注释

transfomWithContainer

但是初始化的时候,没有进行transformWithContainer的处理,在我的理解中,transformWithContainer应该是跟isRestrict同样的控制属性,因此使用同样的逻辑,从data.properties中获取,然后赋值给this.transfromWithContainer的模式

transfromWithContainer1

然后根据注释进行node:rotatenode:resize的阻止

transfromWithContainer2

feat:isRestrict模式下增加resize限制逻辑-根据内容占地位置来限制缩小范围

在原来的isRestrict模式中,会限制子节点移动不能超过当前Node,在这个基础上,为isRestrict模式下增加resize限制逻辑:根据内容占地位置来限制缩小范围,也就是说:

当一个group处于isRestrict模式下时,它的子节点移动不能脱离group的范围,而group的resize操作也不能小于子节点的占地面积,如下面视频所示

resize_1.mp4

而增加的逻辑也非常简单,基本是仿造moveRules进行逻辑构建,如下面代码所示,触发checkGroupBoundsWithChildren()进行resize的判断

class DynamicGroup {  
    init() {
        // 添加分组节点移动规则
        // 1. 移动分组节点时,同时移动分组内所有节点
        // 2. 移动子节点时,判断是否有限制规则(isRestrict)
        graphModel.addNodeMoveRules((model, deltaX, deltaY) => {
            if (model.isGroup) {
                return true
            }
            const groupId = this.nodeGroupMap.get(model.id)!
            const groupModel = this.lf.getNodeModelById(
                groupId,
            ) as DynamicGroupNodeModel
            if (groupModel && groupModel.isRestrict) {
                // 如果移动的节点存在于某个分组中,且这个分组禁止子节点移出去
                const groupBounds = groupModel.getBounds()
                return isAllowMoveTo(groupBounds, model, deltaX, deltaY)
            }
            return true
        })

        // 添加分组节点resize规则
        // isRestrict限制模式下,当前model resize时不能小于children的占地面积
        graphModel.addNodeResizeRules((model, deltaX, deltaY, width, height) => {
            if (model.isGroup && model.isRestrict) {
                return this.checkGroupBoundsWithChildren(
                      model as DynamicGroupNodeModel,
                      deltaX,
                      deltaY,
                      width,
                      height,
                )
            }
            return true
        })
    }
}

addNodeResizeRules是如何阻止resize的呢?

resize()中,如果我们返回了isAllowResize=false,那么我们就阻止执行this.move()this.widththis.height的更新,直接返回旧的getData()

// BaseNodeModel.ts
resize(resizeInfo: ResizeInfo): ResizeNodeData {
    const { width, height, deltaX, deltaY } = resizeInfo

    const isAllowResize = this.isAllowResizeNode(deltaX, deltaY, width, height)

    if (!isAllowResize) {
      return this.getData()
    }

    // 移动节点以及文本内容
    this.move(deltaX / 2, deltaY / 2)

    this.width = width
    this.height = height
    this.setProperties({
      width,
      height,
    })
    return this.getData()
}

当然我们也要同时阻止下当前node的children的相关resize逻辑,也就是

transfrom3

而检测group:resize后的bounds是否会小于children的bounds的逻辑也非常简单

  • 首先根据上面BaseNodeModel.tsresize()中的this.move(deltaX / 2, deltaY / 2)进行xy的更新
  • 根据新的xywidthheight进行当前model新的bounds的计算,我们就可以得到parent:resize后的bounds
  • 然后将parent:resize后的bounds与child:bounds进行比较,检测是否要阻止其resize
 /**
   * 检测group:resize后的bounds是否会小于children的bounds
   * 限制group进行resize时不能小于内部的占地面积
   * @param groupModel
   * @param deltaX
   * @param deltaY
   * @param newWidth
   * @param newHeight
   */
 checkGroupBoundsWithChildren(
    groupModel: DynamicGroupNodeModel,
    deltaX: number,
    deltaY: number,
    newWidth: number,
    newHeight: number,
  ) {
    if (groupModel.children) {
      const { children, x, y } = groupModel
      // 根据deltaX和deltaY计算出当前model的bounds
      const newX = x + deltaX / 2
      const newY = y + deltaY / 2
      const groupMinX = newX - newWidth / 2
      const groupMinY = newY - newHeight / 2
      const groupMaxX = newX + newWidth / 2
      const groupMaxY = newY + newHeight / 2

      const childrenArray = Array.from(children)
      for (let i = 0; i < childrenArray.length; i++) {
        const childId = childrenArray[i]
        const child = this.lf.getNodeModelById(childId)
        if (!child) {
          continue
        }
        const childBounds = child.getBounds()
        const { minX, minY, maxX, maxY } = childBounds
        // parent:resize后的bounds不能小于child:bounds,否则阻止其resize
        const canResize =
          groupMinX <= minX &&
          groupMinY <= minY &&
          groupMaxX >= maxX &&
          groupMaxY >= maxY
        if (!canResize) {
          return false
        }
      }
    }

    return true
  }

transformWithContainer和isRestrict冲突问题

目前group:resize->children:resize的模式是通过emit事件的形式,也就是

  • group:resize已经成功了,然后通知children:resize

当我们处于isRestrict模式时,我们需要限制group:resize完成后的bounds小于children:resize完成后的bounds,因此整个逻辑就会变成我们需要根据child:resize完成后的bounds来递归判断parent能否resize,我们得先完成child:resize->判断 group:resize能否执行

这其实跟目前的【group:resize已经成功了,然后通知children:resize】是冲突的,考虑实现的复杂性以及对应

本质是基于1.x的Group提出的问题,1.x的Group就是没有联动效果的,也就是在 group 缩放时,组内的所有子节点不会进行对应的缩放计算

因此在此次pr中,当处于isRestrict模式时,直接阻止transformWithContainer的生效,也就是

tranfrom4


docs:增加isRestrict新的限制说明+transformWithContainer的说明

增加dynamic-group.en.mddynamic-group.zh.md相关的文档说明,比如下面在properties增加transformWithContainer的声明

const dynamicGroupNodeConfig = {
  id: 'dynamic-group_1',
  type: 'dynamic-group',
  x: 500,
  y: 140,
  text: 'dynamic-group_1',
  resizable: true,
  rotatable: false,
  properties: {
    children: ["rect_3"],
    collapsible: true,
    width: 420,
    height: 250,
    radius: 5,
    isCollapsed: true,
    transformWithContainer: true,
  },
}

Copy link

changeset-bot bot commented Sep 25, 2024

⚠️ No Changeset found

Latest commit: d15d8a2

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

@wbccb wbccb changed the title feat(extension):【dynamic-group】isRestrict模式下根据内容占地位置来限制resize范围+transformWidthContainer控制子元素是否需要同时缩放 feat(extension):【dynamic-group】isRestrict分组缩放限制+transformWidthContainer控制子元素是否需要同时缩放 Sep 25, 2024
@boyongjiong boyongjiong merged commit 3c09c8a into didi:master Sep 29, 2024
@wbccb wbccb deleted the feature/group-restrict-transformWithContainer branch September 29, 2024 08:47
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