119 lines
3.5 KiB
TypeScript
119 lines
3.5 KiB
TypeScript
|
/**
|
||
|
* @author Martin Karkowski
|
||
|
* @email m.karkowski@zema.de
|
||
|
* @create date 2021-06-24 17:58:16
|
||
|
* @modify date 2021-06-24 17:58:16
|
||
|
* @desc [description]
|
||
|
*/
|
||
|
|
||
|
import * as go from "gojs";
|
||
|
|
||
|
const make = go.GraphObject.make;
|
||
|
|
||
|
export function addNodeNextTo<N = any, L = any>(node: go.Node, newNodeOptions: N, newLinkOptions: L, mode: "from" | "to", direction: "n" | "e" | "s" | "w" = "s", offset = 100, movingOffset = 20) {
|
||
|
// We get the Diagram of the Node.
|
||
|
const diagram = node.diagram;
|
||
|
// To position the
|
||
|
const nodeBox = node.actualBounds;
|
||
|
const middleY = nodeBox.y + nodeBox.height / 2;
|
||
|
const middleX = nodeBox.x + nodeBox.width / 2;
|
||
|
|
||
|
|
||
|
diagram.startTransaction("add_node_and_link");
|
||
|
|
||
|
// Add the new Node.
|
||
|
diagram.model.addNodeData(newNodeOptions);
|
||
|
const newNodeBox = diagram.findNodeForData(newNodeOptions).actualBounds;
|
||
|
|
||
|
// New Node Location
|
||
|
const location = new go.Point();
|
||
|
|
||
|
// Define the Position
|
||
|
switch (direction) {
|
||
|
case "n":
|
||
|
location.x = middleX - newNodeBox.width / 2;
|
||
|
location.y = nodeBox.y - offset - newNodeBox.height / 2;
|
||
|
break;
|
||
|
case "s":
|
||
|
location.x = middleX - newNodeBox.width / 2;
|
||
|
location.y = nodeBox.y + nodeBox.height + offset - newNodeBox.height / 2;
|
||
|
break;
|
||
|
case "e":
|
||
|
location.x = nodeBox.x + nodeBox.width + offset + newNodeBox.width / 2;
|
||
|
location.y = middleY - newNodeBox.height / 2;
|
||
|
break;
|
||
|
case "w":
|
||
|
location.x = nodeBox.x - offset - newNodeBox.width / 2;
|
||
|
location.y = middleY - newNodeBox.height / 2;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
const linkData = Object.assign(newLinkOptions, mode === "from" ? {
|
||
|
from: diagram.model.getKeyForNodeData(node.data),
|
||
|
to: diagram.model.getKeyForNodeData(newNodeOptions),
|
||
|
} : {
|
||
|
to: diagram.model.getKeyForNodeData(node.data),
|
||
|
from: diagram.model.getKeyForNodeData(newNodeOptions),
|
||
|
});
|
||
|
|
||
|
diagram.findNodeForData(newNodeOptions).location = location;
|
||
|
|
||
|
// Assign the Position
|
||
|
const foundObjects = diagram.findObjectsNear(
|
||
|
location,
|
||
|
Math.max(newNodeBox.width, newNodeBox.height),
|
||
|
// Filter Function, which only returns nodes and
|
||
|
// check if the node isnt the node we are considering
|
||
|
x => {
|
||
|
const p = x.part;
|
||
|
return (p instanceof go.Node && p !== node) ?
|
||
|
p : null;
|
||
|
}
|
||
|
);
|
||
|
|
||
|
// If we will found new Objects => we will adapt theese nodes. with respect to there position
|
||
|
if (foundObjects.size > 1) {
|
||
|
const attribute: "width" | "height" = (direction == "n" || direction == "s") ? "width" : "height";
|
||
|
|
||
|
let length = 0;
|
||
|
for (const obj of foundObjects.toArray()) {
|
||
|
length += (obj as go.Node).actualBounds[attribute];
|
||
|
}
|
||
|
length += movingOffset * (foundObjects.size - 1);
|
||
|
|
||
|
const start = length / 2;
|
||
|
let _offset = 0;
|
||
|
|
||
|
// Iterate over the found elements
|
||
|
for (const obj of foundObjects.toArray()) {
|
||
|
// Location
|
||
|
const locationForNode = obj.position.copy();
|
||
|
|
||
|
switch (direction) {
|
||
|
case "n":
|
||
|
case "s":
|
||
|
locationForNode.x = middleX - start + _offset;
|
||
|
break;
|
||
|
case "e":
|
||
|
case "w":
|
||
|
locationForNode.y = middleY - start + _offset;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Adapt the Offset
|
||
|
_offset += movingOffset + obj.actualBounds[attribute];
|
||
|
|
||
|
// Adapt the Position
|
||
|
diagram.findNodeForData(obj.data).location = locationForNode;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// and add the link data to the model
|
||
|
diagram.model.addLinkData(linkData);
|
||
|
console.log(linkData);
|
||
|
|
||
|
|
||
|
// Commit the Change
|
||
|
diagram.commitTransaction("add_node_and_link");
|
||
|
}
|