Collision Layout
Loading example…
import { BaseBehavior, ExtensionCategory, Graph, invokeLayoutMethod, register } from '@antv/g6';
function getData(width, size = 200) {
const k = width / 200;
const r = randomUniform(k * 2, k * 8);
const n = 4;
return {
nodes: Array.from({ length: size }, (_, i) => ({ id: `${i}`, data: { r: r(), group: i && (i % n) + 1 } })),
edges: [],
};
}
function randomUniform(min, max) {
min = min == null ? 0 : +min;
max = max == null ? 1 : +max;
if (arguments.length === 1) (max = min), (min = 0);
else max -= min;
return function () {
return Math.random() * max + min;
};
}
class CollisionElement extends BaseBehavior {
constructor(context) {
super(context, {});
this.onPointerMove = this.onPointerMove.bind(this);
this.bindEvents();
}
bindEvents() {
this.context.graph.on('pointermove', this.onPointerMove);
}
onPointerMove(event) {
const pos = this.context.graph.getCanvasByClient([event.client.x, event.client.y]);
const layoutInstance = this.context.layout
?.getLayoutInstance()
.find((layout) => ['d3-force', 'd3-force-3d'].includes(layout?.id));
if (layoutInstance) {
invokeLayoutMethod(layoutInstance, 'setFixedPosition', '0', [...pos]);
}
}
}
register(ExtensionCategory.BEHAVIOR, 'collision-element', CollisionElement);
const container = document.getElementById('container');
const width = container.scrollWidth;
const graph = new Graph({
container,
data: getData(width),
layout: {
type: 'd3-force',
alphaTarget: 0.3,
velocityDecay: 0.1,
x: {
strength: 0.01,
},
y: {
strength: 0.01,
},
collide: {
radius: (d) => d.data.r,
iterations: 3,
},
manyBody: {
strength: (d, i) => (i ? 0 : (-width * 2) / 3),
},
link: false,
},
node: {
style: {
size: (d) => (d.id === '0' ? 0 : d.data.r * 2),
},
palette: {
color: 'tableau',
type: 'group',
field: (d) => d.data.group,
},
},
behaviors: ['collision-element'],
});
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;
}