Skip to content

[Bug Report]: 自定义锚点时的非正常情况 #2365

@hg2370634854

Description

@hg2370634854

发生了什么?

背景

在使用HtmlNodeModel、HtmlNode自定义节点时,由于自定义节点中的锚点需要通过渲染后才可以计算出位置,在本例中使用修改anchorsOffset属性来达到目的,重写了getDefaultAnchors方法返回出锚点的基本信息和自定义信息,然后setAttributes中自定义properties的anchorsOffset属性,最后赋值到model中的anchorsOffset。

问题

但是页面中的锚点位置确实更新了,只是在重写getConnectedTargetRules方法时返回每个规则的validate中的targetAnchor或sourceAnchor参数信息不包含自定义的属性,例如本例中的type: "in",在修改anchorsOffset前后通过打印日志
console.log(this.props.model.anchors)
发现anchors中的数据已变成baseModel中实现方法getDefaultAnchor,也就是默认的锚点信息,下图中左侧正常锚点是未修改自定义节点的anchorsOffset的数据,右侧为修改过后的

Image

核心代码

class BaseFlowNodeView extends HtmlNode {

    setHtml(rootEl) {

        const model = this.props.model
        const { id, containerClassName, mainColor, secondaryColor, icon, height } = model

        // 根部容器
        const container = document.createElement("div")
        container.className = `node-container ${containerClassName}`
        container.style = `border: 1.5px solid ${mainColor}`
        container.id = id

        // 头部
        const header = document.createElement("div")
        header.className = 'header'
        header.style = `
            background-color: ${secondaryColor};
            border-bottom: 1px solid ${secondaryColor};
        `
        const headerIcon = document.createElement('i')
        headerIcon.style = `color: ${mainColor}`
        headerIcon.className = 'icon'
        headerIcon.innerHTML = icon
        header.appendChild(headerIcon)

        const headerTitle = document.createElement("div")
        headerTitle.className = 'title';
        headerTitle.style = `color: ${mainColor}`;
        headerTitle.innerText = model.getProperties().title || ''
        header.appendChild(headerTitle)

        container.appendChild(header)

        // 主内容区域
        const body = document.createElement("div")
        body.className = 'body'

        const main = this.getMain()
        if (main) {
            body.appendChild(main)
        }
        container.appendChild(body)

        rootEl.innerHTML = ''
        rootEl.appendChild(container)

        const updateProperties = this.getUpdateProperties();

        const newHeight = document.getElementById(id).getBoundingClientRect().height
        if (height != newHeight) {
            updateProperties.height = newHeight
        }
        model.setProperties(updateProperties)
    }

    getUpdateProperties() {
        return {}
    }

    getRelativePosition(element, container) {
        const elemRect = element.getBoundingClientRect();
        const containerRect = container.getBoundingClientRect();

        const relativeX = elemRect.left - containerRect.left;
        const relativeY = elemRect.top - containerRect.top;

        return { x: relativeX, y: relativeY };
    }

}

class BaseFlowNodeModel extends HtmlNodeModel {

    setAttributes() {
        this.text.editable = false;
        this.isRestrict = true
        this.autoResize = true
        this.collapsible = false
        const { height = 200 } = this.properties
        this.height = height

        // 自定义通用属性
        this.containerClassName = ''
        this.mainColor = '#332d2d'
        this.secondaryColor = '#eee'
        this.icon =
            `<svg width="23" height="23" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
                <g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M12 3l8 4.5v9L12 21l-8-4.5v-9L12 3"></path><path d="M12 12l8-4.5"></path>
                    <path d="M12 12v9"></path>
                    <path d="M12 12L4 7.5"></path>
                </g>
            </svg>
            `
        this.setExtraAttributes();
    }

    getConnectedTargetRules() {
        const rules = super.getConnectedTargetRules();
        rules.push({
            message: '不允许连接此锚点',
            validate(sourceNode, targetNode, sourceAnchor, targetAnchor) {
                console.log(sourceNode, targetNode, sourceAnchor, targetAnchor);
                return true;
            }
        });
        return rules;
    }
}

export {
    BaseFlowNodeView,
    BaseFlowNodeModel
}

import { BaseFlowNodeModel, BaseFlowNodeView } from "./BaseFLowNode"
import '@/assets/logic_flow/node/action_node.css'
import { toJS } from 'mobx';

class ActionNodeView extends BaseFlowNodeView {

  getMain() {
    const model = this.props.model
    const { id } = model
    const properties = model.getProperties()
    const actions = properties.actions || []

    const actionContainer = document.createElement("div")
    actions.forEach(action => {
      const span = document.createElement("span")
      span.className = 'action'
      span.id = `${id}_${action.value}`
      span.innerText = action.title
      actionContainer.appendChild(span)
    })

    return actionContainer
  }

  getUpdateProperties() {
    const { height, } = this.props.model
    return { anchorsOffset: [[0, - height / 2], [0, height / 2]] }
  }
}

class ActionNodeModel extends BaseFlowNodeModel {

  setExtraAttributes() {
    const { height = 150 } = this.properties;
    this.text.editable = false;
    this.isRestrict = true
    this.autoResize = true
    this.collapsible = false

    this.width = 250;
    this.height = height;

    this.radius = 5;

    this.containerClassName = 'action-container'
    this.mainColor = '#2080f0'
    this.secondaryColor = 'rgba(32, 128, 240, 0.16)'
    this.icon =
      `
    <svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
      <g fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M4 21V8a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v6a3 3 0 0 1-3 3H8l-4 4"></path><path d="M8 9h8"></path>
        <path d="M8 13h6"></path>
      </g>
    </svg>
    `

    const { anchorsOffset = [] } = this.properties
    this.anchorsOffset = toJS(anchorsOffset)
  }

  getDefaultAnchor() {
    const { x, y, id } = this
    return [{ x, y, id: `${id}_in`, type: 'in' }, { x, y, id: `${id}_out`, type: 'out' }]
  }
}

export default {
  type: "action",
  view: ActionNodeView,
  model: ActionNodeModel
}

logicflow/core版本

2.1.1

logicflow/extension版本

2.1.1

logicflow/engine版本

No response

浏览器&环境

Chrome

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions