Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2276 Allow click on a port to cause an action #2277

Merged
merged 5 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,13 @@ export default class CanvasUtils {
return null;
}

// Returns the distance from the start point to finsih point of the link line.
// Returns true if point 1 is inside a circle of the specified radius whose
// center is point 2.
static isInside(point1, point2, radius) {
return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2)) < radius;
}

// Returns the distance from the start point to finish point of the link line.
static getLinkDistance(link) {
const x = link.x2 - link.x1;
const y = link.y2 - link.y1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export const PORT_DISPLAY_JSX = "jsx";
export const FLOW_IN = "in";
export const FLOW_OUT = "out";

export const SINGLE_CLICK = "SINGLE_CLICK";
export const SINGLE_CLICK_CONTEXTMENU = "SINGLE_CLICK_CONTEXTMENU";
export const DOUBLE_CLICK = "DOUBLE_CLICK";

// Variations of association links - when enableAssocLinkType === ASSOC_RIGHT_SIDE_CURVE
export const ASSOC_VAR_CURVE_RIGHT = "curveRight";
export const ASSOC_VAR_CURVE_LEFT = "curveLeft";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { ASSOC_RIGHT_SIDE_CURVE, ASSOCIATION_LINK, NODE_LINK, COMMENT_LINK,
WYSIWYG, CAUSE_KEYBOARD, CAUSE_MOUSE,
FLOW_IN, FLOW_OUT,
PORT_WIDTH_DEFAULT, PORT_HEIGHT_DEFAULT,
SINGLE_CLICK, SINGLE_CLICK_CONTEXTMENU, DOUBLE_CLICK,
CANVAS_FOCUS
} from "./constants/canvas-constants";
import SUPERNODE_ICON from "../../assets/images/supernode.svg";
Expand Down Expand Up @@ -1347,15 +1348,15 @@ export default class SVGCanvasRenderer {
this.logger.log("Canvas - click-zoom");

this.canvasController.clickActionHandler({
clickType: d3Event.type === "contextmenu" ? "SINGLE_CLICK_CONTEXTMENU" : "SINGLE_CLICK",
clickType: d3Event.type === "contextmenu" ? SINGLE_CLICK_CONTEXTMENU : SINGLE_CLICK,
objectType: "canvas",
selectedObjectIds: this.activePipeline.getSelectedObjectIds()
});
})
.on("dblclick.zoom", () => {
this.logger.log("Zoom - double click");
this.canvasController.clickActionHandler({
clickType: "DOUBLE_CLICK",
clickType: DOUBLE_CLICK,
objectType: "canvas",
selectedObjectIds: this.activePipeline.getSelectedObjectIds() });
})
Expand Down Expand Up @@ -2276,7 +2277,7 @@ export default class SVGCanvasRenderer {
this.logger.log("Node Group - double click");
CanvasUtils.stopPropagationAndPreventDefault(d3Event);
this.canvasController.clickActionHandler({
clickType: "DOUBLE_CLICK",
clickType: DOUBLE_CLICK,
objectType: "node",
id: d.id,
selectedObjectIds: this.activePipeline.getSelectedObjectIds(),
Expand Down Expand Up @@ -2579,7 +2580,7 @@ export default class SVGCanvasRenderer {
// TODO - Issue 2465 - Find out why this problem occurs.
if (objectType === "node" || objectType === "link") {
this.canvasController.clickActionHandler({
clickType: d3EventType === "contextmenu" || this.ellipsisClicked ? "SINGLE_CLICK_CONTEXTMENU" : "SINGLE_CLICK",
clickType: d3EventType === "contextmenu" || this.ellipsisClicked ? SINGLE_CLICK_CONTEXTMENU : SINGLE_CLICK,
objectType: objectType,
id: d.id,
selectedObjectIds: this.activePipeline.getSelectedObjectIds(),
Expand Down Expand Up @@ -4189,7 +4190,7 @@ export default class SVGCanvasRenderer {
this.displayCommentTextArea(d, d3Event.currentTarget);

this.canvasController.clickActionHandler({
clickType: "DOUBLE_CLICK",
clickType: DOUBLE_CLICK,
objectType: "comment",
id: d.id,
selectedObjectIds: this.activePipeline.getSelectedObjectIds(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ import { ASSOCIATION_LINK, COMMENT_LINK, NODE_LINK,
LINK_TYPE_CURVE, LINK_TYPE_STRAIGHT, LINK_SELECTION_DETACHABLE,
FLOW_IN, FLOW_OUT,
PORT_DISPLAY_CIRCLE,
LINK_METHOD_PORTS }
from "./constants/canvas-constants.js";
LINK_METHOD_PORTS,
SINGLE_CLICK
} from "./constants/canvas-constants.js";

// This utility files provides a drag handler which manages drag operations to
// create new links either between nodes or from a comment to a node.
Expand Down Expand Up @@ -65,14 +66,14 @@ export default class SVGCanvasUtilsDragNewLink {
dragStartNewLink(d3Event, d) {
if (this.isEventForOutputPort(d3Event)) {
const node = this.getNodeForPort(d3Event);
this.startOutputPortNewLink(d, node);
this.startOutputPortNewLink(d3Event, d, node);

} else if (this.isEventForInputPort(d3Event)) {
const node = this.getNodeForPort(d3Event);
this.startInputPortNewLink(d, node);
this.startInputPortNewLink(d3Event, d, node);

} else if (this.ren.activePipeline.getObjectTypeName(d) === "comment") {
this.startCommentNewLink(d);
this.startCommentNewLink(d3Event, d);
}
}

Expand Down Expand Up @@ -110,7 +111,7 @@ export default class SVGCanvasUtilsDragNewLink {
}

// Initialize this.drawingNewLinkData when dragging a comment port.
startCommentNewLink(comment) {
startCommentNewLink(d3Event, comment) {
const srcObj = this.ren.activePipeline.getComment(comment.id);
this.drawingNewLinkData = {
srcObj: srcObj,
Expand All @@ -119,20 +120,22 @@ export default class SVGCanvasUtilsDragNewLink {
x: comment.x_pos - this.ren.canvasLayout.commentHighlightGap,
y: comment.y_pos - this.ren.canvasLayout.commentHighlightGap
},
mousePos: { x: d3Event.x, y: d3Event.y },
linkArray: []
};
}

// Initialize this.drawingNewLinkData when dragging an input port. This gesture
// is only supported for association link creation.
startInputPortNewLink(port, node) {
startInputPortNewLink(d3Event, port, node) {
if (this.ren.config.enableAssocLinkCreation) {
const srcNode = this.ren.activePipeline.getNode(node.id);
const portIndex = CanvasUtils.getPortIndex(node.inputs, port.id);
this.drawingNewLinkData = {
srcObj: srcNode,
srcPort: port,
action: this.ren.config.enableAssocLinkCreation ? ASSOCIATION_LINK : NODE_LINK,
mousePos: { x: d3Event.x, y: d3Event.y },
startPos: { x: srcNode.x_pos + port.cx, y: srcNode.y_pos + port.cy },
portFlow: FLOW_IN,
portDisplayInfo: this.ren.getPortDisplayInfo(srcNode.layout.inputPortDisplayObjects, portIndex),
Expand All @@ -145,14 +148,15 @@ export default class SVGCanvasUtilsDragNewLink {
}

// Initialize this.drawingNewLinkData when dragging an output port.
startOutputPortNewLink(port, node) {
startOutputPortNewLink(d3Event, port, node) {
const srcNode = this.ren.activePipeline.getNode(node.id);
if (!CanvasUtils.isSrcCardinalityAtMax(port.id, srcNode, this.ren.activePipeline.links)) {
const portIndex = CanvasUtils.getPortIndex(node.outputs, port.id);
this.drawingNewLinkData = {
srcObj: srcNode,
srcPort: port,
action: this.ren.config.enableAssocLinkCreation ? ASSOCIATION_LINK : NODE_LINK,
mousePos: { x: d3Event.x, y: d3Event.y },
startPos: { x: srcNode.x_pos + port.cx, y: srcNode.y_pos + port.cy },
portFlow: FLOW_OUT,
portDisplayInfo: this.ren.getPortDisplayInfo(srcNode.layout.outputPortDisplayObjects, portIndex),
Expand Down Expand Up @@ -348,6 +352,21 @@ export default class SVGCanvasUtilsDragNewLink {
const drawingNewLinkData = this.drawingNewLinkData;
this.drawingNewLinkData = null;

// If the user has not dragged the mouse far enough to create a new link, we
// treat it as a click on the port.
if (this.isClicked(drawingNewLinkData.mousePos, d3Event)) {
this.removeNewLink();
this.ren.canvasController.clickActionHandler({
clickType: SINGLE_CLICK,
objectType: "port",
id: drawingNewLinkData.srcPort.id,
nodeId: drawingNewLinkData.srcObj.id,
selectedObjectIds: this.ren.activePipeline.getSelectedObjectIds(),
pipelineId: this.ren.activePipeline.id
});
return;
}

if (this.ren.config.enableHighlightUnavailableNodes) {
this.ren.unsetUnavailableNodesHighlighting();
}
Expand All @@ -367,6 +386,12 @@ export default class SVGCanvasUtilsDragNewLink {
}
}

// Returns true if the mouse position is inside a circle with a radius of
// 3px centred at the d3Event x and y.
isClicked(mousePos, d3Event) {
return CanvasUtils.isInside(mousePos, { x: d3Event.x, y: d3Event.y }, 3);
}

// Handles the creation of a link when the end of a new link
// being drawn from a source node is dropped on a target node.
createNewLinkFromDragData(d3Event, trgNode, drawingNewLinkData) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ export default class PromptCanvas extends React.Component {
}

clickActionHandler(source) {
// this.addPromptNode();
if (source.objectType === "port" &&
source.clickType === "SINGLE_CLICK") {
this.addPromptNode(source.nodeId, source.id);
}
}

layoutHandler(node) {
Expand All @@ -115,7 +118,7 @@ export default class PromptCanvas extends React.Component {

editActionHandler(data) {
if (data.editType === "app_addPropmpt") {
this.addPromptNode(data.targetObject);
this.addPromptNode(data.targetObject.id);
}
}

Expand All @@ -135,10 +138,10 @@ export default class PromptCanvas extends React.Component {
return defaultMenu;
}

addNodeHandler(nodeTemplate) {
const promptNode = this.canvasController.getNode(this.promptNodeId);
this.canvasController.deleteNode(this.promptNodeId);
this.canvasController.deleteLink("link_to_prompt");
addNodeHandler(srcNodeId, srcPortId, nodeTemplate, promptNodeId) {
const promptNode = this.canvasController.getNode(promptNodeId);
this.canvasController.deleteNode(promptNodeId);
this.canvasController.deleteLink(this.genPromptLinkId(srcNodeId, srcPortId));

const newNode = this.canvasController.createNode({
nodeTemplate: nodeTemplate,
Expand All @@ -149,51 +152,56 @@ export default class PromptCanvas extends React.Component {

const linksToAdd = this.canvasController.createNodeLinks({
type: "nodeLink",
nodes: [{ id: this.sourceNodeId }],
nodes: [{ id: srcNodeId, portId: srcPortId }],
targetNodes: [{ id: newNode.id }]
});

this.canvasController.addLinks(linksToAdd);

}

addPromptNode(sourceNode) {
this.sourceNodeId = sourceNode.id;
addPromptNode(srcNodeId, srcPortId) {
const srcNode = this.canvasController.getNode(srcNodeId);

const template = Template;
template.app_data.prompt_data = {
addNodeCallback: this.addNodeHandler.bind(this)
addNodeCallback: this.addNodeHandler.bind(this, srcNodeId, srcPortId)
};
const newNode = this.canvasController.createNode({
const promptNode = this.canvasController.createNode({
nodeTemplate: template,
offsetX: sourceNode.x_pos + 200, // Position prompt 200px to right of source node
offsetY: sourceNode.y_pos
offsetX: srcNode.x_pos + 200, // Position prompt 200px to right of source node
offsetY: srcNode.y_pos
});

// Make sure prompt doesn't overlap other nodes.
this.adjustNodePosition(newNode, 100);

// Save the ID of the prompt node for removal, later
this.promptNodeId = newNode.id;
this.adjustNodePosition(promptNode);

// Add the prompt node to the canvas with a link
this.canvasController.addNode(newNode);
this.canvasController.addNode(promptNode);
const linksToAdd = this.canvasController.createNodeLinks({
id: "link_to_prompt",
id: this.genPromptLinkId(srcNodeId, srcPortId),
type: "nodeLink",
nodes: [{ id: sourceNode.id }],
targetNodes: [{ id: this.promptNodeId }]
nodes: [{ id: srcNodeId, portId: srcPortId }],
targetNodes: [{ id: promptNode.id }]
});

this.canvasController.addLinks(linksToAdd);
}

adjustNodePosition(node, yInc) {
genPromptLinkId(srcNodeId, srcPortId) {
return "link_to_prompt_" + srcNodeId + "_" + srcPortId;
}

adjustNodePosition(node) {
let overlapNode = true;
while (overlapNode) {
overlapNode = this.canvasController.getNodes().find((n) => n.x_pos === node.x_pos && n.y_pos === node.y_pos);
overlapNode = this.canvasController.getNodes().find((n) =>
node.x_pos >= n.x_pos &&
node.x_pos <= n.x_pos + n.height &&
node.y_pos >= n.y_pos &&
node.y_pos <= n.y_pos + n.width
);
if (overlapNode) {
node.y_pos += yInc;
node.y_pos += overlapNode.height + 20;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"label": "Type",
"image": "images/custom-canvases/flows/palette/icons/type.svg",
"x_pos": 54,
"y_pos": 250,
"y_pos": 331.2,
"description": "Type node."
}
},
Expand Down Expand Up @@ -80,12 +80,12 @@
"comments": [
{
"id": "0b123469-7d21-43a5-ae84-cbc999990033",
"x_pos": 54,
"y_pos": 43.2,
"width": 288,
"height": 158.4,
"x_pos": 36,
"y_pos": 28.8,
"width": 342,
"height": 231,
"class_name": "d3-comment-rect bkg-col-green-20",
"content": "### Prompt Canvas\n\nThis canvas provides a method to add new nodes to the flow with a prompt. To do this:\n1. Hover over the Type node\n2. In the context toolbar, click the \"Add node with prompt\" button\n3. Select a node type from the prompt. ",
"content": "### Prompt Canvas\n\nThis canvas provides a method to add new nodes to the flow with a prompt. To do this either:\n1. Click one of the ports of the Type node\n2. Select a node type from the prompt. \n\nor:\n1. Hover over the Type node \n2. Click the \"Add node with prompt\" button in the context toolbar",
"associated_id_refs": []
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export default class PromptReactNode extends React.Component {
}

onClick(nodeTemplate, evt) {
this.props.nodeData.app_data.prompt_data.addNodeCallback(nodeTemplate);
this.props.nodeData.app_data.prompt_data
.addNodeCallback(nodeTemplate, this.props.nodeData.id);
}

onScroll(evt) {
Expand All @@ -46,7 +47,7 @@ export default class PromptReactNode extends React.Component {
}

return (
<div style={{ height: "100%", width: "100%", overflowY: "scroll", backgroundColor: "white" }}
<div style={{ height: "100%", width: "100%", overflowY: "scroll", padding: "5px", backgroundColor: "white" }}
onScroll={this.onScroll} onWheel={this.onScroll}
>
{ nodeDivs }
Expand Down
Loading