Skip to content

Commit

Permalink
Merge branch 'new/add-setters-and-getters' into new/add-state-setters…
Browse files Browse the repository at this point in the history
…-with-options
  • Loading branch information
AlexIchenskiy committed Mar 20, 2024
2 parents 1022aa9 + 0ee733d commit a5c60a1
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 79 deletions.
24 changes: 14 additions & 10 deletions src/models/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type IEdgeFilter<N extends INodeBase, E extends IEdgeBase> = (edge: IEdge

export type INodeFilter<N extends INodeBase, E extends IEdgeBase> = (node: INode<N, E>) => boolean;

export interface IGraph<N extends INodeBase, E extends IEdgeBase> extends IObserver, ISubject {
export interface IGraph<N extends INodeBase, E extends IEdgeBase> extends ISubject {
getNodes(filterBy?: INodeFilter<N, E>): INode<N, E>[];
getEdges(filterBy?: IEdgeFilter<N, E>): IEdge<N, E>[];
getNodeCount(): number;
Expand Down Expand Up @@ -74,6 +74,7 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
if (settings && settings.listeners) {
this.listeners = settings.listeners;
}
this.notifyListeners = this.notifyListeners.bind(this);
this.setup({ nodes, edges });
}

Expand Down Expand Up @@ -200,7 +201,7 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
for (let i = 0; i < positions.length; i++) {
const node = this._nodes.getOne(positions[i].id);
if (node) {
node.setPosition(positions[i], true);
node.setPosition(positions[i], { isNotifySkipped: true });
}
}
}
Expand Down Expand Up @@ -377,7 +378,9 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
return nearestEdge;
}

update(data?: IObserverDataPayload): void {
// Arrow function is used because they inherit the context from the enclosing scope
// which is important for the callback to notify listeners as expected
private _update: IObserver = (data?: IObserverDataPayload): void => {
if (data && 'type' in data && 'options' in data && 'isSingle' in data.options) {
if (data.type === 'node' && data.options.isSingle) {
const nodes = this._nodes.getAll();
Expand All @@ -399,15 +402,16 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
}
}
}

this.notifyListeners(data);
}
};

private _insertNodes(nodes: N[]) {
const newNodes: INode<N, E>[] = new Array<INode<N, E>>(nodes.length);
for (let i = 0; i < nodes.length; i++) {
newNodes[i] = NodeFactory.create<N, E>(
{ data: nodes[i] },
{ onLoadedImage: () => this._settings?.onLoadedImages?.(), listeners: [this] },
{ onLoadedImage: () => this._settings?.onLoadedImages?.(), listeners: [this._update] },
);
}
this._nodes.setMany(newNodes);
Expand All @@ -428,7 +432,7 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
endNode,
},
{
listeners: [this],
listeners: [this._update],
},
),
);
Expand All @@ -443,14 +447,14 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
const existingNode = this.getNodeById(nodes[i].id);
if (existingNode) {
existingNode.setData(nodes[i]);
existingNode.setPosition(nodes[i], true);
existingNode.setPosition(nodes[i], { isNotifySkipped: true });
continue;
}

newNodes.push(
NodeFactory.create<N, E>(
{ data: nodes[i] },
{ onLoadedImage: () => this._settings?.onLoadedImages?.(), listeners: [this] },
{ onLoadedImage: () => this._settings?.onLoadedImages?.(), listeners: [this._update] },
),
);
}
Expand Down Expand Up @@ -478,7 +482,7 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
endNode,
},
{
listeners: [this],
listeners: [this._update],
},
);
newEdges.push(edge);
Expand Down Expand Up @@ -511,7 +515,7 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject imp
endNode,
},
{
listeners: [this],
listeners: [this._update],
},
);
edge.setState(existingEdge.getState());
Expand Down
48 changes: 13 additions & 35 deletions src/models/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ export interface INodeCoordinates {
y: number;
}

