seatunnel-ui/src/views/task/synchronization-instance/detail/dag/use-dag-layout.ts (85 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DagreLayout } from '@antv/layout'
import _ from 'lodash'
import { DagEdgeName, DagNodeName } from './dag-setting'
const updateParentNodePosition = (nodes: any, node: any) => {
if (node.children && node.children.length) {
const children = node.children
let minX = Number.MAX_VALUE
let maxX = 0
let minY = Number.MAX_VALUE
let maxY = 0
nodes
.filter((node: any) => children.includes(node.id))
.map((node: any) => {
minX = Math.min(minX, node.x)
maxX = Math.max(maxX, node.x)
minY = Math.min(minY, node.y)
maxY = Math.max(maxY, node.y)
})
node.x = minX - 20
node.y = minY - 20
node.size = {
width: maxX - minX + 200,
height: maxY - minY + 80
}
}
}
const useDagLayout = (graph: any) => {
const layoutConfig = {
nodesep: 50,
padding: 50,
ranksep: 30
}
if (!graph) {
return
}
graph.cleanSelection()
const layoutFunc = new DagreLayout({
type: 'dagre',
rankdir: 'LR',
align: 'UL',
// Calculate the node spacing based on the edge label length
ranksepFunc: (d) => {
const edges = graph.getOutgoingEdges(d.id)
let max = 0
if (edges && edges.length > 0) {
edges.forEach((edge: any) => {
const edgeView = graph.findViewByCell(edge)
const labelView = edgeView?.findAttr(
'width',
_.get(edgeView, ['labelSelectors', '0', 'body'], null)
)
const labelWidth = labelView ? +labelView : 0
max = Math.max(max, labelWidth)
})
}
return layoutConfig.ranksep + max
},
nodesep: layoutConfig.nodesep,
controlPoints: true
})
const json = graph.toJSON()
const groups = json.cells
.filter((cell: any) => cell.shape === 'rect')
.map((item: any) => {
return {
...item,
// sort by code aesc
_index: -(item.id as string)
}
})
const nodes = json.cells
.filter((cell: any) => cell.shape === DagNodeName)
.map((item: any) => {
return {
...item,
// sort by code aesc
_index: -(item.id as string)
}
})
const edges = json.cells.filter((cell: any) => cell.shape === DagEdgeName)
const newModel: any = layoutFunc?.layout({
nodes: [...nodes, ...groups],
edges
} as any)
newModel.nodes.map((node: any) => updateParentNodePosition(nodes, node))
graph.fromJSON(newModel)
}
export { useDagLayout }