Skip to content

Commit

Permalink
Chore: Refactor subject implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexIchenskiy committed Feb 28, 2024
1 parent f6bbec5 commit 3a8049f
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 61 deletions.
34 changes: 9 additions & 25 deletions src/models/edge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { INodeBase, INode } from './node';
import { GraphObjectState } from './state';
import { Color, IPosition, ICircle, getDistanceToLine } from '../common';
import { isArrayOfNumbers } from '../utils/type.utils';
import { IObserver, ISubject } from '../utils/observer.utils';
import { IObserver, ISubject, Subject } from '../utils/observer.utils';
import { copyProperties } from '../utils/object.utils';

const CURVED_CONTROL_POINT_OFFSET_MIN_SIZE = 4;
Expand Down Expand Up @@ -157,9 +157,11 @@ export class EdgeFactory {
});
newEdge.setState(edge.getState());
newEdge.setStyle(edge.getStyle());
edge.getListeners().forEach((listener) => {
newEdge.addListener(listener);
});
const listeners = edge.getListeners();

for (let i = 0; i < listeners.length; i++) {
newEdge.addListener(listeners[i]);
}

return newEdge;
}
Expand All @@ -169,7 +171,7 @@ export const isEdge = <N extends INodeBase, E extends IEdgeBase>(obj: any): obj
return obj instanceof EdgeStraight || obj instanceof EdgeCurved || obj instanceof EdgeLoopback;
};

abstract class Edge<N extends INodeBase, E extends IEdgeBase> implements IEdge<N, E> {
abstract class Edge<N extends INodeBase, E extends IEdgeBase> extends Subject implements IEdge<N, E> {
protected _data: E;

public readonly id: number;
Expand All @@ -181,10 +183,10 @@ abstract class Edge<N extends INodeBase, E extends IEdgeBase> implements IEdge<N
protected _state = GraphObjectState.NONE;
protected _position: IEdgePosition;

private readonly _listeners: IObserver[] = [];
private _type: EdgeType = EdgeType.STRAIGHT;

constructor(data: IEdgeData<N, E>, settings?: IEdgeSettings) {
super();
this.id = data.data.id;
this._data = data.data;
this.offset = data.offset ?? 0;
Expand All @@ -197,7 +199,7 @@ abstract class Edge<N extends INodeBase, E extends IEdgeBase> implements IEdge<N
this.endNode.addEdge(this);

if (settings && settings.listeners) {
this._listeners = settings.listeners;
this.listeners = settings.listeners;
}
}

Expand Down Expand Up @@ -233,10 +235,6 @@ abstract class Edge<N extends INodeBase, E extends IEdgeBase> implements IEdge<N
return this._data.end;
}

getListeners(): IObserver[] {
return [...this._listeners];
}

hasStyle(): boolean {
return this._style && Object.keys(this._style).length > 0;
}
Expand Down Expand Up @@ -411,20 +409,6 @@ abstract class Edge<N extends INodeBase, E extends IEdgeBase> implements IEdge<N
}
this.notifyListeners();
}

addListener(observer: IObserver): void {
this._listeners.push(observer);
}

removeListener(observer: IObserver): void {
this._listeners.splice(this._listeners.indexOf(observer), 1);
}

notifyListeners(): void {
this._listeners.forEach((listener) => {
listener.update();
});
}
}

