ComboCombined Layout
Overview
ComboCombined composite layout is suitable for graph data with composite group structures. It supports flexible configuration of the layout for elements inside combos as well as the layout between the outermost combos and nodes. By default, the internal elements use the Concentric layout, and the outer layout uses the gForce force-directed layout, balancing layout effect and overall stability. See more ComboCombined layout examples and source code.
Usage Scenarios
- User profile analysis: Analyze user behavior and product relationships, use user interest circles as combos, display specific products and behavior tags as internal nodes, and help operators identify user consumption paths.
- Supply chain management graph: Divide suppliers, manufacturers, warehouses, and distributors into combos by role or region, display resources, personnel, or equipment as internal nodes, and clearly show the internal structure of each link in the supply chain.
Options
| Property | Description | Type | Default | Required |
|---|---|---|---|---|
| type | Layout type | combo-combined |
- | ✓ |
| center | Layout center | PointTuple |
Graph center | |
| layout | Layout configuration. Can be fixed, or returned dynamically based on comboId |
string | object | (comboId?: string) => string | object |
- | |
| nodeSize | Node size (diameter), used for collision detection | number | number[] | (d?: NodeData) => number |
- | |
| nodeSpacing | Spacing between nodes | number | (d?: NodeData) => number |
- | |
| comboSpacing | Spacing between combos | number | (d?: unknown) => number |
- | |
| comboPadding | Padding value inside the combo, used only for force calculation, not for rendering. It is recommended to set the same value as the visual padding. | ((d?: unknown) => number) | number | number[] | undefined |
- |
layout
string | object | (comboId?: string) => string | object
In 5.1, it is recommended to use a single layout field to choose layouts for different levels, instead of configuring innerLayout and outerLayout separately.
Example:
new Graph({
layout: {
type: 'combo-combined',
layout: (comboId) => (comboId ? { type: 'grid' } : { type: 'force' }),
},
});
Example Code
import { Graph } from '@antv/g6';
fetch('https://assets.antv.antgroup.com/g6/combo.json')
.then((res) => res.json())
.then((data) => {
const graph = new Graph({
container: 'container',
data,
layout: {
type: 'combo-combined',
comboPadding: 2,
},
node: {
style: {
size: 20,
labelText: (d) => d.id,
},
palette: {
type: 'group',
field: (d) => d.combo,
},
},
edge: {
style: (model) => {
const { size, color } = model.data;
return {
stroke: color || '#99ADD1',
lineWidth: size || 1,
};
},
},
behaviors: ['drag-element', 'drag-canvas', 'zoom-canvas'],
autoFit: 'view',
});
graph.render();
});
import { Graph } from '@antv/g6';
import GUI from 'lil-gui';
export function addPanel(renderPanel: (gui: GUI) => void) {
const gui = new GUI({ container: document.body });
gui.title('Control');
Object.assign(gui.domElement.style, { position: 'absolute', top: '0', right: '0', zIndex: '10' });
renderPanel(gui);
addEventListener('pagehide', () => gui.destroy(), { once: true });
}
export async function createGraph(
options: ConstructorParameters<typeof Graph>[0],
size: { width?: number; height?: number } = {},
renderPanel?: (gui: GUI, graph: Graph) => void,
) {
const container = document.createElement('div');
Object.assign(container.style, {
width: '100%',
maxWidth: `${size.width || 600}px`,
height: `${size.height || 400}px`,
});
document.getElementById('container')!.append(container);
const graph = new Graph({ ...size, ...options, width: container.clientWidth, container, autoResize: true });
addEventListener('pagehide', () => graph.destroy(), { once: true });
await graph.render();
if (renderPanel) addPanel((gui) => renderPanel(gui, graph));
return container;
}