如何实现GoJS树形图:含子节点水平排布,叶子节点垂直排布?
实现GoJS混合排布树形图(含子节点水平、叶子节点垂直)
核心需求:所有层级中,含子节点的父节点,其子节点采用水平排布;无子女的叶子节点,同级节点采用垂直排布,同时保持AlignmentStart对齐模式。
实现方案:自定义混合树形布局
通过继承GoJS的TreeLayout,重写节点排布逻辑,区分不同类型节点的布局规则。
1. 定义节点与链接模板
// 节点模板 myDiagram.nodeTemplate = $(go.Node, "Auto", $(go.Shape, "RoundedRectangle", { strokeWidth: 2, fill: "#ffffff" }, new go.Binding("fill", "color")), $(go.TextBlock, { margin: 8, font: "14px sans-serif" }, new go.Binding("text", "key")) ); // 链接模板(正交折线) myDiagram.linkTemplate = $(go.Link, go.Link.Orthogonal, $(go.Shape, { strokeWidth: 2, stroke: "#666666" }));
2. 自定义混合布局类
function MixedTreeLayout() { go.TreeLayout.call(this); this.alignment = go.TreeLayout.AlignmentStart; // 保持AlignmentStart对齐 } go.Diagram.inherit(MixedTreeLayout, go.TreeLayout); // 重写commitNodes方法,自定义子节点排布逻辑 MixedTreeLayout.prototype.commitNodes = function() { // 先执行父类的基础布局逻辑 go.TreeLayout.prototype.commitNodes.call(this); // 遍历所有节点顶点,调整子节点排布规则 this.network.vertexes.each(vertex => { const currentNode = vertex.node; if (!currentNode) return; const childVertices = vertex.treeChildren; if (childVertices.count === 0) return; // 判断当前节点的所有子节点是否都是叶子节点 const allChildrenAreLeaves = childVertices.every(v => v.node.children.count === 0); if (allChildrenAreLeaves) { // 所有子节点都是叶子:垂直排布 childVertices.forEach(v => { v.direction = 90; // 垂直向下方向 v.spacing = new go.Size(20, 60); // 水平间距20,垂直间距60 }); } else { // 子节点包含非叶子节点:水平排布 childVertices.forEach(v => { v.direction = 0; // 水平向右方向 v.spacing = new go.Size(60, 20); // 水平间距60,垂直间距20 }); } }); // 重新计算布局 this.network.commitLayers(); };
3. 初始化Diagram与示例数据
// 初始化画布 const myDiagram = $(go.Diagram, "myDiagramDiv", { layout: new MixedTreeLayout(), initialContentAlignment: go.Spot.Center, allowZoom: true, allowPan: true }); // 动态树形数据(支持多层嵌套) myDiagram.model = new go.TreeModel([ { key: "Root", color: "#F5B041" }, { key: "A", parent: "Root", color: "#85C1E9" }, { key: "A1", parent: "A", color: "#82E0AA" }, { key: "A2", parent: "A", color: "#82E0AA" }, { key: "B", parent: "Root", color: "#85C1E9" }, { key: "B1", parent: "B", color: "#82E0AA" }, { key: "B2", parent: "B", color: "#82E0AA" }, { key: "B3", parent: "B", color: "#82E0AA" }, { key: "C", parent: "Root", color: "#85C1E9" }, { key: "C1", parent: "C", color: "#82E0AA" }, { key: "C1a", parent: "C1", color: "#F8C471" }, { key: "C1b", parent: "C1", color: "#F8C471" } ]);
关键逻辑说明
- AlignmentStart对齐:通过布局初始化时设置
this.alignment = go.TreeLayout.AlignmentStart,确保所有层级的节点沿起始边对齐(水平布局时左对齐,垂直布局时顶部对齐) - 动态适配:每次节点增删或数据更新时,布局会重新计算,自动适配新的树形结构
- 场景覆盖:
- 父节点含非叶子子节点:子节点水平排布
- 父节点所有子节点都是叶子:子节点垂直排布
- 多层嵌套结构:递归适配每个层级的布局规则
内容的提问来源于stack exchange,提问作者Tanmay Shah
相关产品推荐
相关产品推荐