export interface INodeMapCoordinates {
lat: number;
lng: number;
export interface INodeSetPositionOptions {
isNotifySkipped: boolean;
}

export enum NodeShapeType {
Expand Down Expand Up @@ -113,10 +112,10 @@ export interface INode<N extends INodeBase, E extends IEdgeBase> extends ISubjec
setData(callback: (node: INode<N, E>) => N): void;
patchData(data: Partial<N>): void;
patchData(callback: (node: INode<N, E>) => Partial<N>): void;
setPosition(position: INodeCoordinates | INodeMapCoordinates | INodePosition, call: boolean): void;
setPosition(position: INodeCoordinates | INodePosition, options?: INodeSetPositionOptions): void;
setPosition(
callback: (node: INode<N, E>) => INodeCoordinates | INodeMapCoordinates | INodePosition,
call: boolean,
callback: (node: INode<N, E>) => INodeCoordinates | INodePosition,
options?: INodeSetPositionOptions,
): void;
setStyle(style: INodeStyle): void;
setStyle(callback: (node: INode<N, E>) => INodeStyle): void;
Expand Down Expand Up @@ -193,15 +192,6 @@ export class Node<N extends INodeBase, E extends IEdgeBase> extends Subject impl
clearPosition() {
this._position.x = undefined;
this._position.y = undefined;
const data = this.getData();

if ('lng' in this._data) {
this.setData({ ...data, lng: undefined });
}

if ('lat' in this._data) {
this.setData({ ...data, lat: undefined });
}

this.notifyListeners();
}
Expand Down Expand Up @@ -459,22 +449,18 @@ export class Node<N extends INodeBase, E extends IEdgeBase> extends Subject impl
this.notifyListeners();
}

setPosition(position: INodeCoordinates | INodeMapCoordinates | INodePosition, isInner?: boolean): void;
setPosition(position: INodeCoordinates | INodePosition, options?: INodeSetPositionOptions): void;
setPosition(
callback: (node: INode<N, E>) => INodeCoordinates | INodeMapCoordinates | INodePosition,
isInner?: boolean,
callback: (node: INode<N, E>) => INodeCoordinates | INodePosition,
options?: INodeSetPositionOptions,
): void;
setPosition(
arg:
| INodeCoordinates
| INodeMapCoordinates
| INodePosition
| ((node: INode<N, E>) => INodeCoordinates | INodeMapCoordinates | INodePosition),
isInner?: boolean,
arg: INodeCoordinates | INodePosition | ((node: INode<N, E>) => INodeCoordinates | INodePosition),
options?: INodeSetPositionOptions,
) {
let position: INodeCoordinates | INodeMapCoordinates | INodePosition;
let position: INodeCoordinates | INodePosition;
if (isFunction(arg)) {
position = (arg as (node: INode<N, E>) => INodeCoordinates | INodeMapCoordinates)(this);
position = (arg as (node: INode<N, E>) => INodeCoordinates)(this);
} else {
position = arg;
}
Expand All @@ -487,15 +473,7 @@ export class Node<N extends INodeBase, E extends IEdgeBase> extends Subject impl
}
}

if ('lat' in position && 'lng' in position) {
this._data = {
...this._data,
lat: position.lat,
lng: position.lng,
};
}

