diff --git a/src/models/graph.ts b/src/models/graph.ts index 076971a..071612f 100644 --- a/src/models/graph.ts +++ b/src/models/graph.ts @@ -7,12 +7,18 @@ import { getEdgeOffsets } from './topology'; import { IEntityState, EntityState } from '../utils/entity.utils'; import { IObserver, IObserverDataPayload, ISubject, Subject } from '../utils/observer.utils'; import { patchProperties } from '../utils/object.utils'; +import { dedupArrays } from '../utils/array.utils'; export interface IGraphData { nodes: N[]; edges: E[]; } +export interface IGraphObjectsIds { + nodeIds: any[]; + edgeIds: any[]; +} + export type IEdgeFilter = (edge: IEdge) => boolean; export type INodeFilter = (node: INode) => boolean; @@ -35,7 +41,10 @@ export interface IGraph extends ISubje setup(data: Partial>): void; clearPositions(): void; merge(data: Partial>): void; - remove(data: Partial<{ nodeIds: number[]; edgeIds: number[] }>): void; + remove(data: Partial): void; + removeAll(): void; + removeAllNodes(): void; + removeAllEdges(): void; isEqual(graph: Graph): boolean; getBoundingBox(): IRectangle; getNearestNode(point: IPosition): INode | undefined; @@ -49,7 +58,7 @@ export interface IGraphSettings { onLoadedImages?: () => void; onSetupData?: (data: Partial>) => void; onMergeData?: (data: Partial>) => void; - onRemoveData?: (data: Partial<{ nodeIds: number[]; edgeIds: number[] }>) => void; + onRemoveData?: (data: Partial) => void; listeners?: IObserver[]; } @@ -269,18 +278,41 @@ export class Graph extends Subject imp this._settings?.onMergeData?.(data); } - // TODO(dlozic): Add delete all mechanic. - remove(data: Partial<{ nodeIds: number[]; edgeIds: number[] }>) { + remove(data: Partial) { const nodeIds = data.nodeIds ?? []; const edgeIds = data.edgeIds ?? []; - this._removeNodes(nodeIds); - this._removeEdges(edgeIds); + const removedNodesData = this._removeNodes(nodeIds); + const removedEdgesData = this._removeEdges(edgeIds); this._applyEdgeOffsets(); this._applyStyle(); - this._settings?.onRemoveData?.(data); + if (this._settings && this._settings.onRemoveData) { + const removedData: IGraphObjectsIds = { + nodeIds: dedupArrays(removedNodesData.nodeIds, removedEdgesData.nodeIds), + edgeIds: dedupArrays(removedNodesData.edgeIds, removedEdgesData.edgeIds), + }; + + this._settings.onRemoveData(removedData); + } + } + + removeAll() { + const nodeIds = this._nodes.getAll().map((node) => node.id); + const edgeIds = this._edges.getAll().map((edge) => edge.id); + + this.remove({ nodeIds, edgeIds }); + } + + removeAllEdges() { + const edgeIds = this._edges.getAll().map((edge) => edge.id); + + this.remove({ edgeIds }); + } + + removeAllNodes() { + this.removeAll(); } isEqual(graph: Graph): boolean { @@ -527,7 +559,7 @@ export class Graph extends Subject imp this._edges.removeMany(removedEdgeIds); } - private _removeNodes(nodeIds: any[]) { + private _removeNodes(nodeIds: any[]): IGraphObjectsIds { const removedNodeIds: any[] = []; const removedEdgeIds: any[] = []; @@ -549,9 +581,11 @@ export class Graph extends Subject imp } this._nodes.removeMany(removedNodeIds); this._edges.removeMany(removedEdgeIds); + + return { nodeIds: removedNodeIds, edgeIds: removedEdgeIds }; } - private _removeEdges(edgeIds: any[]) { + private _removeEdges(edgeIds: any[]): IGraphObjectsIds { const removedEdgeIds: any[] = []; for (let i = 0; i < edgeIds.length; i++) { @@ -565,6 +599,8 @@ export class Graph extends Subject imp removedEdgeIds.push(edge.getId()); } this._edges.removeMany(removedEdgeIds); + + return { nodeIds: [], edgeIds: removedEdgeIds }; } private _applyEdgeOffsets() { diff --git a/src/simulator/engine/d3-simulator-engine.ts b/src/simulator/engine/d3-simulator-engine.ts index 78de075..225fd67 100644 --- a/src/simulator/engine/d3-simulator-engine.ts +++ b/src/simulator/engine/d3-simulator-engine.ts @@ -16,7 +16,7 @@ import { Emitter } from '../../utils/emitter.utils'; import { isObjectEqual, copyObject } from '../../utils/object.utils'; const MANY_BODY_MAX_DISTANCE_TO_LINK_DISTANCE_RATIO = 100; -const DEFAULT_LINK_DISTANCE = 30; +const DEFAULT_LINK_DISTANCE = 50; export enum D3SimulatorEngineEventType { SIMULATION_START = 'simulation-start', @@ -115,7 +115,7 @@ export const DEFAULT_SETTINGS: ID3SimulatorEngineSettings = { }, links: { distance: DEFAULT_LINK_DISTANCE, - strength: undefined, + strength: 1, iterations: 1, }, manyBody: { diff --git a/src/utils/array.utils.ts b/src/utils/array.utils.ts index 376012a..a9db93b 100644 --- a/src/utils/array.utils.ts +++ b/src/utils/array.utils.ts @@ -15,3 +15,8 @@ export const copyArray = (array: Array): Array => { } return newArray; }; + +export const dedupArrays = (...arrays: T[][]): T[] => { + const combinedArray = arrays.reduce((acc, curr) => acc.concat(curr), []); + return Array.from(new Set(combinedArray)); +};