From f669333310049e2f54265b88a744b8a5ee9f97f5 Mon Sep 17 00:00:00 2001 From: delgalaenza Date: Mon, 18 Nov 2024 17:47:00 +0100 Subject: [PATCH] Prevent flow to have a circular path --- README.md | 2 ++ src/drawflow.js | 45 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c8851c4..056e228 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,8 @@ Parameter | Type | Default | Description `zoom_last_value` | Number | 1 | Default zoom last value `draggable_inputs` | Boolean | true | Drag nodes on click inputs `useuuid` | Boolean | false | Use UUID as node ID instead of integer index. Only affect newly created nodes, do not affect imported nodes +`force_first_input` | Boolean | false | Prevent flow to have a circular path + ### Reroute Active reroute connections. Use before `start` or `import`. diff --git a/src/drawflow.js b/src/drawflow.js index 5c0dba0..96d626f 100644 --- a/src/drawflow.js +++ b/src/drawflow.js @@ -32,6 +32,7 @@ export default class Drawflow { this.draggable_inputs = true; this.useuuid = false; this.parent = parent; + this.preventCircularFlow = false; this.noderegister = {}; this.render = render; @@ -418,6 +419,18 @@ export default class Drawflow { this.dispatch('mouseMove', {x: e_pos_x,y: e_pos_y }); } + checkCircularFlow(inputInfo, outputInfo) { + return Object.entries(inputInfo.outputs).some(([key, output]) => + output.connections.some(connection => { + if (Number(connection.node) === outputInfo.id) { + return true; + } else { + return this.checkCircularFlow(this.getNodeFromId(connection.node), outputInfo); + } + }) + ); + } + dragEnd(e) { if (e.type === "touchend") { var e_pos_x = this.mouse_x; @@ -475,20 +488,32 @@ export default class Drawflow { if(this.container.querySelectorAll('.connection.node_in_'+input_id+'.node_out_'+output_id+'.'+output_class+'.'+input_class).length === 0) { // Conection no exist save connection - - this.connection_ele.classList.add("node_in_"+input_id); - this.connection_ele.classList.add("node_out_"+output_id); - this.connection_ele.classList.add(output_class); - this.connection_ele.classList.add(input_class); var id_input = input_id.slice(5); var id_output = output_id.slice(5); + var foundCircularFlow = false - this.drawflow.drawflow[this.module].data[id_output].outputs[output_class].connections.push( {"node": id_input, "output": input_class}); - this.drawflow.drawflow[this.module].data[id_input].inputs[input_class].connections.push( {"node": id_output, "input": output_class}); - this.updateConnectionNodes('node-'+id_output); - this.updateConnectionNodes('node-'+id_input); - this.dispatch('connectionCreated', { output_id: id_output, input_id: id_input, output_class: output_class, input_class: input_class}); + if(this.preventCircularFlow) { + var outputInfo = this.getNodeFromId(id_output); + var inputInfo = this.getNodeFromId(id_input); + foundCircularFlow = this.checkCircularFlow(inputInfo, outputInfo); + } + if(foundCircularFlow ) { + this.dispatch('connectionCancel', true); + this.connection_ele.remove(); + } else { + this.connection_ele.classList.add("node_in_"+input_id); + this.connection_ele.classList.add("node_out_"+output_id); + this.connection_ele.classList.add(output_class); + this.connection_ele.classList.add(input_class); + + this.drawflow.drawflow[this.module].data[id_output].outputs[output_class].connections.push( {"node": id_input, "output": input_class}); + this.drawflow.drawflow[this.module].data[id_input].inputs[input_class].connections.push( {"node": id_output, "input": output_class}); + this.updateConnectionNodes('node-'+id_output); + this.updateConnectionNodes('node-'+id_input); + this.dispatch('connectionCreated', { output_id: id_output, input_id: id_input, output_class: output_class, input_class: input_class}); + + } } else { this.dispatch('connectionCancel', true); this.connection_ele.remove();