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

Now rendering new space format

parent 18df5905
No related branches found
No related tags found
No related merge requests found
Pipeline #54691 passed
import { State } from "./state";
import * as Graph from "./graph";
import { loadGraphJson } from "../../datasets/datasets";
import { loadSpaceJson } from "../../datasets/datasets";
import ForceGraph from "force-graph";
import * as Interactions from "./interactions";
import { setSpace, SPACE } from "../../config";
......@@ -30,11 +30,18 @@ export function loadSpace(spaceId) {
}
setSpace(spaceId);
return loadGraphJson(SPACE).then((graphConfig) => {
jquery("#ks-editor #header-space-title").text(" - " + graphConfig.name + " [" + graphConfig.id + "]");
return loadSpaceJson(SPACE).then((response) => {
if (response.spaces.length <= 0) {
return;
}
const space = Object.values(response.spaces)[0];
jquery("#ks-editor #header-space-title").text(
" - " + space.name + " [" + space.space_id + "]"
);
state = new State();
graph = new Graph.Graph(graphConfig);
graph = new Graph.Graph(space);
load();
graph.restartSimulation();
......@@ -57,10 +64,15 @@ function load() {
.width(width)
.graphData(graph.data)
.nodeLabel(Graph.NODE_LABEL)
.nodeId(Graph.NODE_ID)
.linkSource(Graph.LINK_SOURCE)
.linkTarget(Graph.LINK_TARGET)
.linkColor((link) => state.linkColor(link))
.nodeColor((node) => state.nodeColor(node))
.onNodeClick((node) => state.onNodeClick(node))
.onNodeDragEnd((node, translate) => state.onNodeDragEnd(node, translate))
.onNodeDragEnd((node, translate) =>
state.onNodeDragEnd(node, translate)
)
.autoPauseRedraw(false) // keep redrawing after engine has stopped
.linkWidth((link) => state.linkWidth(link))
.linkDirectionalParticles(state.linkDirectionalParticles())
......
import ManagedData from "./manageddata";
import { PLUGIN_PATH, COLOR_PALETTE } from "../../config";
import { PLUGIN_PATH } from "../../config";
const LINK_NAME_CONNECTOR = "";
export const NODE_LABEL = "name";
export const NODE_ID = "id";
export const NODE_LABEL = "title";
export const NODE_ID = "node_id";
export const NODE_TYPE = "type";
export const NODE_DESCRIPTION = "description";
export const NODE_IMAGE = "image";
export const NODE_REFERENCES = "infoLinks";
export const NODE_VIDEO = "video";
export const NODE_DETAIL_IMAGE = "infoImage";
export const LINK_SOURCE = "source";
export const LINK_TARGET = "target";
export const LINK_TYPE = "type";
export const NODE_ICON_IMG = "icon_url";
export const NODE_REFERENCES = "references";
export const NODE_VIDEO = "video_url";
export const NODE_HEADER_IMG = "header_url";
export const LINK_SOURCE_OBJ = "source";
export const LINK_TARGET_OBJ = "target";
export const LINK_SOURCE = "source_node_id";
export const LINK_TARGET = "target_node_id";
export const LINK_ID = "link_id";
export const LINK_PARTICLE_COUNT = 4;
export const GRAPH_NODES = "nodes";
export const GRAPH_LINKS = "links";
export const TAG_EDITED = "updated";
export const TAG_DELETED = "deleted";
export const TAG_CREATED = "created";
export const IMAGE_SIZE = 12;
export const IMAGE_SRC = PLUGIN_PATH + "datasets/images/";
export const LINK_PARAMS = [];
export const LINK_PARAMS = [LINK_ID];
export const NODE_PARAMS = [
NODE_ID,
NODE_LABEL,
NODE_IMAGE,
NODE_ICON_IMG,
NODE_DESCRIPTION,
NODE_REFERENCES,
NODE_VIDEO,
NODE_TYPE,
NODE_DETAIL_IMAGE,
NODE_HEADER_IMG,
];
export const LINK_SIM_PARAMS = ["index"];
export const NODE_SIM_PARAMS = ["index", "x", "y", "vx", "vy", "fx", "fy"]; // Based on https://github.com/d3/d3-force#simulation_nodes
......@@ -56,7 +59,6 @@ export class Graph extends ManagedData {
clearTimeout(this.physicsStopTimeoutId);
}
this.data = Graph.addIdentifiers(this.getCleanData(this.data, false));
this.triggerOnChange();
......@@ -84,44 +86,30 @@ export class Graph extends ManagedData {
return this.getCleanData(data, true);
}
/**
* Based on the function from the 3d-graph code from @JoschaRode
*/
getNodeColor(node) {
return node.type.color;
}
calculateNodeTypes() {
// TODO: Collect all types from database
const nodeClasses = [];
this.data[GRAPH_NODES].forEach((node) =>
this.data.nodes.forEach((node) =>
nodeClasses.push(node[NODE_TYPE])
);
this.nodeTypes = [...new Set(nodeClasses)];
}
getNodeColor(node) {
return this.getTypeColor(node[NODE_TYPE]);
}
getTypeColor(typeClass) {
var classIndex = this.nodeTypes.indexOf(typeClass);
if (classIndex <= -1) {
return "black";
}
return COLOR_PALETTE[classIndex % COLOR_PALETTE.length];
}
deleteNode(nodeId) {
// Delete node from nodes
this.data[GRAPH_NODES] = this.data[GRAPH_NODES].filter(
(n) => n[NODE_ID] !== nodeId
);
this.data.nodes = this.data.nodes.filter((n) => n[NODE_ID] !== nodeId);
// Delete links with node
this.data[GRAPH_LINKS] = this.data[GRAPH_LINKS].filter(
this.data.links = this.data.links.filter(
(l) =>
l[LINK_SOURCE][NODE_ID] !== nodeId &&
l[LINK_TARGET][NODE_ID] !== nodeId
l[LINK_SOURCE_OBJ][NODE_ID] !== nodeId &&
l[LINK_TARGET_OBJ][NODE_ID] !== nodeId
);
this.storeCurrentData("Deleted node with id [" + nodeId + "]");
......@@ -143,22 +131,24 @@ export class Graph extends ManagedData {
this.enableStoring();
}
this.storeCurrentData("Deleted nodes with ids [" + nodeIds.join(",") + "]");
this.storeCurrentData(
"Deleted nodes with ids [" + nodeIds.join(",") + "]"
);
}
stopPhysics() {
this.data[GRAPH_NODES].forEach((n) => {
this.data.nodes.forEach((n) => {
n.fx = n.x;
n.fy = n.y;
});
}
static addIdentifiers(data) {
data[GRAPH_NODES].forEach((n) => {
data.nodes.forEach((n) => {
n.node = true;
n.link = false;
});
data[GRAPH_LINKS].forEach((l) => {
data.links.forEach((l) => {
l.node = false;
l.link = true;
});
......@@ -168,10 +158,10 @@ export class Graph extends ManagedData {
deleteLink(sourceId, targetId) {
// Only keep links, of one of the nodes is different
this.data[GRAPH_LINKS] = this.data[GRAPH_LINKS].filter(
this.data.links = this.data.links.filter(
(l) =>
l[LINK_SOURCE][NODE_ID] !== sourceId ||
l[LINK_TARGET][NODE_ID] !== targetId
l[LINK_SOURCE_OBJ][NODE_ID] !== sourceId ||
l[LINK_TARGET_OBJ][NODE_ID] !== targetId
);
this.storeCurrentData(
......@@ -180,6 +170,7 @@ export class Graph extends ManagedData {
}
isLinkOnNode(link, node) {
// Parameters valid?
if (link === undefined || node === undefined) {
return false;
}
......@@ -188,20 +179,21 @@ export class Graph extends ManagedData {
return false;
}
// Is node on at least one end of the link?
return (
link[LINK_SOURCE][NODE_ID] === node[NODE_ID] ||
link[LINK_TARGET][NODE_ID] === node[NODE_ID]
link[LINK_SOURCE_OBJ][NODE_ID] === node[NODE_ID] ||
link[LINK_TARGET_OBJ][NODE_ID] === node[NODE_ID]
);
}
existsLink(sourceId, targetId) {
const links = this.data[GRAPH_LINKS];
const links = this.data.links;
for (var i = 0; i < links.length; i++) {
var link = links[i];
if (
link[LINK_SOURCE][NODE_ID] === sourceId &&
link[LINK_TARGET][NODE_ID] === targetId
link[LINK_SOURCE_OBJ][NODE_ID] === sourceId &&
link[LINK_TARGET_OBJ][NODE_ID] === targetId
) {
return true;
}
......@@ -215,15 +207,15 @@ export class Graph extends ManagedData {
this.changeNodeDetails(selectionDetails[NODE_ID], selectionDetails);
} else if (selectionDetails.link === true) {
this.changeLinkDetails(
selectionDetails[LINK_SOURCE][NODE_ID],
selectionDetails[LINK_TARGET][NODE_ID],
selectionDetails[LINK_SOURCE_OBJ][NODE_ID],
selectionDetails[LINK_TARGET_OBJ][NODE_ID],
selectionDetails
);
}
}
changeNodeDetails(nodeId, newDetails) {
var nodes = this.data[GRAPH_NODES];
var nodes = this.data.nodes;
for (var i = 0; i < nodes.length; i++) {
// Is relevant node?
if (nodes[i][NODE_ID] !== nodeId) {
......@@ -240,12 +232,12 @@ export class Graph extends ManagedData {
}
changeLinkDetails(sourceId, targetId, newDetails) {
var links = this.data[GRAPH_LINKS];
var links = this.data.links;
for (var i = 0; i < links.length; i++) {
// Is relevant link?
if (
links[i][LINK_SOURCE][NODE_ID] !== sourceId ||
links[i][LINK_TARGET][NODE_ID] !== targetId
links[i][LINK_SOURCE_OBJ][NODE_ID] !== sourceId ||
links[i][LINK_TARGET_OBJ][NODE_ID] !== targetId
) {
continue; // No
}
......@@ -278,19 +270,15 @@ export class Graph extends ManagedData {
}
var cleanData = {};
cleanData[GRAPH_LINKS] = [];
cleanData[GRAPH_NODES] = [];
cleanData.links = [];
cleanData.nodes = [];
data[GRAPH_LINKS].forEach((link) =>
cleanData[GRAPH_LINKS].push(
this.getCleanLink(link, simulationParameters)
)
data.links.forEach((link) =>
cleanData.links.push(this.getCleanLink(link, simulationParameters))
);
data[GRAPH_NODES].forEach((node) =>
cleanData[GRAPH_NODES].push(
this.getCleanNode(node, simulationParameters)
)
data.nodes.forEach((node) =>
cleanData.nodes.push(this.getCleanNode(node, simulationParameters))
);
return cleanData;
......@@ -317,11 +305,11 @@ export class Graph extends ManagedData {
// Assuming that all nodes are valid, there are two possible formats
// 1. source and target are node objects
if (link[LINK_SOURCE][NODE_ID] !== undefined) {
// Source and target nodes
if (link[LINK_SOURCE_OBJ] !== undefined) {
// Source and target are nodes
// Node ids will be converted to complete node objects on running graphs, gotta convert back
cleanLink[LINK_SOURCE] = link[LINK_SOURCE][NODE_ID];
cleanLink[LINK_TARGET] = link[LINK_TARGET][NODE_ID];
cleanLink[LINK_SOURCE] = link[LINK_SOURCE_OBJ][NODE_ID];
cleanLink[LINK_TARGET] = link[LINK_TARGET_OBJ][NODE_ID];
} else {
// 2. source and target are just node ids
cleanLink[LINK_SOURCE] = link[LINK_SOURCE];
......@@ -343,7 +331,7 @@ export class Graph extends ManagedData {
}
existsNodeId(nodeId) {
var nodes = this.data[GRAPH_NODES];
var nodes = this.data.nodes;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i][NODE_ID] === nodeId) {
return true;
......@@ -403,7 +391,7 @@ export class Graph extends ManagedData {
newLink.node = false;
// Add node
this.data[GRAPH_LINKS].push(newLink);
this.data.links.push(newLink);
this.triggerOnChange();
this.storeCurrentData(
......@@ -433,7 +421,7 @@ export class Graph extends ManagedData {
newNode.link = false;
// Add node
this.data[GRAPH_NODES].push(newNode);
this.data.nodes.push(newNode);
this.triggerOnChange();
this.storeCurrentData(
......@@ -452,9 +440,9 @@ export class Graph extends ManagedData {
return item[NODE_LABEL];
} else if (item.link) {
return (
Graph.toStr(item[LINK_SOURCE]) +
Graph.toStr(item[LINK_SOURCE_OBJ]) +
LINK_NAME_CONNECTOR +
Graph.toStr(item[LINK_TARGET])
Graph.toStr(item[LINK_TARGET_OBJ])
);
} else {
return "UNDEFINED";
......
......@@ -95,11 +95,12 @@ export class State extends Tool {
onNodeDragEnd(node, translate) {
// Handle as click event, if drag distance under a certain threshold
var distanceDragged = Math.sqrt(Math.pow(translate.x, 2) + Math.pow(translate.y, 2));
var distanceDragged = Math.sqrt(
Math.pow(translate.x, 2) + Math.pow(translate.y, 2)
);
if (distanceDragged < DRAG_THRESHOLD_2D) {
this.onNodeClick(node);
return;
} else {
this.tool.onNodeDragEnd(node, translate);
}
......@@ -161,8 +162,8 @@ export class State extends Tool {
}
// Draw image
if (node[Graph.NODE_IMAGE] !== undefined) {
var path = node[Graph.NODE_IMAGE];
if (node[Graph.NODE_ICON_IMG] != null) {
var path = node[Graph.NODE_ICON_IMG];
if (!path.includes("/")) {
path = Graph.IMAGE_SRC + path;
......@@ -250,34 +251,40 @@ export class State extends Tool {
}
// Links already initialized?
if (link.source.x === undefined) {
if (link[Graph.LINK_SOURCE_OBJ] === undefined) {
return undefined;
}
// Draw gradient link
var gradient = ctx.createLinearGradient(
link.source.x,
link.source.y,
link.target.x,
link.target.y
link[Graph.LINK_SOURCE_OBJ].x,
link[Graph.LINK_SOURCE_OBJ].y,
link[Graph.LINK_TARGET_OBJ].x,
link[Graph.LINK_TARGET_OBJ].y
);
// Have reversed colors
// Color at source node referencing the target node and vice versa
gradient.addColorStop("0", graph.getNodeColor(link.target));
gradient.addColorStop("1", graph.getNodeColor(link.source));
gradient.addColorStop(
"0",
"#" + graph.getNodeColor(link[Graph.LINK_TARGET_OBJ])
);
gradient.addColorStop(
"1",
"#" + graph.getNodeColor(link[Graph.LINK_SOURCE_OBJ])
);
ctx.beginPath();
ctx.moveTo(link.source.x, link.source.y);
ctx.lineTo(link.target.x, link.target.y);
ctx.moveTo(
link[Graph.LINK_SOURCE_OBJ].x,
link[Graph.LINK_SOURCE_OBJ].y
);
ctx.lineTo(
link[Graph.LINK_TARGET_OBJ].x,
link[Graph.LINK_TARGET_OBJ].y
);
ctx.strokeStyle = gradient;
ctx.stroke();
// Only render strokes on last link
// var lastLink = graph.data[Graph.GRAPH_LINKS][graph.data[Graph.GRAPH_LINKS].length - 1];
// if (link === lastLink) {
// ctx.stroke();
// }
return undefined;
}
......
......@@ -68,8 +68,8 @@ export default class DeleteTool extends Tool {
onLinkClick(link) {
graph.deleteLink(
link[Graph.LINK_SOURCE][Graph.NODE_ID],
link[Graph.LINK_TARGET][Graph.NODE_ID]
link[Graph.LINK_SOURCE_OBJ][Graph.NODE_ID],
link[Graph.LINK_TARGET_OBJ][Graph.NODE_ID]
);
if (state.selectedItem == link) {
......
......@@ -55,12 +55,12 @@ export class SelectMenu extends ToolMenu {
this.context = undefined;
this.map = [
{ menu: NODE_NAME_ID, property: Graph.NODE_LABEL },
{ menu: NODE_IMG_ID, property: Graph.NODE_IMAGE },
{ menu: NODE_IMG_ID, property: Graph.NODE_ICON_IMG },
{ menu: NODE_DESC_ID, property: Graph.NODE_DESCRIPTION },
{ menu: NODE_TYPE_ID, property: Graph.NODE_TYPE },
{ menu: NODE_REF_ID, property: Graph.NODE_REFERENCES },
{ menu: NODE_VIDEO_ID, property: Graph.NODE_VIDEO },
{ menu: NODE_DETAIL_IMG_ID, property: Graph.NODE_DETAIL_IMAGE },
{ menu: NODE_DETAIL_IMG_ID, property: Graph.NODE_HEADER_IMG },
];
this.hooked = false; // Can only hook menu events once, but have to do it later, when they are loaded
}
......@@ -158,11 +158,23 @@ export class SelectMenu extends ToolMenu {
formatValue(propertyKey, rawValue) {
var formattedValue = rawValue;
// Format references
if (propertyKey === Graph.NODE_REFERENCES) {
// Explode to list of url-lines
formattedValue = rawValue
.split("\n") // Every line is it's own url
.filter((url) => url); // Remove empty entries
.filter((url) => url) // Remove empty entries
.map((url) => {
return {
node_id: this.values[SELECTION_KEY][Graph.NODE_ID],
url: url,
};
}); // Map to reference object
// Set created tag for every reference
formattedValue.forEach((reference) => {
reference[Graph.TAG_CREATED] = true;
});
}
return formattedValue;
......@@ -239,7 +251,7 @@ export class SelectMenu extends ToolMenu {
var formattedValue = undefined;
if (propertyKey === Graph.NODE_REFERENCES && Array.isArray(value)) {
formattedValue = value.join("\n");
formattedValue = value.map((ref) => ref.url).join("\n");
} else {
formattedValue = value;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment