---
title: 紧凑树布局 CompactBox
order: 5
---
## 概述
紧凑树布局适用于结构化树形数据的展示,基于经典的 [Reingold–Tilford tidy 布局算法](http://emr.cs.iit.edu/~reingold/tidier-drawings.pdf) 演进而来,通过布局时综合考虑每个树节点的包围盒,有效保持树结构的紧凑性与层次清晰。参考更多 CompactBox 布局[样例](/examples#layout-compact-box)和[源码](https://github.com/antvis/hierarchy/blob/master/src/compact-box.js)
## 使用场景
- 决策树: 通过紧凑树布局可简单直观的图形化展示每个决策路径
- 知识图谱: 展示概念之间的层级关系和连接,紧凑布局可以在有限空间内呈现复杂的知识网络
## 配置方式
```js
const graph = new Graph({
layout: {
type: 'compact-box',
direction: 'LR',
getHeight: () => 16,
getWidth: () => 16,
getVGap: () => 16,
getHGap: () => 40,
},
});
```
## 配置项
| 属性 | 描述 | 类型 | 默认值 | 必选 |
| --------- | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | ------ | ---- |
| type | 布局类型 | `compact-box` | - | ✓ |
| direction | 布局方向,[可选值](#direction) | `LR` \| `RL` \| `TB` \| `BT` \| `H` \| `V` | `LR` | |
| getSide | 设置节点排布在根节点的左侧/右侧,如未设置,则算法自动分配左侧/右侧。注意:该参数仅在 `H` 布局方向上生效 | (d: { data?: [NodeData](/manual/data#节点数据nodedata) }) => string | | |
| getId | 节点 id 的回调函数 | (d?: [NodeData](/manual/data#节点数据nodedata)) => string | | |
| getWidth | 计算每个节点的宽度 | (d?: [NodeData](/manual/data#节点数据nodedata)) => number | | |
| getHeight | 计算每个节点的高度 | (d?: [NodeData](/manual/data#节点数据nodedata)) => number | | |
| getHGap | 计算每个节点的水平间隙 | (d?: [NodeData](/manual/data#节点数据nodedata)) => number | | |
| getVGap | 计算每个节点的垂直间隙 | (d?: [NodeData](/manual/data#节点数据nodedata)) => number | | |
| radial | 是否启用辐射状布局,[说明](#radial) | boolean | false | |
### direction
> `LR` \| `RL` \| `TB` \| `BT` \| `H` \| `V` **Default:** `LR`
树布局方向
- `TB`:根节点在上,往下布局
- `BT`:根节点在下,往上布局
- `LR`:根节点在左,往右布局
- `RL`:根节点在右,往左布局
- `H`:根节点在中间,水平对称布局。可传入 `getSide` 方法指定每个节点的左右分布逻辑
- `V`:根节点在中间,垂直对称布局
### getSide
> _(d: { data?: [NodeData](/manual/data#节点数据nodedata) }) => string_
设置节点排布在根节点的左侧/右侧。注意:该参数仅在 `direction` 为 `H` 时生效。如未设置,会默认将子节点前半部分放置在右侧,后半部分放置在左侧,参考 [getSide自动计算逻辑](https://github.com/antvis/hierarchy/blob/d786901874f59d96c47e2a5dfe17b373eefd72e3/src/layout/separate-root.js#L11)。
示例:
```javascript
({ data }) => {
// data 是一个节点
if (data.id === 'test-child-id') return 'right';
return 'left';
};
```
### getId
> _(d?: [NodeData](/manual/data#节点数据nodedata)) => string_
节点 id 的回调函数
示例:
```javascript
(d) => {
// d 是一个节点
return d.id + '_node';
};
```
### getWidth
> _(d?: [NodeData](/manual/data#节点数据nodedata)) => number_
每个节点的宽度
示例:
```javascript
(d) => {
// d 是一个节点
if (d.id === 'testId') return 50;
return 100;
};
```
### getHeight
> _(d?: [NodeData](/manual/data#节点数据nodedata)) => number_
每个节点的高度
示例:
```javascript
(d) => {
// d 是一个节点
if (d.id === 'testId') return 50;
return 100;
};
```
### getHGap
> _(d?: [NodeData](/manual/data#节点数据nodedata)) => number_
每个节点的水平间隙
示例:
```javascript
(d) => {
// d 是一个节点
if (d.id === 'testId') return 50;
return 100;
};
```
### getVGap
> _(d?: [NodeData](/manual/data#节点数据nodedata)) => number_
每个节点的垂直间隙
示例:
```javascript
(d) => {
// d 是一个节点
if (d.id === 'testId') return 50;
return 100;
};
```
### radial
> _boolean_
是否按照辐射状布局。若 `radial` 为 `true`,建议 `direction` 设置为 `'LR'` 或 `'RL'`
## 代码示例
```js | ob { inject: true }
import { Graph, treeToGraphData } from '@antv/g6';
/**
* If the node is a leaf node
* @param {*} d - node data
* @returns {boolean} - whether the node is a leaf node
*/
function isLeafNode(d) {
return !d.children || d.children.length === 0;
}
fetch('https://gw.alipayobjects.com/os/antvdemo/assets/data/algorithm-category.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
autoFit: 'view',
data: treeToGraphData(data),
behaviors: ['drag-canvas', 'zoom-canvas', 'drag-element', 'collapse-expand'],
node: {
style: {
labelText: (d) => d.id,
labelPlacement: (d) => (isLeafNode(d) ? 'right' : 'left'),
labelBackground: true,
ports: [{ placement: 'right' }, { placement: 'left' }],
},
animation: {
enter: false,
},
},
edge: {
type: 'cubic-horizontal',
animation: {
enter: false,
},
},
layout: {
type: 'compact-box',
direction: 'LR',
getHeight: function getHeight() {
return 32;
},
getWidth: function getWidth() {
return 32;
},
getVGap: function getVGap() {
return 10;
},
getHGap: function getHGap() {
return 100;
},
},
});
graph.render();
});
```