if (!isInner) {
if (!options?.isNotifySkipped) {
this.notifyListeners({ id: this.id, ...position });
}
}
Expand Down
29 changes: 17 additions & 12 deletions src/simulator/engine/d3-simulator-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,15 +315,21 @@ export class D3SimulatorEngine extends Emitter<D3SimulatorEvents> {
patchData(data: Partial<ISimulationGraph>) {
if (data.nodes) {
data.nodes = this._fixDefinedNodes(data.nodes);
const nodeIds = this._nodes.map((node) => node.id);
const nodeIds: { [id: number]: number } = {};

for (let i = 0; i < this._nodes.length; i++) {
nodeIds[this._nodes[i].id] = i;
}

for (let i = 0; i < data.nodes.length; i += 1) {
if (nodeIds.includes(data.nodes[i].id)) {
this._nodeIndexByNodeId = {
...this._nodeIndexByNodeId,
...data.nodes[i],
};
const index = this._nodes.findIndex((node) => data.nodes && node.id === data.nodes[i].id);
const nodeId: any = data.nodes[i].id;

if (nodeId in nodeIds) {
const index = nodeIds[nodeId];
this._nodeIndexByNodeId[nodeId] = index;
this._nodes[index] = data.nodes[i];
} else {
this._nodes.push(data.nodes[i]);
}
}
}
Expand All @@ -337,11 +343,10 @@ export class D3SimulatorEngine extends Emitter<D3SimulatorEvents> {
if (data.nodes) {
data.nodes = this._fixDefinedNodes(data.nodes);
for (let i = 0; i < data.nodes.length; i += 1) {
if (this._nodeIndexByNodeId[data.nodes[i].id]) {
this._nodeIndexByNodeId = {
...this._nodeIndexByNodeId,
...data.nodes[i],
};
const nodeId = data.nodes[i].id;

if (this._nodeIndexByNodeId[nodeId]) {
this._nodeIndexByNodeId[nodeId] = i;
} else {
this._nodes.push(data.nodes[i]);
}
Expand Down
4 changes: 2 additions & 2 deletions src/utils/object.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,9 @@ const copyPlainObject = <T>(obj: Record<string, T>): Record<string, T> => {
};

export const patchProperties = <T>(target: T, source: T): void => {
const keys = Object.keys(source as Object);
const keys = Object.keys(source as Object) as (keyof T)[];

for (let i = 0; i < keys.length; i++) {
(target[keys[i] as keyof T] as T[keyof T]) = source[keys[i] as keyof T] as T[keyof T];
target[keys[i]] = source[keys[i]];
}
};
11 changes: 5 additions & 6 deletions src/utils/observer.utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { INodeCoordinates, INodeMapCoordinates, INodePosition } from '../models/node';
import { INodeCoordinates, INodePosition } from '../models/node';
import { ISetStateDataPayload } from '../models/state';

export type GraphObject = 'node' | 'edge';

export type IObserverDataPayload = INodePosition | INodeCoordinates | INodeMapCoordinates | ISetStateDataPayload;
export type IObserverDataPayload = INodePosition | INodeCoordinates | ISetStateDataPayload;

export interface IObserver {
update(data?: IObserverDataPayload): void;
}
// Using callbacks here to ensure that the Observer update is abstracted from the user
export type IObserver = (data?: IObserverDataPayload) => void;

export interface ISubject {
listeners: IObserver[];
Expand Down Expand Up @@ -45,7 +44,7 @@ export class Subject implements ISubject {

notifyListeners(data?: IObserverDataPayload): void {
for (let i = 0; i < this.listeners.length; i++) {
this.listeners[i].update(data);
this.listeners[i](data);
}
}
}
12 changes: 5 additions & 7 deletions src/views/orb-map-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ export type IOrbMapViewSettingsUpdate<N extends INodeBase, E extends IEdgeBase>
IOrbMapViewSettingsInit<N, E>
>;

export class OrbMapView<N extends INodeBase, E extends IEdgeBase>
// eslint-disable-next-line prettier/prettier
implements IObserver, IOrbView<N, E, IOrbMapViewSettings<N, E>> {
export class OrbMapView<N extends INodeBase, E extends IEdgeBase> implements IOrbView<N, E, IOrbMapViewSettings<N, E>> {
private _container: HTMLElement;
private _resizeObs: ResizeObserver;
private _graph: IGraph<N, E>;
Expand All @@ -92,7 +90,7 @@ export class OrbMapView<N extends INodeBase, E extends IEdgeBase>
this.render();
}
},
listeners: [this],
listeners: [this._update],
});
this._graph.setDefaultStyle(getDefaultGraphStyle());
this._events = new OrbEmitter<N, E>();
Expand Down Expand Up @@ -230,9 +228,9 @@ export class OrbMapView<N extends INodeBase, E extends IEdgeBase>
this._canvas.outerHTML = '';
}

update(): void {
private _update: IObserver = (): void => {
this.render();
}
};

private _initCanvas() {
const canvas = document.createElement('canvas');
Expand Down Expand Up @@ -456,7 +454,7 @@ export class OrbMapView<N extends INodeBase, E extends IEdgeBase>
}

const layerPoint = this._leaflet.latLngToLayerPoint([coordinates.lat, coordinates.lng]);
nodes[i].setPosition(layerPoint, true);
nodes[i].setPosition(layerPoint, { isNotifySkipped: true });
}
}

Expand Down
12 changes: 5 additions & 7 deletions src/views/orb-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ export type IOrbViewSettingsInit<N extends INodeBase, E extends IEdgeBase> = Omi
'render'
> & { render?: Partial<IRendererSettingsInit> };

export class OrbView<N extends INodeBase, E extends IEdgeBase>
// eslint-disable-next-line prettier/prettier
implements IObserver, IOrbView<N, E, IOrbViewSettings<N, E>> {
export class OrbView<N extends INodeBase, E extends IEdgeBase> implements IOrbView<N, E, IOrbViewSettings<N, E>> {
private _container: HTMLElement;
private _resizeObs: ResizeObserver;
private _graph: IGraph<N, E>;
Expand Down Expand Up @@ -103,7 +101,7 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase>
this.render();
}
},
listeners: [this],
listeners: [this._update],
});
this._graph.setDefaultStyle(getDefaultGraphStyle());
this._events = new OrbEmitter<N, E>();
Expand Down Expand Up @@ -286,7 +284,7 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase>
for (let i = 0; i < nodes.length; i++) {
const position = this._settings.getPosition(nodes[i]);
if (position) {
nodes[i].setPosition({ id: nodes[i].getId(), ...position }, true);
nodes[i].setPosition({ id: nodes[i].getId(), ...position }, { isNotifySkipped: true });
}
}
}
Expand Down Expand Up @@ -598,7 +596,7 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase>
}
};

update(data?: IObserverDataPayload): void {
private _update: IObserver = (data?: IObserverDataPayload): void => {
if (data && 'x' in data && 'y' in data && 'id' in data) {
this._simulator.patchData({
nodes: [
Expand All @@ -616,7 +614,7 @@ export class OrbView<N extends INodeBase, E extends IEdgeBase>
});
}
this.render();
}
};

private _initCanvas(): HTMLCanvasElement {
const canvas = document.createElement('canvas');
Expand Down

0 comments on commit a5c60a1

Please sign in to comment.