Newer
Older
import ManagedData from "../manageddata";
import { Link } from "./link";
import { NodeType } from "./nodetype";
import { Node } from "./node";
import { GLOBAL_PARAMS } from "../helper/serializableitem";
import { GraphElement } from "./graphelement";
const GRAPH_PARAMS = [...GLOBAL_PARAMS];
const GRAPH_DATA_PARAMS = ["nodes", "links", "types"];
type GraphData = { nodes: Node[]; links: Link[]; types: NodeType[] };
export class Graph extends ManagedData {
private nextNodeId = 0;
private nextLinkId = 0;
private nextTypeId = 0;
public onChangeCallbacks: { (data: any): void }[];
super(data);
this.onChangeCallbacks = [];
/**
* Intuitive getter for links.
* @returns All links associated with the graph.
*/
public get links(): Link[] {
return this.data.links;
}
/**
* Intuitive getter for nodes.
* @returns All nodes associated with the graph.number
*/
public get nodes(): Node[] {
return this.data.nodes;
}
/**
* Intuitive getter for node types.
* @returns All node types associated with the graph.
*/
public get types(): NodeType[] {
return this.data.types;
}
/**
* Determines the highest, used ids for GraphElements in data for later use.
* @param data Data to analyse.
*/
private prepareIds(data: GraphData) {
if (data.links.length > 0) {
this.nextLinkId = this.getHighestId(data.links) + 1;
}
if (data.nodes.length > 0) {
this.nextNodeId = this.getHighestId(data.nodes) + 1;
}
if (data.types.length > 0) {
this.nextTypeId = this.getHighestId(data.types) + 1;
}
}
/**
* Finds the highest id from a list of graph elements.
* @param elements List of elements containing element with highest id.
* @returns Highest id in list.
*/
private getHighestId(elements: GraphElement[]): number {
elements.forEach((element) => {
if (highest < element.id) {
highest = element.id;
}
});
return highest;
}
/**
* Calls all registered callbacks for the onChange event.
* @private
*/
private triggerOnChange() {
this.onChangeCallbacks.forEach((fn) => fn(this.data));
}
/**
* Triggers change event on data-redo.
*/
protected onRedo() {
this.triggerOnChange();
}
/**
* Triggers change event on data-undo.
*/
protected onUndo() {
this.triggerOnChange();
}
protected storableData(data: GraphData): any {
let clean: GraphData;
clean.links = data.links.map((link) => link.getCleanInstance());
clean.nodes = data.nodes.map((node) => node.getCleanInstance());
clean.types = data.types.map((type) => type.getCleanInstance());
return clean;
}
serialize(): any {
return this.serializeData(this.data);
}
/**
* Takes a data object and serializes it.
* @param data GraphData object to serialize.
* @returns Serialized data.
*/
return {
...this.serializeProperties(GRAPH_PARAMS),
...this.serializeProperties(GRAPH_DATA_PARAMS, data),
}
/**
* Adds a pre-created node to the graph.
* @param node New node object.
* @returns True, if successful.
*/
public addNode(node: Node) {
// Update id
node.id = this.nextNodeId;
this.nextNodeId += 1;
this.data.nodes.push(node);
this.triggerOnChange();
// TODO: Use toString implementation of node
this.storeCurrentData("Added node [" + node + "]");
return true;
}
/**
* Deletes a node from the graph.
* @param node Node object to remove.
* @returns True, if successful.
*/
public deleteNode(node: Node): boolean {
return true; // Doesn't even exist in graph to begin with.
this.data.nodes.filter((n: Node) => n !== node);
try {
// No save points should be created when deleting the links
this.disableStoring();
// Delete all the links that contain this node
node.links().forEach((l) => {
l.delete();
});
} finally {
this.enableStoring();
}
this.triggerOnChange();
// TODO: Use toString implementation of node
this.storeCurrentData(
"Deleted node [" + node + "] and all connected links"
);
return true;
}
/**
* Adds a pre-created link to the graph.
* @param link New link object.
* @returns True, if successful.
*/
public addLink(link: Link): boolean {
// Updateid
link.id = this.nextLinkId;
this.nextLinkId += 1;
this.data.links.push(link);
this.triggerOnChange();
// TODO: Use toString implementation of link
this.storeCurrentData("Added link [" + link + "]");
return true;
}
/**
* Deletes a link from the graph.
* @param link Link object to remove.
* @returns True, if successful.
*/
public deleteLink(link: Link): boolean {
return true; // Doesn't even exist in graph to begin with.
this.data.links.filter((l: Link) => l !== link);
this.triggerOnChange();
// TODO: Use toString implementation of link
this.storeCurrentData("Deleted link [" + link + "]");
return true;
}