Newer
Older
const NODE_LABEL = "name";
const NODE_ID = "id";
const NODE_GROUP = "group";
const NODE_DESCRIPTION = "description";
const NODE_IMAGE = "image";
const LINK_SOURCE = "source";
const LINK_TARGET = "target";
const LINK_TYPE = "type";
const LINK_PARTICLE_COUNT = 4;
const GRAPH_NODES = "nodes";
const GRAPH_LINKS = "links";
const IMAGE_SIZE = 12;
const IMAGE_SRC = PLUGIN_PATH + "datasets/images/";
const LINK_PARAMS = [LINK_TYPE];
const NODE_PARAMS = [NODE_ID, NODE_LABEL, NODE_IMAGE, NODE_DESCRIPTION];
const LINK_SIM_PARAMS = ["index"];
const NODE_SIM_PARAMS = ["index", "x", "y", "vx", "vy", "fx", "fy"]; // Based on https://github.com/d3/d3-force#simulation_nodes
const JSON_CONFIG = PLUGIN_PATH + "datasets/aud1.json";
const STOP_PHYSICS_DELAY = 5000; // ms
class Graph extends ManagedData {
constructor(data) {
super(Graph.addIdentifiers(data));
this.onChangeCallbacks = [];
}
triggerOnChange() {
this.onChangeCallbacks.forEach((fn) => fn(this.data));
}
onRedo() {
this.triggerOnChange();
}
onUndo() {
this.triggerOnChange();
}
this.data[GRAPH_NODES] = this.data[GRAPH_NODES].filter(
(n) => n[NODE_ID] !== nodeId
);
// Delete links with node
this.data[GRAPH_LINKS] = this.data[GRAPH_LINKS].filter(
(l) =>
l[LINK_SOURCE][NODE_ID] !== nodeId &&
l[LINK_TARGET][NODE_ID] !== nodeId
);
this.storeCurrentData("Deleted node with id [" + nodeId + "]");
}
static addIdentifiers(data) {
data[GRAPH_NODES].forEach((n) => {
deleteLink(sourceId, targetId) {
// Only keep links, of one of the nodes is different
this.data[GRAPH_LINKS] = this.data[GRAPH_LINKS].filter(
(l) =>
l[LINK_SOURCE][NODE_ID] !== sourceId ||
l[LINK_TARGET][NODE_ID] !== targetId
);
this.storeCurrentData(
"Deleted link connecting [" + sourceId + "] with [" + targetId + "]"
);
}
isLinkOnNode(link, node) {
if (link === undefined || node === undefined) {
return false;
}
if (link.link !== true || node.node !== true) {
return false;
}
return (
link[LINK_SOURCE][NODE_ID] === node[NODE_ID] ||
link[LINK_TARGET][NODE_ID] === node[NODE_ID]
);
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
) {
return true;
}
}
return false;
connectNodes(sourceId, targetIds) {
targetIds.forEach((targetId) => {
if (
this.existsLink(sourceId, targetId) ||
this.existsLink(targetId, sourceId)
) {
return;
}
var link = {};
link[LINK_SOURCE] = sourceId;
link[LINK_TARGET] = targetId;
this.storeCurrentData(
"Created link connecting [" +
sourceId +
"] with [" +
targetIds.join() +
"]"
);
}
getCleanData(data = undefined, simulationParameters = false) {
if (data === undefined) {
data = this.data;
}
var cleanData = {};
cleanData[GRAPH_LINKS] = [];
cleanData[GRAPH_NODES] = [];
cleanData[GRAPH_LINKS].push(this.getCleanLink(link, simulationParameters))
cleanData[GRAPH_NODES].push(this.getCleanNode(node, simulationParameters))
getCleanNode(node, simulationParameters) {
var cleanNode = {};
NODE_PARAMS.forEach((param) => {
cleanNode[param] = node[param];
});
if (simulationParameters) {
NODE_SIM_PARAMS.forEach((param) => {
cleanNode[param] = node[param];
});
getCleanLink(link, simulationParameters) {
var cleanLink = {};
// Source and target 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];
// Other parameters
LINK_PARAMS.forEach((param) => {
cleanLink[param] = link[param];
});
if (simulationParameters) {
LINK_SIM_PARAMS.forEach((param) => {
cleanLink[param] = link[param];
});
}
for (var i = 0; i < nodes.length; i++) {
if (nodes[i][NODE_ID] === nodeId) {
return true;
}
}
return false;
id = this.getRandomString();
} while (this.existsNodeId(id));
// Based on: https://stackoverflow.com/a/1349426/7376120
var characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
var result = "";
for (var i = 0; i < length; i++) {
result += characters.charAt(
Math.floor(Math.random() * charactersLength)
);
}
return result;
addLink(sourceId, targetId, linkDetails = {}) {
// Copy params
var newLink = linkDetails;
// Make sure the IDs exist
if (
sourceId === undefined ||
targetId === undefined ||
this.existsNodeId(sourceId) === false ||
this.existsNodeId(targetId) === false
) {
return;
}
// Make sure the link is unique
return;
}
newLink[LINK_SOURCE] = sourceId;
newLink[LINK_TARGET] = targetId;
// Basic node properties
newLink.link = true;
newLink.node = false;
// Add node
this.data[GRAPH_LINKS].push(newLink);
this.triggerOnChange();
this.storeCurrentData(
"Added custom link connecting [" +
sourceId +
"] with [" +
targetId +
"]"
);
addNode(nodeDetails) {
// Copy params
var newNode = nodeDetails;
// Make sure the ID is set and unique
if (newNode[NODE_ID] === undefined) {
newNode[NODE_ID] = this.getUnusedNodeId();
} else if (this.existsNodeId(newNode[NODE_ID])) {
return;
}
// Basic node properties
newNode.node = true;
newNode.link = false;
// Add node
this.data[GRAPH_NODES].push(newNode);
this.triggerOnChange();
this.storeCurrentData(
"Added custom node with id [" + newNode[NODE_ID] + "]"
);