antvis / layout

Layout algorithms for graphs.
193 stars 55 forks source link

feat:修复使用Degre布局TB方向,节点高度不同导致间距不一致问题 #199

Closed webhao closed 6 months ago

webhao commented 9 months ago

背景

项目存在两种展示模式,一种是配置的,一种是使用数据的,两种展示的内容不同会导致节点高度不同,在不同节点高度使用Degre布局时positiony计算使得两节点间距不等。

degre

可用数据

{
    "nodes": [
        {
            "shape": "vue-base-node",
            "zIndex": 2,
            "_order": 0,
            "id": "0a206645-f545-47f9-8e78-fdc025bff3d2",
            "width": 280,
            "height": 130,
            "size": {
                "width": 280,
                "height": 130
            }
        },
        {
            "shape": "vue-base-node",
            "zIndex": 3,
            "_order": 0,
            "id": "03a716f8-fc27-4207-b967-686c0e86f7bf",
            "width": 280,
            "height": 226,
            "size": {
                "width": 280,
                "height": 226
            }
        },
        {
            "shape": "vue-base-node",
            "zIndex": 1,
            "_order": 0,
            "id": "be764037-ba8a-4846-826a-a03236a7c4b1",
            "width": 280,
            "height": 130,
            "size": {
                "width": 280,
                "height": 130
            }
        }
    ],
    "edges": [
        {
            "shape": "edge",
            "defaultLabel": {
                "markup": {
                    "tagName": "foreignObject",
                    "selector": "fo",
                    "children": [
                        {
                            "ns": "http://www.w3.org/1999/xhtml",
                            "tagName": "body",
                            "selector": "foBody",
                            "attrs": {
                                "xmlns": "http://www.w3.org/1999/xhtml"
                            },
                            "style": {
                                "width": "100%",
                                "height": "100%",
                                "background": "transparent"
                            },
                            "children": [
                                {
                                    "tagName": "div",
                                    "selector": "foContent",
                                    "style": {
                                        "width": "100%",
                                        "height": "100%"
                                    }
                                }
                            ]
                        }
                    ]
                },
                "attrs": {
                    "fo": {
                        "width": 64,
                        "height": 28,
                        "x": -32,
                        "y": -14
                    }
                }
            },
            "router": {
                "name": "normal"
            },
            "connector": {
                "name": "smooth",
                "args": {
                    "direction": "V"
                }
            },
            "label": {
                "position": {
                    "distance": 0.5
                },
                "text": "",
                "type": ""
            },
            "attrs": {
                "line": {
                    "strokeWidth": 2,
                    "stroke": "rgba(90, 114, 162, 1)",
                    "targetMarker": "classic"
                }
            },
            "source": {
                "cell": "0a206645-f545-47f9-8e78-fdc025bff3d2",
                "anchor": "bottom"
            },
            "target": {
                "cell": "03a716f8-fc27-4207-b967-686c0e86f7bf",
                "anchor": "top"
            }
        },
        {
            "shape": "edge",
            "defaultLabel": {
                "markup": {
                    "tagName": "foreignObject",
                    "selector": "fo",
                    "children": [
                        {
                            "ns": "http://www.w3.org/1999/xhtml",
                            "tagName": "body",
                            "selector": "foBody",
                            "attrs": {
                                "xmlns": "http://www.w3.org/1999/xhtml"
                            },
                            "style": {
                                "width": "100%",
                                "height": "100%",
                                "background": "transparent"
                            },
                            "children": [
                                {
                                    "tagName": "div",
                                    "selector": "foContent",
                                    "style": {
                                        "width": "100%",
                                        "height": "100%"
                                    }
                                }
                            ]
                        }
                    ]
                },
                "attrs": {
                    "fo": {
                        "width": 64,
                        "height": 28,
                        "x": -32,
                        "y": -14
                    }
                }
            },
            "router": {
                "name": "normal"
            },
            "connector": {
                "name": "smooth",
                "args": {
                    "direction": "V"
                }
            },
            "label": {
                "position": {
                    "distance": 0.5
                },
                "text": "",
                "type": ""
            },
            "attrs": {
                "line": {
                    "strokeWidth": 2,
                    "stroke": "rgba(90, 114, 162, 1)",
                    "targetMarker": "classic"
                }
            },
            "source": {
                "cell": "03a716f8-fc27-4207-b967-686c0e86f7bf",
                "anchor": "bottom"
            },
            "target": {
                "cell": "be764037-ba8a-4846-826a-a03236a7c4b1",
                "anchor": "top"
            },
            "data": {
                "edgeLabel": ""
            }
        }
    ]
}

问题分析

out

流程图 layering 表示的 cell,而 layer 可能有多个,取最大的那个(往下继续排,以同层最大节点为基准计算),在 TB 模式下会不断往下找之后 cell 的位置,每次除了maxHeight 还要加上预置的 rankSep。

我们需要计算的时候不去增加 maxHeight / 2,而是以当前的 prevY 当做 y 开始的点,这样可以保证每层为上一层maxHeight + rank + prevY,间距相同。