mirror of
https://github.com/rio-labs/rio.git
synced 2026-01-13 16:49:34 -06:00
141 lines
4.7 KiB
TypeScript
141 lines
4.7 KiB
TypeScript
import { componentsByElement, componentsById } from "../../componentManagement";
|
|
import { ComponentId } from "../../dataModels";
|
|
import { GraphEditorComponent } from "./graphEditor";
|
|
import { NodeInputComponent } from "../nodeInput";
|
|
import { NodeOutputComponent } from "../nodeOutput";
|
|
import {
|
|
getNodeFromPort,
|
|
getPortFromCircle,
|
|
getPortViewportPosition,
|
|
makeConnectionElement,
|
|
updateConnectionFromCoordinates,
|
|
updateConnectionFromObject,
|
|
} from "./utils";
|
|
import { AugmentedConnectionState } from "./graphStore";
|
|
|
|
/// The user is currently dragging a connection from a port. This means the
|
|
/// connection is already connected to one port, with the other end dangling at
|
|
/// the pointer.
|
|
export class DraggingConnectionStrategy {
|
|
fixedNodeId: ComponentId;
|
|
fixedPortId: ComponentId;
|
|
element: SVGPathElement;
|
|
|
|
constructor(
|
|
fixedNodeId: ComponentId,
|
|
fixedPortId: ComponentId,
|
|
element: SVGPathElement
|
|
) {
|
|
this.fixedNodeId = fixedNodeId;
|
|
this.fixedPortId = fixedPortId;
|
|
this.element = element;
|
|
}
|
|
|
|
onDragMove(ge: GraphEditorComponent, event: PointerEvent): void {
|
|
// Update the latent connection
|
|
const fixedPortComponent = componentsById[this.fixedPortId] as
|
|
| NodeInputComponent
|
|
| NodeOutputComponent
|
|
| undefined;
|
|
|
|
// The element could've been deleted in the meantime
|
|
if (fixedPortComponent === undefined) {
|
|
return;
|
|
}
|
|
|
|
let [x1, y1] = getPortViewportPosition(fixedPortComponent);
|
|
let [x2, y2] = [event.clientX, event.clientY];
|
|
|
|
// Convert the coordinates to the editor's coordinate system
|
|
const editorRect = ge.element.getBoundingClientRect();
|
|
|
|
x1 = x1 - editorRect.left;
|
|
y1 = y1 - editorRect.top;
|
|
x2 = x2 - editorRect.left;
|
|
y2 = y2 - editorRect.top;
|
|
|
|
// If dragging from an input port, flip the coordinates
|
|
if (fixedPortComponent instanceof NodeInputComponent) {
|
|
[x1, y1, x2, y2] = [x2, y2, x1, y1];
|
|
}
|
|
|
|
// Update the SVG path
|
|
updateConnectionFromCoordinates(this.element, x1, y1, x2, y2);
|
|
}
|
|
|
|
onDragEnd(ge: GraphEditorComponent, event: PointerEvent): void {
|
|
// Remove the SVG path
|
|
this.element.remove();
|
|
|
|
// Was the pointer released on a port?
|
|
let dropElement = event.target as HTMLElement;
|
|
|
|
if (!dropElement.classList.contains("rio-graph-editor-port-circle")) {
|
|
return;
|
|
}
|
|
|
|
let dropPortComponent = getPortFromCircle(dropElement);
|
|
|
|
// Get the fixed port
|
|
let fixedPortComponent = componentsById[this.fixedPortId] as
|
|
| NodeInputComponent
|
|
| NodeOutputComponent
|
|
| undefined;
|
|
|
|
// The element could've been deleted in the meantime
|
|
if (fixedPortComponent === undefined) {
|
|
return;
|
|
}
|
|
|
|
// Each connection must connect exactly one input and one output
|
|
let fromPortComponent: NodeOutputComponent;
|
|
let toPortComponent: NodeInputComponent;
|
|
|
|
if (fixedPortComponent instanceof NodeOutputComponent) {
|
|
if (dropPortComponent instanceof NodeOutputComponent) {
|
|
return;
|
|
}
|
|
|
|
fromPortComponent = fixedPortComponent;
|
|
toPortComponent = dropPortComponent as NodeInputComponent;
|
|
} else {
|
|
if (dropPortComponent instanceof NodeInputComponent) {
|
|
return;
|
|
}
|
|
|
|
fromPortComponent = dropPortComponent as NodeOutputComponent;
|
|
toPortComponent = fixedPortComponent;
|
|
}
|
|
|
|
// Prepare all data needed to make the connection
|
|
const fromNodeComponent = getNodeFromPort(fromPortComponent);
|
|
const toNodeComponent = getNodeFromPort(toPortComponent);
|
|
|
|
// Input nodes can only have one connection at a time. If the target
|
|
// port already has a connection, stop here.
|
|
let existingConnections = ge.graphStore.getConnectionsForPort(
|
|
toNodeComponent.id,
|
|
toPortComponent.id
|
|
);
|
|
|
|
if (existingConnections.length > 0) {
|
|
return;
|
|
}
|
|
|
|
// Create a real connection between the two ports
|
|
let connectionElement = makeConnectionElement();
|
|
ge.svgChild.appendChild(connectionElement);
|
|
|
|
let augmentedConn: AugmentedConnectionState = {
|
|
fromNode: fromNodeComponent.id,
|
|
fromPort: fromPortComponent.id,
|
|
toNode: toNodeComponent.id,
|
|
toPort: toPortComponent.id,
|
|
element: connectionElement,
|
|
};
|
|
|
|
ge.graphStore.addConnection(augmentedConn);
|
|
updateConnectionFromObject(ge, augmentedConn);
|
|
}
|
|
}
|