Newer
Older
import * as Config from "../config";

Matthias Konitzny
committed
interface LinkData {
source: string;
target: string;
type?: string;
}

Matthias Konitzny
committed
export interface Link {
source: Node;
target: Node;
type?: GraphObjectType;

Matthias Konitzny
committed
interface NodeContent {
name: string;
description?: string;
icon?: string;
banner?: string;
references?: string[];

Matthias Konitzny
committed
}
interface NodeData extends NodeContent {
id: string;
type?: string;
}
export interface Node extends NodeContent {
id: string;
type: GraphObjectType;
neighbors: Node[];
links: Link[];
}
export interface GraphObjectType {
name: string;
color?: string;
}
export interface Coordinate {
x: number;
y: number;
z: number;
}
/**
* Basic graph data structure.
*/

Matthias Konitzny
committed
public nodes: Node[];
public links: Link[];
public objectGroups: GraphObjectType[];
public nameToObjectGroup: Map<string, GraphObjectType>;
private idToNode: Map<string, Node>;
constructor(
nodes: NodeData[],
links: LinkData[],
objectGroups?: GraphObjectType[]
) {
this.objectGroups = objectGroups ?? this.createObjectGroups(nodes);
this.nameToObjectGroup = new Map<string, GraphObjectType>();
this.objectGroups.forEach((group) =>
this.nameToObjectGroup.set(group.name, group)
);
this.createNodes(nodes);
this.links = links.map((link) => {
return {
source: this.idToNode.get(link.source),
target: this.idToNode.get(link.target),
};
});

Matthias Konitzny
committed
this.removeFloatingNodes();

Matthias Konitzny
committed
private createNodes(nodes: NodeData[]) {
this.nodes = [];
for (const nodeData of nodes) {
const { type, ...nodeVars } = nodeData;
const node = { ...nodeVars } as Node;
node.type = this.nameToObjectGroup.get(type);
node.neighbors = [];
node.links = [];

Matthias Konitzny
committed
this.nodes.push(node);

Matthias Konitzny
committed
this.idToNode = new Map<string, Node>();
this.nodes.forEach((node) => {
this.idToNode.set(node.id, node);
});

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.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);
});
}

Matthias Konitzny
committed
public node(id: string): Node {
return this.idToNode.get(id);
}

Matthias Konitzny
committed
private createObjectGroups(nodes: NodeData[]): GraphObjectType[] {
const objectGroups: GraphObjectType[] = [];
const nodeClasses: string[] = [];
nodes.forEach((node) => nodeClasses.push(node.type));
const nodeTypes = [...new Set(nodeClasses)].map((c) => String(c));
for (let i = 0; i < nodeTypes.length; i++) {
objectGroups.push({
name: nodeTypes[i],
color: Config.COLOR_PALETTE[i % Config.COLOR_PALETTE.length],
});
}

Matthias Konitzny
committed
return objectGroups;
}
public view(
linkTypes?: Map<string, boolean>

Matthias Konitzny
committed
// Filter nodes depending on type

Matthias Konitzny
committed
const nodes = this.nodes.filter((l) => nodeTypes.get(l.type.name));

Matthias Konitzny
committed
// Filter links depending on type
let links;
if (linkTypes === undefined) {
links = this.links;
} else {

Matthias Konitzny
committed
links = this.links.filter((l) => linkTypes.get(l.type.name));

Matthias Konitzny
committed
// Filter links which are connected to an invisible node
links = links.filter(

Matthias Konitzny
committed
(l) =>
nodeTypes.get(l.source.type.name) &&
nodeTypes.get(l.target.type.name)

Matthias Konitzny
committed
);

Matthias Konitzny
committed
// Convert to data objects and create new graph.
// Using spread syntax to simplify object copying.

Matthias Konitzny
committed
nodes.map((node) => {
// eslint-disable-next-line no-unused-vars
const { type, neighbors, links, ...nodeVars } = node;
const nodeData = { ...nodeVars } as NodeData;
nodeData.type = type.name;
return nodeData;
}),
links.map((link) => {
return {
source: link.source.id,
target: link.target.id,
};

Matthias Konitzny
committed
}),
this.objectGroups