1 import {Edge as ModelEdge} from "cwlts/models";
2 import {Geometry} from "../utils/geometry";
3 import {IOPort} from "./io-port";
4 import {Workflow} from "./workflow";
8 static makeTemplate(edge: ModelEdge, containerNode: SVGGElement, connectionStates?: string): string | undefined {
9 if (!edge.isVisible || edge.source.type === "Step" || edge.destination.type === "Step") {
13 const [sourceSide, sourceStepId, sourcePort] = edge.source.id.split("/");
14 const [destSide, destStepId, destPort] = edge.destination.id.split("/");
16 const sourceVertex = containerNode.querySelector(`.node[data-id="${sourceStepId}"] .output-port[data-port-id="${sourcePort}"] .io-port`) as SVGGElement;
17 const destVertex = containerNode.querySelector(`.node[data-id="${destStepId}"] .input-port[data-port-id="${destPort}"] .io-port`) as SVGGElement;
19 if (edge.source.type === edge.destination.type) {
20 console.error("Can't update edge between nodes of the same type.", edge);
25 console.error("Source vertex not found for edge " + edge.source.id, edge);
30 console.error("Destination vertex not found for edge " + edge.destination.id, edge);
34 const sourceCTM = sourceVertex.getCTM() as SVGMatrix;
35 const destCTM = destVertex.getCTM() as SVGMatrix;
37 const wfMatrix = containerNode.transform.baseVal.getItem(0).matrix;
39 const pathStr = Workflow.makeConnectionPath(
40 (sourceCTM.e - wfMatrix.e) / sourceCTM.a,
41 (sourceCTM.f - wfMatrix.f) / sourceCTM.a,
42 (destCTM.e - wfMatrix.e) / sourceCTM.a,
43 (destCTM.f - wfMatrix.f) / sourceCTM.a
47 <g tabindex="-1" class="edge ${connectionStates}"
48 data-source-port="${sourcePort}"
49 data-destination-port="${destPort}"
50 data-source-node="${sourceStepId}"
51 data-source-connection="${edge.source.id}"
52 data-destination-connection="${edge.destination.id}"
53 data-destination-node="${destStepId}">
54 <path class="sub-edge outer" d="${pathStr}"></path>
55 <path class="sub-edge inner" d="${pathStr}"></path>
60 static spawn(pathStr = "", connectionIDs: {
65 const ns = "http://www.w3.org/2000/svg";
66 const edge = document.createElementNS(ns, "g");
68 const [sourceSide, sourceStepId, sourcePort] = (connectionIDs.source || "//").split("/");
69 const [destSide, destStepId, destPort] = (connectionIDs.destination || "//").split("/");
71 edge.classList.add("edge");
73 edge.classList.add(sourceStepId);
76 edge.classList.add(destStepId);
78 edge.setAttribute("tabindex", "-1");
79 edge.setAttribute("data-destination-node", destStepId);
80 edge.setAttribute("data-destination-port", destPort);
81 edge.setAttribute("data-source-port", sourcePort);
82 edge.setAttribute("data-source-node", sourceStepId);
83 edge.setAttribute("data-source-connection", connectionIDs.source!);
84 edge.setAttribute("data-destination-connection", connectionIDs.destination!);
87 <path class="sub-edge outer" d="${pathStr}"></path>
88 <path class="sub-edge inner" d="${pathStr}"></path>
94 static spawnBetweenConnectionIDs(root: SVGElement, source: string, destination: string) {
96 if (source.startsWith("in")) {
102 const sourceNode = root.querySelector(`.port[data-connection-id="${source}"]`) as SVGGElement;
103 const destinationNode = root.querySelector(`.port[data-connection-id="${destination}"]`) as SVGAElement;
105 const sourceCTM = Geometry.getTransformToElement(sourceNode, root);
106 const destCTM = Geometry.getTransformToElement(destinationNode, root);
107 const path = IOPort.makeConnectionPath(sourceCTM.e, sourceCTM.f, destCTM.e, destCTM.f);
109 // If there is already a connection between these ports, update that one instead
110 const existingEdge = root.querySelector(`.edge[data-source-connection="${source}"][data-destination-connection="${destination}"]`);
112 existingEdge.querySelectorAll(".sub-edge").forEach(sub => sub.setAttribute("d", path!));
116 const edge = Edge.spawn(path, {
121 const firstNode = root.querySelector(".node");
122 root.insertBefore(edge, firstNode);
127 static findEdge(root: any, sourceConnectionID: string, destinationConnectionID: string) {
128 return root.querySelector(`[data-source-connection="${sourceConnectionID}"][data-destination-connection="${destinationConnectionID}"]`);
131 static parseConnectionID(cid: string) {
132 const [side, stepID, portID] = (cid || "//").split("/");
133 return {side, stepID, portID};