Skip to content

Commit

Permalink
#2033 Support new link line types (#2034)
Browse files Browse the repository at this point in the history
Signed-off-by: CTomlyn <[email protected]>
  • Loading branch information
tomlyn authored Jun 27, 2024
1 parent 830bfe3 commit 3efae17
Show file tree
Hide file tree
Showing 60 changed files with 4,649 additions and 598 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import Toolbar from "../../src/toolbar/toolbar.jsx";
import CanvasBottomPanel from "../../src/common-canvas/cc-bottom-panel.jsx";
import CommonCanvasRightFlyout from "../../src/common-canvas/cc-right-flyout.jsx";
import CommonCanvasStateTag from "../../src/common-canvas/cc-state-tag.jsx";
import { createCommonCanvas } from "../_utils_/common-canvas-utils.js";
import { createCommonCanvas } from "../_utils_/cc-utils.js";
import { expect } from "chai";
import sinon from "sinon";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import CanvasController from "../../src/common-canvas/canvas-controller";
import CommonCanvasTextToolbar from "../../src/common-canvas/cc-text-toolbar.jsx";
import Toolbar from "../../src/toolbar/toolbar.jsx";
import { createIntlCommonCanvasTextToolbar } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvasTextToolbar } from "../_utils_/cc-utils.js";
import { expect } from "chai";

const canvasController = new CanvasController();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import CanvasController from "../../src/common-canvas/canvas-controller";
import CommonCanvasToolbar from "../../src/common-canvas/cc-toolbar.jsx";
import Toolbar from "../../src/toolbar/toolbar.jsx";
import { createIntlCommonCanvasToolbar } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvasToolbar } from "../_utils_/cc-utils.js";
import { expect } from "chai";

const canvasController = new CanvasController();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2024 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import CanvasUtils from "../../src/common-canvas/common-canvas-utils.js";


