import {Edge as ModelEdge} from "cwlts/models"; import {Geometry} from "../utils/geometry"; import {IOPort} from "./io-port"; import {Workflow} from "./workflow"; export class Edge { static makeTemplate(edge: ModelEdge, containerNode: SVGGElement, connectionStates?: string): string | undefined { if (!edge.isVisible || edge.source.type === "Step" || edge.destination.type === "Step") { return ""; } const [sourceSide, sourceStepId, sourcePort] = edge.source.id.split("/"); const [destSide, destStepId, destPort] = edge.destination.id.split("/"); const sourceVertex = containerNode.querySelector(`.node[data-id="${sourceStepId}"] .output-port[data-port-id="${sourcePort}"] .io-port`) as SVGGElement; const destVertex = containerNode.querySelector(`.node[data-id="${destStepId}"] .input-port[data-port-id="${destPort}"] .io-port`) as SVGGElement; if (edge.source.type === edge.destination.type) { console.error("Can't update edge between nodes of the same type.", edge); return; } if (!sourceVertex) { console.error("Source vertex not found for edge " + edge.source.id, edge); return; } if (!destVertex) { console.error("Destination vertex not found for edge " + edge.destination.id, edge); return; } const sourceCTM = sourceVertex.getCTM() as SVGMatrix; const destCTM = destVertex.getCTM() as SVGMatrix; const wfMatrix = containerNode.transform.baseVal.getItem(0).matrix; const pathStr = Workflow.makeConnectionPath( (sourceCTM.e - wfMatrix.e) / sourceCTM.a, (sourceCTM.f - wfMatrix.f) / sourceCTM.a, (destCTM.e - wfMatrix.e) / sourceCTM.a, (destCTM.f - wfMatrix.f) / sourceCTM.a ); return ` `; } static spawn(pathStr = "", connectionIDs: { source?: string, destination?: string, } = {}) { const ns = "http://www.w3.org/2000/svg"; const edge = document.createElementNS(ns, "g"); const [sourceSide, sourceStepId, sourcePort] = (connectionIDs.source || "//").split("/"); const [destSide, destStepId, destPort] = (connectionIDs.destination || "//").split("/"); edge.classList.add("edge"); if (sourceStepId) { edge.classList.add(sourceStepId); } if (destStepId) { edge.classList.add(destStepId); } edge.setAttribute("tabindex", "-1"); edge.setAttribute("data-destination-node", destStepId); edge.setAttribute("data-destination-port", destPort); edge.setAttribute("data-source-port", sourcePort); edge.setAttribute("data-source-node", sourceStepId); edge.setAttribute("data-source-connection", connectionIDs.source!); edge.setAttribute("data-destination-connection", connectionIDs.destination!); edge.innerHTML = ` `; return edge; } static spawnBetweenConnectionIDs(root: SVGElement, source: string, destination: string) { if (source.startsWith("in")) { const tmp = source; source = destination; destination = tmp; } const sourceNode = root.querySelector(`.port[data-connection-id="${source}"]`) as SVGGElement; const destinationNode = root.querySelector(`.port[data-connection-id="${destination}"]`) as SVGAElement; const sourceCTM = Geometry.getTransformToElement(sourceNode, root); const destCTM = Geometry.getTransformToElement(destinationNode, root); const path = IOPort.makeConnectionPath(sourceCTM.e, sourceCTM.f, destCTM.e, destCTM.f); // If there is already a connection between these ports, update that one instead const existingEdge = root.querySelector(`.edge[data-source-connection="${source}"][data-destination-connection="${destination}"]`); if (existingEdge) { existingEdge.querySelectorAll(".sub-edge").forEach(sub => sub.setAttribute("d", path!)); return existingEdge; } const edge = Edge.spawn(path, { source, destination }); const firstNode = root.querySelector(".node"); root.insertBefore(edge, firstNode); return edge; } static findEdge(root: any, sourceConnectionID: string, destinationConnectionID: string) { return root.querySelector(`[data-source-connection="${sourceConnectionID}"][data-destination-connection="${destinationConnectionID}"]`); } static parseConnectionID(cid: string) { const [side, stepID, portID] = (cid || "//").split("/"); return {side, stepID, portID}; } }