New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

cwl-svg

Package Overview
Dependencies
Maintainers
1
Versions
75
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cwl-svg - npm Package Compare versions

Comparing version 0.0.30 to 0.0.31

utils/svg-utils.d.ts

8

demo.js

@@ -6,7 +6,7 @@ "use strict";

var workflow_1 = require("./graph/workflow");
// import * as loaded from "/Users/ivanbatic/Documents/CWL/Whole Genome Analysis - BWA + GATK 2.3.9-Lite (with Metrics).json";
var loaded = require("../cwl-samples/rna-seq-alignment.json");
var wf = models_1.WorkflowFactory.from(loaded);
var wf = models_1.WorkflowFactory.from(samples.bcBio);
console.log("Model", wf);
var workflow = new workflow_1.Workflow(new Snap("#svg"), wf);
var svgRoot = document.getElementById("svg");
var workflow = new workflow_1.Workflow(svgRoot, wf);
window["workflow"] = workflow;
//# sourceMappingURL=demo.js.map

@@ -1,5 +0,4 @@

/// <reference types="snapsvg" />
import { Edge as ModelEdge } from "cwlts/models";
export declare class Edge {
static makeTemplate(edge: ModelEdge, paper: Snap.Paper): string;
static makeTemplate(edge: ModelEdge, containerNode: SVGGElement): string;
static spawn(pathStr?: string, connectionIDs?: {

@@ -6,0 +5,0 @@ source?: string;

@@ -8,3 +8,3 @@ "use strict";

}
Edge.makeTemplate = function (edge, paper) {
Edge.makeTemplate = function (edge, containerNode) {
if (!edge.isVisible || edge.source.type === "Step" || edge.destination.type === "Step") {

@@ -15,4 +15,4 @@ return "";

var _b = edge.destination.id.split("/"), destSide = _b[0], destStepId = _b[1], destPort = _b[2];
var sourceVertex = paper.node.querySelector("." + sourceStepId + " .output-port ." + sourcePort);
var destVertex = paper.node.querySelector("." + destStepId + " .input-port ." + destPort);
var sourceVertex = containerNode.querySelector("." + sourceStepId + " .output-port ." + sourcePort);
var destVertex = containerNode.querySelector("." + destStepId + " .input-port ." + destPort);
if (edge.source.type === edge.destination.type) {

@@ -19,0 +19,0 @@ console.error("Cant draw edge between nodes of the same type.", edge);

@@ -1,5 +0,1 @@

/// <reference types="snapsvg" />
import { InputPort } from "./input-port";
import { OutputPort } from "./output-port";
import { Shape } from "./shape";
import { StepModel, WorkflowInputParameterModel, WorkflowOutputParameterModel } from "cwlts/models";

@@ -11,35 +7,31 @@ export declare type NodePosition = {

export declare type NodeDataModel = WorkflowInputParameterModel | WorkflowOutputParameterModel | StepModel;
export declare class GraphNode extends Shape {
export declare class GraphNode {
private dataModel;
position: NodePosition;
protected paper: Snap.Paper;
protected group: any;
protected static radius: number;
constructor(position: Partial<NodePosition>, dataModel: NodeDataModel, paper: Snap.Paper);
static radius: number;
constructor(position: Partial<NodePosition>, dataModel: NodeDataModel);
/**
* @FIXME Making icons increases the rendering time by 50-100%. Try embedding the SVG directly.
*/
private static workflowIconSvg;
private static toolIconSvg;
private static fileInputIconSvg;
private static fileOutputIconSvg;
private static inputIconSvg;
private static outputIconSvg;
private static makeIconFragment(model);
static makeTemplate(x: number, y: number, dataModel: NodeDataModel & {
in: any[];
out: any[];
static makeTemplate(x: number, y: number, dataModel: {
id: string;
connectionId: string;
label?: string;
in?: any[];
out?: any[];
}): string;
draw(): Snap.Element;
private static makePortTemplate(port, type, transform?);
addPort(port: OutputPort | InputPort): void;
/**
* Moves the element to the outer edge of the node given an angle and the node radius
* @param el Element to move
* @param angle Angle along which the element should be moved
* @param radius Radius of the parent node
*/
private static movePortToOuterEdge(el, angle, radius);
/**
* Repositions input and output ports to their designated places on the outer edge
* of the node and scales the node in the process if necessary.
*/
distributePorts(): void;
static createPortMatrix(totalPortLength: number, portIndex: number, radius: number, type: "input" | "output"): Snap.Matrix;
static createPortMatrix(totalPortLength: number, portIndex: number, radius: number, type: "input" | "output"): SVGMatrix;
static createGhostIO(): SVGGElement;
static patchModelPorts<T>(model: T): T;
static patchModelPorts<T>(model: T & {
connectionId: string;
id: string;
}): T;
}
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var shape_1 = require("./shape");
var models_1 = require("cwlts/models");
var svg_utils_1 = require("../utils/svg-utils");
var io_port_1 = require("./io-port");
var GraphNode = (function (_super) {
__extends(GraphNode, _super);
function GraphNode(position, dataModel, paper) {
var _this = _super.call(this) || this;
_this.dataModel = dataModel;
_this.position = { x: 0, y: 0 };
_this.paper = paper;
_this.dataModel = dataModel;
Object.assign(_this.position, position);
return _this;
var GraphNode = (function () {
function GraphNode(position, dataModel) {
this.dataModel = dataModel;
this.position = { x: 0, y: 0 };
this.dataModel = dataModel;
Object.assign(this.position, position);
}
/**
* @FIXME Making icons increases the rendering time by 50-100%. Try embedding the SVG directly.
*/
GraphNode.makeIconFragment = function (model) {

@@ -36,14 +19,14 @@ var modelType = model instanceof models_1.StepModel ? "step" :

if (modelType === "step") {
iconStr = model.run && model.run.class === "Workflow" ? "data:image/svg+xml;base64,PHN2ZyBpZD0id29ya2Zsb3ciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUwMCA1MDAiPjx0aXRsZT53b3JrZmxvd19uZXc8L3RpdGxlPjxjaXJjbGUgY3g9IjQwMC41IiBjeT0iMjQ5LjUiIHI9Ijk5LjUiLz48Y2lyY2xlIGN4PSI5OS41IiBjeT0iOTkuNSIgcj0iOTkuNSIvPjxjaXJjbGUgY3g9Ijk5LjUiIGN5PSI0MDAuNSIgcj0iOTkuNSIvPjxnIGlkPSJMYXllcl80IiBkYXRhLW5hbWU9IkxheWVyIDQiPjxsaW5lIHgxPSI5OSIgeTE9Ijk5IiB4Mj0iNDAwIiB5Mj0iMjQ5IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS13aWR0aDo0MHB4Ii8+PGxpbmUgeDE9Ijk5IiB5MT0iNDAwIiB4Mj0iNDAwIiB5Mj0iMjQ5IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS13aWR0aDo0MHB4Ii8+PC9nPjwvc3ZnPg==" :
model.run && model.run.class === "CommandLineTool" ? "data:image/svg+xml;base64,PHN2ZyBpZD0idG9vbCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTAwLjA3IDUwMC4yNCI+PHRpdGxlPnRvb2xfbmV3PC90aXRsZT48cmVjdCB4PSIyODQuMDciIHk9IjQ1MC4wNyIgd2lkdGg9IjIxNiIgaGVpZ2h0PSI1MCIvPjxyZWN0IHg9Ii0zNC4xNCIgeT0iMTE3LjU2IiB3aWR0aD0iMzUzLjQiIGhlaWdodD0iNTAiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0Mi42MiAtNTguOTgpIHJvdGF0ZSg0NSkiLz48cmVjdCB4PSItMzQuMTUiIHk9IjMzMi41MyIgd2lkdGg9IjM1My40NyIgaGVpZ2h0PSI1MCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDk2LjI4IDUwOS41OCkgcm90YXRlKDEzNSkiLz48L3N2Zz4=" : "";
iconStr = model.run && model.run.class === "Workflow" ? this.workflowIconSvg :
model.run && model.run.class === "CommandLineTool" ? this.toolIconSvg : "";
}
else if (modelType === "input") {
iconStr = model.type && model.type.type === "File" ||
model.type.type === "array" ? "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OTkgNDYyLjg2Ij48dGl0bGU+ZmlsZV9pbnB1dDwvdGl0bGU+PGcgaWQ9IkxheWVyXzE2IiBkYXRhLW5hbWU9IkxheWVyIDE2Ij48cG9seWdvbiBwb2ludHM9IjM4Ni4wNiAwIDM4Ni4wNiAwIDE3NSAwIDE3NSA1OC4yOSAyMjUgMTA4LjI5IDIyNSA1MCAzNjUuMzUgNTAgNDQ5IDEzMy42NSA0NDkgNDEyLjg2IDIyNSA0MTIuODYgMjI1IDM1My43MSAxNzUgNDAzLjcxIDE3NSA0NjIuODYgNDk5IDQ2Mi44NiA0OTkgMTEyLjk0IDM4Ni4wNiAwIi8+PC9nPjxnIGlkPSJMYXllcl83X2NvcHkiIGRhdGEtbmFtZT0iTGF5ZXIgNyBjb3B5Ij48cG9seWxpbmUgcG9pbnRzPSI0OTguNzggMTM4Ljc2IDM2Mi45MyAxMzguMzggMzYyLjgxIDEzOC4zOCAzNjIuODEgMS4wNiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6NTBweCIvPjwvZz48ZyBpZD0iTGF5ZXJfMTFfY29weSIgZGF0YS1uYW1lPSJMYXllciAxMSBjb3B5Ij48cG9seWxpbmUgcG9pbnRzPSIxNTkgMzI3IDI1NSAyMzEgMTYwIDEzNiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6NTBweCIvPjxnIGlkPSJMYXllcl85X2NvcHlfMiIgZGF0YS1uYW1lPSJMYXllciA5IGNvcHkgMiI+PGxpbmUgeTE9IjIzMSIgeDI9IjI1NSIgeTI9IjIzMSIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6NTBweCIvPjwvZz48L2c+PC9zdmc+" :
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0OTkgMzY1Ij48dGl0bGU+dHlwZV9pbnB1dDwvdGl0bGU+PGcgaWQ9ImlucHV0Ij48cGF0aCBkPSJNMzE2LjUsNjhhMTgxLjcyLDE4MS43MiwwLDAsMC0xMTQuMTIsNDAuMDlMMjM4LDE0My43MmExMzIuNSwxMzIuNSwwLDEsMSwxLjE2LDIxNC4zOUwyMDMuNDgsMzkzLjhBMTgyLjUsMTgyLjUsMCwxLDAsMzE2LjUsNjhaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIC02OCkiLz48ZyBpZD0iTGF5ZXJfMjIiIGRhdGEtbmFtZT0iTGF5ZXIgMjIiPjxnIGlkPSJMYXllcl85X2NvcHlfNCIgZGF0YS1uYW1lPSJMYXllciA5IGNvcHkgNCI+PHBvbHlnb24gcG9pbnRzPSIyOTAuMzYgMTgyIDE3Ni42OCAyOTUuNjggMTQxLjMyIDI2MC4zMiAxOTQuNjQgMjA3IDAgMjA3IDAgMTU3IDE5NC42NCAxNTcgMTQyLjMyIDEwNC42OCAxNzcuNjggNjkuMzIgMjkwLjM2IDE4MiIvPjwvZz48L2c+PC9nPjwvc3ZnPg==";
model.type.type === "array" ? this.fileInputIconSvg :
this.inputIconSvg;
}
else if (modelType === "output") {
iconStr = model.type && model.type.type === "File" ||
model.type.type === "array" ? "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDcuMzYgNDYyLjg2Ij48dGl0bGU+ZmlsZV9vdXRwdXQ8L3RpdGxlPjxnIGlkPSJMYXllcl8xMCIgZGF0YS1uYW1lPSJMYXllciAxMCI+PGcgaWQ9IkxheWVyXzlfY29weSIgZGF0YS1uYW1lPSJMYXllciA5IGNvcHkiPjxwb2x5Z29uIHBvaW50cz0iMjc0IDI5OC41IDI3NCA0MTIuODYgNTAgNDEyLjg2IDUwIDUwIDE5MC4zNSA1MCAyNzQgMTMzLjY1IDI3NCAxNjMuNSAzMjQgMTYzLjUgMzI0IDExMi45NCAyMTEuMDYgMCAyMTEuMDYgMCAwIDAgMCA0NjIuODYgMzI0IDQ2Mi44NiAzMjQgMjk4LjUgMjc0IDI5OC41Ii8+PC9nPjwvZz48ZyBpZD0iTGF5ZXJfNyIgZGF0YS1uYW1lPSJMYXllciA3Ij48cG9seWxpbmUgcG9pbnRzPSIzMjMuNzggMTM4Ljc2IDE4Ny45MyAxMzguMzggMTg3LjgxIDEzOC4zOCAxODcuODEgMS4wNiIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6NTBweCIvPjwvZz48ZyBpZD0iTGF5ZXJfMTEiIGRhdGEtbmFtZT0iTGF5ZXIgMTEiPjxwb2x5bGluZSBwb2ludHM9IjM3NiAzMjcgNDcyIDIzMSAzNzcgMTM2IiBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS13aWR0aDo1MHB4Ii8+PGcgaWQ9IkxheWVyXzkiIGRhdGEtbmFtZT0iTGF5ZXIgOSI+PGxpbmUgeDE9IjIxNyIgeTE9IjIzMSIgeDI9IjQ3MiIgeTI9IjIzMSIgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2Utd2lkdGg6NTBweCIvPjwvZz48L2c+PC9zdmc+" :
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAuMzYgMzY1Ij48dGl0bGU+dHlwZV9vdXRwdXQ8L3RpdGxlPjxnIGlkPSJvdXRwdXQiPjxwYXRoIGQ9Ik0yOTEuOTUsMzI1LjIzYTEzNCwxMzQsMCwwLDEtMTUuNzYsMTksMTMyLjUsMTMyLjUsMCwxLDEsMC0xODcuMzgsMTMzLjksMTMzLjksMCwwLDEsMTYuMTYsMTkuNTVsMzUuODEtMzUuODFBMTgyLjUsMTgyLjUsMCwxLDAsMzI3LjczLDM2MVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTY4KSIvPjxnIGlkPSJjaXJjbGVfc291cmNlX2NvcHkiIGRhdGEtbmFtZT0iY2lyY2xlIHNvdXJjZSBjb3B5Ij48ZyBpZD0iTGF5ZXJfMjJfY29weSIgZGF0YS1uYW1lPSJMYXllciAyMiBjb3B5Ij48ZyBpZD0iTGF5ZXJfOV9jb3B5XzUiIGRhdGEtbmFtZT0iTGF5ZXIgOSBjb3B5IDUiPjxwb2x5Z29uIHBvaW50cz0iNTAwLjM2IDE4MiAzODYuNjggMjk1LjY4IDM1MS4zMiAyNjAuMzIgNDA0LjY0IDIwNyAyMTAgMjA3IDIxMCAxNTcgNDA0LjY0IDE1NyAzNTIuMzIgMTA0LjY4IDM4Ny42OCA2OS4zMiA1MDAuMzYgMTgyIi8+PC9nPjwvZz48L2c+PC9nPjwvc3ZnPg==";
model.type.type === "array" ? this.fileOutputIconSvg :
this.outputIconSvg;
}

@@ -53,7 +36,3 @@ if (!modelType.length || !iconStr.length) {

}
// return `
// <g class="icon icon-${iconStr}">
// </g>
// `;
return "\n <image x=\"-10\" y=\"-10\" width=\"20\" height=\"20\" xlink:href=\"" + iconStr + "\"></image>\n ";
return iconStr;
};

@@ -68,4 +47,4 @@ GraphNode.makeTemplate = function (x, y, dataModel) {

}
var inputs = (dataModel.in || []).filter(function (p) { return p.isVisible; });
var outputs = (dataModel.out || []).filter(function (p) { return p.isVisible; });
var inputs = (dataModel["in"] || []).filter(function (p) { return p.isVisible; });
var outputs = (dataModel["out"] || []).filter(function (p) { return p.isVisible; });
var maxPorts = Math.max(inputs.length, outputs.length);

@@ -75,26 +54,10 @@ var radius = GraphNode.radius + maxPorts * io_port_1.IOPort.radius;

.sort(function (a, b) { return -a.id.localeCompare(b.id); })
.map(function (p, i, arr) { return GraphNode.makePortTemplate(p, "input", GraphNode.createPortMatrix(arr.length, i, radius, "input").toString()); })
.map(function (p, i, arr) { return GraphNode.makePortTemplate(p, "input", svg_utils_1.SVGUtils.matrixToTransformAttr(GraphNode.createPortMatrix(arr.length, i, radius, "input"))); })
.reduce(function (acc, tpl) { return acc + tpl; }, "");
var outputPortTemplates = outputs
.sort(function (a, b) { return -a.id.localeCompare(b.id); })
.map(function (p, i, arr) { return GraphNode.makePortTemplate(p, "output", GraphNode.createPortMatrix(arr.length, i, radius, "output").toString()); })
.map(function (p, i, arr) { return GraphNode.makePortTemplate(p, "output", svg_utils_1.SVGUtils.matrixToTransformAttr(GraphNode.createPortMatrix(arr.length, i, radius, "output"))); })
.reduce(function (acc, tpl) { return acc + tpl; }, "");
return "\n <g tabindex=\"-1\" class=\"node " + dataModel.id + " " + nodeTypeClass + "\"\n data-connection-id=\"" + dataModel.connectionId + "\"\n transform=\"matrix(1, 0, 0, 1, " + x + ", " + y + ")\"\n data-id=\"" + dataModel.id + "\">\n <g class=\"drag-handle\" transform=\"matrix(1, 0, 0, 1, 0, 0)\">\n <circle cx=\"0\" cy=\"0\" r=\"" + radius + "\" class=\"outer\"></circle>\n <circle cx=\"0\" cy=\"0\" r=\"" + radius * .75 + "\" class=\"inner\"></circle>\n " + GraphNode.makeIconFragment(dataModel) + "\n </g>\n <text transform=\"matrix(1,0,0,1,0," + (radius + 30) + ")\" class=\"title label\">" + (dataModel.label || dataModel.id) + "</text>\n " + inputPortTemplates + "\n " + outputPortTemplates + "\n </g>\n ";
};
GraphNode.prototype.draw = function () {
console.log("Drawing snap el");
this.group.transform(new Snap.Matrix().translate(this.position.x, this.position.y));
var iconFragment = "";
if (this.dataModel instanceof models_1.StepModel) {
if (this.dataModel.run.class == "CommandLineTool") {
iconFragment = "\n <g class=\"icon icon-tool\">\n <path d=\"M 0 10 h 15\"></path>\n <path d=\"M -10 10 L 0 0 L -10 -10\"></path>\n </g>\n ";
}
else if (this.dataModel.run.class === "Workflow") {
iconFragment = "\n <g class=\"icon icon-workflow\">\n <circle cx=\"-8\" cy=\"10\" r=\"3\"></circle>\n <circle cx=\"12\" cy=\"0\" r=\"3\"></circle>\n <circle cx=\"-8\" cy=\"-10\" r=\"3\"></circle>\n <line x1=\"-8\" y1=\"10\" x2=\"12\" y2=\"0\"></line>\n <line x1=\"-8\" y1=\"-10\" x2=\"12\" y2=\"0\"></line>\n </g>\n ";
}
}
this.group.add(Snap.parse("\n <g class=\"drag-handle\" transform=\"matrix(1, 0, 0, 1, 0, 0)\">\n <circle cx=\"0\" cy=\"0\" r=\"" + GraphNode.radius + "\" class=\"outer\"></circle>\n <circle cx=\"0\" cy=\"0\" r=\"" + GraphNode.radius * .8 + "\" class=\"inner\"></circle>\n " + iconFragment + "\n </g>\n <text transform=\"matrix(1,0,0,1,0," + (GraphNode.radius + 30) + ")\" class=\"label\">" + (this.dataModel.label || this.dataModel.id) + "</text>\n "));
// this.attachEventListeners(this.circleGroup);
return this.group;
};
GraphNode.makePortTemplate = function (port, type, transform) {

@@ -104,64 +67,4 @@ if (transform === void 0) { transform = "matrix(1, 0, 0, 1, 0, 0)"; }

var label = port.label || port.id;
var template = "\n <g class=\"port " + portClass + " " + port.id + "\" transform=\"" + (transform || 'matrix(1, 0, 0, 1, 0, 0)') + "\"\n data-connection-id=\"" + port.connectionId + "\"\n data-port-id=\"" + port.id + "\"\n >\n <g class=\"io-port " + port.id + "\">\n <circle cx=\"0\" cy=\"0\" r=\"7\" class=\"port-handle\"></circle>\n </g>\n <text x=\"0\" y=\"0\" transform=\"matrix(1,0,0,1,0,0)\" class=\"label unselectable\">" + label + "</text>\n </g>\n \n ";
return template;
return "\n <g class=\"port " + portClass + " " + port.id + "\" transform=\"" + (transform || 'matrix(1, 0, 0, 1, 0, 0)') + "\"\n data-connection-id=\"" + port.connectionId + "\"\n data-port-id=\"" + port.id + "\"\n >\n <g class=\"io-port " + port.id + "\">\n <circle cx=\"0\" cy=\"0\" r=\"7\" class=\"port-handle\"></circle>\n </g>\n <text x=\"0\" y=\"0\" transform=\"matrix(1,0,0,1,0,0)\" class=\"label unselectable\">" + label + "</text>\n </g>\n \n ";
};
GraphNode.prototype.addPort = function (port) {
var template = GraphNode.makePortTemplate(port);
this.group.add(Snap.parse(template));
// Ports should be sorted in reverse to comply with the SBG platform's coordinate positioning
// portStore = portStore.sort((a, b) => -a.portModel.id.localeCompare(b.portModel.id));
this.distributePorts();
// if (portStore.length > 6 && portStore.length <= 20) {
//
// const [a, b] = portStore.slice(-2).map(i => i.group.getBBox());
// const overlapping = a.y + a.height >= b.y;
// if (overlapping) {
// this.scale(1.08);
// this.distributePorts();
// }
// }
};
/**
* Moves the element to the outer edge of the node given an angle and the node radius
* @param el Element to move
* @param angle Angle along which the element should be moved
* @param radius Radius of the parent node
*/
GraphNode.movePortToOuterEdge = function (el, angle, radius) {
el // Remove previous transformations, bring it to the center
.transform(new Snap.Matrix()
.rotate(angle, 0, 0)
.translate(radius, 0)
.rotate(-angle, 0, 0));
};
/**
* Repositions input and output ports to their designated places on the outer edge
* of the node and scales the node in the process if necessary.
*/
GraphNode.prototype.distributePorts = function () {
var outputs = Array.from(this.group.node.querySelectorAll(".output-port")).map(function (p) { return Snap(p); });
var inputs = Array.from(this.group.node.querySelectorAll(".input-port")).map(function (p) { return Snap(p); });
var availableAngle = 140;
var rotationAngle;
// Distribute output ports
for (var i = 0; i < outputs.length; i++) {
rotationAngle =
// Starting rotation angle
(-availableAngle / 2) +
(
// Angular offset by element index
(i + 1)
* availableAngle / (outputs.length + 1));
GraphNode.movePortToOuterEdge(outputs[i], rotationAngle, GraphNode.radius);
}
// Distribute input ports
for (var i = 0; i < inputs.length; i++) {
rotationAngle =
// Determines the starting rotation angle
180 - (availableAngle / -2)
- (i + 1)
* availableAngle / (inputs.length + 1);
GraphNode.movePortToOuterEdge(inputs[i], rotationAngle, GraphNode.radius);
}
};
GraphNode.createPortMatrix = function (totalPortLength, portIndex, radius, type) {

@@ -183,6 +86,4 @@ var availableAngle = 140;

}
return new Snap.Matrix()
.rotate(rotationAngle, 0, 0)
.translate(radius, 0)
.rotate(-rotationAngle, 0, 0);
var matrix = svg_utils_1.SVGUtils.createMatrix();
return matrix.rotate(rotationAngle).translate(radius, 0).rotate(-rotationAngle);
};

@@ -210,5 +111,14 @@ GraphNode.createGhostIO = function () {

return GraphNode;
}(shape_1.Shape));
}());
GraphNode.radius = 30;
/**
* @FIXME Making icons increases the rendering time by 50-100%. Try embedding the SVG directly.
*/
GraphNode.workflowIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500" x="-9" y="-9" width="20" height="20"><title>workflow_new</title><circle cx="400.5" cy="249.5" r="99.5"/><circle cx="99.5" cy="99.5" r="99.5"/><circle cx="99.5" cy="400.5" r="99.5"/><g id="Layer_4" data-name="Layer 4"><line x1="99" y1="99" x2="400" y2="249" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:40px"/><line x1="99" y1="400" x2="400" y2="249" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:40px"/></g></svg>';
GraphNode.toolIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500.07 500.24" x="-10" y="-10" width="20" height="20"><title>tool_new</title><rect x="284.07" y="450.07" width="216" height="50"/><rect x="-34.14" y="117.56" width="353.4" height="50" transform="translate(142.62 -58.98) rotate(45)"/><rect x="-34.15" y="332.53" width="353.47" height="50" transform="translate(496.28 509.58) rotate(135)"/></svg>';
GraphNode.fileInputIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 499 462.86" y="-10" x="-11" width="20" height="20"><title>file_input</title><g id="Layer_16" data-name="Layer 16"><polygon points="386.06 0 386.06 0 175 0 175 58.29 225 108.29 225 50 365.35 50 449 133.65 449 412.86 225 412.86 225 353.71 175 403.71 175 462.86 499 462.86 499 112.94 386.06 0"/></g><g id="Layer_7_copy" data-name="Layer 7 copy"><polyline points="498.78 138.76 362.93 138.38 362.81 138.38 362.81 1.06" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/></g><g id="Layer_11_copy" data-name="Layer 11 copy"><polyline points="159 327 255 231 160 136" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/><g id="Layer_9_copy_2" data-name="Layer 9 copy 2"><line y1="231" x2="255" y2="231" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/></g></g></svg>';
GraphNode.fileOutputIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 507.36 462.86" x="-9" y="-10" width="20" height="20"><title>file_output</title><g id="Layer_10" data-name="Layer 10"><g id="Layer_9_copy" data-name="Layer 9 copy"><polygon points="274 298.5 274 412.86 50 412.86 50 50 190.35 50 274 133.65 274 163.5 324 163.5 324 112.94 211.06 0 211.06 0 0 0 0 462.86 324 462.86 324 298.5 274 298.5"/></g></g><g id="Layer_7" data-name="Layer 7"><polyline points="323.78 138.76 187.93 138.38 187.81 138.38 187.81 1.06" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/></g><g id="Layer_11" data-name="Layer 11"><polyline points="376 327 472 231 377 136" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/><g id="Layer_9" data-name="Layer 9"><line x1="217" y1="231" x2="472" y2="231" style="fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px"/></g></g></svg>';
GraphNode.inputIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 499 365" x="-11" y="-10" width="20" height="20"><title>type_input</title><g id="input"><path d="M316.5,68a181.72,181.72,0,0,0-114.12,40.09L238,143.72a132.5,132.5,0,1,1,1.16,214.39L203.48,393.8A182.5,182.5,0,1,0,316.5,68Z" transform="translate(0 -68)"/><g id="Layer_22" data-name="Layer 22"><g id="Layer_9_copy_4" data-name="Layer 9 copy 4"><polygon points="290.36 182 176.68 295.68 141.32 260.32 194.64 207 0 207 0 157 194.64 157 142.32 104.68 177.68 69.32 290.36 182"/></g></g></g></svg>';
GraphNode.outputIconSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500.36 365" x="-9" y="-10" width="20" height="20"><title>type_output</title><g id="output"><path d="M291.95,325.23a134,134,0,0,1-15.76,19,132.5,132.5,0,1,1,0-187.38,133.9,133.9,0,0,1,16.16,19.55l35.81-35.81A182.5,182.5,0,1,0,327.73,361Z" transform="translate(0 -68)"/><g id="circle_source_copy" data-name="circle source copy"><g id="Layer_22_copy" data-name="Layer 22 copy"><g id="Layer_9_copy_5" data-name="Layer 9 copy 5"><polygon points="500.36 182 386.68 295.68 351.32 260.32 404.64 207 210 207 210 157 404.64 157 352.32 104.68 387.68 69.32 500.36 182"/></g></g></g></g></svg>';
exports.GraphNode = GraphNode;
//# sourceMappingURL=graph-node.js.map

@@ -1,19 +0,4 @@

/// <reference types="snapsvg" />
import { WorkflowStepInputModel, WorkflowStepOutputModel } from "cwlts/models";
import { Shape } from "./shape";
export declare class IOPort extends Shape {
group: Snap.Element;
protected paper: Snap.Paper;
export declare class IOPort {
static radius: number;
private connection;
private connectionFormat;
portModel: WorkflowStepInputModel | WorkflowStepOutputModel;
protected handle: Snap.Element;
constructor(paper: Snap.Paper, portModel: any);
protected drawHandle(): Snap.Element;
private attachDragBehaviour(el);
static makeConnectionPath(x1: any, y1: any, x2: any, y2: any, forceDirection?: "right" | "left"): string;
private makePathStringBetween(x1, y1, x2, y2);
protected getClass(): string;
connectTo(port: IOPort): void;
static makeConnectionPath(x1: any, y1: any, x2: any, y2: any, forceDirection?: "right" | "left" | string): string;
}
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var shape_1 = require("./shape");
var IOPort = (function (_super) {
__extends(IOPort, _super);
function IOPort(paper, portModel) {
var _this = _super.call(this) || this;
_this.connectionFormat = "M {x1} {y1}, C {bx1} {by1} {bx2} {by2} {x2} {y2}";
_this.paper = paper;
_this.portModel = portModel;
return _this;
var IOPort = (function () {
function IOPort() {
}
IOPort.prototype.drawHandle = function () {
var _a = this.portModel.connectionId.split("/"), id = _a[2];
var outer = this.paper.circle(0, 0, IOPort.radius).addClass("port-handle");
return this.paper.group(outer).addClass("io-port " + id);
};
IOPort.prototype.attachDragBehaviour = function (el) {
var _this = this;
var path;
var rect;
el.drag(function (dx, dy, mx, my, ev) {
path.attr({
path: Snap.format(_this.connectionFormat, {
x1: rect.left,
y1: rect.top,
bx1: (rect.left + mx) / 2,
by1: rect.top,
bx2: (rect.left + mx) / 2,
by2: my,
x2: mx,
y2: my
})
});
}, function (x, y, ev) {
rect = el.node.getBoundingClientRect();
path = _this.paper.path(Snap.format(_this.connectionFormat, {
x1: rect.left,
y1: rect.top,
bx1: rect.left,
by1: rect.top,
bx2: rect.left,
by2: rect.top,
x2: rect.left,
y2: rect.top
})).attr({
fill: "none",
stroke: "gray",
strokeWidth: 2,
id: (_this.constructor.name)
});
}, function (ev) {
path.remove();
});
};
IOPort.makeConnectionPath = function (x1, y1, x2, y2, forceDirection) {

@@ -82,34 +22,6 @@ if (forceDirection === void 0) { forceDirection = "right"; }

};
IOPort.prototype.makePathStringBetween = function (x1, y1, x2, y2) {
return Snap.format(this.connectionFormat, {
x1: x1,
y1: y1,
bx1: (x1 + x2) / 2,
by1: y1,
bx2: (x1 + x2) / 2,
by2: y2,
x2: x2,
y2: y2
});
};
IOPort.prototype.getClass = function () {
return "port";
};
IOPort.prototype.connectTo = function (port) {
if (this.connection) {
this.connection.remove();
this.connection = undefined;
}
var thisRect = this.group.node.getBoundingClientRect();
var otherRect = port.group.node.getBoundingClientRect();
this.connection = this.paper.path(this.makePathStringBetween(thisRect.left, thisRect.top, otherRect.left, otherRect.top)).attr({
fill: "none",
stroke: "gray",
strokeWidth: 2
});
};
return IOPort;
}(shape_1.Shape));
}());
IOPort.radius = 7;
exports.IOPort = IOPort;
//# sourceMappingURL=io-port.js.map

@@ -1,8 +0,5 @@

/// <reference types="snapsvg" />
import { WorkflowModel } from "cwlts/models";
import "snapsvg-cjs";
import { EventHub } from "../utils/event-hub";
export declare class Workflow {
private paper;
private group;
/** Current scale of the document */
private scale;

@@ -14,3 +11,22 @@ readonly eventHub: EventHub;

private model;
constructor(paper: Snap.Paper, model: WorkflowModel);
private workflowBoundingClientRect;
/**
* The size of the workflow boundary / padding that stops nodes from being dragged
* outside the workflow viewport; drag "scroll" is activated when cursor hits a boundary
* @type {number}
*/
private dragBoundary;
/**
* The amount which the workflow, node, and necessary paths will be translated
* when mouse is dragged on boundary or outside workflow every time the interval runs
* @type {number}
*/
private dragBoundaryTranslation;
/**
* The interval that is set when the cursor hits a boundary (or multiple boundaries)
* x and y represent the axes on which the boundary is hit, the interval is the interval
* function itself, and xOffset and yOffset represent the accumulated translations
*/
private dragBoundaryInterval;
constructor(svgRoot: SVGSVGElement, model: WorkflowModel);
command(event: string, ...data: any[]): void;

@@ -20,2 +36,3 @@ on(event: string, handler: any): void;

getScale(): number;
arrange(): void;
/**

@@ -25,2 +42,3 @@ * Scales the workflow to fit the available viewport

fitToViewport(): void;
private redrawEdges();
private renderModel(model);

@@ -34,12 +52,46 @@ static canDrawIn(element: SVGElement): boolean;

}): void;
private edgePadding;
private edgeInterval;
private ifDraggingMouseCloseToEdge(el, coords, dx, dy);
private addEventListeners(root);
/**
* Sets the interval for dragging within a boundary zone if a new
* boundary zone has been hit. The interval function translates the workflow,
* the dragging node, and the edges attached to that node.
* @param el
* @param boundary
* @param pathInfo
* @param ghostIO
*/
private setDragBoundaryIntervalIfNecessary(el, boundary, pathInfo?, ghostIO?);
/**
* Check all possible workflow boundaries to see if (x,y) is on edge(s)
* -1 / 1 values are left / right and top / bottom depending on the axis,
* and 0 means it has not hit a boundary on that axis
*/
private getBoundaryZonesXYAxes(x, y);
/**
* Calculates the change in x and y for drag, taking into account the starting x and y,
* the cursor position, the boundary offsets, and the current scale coefficient.
* @param boundary
* @param ev
* @param startX
* @param startY
* @param dx
* @param dy
* @returns {{x: any, y: any}}
*/
private getScaledDeltaXYForDrag(boundary, ev, startX, startY, dx, dy);
/**
* Updates a node's input edges based on the node's output ports' locations,
* and a node's output edges based on the node's input ports' locations
* @param inputEdges
* @param outputEdges
* @param dx
* @param dy
*/
private setInputAndOutputEdges(inputEdges, outputEdges, dx, dy);
private highlightEdge(el);
private adaptToScale(x);
deselectEverything(): void;
translateMouseCoords(x: any, y: any): {
x: any;
y: any;
transformScreenCTMtoCanvas(x: any, y: any): {
x: number;
y: number;
};

@@ -55,2 +107,3 @@ private attachEdgeHoverBehavior(el);

destroy(): void;
private resetTransform();
}

@@ -11,3 +11,2 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
require("snapsvg-cjs");
var dom_events_1 = require("../utils/dom-events");

@@ -20,25 +19,41 @@ var event_hub_1 = require("../utils/event-hub");

var template_parser_1 = require("./template-parser");
Snap.plugin(function (Snap, Element) {
var proto = Element.prototype;
proto.toFront = function () {
this.appendTo(this.node.parentNode);
};
proto.toBack = function () {
this.prependTo(this.node.parentNode);
};
});
var svg_utils_1 = require("../utils/svg-utils");
var Workflow = (function () {
function Workflow(paper, model) {
function Workflow(svgRoot, model) {
var _this = this;
/** Current scale of the document */
this.scale = 1;
this.edgePadding = 100;
this.edgeInterval = null;
this.paper = paper;
this.svgRoot = paper.node;
/**
* The size of the workflow boundary / padding that stops nodes from being dragged
* outside the workflow viewport; drag "scroll" is activated when cursor hits a boundary
* @type {number}
*/
this.dragBoundary = 50;
/**
* The amount which the workflow, node, and necessary paths will be translated
* when mouse is dragged on boundary or outside workflow every time the interval runs
* @type {number}
*/
this.dragBoundaryTranslation = 5;
/**
* The interval that is set when the cursor hits a boundary (or multiple boundaries)
* x and y represent the axes on which the boundary is hit, the interval is the interval
* function itself, and xOffset and yOffset represent the accumulated translations
*/
this.dragBoundaryInterval = {
x: false,
y: false,
interval: null,
xOffset: 0,
yOffset: 0
};
this.svgRoot = svgRoot;
this.model = model;
this.domEvents = new dom_events_1.DomEvents(this.paper.node);
this.paper.node.innerHTML = "\n <symbol id=\"file_input\" viewBox=\"0 0 499 462.86\"><title>file_input</title><g id=\"Layer_16\" data-name=\"Layer 16\"><polygon points=\"386.06 0 386.06 0 175 0 175 58.29 225 108.29 225 50 365.35 50 449 133.65 449 412.86 225 412.86 225 353.71 175 403.71 175 462.86 499 462.86 499 112.94 386.06 0\"/></g><g id=\"Layer_7_copy\" data-name=\"Layer 7 copy\"><polyline points=\"498.78 138.76 362.93 138.38 362.81 138.38 362.81 1.06\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/></g><g id=\"Layer_11_copy\" data-name=\"Layer 11 copy\"><polyline points=\"159 327 255 231 160 136\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/><g id=\"Layer_9_copy_2\" data-name=\"Layer 9 copy 2\"><line y1=\"231\" x2=\"255\" y2=\"231\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/></g></g></symbol>\n <symbol id=\"file_output\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 507.36 462.86\"><title>file_output</title><g id=\"Layer_10\" data-name=\"Layer 10\"><g id=\"Layer_9_copy\" data-name=\"Layer 9 copy\"><polygon points=\"274 298.5 274 412.86 50 412.86 50 50 190.35 50 274 133.65 274 163.5 324 163.5 324 112.94 211.06 0 211.06 0 0 0 0 462.86 324 462.86 324 298.5 274 298.5\"/></g></g><g id=\"Layer_7\" data-name=\"Layer 7\"><polyline points=\"323.78 138.76 187.93 138.38 187.81 138.38 187.81 1.06\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/></g><g id=\"Layer_11\" data-name=\"Layer 11\"><polyline points=\"376 327 472 231 377 136\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/><g id=\"Layer_9\" data-name=\"Layer 9\"><line x1=\"217\" y1=\"231\" x2=\"472\" y2=\"231\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:50px\"/></g></g></symbol>\n <symbol id=\"tool\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500.07 500.24\"><title>tool_new</title><rect x=\"284.07\" y=\"450.07\" width=\"216\" height=\"50\"/><rect x=\"-34.14\" y=\"117.56\" width=\"353.4\" height=\"50\" transform=\"translate(142.62 -58.98) rotate(45)\"/><rect x=\"-34.15\" y=\"332.53\" width=\"353.47\" height=\"50\" transform=\"translate(496.28 509.58) rotate(135)\"/></symbol>\n <symbol id=\"workflow\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500 500\"><title>workflow_new</title><circle cx=\"400.5\" cy=\"249.5\" r=\"99.5\"/><circle cx=\"99.5\" cy=\"99.5\" r=\"99.5\"/><circle cx=\"99.5\" cy=\"400.5\" r=\"99.5\"/><g id=\"Layer_4\" data-name=\"Layer 4\"><line x1=\"99\" y1=\"99\" x2=\"400\" y2=\"249\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:40px\"/><line x1=\"99\" y1=\"400\" x2=\"400\" y2=\"249\" style=\"fill:none;stroke:#000;stroke-miterlimit:10;stroke-width:40px\"/></g></symbol>\n <symbol id=\"type_input\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 499 365\"><title>type_input</title><g id=\"input\"><path d=\"M316.5,68a181.72,181.72,0,0,0-114.12,40.09L238,143.72a132.5,132.5,0,1,1,1.16,214.39L203.48,393.8A182.5,182.5,0,1,0,316.5,68Z\" transform=\"translate(0 -68)\"/><g id=\"Layer_22\" data-name=\"Layer 22\"><g id=\"Layer_9_copy_4\" data-name=\"Layer 9 copy 4\"><polygon points=\"290.36 182 176.68 295.68 141.32 260.32 194.64 207 0 207 0 157 194.64 157 142.32 104.68 177.68 69.32 290.36 182\"/></g></g></g></symbol>\n <symbol id=\"type_output\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 500.36 365\"><title>type_output</title><g id=\"output\"><path d=\"M291.95,325.23a134,134,0,0,1-15.76,19,132.5,132.5,0,1,1,0-187.38,133.9,133.9,0,0,1,16.16,19.55l35.81-35.81A182.5,182.5,0,1,0,327.73,361Z\" transform=\"translate(0 -68)\"/><g id=\"circle_source_copy\" data-name=\"circle source copy\"><g id=\"Layer_22_copy\" data-name=\"Layer 22 copy\"><g id=\"Layer_9_copy_5\" data-name=\"Layer 9 copy 5\"><polygon points=\"500.36 182 386.68 295.68 351.32 260.32 404.64 207 210 207 210 157 404.64 157 352.32 104.68 387.68 69.32 500.36 182\"/></g></g></g></g></symbol>\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" class=\"pan-handle\" transform=\"matrix(1,0,0,1,0,0)\"></rect>\n \n <g class=\"workflow\" transform=\"matrix(1,0,0,1,0,0)\"></g>\n ";
this.workflow = this.paper.node.querySelector(".workflow");
this.group = Snap(this.workflow);
this.paper.node.addEventListener("mousewheel", function (ev) {
this.domEvents = new dom_events_1.DomEvents(this.svgRoot);
this.svgRoot.innerHTML = "\n <rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" class=\"pan-handle\" transform=\"matrix(1,0,0,1,0,0)\"></rect>\n <g class=\"workflow\" transform=\"matrix(1,0,0,1,0,0)\"></g>\n ";
this.workflow = this.svgRoot.querySelector(".workflow");
/**
* Whenever user scrolls, take the scroll delta and scale the workflow.
*/
this.svgRoot.addEventListener("mousewheel", function (ev) {
var scale = _this.scale + ev.deltaY / 500;

@@ -61,8 +76,3 @@ // Prevent scaling to unreasonable proportions.

"app.create.output",
/** @link workflow.arrange */
"workflow.arrange",
/** @link workflow.scale */
"workflow.scale",
/** @link workflow.fit */
"workflow.fit",
"beforeChange",

@@ -74,4 +84,2 @@ ]);

}
console.time("Event Listeners");
console.timeEnd("Event Listeners");
}

@@ -95,2 +103,134 @@ Workflow.prototype.command = function (event) {

};
Workflow.prototype.arrange = function () {
var _this = this;
this.resetTransform();
// Edges are the main source of information from which we will distribute nodes
var edges = Array.from(this.workflow.querySelectorAll(".edge"));
// Make a graph representation where you can trace inputs and outputs from/to connection ids
var nodeSet = {};
var danglingNodes = Array.from(this.workflow.querySelectorAll(".node")).reduce(function (acc, el) {
return __assign({}, acc, (_a = {}, _a[el.getAttribute("data-connection-id")] = el, _a));
var _a;
}, {});
edges.forEach(function (edge) {
var sourceConnectionID = edge.getAttribute("data-source-connection");
var destinationConnectionID = edge.getAttribute("data-destination-connection");
var _a = sourceConnectionID.split("/"), sourceSide = _a[0], sourceNodeID = _a[1], sourcePortID = _a[2];
var _b = destinationConnectionID.split("/"), destinationSide = _b[0], destinationNodeID = _b[1], destinationPortID = _b[2];
var sourceType = "step";
var destinationType = "step";
if (sourceNodeID === sourcePortID) {
sourceType = sourceSide === "in" ? "output" : "input";
}
if (destinationNodeID === destinationPortID) {
destinationType = destinationSide === "in" ? "output" : "input";
}
// Initialize keys on graph if they don't exist
var sourceNode = _this.workflow.querySelector(".node[data-id=\"" + sourceNodeID + "\"]");
var destinationNode = _this.workflow.querySelector(".node[data-id=\"" + destinationNodeID + "\"]");
var sourceNodeConnectionID = sourceNode.getAttribute("data-connection-id");
var destinationNodeConnectionID = destinationNode.getAttribute("data-connection-id");
delete danglingNodes[sourceNodeConnectionID];
delete danglingNodes[destinationNodeConnectionID];
//
(nodeSet[sourceNodeID] || (nodeSet[sourceNodeID] = {
inputs: [],
outputs: [],
type: sourceType,
connectionID: sourceNodeConnectionID,
el: sourceNode,
rect: sourceNode.getBoundingClientRect()
}));
(nodeSet[destinationNodeID] || (nodeSet[destinationNodeID] = {
inputs: [],
outputs: [],
type: destinationType,
connectionID: destinationNodeConnectionID,
el: destinationNode,
rect: destinationNode.getBoundingClientRect()
}));
nodeSet[sourceNodeID].outputs.push(destinationNodeID);
nodeSet[destinationNodeID].inputs.push(sourceNodeID);
});
var traceLongestPath = function (node, visited) {
visited.add(node);
var ins = node.inputs.map(function (nid) { return nodeSet[nid]; });
return 1 + (ins.length ? Math.max.apply(Math, ins.filter(function (e) { return !visited.has(e); }).map(function (e) { return traceLongestPath(e, visited); })) : 0);
};
var idToZoneMap = Object.keys(nodeSet).reduce(function (zoneMap, nid) {
var item = nodeSet[nid];
var zone = traceLongestPath(item, new Set()) - 1;
return __assign({}, zoneMap, (_a = {}, _a[nid] = zone, _a));
var _a;
}, {});
for (var nid in nodeSet) {
var node = nodeSet[nid];
if (node.type === "input") {
var newZone = Math.min.apply(Math, node.outputs.map(function (out) { return idToZoneMap[out]; })) - 1;
idToZoneMap[nid] = newZone;
}
}
var columns = Object.keys(idToZoneMap).reduce(function (acc, nid) {
var zone = idToZoneMap[nid];
if (!acc[zone]) {
acc[zone] = [];
}
acc[zone].push(nodeSet[nid]);
return acc;
}, []);
var distributionAreaHeight = 0;
var distributionAreaWidth = 0;
var columnDimensions = Object.keys(columns).map(function (col) { return ({ height: 0, width: 0 }); });
columns.forEach(function (column, index) {
var width = 0;
var height = 0;
column.forEach(function (entry) {
height += entry.rect.height;
if (width < entry.rect.width) {
width = entry.rect.width;
}
});
columnDimensions[index] = { height: height, width: width };
distributionAreaWidth += width;
if (height > distributionAreaHeight) {
distributionAreaHeight = height;
}
});
var baseline = distributionAreaHeight / 2;
var xOffset = 0;
var maxYOffset = 0;
columns.forEach(function (column, index) {
var rowCount = column.length + 1;
var colSize = columnDimensions[index];
var yOffset = baseline - (colSize.height / 2);
column.forEach(function (node) {
var matrix = svg_utils_1.SVGUtils.createMatrix().translate(xOffset, yOffset);
yOffset += node.rect.height;
if (yOffset > maxYOffset) {
maxYOffset = yOffset;
}
node.el.setAttribute("transform", svg_utils_1.SVGUtils.matrixToTransformAttr(matrix));
var modelEntry = _this.model.findById(node.connectionID);
_this.setModelPosition(modelEntry, matrix.e, matrix.f);
});
xOffset += colSize.width;
});
var danglingNodeSideLength = graph_node_1.GraphNode.radius * 5;
var danglingNodeCount = Object.keys(danglingNodes).length;
var danglingRowBreakpoint = Math.floor(distributionAreaWidth / danglingNodeSideLength);
Object.keys(danglingNodes).forEach(function (connectionID, index) {
var el = danglingNodes[connectionID];
var left = (index % danglingRowBreakpoint) * danglingNodeSideLength;
var top = maxYOffset
+ danglingNodeSideLength
+ ((index % 3) * danglingNodeSideLength / 3)
+ Math.floor(index / danglingRowBreakpoint);
var matrix = svg_utils_1.SVGUtils.createMatrix().translate(left, top);
var modelEntry = _this.model.findById(el.getAttribute("data-connection-id"));
el.setAttribute("transform", svg_utils_1.SVGUtils.matrixToTransformAttr(matrix));
_this.setModelPosition(modelEntry, matrix.e, matrix.f);
});
this.redrawEdges();
this.fitToViewport();
};
/**

@@ -124,13 +264,19 @@ * Scales the workflow to fit the available viewport

};
Workflow.prototype.redrawEdges = function () {
var _this = this;
Array.from(this.workflow.querySelectorAll(".edge")).forEach(function (el) {
el.remove();
});
var edgesTpl = this.model.connections.map(function (c) { return edge_1.Edge.makeTemplate(c, _this.workflow); }).reduce(function (acc, tpl) { return acc + tpl; }, "");
this.workflow.innerHTML = edgesTpl + this.workflow.innerHTML;
};
Workflow.prototype.renderModel = function (model) {
var _this = this;
console.time("Graph Rendering");
this.model = model;
// We will need to restore the transformations when we redraw the model, so save the current state
var oldTransform = this.workflow.getAttribute("transform");
var selectedStuff = this.workflow.querySelectorAll(".selected");
if (selectedStuff.length) {
selectedStuff = selectedStuff.item(0).getAttribute("data-connection-id");
}
else {
selectedStuff = undefined;
}
// We might have an active selection that we want to preserve upon redrawing, save it
var selectedStuff = this.workflow.querySelector(".selected");
var selectedItemConnectionID = selectedStuff ? selectedStuff.getAttribute("data-connection-id") : undefined;
this.clearCanvas();

@@ -146,16 +292,19 @@ this.workflow.setAttribute("transform", "matrix(1,0,0,1,0,0)");

this.workflow.innerHTML += nodesTpl;
var edgesTpl = model.connections.map(function (c) { return edge_1.Edge.makeTemplate(c, _this.paper); }).reduce(function (acc, tpl) { return acc + tpl; }, "");
this.workflow.innerHTML += edgesTpl;
this.redrawEdges();
console.timeEnd("Graph Rendering");
console.time("Ordering");
this.workflow.querySelectorAll(".node").forEach(function (e) {
Array.from(this.workflow.querySelectorAll(".node")).forEach(function (e) {
_this.workflow.appendChild(e);
});
this.addEventListeners(this.paper.node);
this.addEventListeners(this.svgRoot);
this.workflow.setAttribute("transform", oldTransform);
console.timeEnd("Ordering");
this.scaleWorkflow(this.scale);
var newSelection = this.workflow.querySelector("[data-connection-id='" + selectedStuff + "']");
if (newSelection) {
this.activateSelection(newSelection);
// If we had a selection before, restore it
if (selectedItemConnectionID) {
var newSelection = this.workflow.querySelector("[data-connection-id='" + selectedItemConnectionID + "']");
// We need to check if the previously selected item still exist, since it might be deleted in the meantime
if (newSelection) {
this.activateSelection(newSelection);
}
}

@@ -165,3 +314,2 @@ };

var clientBounds = element.getBoundingClientRect();
console.log("Checking if drawable", clientBounds, element.getClientRects());
return clientBounds.width !== 0;

@@ -226,61 +374,2 @@ };

});
/**
* @name workflow.arrange
*/
this.eventHub.on("workflow.arrange", function (connections) {
var tracker = {};
var zones = {};
var width = _this.paper.node.clientWidth;
var height = _this.paper.node.clientHeight;
var workflowIns = new Map();
connections.forEach(function (c) {
var _a = c.source.id.split("/"), sName = _a[1], spName = _a[2];
var _b = c.destination.id.split("/"), dName = _b[1], dpName = _b[2];
tracker[sName] || (tracker[sName] = []);
(tracker[dName] || (tracker[dName] = [])).push(tracker[sName]);
if (sName === spName) {
workflowIns.set(tracker[sName], sName);
}
});
var trace = function (arr, visited) {
visited.add(arr);
return 1 + (arr.length ? Math.max.apply(Math, arr.filter(function (e) { return !visited.has(e); }).map(function (e) { return trace(e, visited); })) : 0);
};
var trackerKeys = Object.keys(tracker);
var idToZoneMap = trackerKeys.reduce(function (acc, k) {
return Object.assign(acc, (_a = {}, _a[k] = trace(tracker[k], new Set()) - 1, _a));
var _a;
}, {});
trackerKeys.forEach(function (k) {
tracker[k].filter(function (p) { return workflowIns.has(p); }).forEach(function (pre) {
idToZoneMap[workflowIns.get(pre)] = idToZoneMap[k] - 1;
});
});
trackerKeys.forEach(function (k) {
try {
var snap = Snap(".node." + k);
var zone = idToZoneMap[k];
if (!snap) {
throw new Error("Cant find node " + k);
}
(zones[zone] || (zones[zone] = [])).push(snap);
}
catch (ex) {
console.error("ERROR", k, ex, tracker);
}
});
var columnCount = Object.keys(zones).length + 1;
var columnWidth = (width / columnCount);
var _loop_1 = function (z) {
var rowCount = zones[z].length + 1;
var rowHeight = height / rowCount;
zones[z].forEach(function (el, i) {
el.transform(new Snap.Matrix()
.translate(columnWidth * (~~z + 1), (i + 1) * rowHeight));
});
};
for (var z in zones) {
_loop_1(z);
}
});
};

@@ -292,3 +381,3 @@ Workflow.prototype.scaleWorkflow = function (scaleCoefficient, ev) {

var matrix = transform.getItem(0).matrix;
var coords = this.translateMouseCoords(ev ? ev.clientX : 0, ev ? ev.clientY : 0);
var coords = this.transformScreenCTMtoCanvas(ev ? ev.clientX : 0, ev ? ev.clientY : 0);
matrix.e += matrix.a * coords.x;

@@ -307,32 +396,2 @@ matrix.f += matrix.a * coords.y;

};
Workflow.prototype.ifDraggingMouseCloseToEdge = function (el, coords, dx, dy) {
var _this = this;
var checkIfTranslateX = coords.x > window.innerWidth - this.edgePadding && dx > 0 ||
coords.x < this.edgePadding && dx < 0;
var checkIfTranslateY = coords.y > window.innerHeight - this.edgePadding && dy > 0 ||
coords.y < this.edgePadding && dy < 0;
if (checkIfTranslateX || checkIfTranslateY) {
var workflowMatrix = this.workflow.transform.baseVal.getItem(0).matrix;
var newMatrix = workflowMatrix.translate(checkIfTranslateX ? -dx : 0, checkIfTranslateY ? -dy : 0);
workflowMatrix.e = newMatrix.e;
workflowMatrix.f = newMatrix.f;
if (!this.edgeInterval) {
this.edgeInterval = setInterval(function () {
var workflowMatrix = _this.workflow.transform.baseVal.getItem(0).matrix;
var newMatrix = workflowMatrix.translate(checkIfTranslateX ? -dx : 0, checkIfTranslateY ? -dy : 0);
workflowMatrix.e = newMatrix.e;
workflowMatrix.f = newMatrix.f;
var mx = el.transform.baseVal.getItem(0).matrix.translate(dx, dy);
el.transform.baseVal.getItem(0).setTranslate(mx.e, mx.f);
}, 1000 / 60);
}
console.log("Dragging Close to Edge dx: %d", dx);
}
else {
if (this.edgeInterval) {
clearInterval(this.edgeInterval);
this.edgeInterval = null;
}
}
};
Workflow.prototype.addEventListeners = function (root) {

@@ -365,26 +424,18 @@ var _this = this;

this.domEvents.drag(".node .drag-handle", function (dx, dy, ev, handle) {
var outX = ev.clientX < 0 || ev.clientX > window.innerWidth;
var outY = ev.clientY < 0 || ev.clientY > window.innerHeight;
var el = handle.parentNode;
var sdx = _this.adaptToScale(dx);
var sdy = _this.adaptToScale(dy);
var lastDragDx = (startX_1 + sdx) - newX_1;
var lastDragDy = (startY_1 + sdy) - newY_1;
var nodeEl = handle.parentNode;
var sdx, sdy;
var boundary = _this.getBoundaryZonesXYAxes(ev.clientX, ev.clientY);
// if a workflow boundary has been hit, then call function which calls the interval
if (boundary.x || boundary.y) {
_this.setDragBoundaryIntervalIfNecessary(nodeEl, { x: boundary.x, y: boundary.y }, { startX: startX_1, startY: startY_1, inputEdges: inputEdges_1, outputEdges: outputEdges_1 });
}
// returns the delta x and y - change in node position - based on mouse position and
// boundary offsets (if necessary)
var scaledDeltas = _this.getScaledDeltaXYForDrag(boundary, ev, startX_1, startY_1, dx, dy);
sdx = scaledDeltas.x;
sdy = scaledDeltas.y;
newX_1 = startX_1 + sdx;
newY_1 = startY_1 + sdy;
// console.log("Mouse x: %d", ev.clientX);
// console.log("Mouse y: %d", ev.clientY);
// console.log("X out of bounds: %s", outX.toString());
// console.log("Y out of bounds: %s", outY.toString());
// this.ifDraggingMouseCloseToEdge(el, { x: ev.clientX, y: ev.clientY }, lastDragDx, lastDragDy);
el.transform.baseVal.getItem(0).setTranslate(newX_1, newY_1);
// console.log("Dom Events Drag dx: %d", dx);
// console.log("Dom Events Drag newX: %d", newX);
// console.log("Dom Events Drag matrix.e: %d", el.transform.baseVal.getItem(0).matrix.e);
inputEdges_1.forEach(function (p, el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(p[0], p[1], p[6] + sdx, p[7] + sdy));
});
outputEdges_1.forEach(function (p, el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(p[0] + sdx, p[1] + sdy, p[6], p[7]));
});
nodeEl.transform.baseVal.getItem(0).setTranslate(newX_1, newY_1);
_this.setInputAndOutputEdges(inputEdges_1, outputEdges_1, sdx, sdy);
}, function (ev, handle, root) {

@@ -397,2 +448,3 @@ var el = handle.parentNode;

outputEdges_1 = new Map();
_this.workflowBoundingClientRect = _this.svgRoot.getBoundingClientRect();
Array.from(root.querySelectorAll(".edge[data-destination-node='" + el.getAttribute("data-id") + "'] .sub-edge"))

@@ -407,9 +459,13 @@ .forEach(function (el) {

}, function (ev, target) {
if (_this.edgeInterval) {
clearInterval(_this.edgeInterval);
_this.edgeInterval = null;
if (_this.dragBoundaryInterval.interval) {
clearInterval(_this.dragBoundaryInterval.interval);
_this.dragBoundaryInterval.x = _this.dragBoundaryInterval.y = false;
_this.dragBoundaryInterval.interval = null;
}
_this.dragBoundaryInterval.xOffset = _this.dragBoundaryInterval.yOffset = 0;
var parentNode = Workflow.findParentNode(target);
var model = _this.model.findById(parentNode.getAttribute("data-connection-id"));
_this.setModelPosition(model, newX_1, newY_1);
if (model) {
_this.setModelPosition(model, newX_1, newY_1);
}
inputEdges_1 = undefined;

@@ -467,2 +523,154 @@ outputEdges_1 = undefined;

};
/**
* Sets the interval for dragging within a boundary zone if a new
* boundary zone has been hit. The interval function translates the workflow,
* the dragging node, and the edges attached to that node.
* @param el
* @param boundary
* @param pathInfo
* @param ghostIO
*/
Workflow.prototype.setDragBoundaryIntervalIfNecessary = function (el, boundary, pathInfo, ghostIO) {
var _this = this;
// If boundary areas overlap or if boundary areas take up half - or more - of the svg, resize dragBoundary
while (this.workflowBoundingClientRect.right - this.dragBoundary <= this.workflowBoundingClientRect.left + this.dragBoundary ||
this.workflowBoundingClientRect.right <= this.workflowBoundingClientRect.left + (this.dragBoundary * 4)) {
this.dragBoundary = this.dragBoundary / 2;
}
var checkIfLeftBoundary = boundary.x === -1;
var checkIfRightBoundary = boundary.x === 1;
var checkIfTopBoundary = boundary.y === -1;
var checkIfBottomBoundary = boundary.y === 1;
if (boundary.x || boundary.y) {
// If mouse has hit a boundary but 'this.dragBoundaryInterval' has not registered it yet,
// or if both are registered - which happens in corner case - but mouse has been moved to
// hit only one boundary afterwards
if (!this.dragBoundaryInterval.x && boundary.x ||
!this.dragBoundaryInterval.y && boundary.y ||
(this.dragBoundaryInterval.x && this.dragBoundaryInterval.y && !(boundary.x && boundary.y))) {
this.dragBoundaryInterval.x = boundary.x !== 0;
this.dragBoundaryInterval.y = boundary.y !== 0;
var workflowMatrix_1 = this.workflow.transform.baseVal.getItem(0).matrix;
var mx_1 = el.transform.baseVal.getItem(0).matrix;
// Create new interval every time mouse hits new edge
clearInterval(this.dragBoundaryInterval.interval);
this.dragBoundaryInterval.interval = setInterval(function () {
var moveX = checkIfRightBoundary ? _this.dragBoundaryTranslation : checkIfLeftBoundary ? -_this.dragBoundaryTranslation : 0;
var moveY = checkIfBottomBoundary ? _this.dragBoundaryTranslation : checkIfTopBoundary ? -_this.dragBoundaryTranslation : 0;
// Change matrix e and f values - these represent x and y translate, respectively -
// by 'this.dragBoundaryTranslation' every time this function is called. This translates the matrix
// when the mouse down held on an edge.
workflowMatrix_1.e -= moveX;
workflowMatrix_1.f -= moveY;
_this.dragBoundaryInterval.xOffset += _this.adaptToScale(moveX);
_this.dragBoundaryInterval.yOffset += _this.adaptToScale(moveY);
// Translates the node by 'this.dragBoundaryTranslation' every time this interval function is called.
mx_1.e += _this.adaptToScale(moveX);
mx_1.f += _this.adaptToScale(moveY);
// If node has edges - i.e. if it is not a ghost node
if (pathInfo) {
// Sets the paths correctly for the input edges and the output edges where necessary
_this.setInputAndOutputEdges(pathInfo.inputEdges, pathInfo.outputEdges, mx_1.e - pathInfo.startX, mx_1.f - pathInfo.startY);
}
else if (ghostIO) {
Array.from(ghostIO.edge.children).forEach(function (el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(ghostIO.originX, ghostIO.originY, mx_1.e, mx_1.f, ghostIO.edgeDirection));
});
}
}, 1000 / 60);
}
}
};
/**
* Check all possible workflow boundaries to see if (x,y) is on edge(s)
* -1 / 1 values are left / right and top / bottom depending on the axis,
* and 0 means it has not hit a boundary on that axis
*/
Workflow.prototype.getBoundaryZonesXYAxes = function (x, y) {
var isLeftBoundary = x < this.workflowBoundingClientRect.left + this.dragBoundary;
var isRightBoundary = x > this.workflowBoundingClientRect.right - this.dragBoundary;
var isTopBoundary = y < this.workflowBoundingClientRect.top + this.dragBoundary;
var isBottomBoundary = y > this.workflowBoundingClientRect.bottom - this.dragBoundary;
// if cursor is not on a boundary, then clear interval
if (!isLeftBoundary && !isRightBoundary &&
!isTopBoundary && !isBottomBoundary) {
if (this.dragBoundaryInterval.interval) {
clearInterval(this.dragBoundaryInterval.interval);
this.dragBoundaryInterval.x = this.dragBoundaryInterval.y = false;
this.dragBoundaryInterval.interval = null;
}
}
// return -1 if (x,y) is on left / top edge or outside the window on the left / top side,
// return 1 if opposite, and 0 if cursor is in the main part of the canvas (standard), for each axis
return {
x: isLeftBoundary ? -1 : isRightBoundary ? 1 : 0,
y: isTopBoundary ? -1 : isBottomBoundary ? 1 : 0
};
};
/**
* Calculates the change in x and y for drag, taking into account the starting x and y,
* the cursor position, the boundary offsets, and the current scale coefficient.
* @param boundary
* @param ev
* @param startX
* @param startY
* @param dx
* @param dy
* @returns {{x: any, y: any}}
*/
Workflow.prototype.getScaledDeltaXYForDrag = function (boundary, ev, startX, startY, dx, dy) {
var edgeIntervalOn = this.dragBoundaryInterval.interval !== null;
var sdx, sdy;
if (boundary.x !== 0 || boundary.y !== 0) {
if (boundary.x !== 0) {
var edgeX = this.transformScreenCTMtoCanvas(boundary.x === 1 ?
this.workflowBoundingClientRect.right - this.dragBoundary :
this.workflowBoundingClientRect.left + this.dragBoundary, 0).x; // CHANGE HERE
sdx = edgeX - startX;
}
else {
sdx = this.adaptToScale(dx) + this.dragBoundaryInterval.xOffset;
}
if (boundary.y !== 0) {
var edgeY = this.transformScreenCTMtoCanvas(0, boundary.y === 1 ?
this.workflowBoundingClientRect.bottom - this.dragBoundary :
this.workflowBoundingClientRect.top + this.dragBoundary).y; // CHANGE HERE
sdy = edgeY - startY;
}
else {
sdy = this.adaptToScale(dy) + this.dragBoundaryInterval.yOffset;
}
}
else if (edgeIntervalOn) {
var mouseCoords = this.transformScreenCTMtoCanvas(ev.clientX, ev.clientY);
sdx = mouseCoords.x - startX;
sdy = mouseCoords.y - startY;
this.dragBoundaryInterval.xOffset = sdx - this.adaptToScale(dx);
this.dragBoundaryInterval.yOffset = sdy - this.adaptToScale(dy);
}
else {
sdx = this.adaptToScale(dx) + this.dragBoundaryInterval.xOffset;
sdy = this.adaptToScale(dy) + this.dragBoundaryInterval.yOffset;
}
return {
x: sdx,
y: sdy
};
};
/**
* Updates a node's input edges based on the node's output ports' locations,
* and a node's output edges based on the node's input ports' locations
* @param inputEdges
* @param outputEdges
* @param dx
* @param dy
*/
Workflow.prototype.setInputAndOutputEdges = function (inputEdges, outputEdges, dx, dy) {
inputEdges.forEach(function (p, el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(p[0], p[1], p[6] + dx, p[7] + dy));
});
outputEdges.forEach(function (p, el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(p[0] + dx, p[1] + dy, p[6], p[7]));
});
};
Workflow.prototype.highlightEdge = function (el) {

@@ -491,6 +699,5 @@ var sourceNode = el.getAttribute("data-source-node");

};
Workflow.prototype.translateMouseCoords = function (x, y) {
var svg = this.paper.node;
var wf = svg.querySelector(".workflow");
var ctm = wf.getScreenCTM();
Workflow.prototype.transformScreenCTMtoCanvas = function (x, y) {
var svg = this.svgRoot;
var ctm = this.workflow.getScreenCTM();
var point = svg.createSVGPoint();

@@ -512,3 +719,3 @@ point.x = x;

}
var coords = _this.translateMouseCoords(ev.clientX, ev.clientY);
var coords = _this.transformScreenCTMtoCanvas(ev.clientX, ev.clientY);
tipEl.setAttribute("x", coords.x);

@@ -526,3 +733,3 @@ tipEl.setAttribute("y", coords.y - 16);

var destLabel = destNode === destPort ? destNode : destNode + " (" + destPort + ")";
var coords = _this.translateMouseCoords(ev.clientX, ev.clientY);
var coords = _this.transformScreenCTMtoCanvas(ev.clientX, ev.clientY);
var ns = "http://www.w3.org/2000/svg";

@@ -592,3 +799,3 @@ tipEl = document.createElementNS(ns, "text");

var preferredConnectionPorts;
var allConnectionPorts;
var allOppositeConnectionPorts;
var highlightedPort;

@@ -598,14 +805,20 @@ var edgeDirection;

var originNodeCoords;
var portToOriginTransformation;
this.domEvents.drag(".port", function (dx, dy, ev, target) {
// Gather the necessary positions that we need in order to draw a path
var ctm = target.getScreenCTM();
var coords = _this.translateMouseCoords(ev.clientX, ev.clientY);
var origin = _this.translateMouseCoords(ctm.e, ctm.f);
var coords = _this.transformScreenCTMtoCanvas(ev.clientX, ev.clientY);
var origin = _this.transformScreenCTMtoCanvas(ctm.e, ctm.f);
var nodeToMouseDistance = geometry_1.Geometry.distance(originNodeCoords.x, originNodeCoords.y, coords.x, coords.y);
var boundary = _this.getBoundaryZonesXYAxes(ev.clientX, ev.clientY);
if (boundary.x || boundary.y) {
_this.setDragBoundaryIntervalIfNecessary(ghostIONode, { x: boundary.x, y: boundary.y }, null, { edge: edge, originX: origin.x, originY: origin.y, edgeDirection: edgeDirection });
}
var scaledDeltas = _this.getScaledDeltaXYForDrag(boundary, ev, origin.x, origin.y, dx, dy);
// Draw a path from the origin port to the cursor
Array.from(edge.children).forEach(function (el) {
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(origin.x, origin.y, coords.x, coords.y, edgeDirection));
el.setAttribute("d", io_port_1.IOPort.makeConnectionPath(origin.x, origin.y, origin.x + scaledDeltas.x, origin.y + scaledDeltas.y, edgeDirection));
});
var sorted = allConnectionPorts.map(function (el) {
var ctm = el.wfCTM;
var sorted = allOppositeConnectionPorts.map(function (el) {
var ctm = portToOriginTransformation.get(el);
el.distance = geometry_1.Geometry.distance(coords.x, coords.y, ctm.e, ctm.f);

@@ -635,3 +848,4 @@ return el;

// Otherwise, we might create an input or an ooutput node
ghostIONode.transform.baseVal.getItem(0).setTranslate(coords.x, coords.y);
// ghostIONode.transform.baseVal.getItem(0).setTranslate(coords.x, coords.y);
ghostIONode.transform.baseVal.getItem(0).setTranslate(origin.x + scaledDeltas.x, origin.y + scaledDeltas.y);
}

@@ -642,5 +856,7 @@ else {

}, function (ev, origin, root) {
portToOriginTransformation = new WeakMap();
_this.workflowBoundingClientRect = _this.svgRoot.getBoundingClientRect();
var originNode = Workflow.findParentNode(origin);
var originNodeCTM = originNode.getScreenCTM();
originNodeCoords = _this.translateMouseCoords(originNodeCTM.e, originNodeCTM.f);
originNodeCoords = _this.transformScreenCTMtoCanvas(originNodeCTM.e, originNodeCTM.f);
var isInputPort = origin.classList.contains("input-port");

@@ -657,12 +873,11 @@ ghostIONode = graph_node_1.GraphNode.createGhostIO();

var targetConnectionId = origin.getAttribute("data-connection-id");
// Have a set of all ports of the opposite type, they are all possible destinations
allConnectionPorts = Array.from(_this.workflow.querySelectorAll(".port." + (isInputPort ? "output-port" : "input-port"))).filter(function (el) {
// Except the same node that we are dragging from
return Workflow.findParentNode(el) !== originNode;
}).map(function (el) {
// Have a set of all ports of the opposite type, they are all possible destinations.
// Except the same node that we are dragging from.
allOppositeConnectionPorts = Array.from(_this.workflow.querySelectorAll(".port." + (isInputPort ? "output-port" : "input-port"))).filter(function (el) { return Workflow.findParentNode(el) !== originNode; });
allOppositeConnectionPorts.forEach(function (el) {
// Find the position of the port relative to the canvas origin
el.wfCTM = geometry_1.Geometry.getTransformToElement(el, _this.workflow);
return el;
portToOriginTransformation.set(el, geometry_1.Geometry.getTransformToElement(el, _this.workflow));
});
// Get all valid connection destinations
// Get all valid and visible connection destinations
// Find them in the dom and mark them as connection candidates
preferredConnectionPorts = (_this.model.gatherValidConnectionPoints(targetConnectionId) || [])

@@ -672,3 +887,3 @@ .filter(function (point) { return point.isVisible; })

var el = _this.workflow.querySelector(".port[data-connection-id=\"" + p.connectionId + "\"]");
el.wfCTM = geometry_1.Geometry.getTransformToElement(el, _this.workflow);
portToOriginTransformation.set(el, geometry_1.Geometry.getTransformToElement(el, _this.workflow));
el.classList.add("connection-suggestion");

@@ -686,2 +901,8 @@ return el;

}, function (ev, origin) {
if (_this.dragBoundaryInterval.interval) {
clearInterval(_this.dragBoundaryInterval.interval);
_this.dragBoundaryInterval.x = _this.dragBoundaryInterval.y = false;
_this.dragBoundaryInterval.interval = null;
}
_this.dragBoundaryInterval.xOffset = _this.dragBoundaryInterval.yOffset = 0;
/**

@@ -734,7 +955,19 @@ * If a port is highlighted, that means that we are supposed to snap the connection to that port

: _this.model.createOutputFromPort(portID));
// Check to see if cursor is on boundary (or boundaries)
var boundary = _this.getBoundaryZonesXYAxes(ev.clientX, ev.clientY);
var mouseCoords = _this.transformScreenCTMtoCanvas(ev.clientX, ev.clientY);
var newX = mouseCoords.x;
var newY = mouseCoords.y;
if (boundary.x) {
newX = _this.transformScreenCTMtoCanvas(boundary.x === -1 ? _this.workflowBoundingClientRect.left + _this.dragBoundary :
_this.workflowBoundingClientRect.right - _this.dragBoundary, 0).x;
}
if (boundary.y) {
newY = _this.transformScreenCTMtoCanvas(0, boundary.y === -1 ? _this.workflowBoundingClientRect.top + _this.dragBoundary :
_this.workflowBoundingClientRect.bottom - _this.dragBoundary).y;
}
// Translate mouse coordinates to the canvas coordinates,
// make a template for the graph node, create an element out of that,
// and add that element to the dom
var mouseCoords = _this.translateMouseCoords(ev.clientX, ev.clientY);
var tpl = graph_node_1.GraphNode.makeTemplate(mouseCoords.x, mouseCoords.y, newIO);
var tpl = graph_node_1.GraphNode.makeTemplate(newX, newY, newIO);
var el = template_parser_1.TemplateParser.parse(tpl);

@@ -746,3 +979,3 @@ _this.workflow.appendChild(el);

var edge_2 = edge_1.Edge.spawnBetweenConnectionIDs(_this.workflow, portID, newIO.connectionId);
// This edge still gas no events bound to it, so fix that
// This edge still has no events bound to it, so fix that
_this.attachEdgeHoverBehavior(edge_2);

@@ -764,5 +997,6 @@ // Re-scale the workflow so the label gets upscaled or downscaled properly

ghostIONode = undefined;
edgeDirection = undefined;
originNodeCoords = undefined;
edgeDirection = undefined;
preferredConnectionPorts = undefined;
portToOriginTransformation = undefined;
});

@@ -830,2 +1064,5 @@ };

};
Workflow.prototype.resetTransform = function () {
this.workflow.setAttribute("transform", "matrix(1,0,0,1,0,0)");
};
return Workflow;

@@ -832,0 +1069,0 @@ }());

@@ -10,25 +10,29 @@ {

"description": "A library for generating an interactive SVG visualization of CWL workflows",
"version": "0.0.30",
"version": "0.0.31",
"scripts": {
"webpack:watch": "node_modules/.bin/webpack --watch"
},
"dependencies": {
"core-js": "^2.4.1",
"cwlts": "^1.12.3",
"snapsvg-cjs": "0.0.4"
"cwlts": "^1.12.18",
"phantom": "^4.0.2"
},
"peerDependencies": {
"cwlts": "^1.12.3"
"cwlts": "^1.12.18"
},
"devDependencies": {
"@types/core-js": "0.9.35",
"@types/snapsvg": "0.4.27",
"css-loader": "^0.26.1",
"@types/core-js": "0.9.41",
"@types/node": "^6.0.69",
"@types/phantom": "^3.2.1",
"css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^2.1.0",
"json-loader": "0.5.4",
"node-sass": "^4.5.0",
"sass-loader": "^5.0.1",
"source-map-loader": "^0.1.6",
"style-loader": "^0.13.1",
"systemjs": "^0.20.2",
"ts-loader": "2.0.0",
"node-sass": "^4.5.2",
"sass-loader": "^6.0.3",
"source-map-loader": "^0.2.1",
"style-loader": "^0.16.1",
"ts-loader": "2.0.3",
"typescript": "^2.1.6",
"webpack": "^2.2.1"
"webpack": "^2.4.1"
}
}

@@ -5,7 +5,8 @@ export declare class DomEvents {

constructor(root: HTMLElement);
on(event: string, selector: string, handler: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any, root?: any): () => void;
on(event: string, selector: string, handler: (UIEvent, target?: Element, root?: Element) => any, root?: any): any;
on(event: string, handler: (UIEvent, target?: Element, root?: Element) => any, root?: any): any;
keyup(): void;
drag(selector: any, move: (dx: number, dy: number, UIEvent, target?: HTMLElement, root?: HTMLElement) => any, start: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any, end: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any): void;
drag(selector: any, move: (dx: number, dy: number, UIEvent, target?: Element, root?: Element) => any, start: (UIEvent, target?: Element, root?: Element) => any, end: (UIEvent, target?: Element, root?: Element) => any): void;
hover(element: any, hover?: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any, enter?: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any, leave?: (UIEvent, target?: HTMLElement, root?: HTMLElement) => any): void;
detachAll(): void;
}

@@ -8,9 +8,13 @@ "use strict";

}
DomEvents.prototype.on = function (event, selector, handler, root) {
DomEvents.prototype.on = function () {
var _this = this;
if (typeof selector === "function") {
root = handler;
handler = selector;
selector = undefined;
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var event = args.shift();
var selector = typeof args[0] === "string" ? args.shift() : undefined;
var handler = typeof args[0] === "function" ? args.shift() : function () {
};
var root = args.shift();
var eventHolder = root || this.root;

@@ -17,0 +21,0 @@ if (!this.handlers.has(eventHolder)) {

export declare class Geometry {
static isColliding(a: Snap.Element, b: Snap.Element): void;
static distance(x1: any, y1: any, x2: any, y2: any): number;
static getTransformToElement(from: any, to: any): any;
}

@@ -6,6 +6,2 @@ "use strict";

}
Geometry.isColliding = function (a, b) {
var _a = a.getBBox(), aX = _a.x, aY = _a.y, aWidth = _a.width, aHeight = _a.height;
var _b = b.getBBox(), bX = _b.x, bY = _b.y, bWidth = _b.width, bHeight = _b.height;
};
Geometry.distance = function (x1, y1, x2, y2) {

@@ -12,0 +8,0 @@ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc