Skip to content

Commit 5362f34

Browse files
committed
New: Enable layout node add/remove
1 parent c6e05f2 commit 5362f34

File tree

5 files changed

+51
-49
lines changed

5 files changed

+51
-49
lines changed

src/models/graph.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
293293
this._applyEdgeOffsets();
294294
this._applyStyle();
295295

296+
if (this._layout) {
297+
this.setNodePositions(this._layout.getPositions(this.getNodes()));
298+
}
299+
296300
this._settings?.onMergeData?.(data);
297301
}
298302

@@ -306,6 +310,10 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
306310
this._applyEdgeOffsets();
307311
this._applyStyle();
308312

313+
if (this._layout) {
314+
this.setNodePositions(this._layout.getPositions(this.getNodes()));
315+
}
316+
309317
if (this._settings && this._settings.onRemoveData) {
310318
const removedData: IGraphObjectsIds = {
311319
nodeIds: dedupArrays(removedNodesData.nodeIds, removedEdgesData.nodeIds),

src/simulator/layout/layout.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class LayoutFactory {
3434
case 'hierarchical':
3535
return new HierarchicalLayout<N, E>(settings.options as IHierarchicalLayoutOptions);
3636
default:
37-
return null;
37+
throw new Error('Incorrect layout type.');
3838
}
3939
}
4040
}

src/simulator/layout/layouts/circular.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ export class CircularLayout<N extends INodeBase, E extends IEdgeBase> implements
2929
getPositions(nodes: INode<N, E>[]): INodePosition[] {
3030
const angleStep = (2 * Math.PI) / nodes.length;
3131

32-
return nodes.map((node) => {
32+
const positions = nodes.map((node, index) => {
3333
return {
34-
id: node.getId(),
35-
x: this._centerX + this._radius * Math.cos(angleStep * node.getId()),
36-
y: this._centerY + this._radius * Math.sin(angleStep * node.getId()),
34+
id: node.id,
35+
x: this._centerX + this._radius * Math.cos(angleStep * index),
36+
y: this._centerY + this._radius * Math.sin(angleStep * index),
3737
};
3838
});
39+
40+
return positions;
3941
}
4042
}

src/simulator/layout/layouts/grid.ts

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,28 @@ import { INode, INodeBase, INodePosition } from '../../../models/node';
33
import { ILayout } from '../layout';
44

55
export interface IGridLayoutOptions {
6-
fit?: boolean;
7-
rows?: number;
8-
cols?: number;
96
rowGap?: number;
107
colGap?: number;
118
}
129

1310
export const DEFAULT_GRID_LAYOUT_OPTIONS: IGridLayoutOptions = {
14-
fit: true,
15-
rows: 1,
16-
cols: 1,
1711
rowGap: 50,
1812
colGap: 50,
1913
};
2014

2115
export class GridLayout<N extends INodeBase, E extends IEdgeBase> implements ILayout<N, E> {
22-
private _fit: boolean;
23-
private _rows: number;
24-
private _cols: number;
2516
private _rowGap: number;
2617
private _colGap: number;
2718

2819
constructor(options?: IGridLayoutOptions) {
2920
const _options = { ...DEFAULT_GRID_LAYOUT_OPTIONS, ...options } as Required<IGridLayoutOptions>;
30-
this._fit = _options.fit;
31-
this._rows = _options.rows;
32-
this._cols = _options.cols;
3321
this._rowGap = _options.rowGap;
3422
this._colGap = _options.colGap;
3523
}
3624

3725
getPositions(nodes: INode<N, E>[]): INodePosition[] {
38-
const rows = this._fit ? Math.ceil(Math.sqrt(nodes.length)) : this._rows;
39-
const cols = this._fit ? Math.ceil(nodes.length / rows) : this._cols;
26+
const rows = Math.ceil(Math.sqrt(nodes.length));
27+
const cols = Math.ceil(nodes.length / rows);
4028

4129
const positions: INodePosition[] = [];
4230
nodes.forEach((node, index) => {

src/views/orb-view.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase> implements IOrbVi
7575
...settings?.simulation,
7676
},
7777
layout: {
78+
type: 'force',
7879
...settings?.layout,
7980
},
8081
render: {
@@ -154,37 +155,40 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase> implements IOrbVi
154155
.on('dblclick.zoom', this.mouseDoubleClicked);
155156

156157
this._simulator = SimulatorFactory.getSimulator();
157-
this._simulator.on(SimulatorEventType.SIMULATION_START, () => {
158-
// this._isSimulating = true;
159-
this._simulationStartedAt = Date.now();
160-
this._events.emit(OrbEventType.SIMULATION_START, undefined);
161-
});
162-
this._simulator.on(SimulatorEventType.SIMULATION_PROGRESS, (data) => {
163-
this._graph.setNodePositions(data.nodes);
164-
this._events.emit(OrbEventType.SIMULATION_STEP, { progress: data.progress });
165-
this.render();
166-
});
167-
this._simulator.on(SimulatorEventType.SIMULATION_END, (data) => {
168-
this._graph.setNodePositions(data.nodes);
169-
this.render();
170-
// this._isSimulating = false;
171-
this._onSimulationEnd?.();
172-
this._onSimulationEnd = undefined;
173-
this._events.emit(OrbEventType.SIMULATION_END, { durationMs: Date.now() - this._simulationStartedAt });
174-
});
175-
this._simulator.on(SimulatorEventType.SIMULATION_STEP, (data) => {
176-
this._graph.setNodePositions(data.nodes);
177-
this.render();
178-
});
179-
this._simulator.on(SimulatorEventType.NODE_DRAG, (data) => {
180-
this._graph.setNodePositions(data.nodes);
181-
this.render();
182-
});
183-
this._simulator.on(SimulatorEventType.SETTINGS_UPDATE, (data) => {
184-
this._settings.simulation = data.settings;
185-
});
186158

187-
this._simulator.setSettings(this._settings.simulation);
159+
if (this._settings.layout.type === 'force') {
160+
this._simulator.on(SimulatorEventType.SIMULATION_START, () => {
161+
// this._isSimulating = true;
162+
this._simulationStartedAt = Date.now();
163+
this._events.emit(OrbEventType.SIMULATION_START, undefined);
164+
});
165+
this._simulator.on(SimulatorEventType.SIMULATION_PROGRESS, (data) => {
166+
this._graph.setNodePositions(data.nodes);
167+
this._events.emit(OrbEventType.SIMULATION_STEP, { progress: data.progress });
168+
this.render();
169+
});
170+
this._simulator.on(SimulatorEventType.SIMULATION_END, (data) => {
171+
this._graph.setNodePositions(data.nodes);
172+
this.render();
173+
// this._isSimulating = false;
174+
this._onSimulationEnd?.();
175+
this._onSimulationEnd = undefined;
176+
this._events.emit(OrbEventType.SIMULATION_END, { durationMs: Date.now() - this._simulationStartedAt });
177+
});
178+
this._simulator.on(SimulatorEventType.SIMULATION_STEP, (data) => {
179+
this._graph.setNodePositions(data.nodes);
180+
this.render();
181+
});
182+
this._simulator.on(SimulatorEventType.NODE_DRAG, (data) => {
183+
this._graph.setNodePositions(data.nodes);
184+
this.render();
185+
});
186+
this._simulator.on(SimulatorEventType.SETTINGS_UPDATE, (data) => {
187+
this._settings.simulation = data.settings;
188+
});
189+
190+
this._simulator.setSettings(this._settings.simulation);
191+
}
188192

189193
// TODO(dlozic): Optimize crud operations here.
190194
this._graph.setSettings({

0 commit comments

Comments
 (0)