describe("Test Common Canvas utility functions", () => {
beforeEach(() => {
//
});

it("should get correct directions from getPortDir()", () => {
// Create a dummy node
const node = { width: 70, height: 160 };

// WEST -- These tests should return "w"
let dir = CanvasUtils.getPortDir(0, 1, node);
expect(dir).toEqual("w");
dir = CanvasUtils.getPortDir(0, node.height - 1, node);
expect(dir).toEqual("w");
dir = CanvasUtils.getPortDir(0, (node.height / 2) - 1, node);
expect(dir).toEqual("w");

// EAST -- These tests should return "e"
dir = CanvasUtils.getPortDir(node.width, 1, node);
expect(dir).toEqual("e");
dir = CanvasUtils.getPortDir(node.width, node.height - 1, node);
expect(dir).toEqual("e");
dir = CanvasUtils.getPortDir(node.width, (node.height / 2), node);
expect(dir).toEqual("e");

// NORTH -- These tests should return "n"
dir = CanvasUtils.getPortDir(node.width - 1, 0, node);
expect(dir).toEqual("n");
dir = CanvasUtils.getPortDir(1, 0, node);
expect(dir).toEqual("n");
dir = CanvasUtils.getPortDir((node.width / 2), 0, node);
expect(dir).toEqual("n");

// SOUTH -- These tests should return "s"
dir = CanvasUtils.getPortDir(node.width - 1, node.height, node);
expect(dir).toEqual("s");
dir = CanvasUtils.getPortDir(1, node.height, node);
expect(dir).toEqual("s");
dir = CanvasUtils.getPortDir((node.width / 2), node.height, node);
expect(dir).toEqual("s");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import isEqual from "lodash/isEqual";
import CanvasController from "../../src/common-canvas/canvas-controller";
import { createIntlCommonCanvas } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvas } from "../_utils_/cc-utils.js";
import { expect } from "chai";
import sinon from "sinon";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import isEqual from "lodash/isEqual";
import CanvasController from "../../src/common-canvas/canvas-controller";
import deepFreeze from "deep-freeze";
import { createIntlCommonCanvas } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvas } from "../_utils_/cc-utils.js";
import { expect } from "chai";
import sinon from "sinon";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import React from "react";
import CommonContextMenu from "./../../src/context-menu/common-context-menu";
import { createIntlCommonCanvasRTL } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvasRTL } from "../_utils_/cc-utils.js";
import { expect } from "chai";
import { expect as expectJest } from "@jest/globals";
import sinon from "sinon";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { Provider } from "react-redux";
import NotificationPanel from "./../../src/notification-panel/notification-panel";
import CanvasController from "./../../src/common-canvas/canvas-controller";

import { createIntlCommonCanvasRTL } from "../_utils_/common-canvas-utils.js";
import { createIntlCommonCanvasRTL } from "../_utils_/cc-utils.js";
import { expect } from "chai";
import { expect as expectJest } from "@jest/globals";
import sinon from "sinon";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import deepFreeze from "deep-freeze";
import { expect } from "chai";
import isEqual from "lodash/isEqual";
import { createCommonCanvas } from "../_utils_/common-canvas-utils.js";
import { createCommonCanvas } from "../_utils_/cc-utils.js";

// Imports from harness test resources
import startCanvas from "../test_resources/json/startCanvas.json";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { ASSOCIATION_LINK, ASSOC_STRAIGHT, COMMENT_LINK, NODE_LINK,
LINK_TYPE_STRAIGHT, SUPER_NODE, NORTH, SOUTH, EAST, WEST }
from "../common-canvas/constants/canvas-constants.js";


export default class CanvasUtils {

static getObjectPositions(objects) {
Expand Down Expand Up @@ -310,10 +309,12 @@ export default class CanvasUtils {

var startPointX;
var startPointY;
let dir = NORTH;

if (originToEndX === 0) {
startPointX = originX;
startPointY = (endY < originY) ? topEdge : bottomEdge;
dir = originToEndY > 0 ? NORTH : SOUTH;

} else if (endX > originX) {
const topRightRatio = originTopOffsetY / (originX - rightEdge);
Expand All @@ -328,10 +329,12 @@ export default class CanvasUtils {
} else if (ratioRight > botRightRatio) {
startPointX = originX + (originBottomOffsetY / ratioRight);
startPointY = bottomEdge;
dir = SOUTH;
// East
} else {
startPointX = rightEdge;
startPointY = originY + (originRightOffsetX * ratioRight);
dir = EAST;
}
// End point is to the left of center
} else {
Expand All @@ -347,14 +350,16 @@ export default class CanvasUtils {
} else if (ratioLeft < botLeftRatio) {
startPointX = originX + (originBottomOffsetY / ratioLeft);
startPointY = bottomEdge;
dir = SOUTH;
// West
} else {
startPointX = leftEdge;
startPointY = originY - (originLeftOffsetX * ratioLeft);
dir = WEST;
}
}

return { x: startPointX, y: startPointY, originX, originY };
return { x: startPointX, y: startPointY, originX, originY, dir };
}

// Returns a direction NORTH, SOUTH, EAST or WEST which is the direction
Expand Down Expand Up @@ -407,6 +412,52 @@ export default class CanvasUtils {
return dir;
}

// Returns a direction (n, s, e or w) of a port at the
// x, y position on a node. This is the direction that
// would be taken by an outgoing link from a source node
// or an incoming link to a target node.
static getPortDir(x, y, node) {
const halfNodeWidth = (node.width / 2);
const halfNodeHeight = (node.height / 2);
const xFromCenter = x - halfNodeWidth;
const yFromCenter = y - halfNodeHeight;
// In the center horizontally
if (xFromCenter === 0) {
if (yFromCenter > 0) {
return SOUTH;
}
return NORTH;

// To the right
} else if (xFromCenter > 0) {
const angleToRight = Math.atan(yFromCenter / xFromCenter);
const angleToBottomRight = Math.atan(halfNodeHeight / halfNodeWidth);
const angleTopRight = -angleToBottomRight;
if (angleToRight === 0) {
return EAST;
} else if (angleToRight < angleTopRight) {
return NORTH;
} else if (angleToRight > angleToBottomRight) {
return SOUTH;
}
return EAST;

}
// To the left
const angleToLeft = Math.atan(yFromCenter / xFromCenter);
const angleToTopLeft = Math.atan(halfNodeHeight / halfNodeWidth);
const angleToBottomLeft = -angleToTopLeft;
if (angleToLeft === 0) {
return WEST;
} else if (angleToLeft > angleToTopLeft) {
return NORTH;
} else if (angleToLeft < angleToBottomLeft) {
return SOUTH;
}
return WEST;
}


// Returns true if the line described by x1, y1, x2, y2 either intersects or
// is fully inside the rectangle described by rx1, ry1, rx2, ry2.
static lineIntersectRectangle(x1, y1, x2, y2, rx1, ry1, rx2, ry2) {
Expand Down Expand Up @@ -445,20 +496,36 @@ export default class CanvasUtils {
return null;
}

// Return the center point of a quadratic bezier curve where p0 is the
// start point, p1 is the control point and p2 is the end point.
// This works for either the x or y coordinate.
static getCenterPointQuadBezier(p0, p1, p2) {
const t = 0.5;
return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2;
}

// Return the center point of a cubic bezier curve where p0 is the
// start point, p1 and p2 are the control points and p3 is the end point.
// This works for either the x or y coordinate.
static getCenterPointCubicBezier(p0, p1, p2, p3) {
const t = 0.5;
return (1 - t) * (1 - t) * (1 - t) * p0 + 3 * (1 - t) * (1 - t) * t * p1 + 3 * (1 - t) * t * t * p2 + t * t * t * p3;
}

// Returns true if a link of type `type` can be created between the two
// node/port combinations provided given the set of current links provided.
static isConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links, type) {
static isConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links, type, selfRefLinkAllowed) {
if (type === ASSOCIATION_LINK) {
return this.isAssocConnectionAllowed(srcNode, trgNode, links);
}
return this.isDataConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links);
return this.isDataConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed);
}

// Returns true if a node-node data link can be created between the two
// node/port combinations provided on a canvas where detached links are
// allowed, given the set of current link provided.
static isConnectionAllowedWithDetachedLinks(srcNodePortId, trgNodePortId, srcNode, trgNode, links) {
if (srcNode && trgNode && srcNode.id === trgNode.id) { // Cannot connect to ourselves, currently.
static isConnectionAllowedWithDetachedLinks(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed) {
if (srcNode && trgNode && srcNode.id === trgNode.id && !selfRefLinkAllowed) { // Cannot connect to ourselves.
return false;
}

Expand Down Expand Up @@ -509,9 +576,9 @@ export default class CanvasUtils {

// Returns true if an existing link to the target node and port can be
// replaced with a new link from the srcNode to the trgNode and trgPortId.
static isDataLinkReplacementAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links) {
static isDataLinkReplacementAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed) {

if (!this.isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links)) {
if (!this.isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed)) {
return false;
}

Expand All @@ -530,9 +597,9 @@ export default class CanvasUtils {
// Returns true if a regular node-node data link can be created between the
// two node/port combinations provided, given the current set of links
// passed in.
static isDataConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links) {
static isDataConnectionAllowed(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed) {

if (!this.isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links)) {
if (!this.isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed)) {
return false;
}

Expand All @@ -546,13 +613,13 @@ export default class CanvasUtils {
// Returns true if a regular node-node data link can be created between the
// two node/port combinations provided, without checking on cardinalities of
// the source or target nodes.
static isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links) {
static isDataConnectionAllowedNoCardinality(srcNodePortId, trgNodePortId, srcNode, trgNode, links, selfRefLinkAllowed) {

if (!srcNode || !trgNode) { // Source or target are not valid.
return false;
}

if (srcNode.id === trgNode.id) { // Cannot connect to ourselves, currently.
if (srcNode.id === trgNode.id && !selfRefLinkAllowed) { // Cannot connect to ourselves.
return false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ export const INTERACTION_CARBON = "Carbon";
export const LINK_TYPE_CURVE = "Curve";
export const LINK_TYPE_ELBOW = "Elbow";
export const LINK_TYPE_STRAIGHT = "Straight";
export const LINK_TYPE_PARALLAX = "Parallax";

// Values for enableLinkDirection config parameter
export const LINK_DIR_FREEFORM = "Freeform";
export const LINK_DIR_LEFT_RIGHT = "LeftRight";
export const LINK_DIR_RIGHT_LEFT = "RightLeft";
export const LINK_DIR_TOP_BOTTOM = "TopBottom";
export const LINK_DIR_BOTTOM_TOP = "BottomTop";

Expand Down
Loading

0 comments on commit 3efae17

Please sign in to comment.