Drag out links to disconnect nodes (#894)

* Disconnecting Links

* Fix bug if nodeid is 0
This commit is contained in:
0HyperCube 2022-12-21 19:19:24 +00:00 committed by Keavon Chambers
parent 81f365c999
commit 49b1770c34
4 changed files with 58 additions and 3 deletions

View File

@ -25,6 +25,10 @@ pub enum NodeGraphMessage {
node_id: NodeId, node_id: NodeId,
}, },
DeleteSelectedNodes, DeleteSelectedNodes,
DisconnectNodes {
node_id: NodeId,
input_index: usize,
},
DoubleClickNode { DoubleClickNode {
node: NodeId, node: NodeId,
}, },

View File

@ -392,6 +392,22 @@ impl MessageHandler<NodeGraphMessage, (&mut Document, &InputPreprocessorMessageH
} }
} }
} }
NodeGraphMessage::DisconnectNodes { node_id, input_index } => {
let Some(network) = self.get_active_network_mut(document) else {
warn!("No network");
return;
};
let Some(node) = network.nodes.get_mut(&node_id) else {
warn!("Invalid node");
return;
};
let Some(node_type) = resolve_document_node_type(&node.name) else {
warn!("Node {} not in library", node.name);
return;
};
node.inputs[input_index] = node_type.inputs[input_index].default.clone();
Self::send_graph(network, responses);
}
NodeGraphMessage::DoubleClickNode { node } => { NodeGraphMessage::DoubleClickNode { node } => {
self.selected_nodes = Vec::new(); self.selected_nodes = Vec::new();
if let Some(network) = self.get_active_network_mut(document) { if let Some(network) = self.get_active_network_mut(document) {

View File

@ -323,6 +323,7 @@ export default defineComponent({
selectIfNotDragged: undefined as undefined | bigint, selectIfNotDragged: undefined as undefined | bigint,
linkInProgressFromConnector: undefined as HTMLDivElement | undefined, linkInProgressFromConnector: undefined as HTMLDivElement | undefined,
linkInProgressToConnector: undefined as HTMLDivElement | DOMRect | undefined, linkInProgressToConnector: undefined as HTMLDivElement | DOMRect | undefined,
disconnecting: undefined as { nodeId: bigint; inputIndex: number; linkIndex: number } | undefined,
nodeLinkPaths: [] as [string, string][], nodeLinkPaths: [] as [string, string][],
searchTerm: "", searchTerm: "",
nodeListLocation: undefined as { x: number; y: number } | undefined, nodeListLocation: undefined as { x: number; y: number } | undefined,
@ -394,7 +395,7 @@ export default defineComponent({
if (!containerBounds) return; if (!containerBounds) return;
const links = this.nodeGraph.state.links; const links = this.nodeGraph.state.links;
this.nodeLinkPaths = links.flatMap((link) => { this.nodeLinkPaths = links.flatMap((link, index) => {
const connectorIndex = Number(link.linkEndInputIndex); const connectorIndex = Number(link.linkEndInputIndex);
const nodePrimaryOutput = (containerBounds.querySelector(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined) as HTMLDivElement | undefined; const nodePrimaryOutput = (containerBounds.querySelector(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined) as HTMLDivElement | undefined;
@ -403,6 +404,8 @@ export default defineComponent({
const nodePrimaryInput = nodeInputConnectors?.[connectorIndex] as HTMLDivElement | undefined; const nodePrimaryInput = nodeInputConnectors?.[connectorIndex] as HTMLDivElement | undefined;
if (!nodePrimaryInput || !nodePrimaryOutput) return []; if (!nodePrimaryInput || !nodePrimaryOutput) return [];
if (this.disconnecting?.linkIndex === index) return [];
return [this.createWirePath(nodePrimaryOutput, nodePrimaryInput.getBoundingClientRect(), false, false)]; return [this.createWirePath(nodePrimaryOutput, nodePrimaryInput.getBoundingClientRect(), false, false)];
}); });
}, },
@ -506,15 +509,35 @@ export default defineComponent({
const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined; const node = (e.target as HTMLElement).closest("[data-node]") as HTMLElement | undefined;
const nodeId = node?.getAttribute("data-node") || undefined; const nodeId = node?.getAttribute("data-node") || undefined;
const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined; const nodeList = (e.target as HTMLElement).closest("[data-node-list]") as HTMLElement | undefined;
const containerBounds = this.$refs.nodesContainer as HTMLDivElement | undefined;
if (!containerBounds) return;
// If the user is clicking on the add nodes list, exit here // If the user is clicking on the add nodes list, exit here
if (nodeList) return; if (nodeList) return;
// Clicked on a port dot // Clicked on a port dot
if (port) { if (port && node) {
const isOutput = Boolean(port.getAttribute("data-port") === "output"); const isOutput = Boolean(port.getAttribute("data-port") === "output");
if (isOutput) this.linkInProgressFromConnector = port; if (isOutput) this.linkInProgressFromConnector = port;
else {
const inputNodeInPorts = Array.from(node.querySelectorAll(`[data-port="input"]`));
const inputNodeConnectionIndexSearch = inputNodeInPorts.indexOf(port);
const inputIndex = inputNodeConnectionIndexSearch > -1 ? inputNodeConnectionIndexSearch : undefined;
// Set the link to draw from the input that a previous link was on
if (inputIndex !== undefined && nodeId) {
const nodeIdInt = BigInt(nodeId);
const inputIndexInt = BigInt(inputIndex);
const links = this.nodeGraph.state.links;
const linkIndex = links.findIndex((value) => value.linkEnd === nodeIdInt && value.linkEndInputIndex === inputIndexInt);
const queryString = `[data-node="${String(links[linkIndex].linkStart)}"] [data-port="output"]`;
this.linkInProgressFromConnector = (containerBounds.querySelector(queryString) || undefined) as HTMLDivElement | undefined;
const nodeInputConnectors = containerBounds.querySelectorAll(`[data-node="${String(links[linkIndex].linkEnd)}"] [data-port="input"]`) || undefined;
this.linkInProgressToConnector = nodeInputConnectors?.[Number(links[linkIndex].linkEndInputIndex)] as HTMLDivElement | undefined;
this.disconnecting = { nodeId: nodeIdInt, inputIndex, linkIndex };
this.refreshLinks();
}
}
return; return;
} }
@ -578,6 +601,11 @@ export default defineComponent({
pointerUp(e: PointerEvent) { pointerUp(e: PointerEvent) {
this.panning = false; this.panning = false;
if (this.disconnecting) {
this.editor.instance.disconnectNodes(BigInt(this.disconnecting.nodeId), this.disconnecting.inputIndex);
}
this.disconnecting = undefined;
if (this.linkInProgressToConnector instanceof HTMLDivElement && this.linkInProgressFromConnector) { if (this.linkInProgressToConnector instanceof HTMLDivElement && this.linkInProgressFromConnector) {
const outputNode = this.linkInProgressFromConnector.closest("[data-node]"); const outputNode = this.linkInProgressFromConnector.closest("[data-node]");
const inputNode = this.linkInProgressToConnector.closest("[data-node]"); const inputNode = this.linkInProgressToConnector.closest("[data-node]");
@ -598,7 +626,7 @@ export default defineComponent({
} }
} else if (this.draggingNodes) { } else if (this.draggingNodes) {
if (this.draggingNodes.startX === e.x || this.draggingNodes.startY === e.y) { if (this.draggingNodes.startX === e.x || this.draggingNodes.startY === e.y) {
if (this.selectIfNotDragged) { if (this.selectIfNotDragged !== undefined) {
this.selected = [this.selectIfNotDragged]; this.selected = [this.selectIfNotDragged];
this.editor.instance.selectNodes(new BigUint64Array(this.selected)); this.editor.instance.selectNodes(new BigUint64Array(this.selected));
} }

View File

@ -587,6 +587,13 @@ impl JsEditorHandle {
self.dispatch(message); self.dispatch(message);
} }
/// Notifies the backend that the user disconnected a node
#[wasm_bindgen(js_name = disconnectNodes)]
pub fn disconnect_nodes(&self, node_id: u64, input_index: usize) {
let message = NodeGraphMessage::DisconnectNodes { node_id, input_index };
self.dispatch(message);
}
/// Creates a new document node in the node graph /// Creates a new document node in the node graph
#[wasm_bindgen(js_name = createNode)] #[wasm_bindgen(js_name = createNode)]
pub fn create_node(&self, node_type: String, x: i32, y: i32) { pub fn create_node(&self, node_type: String, x: i32, y: i32) {