Newer
Older
import * as Config from "../config";
interface Link {
source: string;
target: string;
type?: string;
}
export interface LinkData {
source: NodeData;
target: NodeData;
type?: string;
}
export interface NodeData {
id: string;
name: string;
description?: string;
icon?: string;
banner?: string;
references?: string[];
neighbors: NodeData[];
links: LinkData[];
}
export interface Coordinate {
x: number;
y: number;
z: number;
}
/**
* Basic graph data structure.
*/
public nodes: NodeData[];
public links: LinkData[];
private idToNode: Map<string, NodeData>;
public edgeColors: Map<string, string>;
public nodeColors: Map<string, string>;
constructor(nodes: NodeData[], links: Link[]) {
this.nodes = nodes;
this.idToNode = new Map<string, NodeData>();
nodes.forEach((node) => {
this.idToNode.set(node.id, node);
});
this.links = links.map((link) => {
return {
source: this.idToNode.get(link.source),
target: this.idToNode.get(link.target),
type: link.type,
};
});
this.edgeColors = new Map<string, string>();
this.nodeColors = new Map<string, string>();

Matthias Konitzny
committed
this.removeFloatingNodes();
this.mapNodeColors();
this.mapLinkColors();
private resetNodeData() {
for (const node of this.nodes) {
node.neighbors = [];
node.links = [];
}
}

Matthias Konitzny
committed
private removeFloatingNodes() {
this.nodes = this.nodes.filter((node) => node.neighbors.length > 0);
}
/**
* Updates the graph data structure to contain additional values.
* Creates a 'neighbors' and 'links' array for each node object.
*/
private updateNodeData() {
this.resetNodeData();
this.links.forEach((link) => {
const a = link.source;
const b = link.target;
a.neighbors.push(b);
b.neighbors.push(a);
a.links.push(link);
b.links.push(link);
});
}
public node(id: string): NodeData {
return this.idToNode.get(id);
}
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/**
* Maps the colors of the color palette to the different edge types
*/
private mapLinkColors() {
// TODO: Legacy - is there a use-case for link types?
const linkClasses = this.getLinkClasses();
for (let i = 0; i < linkClasses.length; i++) {
this.edgeColors.set(
linkClasses[i],
Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
);
}
}
/**
* Maps the colors of the color palette to the different edge types
*/
private mapNodeColors() {
const nodeClasses = this.getNodeClasses();
for (let i = 0; i < nodeClasses.length; i++) {
this.nodeColors.set(
nodeClasses[i],
Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length]
);
}
}
/**
* Returns an array containing the different edge types of the graph.
* @returns {*[]}
*/
public getLinkClasses(): string[] {
const linkClasses: string[] = [];
this.links.forEach((link) => linkClasses.push(link.type));
return [...new Set(linkClasses)].map((c) => String(c));
}
public getNodeClasses(): string[] {
const nodeClasses: string[] = [];
this.nodes.forEach((node) => nodeClasses.push(node.type));
return [...new Set(nodeClasses)].map((c) => String(c));
}
public view(
linkTypes?: Map<string, boolean>

Matthias Konitzny
committed
// Filter nodes depending on type
const nodes = this.nodes.filter((l) => nodeTypes.get(l.type));
// Filter links depending on type
let links;
if (linkTypes === undefined) {
links = this.links;
} else {
links = this.links.filter((l) => linkTypes.get(l.type));
}

Matthias Konitzny
committed
// Filter links which are connected to an invisible node
links = links.filter(
(l) => nodeTypes.get(l.source.type) && nodeTypes.get(l.target.type)
);

Matthias Konitzny
committed
nodes,
links.map((link) => {
return {
source: link.source.id,
target: link.target.id,
type: link.type,
};
})