diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bb7ab60 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,165 @@ +# Contributing to Drawflow + +Thank you for your interest in contributing to Drawflow! This document provides guidelines and instructions for contributing to this project. + +## Table of Contents + +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Setting Up the Development Environment](#setting-up-the-development-environment) +- [Development Workflow](#development-workflow) + - [Building the Library](#building-the-library) + - [Running the Development Server](#running-the-development-server) + - [Project Structure](#project-structure) +- [How to Contribute](#how-to-contribute) + - [Reporting Bugs](#reporting-bugs) + - [Suggesting Features](#suggesting-features) + - [Submitting Pull Requests](#submitting-pull-requests) +- [Code Guidelines](#code-guidelines) +- [License](#license) + +## Getting Started + +### Prerequisites + +Before you begin, ensure you have the following installed: + +- [Node.js](https://nodejs.org/) (v12 or higher recommended) +- [npm](https://www.npmjs.com/) (comes with Node.js) +- [Git](https://git-scm.com/) + +### Setting Up the Development Environment + +1. **Fork the repository** on GitHub + +2. **Clone your fork** to your local machine: + ```bash + git clone https://github.com/YOUR_USERNAME/Drawflow.git + cd Drawflow + ``` + +3. **Install dependencies**: + ```bash + npm install + ``` + +4. **Verify the setup** by running the build: + ```bash + npm run build + ``` + +## Development Workflow + +### Building the Library + +To build the library for production: + +```bash +npm run build +``` + +This command: +- Runs webpack to bundle the JavaScript into `dist/drawflow.min.js` +- Runs gulp to minify CSS into `dist/drawflow.min.css` +- Generates `dist/drawflow.style.js` for LitElement usage + +### Running the Development Server + +To start a development server with hot reloading: + +```bash +npm run dev +``` + +This will open a browser window at `http://localhost:8080` where you can test your changes in real-time. + +### Project Structure + +``` +Drawflow/ +├── src/ +│ ├── drawflow.js # Main entry point +│ ├── drawflow.css # Core styles +│ ├── modules/ # Feature modules +│ │ ├── ConnectionManager.js +│ │ ├── MobileHandler.js +│ │ ├── ModuleManager.js +│ │ ├── NodeManager.js +│ │ ├── RerouteManager.js +│ │ └── ZoomHandler.js +│ └── utils/ # Utility functions +│ ├── curvature.js +│ ├── EventEmitter.js +│ └── uuid.js +├── dist/ # Built files (generated) +├── docs/ # Documentation and examples +├── gulpfile.js # Gulp tasks for CSS processing +├── webpack.config.js # Webpack configuration +└── package.json +``` + +## How to Contribute + +### Reporting Bugs + +If you find a bug, please [open an issue](https://github.com/jerosoler/Drawflow/issues/new) with: + +- A clear, descriptive title +- Steps to reproduce the issue +- Expected behavior +- Actual behavior +- Browser and OS information +- Code samples or screenshots if applicable + +### Suggesting Features + +Feature suggestions are welcome! Please [open an issue](https://github.com/jerosoler/Drawflow/issues/new) with: + +- A clear description of the feature +- The use case or problem it solves +- Any implementation ideas you may have + +### Submitting Pull Requests + +1. **Create a new branch** for your changes: + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make your changes** following the [Code Guidelines](#code-guidelines) + +3. **Test your changes** by running the development server and verifying functionality + +4. **Build the project** to ensure there are no errors: + ```bash + npm run build + ``` + +5. **Commit your changes** with a clear, descriptive commit message: + ```bash + git commit -m "Add: description of your changes" + ``` + +6. **Push to your fork**: + ```bash + git push origin feature/your-feature-name + ``` + +7. **Open a Pull Request** on GitHub with: + - A clear title and description + - Reference to any related issues + - Screenshots or GIFs for visual changes + +## Code Guidelines + +- Write clean, readable, and well-documented code +- Follow the existing code style in the project +- Keep changes focused and atomic +- Avoid introducing new dependencies unless absolutely necessary +- Ensure your changes work across major browsers +- Test on both desktop and mobile devices when applicable +- Update documentation if your changes affect the public API + +## License + +By contributing to Drawflow, you agree that your contributions will be licensed under the [MIT License](LICENSE). diff --git a/dist/drawflow.min.js b/dist/drawflow.min.js index ebdcbdd..a3b36dd 100644 --- a/dist/drawflow.min.js +++ b/dist/drawflow.min.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Drawflow=t():e.Drawflow=t()}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)n.d(i,s,function(t){return e[t]}.bind(null,s));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t),n.d(t,"default",(function(){return i}));class i{constructor(e,t=null,n=null){this.events={},this.container=e,this.precanvas=null,this.nodeId=1,this.ele_selected=null,this.node_selected=null,this.drag=!1,this.reroute=!1,this.reroute_fix_curvature=!1,this.curvature=.5,this.reroute_curvature_start_end=.5,this.reroute_curvature=.5,this.reroute_width=6,this.drag_point=!1,this.editor_selected=!1,this.connection=!1,this.connection_ele=null,this.connection_selected=null,this.canvas_x=0,this.canvas_y=0,this.pos_x=0,this.pos_x_start=0,this.pos_y=0,this.pos_y_start=0,this.mouse_x=0,this.mouse_y=0,this.line_path=5,this.first_click=null,this.force_first_input=!1,this.draggable_inputs=!0,this.useuuid=!1,this.parent=n,this.noderegister={},this.render=t,this.drawflow={drawflow:{Home:{data:{}}}},this.module="Home",this.editor_mode="edit",this.zoom=1,this.zoom_max=1.6,this.zoom_min=.5,this.zoom_value=.1,this.zoom_last_value=1,this.evCache=new Array,this.prevDiff=-1}start(){this.container.classList.add("parent-drawflow"),this.container.tabIndex=0,this.precanvas=document.createElement("div"),this.precanvas.classList.add("drawflow"),this.container.appendChild(this.precanvas),this.container.addEventListener("mouseup",this.dragEnd.bind(this)),this.container.addEventListener("mousemove",this.position.bind(this)),this.container.addEventListener("mousedown",this.click.bind(this)),this.container.addEventListener("touchend",this.dragEnd.bind(this)),this.container.addEventListener("touchmove",this.position.bind(this)),this.container.addEventListener("touchstart",this.click.bind(this)),this.container.addEventListener("contextmenu",this.contextmenu.bind(this)),this.container.addEventListener("keydown",this.key.bind(this)),this.container.addEventListener("wheel",this.zoom_enter.bind(this)),this.container.addEventListener("input",this.updateNodeValue.bind(this)),this.container.addEventListener("dblclick",this.dblclick.bind(this)),this.container.onpointerdown=this.pointerdown_handler.bind(this),this.container.onpointermove=this.pointermove_handler.bind(this),this.container.onpointerup=this.pointerup_handler.bind(this),this.container.onpointercancel=this.pointerup_handler.bind(this),this.container.onpointerout=this.pointerup_handler.bind(this),this.container.onpointerleave=this.pointerup_handler.bind(this),this.load()}pointerdown_handler(e){this.evCache.push(e)}pointermove_handler(e){for(var t=0;t100&&(n>this.prevDiff&&this.zoom_in(),n=n&&(n=parseInt(e)+1)}))})),this.nodeId=n}removeReouteConnectionSelected(){this.dispatch("connectionUnselected",!0),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.remove("selected")})}click(e){if(this.dispatch("click",e),"fixed"===this.editor_mode){if("parent-drawflow"!==e.target.classList[0]&&"drawflow"!==e.target.classList[0])return!1;this.ele_selected=e.target.closest(".parent-drawflow"),e.preventDefault()}else"view"===this.editor_mode?(null!=e.target.closest(".drawflow")||e.target.matches(".parent-drawflow"))&&(this.ele_selected=e.target.closest(".parent-drawflow"),e.preventDefault()):(this.first_click=e.target,this.ele_selected=e.target,0===e.button&&this.contextmenuDel(),null!=e.target.closest(".drawflow_content_node")&&(this.ele_selected=e.target.closest(".drawflow_content_node").parentElement));switch(this.ele_selected.classList[0]){case"drawflow-node":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected!=this.ele_selected&&this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.node_selected!=this.ele_selected&&this.dispatch("nodeSelected",this.ele_selected.id.slice(5)),this.node_selected=this.ele_selected,this.node_selected.classList.add("selected"),this.draggable_inputs?"SELECT"!==e.target.tagName&&(this.drag=!0):"INPUT"!==e.target.tagName&&"TEXTAREA"!==e.target.tagName&&"SELECT"!==e.target.tagName&&!0!==e.target.hasAttribute("contenteditable")&&(this.drag=!0);break;case"output":this.connection=!0,null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.drawConnection(e.target);break;case"parent-drawflow":case"drawflow":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.editor_selected=!0;break;case"main-path":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.connection_selected=this.ele_selected,this.connection_selected.classList.add("selected");const t=this.connection_selected.parentElement.classList;t.length>1&&(this.dispatch("connectionSelected",{output_id:t[2].slice(14),input_id:t[1].slice(13),output_class:t[3],input_class:t[4]}),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.add("selected")}));break;case"point":this.drag_point=!0,this.ele_selected.classList.add("selected");break;case"drawflow-delete":this.node_selected&&this.removeNodeId(this.node_selected.id),this.connection_selected&&this.removeConnection(),null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null)}"touchstart"===e.type?(this.pos_x=e.touches[0].clientX,this.pos_x_start=e.touches[0].clientX,this.pos_y=e.touches[0].clientY,this.pos_y_start=e.touches[0].clientY,this.mouse_x=e.touches[0].clientX,this.mouse_y=e.touches[0].clientY):(this.pos_x=e.clientX,this.pos_x_start=e.clientX,this.pos_y=e.clientY,this.pos_y_start=e.clientY),["input","output","main-path"].includes(this.ele_selected.classList[0])&&e.preventDefault(),this.dispatch("clickEnd",e)}position(e){if("touchmove"===e.type)var t=e.touches[0].clientX,n=e.touches[0].clientY;else t=e.clientX,n=e.clientY;if(this.connection&&this.updateConnection(t,n),this.editor_selected&&(i=this.canvas_x+-(this.pos_x-t),s=this.canvas_y+-(this.pos_y-n),this.dispatch("translate",{x:i,y:s}),this.precanvas.style.transform="translate("+i+"px, "+s+"px) scale("+this.zoom+")"),this.drag){e.preventDefault();var i=(this.pos_x-t)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=t,this.pos_y=n,this.ele_selected.style.top=this.ele_selected.offsetTop-s+"px",this.ele_selected.style.left=this.ele_selected.offsetLeft-i+"px",this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_x=this.ele_selected.offsetLeft-i,this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_y=this.ele_selected.offsetTop-s,this.updateConnectionNodes(this.ele_selected.id)}if(this.drag_point){i=(this.pos_x-t)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=t,this.pos_y=n;var o=this.pos_x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),l=this.pos_y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom));this.ele_selected.setAttributeNS(null,"cx",o),this.ele_selected.setAttributeNS(null,"cy",l);const e=this.ele_selected.parentElement.classList[2].slice(9),c=this.ele_selected.parentElement.classList[1].slice(13),d=this.ele_selected.parentElement.classList[3],a=this.ele_selected.parentElement.classList[4];let r=Array.from(this.ele_selected.parentElement.children).indexOf(this.ele_selected)-1;if(this.reroute_fix_curvature){r-=this.ele_selected.parentElement.querySelectorAll(".main-path").length-1,r<0&&(r=0)}const h=e.slice(5),u=this.drawflow.drawflow[this.module].data[h].outputs[d].connections.findIndex((function(e,t){return e.node===c&&e.output===a}));this.drawflow.drawflow[this.module].data[h].outputs[d].connections[u].points[r]={pos_x:o,pos_y:l};const p=this.ele_selected.parentElement.classList[2].slice(9);this.updateConnectionNodes(p)}"touchmove"===e.type&&(this.mouse_x=t,this.mouse_y=n),this.dispatch("mouseMove",{x:t,y:n})}dragEnd(e){if("touchend"===e.type)var t=this.mouse_x,n=this.mouse_y,i=document.elementFromPoint(t,n);else t=e.clientX,n=e.clientY,i=e.target;if(this.drag&&(this.pos_x_start==t&&this.pos_y_start==n||this.dispatch("nodeMoved",this.ele_selected.id.slice(5))),this.drag_point&&(this.ele_selected.classList.remove("selected"),this.pos_x_start==t&&this.pos_y_start==n||this.dispatch("rerouteMoved",this.ele_selected.parentElement.classList[2].slice(14))),this.editor_selected&&(this.canvas_x=this.canvas_x+-(this.pos_x-t),this.canvas_y=this.canvas_y+-(this.pos_y-n),this.editor_selected=!1),!0===this.connection)if("input"===i.classList[0]||this.force_first_input&&(null!=i.closest(".drawflow_content_node")||"drawflow-node"===i.classList[0])){if(!this.force_first_input||null==i.closest(".drawflow_content_node")&&"drawflow-node"!==i.classList[0])s=i.parentElement.parentElement.id,o=i.classList[1];else{if(null!=i.closest(".drawflow_content_node"))var s=i.closest(".drawflow_content_node").parentElement.id;else var s=i.id;if(0===Object.keys(this.getNodeFromId(s.slice(5)).inputs).length)var o=!1;else var o="input_1"}var l=this.ele_selected.parentElement.parentElement.id,c=this.ele_selected.classList[1];if(l!==s&&!1!==o){if(0===this.container.querySelectorAll(".connection.node_in_"+s+".node_out_"+l+"."+c+"."+o).length){this.connection_ele.classList.add("node_in_"+s),this.connection_ele.classList.add("node_out_"+l),this.connection_ele.classList.add(c),this.connection_ele.classList.add(o);var d=s.slice(5),a=l.slice(5);this.drawflow.drawflow[this.module].data[a].outputs[c].connections.push({node:d,output:o}),this.drawflow.drawflow[this.module].data[d].inputs[o].connections.push({node:a,input:c}),this.updateConnectionNodes("node-"+a),this.updateConnectionNodes("node-"+d),this.dispatch("connectionCreated",{output_id:a,input_id:d,output_class:c,input_class:o})}else this.dispatch("connectionCancel",!0),this.connection_ele.remove();this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null;this.drag=!1,this.drag_point=!1,this.connection=!1,this.ele_selected=null,this.editor_selected=!1,this.dispatch("mouseUp",e)}contextmenu(e){if(this.dispatch("contextmenu",e),e.preventDefault(),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;if(this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove(),this.node_selected||this.connection_selected){var t=document.createElement("div");t.classList.add("drawflow-delete"),t.innerHTML="x",this.node_selected&&this.node_selected.appendChild(t),this.connection_selected&&this.connection_selected.parentElement.classList.length>1&&(t.style.top=e.clientY*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))+"px",t.style.left=e.clientX*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))+"px",this.precanvas.appendChild(t))}}contextmenuDel(){this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove()}key(e){if(this.dispatch("keydown",e),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;("Delete"===e.key||"Backspace"===e.key&&e.metaKey)&&(null!=this.node_selected&&"INPUT"!==this.first_click.tagName&&"TEXTAREA"!==this.first_click.tagName&&!0!==this.first_click.hasAttribute("contenteditable")&&this.removeNodeId(this.node_selected.id),null!=this.connection_selected&&this.removeConnection())}zoom_enter(e,t){e.ctrlKey&&(e.preventDefault(),e.deltaY>0?this.zoom_out():this.zoom_in())}zoom_refresh(){this.dispatch("zoom",this.zoom),this.canvas_x=this.canvas_x/this.zoom_last_value*this.zoom,this.canvas_y=this.canvas_y/this.zoom_last_value*this.zoom,this.zoom_last_value=this.zoom,this.precanvas.style.transform="translate("+this.canvas_x+"px, "+this.canvas_y+"px) scale("+this.zoom+")"}zoom_in(){this.zoomthis.zoom_min&&(this.zoom-=this.zoom_value,this.zoom_refresh())}zoom_reset(){1!=this.zoom&&(this.zoom=1,this.zoom_refresh())}createCurvature(e,t,n,i,s,o){var l=e,c=t,d=n,a=i,r=s;switch(o){case"open":if(e>=n)var h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"close":if(e>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*r;else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"other":if(e>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;default:return" M "+l+" "+c+" C "+(h=l+Math.abs(d-l)*r)+" "+c+" "+(u=d-Math.abs(d-l)*r)+" "+a+" "+d+" "+a}}drawConnection(e){var t=document.createElementNS("http://www.w3.org/2000/svg","svg");this.connection_ele=t;var n=document.createElementNS("http://www.w3.org/2000/svg","path");n.classList.add("main-path"),n.setAttributeNS(null,"d",""),t.classList.add("connection"),t.appendChild(n),this.precanvas.appendChild(t);var i=e.parentElement.parentElement.id.slice(5),s=e.classList[1];this.dispatch("connectionStart",{output_id:i,output_class:s})}updateConnection(e,t){const n=this.precanvas,i=this.zoom;let s=n.clientWidth/(n.clientWidth*i);s=s||0;let o=n.clientHeight/(n.clientHeight*i);o=o||0;var l=this.connection_ele.children[0],c=this.ele_selected.offsetWidth/2+(this.ele_selected.getBoundingClientRect().x-n.getBoundingClientRect().x)*s,d=this.ele_selected.offsetHeight/2+(this.ele_selected.getBoundingClientRect().y-n.getBoundingClientRect().y)*o,a=e*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),r=t*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom)),h=this.curvature,u=this.createCurvature(c,d,a,r,h,"openclose");l.setAttributeNS(null,"d",u)}addConnection(e,t,n,i){var s=this.getModuleFromNodeId(e);if(s===this.getModuleFromNodeId(t)){var o=this.getNodeFromId(e),l=!1;for(var c in o.outputs[n].connections){var d=o.outputs[n].connections[c];d.node==t&&d.output==i&&(l=!0)}if(!1===l){if(this.drawflow.drawflow[s].data[e].outputs[n].connections.push({node:t.toString(),output:i}),this.drawflow.drawflow[s].data[t].inputs[i].connections.push({node:e.toString(),input:n}),this.module===s){var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),r=document.createElementNS("http://www.w3.org/2000/svg","path");r.classList.add("main-path"),r.setAttributeNS(null,"d",""),a.classList.add("connection"),a.classList.add("node_in_node-"+t),a.classList.add("node_out_node-"+e),a.classList.add(n),a.classList.add(i),a.appendChild(r),this.precanvas.appendChild(a),this.updateConnectionNodes("node-"+e),this.updateConnectionNodes("node-"+t)}this.dispatch("connectionCreated",{output_id:e,input_id:t,output_class:n,input_class:i})}}}updateConnectionNodes(e){const t="node_in_"+e,n="node_out_"+e;this.line_path;const i=this.container,s=this.precanvas,o=this.curvature,l=this.createCurvature,c=this.reroute_curvature,d=this.reroute_curvature_start_end,a=this.reroute_fix_curvature,r=this.reroute_width,h=this.zoom;let u=s.clientWidth/(s.clientWidth*h);u=u||0;let p=s.clientHeight/(s.clientHeight*h);p=p||0;const f=i.querySelectorAll("."+n);Object.keys(f).map((function(t,n){if(null===f[t].querySelector(".point")){var m=i.querySelector("#"+e),g=f[t].classList[1].replace("node_in_",""),_=i.querySelector("#"+g).querySelectorAll("."+f[t].classList[4])[0],w=_.offsetWidth/2+(_.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=_.offsetHeight/2+(_.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=m.querySelectorAll("."+f[t].classList[3])[0],C=y.offsetWidth/2+(y.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,x=y.offsetHeight/2+(y.getBoundingClientRect().y-s.getBoundingClientRect().y)*p;const n=l(C,x,w,v,o,"openclose");f[t].children[0].setAttributeNS(null,"d",n)}else{const n=f[t].querySelectorAll(".point");let o="";const m=[];n.forEach((t,a)=>{if(0===a&&n.length-1==0){var f=i.querySelector("#"+e),g=((x=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(L=f.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(L.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=L.offsetHeight/2+(L.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=l(w,v,g,_,d,"open");o+=y,m.push(y);f=t;var C=t.parentElement.classList[1].replace("node_in_",""),x=(E=i.querySelector("#"+C)).querySelectorAll("."+t.parentElement.classList[4])[0];g=(R=E.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(R.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,_=R.offsetHeight/2+(R.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,y=l(w,v,g,_,d,"close");o+=y,m.push(y)}else if(0===a){var L;f=i.querySelector("#"+e),g=((x=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(L=f.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(L.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,v=L.offsetHeight/2+(L.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,y=l(w,v,g,_,d,"open");o+=y,m.push(y);f=t,g=((x=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,y=l(w,v,g,_,c,"other");o+=y,m.push(y)}else if(a===n.length-1){var E,R;f=t,C=t.parentElement.classList[1].replace("node_in_",""),x=(E=i.querySelector("#"+C)).querySelectorAll("."+t.parentElement.classList[4])[0],g=(R=E.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(R.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,_=R.offsetHeight/2+(R.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,y=l(w,v,g,_,d,"close");o+=y,m.push(y)}else{f=t,g=((x=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,_=(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,w=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*(s.clientWidth/(s.clientWidth*h))+r,v=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*(s.clientHeight/(s.clientHeight*h))+r,y=l(w,v,g,_,c,"other");o+=y,m.push(y)}}),a?m.forEach((e,n)=>{f[t].children[n].setAttributeNS(null,"d",e)}):f[t].children[0].setAttributeNS(null,"d",o)}}));const m=i.querySelectorAll("."+t);Object.keys(m).map((function(t,n){if(null===m[t].querySelector(".point")){var h=i.querySelector("#"+e),f=m[t].classList[2].replace("node_out_",""),g=i.querySelector("#"+f).querySelectorAll("."+m[t].classList[3])[0],_=g.offsetWidth/2+(g.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=g.offsetHeight/2+(g.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,v=(h=h.querySelectorAll("."+m[t].classList[4])[0]).offsetWidth/2+(h.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,y=h.offsetHeight/2+(h.getBoundingClientRect().y-s.getBoundingClientRect().y)*p;const n=l(_,w,v,y,o,"openclose");m[t].children[0].setAttributeNS(null,"d",n)}else{const n=m[t].querySelectorAll(".point");let o="";const h=[];n.forEach((t,a)=>{if(0===a&&n.length-1==0){var f=i.querySelector("#"+e),m=((C=t).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,_=(E=f.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(E.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=E.offsetHeight/2+(E.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,v=l(m,g,_,w,d,"close");o+=v,h.push(v);f=t;var y=t.parentElement.classList[2].replace("node_out_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[3])[0];m=(x=L.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(x.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,g=x.offsetHeight/2+(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,_=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"open");o+=v,h.push(v)}else if(0===a){var x;f=t,y=t.parentElement.classList[2].replace("node_out_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[3])[0],m=(x=L.querySelectorAll("."+t.parentElement.classList[3])[0]).offsetWidth/2+(x.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,g=x.offsetHeight/2+(x.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,_=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"open");o+=v,h.push(v);f=t,_=((C=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,c,"other");o+=v,h.push(v)}else if(a===n.length-1){var L,E;f=t,y=t.parentElement.classList[1].replace("node_in_",""),C=(L=i.querySelector("#"+y)).querySelectorAll("."+t.parentElement.classList[4])[0],_=(E=L.querySelectorAll("."+t.parentElement.classList[4])[0]).offsetWidth/2+(E.getBoundingClientRect().x-s.getBoundingClientRect().x)*u,w=E.offsetHeight/2+(E.getBoundingClientRect().y-s.getBoundingClientRect().y)*p,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,d,"close");o+=v,h.push(v)}else{f=t,_=((C=n[a+1]).getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,w=(C.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,m=(f.getBoundingClientRect().x-s.getBoundingClientRect().x)*u+r,g=(f.getBoundingClientRect().y-s.getBoundingClientRect().y)*p+r,v=l(m,g,_,w,c,"other");o+=v,h.push(v)}}),a?h.forEach((e,n)=>{m[t].children[n].setAttributeNS(null,"d",e)}):m[t].children[0].setAttributeNS(null,"d",o)}}))}dblclick(e){null!=this.connection_selected&&this.reroute&&this.createReroutePoint(this.connection_selected),"point"===e.target.classList[0]&&this.removeReroutePoint(e.target)}createReroutePoint(e){this.connection_selected.classList.remove("selected");const t=this.connection_selected.parentElement.classList[2].slice(9),n=this.connection_selected.parentElement.classList[1].slice(13),i=this.connection_selected.parentElement.classList[3],s=this.connection_selected.parentElement.classList[4];this.connection_selected=null;const o=document.createElementNS("http://www.w3.org/2000/svg","circle");o.classList.add("point");var l=this.pos_x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),c=this.pos_y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom));o.setAttributeNS(null,"cx",l),o.setAttributeNS(null,"cy",c),o.setAttributeNS(null,"r",this.reroute_width);let d=0;if(this.reroute_fix_curvature){const t=e.parentElement.querySelectorAll(".main-path").length;var a=document.createElementNS("http://www.w3.org/2000/svg","path");if(a.classList.add("main-path"),a.setAttributeNS(null,"d",""),e.parentElement.insertBefore(a,e.parentElement.children[t]),1===t)e.parentElement.appendChild(o);else{const n=Array.from(e.parentElement.children).indexOf(e);d=n,e.parentElement.insertBefore(o,e.parentElement.children[n+t+1])}}else e.parentElement.appendChild(o);const r=t.slice(5),h=this.drawflow.drawflow[this.module].data[r].outputs[i].connections.findIndex((function(e,t){return e.node===n&&e.output===s}));void 0===this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points&&(this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points=[]),this.reroute_fix_curvature?(d>0||this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points!==[]?this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.splice(d,0,{pos_x:l,pos_y:c}):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),e.parentElement.querySelectorAll(".main-path").forEach((e,t)=>{e.classList.remove("selected")})):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),this.dispatch("addReroute",r),this.updateConnectionNodes(t)}removeReroutePoint(e){const t=e.parentElement.classList[2].slice(9),n=e.parentElement.classList[1].slice(13),i=e.parentElement.classList[3],s=e.parentElement.classList[4];let o=Array.from(e.parentElement.children).indexOf(e);const l=t.slice(5),c=this.drawflow.drawflow[this.module].data[l].outputs[i].connections.findIndex((function(e,t){return e.node===n&&e.output===s}));if(this.reroute_fix_curvature){const t=e.parentElement.querySelectorAll(".main-path").length;e.parentElement.children[t-1].remove(),o-=t,o<0&&(o=0)}else o--;this.drawflow.drawflow[this.module].data[l].outputs[i].connections[c].points.splice(o,1),e.remove(),this.dispatch("removeReroute",l),this.updateConnectionNodes(t)}registerNode(e,t,n=null,i=null){this.noderegister[e]={html:t,props:n,options:i}}getNodeFromId(e){var t=this.getModuleFromNodeId(e);return JSON.parse(JSON.stringify(this.drawflow.drawflow[t].data[e]))}getNodesFromName(e){var t=[];const n=this.drawflow.drawflow;return Object.keys(n).map((function(i,s){for(var o in n[i].data)n[i].data[o].name==e&&t.push(n[i].data[o].id)})),t}addNode(e,t,n,i,s,o,l,c,d=!1){if(this.useuuid)var a=this.getUuid();else a=this.nodeId;const r=document.createElement("div");r.classList.add("parent-node");const h=document.createElement("div");h.innerHTML="",h.setAttribute("id","node-"+a),h.classList.add("drawflow-node"),""!=o&&h.classList.add(...o.split(" "));const u=document.createElement("div");u.classList.add("inputs");const p=document.createElement("div");p.classList.add("outputs");const f={};for(var m=0;me(this.noderegister[c].html,{props:this.noderegister[c].props}),...this.noderegister[c].options}).$mount();_.appendChild(e.$el)}Object.entries(l).forEach((function(e,t){if("object"==typeof e[1])!function e(t,n,i){if(null===t)t=l[n];else t=t[n];null!==t&&Object.entries(t).forEach((function(n,s){if("object"==typeof n[1])e(t,n[0],i+"-"+n[0]);else for(var o=_.querySelectorAll("[df-"+i+"-"+n[0]+"]"),l=0;lt(this.noderegister[e.html].html,{props:this.noderegister[e.html].props}),...this.noderegister[e.html].options}).$mount();c.appendChild(t.$el)}Object.entries(e.data).forEach((function(t,n){if("object"==typeof t[1])!function t(n,i,s){if(null===n)n=e.data[i];else n=n[i];null!==n&&Object.entries(n).forEach((function(e,i){if("object"==typeof e[1])t(n,e[0],s+"-"+e[0]);else for(var o=c.querySelectorAll("[df-"+s+"-"+e[0]+"]"),l=0;l{const a=e.outputs[s].connections[o].node,r=e.outputs[s].connections[o].output,h=i.querySelector(".connection.node_in_node-"+a+".node_out_node-"+e.id+"."+s+"."+r);if(n&&0===d)for(var u=0;u{this.removeSingleConnection(e.id_output,e.id,e.output_class,e.input_class)}),delete this.drawflow.drawflow[n].data[e].inputs[t];const o=[],l=this.drawflow.drawflow[n].data[e].inputs;Object.keys(l).map((function(e,t){o.push(l[e])})),this.drawflow.drawflow[n].data[e].inputs={};const c=t.slice(6);let d=[];if(o.forEach((t,i)=>{t.connections.forEach((e,t)=>{d.push(e)}),this.drawflow.drawflow[n].data[e].inputs["input_"+(i+1)]=t}),d=new Set(d.map(e=>JSON.stringify(e))),d=Array.from(d).map(e=>JSON.parse(e)),this.module===n){this.container.querySelectorAll("#node-"+e+" .inputs .input").forEach((e,t)=>{const n=e.classList[1].slice(6);parseInt(c){this.drawflow.drawflow[n].data[t.node].outputs[t.input].connections.forEach((i,s)=>{if(i.node==e){const o=i.output.slice(6);if(parseInt(c){this.removeSingleConnection(e.id,e.id_input,e.output_class,e.input_class)}),delete this.drawflow.drawflow[n].data[e].outputs[t];const o=[],l=this.drawflow.drawflow[n].data[e].outputs;Object.keys(l).map((function(e,t){o.push(l[e])})),this.drawflow.drawflow[n].data[e].outputs={};const c=t.slice(7);let d=[];if(o.forEach((t,i)=>{t.connections.forEach((e,t)=>{d.push({node:e.node,output:e.output})}),this.drawflow.drawflow[n].data[e].outputs["output_"+(i+1)]=t}),d=new Set(d.map(e=>JSON.stringify(e))),d=Array.from(d).map(e=>JSON.parse(e)),this.module===n){this.container.querySelectorAll("#node-"+e+" .outputs .output").forEach((e,t)=>{const n=e.classList[1].slice(7);parseInt(c){this.drawflow.drawflow[n].data[t.node].inputs[t.output].connections.forEach((i,s)=>{if(i.node==e){const o=i.input.slice(7);if(parseInt(c)-1){this.module===s&&this.container.querySelector(".connection.node_in_node-"+t+".node_out_node-"+e+"."+n+"."+i).remove();var o=this.drawflow.drawflow[s].data[e].outputs[n].connections.findIndex((function(e,n){return e.node==t&&e.output===i}));this.drawflow.drawflow[s].data[e].outputs[n].connections.splice(o,1);var l=this.drawflow.drawflow[s].data[t].inputs[i].connections.findIndex((function(t,i){return t.node==e&&t.input===n}));return this.drawflow.drawflow[s].data[t].inputs[i].connections.splice(l,1),this.dispatch("connectionRemoved",{output_id:e,input_id:t,output_class:n,input_class:i}),!0}return!1}return!1}removeConnectionNodeId(e){const t="node_in_"+e,n="node_out_"+e,i=this.container.querySelectorAll("."+n);for(var s=i.length-1;s>=0;s--){var o=i[s].classList,l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(e,t){return e.node===o[2].slice(14)&&e.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1);var c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(e,t){return e.node===o[1].slice(13)&&e.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1),i[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}const d=this.container.querySelectorAll("."+t);for(s=d.length-1;s>=0;s--){o=d[s].classList,c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(e,t){return e.node===o[1].slice(13)&&e.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1);l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(e,t){return e.node===o[2].slice(14)&&e.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1),d[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}}getModuleFromNodeId(e){var t;const n=this.drawflow.drawflow;return Object.keys(n).map((function(i,s){Object.keys(n[i].data).map((function(n,s){n==e&&(t=i)}))})),t}addModule(e){this.drawflow.drawflow[e]={data:{}},this.dispatch("moduleCreated",e)}changeModule(e){this.dispatch("moduleChanged",e),this.module=e,this.precanvas.innerHTML="",this.canvas_x=0,this.canvas_y=0,this.pos_x=0,this.pos_y=0,this.mouse_x=0,this.mouse_y=0,this.zoom=1,this.zoom_last_value=1,this.precanvas.style.transform="",this.import(this.drawflow,!1)}removeModule(e){this.module===e&&this.changeModule("Home"),delete this.drawflow.drawflow[e],this.dispatch("moduleRemoved",e)}clearModuleSelected(){this.precanvas.innerHTML="",this.drawflow.drawflow[this.module]={data:{}}}clear(){this.precanvas.innerHTML="",this.drawflow={drawflow:{Home:{data:{}}}}}export(){const e=JSON.parse(JSON.stringify(this.drawflow));return this.dispatch("export",e),e}import(e,t=!0){this.clear(),this.drawflow=JSON.parse(JSON.stringify(e)),this.load(),t&&this.dispatch("import","import")}on(e,t){return"function"!=typeof t?(console.error("The listener callback must be a function, the given type is "+typeof t),!1):"string"!=typeof e?(console.error("The event name must be a string, the given type is "+typeof e),!1):(void 0===this.events[e]&&(this.events[e]={listeners:[]}),void this.events[e].listeners.push(t))}removeListener(e,t){if(!this.events[e])return!1;const n=this.events[e].listeners,i=n.indexOf(t);i>-1&&n.splice(i,1)}dispatch(e,t){if(void 0===this.events[e])return!1;this.events[e].listeners.forEach(e=>{e(t)})}getUuid(){for(var e=[],t=0;t<36;t++)e[t]="0123456789abcdef".substr(Math.floor(16*Math.random()),1);return e[14]="4",e[19]="0123456789abcdef".substr(3&e[19]|8,1),e[8]=e[13]=e[18]=e[23]="-",e.join("")}}}]).default})); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Drawflow=e():t.Drawflow=e()}("undefined"!=typeof self?self:this,(function(){return function(t){var e={};function n(i){if(e[i])return e[i].exports;var s=e[i]={i:i,l:!1,exports:{}};return t[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}return n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)n.d(i,s,function(e){return t[e]}.bind(null,s));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}([function(t,e,n){"use strict";n.r(e),n.d(e,"default",(function(){return o}));function i(t,e,n,i,s,o){var l=t,c=e,d=n,a=i,r=s;switch(o){case"open":if(t>=n)var h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"close":if(t>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*r;else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;case"other":if(t>=n)h=l+Math.abs(d-l)*(-1*r),u=d-Math.abs(d-l)*(-1*r);else h=l+Math.abs(d-l)*r,u=d-Math.abs(d-l)*r;return" M "+l+" "+c+" C "+h+" "+c+" "+u+" "+a+" "+d+" "+a;default:return" M "+l+" "+c+" C "+(h=l+Math.abs(d-l)*r)+" "+c+" "+(u=d-Math.abs(d-l)*r)+" "+a+" "+d+" "+a}}function s(){for(var t=[],e=0;e<36;e++)t[e]="0123456789abcdef".substr(Math.floor(16*Math.random()),1);return t[14]="4",t[19]="0123456789abcdef".substr(3&t[19]|8,1),t[8]=t[13]=t[18]=t[23]="-",t.join("")}class o extends class{constructor(){this.events={}}on(t,e){return"function"!=typeof e?(console.error("The listener callback must be a function, the given type is "+typeof e),!1):"string"!=typeof t?(console.error("The event name must be a string, the given type is "+typeof t),!1):(void 0===this.events[t]&&(this.events[t]={listeners:[]}),void this.events[t].listeners.push(e))}removeListener(t,e){if(!this.events[t])return!1;const n=this.events[t].listeners,i=n.indexOf(e);i>-1&&n.splice(i,1)}dispatch(t,e){if(void 0===this.events[t])return!1;this.events[t].listeners.forEach(t=>{t(e)})}}{constructor(t,e=null,n=null){var i;super(),this.container=t,this.precanvas=null,this.nodeId=1,this.ele_selected=null,this.node_selected=null,this.drag=!1,this.reroute=!1,this.reroute_fix_curvature=!1,this.curvature=.5,this.reroute_curvature_start_end=.5,this.reroute_curvature=.5,this.reroute_width=6,this.drag_point=!1,this.editor_selected=!1,this.connection=!1,this.connection_ele=null,this.connection_selected=null,this.canvas_x=0,this.canvas_y=0,this.pos_x=0,this.pos_x_start=0,this.pos_y=0,this.pos_y_start=0,this.mouse_x=0,this.mouse_y=0,this.line_path=5,this.first_click=null,this.force_first_input=!1,this.draggable_inputs=!0,this.useuuid=!1,this.parent=n,this.noderegister={},this.render=e,this.drawflow={drawflow:{Home:{data:{}}}},this.module="Home",this.editor_mode="edit",this.zoom=1,this.zoom_max=1.6,this.zoom_min=.5,this.zoom_value=.1,this.zoom_last_value=1,(i=this).evCache=new Array,i.prevDiff=-1}start(){this.container.classList.add("parent-drawflow"),this.container.tabIndex=0,this.precanvas=document.createElement("div"),this.precanvas.classList.add("drawflow"),this.container.appendChild(this.precanvas),this.container.addEventListener("mouseup",this.dragEnd.bind(this)),this.container.addEventListener("mousemove",this.position.bind(this)),this.container.addEventListener("mousedown",this.click.bind(this)),this.container.addEventListener("touchend",this.dragEnd.bind(this)),this.container.addEventListener("touchmove",this.position.bind(this)),this.container.addEventListener("touchstart",this.click.bind(this)),this.container.addEventListener("contextmenu",this.contextmenu.bind(this)),this.container.addEventListener("keydown",this.key.bind(this)),this.container.addEventListener("wheel",this.zoom_enter.bind(this)),this.container.addEventListener("input",this.updateNodeValue.bind(this)),this.container.addEventListener("dblclick",this.dblclick.bind(this)),this.container.onpointerdown=this.pointerdown_handler.bind(this),this.container.onpointermove=this.pointermove_handler.bind(this),this.container.onpointerup=this.pointerup_handler.bind(this),this.container.onpointercancel=this.pointerup_handler.bind(this),this.container.onpointerout=this.pointerup_handler.bind(this),this.container.onpointerleave=this.pointerup_handler.bind(this),this.load()}load(){for(var t in this.drawflow.drawflow[this.module].data)this.addNodeImport(this.drawflow.drawflow[this.module].data[t],this.precanvas);if(this.reroute)for(var t in this.drawflow.drawflow[this.module].data)this.addRerouteImport(this.drawflow.drawflow[this.module].data[t]);for(var t in this.drawflow.drawflow[this.module].data)this.updateConnectionNodes("node-"+t);const e=this.drawflow.drawflow;let n=1;Object.keys(e).map((function(t,i){Object.keys(e[t].data).map((function(t,e){parseInt(t)>=n&&(n=parseInt(t)+1)}))})),this.nodeId=n}removeReouteConnectionSelected(){this.dispatch("connectionUnselected",!0),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((t,e)=>{t.classList.remove("selected")})}click(t){if(this.dispatch("click",t),"fixed"===this.editor_mode){if("parent-drawflow"!==t.target.classList[0]&&"drawflow"!==t.target.classList[0])return!1;this.ele_selected=t.target.closest(".parent-drawflow"),t.preventDefault()}else"view"===this.editor_mode?(null!=t.target.closest(".drawflow")||t.target.matches(".parent-drawflow"))&&(this.ele_selected=t.target.closest(".parent-drawflow"),t.preventDefault()):(this.first_click=t.target,this.ele_selected=t.target,0===t.button&&this.contextmenuDel(),null!=t.target.closest(".drawflow_content_node")&&(this.ele_selected=t.target.closest(".drawflow_content_node").parentElement));switch(this.ele_selected.classList[0]){case"drawflow-node":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected!=this.ele_selected&&this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.node_selected!=this.ele_selected&&this.dispatch("nodeSelected",this.ele_selected.id.slice(5)),this.node_selected=this.ele_selected,this.node_selected.classList.add("selected"),this.draggable_inputs?"SELECT"!==t.target.tagName&&(this.drag=!0):"INPUT"!==t.target.tagName&&"TEXTAREA"!==t.target.tagName&&"SELECT"!==t.target.tagName&&!0!==t.target.hasAttribute("contenteditable")&&(this.drag=!0);break;case"output":this.connection=!0,null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.drawConnection(t.target);break;case"parent-drawflow":case"drawflow":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.editor_selected=!0;break;case"main-path":null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null),this.connection_selected=this.ele_selected,this.connection_selected.classList.add("selected");const e=this.connection_selected.parentElement.classList;e.length>1&&(this.dispatch("connectionSelected",{output_id:e[2].slice(14),input_id:e[1].slice(13),output_class:e[3],input_class:e[4]}),this.reroute_fix_curvature&&this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((t,e)=>{t.classList.add("selected")}));break;case"point":this.drag_point=!0,this.ele_selected.classList.add("selected");break;case"drawflow-delete":this.node_selected&&this.removeNodeId(this.node_selected.id),this.connection_selected&&this.removeConnection(),null!=this.node_selected&&(this.node_selected.classList.remove("selected"),this.node_selected=null,this.dispatch("nodeUnselected",!0)),null!=this.connection_selected&&(this.connection_selected.classList.remove("selected"),this.removeReouteConnectionSelected(),this.connection_selected=null)}"touchstart"===t.type?(this.pos_x=t.touches[0].clientX,this.pos_x_start=t.touches[0].clientX,this.pos_y=t.touches[0].clientY,this.pos_y_start=t.touches[0].clientY,this.mouse_x=t.touches[0].clientX,this.mouse_y=t.touches[0].clientY):(this.pos_x=t.clientX,this.pos_x_start=t.clientX,this.pos_y=t.clientY,this.pos_y_start=t.clientY),["input","output","main-path"].includes(this.ele_selected.classList[0])&&t.preventDefault(),this.dispatch("clickEnd",t)}position(t){if("touchmove"===t.type)var e=t.touches[0].clientX,n=t.touches[0].clientY;else e=t.clientX,n=t.clientY;if(this.connection&&this.updateConnection(e,n),this.editor_selected){var i=this.canvas_x+-(this.pos_x-e),s=this.canvas_y+-(this.pos_y-n);this.dispatch("translate",{x:i,y:s}),this.precanvas.style.transform="translate("+i+"px, "+s+"px) scale("+this.zoom+")"}if(this.drag){t.preventDefault();i=(this.pos_x-e)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=e,this.pos_y=n,this.ele_selected.style.top=this.ele_selected.offsetTop-s+"px",this.ele_selected.style.left=this.ele_selected.offsetLeft-i+"px",this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_x=this.ele_selected.offsetLeft-i,this.drawflow.drawflow[this.module].data[this.ele_selected.id.slice(5)].pos_y=this.ele_selected.offsetTop-s,this.updateConnectionNodes(this.ele_selected.id)}if(this.drag_point){i=(this.pos_x-e)*this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom),s=(this.pos_y-n)*this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom);this.pos_x=e,this.pos_y=n;var o=this.pos_x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),l=this.pos_y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom));this.ele_selected.setAttributeNS(null,"cx",o),this.ele_selected.setAttributeNS(null,"cy",l);const t=this.ele_selected.parentElement.classList[2].slice(9),c=this.ele_selected.parentElement.classList[1].slice(13),d=this.ele_selected.parentElement.classList[3],a=this.ele_selected.parentElement.classList[4];let r=Array.from(this.ele_selected.parentElement.children).indexOf(this.ele_selected)-1;if(this.reroute_fix_curvature){r-=this.ele_selected.parentElement.querySelectorAll(".main-path").length-1,r<0&&(r=0)}const h=t.slice(5),u=this.drawflow.drawflow[this.module].data[h].outputs[d].connections.findIndex((function(t,e){return t.node===c&&t.output===a}));this.drawflow.drawflow[this.module].data[h].outputs[d].connections[u].points[r]={pos_x:o,pos_y:l};const p=this.ele_selected.parentElement.classList[2].slice(9);this.updateConnectionNodes(p)}"touchmove"===t.type&&(this.mouse_x=e,this.mouse_y=n),this.dispatch("mouseMove",{x:e,y:n})}dragEnd(t){if("touchend"===t.type)var e=this.mouse_x,n=this.mouse_y,i=document.elementFromPoint(e,n);else e=t.clientX,n=t.clientY,i=t.target;if(this.drag&&(this.pos_x_start==e&&this.pos_y_start==n||this.dispatch("nodeMoved",this.ele_selected.id.slice(5))),this.drag_point&&(this.ele_selected.classList.remove("selected"),this.pos_x_start==e&&this.pos_y_start==n||this.dispatch("rerouteMoved",this.ele_selected.parentElement.classList[2].slice(14))),this.editor_selected&&(this.canvas_x=this.canvas_x+-(this.pos_x-e),this.canvas_y=this.canvas_y+-(this.pos_y-n),this.editor_selected=!1),!0===this.connection)if("input"===i.classList[0]||this.force_first_input&&(null!=i.closest(".drawflow_content_node")||"drawflow-node"===i.classList[0])){if(!this.force_first_input||null==i.closest(".drawflow_content_node")&&"drawflow-node"!==i.classList[0])s=i.parentElement.parentElement.id,o=i.classList[1];else{if(null!=i.closest(".drawflow_content_node"))var s=i.closest(".drawflow_content_node").parentElement.id;else var s=i.id;if(0===Object.keys(this.getNodeFromId(s.slice(5)).inputs).length)var o=!1;else var o="input_1"}var l=this.ele_selected.parentElement.parentElement.id,c=this.ele_selected.classList[1];if(l!==s&&!1!==o){if(0===this.container.querySelectorAll(".connection.node_in_"+s+".node_out_"+l+"."+c+"."+o).length){this.connection_ele.classList.add("node_in_"+s),this.connection_ele.classList.add("node_out_"+l),this.connection_ele.classList.add(c),this.connection_ele.classList.add(o);var d=s.slice(5),a=l.slice(5);this.drawflow.drawflow[this.module].data[a].outputs[c].connections.push({node:d,output:o}),this.drawflow.drawflow[this.module].data[d].inputs[o].connections.push({node:a,input:c}),this.updateConnectionNodes("node-"+a),this.updateConnectionNodes("node-"+d),this.dispatch("connectionCreated",{output_id:a,input_id:d,output_class:c,input_class:o})}else this.dispatch("connectionCancel",!0),this.connection_ele.remove();this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null}else this.dispatch("connectionCancel",!0),this.connection_ele.remove(),this.connection_ele=null;this.drag=!1,this.drag_point=!1,this.connection=!1,this.ele_selected=null,this.editor_selected=!1,this.dispatch("mouseUp",t)}contextmenu(t){if(this.dispatch("contextmenu",t),t.preventDefault(),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;if(this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove(),this.node_selected||this.connection_selected){var e=document.createElement("div");e.classList.add("drawflow-delete"),e.innerHTML="x",this.node_selected&&this.node_selected.appendChild(e),this.connection_selected&&this.connection_selected.parentElement.classList.length>1&&(e.style.top=t.clientY*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))+"px",e.style.left=t.clientX*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))+"px",this.precanvas.appendChild(e))}}contextmenuDel(){this.precanvas.getElementsByClassName("drawflow-delete").length&&this.precanvas.getElementsByClassName("drawflow-delete")[0].remove()}key(t){if(this.dispatch("keydown",t),"fixed"===this.editor_mode||"view"===this.editor_mode)return!1;("Delete"===t.key||"Backspace"===t.key&&t.metaKey)&&(null!=this.node_selected&&"INPUT"!==this.first_click.tagName&&"TEXTAREA"!==this.first_click.tagName&&!0!==this.first_click.hasAttribute("contenteditable")&&this.removeNodeId(this.node_selected.id),null!=this.connection_selected&&this.removeConnection())}createCurvature(t,e,n,s,o,l){return i(t,e,n,s,o,l)}getUuid(){return s()}export(){return this.exportDrawflow()}import(t,e=!0){return this.importDrawflow(t,e)}}o.prototype.pointerdown_handler=function(t){this.evCache.push(t)},o.prototype.pointermove_handler=function(t){for(var e=0;e100&&(n>this.prevDiff&&this.zoom_in(),n0?this.zoom_out():this.zoom_in())},o.prototype.zoom_refresh=function(){this.dispatch("zoom",this.zoom),this.canvas_x=this.canvas_x/this.zoom_last_value*this.zoom,this.canvas_y=this.canvas_y/this.zoom_last_value*this.zoom,this.zoom_last_value=this.zoom,this.precanvas.style.transform="translate("+this.canvas_x+"px, "+this.canvas_y+"px) scale("+this.zoom+")"},o.prototype.zoom_in=function(){this.zoomthis.zoom_min&&(this.zoom-=this.zoom_value,this.zoom_refresh())},o.prototype.zoom_reset=function(){1!=this.zoom&&(this.zoom=1,this.zoom_refresh())},o.prototype.drawConnection=function(t){var e=document.createElementNS("http://www.w3.org/2000/svg","svg");this.connection_ele=e;var n=document.createElementNS("http://www.w3.org/2000/svg","path");n.classList.add("main-path"),n.setAttributeNS(null,"d",""),e.classList.add("connection"),e.appendChild(n),this.precanvas.appendChild(e);var i=t.parentElement.parentElement.id.slice(5),s=t.classList[1];this.dispatch("connectionStart",{output_id:i,output_class:s})},o.prototype.updateConnection=function(t,e){const n=this.precanvas,s=this.zoom;let o=n.clientWidth/(n.clientWidth*s);o=o||0;let l=n.clientHeight/(n.clientHeight*s);l=l||0;var c=this.connection_ele.children[0],d=i(this.ele_selected.offsetWidth/2+(this.ele_selected.getBoundingClientRect().x-n.getBoundingClientRect().x)*o,this.ele_selected.offsetHeight/2+(this.ele_selected.getBoundingClientRect().y-n.getBoundingClientRect().y)*l,t*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom))-this.precanvas.getBoundingClientRect().x*(this.precanvas.clientWidth/(this.precanvas.clientWidth*this.zoom)),e*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom))-this.precanvas.getBoundingClientRect().y*(this.precanvas.clientHeight/(this.precanvas.clientHeight*this.zoom)),this.curvature,"openclose");c.setAttributeNS(null,"d",d)},o.prototype.addConnection=function(t,e,n,i){var s=this.getModuleFromNodeId(t);if(s===this.getModuleFromNodeId(e)){var o=this.getNodeFromId(t),l=!1;for(var c in o.outputs[n].connections){var d=o.outputs[n].connections[c];d.node==e&&d.output==i&&(l=!0)}if(!1===l){if(this.drawflow.drawflow[s].data[t].outputs[n].connections.push({node:e.toString(),output:i}),this.drawflow.drawflow[s].data[e].inputs[i].connections.push({node:t.toString(),input:n}),this.module===s){var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),r=document.createElementNS("http://www.w3.org/2000/svg","path");r.classList.add("main-path"),r.setAttributeNS(null,"d",""),a.classList.add("connection"),a.classList.add("node_in_node-"+e),a.classList.add("node_out_node-"+t),a.classList.add(n),a.classList.add(i),a.appendChild(r),this.precanvas.appendChild(a),this.updateConnectionNodes("node-"+t),this.updateConnectionNodes("node-"+e)}this.dispatch("connectionCreated",{output_id:t,input_id:e,output_class:n,input_class:i})}}},o.prototype.updateConnectionNodes=function(t){const e="node_in_"+t,n="node_out_"+t;this.line_path;const s=this.container,o=this.precanvas,l=this.curvature,c=this.reroute_curvature,d=this.reroute_curvature_start_end,a=this.reroute_fix_curvature,r=this.reroute_width,h=this.zoom;let u=o.clientWidth/(o.clientWidth*h);u=u||0;let p=o.clientHeight/(o.clientHeight*h);p=p||0;const f=s.querySelectorAll("."+n);Object.keys(f).map((function(e,n){if(null===f[e].querySelector(".point")){var m=s.querySelector("#"+t),g=f[e].classList[1].replace("node_in_",""),_=s.querySelector("#"+g).querySelectorAll("."+f[e].classList[4])[0],w=_.offsetWidth/2+(_.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,v=_.offsetHeight/2+(_.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,y=m.querySelectorAll("."+f[e].classList[3])[0];const n=i(y.offsetWidth/2+(y.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,y.offsetHeight/2+(y.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,w,v,l,"openclose");f[e].children[0].setAttributeNS(null,"d",n)}else{const n=f[e].querySelectorAll(".point");let l="";const m=[];n.forEach((e,a)=>{if(0===a&&n.length-1==0){var f=s.querySelector("#"+t),g=((y=e).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,_=(y.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,w=i((C=f.querySelectorAll("."+e.parentElement.classList[3])[0]).offsetWidth/2+(C.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,C.offsetHeight/2+(C.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,g,_,d,"open");l+=w,m.push(w);f=e;var v=e.parentElement.classList[1].replace("node_in_",""),y=(x=s.querySelector("#"+v)).querySelectorAll("."+e.parentElement.classList[4])[0];g=(L=x.querySelectorAll("."+e.parentElement.classList[4])[0]).offsetWidth/2+(L.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,_=L.offsetHeight/2+(L.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,w=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,g,_,d,"close");l+=w,m.push(w)}else if(0===a){var C;f=s.querySelector("#"+t),g=((y=e).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,_=(y.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,w=i((C=f.querySelectorAll("."+e.parentElement.classList[3])[0]).offsetWidth/2+(C.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,C.offsetHeight/2+(C.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,g,_,d,"open");l+=w,m.push(w);f=e,g=((y=n[a+1]).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,_=(y.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,w=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,g,_,c,"other");l+=w,m.push(w)}else if(a===n.length-1){var x,L;f=e,v=e.parentElement.classList[1].replace("node_in_",""),y=(x=s.querySelector("#"+v)).querySelectorAll("."+e.parentElement.classList[4])[0],g=(L=x.querySelectorAll("."+e.parentElement.classList[4])[0]).offsetWidth/2+(L.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,_=L.offsetHeight/2+(L.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,w=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*(o.clientWidth/(o.clientWidth*h))+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*(o.clientHeight/(o.clientHeight*h))+r,g,_,d,"close");l+=w,m.push(w)}else{f=e,g=((y=n[a+1]).getBoundingClientRect().x-o.getBoundingClientRect().x)*(o.clientWidth/(o.clientWidth*h))+r,_=(y.getBoundingClientRect().y-o.getBoundingClientRect().y)*(o.clientHeight/(o.clientHeight*h))+r,w=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*(o.clientWidth/(o.clientWidth*h))+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*(o.clientHeight/(o.clientHeight*h))+r,g,_,c,"other");l+=w,m.push(w)}}),a?m.forEach((t,n)=>{f[e].children[n].setAttributeNS(null,"d",t)}):f[e].children[0].setAttributeNS(null,"d",l)}}));const m=s.querySelectorAll("."+e);Object.keys(m).map((function(e,n){if(null===m[e].querySelector(".point")){var h=s.querySelector("#"+t),f=m[e].classList[2].replace("node_out_",""),g=s.querySelector("#"+f).querySelectorAll("."+m[e].classList[3])[0];const n=i(g.offsetWidth/2+(g.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,g.offsetHeight/2+(g.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,(h=h.querySelectorAll("."+m[e].classList[4])[0]).offsetWidth/2+(h.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,h.offsetHeight/2+(h.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,l,"openclose");m[e].children[0].setAttributeNS(null,"d",n)}else{const n=m[e].querySelectorAll(".point");let l="";const h=[];n.forEach((e,a)=>{if(0===a&&n.length-1==0){var f=s.querySelector("#"+t),m=i(((_=e).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(_.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,v=(x=f.querySelectorAll("."+e.parentElement.classList[4])[0]).offsetWidth/2+(x.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,y=x.offsetHeight/2+(x.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,d,"close");l+=m,h.push(m);f=e;var g=e.parentElement.classList[2].replace("node_out_",""),_=(C=s.querySelector("#"+g)).querySelectorAll("."+e.parentElement.classList[3])[0];m=i((w=C.querySelectorAll("."+e.parentElement.classList[3])[0]).offsetWidth/2+(w.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,w.offsetHeight/2+(w.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,v=(f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,y=(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,d,"open");l+=m,h.push(m)}else if(0===a){var w;f=e,g=e.parentElement.classList[2].replace("node_out_",""),_=(C=s.querySelector("#"+g)).querySelectorAll("."+e.parentElement.classList[3])[0],m=i((w=C.querySelectorAll("."+e.parentElement.classList[3])[0]).offsetWidth/2+(w.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,w.offsetHeight/2+(w.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,v=(f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,y=(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,d,"open");l+=m,h.push(m);f=e;var v=((_=n[a+1]).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,y=(_.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r;m=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,v,y,c,"other");l+=m,h.push(m)}else if(a===n.length-1){var C,x;f=e,g=e.parentElement.classList[1].replace("node_in_",""),_=(C=s.querySelector("#"+g)).querySelectorAll("."+e.parentElement.classList[4])[0],v=(x=C.querySelectorAll("."+e.parentElement.classList[4])[0]).offsetWidth/2+(x.getBoundingClientRect().x-o.getBoundingClientRect().x)*u,y=x.offsetHeight/2+(x.getBoundingClientRect().y-o.getBoundingClientRect().y)*p,m=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,v,y,d,"close");l+=m,h.push(m)}else{f=e,v=((_=n[a+1]).getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,y=(_.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,m=i((f.getBoundingClientRect().x-o.getBoundingClientRect().x)*u+r,(f.getBoundingClientRect().y-o.getBoundingClientRect().y)*p+r,v,y,c,"other");l+=m,h.push(m)}}),a?h.forEach((t,n)=>{m[e].children[n].setAttributeNS(null,"d",t)}):m[e].children[0].setAttributeNS(null,"d",l)}}))},o.prototype.removeConnection=function(){if(null!=this.connection_selected){var t=this.connection_selected.parentElement.classList;this.connection_selected.parentElement.remove();var e=this.drawflow.drawflow[this.module].data[t[2].slice(14)].outputs[t[3]].connections.findIndex((function(e,n){return e.node===t[1].slice(13)&&e.output===t[4]}));this.drawflow.drawflow[this.module].data[t[2].slice(14)].outputs[t[3]].connections.splice(e,1);var n=this.drawflow.drawflow[this.module].data[t[1].slice(13)].inputs[t[4]].connections.findIndex((function(e,n){return e.node===t[2].slice(14)&&e.input===t[3]}));this.drawflow.drawflow[this.module].data[t[1].slice(13)].inputs[t[4]].connections.splice(n,1),this.dispatch("connectionRemoved",{output_id:t[2].slice(14),input_id:t[1].slice(13),output_class:t[3],input_class:t[4]}),this.connection_selected=null}},o.prototype.removeSingleConnection=function(t,e,n,i){var s=this.getModuleFromNodeId(t);if(s===this.getModuleFromNodeId(e)){if(this.drawflow.drawflow[s].data[t].outputs[n].connections.findIndex((function(t,n){return t.node==e&&t.output===i}))>-1){this.module===s&&this.container.querySelector(".connection.node_in_node-"+e+".node_out_node-"+t+"."+n+"."+i).remove();var o=this.drawflow.drawflow[s].data[t].outputs[n].connections.findIndex((function(t,n){return t.node==e&&t.output===i}));this.drawflow.drawflow[s].data[t].outputs[n].connections.splice(o,1);var l=this.drawflow.drawflow[s].data[e].inputs[i].connections.findIndex((function(e,i){return e.node==t&&e.input===n}));return this.drawflow.drawflow[s].data[e].inputs[i].connections.splice(l,1),this.dispatch("connectionRemoved",{output_id:t,input_id:e,output_class:n,input_class:i}),!0}return!1}return!1},o.prototype.removeConnectionNodeId=function(t){const e="node_in_"+t,n="node_out_"+t,i=this.container.querySelectorAll("."+n);for(var s=i.length-1;s>=0;s--){var o=i[s].classList,l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(t,e){return t.node===o[2].slice(14)&&t.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1);var c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(t,e){return t.node===o[1].slice(13)&&t.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1),i[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}const d=this.container.querySelectorAll("."+e);for(s=d.length-1;s>=0;s--){o=d[s].classList,c=this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.findIndex((function(t,e){return t.node===o[1].slice(13)&&t.output===o[4]}));this.drawflow.drawflow[this.module].data[o[2].slice(14)].outputs[o[3]].connections.splice(c,1);l=this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.findIndex((function(t,e){return t.node===o[2].slice(14)&&t.input===o[3]}));this.drawflow.drawflow[this.module].data[o[1].slice(13)].inputs[o[4]].connections.splice(l,1),d[s].remove(),this.dispatch("connectionRemoved",{output_id:o[2].slice(14),input_id:o[1].slice(13),output_class:o[3],input_class:o[4]})}},o.prototype.registerNode=function(t,e,n=null,i=null){this.noderegister[t]={html:e,props:n,options:i}},o.prototype.getNodeFromId=function(t){var e=this.getModuleFromNodeId(t);return JSON.parse(JSON.stringify(this.drawflow.drawflow[e].data[t]))},o.prototype.getNodesFromName=function(t){var e=[];const n=this.drawflow.drawflow;return Object.keys(n).map((function(i,s){for(var o in n[i].data)n[i].data[o].name==t&&e.push(n[i].data[o].id)})),e},o.prototype.addNode=function(t,e,n,i,o,l,c,d,a=!1){if(this.useuuid)var r=s();else r=this.nodeId;const h=document.createElement("div");h.classList.add("parent-node");const u=document.createElement("div");u.innerHTML="",u.setAttribute("id","node-"+r),u.classList.add("drawflow-node"),""!=l&&u.classList.add(...l.split(" "));const p=document.createElement("div");p.classList.add("inputs");const f=document.createElement("div");f.classList.add("outputs");const m={};for(var g=0;gt(this.noderegister[d].html,{props:this.noderegister[d].props}),...this.noderegister[d].options}).$mount();w.appendChild(t.$el)}Object.entries(c).forEach((function(t,e){if("object"==typeof t[1])!function t(e,n,i){if(null===e)e=c[n];else e=e[n];null!==e&&Object.entries(e).forEach((function(n,s){if("object"==typeof n[1])t(e,n[0],i+"-"+n[0]);else for(var o=w.querySelectorAll("[df-"+i+"-"+n[0]+"]"),l=0;le(this.noderegister[t.html].html,{props:this.noderegister[t.html].props}),...this.noderegister[t.html].options}).$mount();c.appendChild(e.$el)}Object.entries(t.data).forEach((function(e,n){if("object"==typeof e[1])!function e(n,i,s){if(null===n)n=t.data[i];else n=n[i];null!==n&&Object.entries(n).forEach((function(t,i){if("object"==typeof t[1])e(n,t[0],s+"-"+t[0]);else for(var o=c.querySelectorAll("[df-"+s+"-"+t[0]+"]"),l=0;l{this.removeSingleConnection(t.id_output,t.id,t.output_class,t.input_class)}),delete this.drawflow.drawflow[n].data[t].inputs[e];const o=[],l=this.drawflow.drawflow[n].data[t].inputs;Object.keys(l).map((function(t,e){o.push(l[t])})),this.drawflow.drawflow[n].data[t].inputs={};const c=e.slice(6);let d=[];if(o.forEach((e,i)=>{e.connections.forEach((t,e)=>{d.push(t)}),this.drawflow.drawflow[n].data[t].inputs["input_"+(i+1)]=e}),d=new Set(d.map(t=>JSON.stringify(t))),d=Array.from(d).map(t=>JSON.parse(t)),this.module===n){this.container.querySelectorAll("#node-"+t+" .inputs .input").forEach((t,e)=>{const n=t.classList[1].slice(6);parseInt(c){this.drawflow.drawflow[n].data[e.node].outputs[e.input].connections.forEach((i,s)=>{if(i.node==t){const o=i.output.slice(6);if(parseInt(c){this.removeSingleConnection(t.id,t.id_input,t.output_class,t.input_class)}),delete this.drawflow.drawflow[n].data[t].outputs[e];const o=[],l=this.drawflow.drawflow[n].data[t].outputs;Object.keys(l).map((function(t,e){o.push(l[t])})),this.drawflow.drawflow[n].data[t].outputs={};const c=e.slice(7);let d=[];if(o.forEach((e,i)=>{e.connections.forEach((t,e)=>{d.push({node:t.node,output:t.output})}),this.drawflow.drawflow[n].data[t].outputs["output_"+(i+1)]=e}),d=new Set(d.map(t=>JSON.stringify(t))),d=Array.from(d).map(t=>JSON.parse(t)),this.module===n){this.container.querySelectorAll("#node-"+t+" .outputs .output").forEach((t,e)=>{const n=t.classList[1].slice(7);parseInt(c){this.drawflow.drawflow[n].data[e.node].inputs[e.output].connections.forEach((i,s)=>{if(i.node==t){const o=i.input.slice(7);if(parseInt(c)0||this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points!==[]?this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.splice(d,0,{pos_x:l,pos_y:c}):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),t.parentElement.querySelectorAll(".main-path").forEach((t,e)=>{t.classList.remove("selected")})):this.drawflow.drawflow[this.module].data[r].outputs[i].connections[h].points.push({pos_x:l,pos_y:c}),this.dispatch("addReroute",r),this.updateConnectionNodes(e)},o.prototype.removeReroutePoint=function(t){const e=t.parentElement.classList[2].slice(9),n=t.parentElement.classList[1].slice(13),i=t.parentElement.classList[3],s=t.parentElement.classList[4];let o=Array.from(t.parentElement.children).indexOf(t);const l=e.slice(5),c=this.drawflow.drawflow[this.module].data[l].outputs[i].connections.findIndex((function(t,e){return t.node===n&&t.output===s}));if(this.reroute_fix_curvature){const e=t.parentElement.querySelectorAll(".main-path").length;t.parentElement.children[e-1].remove(),o-=e,o<0&&(o=0)}else o--;this.drawflow.drawflow[this.module].data[l].outputs[i].connections[c].points.splice(o,1),t.remove(),this.dispatch("removeReroute",l),this.updateConnectionNodes(e)},o.prototype.addRerouteImport=function(t){const e=this.reroute_width,n=this.reroute_fix_curvature,i=this.container;Object.keys(t.outputs).map((function(s,o){Object.keys(t.outputs[s].connections).map((function(o,l){const c=t.outputs[s].connections[o].points;void 0!==c&&c.forEach((l,d)=>{const a=t.outputs[s].connections[o].node,r=t.outputs[s].connections[o].output,h=i.querySelector(".connection.node_in_node-"+a+".node_out_node-"+t.id+"."+s+"."+r);if(n&&0===d)for(var u=0;u 100) { - if (curDiff > this.prevDiff) { - // The distance between the two pointers has increased - - this.zoom_in(); - } - if (curDiff < this.prevDiff) { - // The distance between the two pointers has decreased - this.zoom_out(); - } - } - this.prevDiff = curDiff; - } - } - - pointerup_handler(ev) { - this.remove_event(ev); - if (this.evCache.length < 2) { - this.prevDiff = -1; - } - } - remove_event(ev) { - // Remove this event from the target's cache - for (var i = 0; i < this.evCache.length; i++) { - if (this.evCache[i].pointerId == ev.pointerId) { - this.evCache.splice(i, 1); - break; - } - } - } - /* End Mobile Zoom */ load() { for (var key in this.drawflow.drawflow[this.module].data) { this.addNodeImport(this.drawflow.drawflow[this.module].data[key], this.precanvas); @@ -164,7 +189,7 @@ export default class Drawflow { this.nodeId = number; } - removeReouteConnectionSelected(){ + removeReouteConnectionSelected() { this.dispatch('connectionUnselected', true); if(this.reroute_fix_curvature) { this.connection_selected.parentElement.querySelectorAll(".main-path").forEach((item, i) => { @@ -350,8 +375,8 @@ export default class Drawflow { this.updateConnection(e_pos_x, e_pos_y); } if(this.editor_selected) { - x = this.canvas_x + (-(this.pos_x - e_pos_x)) - y = this.canvas_y + (-(this.pos_y - e_pos_y)) + var x = this.canvas_x + (-(this.pos_x - e_pos_x)) + var y = this.canvas_y + (-(this.pos_y - e_pos_y)) this.dispatch('translate', { x: x, y: y}); this.precanvas.style.transform = "translate("+x+"px, "+y+"px) scale("+this.zoom+")"; } @@ -518,6 +543,7 @@ export default class Drawflow { this.dispatch('mouseUp', e); } + contextmenu(e) { this.dispatch('contextmenu', e); e.preventDefault(); @@ -546,6 +572,7 @@ export default class Drawflow { } } + contextmenuDel() { if(this.precanvas.getElementsByClassName("drawflow-delete").length) { this.precanvas.getElementsByClassName("drawflow-delete")[0].remove() @@ -569,1385 +596,75 @@ export default class Drawflow { } } - zoom_enter(event, delta) { - if (event.ctrlKey) { - event.preventDefault() - if(event.deltaY > 0) { - // Zoom Out - this.zoom_out(); - } else { - // Zoom In - this.zoom_in(); - } - } - } - zoom_refresh(){ - this.dispatch('zoom', this.zoom); - this.canvas_x = (this.canvas_x / this.zoom_last_value) * this.zoom; - this.canvas_y = (this.canvas_y / this.zoom_last_value) * this.zoom; - this.zoom_last_value = this.zoom; - this.precanvas.style.transform = "translate("+this.canvas_x+"px, "+this.canvas_y+"px) scale("+this.zoom+")"; - } - zoom_in() { - if(this.zoom < this.zoom_max) { - this.zoom+=this.zoom_value; - this.zoom_refresh(); - } - } - zoom_out() { - if(this.zoom > this.zoom_min) { - this.zoom-=this.zoom_value; - this.zoom_refresh(); - } - } - zoom_reset(){ - if(this.zoom != 1) { - this.zoom = 1; - this.zoom_refresh(); - } - } - + // Utility method for curvature createCurvature(start_pos_x, start_pos_y, end_pos_x, end_pos_y, curvature_value, type) { - var line_x = start_pos_x; - var line_y = start_pos_y; - var x = end_pos_x; - var y = end_pos_y; - var curvature = curvature_value; - //type openclose open close other - switch (type) { - case 'open': - if(start_pos_x >= end_pos_x) { - var hx1 = line_x + Math.abs(x - line_x) * curvature; - var hx2 = x - Math.abs(x - line_x) * (curvature*-1); - } else { - var hx1 = line_x + Math.abs(x - line_x) * curvature; - var hx2 = x - Math.abs(x - line_x) * curvature; - } - return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; - - break - case 'close': - if(start_pos_x >= end_pos_x) { - var hx1 = line_x + Math.abs(x - line_x) * (curvature*-1); - var hx2 = x - Math.abs(x - line_x) * curvature; - } else { - var hx1 = line_x + Math.abs(x - line_x) * curvature; - var hx2 = x - Math.abs(x - line_x) * curvature; - } - return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; - break; - case 'other': - if(start_pos_x >= end_pos_x) { - var hx1 = line_x + Math.abs(x - line_x) * (curvature*-1); - var hx2 = x - Math.abs(x - line_x) * (curvature*-1); - } else { - var hx1 = line_x + Math.abs(x - line_x) * curvature; - var hx2 = x - Math.abs(x - line_x) * curvature; - } - return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; - break; - default: - - var hx1 = line_x + Math.abs(x - line_x) * curvature; - var hx2 = x - Math.abs(x - line_x) * curvature; - - return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; - } - - } - - drawConnection(ele) { - var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - this.connection_ele = connection; - var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); - path.classList.add("main-path"); - path.setAttributeNS(null, 'd', ''); - // path.innerHTML = 'a'; - connection.classList.add("connection"); - connection.appendChild(path); - this.precanvas.appendChild(connection); - var id_output = ele.parentElement.parentElement.id.slice(5); - var output_class = ele.classList[1]; - this.dispatch('connectionStart', { output_id: id_output, output_class: output_class }); - - } - - updateConnection(eX, eY) { - const precanvas = this.precanvas; - const zoom = this.zoom; - let precanvasWitdhZoom = precanvas.clientWidth / (precanvas.clientWidth * zoom); - precanvasWitdhZoom = precanvasWitdhZoom || 0; - let precanvasHeightZoom = precanvas.clientHeight / (precanvas.clientHeight * zoom); - precanvasHeightZoom = precanvasHeightZoom || 0; - var path = this.connection_ele.children[0]; - - var line_x = this.ele_selected.offsetWidth/2 + (this.ele_selected.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = this.ele_selected.offsetHeight/2 + (this.ele_selected.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var x = eX * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) - (this.precanvas.getBoundingClientRect().x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) ); - var y = eY * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) - (this.precanvas.getBoundingClientRect().y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) ); - - var curvature = this.curvature; - var lineCurve = this.createCurvature(line_x, line_y, x, y, curvature, 'openclose'); - path.setAttributeNS(null, 'd', lineCurve); - - } - - addConnection(id_output, id_input, output_class, input_class) { - var nodeOneModule = this.getModuleFromNodeId(id_output); - var nodeTwoModule = this.getModuleFromNodeId(id_input); - if(nodeOneModule === nodeTwoModule) { - - var dataNode = this.getNodeFromId(id_output); - var exist = false; - for(var checkOutput in dataNode.outputs[output_class].connections){ - var connectionSearch = dataNode.outputs[output_class].connections[checkOutput] - if(connectionSearch.node == id_input && connectionSearch.output == input_class) { - exist = true; - } - } - // Check connection exist - if(exist === false) { - //Create Connection - this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.push( {"node": id_input.toString(), "output": input_class}); - this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.push( {"node": id_output.toString(), "input": output_class}); - - if(this.module === nodeOneModule) { - //Draw connection - var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); - path.classList.add("main-path"); - path.setAttributeNS(null, 'd', ''); - // path.innerHTML = 'a'; - connection.classList.add("connection"); - connection.classList.add("node_in_node-"+id_input); - connection.classList.add("node_out_node-"+id_output); - connection.classList.add(output_class); - connection.classList.add(input_class); - connection.appendChild(path); - this.precanvas.appendChild(connection); - 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}); - } - } - } - - updateConnectionNodes(id) { - - // Aquí nos quedamos; - const idSearch = 'node_in_'+id; - const idSearchOut = 'node_out_'+id; - var line_path = this.line_path/2; - const container = this.container; - const precanvas = this.precanvas; - const curvature = this.curvature; - const createCurvature = this.createCurvature; - const reroute_curvature = this.reroute_curvature; - const reroute_curvature_start_end = this.reroute_curvature_start_end; - const reroute_fix_curvature = this.reroute_fix_curvature; - const rerouteWidth = this.reroute_width; - const zoom = this.zoom; - let precanvasWitdhZoom = precanvas.clientWidth / (precanvas.clientWidth * zoom); - precanvasWitdhZoom = precanvasWitdhZoom || 0; - let precanvasHeightZoom = precanvas.clientHeight / (precanvas.clientHeight * zoom); - precanvasHeightZoom = precanvasHeightZoom || 0; - - const elemsOut = container.querySelectorAll(`.${idSearchOut}`); - - Object.keys(elemsOut).map(function(item, index) { - if(elemsOut[item].querySelector('.point') === null) { - - var elemtsearchId_out = container.querySelector(`#${id}`); - - var id_search = elemsOut[item].classList[1].replace('node_in_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - - var elemtsearch = elemtsearchId.querySelectorAll('.'+elemsOut[item].classList[4])[0] - - var eX = elemtsearch.offsetWidth/2 + (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var eY = elemtsearch.offsetHeight/2 + (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+elemsOut[item].classList[3])[0] - - var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var x = eX; - var y = eY; - - const lineCurve = createCurvature(line_x, line_y, x, y, curvature, 'openclose'); - elemsOut[item].children[0].setAttributeNS(null, 'd', lineCurve ); - } else { - const points = elemsOut[item].querySelectorAll('.point'); - let linecurve = ''; - const reoute_fix = []; - points.forEach((item, i) => { - if(i === 0 && ((points.length -1) === 0)) { - - var elemtsearchId_out = container.querySelector(`#${id}`); - var elemtsearch = item; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - - var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[3])[0] - var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - var elemtsearchId_out = item; - var id_search = item.parentElement.classList[1].replace('node_in_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - - var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - } else if(i === 0) { - - var elemtsearchId_out = container.querySelector(`#${id}`); - var elemtsearch = item; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - - var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[3])[0] - var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - // SECOND - var elemtsearchId_out = item; - var elemtsearch = points[i+1]; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - } else if (i === (points.length -1)) { - - var elemtsearchId_out = item; - - var id_search = item.parentElement.classList[1].replace('node_in_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - - var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - } else { - var elemtsearchId_out = item; - var elemtsearch = points[i+1]; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) +rerouteWidth; - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - } - - }); - if(reroute_fix_curvature) { - reoute_fix.forEach((itempath, i) => { - elemsOut[item].children[i].setAttributeNS(null, 'd', itempath); - }); - - } else { - elemsOut[item].children[0].setAttributeNS(null, 'd', linecurve); - } - - } - }) - - const elems = container.querySelectorAll(`.${idSearch}`); - Object.keys(elems).map(function(item, index) { - - if(elems[item].querySelector('.point') === null) { - var elemtsearchId_in = container.querySelector(`#${id}`); - - var id_search = elems[item].classList[2].replace('node_out_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+elems[item].classList[3])[0] - - var line_x = elemtsearch.offsetWidth/2 + (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearch.offsetHeight/2 + (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var elemtsearchId_in = elemtsearchId_in.querySelectorAll('.'+elems[item].classList[4])[0] - var x = elemtsearchId_in.offsetWidth/2 + (elemtsearchId_in.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var y = elemtsearchId_in.offsetHeight/2 + (elemtsearchId_in.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - const lineCurve = createCurvature(line_x, line_y, x, y, curvature, 'openclose'); - elems[item].children[0].setAttributeNS(null, 'd', lineCurve ); - - } else { - const points = elems[item].querySelectorAll('.point'); - let linecurve = ''; - const reoute_fix = []; - points.forEach((item, i) => { - if(i === 0 && ((points.length -1) === 0)) { - - var elemtsearchId_out = container.querySelector(`#${id}`); - var elemtsearch = item; - - var line_x = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; - - var elemtsearchIn = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[4])[0] - var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - var elemtsearchId_out = item; - var id_search = item.parentElement.classList[2].replace('node_out_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] - - var elemtsearchOut = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] - var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var eX = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - - } else if(i === 0) { - // FIRST - var elemtsearchId_out = item; - var id_search = item.parentElement.classList[2].replace('node_out_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] - var elemtsearchOut = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] - var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var eX = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - // SECOND - var elemtsearchId_out = item; - var elemtsearch = points[i+1]; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - } else if (i === (points.length -1)) { - - var elemtsearchId_out = item; - - var id_search = item.parentElement.classList[1].replace('node_in_', ''); - var elemtsearchId = container.querySelector(`#${id_search}`); - var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - - var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] - var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; - var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; - - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - - } else { - - var elemtsearchId_out = item; - var elemtsearch = points[i+1]; - - var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; - var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; - var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; - var x = eX; - var y = eY; - - var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); - linecurve += lineCurveSearch; - reoute_fix.push(lineCurveSearch); - } - - }); - if(reroute_fix_curvature) { - reoute_fix.forEach((itempath, i) => { - elems[item].children[i].setAttributeNS(null, 'd', itempath); - }); - - } else { - elems[item].children[0].setAttributeNS(null, 'd', linecurve); - } - - } - }) - } - - dblclick(e) { - if(this.connection_selected != null && this.reroute) { - this.createReroutePoint(this.connection_selected); - } - - if(e.target.classList[0] === 'point') { - this.removeReroutePoint(e.target); - } - } - - createReroutePoint(ele) { - this.connection_selected.classList.remove("selected"); - const nodeUpdate = this.connection_selected.parentElement.classList[2].slice(9); - const nodeUpdateIn = this.connection_selected.parentElement.classList[1].slice(13); - const output_class = this.connection_selected.parentElement.classList[3]; - const input_class = this.connection_selected.parentElement.classList[4]; - this.connection_selected = null; - const point = document.createElementNS('http://www.w3.org/2000/svg',"circle"); - point.classList.add("point"); - var pos_x = this.pos_x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) - (this.precanvas.getBoundingClientRect().x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom))); - var pos_y = this.pos_y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) - (this.precanvas.getBoundingClientRect().y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom))); - - point.setAttributeNS(null, 'cx', pos_x); - point.setAttributeNS(null, 'cy', pos_y); - point.setAttributeNS(null, 'r', this.reroute_width); - - let position_add_array_point = 0; - if(this.reroute_fix_curvature) { - - const numberPoints = ele.parentElement.querySelectorAll(".main-path").length; - var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); - path.classList.add("main-path"); - path.setAttributeNS(null, 'd', ''); - - ele.parentElement.insertBefore(path, ele.parentElement.children[numberPoints]); - if(numberPoints === 1) { - ele.parentElement.appendChild(point); - } else { - const search_point = Array.from(ele.parentElement.children).indexOf(ele) - position_add_array_point = search_point; - ele.parentElement.insertBefore(point, ele.parentElement.children[search_point+numberPoints+1]); - } - - } else { - ele.parentElement.appendChild(point); - } - - const nodeId = nodeUpdate.slice(5); - const searchConnection = this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections.findIndex(function(item,i) { - return item.node === nodeUpdateIn && item.output === input_class; - }); - - if(this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points === undefined) { - this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points = []; - } - - if(this.reroute_fix_curvature) { - - if(position_add_array_point > 0 || this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points !== []) { - this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.splice(position_add_array_point, 0, { pos_x: pos_x, pos_y: pos_y }); - } else { - this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.push({ pos_x: pos_x, pos_y: pos_y }); - } - - ele.parentElement.querySelectorAll(".main-path").forEach((item, i) => { - item.classList.remove("selected"); - }); - - } else { - this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.push({ pos_x: pos_x, pos_y: pos_y }); - } - - this.dispatch('addReroute', nodeId); - this.updateConnectionNodes(nodeUpdate); - } - - removeReroutePoint(ele) { - const nodeUpdate = ele.parentElement.classList[2].slice(9) - const nodeUpdateIn = ele.parentElement.classList[1].slice(13); - const output_class = ele.parentElement.classList[3]; - const input_class = ele.parentElement.classList[4]; - - let numberPointPosition = Array.from(ele.parentElement.children).indexOf(ele); - const nodeId = nodeUpdate.slice(5); - const searchConnection = this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections.findIndex(function(item,i) { - return item.node === nodeUpdateIn && item.output === input_class; - }); - - if(this.reroute_fix_curvature) { - const numberMainPath = ele.parentElement.querySelectorAll(".main-path").length - ele.parentElement.children[numberMainPath-1].remove(); - numberPointPosition -= numberMainPath; - if(numberPointPosition < 0) { - numberPointPosition = 0; - } - } else { - numberPointPosition--; - } - this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.splice(numberPointPosition,1); - - ele.remove(); - this.dispatch('removeReroute', nodeId); - this.updateConnectionNodes(nodeUpdate); - } - - registerNode(name, html, props = null, options = null) { - this.noderegister[name] = {html: html, props: props, options: options}; - } - - getNodeFromId(id) { - var moduleName = this.getModuleFromNodeId(id) - return JSON.parse(JSON.stringify(this.drawflow.drawflow[moduleName].data[id])); - } - getNodesFromName(name) { - var nodes = []; - const editor = this.drawflow.drawflow - Object.keys(editor).map(function(moduleName, index) { - for (var node in editor[moduleName].data) { - if(editor[moduleName].data[node].name == name) { - nodes.push(editor[moduleName].data[node].id); - } - } - }); - return nodes; - } - - addNode (name, num_in, num_out, ele_pos_x, ele_pos_y, classoverride, data, html, typenode = false) { - if (this.useuuid) { - var newNodeId = this.getUuid(); - } else { - var newNodeId = this.nodeId; - } - const parent = document.createElement('div'); - parent.classList.add("parent-node"); - - const node = document.createElement('div'); - node.innerHTML = ""; - node.setAttribute("id", "node-"+newNodeId); - node.classList.add("drawflow-node"); - if(classoverride != '') { - node.classList.add(...classoverride.split(' ')); - } - - const inputs = document.createElement('div'); - inputs.classList.add("inputs"); - - const outputs = document.createElement('div'); - outputs.classList.add("outputs"); - - const json_inputs = {} - for(var x = 0; x < num_in; x++) { - const input = document.createElement('div'); - input.classList.add("input"); - input.classList.add("input_"+(x+1)); - json_inputs["input_"+(x+1)] = { "connections": []}; - inputs.appendChild(input); - } - - const json_outputs = {} - for(var x = 0; x < num_out; x++) { - const output = document.createElement('div'); - output.classList.add("output"); - output.classList.add("output_"+(x+1)); - json_outputs["output_"+(x+1)] = { "connections": []}; - outputs.appendChild(output); - } - - const content = document.createElement('div'); - content.classList.add("drawflow_content_node"); - if(typenode === false) { - content.innerHTML = html; - } else if (typenode === true) { - content.appendChild(this.noderegister[html].html.cloneNode(true)); - } else { - if(parseInt(this.render.version) === 3 ) { - //Vue 3 - let wrapper = this.render.h(this.noderegister[html].html, this.noderegister[html].props, this.noderegister[html].options); - wrapper.appContext = this.parent; - this.render.render(wrapper,content); - - } else { - // Vue 2 - let wrapper = new this.render({ - parent: this.parent, - render: h => h(this.noderegister[html].html, { props: this.noderegister[html].props }), - ...this.noderegister[html].options - }).$mount() - // - content.appendChild(wrapper.$el); - } - } - - Object.entries(data).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(null, key[0], key[0]); - } else { - var elems = content.querySelectorAll('[df-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }) - - function insertObjectkeys(object, name, completname) { - if(object === null) { - var object = data[name]; - } else { - var object = object[name] - } - if(object !== null) { - Object.entries(object).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(object, key[0], completname+'-'+key[0]); - } else { - var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }); - } - } - node.appendChild(inputs); - node.appendChild(content); - node.appendChild(outputs); - node.style.top = ele_pos_y + "px"; - node.style.left = ele_pos_x + "px"; - parent.appendChild(node); - this.precanvas.appendChild(parent); - var json = { - id: newNodeId, - name: name, - data: data, - class: classoverride, - html: html, - typenode: typenode, - inputs: json_inputs, - outputs: json_outputs, - pos_x: ele_pos_x, - pos_y: ele_pos_y, - } - this.drawflow.drawflow[this.module].data[newNodeId] = json; - this.dispatch('nodeCreated', newNodeId); - if (!this.useuuid) { - this.nodeId++; - } - return newNodeId; + return createCurvature(start_pos_x, start_pos_y, end_pos_x, end_pos_y, curvature_value, type); } - addNodeImport (dataNode, precanvas) { - const parent = document.createElement('div'); - parent.classList.add("parent-node"); - - const node = document.createElement('div'); - node.innerHTML = ""; - node.setAttribute("id", "node-"+dataNode.id); - node.classList.add("drawflow-node"); - if(dataNode.class != '') { - node.classList.add(...dataNode.class.split(' ')); - } - - const inputs = document.createElement('div'); - inputs.classList.add("inputs"); - - const outputs = document.createElement('div'); - outputs.classList.add("outputs"); - - Object.keys(dataNode.inputs).map(function(input_item, index) { - const input = document.createElement('div'); - input.classList.add("input"); - input.classList.add(input_item); - inputs.appendChild(input); - Object.keys(dataNode.inputs[input_item].connections).map(function(output_item, index) { - - var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); - var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); - path.classList.add("main-path"); - path.setAttributeNS(null, 'd', ''); - // path.innerHTML = 'a'; - connection.classList.add("connection"); - connection.classList.add("node_in_node-"+dataNode.id); - connection.classList.add("node_out_node-"+dataNode.inputs[input_item].connections[output_item].node); - connection.classList.add(dataNode.inputs[input_item].connections[output_item].input); - connection.classList.add(input_item); - - connection.appendChild(path); - precanvas.appendChild(connection); - - }); - }); - - for(var x = 0; x < Object.keys(dataNode.outputs).length; x++) { - const output = document.createElement('div'); - output.classList.add("output"); - output.classList.add("output_"+(x+1)); - outputs.appendChild(output); - } - - const content = document.createElement('div'); - content.classList.add("drawflow_content_node"); - - if(dataNode.typenode === false) { - content.innerHTML = dataNode.html; - } else if (dataNode.typenode === true) { - content.appendChild(this.noderegister[dataNode.html].html.cloneNode(true)); - } else { - if(parseInt(this.render.version) === 3 ) { - //Vue 3 - let wrapper = this.render.h(this.noderegister[dataNode.html].html, this.noderegister[dataNode.html].props, this.noderegister[dataNode.html].options); - wrapper.appContext = this.parent; - this.render.render(wrapper,content); - - } else { - //Vue 2 - let wrapper = new this.render({ - parent: this.parent, - render: h => h(this.noderegister[dataNode.html].html, { props: this.noderegister[dataNode.html].props }), - ...this.noderegister[dataNode.html].options - }).$mount() - content.appendChild(wrapper.$el); - } - } - - Object.entries(dataNode.data).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(null, key[0], key[0]); - } else { - var elems = content.querySelectorAll('[df-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }) - - function insertObjectkeys(object, name, completname) { - if(object === null) { - var object = dataNode.data[name]; - } else { - var object = object[name] - } - if(object !== null) { - Object.entries(object).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(object, key[0], completname+'-'+key[0]); - } else { - var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }); - } - } - node.appendChild(inputs); - node.appendChild(content); - node.appendChild(outputs); - node.style.top = dataNode.pos_y + "px"; - node.style.left = dataNode.pos_x + "px"; - parent.appendChild(node); - this.precanvas.appendChild(parent); + // Utility method for UUID + getUuid() { + return getUuid(); } - addRerouteImport(dataNode) { - const reroute_width = this.reroute_width - const reroute_fix_curvature = this.reroute_fix_curvature - const container = this.container; - Object.keys(dataNode.outputs).map(function(output_item, index) { - Object.keys(dataNode.outputs[output_item].connections).map(function(input_item, index) { - const points = dataNode.outputs[output_item].connections[input_item].points - if(points !== undefined) { - - points.forEach((item, i) => { - const input_id = dataNode.outputs[output_item].connections[input_item].node; - const input_class = dataNode.outputs[output_item].connections[input_item].output; - const ele = container.querySelector('.connection.node_in_node-'+input_id+'.node_out_node-'+dataNode.id+'.'+output_item+'.'+input_class); - - if(reroute_fix_curvature) { - if(i === 0) { - for (var z = 0; z < points.length; z++) { - var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); - path.classList.add("main-path"); - path.setAttributeNS(null, 'd', ''); - ele.appendChild(path); - - } - } - } - - const point = document.createElementNS('http://www.w3.org/2000/svg',"circle"); - point.classList.add("point"); - var pos_x = item.pos_x; - var pos_y = item.pos_y; - - point.setAttributeNS(null, 'cx', pos_x); - point.setAttributeNS(null, 'cy', pos_y); - point.setAttributeNS(null, 'r', reroute_width); - - ele.appendChild(point); - }); - }; - }); - }); + // Export and import wrappers for backwards compatibility + export() { + return this.exportDrawflow(); } - updateNodeValue(event) { - var attr = event.target.attributes - for (var i = 0; i < attr.length; i++) { - if (attr[i].nodeName.startsWith('df-')) { - var keys = attr[i].nodeName.slice(3).split("-"); - var target = this.drawflow.drawflow[this.module].data[event.target.closest(".drawflow_content_node").parentElement.id.slice(5)].data; - for (var index = 0; index < keys.length - 1; index += 1) { - if (target[keys[index]] == null) { - target[keys[index]] = {}; - } - target = target[keys[index]]; - } - target[keys[keys.length - 1]] = event.target.value; - if(event.target.isContentEditable) { - target[keys[keys.length - 1]] = event.target.innerText; - } - this.dispatch('nodeDataChanged', event.target.closest(".drawflow_content_node").parentElement.id.slice(5)); - } - } - } - - updateNodeDataFromId(id, data) { - var moduleName = this.getModuleFromNodeId(id) - this.drawflow.drawflow[moduleName].data[id].data = data; - if(this.module === moduleName) { - const content = this.container.querySelector('#node-'+id); - - Object.entries(data).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(null, key[0], key[0]); - } else { - var elems = content.querySelectorAll('[df-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }) - - function insertObjectkeys(object, name, completname) { - if(object === null) { - var object = data[name]; - } else { - var object = object[name] - } - if(object !== null) { - Object.entries(object).forEach(function (key, value) { - if(typeof key[1] === "object") { - insertObjectkeys(object, key[0], completname+'-'+key[0]); - } else { - var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); - for(var i = 0; i < elems.length; i++) { - elems[i].value = key[1]; - if(elems[i].isContentEditable) { - elems[i].innerText = key[1]; - } - } - } - }); - } - } - - } - } - - addNodeInput(id) { - var moduleName = this.getModuleFromNodeId(id) - const infoNode = this.getNodeFromId(id) - const numInputs = Object.keys(infoNode.inputs).length; - if(this.module === moduleName) { - //Draw input - const input = document.createElement('div'); - input.classList.add("input"); - input.classList.add("input_"+(numInputs+1)); - const parent = this.container.querySelector('#node-'+id+' .inputs'); - parent.appendChild(input); - this.updateConnectionNodes('node-'+id); - - } - this.drawflow.drawflow[moduleName].data[id].inputs["input_"+(numInputs+1)] = { "connections": []}; - } - - addNodeOutput(id) { - var moduleName = this.getModuleFromNodeId(id) - const infoNode = this.getNodeFromId(id) - const numOutputs = Object.keys(infoNode.outputs).length; - if(this.module === moduleName) { - //Draw output - const output = document.createElement('div'); - output.classList.add("output"); - output.classList.add("output_"+(numOutputs+1)); - const parent = this.container.querySelector('#node-'+id+' .outputs'); - parent.appendChild(output); - this.updateConnectionNodes('node-'+id); - - } - this.drawflow.drawflow[moduleName].data[id].outputs["output_"+(numOutputs+1)] = { "connections": []}; + import(data, notifi = true) { + return this.importDrawflow(data, notifi); } - - removeNodeInput(id, input_class) { - var moduleName = this.getModuleFromNodeId(id) - const infoNode = this.getNodeFromId(id) - if(this.module === moduleName) { - this.container.querySelector('#node-'+id+' .inputs .input.'+input_class).remove(); - } - const removeInputs = []; - Object.keys(infoNode.inputs[input_class].connections).map(function(key, index) { - const id_output = infoNode.inputs[input_class].connections[index].node; - const output_class = infoNode.inputs[input_class].connections[index].input; - removeInputs.push({id_output, id, output_class, input_class}) - }) - // Remove connections - removeInputs.forEach((item, i) => { - this.removeSingleConnection(item.id_output, item.id, item.output_class, item.input_class); - }); - - delete this.drawflow.drawflow[moduleName].data[id].inputs[input_class]; - - // Update connection - const connections = []; - const connectionsInputs = this.drawflow.drawflow[moduleName].data[id].inputs - Object.keys(connectionsInputs).map(function(key, index) { - connections.push(connectionsInputs[key]); - }); - this.drawflow.drawflow[moduleName].data[id].inputs = {}; - const input_class_id = input_class.slice(6); - let nodeUpdates = []; - connections.forEach((item, i) => { - item.connections.forEach((itemx, f) => { - nodeUpdates.push(itemx); - }); - this.drawflow.drawflow[moduleName].data[id].inputs['input_'+ (i+1)] = item; - }); - nodeUpdates = new Set(nodeUpdates.map(e => JSON.stringify(e))); - nodeUpdates = Array.from(nodeUpdates).map(e => JSON.parse(e)); - - if(this.module === moduleName) { - const eles = this.container.querySelectorAll("#node-"+id +" .inputs .input"); - eles.forEach((item, i) => { - const id_class = item.classList[1].slice(6); - if(parseInt(input_class_id) < parseInt(id_class)) { - item.classList.remove('input_'+id_class); - item.classList.add('input_'+(id_class-1)); - } - }); - - } - - nodeUpdates.forEach((itemx, i) => { - this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections.forEach((itemz, g) => { - if(itemz.node == id) { - const output_id = itemz.output.slice(6); - if(parseInt(input_class_id) < parseInt(output_id)) { - if(this.module === moduleName) { - const ele = this.container.querySelector(".connection.node_in_node-"+id+".node_out_node-"+itemx.node+"."+itemx.input+".input_"+output_id); - ele.classList.remove('input_'+output_id); - ele.classList.add('input_'+(output_id-1)); - } - if(itemz.points) { - this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections[g] = { node: itemz.node, output: 'input_'+(output_id-1), points: itemz.points } - } else { - this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections[g] = { node: itemz.node, output: 'input_'+(output_id-1)} - } - } - } - }); - }); - this.updateConnectionNodes('node-'+id); - } - - removeNodeOutput(id, output_class) { - var moduleName = this.getModuleFromNodeId(id) - const infoNode = this.getNodeFromId(id) - if(this.module === moduleName) { - this.container.querySelector('#node-'+id+' .outputs .output.'+output_class).remove(); - } - const removeOutputs = []; - Object.keys(infoNode.outputs[output_class].connections).map(function(key, index) { - const id_input = infoNode.outputs[output_class].connections[index].node; - const input_class = infoNode.outputs[output_class].connections[index].output; - removeOutputs.push({id, id_input, output_class, input_class}) - }) - // Remove connections - removeOutputs.forEach((item, i) => { - this.removeSingleConnection(item.id, item.id_input, item.output_class, item.input_class); - }); - - delete this.drawflow.drawflow[moduleName].data[id].outputs[output_class]; - - // Update connection - const connections = []; - const connectionsOuputs = this.drawflow.drawflow[moduleName].data[id].outputs - Object.keys(connectionsOuputs).map(function(key, index) { - connections.push(connectionsOuputs[key]); - }); - this.drawflow.drawflow[moduleName].data[id].outputs = {}; - const output_class_id = output_class.slice(7); - let nodeUpdates = []; - connections.forEach((item, i) => { - item.connections.forEach((itemx, f) => { - nodeUpdates.push({ node: itemx.node, output: itemx.output }); - }); - this.drawflow.drawflow[moduleName].data[id].outputs['output_'+ (i+1)] = item; - }); - nodeUpdates = new Set(nodeUpdates.map(e => JSON.stringify(e))); - nodeUpdates = Array.from(nodeUpdates).map(e => JSON.parse(e)); - - if(this.module === moduleName) { - const eles = this.container.querySelectorAll("#node-"+id +" .outputs .output"); - eles.forEach((item, i) => { - const id_class = item.classList[1].slice(7); - if(parseInt(output_class_id) < parseInt(id_class)) { - item.classList.remove('output_'+id_class); - item.classList.add('output_'+(id_class-1)); - } - }); - - } - - nodeUpdates.forEach((itemx, i) => { - this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections.forEach((itemz, g) => { - if(itemz.node == id) { - const input_id = itemz.input.slice(7); - if(parseInt(output_class_id) < parseInt(input_id)) { - if(this.module === moduleName) { - - const ele = this.container.querySelector(".connection.node_in_node-"+itemx.node+".node_out_node-"+id+".output_"+input_id+"."+itemx.output); - ele.classList.remove('output_'+input_id); - ele.classList.remove(itemx.output); - ele.classList.add('output_'+(input_id-1)); - ele.classList.add(itemx.output); - } - if(itemz.points) { - this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections[g] = { node: itemz.node, input: 'output_'+(input_id-1), points: itemz.points } - } else { - this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections[g] = { node: itemz.node, input: 'output_'+(input_id-1)} - } - } - } - }); - }); - - this.updateConnectionNodes('node-'+id); - } - - removeNodeId(id) { - this.removeConnectionNodeId(id); - var moduleName = this.getModuleFromNodeId(id.slice(5)) - if(this.module === moduleName) { - this.container.querySelector(`#${id}`).remove(); - } - delete this.drawflow.drawflow[moduleName].data[id.slice(5)]; - this.dispatch('nodeRemoved', id.slice(5)); - } - - removeConnection() { - if(this.connection_selected != null) { - var listclass = this.connection_selected.parentElement.classList; - this.connection_selected.parentElement.remove(); - //console.log(listclass); - var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { - return item.node === listclass[1].slice(13) && item.output === listclass[4] - }); - this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); - - var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { - return item.node === listclass[2].slice(14) && item.input === listclass[3] - }); - this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); - this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); - this.connection_selected = null; - } - } - - removeSingleConnection(id_output, id_input, output_class, input_class) { - var nodeOneModule = this.getModuleFromNodeId(id_output); - var nodeTwoModule = this.getModuleFromNodeId(id_input); - if(nodeOneModule === nodeTwoModule) { - // Check nodes in same module. - - // Check connection exist - var exists = this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.findIndex(function(item,i) { - return item.node == id_input && item.output === input_class - }); - if(exists > -1) { - - if(this.module === nodeOneModule) { - // In same module with view. - this.container.querySelector('.connection.node_in_node-'+id_input+'.node_out_node-'+id_output+'.'+output_class+'.'+input_class).remove(); - } - - var index_out = this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.findIndex(function(item,i) { - return item.node == id_input && item.output === input_class - }); - this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.splice(index_out,1); - - var index_in = this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.findIndex(function(item,i) { - return item.node == id_output && item.input === output_class - }); - this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.splice(index_in,1); - - this.dispatch('connectionRemoved', { output_id: id_output, input_id: id_input, output_class: output_class, input_class: input_class}); - return true; - - } else { - return false; - } - } else { - return false; - } - } - - removeConnectionNodeId(id) { - const idSearchIn = 'node_in_'+id; - const idSearchOut = 'node_out_'+id; - - const elemsOut = this.container.querySelectorAll(`.${idSearchOut}`); - for(var i = elemsOut.length-1; i >= 0; i--) { - var listclass = elemsOut[i].classList; - - var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { - return item.node === listclass[2].slice(14) && item.input === listclass[3] - }); - this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); - - var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { - return item.node === listclass[1].slice(13) && item.output === listclass[4] - }); - this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); - - elemsOut[i].remove(); - - this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); - } - - const elemsIn = this.container.querySelectorAll(`.${idSearchIn}`); - for(var i = elemsIn.length-1; i >= 0; i--) { - - var listclass = elemsIn[i].classList; - - var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { - return item.node === listclass[1].slice(13) && item.output === listclass[4] - }); - this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); - - var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { - return item.node === listclass[2].slice(14) && item.input === listclass[3] - }); - this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); - - elemsIn[i].remove(); - - this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); - } - } - - getModuleFromNodeId(id) { - var nameModule; - const editor = this.drawflow.drawflow - Object.keys(editor).map(function(moduleName, index) { - Object.keys(editor[moduleName].data).map(function(node, index2) { - if(node == id) { - nameModule = moduleName; - } - }) - }); - return nameModule; - } - - addModule(name) { - this.drawflow.drawflow[name] = { "data": {} }; - this.dispatch('moduleCreated', name); - } - changeModule(name) { - this.dispatch('moduleChanged', name); - this.module = name; - this.precanvas.innerHTML = ""; - this.canvas_x = 0; - this.canvas_y = 0; - this.pos_x = 0; - this.pos_y = 0; - this.mouse_x = 0; - this.mouse_y = 0; - this.zoom = 1; - this.zoom_last_value = 1; - this.precanvas.style.transform = ''; - this.import(this.drawflow, false); - } - - removeModule(name) { - if(this.module === name) { - this.changeModule('Home'); - } - delete this.drawflow.drawflow[name]; - this.dispatch('moduleRemoved', name); - } - - clearModuleSelected() { - this.precanvas.innerHTML = ""; - this.drawflow.drawflow[this.module] = { "data": {} }; - } - - clear () { - this.precanvas.innerHTML = ""; - this.drawflow = { "drawflow": { "Home": { "data": {} }}}; - } - export () { - const dataExport = JSON.parse(JSON.stringify(this.drawflow)); - this.dispatch('export', dataExport); - return dataExport; - } - - import (data, notifi = true) { - this.clear(); - this.drawflow = JSON.parse(JSON.stringify(data)); - this.load(); - if(notifi) { - this.dispatch('import', 'import'); - } - } - - /* Events */ - on (event, callback) { - // Check if the callback is not a function - if (typeof callback !== 'function') { - console.error(`The listener callback must be a function, the given type is ${typeof callback}`); - return false; - } - // Check if the event is not a string - if (typeof event !== 'string') { - console.error(`The event name must be a string, the given type is ${typeof event}`); - return false; - } - // Check if this event not exists - if (this.events[event] === undefined) { - this.events[event] = { - listeners: [] - } - } - this.events[event].listeners.push(callback); - } - - removeListener (event, callback) { - // Check if this event not exists - - if (!this.events[event]) return false - - const listeners = this.events[event].listeners - const listenerIndex = listeners.indexOf(callback) - const hasListener = listenerIndex > -1 - if (hasListener) listeners.splice(listenerIndex, 1) - } - - dispatch (event, details) { - // Check if this event not exists - if (this.events[event] === undefined) { - // console.error(`This event: ${event} does not exist`); - return false; - } - this.events[event].listeners.forEach((listener) => { - listener(details); - }); - } - - getUuid() { - // http://www.ietf.org/rfc/rfc4122.txt - var s = []; - var hexDigits = "0123456789abcdef"; - for (var i = 0; i < 36; i++) { - s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); - } - s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 - s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 - s[8] = s[13] = s[18] = s[23] = "-"; - - var uuid = s.join(""); - return uuid; - } } + +// Assign module methods to prototype +// Mobile handlers +Drawflow.prototype.pointerdown_handler = pointerdown_handler; +Drawflow.prototype.pointermove_handler = pointermove_handler; +Drawflow.prototype.pointerup_handler = pointerup_handler; +Drawflow.prototype.remove_event = remove_event; + +// Zoom handlers +Drawflow.prototype.zoom_enter = zoom_enter; +Drawflow.prototype.zoom_refresh = zoom_refresh; +Drawflow.prototype.zoom_in = zoom_in; +Drawflow.prototype.zoom_out = zoom_out; +Drawflow.prototype.zoom_reset = zoom_reset; + +// Connection management +Drawflow.prototype.drawConnection = drawConnection; +Drawflow.prototype.updateConnection = updateConnection; +Drawflow.prototype.addConnection = addConnection; +Drawflow.prototype.updateConnectionNodes = updateConnectionNodes; +Drawflow.prototype.removeConnection = removeConnection; +Drawflow.prototype.removeSingleConnection = removeSingleConnection; +Drawflow.prototype.removeConnectionNodeId = removeConnectionNodeId; + +// Node management +Drawflow.prototype.registerNode = registerNode; +Drawflow.prototype.getNodeFromId = getNodeFromId; +Drawflow.prototype.getNodesFromName = getNodesFromName; +Drawflow.prototype.addNode = addNode; +Drawflow.prototype.addNodeImport = addNodeImport; +Drawflow.prototype.updateNodeValue = updateNodeValue; +Drawflow.prototype.updateNodeDataFromId = updateNodeDataFromId; +Drawflow.prototype.addNodeInput = addNodeInput; +Drawflow.prototype.addNodeOutput = addNodeOutput; +Drawflow.prototype.removeNodeInput = removeNodeInput; +Drawflow.prototype.removeNodeOutput = removeNodeOutput; +Drawflow.prototype.removeNodeId = removeNodeId; + +// Reroute management +Drawflow.prototype.dblclick = dblclick; +Drawflow.prototype.createReroutePoint = createReroutePoint; +Drawflow.prototype.removeReroutePoint = removeReroutePoint; +Drawflow.prototype.addRerouteImport = addRerouteImport; + +// Module management +Drawflow.prototype.getModuleFromNodeId = getModuleFromNodeId; +Drawflow.prototype.addModule = addModule; +Drawflow.prototype.changeModule = changeModule; +Drawflow.prototype.removeModule = removeModule; +Drawflow.prototype.clearModuleSelected = clearModuleSelected; +Drawflow.prototype.clear = clear; +Drawflow.prototype.exportDrawflow = exportDrawflow; +Drawflow.prototype.importDrawflow = importDrawflow; diff --git a/src/modules/ConnectionManager.js b/src/modules/ConnectionManager.js new file mode 100644 index 0000000..9a81353 --- /dev/null +++ b/src/modules/ConnectionManager.js @@ -0,0 +1,536 @@ +/** + * Connection management module + * Handles drawing, updating, adding and removing connections + */ + +import { createCurvature } from '../utils/curvature.js'; + +/** + * Start drawing a new connection + * @param {HTMLElement} ele - Output element to connect from + */ +export function drawConnection(ele) { + var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + this.connection_ele = connection; + var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); + path.classList.add("main-path"); + path.setAttributeNS(null, 'd', ''); + // path.innerHTML = 'a'; + connection.classList.add("connection"); + connection.appendChild(path); + this.precanvas.appendChild(connection); + var id_output = ele.parentElement.parentElement.id.slice(5); + var output_class = ele.classList[1]; + this.dispatch('connectionStart', { output_id: id_output, output_class: output_class }); +} + +/** + * Update connection path while dragging + * @param {number} eX - Mouse X position + * @param {number} eY - Mouse Y position + */ +export function updateConnection(eX, eY) { + const precanvas = this.precanvas; + const zoom = this.zoom; + let precanvasWitdhZoom = precanvas.clientWidth / (precanvas.clientWidth * zoom); + precanvasWitdhZoom = precanvasWitdhZoom || 0; + let precanvasHeightZoom = precanvas.clientHeight / (precanvas.clientHeight * zoom); + precanvasHeightZoom = precanvasHeightZoom || 0; + var path = this.connection_ele.children[0]; + + var line_x = this.ele_selected.offsetWidth/2 + (this.ele_selected.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = this.ele_selected.offsetHeight/2 + (this.ele_selected.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var x = eX * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) - (this.precanvas.getBoundingClientRect().x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) ); + var y = eY * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) - (this.precanvas.getBoundingClientRect().y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) ); + + var curvature = this.curvature; + var lineCurve = createCurvature(line_x, line_y, x, y, curvature, 'openclose'); + path.setAttributeNS(null, 'd', lineCurve); +} + +/** + * Add a connection between two nodes + * @param {string|number} id_output - Output node ID + * @param {string|number} id_input - Input node ID + * @param {string} output_class - Output class name + * @param {string} input_class - Input class name + */ +export function addConnection(id_output, id_input, output_class, input_class) { + var nodeOneModule = this.getModuleFromNodeId(id_output); + var nodeTwoModule = this.getModuleFromNodeId(id_input); + if(nodeOneModule === nodeTwoModule) { + + var dataNode = this.getNodeFromId(id_output); + var exist = false; + for(var checkOutput in dataNode.outputs[output_class].connections){ + var connectionSearch = dataNode.outputs[output_class].connections[checkOutput] + if(connectionSearch.node == id_input && connectionSearch.output == input_class) { + exist = true; + } + } + // Check connection exist + if(exist === false) { + //Create Connection + this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.push( {"node": id_input.toString(), "output": input_class}); + this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.push( {"node": id_output.toString(), "input": output_class}); + + if(this.module === nodeOneModule) { + //Draw connection + var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); + path.classList.add("main-path"); + path.setAttributeNS(null, 'd', ''); + // path.innerHTML = 'a'; + connection.classList.add("connection"); + connection.classList.add("node_in_node-"+id_input); + connection.classList.add("node_out_node-"+id_output); + connection.classList.add(output_class); + connection.classList.add(input_class); + connection.appendChild(path); + this.precanvas.appendChild(connection); + 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}); + } + } +} + +/** + * Update connection node paths + * @param {string} id - Node ID + */ +export function updateConnectionNodes(id) { + + const idSearch = 'node_in_'+id; + const idSearchOut = 'node_out_'+id; + var line_path = this.line_path/2; + const container = this.container; + const precanvas = this.precanvas; + const curvature = this.curvature; + const reroute_curvature = this.reroute_curvature; + const reroute_curvature_start_end = this.reroute_curvature_start_end; + const reroute_fix_curvature = this.reroute_fix_curvature; + const rerouteWidth = this.reroute_width; + const zoom = this.zoom; + let precanvasWitdhZoom = precanvas.clientWidth / (precanvas.clientWidth * zoom); + precanvasWitdhZoom = precanvasWitdhZoom || 0; + let precanvasHeightZoom = precanvas.clientHeight / (precanvas.clientHeight * zoom); + precanvasHeightZoom = precanvasHeightZoom || 0; + + const elemsOut = container.querySelectorAll(`.${idSearchOut}`); + + Object.keys(elemsOut).map(function(item, index) { + if(elemsOut[item].querySelector('.point') === null) { + + var elemtsearchId_out = container.querySelector(`#${id}`); + + var id_search = elemsOut[item].classList[1].replace('node_in_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + + var elemtsearch = elemtsearchId.querySelectorAll('.'+elemsOut[item].classList[4])[0] + + var eX = elemtsearch.offsetWidth/2 + (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var eY = elemtsearch.offsetHeight/2 + (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+elemsOut[item].classList[3])[0] + + var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var x = eX; + var y = eY; + + const lineCurve = createCurvature(line_x, line_y, x, y, curvature, 'openclose'); + elemsOut[item].children[0].setAttributeNS(null, 'd', lineCurve ); + } else { + const points = elemsOut[item].querySelectorAll('.point'); + let linecurve = ''; + const reoute_fix = []; + points.forEach((item, i) => { + if(i === 0 && ((points.length -1) === 0)) { + + var elemtsearchId_out = container.querySelector(`#${id}`); + var elemtsearch = item; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + + var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[3])[0] + var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + var elemtsearchId_out = item; + var id_search = item.parentElement.classList[1].replace('node_in_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + + var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + } else if(i === 0) { + + var elemtsearchId_out = container.querySelector(`#${id}`); + var elemtsearch = item; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + + var elemtsearchOut = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[3])[0] + var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + // SECOND + var elemtsearchId_out = item; + var elemtsearch = points[i+1]; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + } else if (i === (points.length -1)) { + + var elemtsearchId_out = item; + + var id_search = item.parentElement.classList[1].replace('node_in_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + + var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + } else { + var elemtsearchId_out = item; + var elemtsearch = points[i+1]; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) +rerouteWidth; + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * (precanvas.clientWidth / (precanvas.clientWidth * zoom)) + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * (precanvas.clientHeight / (precanvas.clientHeight * zoom)) + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + } + + }); + if(reroute_fix_curvature) { + reoute_fix.forEach((itempath, i) => { + elemsOut[item].children[i].setAttributeNS(null, 'd', itempath); + }); + + } else { + elemsOut[item].children[0].setAttributeNS(null, 'd', linecurve); + } + + } + }) + + const elems = container.querySelectorAll(`.${idSearch}`); + Object.keys(elems).map(function(item, index) { + + if(elems[item].querySelector('.point') === null) { + var elemtsearchId_in = container.querySelector(`#${id}`); + + var id_search = elems[item].classList[2].replace('node_out_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+elems[item].classList[3])[0] + + var line_x = elemtsearch.offsetWidth/2 + (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearch.offsetHeight/2 + (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var elemtsearchId_in = elemtsearchId_in.querySelectorAll('.'+elems[item].classList[4])[0] + var x = elemtsearchId_in.offsetWidth/2 + (elemtsearchId_in.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var y = elemtsearchId_in.offsetHeight/2 + (elemtsearchId_in.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + const lineCurve = createCurvature(line_x, line_y, x, y, curvature, 'openclose'); + elems[item].children[0].setAttributeNS(null, 'd', lineCurve ); + + } else { + const points = elems[item].querySelectorAll('.point'); + let linecurve = ''; + const reoute_fix = []; + points.forEach((item, i) => { + if(i === 0 && ((points.length -1) === 0)) { + + var elemtsearchId_out = container.querySelector(`#${id}`); + var elemtsearch = item; + + var line_x = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; + + var elemtsearchIn = elemtsearchId_out.querySelectorAll('.'+item.parentElement.classList[4])[0] + var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + var elemtsearchId_out = item; + var id_search = item.parentElement.classList[2].replace('node_out_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] + + var elemtsearchOut = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] + var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var eX = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + + } else if(i === 0) { + // FIRST + var elemtsearchId_out = item; + var id_search = item.parentElement.classList[2].replace('node_out_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] + var elemtsearchOut = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[3])[0] + var line_x = elemtsearchOut.offsetWidth/2 + (elemtsearchOut.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var line_y = elemtsearchOut.offsetHeight/2 + (elemtsearchOut.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var eX = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'open'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + // SECOND + var elemtsearchId_out = item; + var elemtsearch = points[i+1]; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + } else if (i === (points.length -1)) { + + var elemtsearchId_out = item; + + var id_search = item.parentElement.classList[1].replace('node_in_', ''); + var elemtsearchId = container.querySelector(`#${id_search}`); + var elemtsearch = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + + var elemtsearchIn = elemtsearchId.querySelectorAll('.'+item.parentElement.classList[4])[0] + var eX = elemtsearchIn.offsetWidth/2 + (elemtsearchIn.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom; + var eY = elemtsearchIn.offsetHeight/2 + (elemtsearchIn.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom; + + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature_start_end, 'close'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + + } else { + + var elemtsearchId_out = item; + var elemtsearch = points[i+1]; + + var eX = (elemtsearch.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var eY = (elemtsearch.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom +rerouteWidth; + var line_x = (elemtsearchId_out.getBoundingClientRect().x - precanvas.getBoundingClientRect().x ) * precanvasWitdhZoom + rerouteWidth; + var line_y = (elemtsearchId_out.getBoundingClientRect().y - precanvas.getBoundingClientRect().y ) * precanvasHeightZoom + rerouteWidth; + var x = eX; + var y = eY; + + var lineCurveSearch = createCurvature(line_x, line_y, x, y, reroute_curvature, 'other'); + linecurve += lineCurveSearch; + reoute_fix.push(lineCurveSearch); + } + + }); + if(reroute_fix_curvature) { + reoute_fix.forEach((itempath, i) => { + elems[item].children[i].setAttributeNS(null, 'd', itempath); + }); + + } else { + elems[item].children[0].setAttributeNS(null, 'd', linecurve); + } + + } + }) +} + +/** + * Remove the selected connection + */ +export function removeConnection() { + if(this.connection_selected != null) { + var listclass = this.connection_selected.parentElement.classList; + this.connection_selected.parentElement.remove(); + //console.log(listclass); + var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { + return item.node === listclass[1].slice(13) && item.output === listclass[4] + }); + this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); + + var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { + return item.node === listclass[2].slice(14) && item.input === listclass[3] + }); + this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); + this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); + this.connection_selected = null; + } +} + +/** + * Remove a single connection between two nodes + * @param {string|number} id_output - Output node ID + * @param {string|number} id_input - Input node ID + * @param {string} output_class - Output class name + * @param {string} input_class - Input class name + * @returns {boolean} - True if removed, false otherwise + */ +export function removeSingleConnection(id_output, id_input, output_class, input_class) { + var nodeOneModule = this.getModuleFromNodeId(id_output); + var nodeTwoModule = this.getModuleFromNodeId(id_input); + if(nodeOneModule === nodeTwoModule) { + // Check nodes in same module. + + // Check connection exist + var exists = this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.findIndex(function(item,i) { + return item.node == id_input && item.output === input_class + }); + if(exists > -1) { + + if(this.module === nodeOneModule) { + // In same module with view. + this.container.querySelector('.connection.node_in_node-'+id_input+'.node_out_node-'+id_output+'.'+output_class+'.'+input_class).remove(); + } + + var index_out = this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.findIndex(function(item,i) { + return item.node == id_input && item.output === input_class + }); + this.drawflow.drawflow[nodeOneModule].data[id_output].outputs[output_class].connections.splice(index_out,1); + + var index_in = this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.findIndex(function(item,i) { + return item.node == id_output && item.input === output_class + }); + this.drawflow.drawflow[nodeOneModule].data[id_input].inputs[input_class].connections.splice(index_in,1); + + this.dispatch('connectionRemoved', { output_id: id_output, input_id: id_input, output_class: output_class, input_class: input_class}); + return true; + + } else { + return false; + } + } else { + return false; + } +} + +/** + * Remove all connections for a node + * @param {string} id - Node ID + */ +export function removeConnectionNodeId(id) { + const idSearchIn = 'node_in_'+id; + const idSearchOut = 'node_out_'+id; + + const elemsOut = this.container.querySelectorAll(`.${idSearchOut}`); + for(var i = elemsOut.length-1; i >= 0; i--) { + var listclass = elemsOut[i].classList; + + var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { + return item.node === listclass[2].slice(14) && item.input === listclass[3] + }); + this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); + + var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { + return item.node === listclass[1].slice(13) && item.output === listclass[4] + }); + this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); + + elemsOut[i].remove(); + + this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); + } + + const elemsIn = this.container.querySelectorAll(`.${idSearchIn}`); + for(var i = elemsIn.length-1; i >= 0; i--) { + + var listclass = elemsIn[i].classList; + + var index_out = this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.findIndex(function(item,i) { + return item.node === listclass[1].slice(13) && item.output === listclass[4] + }); + this.drawflow.drawflow[this.module].data[listclass[2].slice(14)].outputs[listclass[3]].connections.splice(index_out,1); + + var index_in = this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.findIndex(function(item,i) { + return item.node === listclass[2].slice(14) && item.input === listclass[3] + }); + this.drawflow.drawflow[this.module].data[listclass[1].slice(13)].inputs[listclass[4]].connections.splice(index_in,1); + + elemsIn[i].remove(); + + this.dispatch('connectionRemoved', { output_id: listclass[2].slice(14), input_id: listclass[1].slice(13), output_class: listclass[3], input_class: listclass[4] } ); + } +} diff --git a/src/modules/MobileHandler.js b/src/modules/MobileHandler.js new file mode 100644 index 0000000..8ab5a5e --- /dev/null +++ b/src/modules/MobileHandler.js @@ -0,0 +1,76 @@ +/** + * Mobile touch and zoom handling mixin + * Provides mobile device support for multi-touch zooming + */ + +/** + * Initialize mobile handlers on the given context + * @param {object} context - Drawflow instance + */ +export function initMobileHandlers(context) { + context.evCache = new Array(); + context.prevDiff = -1; +} + +/** + * Handle pointer down event + * @param {PointerEvent} ev - Pointer event + */ +export function pointerdown_handler(ev) { + this.evCache.push(ev); +} + +/** + * Handle pointer move event for pinch-to-zoom + * @param {PointerEvent} ev - Pointer event + */ +export function pointermove_handler(ev) { + for (var i = 0; i < this.evCache.length; i++) { + if (ev.pointerId == this.evCache[i].pointerId) { + this.evCache[i] = ev; + break; + } + } + + if (this.evCache.length == 2) { + // Calculate the distance between the two pointers + var curDiff = Math.abs(this.evCache[0].clientX - this.evCache[1].clientX); + + if (this.prevDiff > 100) { + if (curDiff > this.prevDiff) { + // The distance between the two pointers has increased + this.zoom_in(); + } + if (curDiff < this.prevDiff) { + // The distance between the two pointers has decreased + this.zoom_out(); + } + } + this.prevDiff = curDiff; + } +} + +/** + * Handle pointer up/cancel/out/leave events + * @param {PointerEvent} ev - Pointer event + */ +export function pointerup_handler(ev) { + this.remove_event(ev); + if (this.evCache.length < 2) { + this.prevDiff = -1; + } +} + +/** + * Remove event from cache + * @param {PointerEvent} ev - Pointer event to remove + */ +export function remove_event(ev) { + // Remove this event from the target's cache + for (var i = 0; i < this.evCache.length; i++) { + if (this.evCache[i].pointerId == ev.pointerId) { + this.evCache.splice(i, 1); + break; + } + } +} diff --git a/src/modules/ModuleManager.js b/src/modules/ModuleManager.js new file mode 100644 index 0000000..06749ad --- /dev/null +++ b/src/modules/ModuleManager.js @@ -0,0 +1,103 @@ +/** + * Module management module + * Handles creating, switching, and removing modules (workspaces) + */ + +/** + * Get the module name from a node ID + * @param {string|number} id - Node ID + * @returns {string} - Module name + */ +export function getModuleFromNodeId(id) { + var nameModule; + const editor = this.drawflow.drawflow + Object.keys(editor).map(function(moduleName, index) { + Object.keys(editor[moduleName].data).map(function(node, index2) { + if(node == id) { + nameModule = moduleName; + } + }) + }); + return nameModule; +} + +/** + * Add a new module + * @param {string} name - Module name + */ +export function addModule(name) { + this.drawflow.drawflow[name] = { "data": {} }; + this.dispatch('moduleCreated', name); +} + +/** + * Change to a different module + * @param {string} name - Module name + */ +export function changeModule(name) { + this.dispatch('moduleChanged', name); + this.module = name; + this.precanvas.innerHTML = ""; + this.canvas_x = 0; + this.canvas_y = 0; + this.pos_x = 0; + this.pos_y = 0; + this.mouse_x = 0; + this.mouse_y = 0; + this.zoom = 1; + this.zoom_last_value = 1; + this.precanvas.style.transform = ''; + this.import(this.drawflow, false); +} + +/** + * Remove a module + * @param {string} name - Module name + */ +export function removeModule(name) { + if(this.module === name) { + this.changeModule('Home'); + } + delete this.drawflow.drawflow[name]; + this.dispatch('moduleRemoved', name); +} + +/** + * Clear the currently selected module + */ +export function clearModuleSelected() { + this.precanvas.innerHTML = ""; + this.drawflow.drawflow[this.module] = { "data": {} }; +} + +/** + * Clear all modules and reset to default + */ +export function clear() { + this.precanvas.innerHTML = ""; + this.drawflow = { "drawflow": { "Home": { "data": {} }}}; +} + +/** + * Export the drawflow data + * @returns {Object} - Exported data + */ +export function exportDrawflow() { + const dataExport = JSON.parse(JSON.stringify(this.drawflow)); + this.dispatch('export', dataExport); + return dataExport; +} + +/** + * Import drawflow data + * @param {Object} data - Data to import + * @param {boolean} notifi - Whether to dispatch import event + */ +export function importDrawflow(data, notifi = true) { + this.clear(); + this.drawflow = JSON.parse(JSON.stringify(data)); + this.load(); + if(notifi) { + this.dispatch('import', 'import'); + } +} diff --git a/src/modules/NodeManager.js b/src/modules/NodeManager.js new file mode 100644 index 0000000..f1dc948 --- /dev/null +++ b/src/modules/NodeManager.js @@ -0,0 +1,599 @@ +/** + * Node management module + * Handles adding, removing, and updating nodes + */ + +import { getUuid } from '../utils/uuid.js'; + +/** + * Register a node type + * @param {string} name - Node type name + * @param {HTMLElement|Object} html - HTML element or component + * @param {Object} props - Props for the component + * @param {Object} options - Options for the component + */ +export function registerNode(name, html, props = null, options = null) { + this.noderegister[name] = {html: html, props: props, options: options}; +} + +/** + * Get a node by ID + * @param {string|number} id - Node ID + * @returns {Object} - Node data + */ +export function getNodeFromId(id) { + var moduleName = this.getModuleFromNodeId(id) + return JSON.parse(JSON.stringify(this.drawflow.drawflow[moduleName].data[id])); +} + +/** + * Get nodes by name + * @param {string} name - Node name + * @returns {Array} - Array of node IDs + */ +export function getNodesFromName(name) { + var nodes = []; + const editor = this.drawflow.drawflow + Object.keys(editor).map(function(moduleName, index) { + for (var node in editor[moduleName].data) { + if(editor[moduleName].data[node].name == name) { + nodes.push(editor[moduleName].data[node].id); + } + } + }); + return nodes; +} + +/** + * Add a new node + * @param {string} name - Node name + * @param {number} num_in - Number of inputs + * @param {number} num_out - Number of outputs + * @param {number} ele_pos_x - X position + * @param {number} ele_pos_y - Y position + * @param {string} classoverride - CSS classes + * @param {Object} data - Node data + * @param {string|HTMLElement} html - HTML content or component name + * @param {boolean} typenode - Node type flag + * @returns {string|number} - New node ID + */ +export function addNode(name, num_in, num_out, ele_pos_x, ele_pos_y, classoverride, data, html, typenode = false) { + if (this.useuuid) { + var newNodeId = getUuid(); + } else { + var newNodeId = this.nodeId; + } + const parent = document.createElement('div'); + parent.classList.add("parent-node"); + + const node = document.createElement('div'); + node.innerHTML = ""; + node.setAttribute("id", "node-"+newNodeId); + node.classList.add("drawflow-node"); + if(classoverride != '') { + node.classList.add(...classoverride.split(' ')); + } + + const inputs = document.createElement('div'); + inputs.classList.add("inputs"); + + const outputs = document.createElement('div'); + outputs.classList.add("outputs"); + + const json_inputs = {} + for(var x = 0; x < num_in; x++) { + const input = document.createElement('div'); + input.classList.add("input"); + input.classList.add("input_"+(x+1)); + json_inputs["input_"+(x+1)] = { "connections": []}; + inputs.appendChild(input); + } + + const json_outputs = {} + for(var x = 0; x < num_out; x++) { + const output = document.createElement('div'); + output.classList.add("output"); + output.classList.add("output_"+(x+1)); + json_outputs["output_"+(x+1)] = { "connections": []}; + outputs.appendChild(output); + } + + const content = document.createElement('div'); + content.classList.add("drawflow_content_node"); + if(typenode === false) { + content.innerHTML = html; + } else if (typenode === true) { + content.appendChild(this.noderegister[html].html.cloneNode(true)); + } else { + if(parseInt(this.render.version) === 3 ) { + //Vue 3 + let wrapper = this.render.h(this.noderegister[html].html, this.noderegister[html].props, this.noderegister[html].options); + wrapper.appContext = this.parent; + this.render.render(wrapper,content); + + } else { + // Vue 2 + let wrapper = new this.render({ + parent: this.parent, + render: h => h(this.noderegister[html].html, { props: this.noderegister[html].props }), + ...this.noderegister[html].options + }).$mount() + // + content.appendChild(wrapper.$el); + } + } + + Object.entries(data).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(null, key[0], key[0]); + } else { + var elems = content.querySelectorAll('[df-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }) + + function insertObjectkeys(object, name, completname) { + if(object === null) { + var object = data[name]; + } else { + var object = object[name] + } + if(object !== null) { + Object.entries(object).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(object, key[0], completname+'-'+key[0]); + } else { + var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }); + } + } + node.appendChild(inputs); + node.appendChild(content); + node.appendChild(outputs); + node.style.top = ele_pos_y + "px"; + node.style.left = ele_pos_x + "px"; + parent.appendChild(node); + this.precanvas.appendChild(parent); + var json = { + id: newNodeId, + name: name, + data: data, + class: classoverride, + html: html, + typenode: typenode, + inputs: json_inputs, + outputs: json_outputs, + pos_x: ele_pos_x, + pos_y: ele_pos_y, + } + this.drawflow.drawflow[this.module].data[newNodeId] = json; + this.dispatch('nodeCreated', newNodeId); + if (!this.useuuid) { + this.nodeId++; + } + return newNodeId; +} + +/** + * Add a node from import data + * @param {Object} dataNode - Node data + * @param {HTMLElement} precanvas - Precanvas element + */ +export function addNodeImport(dataNode, precanvas) { + const parent = document.createElement('div'); + parent.classList.add("parent-node"); + + const node = document.createElement('div'); + node.innerHTML = ""; + node.setAttribute("id", "node-"+dataNode.id); + node.classList.add("drawflow-node"); + if(dataNode.class != '') { + node.classList.add(...dataNode.class.split(' ')); + } + + const inputs = document.createElement('div'); + inputs.classList.add("inputs"); + + const outputs = document.createElement('div'); + outputs.classList.add("outputs"); + + Object.keys(dataNode.inputs).map(function(input_item, index) { + const input = document.createElement('div'); + input.classList.add("input"); + input.classList.add(input_item); + inputs.appendChild(input); + Object.keys(dataNode.inputs[input_item].connections).map(function(output_item, index) { + + var connection = document.createElementNS('http://www.w3.org/2000/svg',"svg"); + var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); + path.classList.add("main-path"); + path.setAttributeNS(null, 'd', ''); + // path.innerHTML = 'a'; + connection.classList.add("connection"); + connection.classList.add("node_in_node-"+dataNode.id); + connection.classList.add("node_out_node-"+dataNode.inputs[input_item].connections[output_item].node); + connection.classList.add(dataNode.inputs[input_item].connections[output_item].input); + connection.classList.add(input_item); + + connection.appendChild(path); + precanvas.appendChild(connection); + + }); + }); + + for(var x = 0; x < Object.keys(dataNode.outputs).length; x++) { + const output = document.createElement('div'); + output.classList.add("output"); + output.classList.add("output_"+(x+1)); + outputs.appendChild(output); + } + + const content = document.createElement('div'); + content.classList.add("drawflow_content_node"); + + if(dataNode.typenode === false) { + content.innerHTML = dataNode.html; + } else if (dataNode.typenode === true) { + content.appendChild(this.noderegister[dataNode.html].html.cloneNode(true)); + } else { + if(parseInt(this.render.version) === 3 ) { + //Vue 3 + let wrapper = this.render.h(this.noderegister[dataNode.html].html, this.noderegister[dataNode.html].props, this.noderegister[dataNode.html].options); + wrapper.appContext = this.parent; + this.render.render(wrapper,content); + + } else { + //Vue 2 + let wrapper = new this.render({ + parent: this.parent, + render: h => h(this.noderegister[dataNode.html].html, { props: this.noderegister[dataNode.html].props }), + ...this.noderegister[dataNode.html].options + }).$mount() + content.appendChild(wrapper.$el); + } + } + + Object.entries(dataNode.data).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(null, key[0], key[0]); + } else { + var elems = content.querySelectorAll('[df-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }) + + function insertObjectkeys(object, name, completname) { + if(object === null) { + var object = dataNode.data[name]; + } else { + var object = object[name] + } + if(object !== null) { + Object.entries(object).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(object, key[0], completname+'-'+key[0]); + } else { + var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }); + } + } + node.appendChild(inputs); + node.appendChild(content); + node.appendChild(outputs); + node.style.top = dataNode.pos_y + "px"; + node.style.left = dataNode.pos_x + "px"; + parent.appendChild(node); + this.precanvas.appendChild(parent); +} + +/** + * Update node value from input event + * @param {Event} event - Input event + */ +export function updateNodeValue(event) { + var attr = event.target.attributes + for (var i = 0; i < attr.length; i++) { + if (attr[i].nodeName.startsWith('df-')) { + var keys = attr[i].nodeName.slice(3).split("-"); + var target = this.drawflow.drawflow[this.module].data[event.target.closest(".drawflow_content_node").parentElement.id.slice(5)].data; + for (var index = 0; index < keys.length - 1; index += 1) { + if (target[keys[index]] == null) { + target[keys[index]] = {}; + } + target = target[keys[index]]; + } + target[keys[keys.length - 1]] = event.target.value; + if(event.target.isContentEditable) { + target[keys[keys.length - 1]] = event.target.innerText; + } + this.dispatch('nodeDataChanged', event.target.closest(".drawflow_content_node").parentElement.id.slice(5)); + } + } +} + +/** + * Update node data from ID + * @param {string|number} id - Node ID + * @param {Object} data - New data + */ +export function updateNodeDataFromId(id, data) { + var moduleName = this.getModuleFromNodeId(id) + this.drawflow.drawflow[moduleName].data[id].data = data; + if(this.module === moduleName) { + const content = this.container.querySelector('#node-'+id); + + Object.entries(data).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(null, key[0], key[0]); + } else { + var elems = content.querySelectorAll('[df-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }) + + function insertObjectkeys(object, name, completname) { + if(object === null) { + var object = data[name]; + } else { + var object = object[name] + } + if(object !== null) { + Object.entries(object).forEach(function (key, value) { + if(typeof key[1] === "object") { + insertObjectkeys(object, key[0], completname+'-'+key[0]); + } else { + var elems = content.querySelectorAll('[df-'+completname+'-'+key[0]+']'); + for(var i = 0; i < elems.length; i++) { + elems[i].value = key[1]; + if(elems[i].isContentEditable) { + elems[i].innerText = key[1]; + } + } + } + }); + } + } + + } +} + +/** + * Add an input to a node + * @param {string|number} id - Node ID + */ +export function addNodeInput(id) { + var moduleName = this.getModuleFromNodeId(id) + const infoNode = this.getNodeFromId(id) + const numInputs = Object.keys(infoNode.inputs).length; + if(this.module === moduleName) { + //Draw input + const input = document.createElement('div'); + input.classList.add("input"); + input.classList.add("input_"+(numInputs+1)); + const parent = this.container.querySelector('#node-'+id+' .inputs'); + parent.appendChild(input); + this.updateConnectionNodes('node-'+id); + + } + this.drawflow.drawflow[moduleName].data[id].inputs["input_"+(numInputs+1)] = { "connections": []}; +} + +/** + * Add an output to a node + * @param {string|number} id - Node ID + */ +export function addNodeOutput(id) { + var moduleName = this.getModuleFromNodeId(id) + const infoNode = this.getNodeFromId(id) + const numOutputs = Object.keys(infoNode.outputs).length; + if(this.module === moduleName) { + //Draw output + const output = document.createElement('div'); + output.classList.add("output"); + output.classList.add("output_"+(numOutputs+1)); + const parent = this.container.querySelector('#node-'+id+' .outputs'); + parent.appendChild(output); + this.updateConnectionNodes('node-'+id); + + } + this.drawflow.drawflow[moduleName].data[id].outputs["output_"+(numOutputs+1)] = { "connections": []}; +} + +/** + * Remove an input from a node + * @param {string|number} id - Node ID + * @param {string} input_class - Input class name + */ +export function removeNodeInput(id, input_class) { + var moduleName = this.getModuleFromNodeId(id) + const infoNode = this.getNodeFromId(id) + if(this.module === moduleName) { + this.container.querySelector('#node-'+id+' .inputs .input.'+input_class).remove(); + } + const removeInputs = []; + Object.keys(infoNode.inputs[input_class].connections).map(function(key, index) { + const id_output = infoNode.inputs[input_class].connections[index].node; + const output_class = infoNode.inputs[input_class].connections[index].input; + removeInputs.push({id_output, id, output_class, input_class}) + }) + // Remove connections + removeInputs.forEach((item, i) => { + this.removeSingleConnection(item.id_output, item.id, item.output_class, item.input_class); + }); + + delete this.drawflow.drawflow[moduleName].data[id].inputs[input_class]; + + // Update connection + const connections = []; + const connectionsInputs = this.drawflow.drawflow[moduleName].data[id].inputs + Object.keys(connectionsInputs).map(function(key, index) { + connections.push(connectionsInputs[key]); + }); + this.drawflow.drawflow[moduleName].data[id].inputs = {}; + const input_class_id = input_class.slice(6); + let nodeUpdates = []; + connections.forEach((item, i) => { + item.connections.forEach((itemx, f) => { + nodeUpdates.push(itemx); + }); + this.drawflow.drawflow[moduleName].data[id].inputs['input_'+ (i+1)] = item; + }); + nodeUpdates = new Set(nodeUpdates.map(e => JSON.stringify(e))); + nodeUpdates = Array.from(nodeUpdates).map(e => JSON.parse(e)); + + if(this.module === moduleName) { + const eles = this.container.querySelectorAll("#node-"+id +" .inputs .input"); + eles.forEach((item, i) => { + const id_class = item.classList[1].slice(6); + if(parseInt(input_class_id) < parseInt(id_class)) { + item.classList.remove('input_'+id_class); + item.classList.add('input_'+(id_class-1)); + } + }); + + } + + nodeUpdates.forEach((itemx, i) => { + this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections.forEach((itemz, g) => { + if(itemz.node == id) { + const output_id = itemz.output.slice(6); + if(parseInt(input_class_id) < parseInt(output_id)) { + if(this.module === moduleName) { + const ele = this.container.querySelector(".connection.node_in_node-"+id+".node_out_node-"+itemx.node+"."+itemx.input+".input_"+output_id); + ele.classList.remove('input_'+output_id); + ele.classList.add('input_'+(output_id-1)); + } + if(itemz.points) { + this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections[g] = { node: itemz.node, output: 'input_'+(output_id-1), points: itemz.points } + } else { + this.drawflow.drawflow[moduleName].data[itemx.node].outputs[itemx.input].connections[g] = { node: itemz.node, output: 'input_'+(output_id-1)} + } + } + } + }); + }); + this.updateConnectionNodes('node-'+id); +} + +/** + * Remove an output from a node + * @param {string|number} id - Node ID + * @param {string} output_class - Output class name + */ +export function removeNodeOutput(id, output_class) { + var moduleName = this.getModuleFromNodeId(id) + const infoNode = this.getNodeFromId(id) + if(this.module === moduleName) { + this.container.querySelector('#node-'+id+' .outputs .output.'+output_class).remove(); + } + const removeOutputs = []; + Object.keys(infoNode.outputs[output_class].connections).map(function(key, index) { + const id_input = infoNode.outputs[output_class].connections[index].node; + const input_class = infoNode.outputs[output_class].connections[index].output; + removeOutputs.push({id, id_input, output_class, input_class}) + }) + // Remove connections + removeOutputs.forEach((item, i) => { + this.removeSingleConnection(item.id, item.id_input, item.output_class, item.input_class); + }); + + delete this.drawflow.drawflow[moduleName].data[id].outputs[output_class]; + + // Update connection + const connections = []; + const connectionsOuputs = this.drawflow.drawflow[moduleName].data[id].outputs + Object.keys(connectionsOuputs).map(function(key, index) { + connections.push(connectionsOuputs[key]); + }); + this.drawflow.drawflow[moduleName].data[id].outputs = {}; + const output_class_id = output_class.slice(7); + let nodeUpdates = []; + connections.forEach((item, i) => { + item.connections.forEach((itemx, f) => { + nodeUpdates.push({ node: itemx.node, output: itemx.output }); + }); + this.drawflow.drawflow[moduleName].data[id].outputs['output_'+ (i+1)] = item; + }); + nodeUpdates = new Set(nodeUpdates.map(e => JSON.stringify(e))); + nodeUpdates = Array.from(nodeUpdates).map(e => JSON.parse(e)); + + if(this.module === moduleName) { + const eles = this.container.querySelectorAll("#node-"+id +" .outputs .output"); + eles.forEach((item, i) => { + const id_class = item.classList[1].slice(7); + if(parseInt(output_class_id) < parseInt(id_class)) { + item.classList.remove('output_'+id_class); + item.classList.add('output_'+(id_class-1)); + } + }); + + } + + nodeUpdates.forEach((itemx, i) => { + this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections.forEach((itemz, g) => { + if(itemz.node == id) { + const input_id = itemz.input.slice(7); + if(parseInt(output_class_id) < parseInt(input_id)) { + if(this.module === moduleName) { + + const ele = this.container.querySelector(".connection.node_in_node-"+itemx.node+".node_out_node-"+id+".output_"+input_id+"."+itemx.output); + ele.classList.remove('output_'+input_id); + ele.classList.remove(itemx.output); + ele.classList.add('output_'+(input_id-1)); + ele.classList.add(itemx.output); + } + if(itemz.points) { + this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections[g] = { node: itemz.node, input: 'output_'+(input_id-1), points: itemz.points } + } else { + this.drawflow.drawflow[moduleName].data[itemx.node].inputs[itemx.output].connections[g] = { node: itemz.node, input: 'output_'+(input_id-1)} + } + } + } + }); + }); + + this.updateConnectionNodes('node-'+id); +} + +/** + * Remove a node by ID + * @param {string} id - Node ID (with 'node-' prefix) + */ +export function removeNodeId(id) { + this.removeConnectionNodeId(id); + var moduleName = this.getModuleFromNodeId(id.slice(5)) + if(this.module === moduleName) { + this.container.querySelector(`#${id}`).remove(); + } + delete this.drawflow.drawflow[moduleName].data[id.slice(5)]; + this.dispatch('nodeRemoved', id.slice(5)); +} diff --git a/src/modules/RerouteManager.js b/src/modules/RerouteManager.js new file mode 100644 index 0000000..82e0b30 --- /dev/null +++ b/src/modules/RerouteManager.js @@ -0,0 +1,169 @@ +/** + * Reroute point management module + * Handles creating and removing reroute points on connections + */ + +import { createCurvature } from '../utils/curvature.js'; + +/** + * Handle double click for reroute points + * @param {MouseEvent} e - Mouse event + */ +export function dblclick(e) { + if(this.connection_selected != null && this.reroute) { + this.createReroutePoint(this.connection_selected); + } + + if(e.target.classList[0] === 'point') { + this.removeReroutePoint(e.target); + } +} + +/** + * Create a reroute point on the selected connection + * @param {HTMLElement} ele - Connection element + */ +export function createReroutePoint(ele) { + this.connection_selected.classList.remove("selected"); + const nodeUpdate = this.connection_selected.parentElement.classList[2].slice(9); + const nodeUpdateIn = this.connection_selected.parentElement.classList[1].slice(13); + const output_class = this.connection_selected.parentElement.classList[3]; + const input_class = this.connection_selected.parentElement.classList[4]; + this.connection_selected = null; + const point = document.createElementNS('http://www.w3.org/2000/svg',"circle"); + point.classList.add("point"); + var pos_x = this.pos_x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom)) - (this.precanvas.getBoundingClientRect().x * ( this.precanvas.clientWidth / (this.precanvas.clientWidth * this.zoom))); + var pos_y = this.pos_y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom)) - (this.precanvas.getBoundingClientRect().y * ( this.precanvas.clientHeight / (this.precanvas.clientHeight * this.zoom))); + + point.setAttributeNS(null, 'cx', pos_x); + point.setAttributeNS(null, 'cy', pos_y); + point.setAttributeNS(null, 'r', this.reroute_width); + + let position_add_array_point = 0; + if(this.reroute_fix_curvature) { + + const numberPoints = ele.parentElement.querySelectorAll(".main-path").length; + var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); + path.classList.add("main-path"); + path.setAttributeNS(null, 'd', ''); + + ele.parentElement.insertBefore(path, ele.parentElement.children[numberPoints]); + if(numberPoints === 1) { + ele.parentElement.appendChild(point); + } else { + const search_point = Array.from(ele.parentElement.children).indexOf(ele) + position_add_array_point = search_point; + ele.parentElement.insertBefore(point, ele.parentElement.children[search_point+numberPoints+1]); + } + + } else { + ele.parentElement.appendChild(point); + } + + const nodeId = nodeUpdate.slice(5); + const searchConnection = this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections.findIndex(function(item,i) { + return item.node === nodeUpdateIn && item.output === input_class; + }); + + if(this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points === undefined) { + this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points = []; + } + + if(this.reroute_fix_curvature) { + + if(position_add_array_point > 0 || this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points !== []) { + this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.splice(position_add_array_point, 0, { pos_x: pos_x, pos_y: pos_y }); + } else { + this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.push({ pos_x: pos_x, pos_y: pos_y }); + } + + ele.parentElement.querySelectorAll(".main-path").forEach((item, i) => { + item.classList.remove("selected"); + }); + + } else { + this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.push({ pos_x: pos_x, pos_y: pos_y }); + } + + this.dispatch('addReroute', nodeId); + this.updateConnectionNodes(nodeUpdate); +} + +/** + * Remove a reroute point + * @param {HTMLElement} ele - Reroute point element + */ +export function removeReroutePoint(ele) { + const nodeUpdate = ele.parentElement.classList[2].slice(9) + const nodeUpdateIn = ele.parentElement.classList[1].slice(13); + const output_class = ele.parentElement.classList[3]; + const input_class = ele.parentElement.classList[4]; + + let numberPointPosition = Array.from(ele.parentElement.children).indexOf(ele); + const nodeId = nodeUpdate.slice(5); + const searchConnection = this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections.findIndex(function(item,i) { + return item.node === nodeUpdateIn && item.output === input_class; + }); + + if(this.reroute_fix_curvature) { + const numberMainPath = ele.parentElement.querySelectorAll(".main-path").length + ele.parentElement.children[numberMainPath-1].remove(); + numberPointPosition -= numberMainPath; + if(numberPointPosition < 0) { + numberPointPosition = 0; + } + } else { + numberPointPosition--; + } + this.drawflow.drawflow[this.module].data[nodeId].outputs[output_class].connections[searchConnection].points.splice(numberPointPosition,1); + + ele.remove(); + this.dispatch('removeReroute', nodeId); + this.updateConnectionNodes(nodeUpdate); +} + +/** + * Add reroute points from import data + * @param {Object} dataNode - Node data + */ +export function addRerouteImport(dataNode) { + const reroute_width = this.reroute_width + const reroute_fix_curvature = this.reroute_fix_curvature + const container = this.container; + Object.keys(dataNode.outputs).map(function(output_item, index) { + Object.keys(dataNode.outputs[output_item].connections).map(function(input_item, index) { + const points = dataNode.outputs[output_item].connections[input_item].points + if(points !== undefined) { + + points.forEach((item, i) => { + const input_id = dataNode.outputs[output_item].connections[input_item].node; + const input_class = dataNode.outputs[output_item].connections[input_item].output; + const ele = container.querySelector('.connection.node_in_node-'+input_id+'.node_out_node-'+dataNode.id+'.'+output_item+'.'+input_class); + + if(reroute_fix_curvature) { + if(i === 0) { + for (var z = 0; z < points.length; z++) { + var path = document.createElementNS('http://www.w3.org/2000/svg',"path"); + path.classList.add("main-path"); + path.setAttributeNS(null, 'd', ''); + ele.appendChild(path); + + } + } + } + + const point = document.createElementNS('http://www.w3.org/2000/svg',"circle"); + point.classList.add("point"); + var pos_x = item.pos_x; + var pos_y = item.pos_y; + + point.setAttributeNS(null, 'cx', pos_x); + point.setAttributeNS(null, 'cy', pos_y); + point.setAttributeNS(null, 'r', reroute_width); + + ele.appendChild(point); + }); + }; + }); + }); +} diff --git a/src/modules/ZoomHandler.js b/src/modules/ZoomHandler.js new file mode 100644 index 0000000..4035ec6 --- /dev/null +++ b/src/modules/ZoomHandler.js @@ -0,0 +1,63 @@ +/** + * Zoom handling module + * Provides zoom in, out, reset and mouse wheel zoom functionality + */ + +/** + * Handle mouse wheel zoom event + * @param {WheelEvent} event - Wheel event + * @param {number} delta - Optional delta value + */ +export function zoom_enter(event, delta) { + if (event.ctrlKey) { + event.preventDefault() + if(event.deltaY > 0) { + // Zoom Out + this.zoom_out(); + } else { + // Zoom In + this.zoom_in(); + } + } +} + +/** + * Refresh zoom display after zoom value change + */ +export function zoom_refresh() { + this.dispatch('zoom', this.zoom); + this.canvas_x = (this.canvas_x / this.zoom_last_value) * this.zoom; + this.canvas_y = (this.canvas_y / this.zoom_last_value) * this.zoom; + this.zoom_last_value = this.zoom; + this.precanvas.style.transform = "translate("+this.canvas_x+"px, "+this.canvas_y+"px) scale("+this.zoom+")"; +} + +/** + * Zoom in by zoom_value increment + */ +export function zoom_in() { + if(this.zoom < this.zoom_max) { + this.zoom+=this.zoom_value; + this.zoom_refresh(); + } +} + +/** + * Zoom out by zoom_value decrement + */ +export function zoom_out() { + if(this.zoom > this.zoom_min) { + this.zoom-=this.zoom_value; + this.zoom_refresh(); + } +} + +/** + * Reset zoom to 1 + */ +export function zoom_reset() { + if(this.zoom != 1) { + this.zoom = 1; + this.zoom_refresh(); + } +} diff --git a/src/utils/EventEmitter.js b/src/utils/EventEmitter.js new file mode 100644 index 0000000..2f8b1cc --- /dev/null +++ b/src/utils/EventEmitter.js @@ -0,0 +1,68 @@ +/** + * EventEmitter class for handling custom events + * Provides on, dispatch, and removeListener methods + */ +export default class EventEmitter { + constructor() { + this.events = {}; + } + + /** + * Register an event listener + * @param {string} event - Event name + * @param {function} callback - Callback function + * @returns {boolean} - False if invalid parameters + */ + on(event, callback) { + // Check if the callback is not a function + if (typeof callback !== 'function') { + console.error(`The listener callback must be a function, the given type is ${typeof callback}`); + return false; + } + // Check if the event is not a string + if (typeof event !== 'string') { + console.error(`The event name must be a string, the given type is ${typeof event}`); + return false; + } + // Check if this event not exists + if (this.events[event] === undefined) { + this.events[event] = { + listeners: [] + } + } + this.events[event].listeners.push(callback); + } + + /** + * Remove an event listener + * @param {string} event - Event name + * @param {function} callback - Callback function to remove + * @returns {boolean} - False if event doesn't exist + */ + removeListener(event, callback) { + // Check if this event not exists + if (!this.events[event]) return false + + const listeners = this.events[event].listeners + const listenerIndex = listeners.indexOf(callback) + const hasListener = listenerIndex > -1 + if (hasListener) listeners.splice(listenerIndex, 1) + } + + /** + * Dispatch an event to all listeners + * @param {string} event - Event name + * @param {*} details - Event details/payload + * @returns {boolean} - False if event doesn't exist + */ + dispatch(event, details) { + // Check if this event not exists + if (this.events[event] === undefined) { + // console.error(`This event: ${event} does not exist`); + return false; + } + this.events[event].listeners.forEach((listener) => { + listener(details); + }); + } +} diff --git a/src/utils/curvature.js b/src/utils/curvature.js new file mode 100644 index 0000000..a5aa652 --- /dev/null +++ b/src/utils/curvature.js @@ -0,0 +1,50 @@ +/** + * Create a curvature path for connections + * @param {number} start_pos_x - Starting X position + * @param {number} start_pos_y - Starting Y position + * @param {number} end_pos_x - Ending X position + * @param {number} end_pos_y - Ending Y position + * @param {number} curvature_value - Curvature amount + * @param {string} type - Type of curve: 'open', 'close', 'other', or default 'openclose' + * @returns {string} - SVG path string + */ +export function createCurvature(start_pos_x, start_pos_y, end_pos_x, end_pos_y, curvature_value, type) { + var line_x = start_pos_x; + var line_y = start_pos_y; + var x = end_pos_x; + var y = end_pos_y; + var curvature = curvature_value; + switch (type) { + case 'open': + if(start_pos_x >= end_pos_x) { + var hx1 = line_x + Math.abs(x - line_x) * curvature; + var hx2 = x - Math.abs(x - line_x) * (curvature*-1); + } else { + var hx1 = line_x + Math.abs(x - line_x) * curvature; + var hx2 = x - Math.abs(x - line_x) * curvature; + } + return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; + case 'close': + if(start_pos_x >= end_pos_x) { + var hx1 = line_x + Math.abs(x - line_x) * (curvature*-1); + var hx2 = x - Math.abs(x - line_x) * curvature; + } else { + var hx1 = line_x + Math.abs(x - line_x) * curvature; + var hx2 = x - Math.abs(x - line_x) * curvature; + } + return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; + case 'other': + if(start_pos_x >= end_pos_x) { + var hx1 = line_x + Math.abs(x - line_x) * (curvature*-1); + var hx2 = x - Math.abs(x - line_x) * (curvature*-1); + } else { + var hx1 = line_x + Math.abs(x - line_x) * curvature; + var hx2 = x - Math.abs(x - line_x) * curvature; + } + return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; + default: + var hx1 = line_x + Math.abs(x - line_x) * curvature; + var hx2 = x - Math.abs(x - line_x) * curvature; + return ' M '+ line_x +' '+ line_y +' C '+ hx1 +' '+ line_y +' '+ hx2 +' ' + y +' ' + x +' ' + y; + } +} diff --git a/src/utils/uuid.js b/src/utils/uuid.js new file mode 100644 index 0000000..517aeaf --- /dev/null +++ b/src/utils/uuid.js @@ -0,0 +1,18 @@ +/** + * Generate a UUID v4 + * Based on RFC 4122 - http://www.ietf.org/rfc/rfc4122.txt + * @returns {string} - Generated UUID + */ +export function getUuid() { + var s = []; + var hexDigits = "0123456789abcdef"; + for (var i = 0; i < 36; i++) { + s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); + } + s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 + s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 + s[8] = s[13] = s[18] = s[23] = "-"; + + var uuid = s.join(""); + return uuid; +}