const getEdgeType = <N extends INodeBase, E extends IEdgeBase>(data: IEdgeData<N, E>): EdgeType => {
Expand Down
22 changes: 4 additions & 18 deletions src/models/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { IGraphStyle } from './style';
import { ImageHandler } from '../services/images';
import { getEdgeOffsets } from './topology';
import { IEntityState, EntityState } from '../utils/entity.utils';
import { IObserver, ISubject } from '../utils/observer.utils';
import { IObserver, ISubject, Subject } from '../utils/observer.utils';
import { copyProperties } from '../utils/object.utils';

export interface IGraphData<N extends INodeBase, E extends IEdgeBase> {
Expand Down Expand Up @@ -53,7 +53,7 @@ export interface IGraphSettings<N extends INodeBase, E extends IEdgeBase> {
listeners?: IObserver[];
}

export class Graph<N extends INodeBase, E extends IEdgeBase> implements IGraph<N, E> {
export class Graph<N extends INodeBase, E extends IEdgeBase> extends Subject implements IGraph<N, E> {
private _nodes: IEntityState<any, INode<N, E>> = new EntityState<any, INode<N, E>>({
getId: (node) => node.getId(),
sortBy: (node1, node2) => (node1.getStyle().zIndex ?? 0) - (node2.getStyle().zIndex ?? 0),
Expand All @@ -64,15 +64,15 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> implements IGraph<N
});
private _defaultStyle?: Partial<IGraphStyle<N, E>>;
private _settings: IGraphSettings<N, E>;
private _listeners: IObserver[] = [];

constructor(data?: Partial<IGraphData<N, E>>, settings?: Partial<IGraphSettings<N, E>>) {
// TODO(dlozic): How to use object assign here? If I add add and export a default const here, it needs N, E.
super();
this._settings = settings || {};
const nodes = data?.nodes ?? [];
const edges = data?.edges ?? [];
if (settings && settings.listeners) {
this._listeners = settings.listeners;
this.listeners = settings.listeners;
}
this.setup({ nodes, edges });
}
Expand Down Expand Up @@ -377,20 +377,6 @@ export class Graph<N extends INodeBase, E extends IEdgeBase> implements IGraph<N
return nearestEdge;
}

addListener(observer: IObserver): void {
this._listeners.push(observer);
}

removeListener(observer: IObserver): void {
this._listeners.splice(this._listeners.indexOf(observer), 1);
}

notifyListeners(): void {
this._listeners.forEach((listener) => {
listener.update();
});
}

update(): void {
this.notifyListeners();
}
Expand Down
22 changes: 4 additions & 18 deletions src/models/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IEdge, IEdgeBase } from './edge';
import { Color, IPosition, IRectangle, isPointInRectangle } from '../common';
import { ImageHandler } from '../services/images';
import { GraphObjectState } from './state';
import { IObserver, ISubject } from '../utils/observer.utils';
import { IObserver, ISubject, Subject } from '../utils/observer.utils';
import { copyProperties } from '../utils/object.utils';

/**
Expand Down Expand Up @@ -141,25 +141,25 @@ export const isNode = <N extends INodeBase, E extends IEdgeBase>(obj: any): obj
return obj instanceof Node;
};

export class Node<N extends INodeBase, E extends IEdgeBase> implements INode<N, E> {
export class Node<N extends INodeBase, E extends IEdgeBase> extends Subject implements INode<N, E> {
protected readonly _id: number;
protected _data: N;
protected _position: INodePosition;
protected _style: INodeStyle = {};
protected _state = GraphObjectState.NONE;

private readonly _listeners: IObserver[] = [];
private readonly _inEdgesById: { [id: number]: IEdge<N, E> } = {};
private readonly _outEdgesById: { [id: number]: IEdge<N, E> } = {};
private readonly _onLoadedImage?: () => void;

constructor(data: INodeData<N>, settings?: Partial<INodeSettings>) {
super();
this._id = data.data.id;
this._data = data.data;
this._position = { id: this._id };
this._onLoadedImage = settings?.onLoadedImage;
if (settings && settings.listeners) {
this._listeners = settings.listeners;
this.listeners = settings.listeners;
}
}

Expand Down Expand Up @@ -425,20 +425,6 @@ export class Node<N extends INodeBase, E extends IEdgeBase> implements INode<N,
});
}

addListener(observer: IObserver): void {
this._listeners.push(observer);
}

removeListener(observer: IObserver): void {
this._listeners.splice(this._listeners.indexOf(observer), 1);
}

notifyListeners(): void {
this._listeners.forEach((listener) => {
listener.update();
});
}

setData(data: N): void;
setData(callback: (node: INode<N, E>) => N): void;
setData(arg: N | ((node: INode<N, E>) => N)) {
Expand Down
32 changes: 32 additions & 0 deletions src/utils/observer.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,41 @@ export interface IObserver {
}

export interface ISubject {
listeners: IObserver[];

addListener(observer: IObserver): void;

getListeners(): IObserver[];

removeListener(observer: IObserver): void;

notifyListeners(): void;
}

export class Subject implements ISubject {
listeners: IObserver[];

constructor() {
this.listeners = [];
}

addListener(observer: IObserver): void {
this.listeners.push(observer);
}

getListeners(): IObserver[] {
return [...this.listeners];
}

removeListener(observer: IObserver): void {
if (!this.listeners.includes(observer)) {
this.listeners.push(observer);
}
}

notifyListeners(): void {
for (let i = 0; i < this.listeners.length; i++) {
this.listeners[i].update();
}
}
}

0 comments on commit 3a8049f

Please sign in to comment.