如何创建无节点冲突的对称2D水平树布局?
2D水平树布局:节点无重叠+对称的几何计算方案
核心前提(忽略节点高度差异)
- 以父节点垂直中心为对称轴,子节点沿垂直方向均匀分布
- 所有节点间保持最小安全间距(记为
min_gap,可根据需求自定义),从根源避免重叠
分场景坐标计算逻辑
场景1:2个子节点
- 计算父节点垂直中心:
parent_center_y = parent.y + parent.height / 2 - 子节点总垂直跨度:
total_span = 2 * child.height + min_gap - 第一个子节点顶部坐标:
child1.top = parent_center_y - total_span / 2 - 第二个子节点顶部坐标:
child2.top = child1.top + child.height + min_gap - 所有子节点水平坐标统一为:
child.x = parent.x + parent.width + horizontal_gap(horizontal_gap为父子节点的水平间距)
场景2:3个子节点
- 以父节点垂直中心为对称基准
- 子节点总垂直跨度:
total_span = 3 * child.height + 2 * min_gap - 中间子节点顶部坐标:
middle_child.top = parent_center_y - child.height / 2(与父节点中心垂直对齐) - 上方子节点顶部坐标:
top_child.top = middle_child.top - child.height - min_gap - 下方子节点顶部坐标:
bottom_child.top = middle_child.top + child.height + min_gap - 水平坐标同2子节点场景
下层节点冲突修正逻辑
如果下层子节点与其他分支的子节点出现重叠,执行以下操作:
- 计算重叠区域的垂直高度,取高度的一半作为整体偏移量
- 将冲突分支的所有子节点整体偏移,偏移方向为远离重叠区域,同时保持当前分支的子节点对称关系不变
伪代码示例
# 配置参数:最小节点间距min_gap=20,父子水平间距horizontal_gap=30 def calculate_child_positions(parent, children): parent_center_y = parent["y"] + parent["height"] / 2 child_count = len(children) child_height = children[0]["height"] # 忽略高度差异,统一使用第一个子节点高度 total_vertical_span = child_count * child_height + (child_count - 1) * min_gap start_y = parent_center_y - total_vertical_span / 2 child_x = parent["x"] + parent["width"] + horizontal_gap positions = [] for i in range(child_count): child_top = start_y + i * (child_height + min_gap) positions.append({"x": child_x, "y": child_top}) return positions # 重叠冲突修正 def resolve_overlaps(all_nodes): for node in all_nodes: for child in node["children"]: for other_node in all_nodes: if other_node == node: continue for other_child in other_node["children"]: # 检查垂直方向是否重叠 if (child["y"] < other_child["y"] + other_child["height"]) and (child["y"] + child["height"] > other_child["y"]): # 计算重叠高度 overlap_top = max(child["y"], other_child["y"]) overlap_bottom = min(child["y"] + child["height"], other_child["y"] + other_child["height"]) overlap_height = overlap_bottom - overlap_top # 整体偏移当前分支子节点,保持对称 offset = overlap_height / 2 if child["y"] < other_child["y"]: # 当前分支在上,整体向下偏移 for c in node["children"]: c["y"] += offset else: # 当前分支在下,整体向上偏移 for c in node["children"]: c["y"] -= offset
内容的提问来源于stack exchange,提问作者Enes Kaplan
相关产品推荐
相关产品推荐

