Skip to content

分组复制粘贴边相关问题修复 #2149

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 61 additions & 11 deletions packages/core/src/LogicFlow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import { formatData } from './util'
import { Dnd, snapline } from './view/behavior'
import Tool from './tool'
import History from './history'
import Keyboard, { initDefaultShortcut } from './keyboard'
import Keyboard, {
initDefaultShortcut,
transformEdgeData,
transformNodeData,
} from './keyboard'
import { EventCallback, CallbackArgs, EventArgs } from './event/eventEmitter'
import { ElementType, EventType, SegmentDirection } from './constant'

Expand Down Expand Up @@ -691,25 +695,17 @@ export class LogicFlow {
* @param edges
* @param distance
*/
addElements({ nodes, edges }: GraphConfigData, distance = 40): GraphElements {
// TODO: 1. 解决下面方法中 distance 传参缺未使用的问题;该方法在快捷键中有调用
// TODO: 2. review 一下本函数代码逻辑,确认 nodeIdMap 的作用,看是否有优化的空间
console.log('distance', distance)
const nodeIdMap: Record<string, string> = {}
addElements({ nodes, edges }: GraphConfigData): GraphElements {
const elements: GraphElements = {
nodes: [],
edges: [],
}
forEach(nodes, (node) => {
const nodeId = node.id
const nodeModel = this.addNode(node)
if (nodeId) nodeIdMap[nodeId] = nodeModel.id
elements.nodes.push(nodeModel)
})
forEach(edges, (edge) => {
let { sourceNodeId, targetNodeId } = edge
if (nodeIdMap[sourceNodeId]) sourceNodeId = nodeIdMap[sourceNodeId]
if (nodeIdMap[targetNodeId]) targetNodeId = nodeIdMap[targetNodeId]
const { sourceNodeId, targetNodeId } = edge
const edgeModel = this.graphModel.addEdge({
...edge,
sourceNodeId,
Expand All @@ -720,6 +716,60 @@ export class LogicFlow {
return elements
}

cloneElements({ nodes, edges }: GraphData, distance = 40): GraphElements {
const nodeIdMap: Record<string, string> = {}
const anchorIdMap: Record<string, string> = {}
const elements: GraphElements = {
nodes: [],
edges: [],
}
forEach(nodes, (node) => {
const originNodeId = node.id
const nodeModel = this.addNode(transformNodeData(node, distance))
if (originNodeId) {
nodeIdMap[originNodeId] = nodeModel.id
const originNodeModel = this.getNodeModelById(originNodeId)
if (originNodeModel) {
// 建立源节点和新节点的锚点映射
const newNodeAnchors = nodeModel.anchors
originNodeModel.anchors.forEach((originNodeAnchor, index) => {
if (originNodeAnchor.id && newNodeAnchors[index].id) {
// @ts-ignore
anchorIdMap[originNodeAnchor.id] = newNodeAnchors[index].id
}
})
}
}
elements.nodes.push(nodeModel)
})
forEach(edges, (edge) => {
let { sourceNodeId, targetNodeId, sourceAnchorId, targetAnchorId } = edge
if (nodeIdMap[sourceNodeId]) sourceNodeId = nodeIdMap[sourceNodeId]
if (nodeIdMap[targetNodeId]) targetNodeId = nodeIdMap[targetNodeId]
if (sourceAnchorId && targetAnchorId) {
if (anchorIdMap[sourceAnchorId])
sourceAnchorId = anchorIdMap[sourceAnchorId]
if (anchorIdMap[targetAnchorId])
targetAnchorId = anchorIdMap[targetAnchorId]
}

const edgeModel = this.graphModel.addEdge(
transformEdgeData(
{
...edge,
sourceNodeId,
targetNodeId,
sourceAnchorId,
targetAnchorId,
},
distance,
),
)
elements.edges.push(edgeModel)
})
return elements
}

/**
* 将图形选中
* @param id 选择元素ID
Expand Down
14 changes: 1 addition & 13 deletions packages/core/src/keyboard/shortcut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,6 @@ export function initDefaultShortcut(lf: LogicFlow, graph: GraphModel) {
return true
}
selected = elements
selected.nodes.forEach((node) =>
translateNodeData(node, TRANSLATION_DISTANCE),
)
selected.edges.forEach((edge) =>
translateEdgeData(edge, TRANSLATION_DISTANCE),
)
return false
})
// 粘贴
Expand All @@ -149,19 +143,13 @@ export function initDefaultShortcut(lf: LogicFlow, graph: GraphModel) {
if (graph.textEditElement) return true
if (selected && (selected.nodes || selected.edges)) {
lf.clearSelectElements()
const addElements = lf.addElements(
const addElements = lf.cloneElements(
selected,
CHILDREN_TRANSLATION_DISTANCE,
)
if (!addElements) return true
addElements.nodes.forEach((node) => lf.selectElementById(node.id, true))
addElements.edges.forEach((edge) => lf.selectElementById(edge.id, true))
selected.nodes.forEach((node) =>
translateNodeData(node, TRANSLATION_DISTANCE),
)
selected.edges.forEach((edge) =>
translateEdgeData(edge, TRANSLATION_DISTANCE),
)
CHILDREN_TRANSLATION_DISTANCE =
CHILDREN_TRANSLATION_DISTANCE + TRANSLATION_DISTANCE
}
Expand Down
89 changes: 71 additions & 18 deletions packages/extension/src/dynamic-group/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ import LogicFlow, {
transformNodeData,
transformEdgeData,
} from '@logicflow/core'
import { assign, cloneDeep, filter, forEach, has, map, sortBy } from 'lodash-es'
import {
assign,
cloneDeep,
filter,
forEach,
has,
map,
sortBy,
uniqBy,
} from 'lodash-es'
import { DynamicGroupNode } from './node'
import { DynamicGroupNodeModel } from './model'
import { isAllowMoveTo, isBoundsInGroup } from './utils'

import GraphConfigData = LogicFlow.GraphConfigData
import GraphData = LogicFlow.GraphData
import GraphElements = LogicFlow.GraphElements
import EdgeConfig = LogicFlow.EdgeConfig
import EdgeData = LogicFlow.EdgeData
Expand Down Expand Up @@ -466,6 +475,7 @@ export class DynamicGroup {
*/
initGroupChildNodes(
nodeIdMap: Record<string, string>,
anchorIdMap: Record<string, string>,
children: Set<string>,
curGroup: DynamicGroupNodeModel,
distance: number,
Expand All @@ -492,16 +502,24 @@ export class DynamicGroup {
curGroup.addChild(tempChildNode.id)

nodeIdMap[childId] = tempChildNode.id // id 同 childId,做映射存储
childNode.anchors.forEach((anchor, index) => {
if (anchor.id && tempChildNode.anchors[index].id) {
// @ts-ignore
anchorIdMap[anchor.id] = tempChildNode.anchors[index].id
}
})

allChildNodes.push(tempChildNode)

// 1. 存储 children 内部节点相关的输入边(incoming)
allRelatedEdges.push(
...[...tempChildNode.incoming.edges, ...tempChildNode.outgoing.edges],
...[...childNode.incoming.edges, ...childNode.outgoing.edges],
)

if (childNodeChildren instanceof Set) {
const { childNodes, edgesData } = this.initGroupChildNodes(
nodeIdMap,
anchorIdMap,
childNodeChildren,
tempChildNode as DynamicGroupNodeModel,
distance,
Expand Down Expand Up @@ -539,22 +557,35 @@ export class DynamicGroup {
createEdge(
edge: EdgeConfig | EdgeData,
nodeIdMap: Record<string, string>,
anchorIdMap: Record<string, string>,
distance: number,
) {
const { sourceNodeId, targetNodeId } = edge
const {
sourceNodeId,
targetNodeId,
sourceAnchorId: originSourceAnchorId,
targetAnchorId: originTargetAnchorId,
} = edge
const sourceId = nodeIdMap[sourceNodeId] ?? sourceNodeId
const targetId = nodeIdMap[targetNodeId] ?? targetNodeId
let sourceAnchorId = originSourceAnchorId
if (originSourceAnchorId) {
sourceAnchorId = anchorIdMap[originSourceAnchorId] ?? originSourceAnchorId
}
let targetAnchorId = originTargetAnchorId
if (originTargetAnchorId) {
targetAnchorId = anchorIdMap[originTargetAnchorId] ?? originTargetAnchorId
}

// 如果是有 id 且 text 是对象的边,需要重新计算位置,否则直接用 edgeConfig 生成边
let newEdgeConfig = cloneDeep(edge)
if (edge.id && typeof edge.text === 'object' && edge.text !== null) {
newEdgeConfig = transformEdgeData(edge as EdgeData, distance)
}
newEdgeConfig = transformEdgeData(edge as EdgeData, distance)

return this.lf.graphModel.addEdge({
...newEdgeConfig,
sourceNodeId: sourceId,
targetNodeId: targetId,
sourceAnchorId: sourceAnchorId,
targetAnchorId: targetAnchorId,
})
}

Expand Down Expand Up @@ -689,14 +720,16 @@ export class DynamicGroup {
lf.on('group:add-node', this.onGroupAddNode)

// https://github.com/didi/LogicFlow/issues/1346
// 重写 addElements() 方法,在 addElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能
// 使用场景:addElements api 项目内部目前只在快捷键粘贴时使用(此处解决的也应该是粘贴场景的问题)
lf.addElements = (
{ nodes: selectedNodes, edges: selectedEdges }: GraphConfigData,
// 重写 cloneElements() 方法,在 cloneElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能
// 使用场景: cloneElements api 项目内部目前只在快捷键粘贴时使用(此处解决的也应该是粘贴场景的问题)
lf.cloneElements = (
{ nodes: selectedNodes, edges: selectedEdges }: GraphData,
distance = 40,
): GraphElements => {
// oldNodeId -> newNodeId 映射 Map
const nodeIdMap: Record<string, string> = {}
// oldAnchorId -> newAnchorId 映射 Map
const anchorIdMap: Record<string, string> = {}
// 本次添加的所有节点和边
const elements: GraphElements = {
nodes: [],
Expand All @@ -709,28 +742,48 @@ export class DynamicGroup {
const originId = node.id
const children = node.properties?.children ?? node.children

const model = lf.addNode(this.removeChildrenInGroupNodeData(node))

if (originId) nodeIdMap[originId] = model.id
const newNodeConfig = transformNodeData(
this.removeChildrenInGroupNodeData(node),
distance,
)
const model = lf.addNode(newNodeConfig)

if (originId) {
nodeIdMap[originId] = model.id
const originNodeModel = lf.getNodeModelById(originId)
if (originNodeModel) {
// 建立源节点和新节点的锚点映射
const newNodeAnchors = model.anchors
originNodeModel.anchors.forEach((originNodeAnchor, index) => {
if (originNodeAnchor.id && newNodeAnchors[index].id) {
// @ts-ignore
anchorIdMap[originNodeAnchor.id] = newNodeAnchors[index].id
}
})
}
}
elements.nodes.push(model) // 此时为 group 的 nodeModel

// TODO: 递归创建 group 的 nodeModel 的 children
if (model.isGroup) {
const { edgesData } = this.initGroupChildNodes(
nodeIdMap,
anchorIdMap,
children,
model as DynamicGroupNodeModel,
distance,
)
edgesInnerGroup.push(...edgesData)
edgesInnerGroup.push(...uniqBy(edgesData, 'id'))
}
})

forEach(edgesInnerGroup, (edge) => {
this.createEdge(edge, nodeIdMap, distance)
this.createEdge(edge, nodeIdMap, anchorIdMap, distance)
})
forEach(selectedEdges, (edge) => {
elements.edges.push(this.createEdge(edge, nodeIdMap, distance))
elements.edges.push(
this.createEdge(edge, nodeIdMap, anchorIdMap, distance),
)
})

// 返回 elements 进行选中效果,即触发 element.selectElementById()
Expand Down
2 changes: 1 addition & 1 deletion packages/extension/src/materials/group/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Group {

// https://github.com/didi/LogicFlow/issues/1346
// 重写 addElements() 方法,在 addElements() 原有基础上增加对 group 内部所有 nodes 和 edges 的复制功能
lf.addElements = (
lf.cloneElements = (
{ nodes: selectedNodes, edges: selectedEdges }: GraphConfigData,
distance: number,
): {
Expand Down