Skip to content
Snippets Groups Projects
Commit 6a544512 authored by Maximilian Giller's avatar Maximilian Giller :squid:
Browse files

Implemented proper parsing for graph data

parent b167d87f
No related branches found
No related tags found
1 merge request!2Implemented editor in the react framework
Pipeline #56384 failed
import { State } from "./state";
import * as Graph from "./graph";
import { loadGraphJson } from "../../datasets";
import ForceGraph from "force-graph";
import * as Interactions from "./interactions";
import { setSpace, SPACE } from "../../config";
import { Graph } from "./structures/graph/graph";
export var state = undefined;
export var graph = undefined;
export var renderer;
export let state: any = undefined;
export let graph: Graph = undefined;
export let renderer: any;
window.onload = function () {
// Only execute, if corresponding dom is present
......@@ -23,7 +23,7 @@ window.onload = function () {
loadSpace(SPACE);
};
export function loadSpace(spaceId) {
export function loadSpace(spaceId: string) {
if (state !== undefined && spaceId === SPACE) {
return;
}
......@@ -31,14 +31,14 @@ export function loadSpace(spaceId) {
return loadGraphJson(SPACE).then((graphConfig) => {
state = new State();
graph = new Graph.Graph(graphConfig);
graph = Graph.parse(graphConfig);
load();
graph.restartSimulation();
// graph.restartSimulation();
});
}
function extractPositions(event) {
function extractPositions(event: any) {
return {
graph: renderer.screen2GraphCoords(event.layerX, event.layerY),
window: { x: event.clientX, y: event.clientY },
......@@ -53,7 +53,7 @@ function load() {
.height(600)
.width(width)
.graphData(graph.data)
.nodeLabel(Graph.NODE_LABEL)
.nodeLabel("label")
.linkColor((link) => state.linkColor(link))
.nodeColor((node) => state.nodeColor(node))
.onNodeClick((node) => state.onNodeClick(node))
......
......@@ -24,9 +24,23 @@ export class Graph extends ManagedData {
super(data);
this.onChangeCallbacks = [];
this.connectElementsToGraph();
this.prepareIds(data);
}
/**
* Sets the correct graph object for all the graph elements in data.
*/
connectElementsToGraph() {
this.data.nodes.forEach((n) => (n.graph = this));
this.data.links.forEach((l) => {
l.graph = this;
l.source = this.getNode(l.sourceId);
l.target = this.getNode(l.targetId);
});
this.data.types.forEach((t) => (t.graph = this));
}
/**
* Intuitive getter for links.
* @returns All links associated with the graph.
......@@ -105,7 +119,11 @@ export class Graph extends ManagedData {
}
protected storableData(data: GraphData): any {
let clean: GraphData;
const clean: GraphData = {
nodes: [],
links: [],
types: []
};
clean.links = data.links.map((link) => link.getCleanInstance());
clean.nodes = data.nodes.map((node) => node.getCleanInstance());
......@@ -186,6 +204,10 @@ export class Graph extends ManagedData {
return true;
}
getNode(id: number): Node {
return this.nodes.find((n) => n.id === id);
}
/**
* Adds a pre-created link to the graph.
* @param link New link object.
......@@ -227,4 +249,52 @@ export class Graph extends ManagedData {
return true;
}
public static parse(raw: any): Graph {
const data: GraphData = {
nodes: [],
links: [],
types: []
};
// Parse nodes
if (raw.nodes === undefined) {
throw new Error(
"Invalid graph data format. Could not find any nodes."
);
}
raw.nodes.forEach((rawNode: any) => {
data.nodes.push(Node.parse(rawNode));
});
// Parse links
if (raw.links === undefined) {
throw new Error(
"Invalid graph data format. Could not find any links."
);
}
raw.links.forEach((rawLink: any) => {
data.links.push(Link.parse(rawLink));
// No need to replace node ids with proper node objects, since that should be done in the graph itself. Only have to prepare valid GraphData
});
// Collect all node types
// TODO: Remove, when types are directly parsed and not just implicit
data.nodes.forEach((node) => {
const sharedType: NodeType = data.types.find(
// TODO: Use id instead, but not defined at the moment
(type) => type.name === node.type.name
);
if (sharedType !== undefined) {
node.type = sharedType; // Assign it the stored type, to make sure that it has the same reference as every other node to this type
return;
}
// Doesn't exist in list yet, so add
data.types.push(node.type);
});
return new Graph(data);
}
}
......@@ -5,9 +5,9 @@ export class GraphElement extends SerializableItem {
protected isNode: boolean;
protected isLink: boolean;
protected graph: Graph;
public graph: Graph;
constructor(graph: Graph) {
constructor(graph: Graph = undefined) {
super();
this.graph = graph;
this.isNode = false;
......
import {GraphElement} from "./graphelement";
import {Graph} from "./graph";
import {Node} from "./node";
import {GLOBAL_PARAMS} from "../helper/serializableitem";
import { GraphElement } from "./graphelement";
import { Graph } from "./graph";
import { Node } from "./node";
import { GLOBAL_PARAMS } from "../helper/serializableitem";
const LINK_PARAMS = ["source", "target", ...GLOBAL_PARAMS];
const LINK_SIM_PARAMS = ["index"];
......@@ -10,17 +10,66 @@ export class Link extends GraphElement {
public source: Node;
public target: Node;
constructor(graph: Graph) {
private _sourceId: number;
private _targetId: number;
constructor(graph: Graph = undefined) {
super(graph);
this.isLink = true;
}
/**
* Id of the source node.
* @returns Source id.
*/
public get sourceId(): number {
if (this.source == undefined) {
return this._sourceId;
}
return this.source.id;
}
/**
* Removes stored node object and just saves the id instead.
* @param value New source id value.
*/
public set sourceId(value: number) {
this._sourceId = value;
this.source = undefined;
}
/**
* Id of the target node.
* @returns Target id.
*/
public get targetId(): number {
if (this.target == undefined) {
return this._targetId;
}
return this.target.id;
}
/**
* Removes stored node object and just saves the id instead.
* @param value New target id value.
*/
public set targetId(value: number) {
this._targetId = value;
this.target = undefined;
}
public delete() {
return this.graph.deleteLink(this);
}
public add(graph: Graph = this.graph) {
this.graph = graph;
if (this.graph == undefined) {
return false;
}
return this.graph.addLink(this);
}
......@@ -40,7 +89,16 @@ export class Link extends GraphElement {
public getCleanInstance(): any {
return {
...this.serialize(),
...this.serializeProperties(LINK_SIM_PARAMS)
...this.serializeProperties(LINK_SIM_PARAMS),
};
}
}
\ No newline at end of file
public static parse(raw: any): Link {
const link: Link = new Link();
link.sourceId = Number(raw.source);
link.targetId = Number(raw.target);
return link;
}
}
import {Graph} from "./graph";
import {GraphElement} from "./graphelement"
import {NodeType} from "./nodetype";
import {SerializedURL} from "../helper/serializedurl";
import {Link} from "./link";
import {GLOBAL_PARAMS} from "../helper/serializableitem";
import { Graph } from "./graph";
import { GraphElement } from "./graphelement";
import { NodeType } from "./nodetype";
import { SerializedURL } from "../helper/serializedurl";
import { Link } from "./link";
import { GLOBAL_PARAMS } from "../helper/serializableitem";
const NODE_PARAMS = [
"label",
......@@ -13,7 +13,7 @@ const NODE_PARAMS = [
"video",
"type",
"banner",
...GLOBAL_PARAMS
...GLOBAL_PARAMS,
];
const NODE_SIM_PARAMS = ["index", "x", "y", "vx", "vy", "fx", "fy"]; // Based on https://github.com/d3/d3-force#simulation_nodes
......@@ -26,7 +26,7 @@ export class Node extends GraphElement {
public video: SerializedURL;
public references: SerializedURL[];
constructor(graph: Graph) {
constructor(graph: Graph = undefined) {
super(graph);
this.isNode = true;
}
......@@ -37,6 +37,10 @@ export class Node extends GraphElement {
public add(graph: Graph = this.graph) {
this.graph = graph;
if (this.graph == undefined) {
return false;
}
return this.graph.addNode(this);
}
......@@ -83,7 +87,18 @@ export class Node extends GraphElement {
public getCleanInstance(): any {
return {
...this.serialize(),
...this.serializeProperties(NODE_SIM_PARAMS)
...this.serializeProperties(NODE_SIM_PARAMS),
};
}
}
\ No newline at end of file
public static parse(raw: any): Node {
const node: Node = new Node();
node.id = raw.id;
node.label = raw.name;
node.description = raw.description;
node.type = NodeType.parse(raw.type);
return node;
}
}
import {GLOBAL_PARAMS, SerializableItem} from "../helper/serializableitem";
import { GLOBAL_PARAMS, SerializableItem } from "../helper/serializableitem";
import { Graph } from "./graph";
import { GraphElement } from "./graphelement";
......@@ -14,15 +14,24 @@ export class NodeType extends GraphElement {
public delete(): boolean {
// TODO: Implement
throw new Error("Function \"delete()\" has not been implemented.");
throw new Error('Function "delete()" has not been implemented.');
}
public add(graph: Graph = this.graph): boolean {
// TODO: Implement
throw new Error("Function \"add(graph)\" has not been implemented.");
throw new Error('Function "add(graph)" has not been implemented.');
}
public getCleanInstance(): any {
return this.serialize();
}
}
\ No newline at end of file
public static parse(raw: any): NodeType {
const type: NodeType = new NodeType();
type.name = raw;
type.color = "#ff0000"
return type;
}
}
......@@ -19,8 +19,9 @@ export class SerializableItem {
/**
* Creates the current object based on raw, serialized data.
* @param raw The serialized data.
* @returns Parsed data in final form. Could be the finalisd object.
*/
public parse(raw: any) {
public static parse(raw: any): any {
throw new Error("Method 'parse()' must be implemented.");
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment