jerosoler / Drawflow

Simple flow library 🖥️🖱️
https://jerosoler.github.io/Drawflow/
MIT License
4.78k stars 741 forks source link

Adding node dynamically #628

Closed cewebdesigner closed 1 year ago

cewebdesigner commented 1 year ago

I have a problem when adding a node dynamically, when I add more than one node you can see in the image that the output node is disordered, what could it be

in the code to add the node I include this code together:

const links = document.querySelectorAll(#node-${idNode} .drawflow_content_node .link); links.forEach((item) => { const target = document.querySelector(#node-${idNode} .outputs .${item.classList[1]}); if(target != null) { const pos = item.getBoundingClientRect(); const targetPos = target.getBoundingClientRect(); target.style.top =${pos.y - targetPos.y}px; target.style.left =${pos.x - targetPos.x}px; } })

node

jerosoler commented 1 year ago

Show code node and event code complet.

And use code blocks for show code correctly: https://www.markdownguide.org/extended-syntax/#fenced-code-blocks

cewebdesigner commented 1 year ago

Ok, I'll send you the html and JavaScript

HTML you will include a Modal

<div class="modal modal-right large fade" id="modalPainelInfo" tabindex="-1" role="dialog" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title">Editar Mensagem</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body">
            <div class="row">
              <div id="resultadoTipo"></div>
            </div>
          </div>
          <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fechar</button>
          </div>

          <input type="hidden" id="idBotPainel" name="idbotEditar" value="">
        </div>
      </div>
    </div>

Now in JavaScript

var id = document.getElementById("drawflow");
    const editor = new Drawflow(id);
    editor.reroute = true;
    editor.reroute_fix_curvature = true;
    editor.force_first_input = false;

    const dataToImport =  {"drawflow":{"Home":{"data":{"0":{"id":0,"name":"inicial","data":{},"class":"inicial","html":"\n        <div class=\"title\"><i class=\"fas fa-play-circle text-success\"></i> Passo Inicial</div>\n        ","typenode":false,"inputs":{},"outputs":{"output_1":{"connections":[{"node":"1","output":"input_1"}]}},"pos_x":102,"pos_y":100},"1":{"id":1,"name":"template_pergunta","data":{"titulo":"Pergunta","tipo":"pergunta","informadigitacao":"1","aguardarresposta":"1","mensagemtexto":"Escolha uma opção abaixo:","segundodigitacao":"1"},"class":"template_pergunta","html":"\n            <div class=\"title\"><i class=\"fas fa-paperclip me-1\"></i> <span class=\"title-header\">Pergunta<span></span></span></div>\n            <div class=\"panel\">\n              <div class=\"blockyinfotexto\">Escolha uma opção abaixo:</div>\n              <div class=\"blockyinfopergunta\"><div><span class=\"paragrafo-1\"></span></div></div>\n            </div>\n            <div class=\"multiple\"><div class=\"panel\">Outputs 1<div class=\"link output_1\"></div></div></div>\n            <input type=\"hidden\" name=\"titleHeader\" df-temp-title=\"\" id=\"titleHeader\" class=\"titleHeader\" value=\"Pergunta\">\n            <input type=\"hidden\" name=\"tipomensagem\" id=\"tipomensagem\" class=\"tipomensagem\" value=\"pergunta\">\n            <input type=\"hidden\" name=\"informadigitacao\" id=\"informadigitacao\" class=\"informadigitacao\" value=\"1\">\n            <input type=\"hidden\" name=\"aguardarresposta\" id=\"aguardarresposta\" class=\"aguardarresposta\" value=\"1\">\n            <input type=\"hidden\" name=\"mensagemtexto\" id=\"mensagemtexto\" class=\"mensagemtexto\" value=\"Escolha uma opção abaixo:\">\n            <input type=\"hidden\" name=\"segundodigitacao\" id=\"segundodigitacao\" class=\"segundodigitacao\" value=\"1\">\n            <div id=\"resultadoPergunta\"><div><input type=\"hidden\" name=\"perguntaflow[]\" id=\"perguntaidflow\" class=\"perguntaflow-1\" value=\"\"></div></div>","typenode":false,"inputs":{"input_1":{"connections":[{"node":"0","input":"output_1"}]}},"outputs":{"output_1":{"connections":[]}},"pos_x":422,"pos_y":95}}}}}
    editor.start();

    editor.import = function(data) {
      this.clear();
      this.drawflow = JSON.parse(JSON.stringify(data));
      this.load();
      this.dispatch('import', 'import');
    }

    editor.on("import", () => {
      Object.keys(editor.drawflow.drawflow[editor.module].data).forEach(id => {
        const links =  document.querySelectorAll(`#node-${id} .drawflow_content_node .link`);
        console.log(links);
        links.forEach((item) => {
            const target = document.querySelector(`#node-${id} .outputs .${item.classList[1]}`);
            if(target != null) {
                const pos = item.getBoundingClientRect();
                const targetPos = target.getBoundingClientRect();
                target.style.top = `${pos.y - targetPos.y}px`;
                target.style.left = `${pos.x - targetPos.x}px`;
            }
        })        

      })
    })

    editor.import(dataToImport);

    // Events!
    editor.on('nodeCreated', (id) => {
        const links =  document.querySelectorAll(`#node-${id} .drawflow_content_node .link`);
        console.log(links);
        links.forEach((item) => {
            const target = document.querySelector(`#node-${id} .outputs .${item.classList[1]}`);
            if(target != null) {
                const pos = item.getBoundingClientRect();
                const targetPos = target.getBoundingClientRect();
                target.style.top = `${pos.y - targetPos.y}px`;
                target.style.left = `${pos.x - targetPos.x}px`;
            }
        })
    })

    editor.on('nodeRemoved', function(id) {
      console.log("Node removed " + id);
    })

    editor.on('nodeSelected', function(id, event) {
      console.log("Node selected " + id);
    })

    var doneTouch = function (event) {
      console.log(event);

      if (event.type === "dblclick") {
        if (event.target.closest(".drawflow_content_node") && !event.target.closest(".drawflow_content_node").classList.contains("dragging")) {
          tempblock = event.target.closest(".drawflow_content_node");

          var currentTarget;
          currentTarget = event.target.closest(".drawflow_content_node");

          $('#modalPainelInfo').modal('show');

          var tipoFluxo = tempblock.querySelectorAll(".tipomensagem")[0].value;
          if(tipoFluxo == 'pergunta'){

            $('#resultadoTipo').html(`
              <div class="col-md-12">
                <div class="mb-3">
                  <label class="form-label">Nome (Identificação)</label>
                  <input type="text" class="form-control identificacaoPainel" value="Mensagem" id="identificacaoPainel" name="identificacaoPainel" required>
                </div>
              </div>

              <div class="col-md-12">
                <label class="form-label">Texto</label>
                <div class="mb-3">
                  <textarea class="form-control" name="bot_texto_pergunta" id="descriptioninputpergunta" required></textarea>
                </div>
              </div>

              <div id="dynamic_field_novo_pergunta" class="col-md-12"></div>

              <div class="col-md-12">
                <button class="btn btn-sm btn-outline-alternate" type="button" id="add_opcoes_pergunta">+ Add Question</button>
              </div>

              <div class="col-md-12 mt-5" style="">
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="digitacaoinput" name="digitacao" value="1">
                  <label class="form-check-label" for="digitacaoinput">Informar Digitação</label>
                </div>

                <div id="resultadoSlider" class="col-12 col-sm-12 col-xl-12" style="margin-top: 20px; margin-bottom: 70px;">
                  <label class="form-label">Quantos segundos para aparecer a próxima mensagem?</label>
                  <div id="sliderRound"></div>
                </div>
              </div>

              <div class="col-md-12" style="">
                <div class="form-check">
                  <input class="form-check-input" type="checkbox" id="interecao_contato" name="interecao_contato" value="1">
                  <label class="form-check-label" for="interecao_contato">Aguardar uma resposta do contato</label>

                  <div id="aguarda-resposta" class="alert alert-primary" role="alert" style="display: none">Esta etapa aguardará uma resposta do contato antes de seguir adiante.</div>
                </div>
              </div>`);

            var listPergunta = tempblock.querySelectorAll('[name="perguntaflow[]"]').value;

            var checados2 = [];
            $.each(tempblock.querySelectorAll('[name="perguntaflow[]"]'), function(d, value){            
              checados2.push($(this).val());

              var c=d+1;

              $('#dynamic_field_novo_pergunta').append('<div class="row" id="rowss'+c+'"><div class="col-md-12"><label class="form-label">Pergunta</label><div class="input-group mb-3"><input type="text" id="inp'+c+'" class="form-control dudu'+c+'" value="'+$(this).val()+'" name="pergunta[]" required><button type="button" class="btn btn-outline-danger btn_remove_pergunta" name="remove" id="'+c+'"><i class="fas fa-times"></i></button></div></div></div>');

              $("#inp"+c+"").keyup(function () {
                tempblock.querySelectorAll(".perguntaflow-"+c+"")[0].value = document.querySelector("#inp"+c+"").value;
                tempblock.querySelectorAll(".paragrafo-"+c+"")[0].innerText = document.querySelector("#inp"+c+"").value;

                let idNode = currentTarget.parentElement.id.slice(5);
                editor.addNodeOutput(idNode);
                editor.updateConnectionNodes('node-'+idNode+'');

                editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");
                atualizaDataPergunta();
              });
            });

            $(document).ready(function(){
              var c=checados2.length;
              $('#add_opcoes_pergunta').click(function(){

                var verifica = $('.dudu'+c+'').val();

                c++;  

                $('#dynamic_field_novo_pergunta').append('<div class="row" id="rowss'+c+'"><div class="col-md-12"><label class="form-label">Pergunta</label><div class="input-group mb-3"><input type="text" id="inp'+c+'" class="form-control dudu'+c+'" value="" name="pergunta[]" placeholder="Ex: 1- Suporte" required><button type="button" class="btn btn-outline-danger btn_remove_pergunta" name="remove" id="'+c+'"><i class="fas fa-times"></i></button></div></div></div>');

                var div = document.createElement("div");
                var text = document.createElement("input");
                text.setAttribute("type", "hidden");
                text.setAttribute("name", "perguntaflow[]");
                text.setAttribute("id", "perguntaidflow");
                text.setAttribute("class", "perguntaflow-"+c+"");
                text.setAttribute("value", "");
                div.appendChild(text);

                tempblock.querySelectorAll("#resultadoPergunta")[0].append(div);

                var div2 = document.createElement("div");
                var text2 = document.createElement("span");
                text2.setAttribute("class", "paragrafo-"+c+"");
                div2.appendChild(text2);

                tempblock.querySelectorAll(".blockyinfopergunta")[0].append(div2);

                var div3 = document.createElement("div");
                div3.setAttribute("class", "panel");
                div3.textContent = "Outputs "+c+"";
                var text3 = document.createElement("div");
                text3.setAttribute("class", "link output_"+c+"");
                div3.appendChild(text3);

                tempblock.querySelectorAll(".multiple")[0].append(div3);

                let idNode = currentTarget.parentElement.id.slice(5);
                editor.addNodeOutput(idNode);
                editor.updateConnectionNodes('node-'+idNode+'');

                const links =  document.querySelectorAll(`#node-${idNode} .drawflow_content_node .link`);
                console.log(links);
                links.forEach((item) => {
                  const target = document.querySelector(`#node-${idNode} .outputs .${item.classList[1]}`);
                  if(target != null) {
                    const pos = item.getBoundingClientRect();
                    const targetPos = target.getBoundingClientRect();
                    target.style.top = `${pos.y - targetPos.y}px`;
                    target.style.left = `${pos.x - targetPos.x}px`;
                  }
                })

                editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");
                atualizaDataPergunta();

                $("#inp"+c+"").keyup(function () {
                  tempblock.querySelectorAll(".perguntaflow-"+c+"")[0].value = document.querySelector("#inp"+c+"").value;
                  tempblock.querySelectorAll(".paragrafo-"+c+"")[0].innerText = document.querySelector("#inp"+c+"").value;

                  editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");
                  atualizaDataPergunta();
                });

              });

              $(document).on('click', '.btn_remove_pergunta', function(){  
               var button_id = $(this).attr("id");   
               $('#rowss'+button_id+'').remove();
               tempblock.querySelectorAll(".perguntaflow-"+button_id+"")[0].remove();
               tempblock.querySelectorAll(".paragrafo-"+button_id+"")[0].remove();

               editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");
               atualizaDataPergunta();
             });
            });

          // INICIO PEGA SE O FLUXO TEM DIGITAÇÃO
          var digitacao = tempblock.querySelectorAll(".informadigitacao")[0].value;

          if (digitacao == 1) {
            var digitacao = document.getElementById('digitacaoinput');
            digitacao.checked = true;
            $('#resultadoSlider').css("display", "block");
          } else {
            var digitacao = document.getElementById('digitacaoinput');
            digitacao.checked = false;
            $('#resultadoSlider').css("display", "none");
          }
          // FIM PEGA SE O FLUXO TEM DIGITAÇÃO

          // INICIO ALTERA O FLUXO DA DIGITAÇÃO
          $("input:checkbox[id='digitacaoinput']").click(function(e) {
            var digitacaoinput = $("input[id='digitacaoinput']:checked").val();

            if (digitacaoinput == 1) {
              tempblock.querySelectorAll(".informadigitacao")[0].value = 1;
              $('#resultadoSlider').css("display", "block");
            } else {
              tempblock.querySelectorAll(".informadigitacao")[0].value = 0;
              $('#resultadoSlider').css("display", "none");
            }

            editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");

            let idParente = currentTarget.parentElement.id.slice(5);
            atualizaDataPergunta();
          });
          // FIM ALTERA O FLUXO DA DIGITAÇÃO

          // INICIO PEGA SE O FLUXO TEM INTERAÇÃO DO CONTATO
          var interacaoContato = tempblock.querySelectorAll(".aguardarresposta")[0].value;

          if (interacaoContato == 1) {
            var interacaoContato = document.getElementById('interecao_contato');
            interacaoContato.checked = true;
            $('#aguarda-resposta').css("display", "block");
          } else {
            var interacaoContato = document.getElementById('interecao_contato');
            interacaoContato.checked = false;
            $('#aguarda-resposta').css("display", "none");
          }
          // FIM PEGA SE O FLUXO TEM INTERAÇÃO DO CONTATO

          // INICIO ALTERA O FLUXO DA INTERAÇÃO DO CONTATO
          $("input:checkbox[id='interecao_contato']").click(function(e) {
            var interecaoContatos = $("input[id='interecao_contato']:checked").val();

            if (interecaoContatos == 1) {
              tempblock.querySelectorAll(".aguardarresposta")[0].value = 1;
              $('#aguarda-resposta').css("display", "block");
            } else {
              tempblock.querySelectorAll(".aguardarresposta")[0].value = 0;
              $('#aguarda-resposta').css("display", "none");
            }

            editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");

            let idParente = currentTarget.parentElement.id.slice(5);
            atualizaDataPergunta();
          });
          // FIM ALTERA O FLUXO DA INTERAÇÃO DO CONTATO

          document.querySelectorAll("#identificacaoPainel")[0].value = tempblock.querySelectorAll(".titleHeader")[0].value;

          $(".identificacaoPainel").keyup(function () {
            tempblock.querySelectorAll(".title-header")[0].innerText = document.querySelector("#identificacaoPainel").value;
            tempblock.querySelectorAll(".titleHeader")[0].value = document.querySelector("#identificacaoPainel").value;

            editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");

            let idParente = currentTarget.parentElement.id.slice(5);
            atualizaDataPergunta();

          });

          document.querySelector("#descriptioninputpergunta").value = tempblock.querySelectorAll(".blockyinfotexto")[0].innerText;

          $("#descriptioninputpergunta").keyup(function () {
            tempblock.querySelectorAll(".blockyinfotexto")[0].innerText = document.querySelector("#descriptioninputpergunta").value;
            tempblock.querySelectorAll("#mensagemtexto")[0].value = document.querySelector("#descriptioninputpergunta").value;

            editor.drawflow.drawflow[editor.module].data[currentTarget.parentElement.id.slice(5)].html = currentTarget.innerHTML.replaceAll("display: block;","display: none;");
            atualizaDataPergunta();
          });

          function atualizaDataPergunta() {

            var idParenteData = editor.getNodeFromId(currentTarget.parentElement.id.slice(5));
            var idParente = idParenteData.id;

            var titulo = tempblock.querySelectorAll(".titleHeader")[0].value;
            var tipo = tipoFluxo;
            var informadigitacao = tempblock.querySelectorAll(".informadigitacao")[0].value;
            var aguardarresposta = tempblock.querySelectorAll(".aguardarresposta")[0].value;
            var mensagemtexto = tempblock.querySelectorAll(".mensagemtexto")[0].value;
            var segundodigitacao = tempblock.querySelectorAll(".segundodigitacao")[0].value;

            editor.updateNodeDataFromId(idParente, { titulo: titulo, tipo: tipo, informadigitacao: informadigitacao, aguardarresposta: aguardarresposta, mensagemtexto: mensagemtexto, segundodigitacao: segundodigitacao });
          }

          }else{

          }

        }

      }
    }

    //addEventListener("mouseup", doneTouch, false);
    addEventListener("dblclick", doneTouch, false);  

    editor.on('moduleCreated', function(name) {
      console.log("Module Created " + name);
    })

    editor.on('moduleChanged', function(name) {
      console.log("Module Changed " + name);
    })

    editor.on('connectionCreated', (obj) => {
      console.log(obj);
    })

    editor.on('connectionRemoved', (obj) => {
      console.log(obj);
    })

    editor.on('nodeMoved', function(id) {
      console.log("Node moved " + id);
    })

    editor.on('zoom', function(zoom) {
      console.log('Zoom level ' + zoom);
    })

    editor.on('translate', function(position) {
      console.log('Translate x:' + position.x + ' y:'+ position.y);
    })

    editor.on('addReroute', function(id) {
      console.log("Reroute added " + id);
    })

    editor.on('removeReroute', function(id) {
      console.log("Reroute removed " + id);
    })
    /* DRAG EVENT */

    var exportvalue = null;
    function export2(){
      exportvalue = editor.export();
      console.log(JSON.stringify(exportvalue));
    }

    /* Mouse and Touch Actions */

    var elements = document.getElementsByClassName('drag-drawflow');
    for (var i = 0; i < elements.length; i++) {
      elements[i].addEventListener('touchend', drop, false);
      elements[i].addEventListener('touchmove', positionMobile, false);
      elements[i].addEventListener('touchstart', drag, false );
    }

    var mobile_item_selec = '';
    var mobile_last_move = null;
   function positionMobile(ev) {
     mobile_last_move = ev;
   }

   function allowDrop(ev) {
      ev.preventDefault();
    }

    function drag(ev) {
      if (ev.type === "touchstart") {
        mobile_item_selec = ev.target.closest(".drag-drawflow").getAttribute('data-node');
      } else {
      ev.dataTransfer.setData("node", ev.target.getAttribute('data-node'));
      }
    }

    function drop(ev) {
      if (ev.type === "touchend") {
        var parentdrawflow = document.elementFromPoint( mobile_last_move.touches[0].clientX, mobile_last_move.touches[0].clientY).closest("#drawflow");
        if(parentdrawflow != null) {
          addNodeToDrawFlow(mobile_item_selec, mobile_last_move.touches[0].clientX, mobile_last_move.touches[0].clientY);
        }
        mobile_item_selec = '';
      } else {
        ev.preventDefault();
        var data = ev.dataTransfer.getData("node");
        addNodeToDrawFlow(data, ev.clientX, ev.clientY);
      }

    }

    function addNodeToDrawFlow(name, pos_x, pos_y) {
      if(editor.editor_mode === 'fixed') {
        return false;
      }
      pos_x = pos_x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)) - (editor.precanvas.getBoundingClientRect().x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)));
      pos_y = pos_y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)) - (editor.precanvas.getBoundingClientRect().y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)));

      switch (name) {

        case 'inicial':
        var inicial = `
        <div class="title"><i class="fas fa-play-circle text-success"></i> Passo Inicial</div>
        `;
          editor.addNode('inicial', 0,  1, pos_x, pos_y, 'inicial', {}, inicial );
          break;

          case 'template_pergunta':
            var template_pergunta = `
            <div class="title"><i class="fas fa-paperclip me-1"></i> <span class="title-header">Pergunta<span></div>
            <div class="panel">
              <div class='blockyinfotexto'>Escolha uma opção abaixo:</div>
              <div class='blockyinfopergunta'></div>
            </div>
            <div class="multiple"></div>
            <input type="hidden" name="titleHeader" df-temp-title id="titleHeader" class="titleHeader" value="Pergunta">
            <input type="hidden" name="tipomensagem" id="tipomensagem" class="tipomensagem" value="pergunta" />
            <input type="hidden" name="informadigitacao" id="informadigitacao" class="informadigitacao" value="1" />
            <input type="hidden" name="aguardarresposta" id="aguardarresposta" class="aguardarresposta" value="1" />
            <input type="hidden" name="mensagemtexto" id="mensagemtexto" class="mensagemtexto" value="Escolha uma opção abaixo:" />
            <input type="hidden" name="segundodigitacao" id="segundodigitacao" class="segundodigitacao" value="1" />
            <div id='resultadoPergunta'></div>`;

            editor.addNode('template_pergunta', 1, 0, pos_x, pos_y, 
              'template_pergunta',{
              "titulo": 'Pergunta',
              "tipo": 'pergunta',
              "informadigitacao":'1',
              "aguardarresposta": '1',
              "mensagemtexto": 'Escolha uma opção abaixo:',
              "segundodigitacao": '1'},
              template_pergunta);
            break;

        default:
      }
    }

  var transform = '';
  function showpopup(e) {
    e.target.closest(".drawflow-node").style.zIndex = "9999";
    e.target.children[0].style.display = "block";
    //document.getElementById("modalfix").style.display = "block";

    //e.target.children[0].style.transform = 'translate('+translate.x+'px, '+translate.y+'px)';
    transform = editor.precanvas.style.transform;
    editor.precanvas.style.transform = '';
    editor.precanvas.style.left = editor.canvas_x +'px';
    editor.precanvas.style.top = editor.canvas_y +'px';
    console.log(transform);

    //e.target.children[0].style.top  =  -editor.canvas_y - editor.container.offsetTop +'px';
    //e.target.children[0].style.left  =  -editor.canvas_x  - editor.container.offsetLeft +'px';
    editor.editor_mode = "fixed";

  }

   function closemodal(e) {
     e.target.closest(".drawflow-node").style.zIndex = "2";
     e.target.parentElement.parentElement.style.display  ="none";
     //document.getElementById("modalfix").style.display = "none";
     editor.precanvas.style.transform = transform;
       editor.precanvas.style.left = '0px';
       editor.precanvas.style.top = '0px';
      editor.editor_mode = "edit";
   }

    function changeModule(event) {
      var all = document.querySelectorAll(".menu ul li");
        for (var i = 0; i < all.length; i++) {
          all[i].classList.remove('selected');
        }
      event.target.classList.add('selected');
    }

    function changeMode(option) {

    //console.log(lock.id);
      if(option == 'lock') {
        lock.style.display = 'none';
        unlock.style.display = 'block';
      } else {
        lock.style.display = 'block';
        unlock.style.display = 'none';
      }

    }

Then you double click to show the modal

and uses the Add question button to dynamically add outputs

jerosoler commented 1 year ago

It is impossible to check your code, without your css or with jquery. Try going next time you see a codepen where to test the example...

The problem is that when adding a new node you change the position again.

The best solution is to send the element to its natural position and recalculate the outputs.

Try adding:

              target.style.top = "auto";
                target.style.left = "auto";

Complet example:

editor.addNode('question', 1, 3, 300, 200, 'question', {}, `
        <div class="title">Ask question</div>
        <div class="panel">Nice to meet yout (name)...</div>
        <div class="panel">Custom API</div>
        <div class="multiple">
            <div class="panel">Yes<div class="link output_1"></div></div>
            <div class="panel">No<div class="link output_2"></div></div>
            <div class="panel">No Match<div class="link output_3"></div></div>
        </div>
    ` );

    const c = 4;
    var div3 = document.createElement("div");
                div3.setAttribute("class", "panel");
                div3.textContent = "Outputs "+c+"";
                var text3 = document.createElement("div");
                text3.setAttribute("class", "link output_"+c+"");
                div3.appendChild(text3);

                document.querySelectorAll(".multiple")[0].append(div3);
                editor.addNodeOutput(1);

        const idNum = 1;
        const links =  document.querySelectorAll(`#node-${idNum} .drawflow_content_node .link`);
        links.forEach((item) => {

            const target = document.querySelector(`#node-${idNum} .outputs .${item.classList[1]}`);

            if(target != null) {
                target.style.top = "auto";
                target.style.left = "auto";
                const pos = item.getBoundingClientRect();
                const targetPos = target.getBoundingClientRect();
                console.log(pos, targetPos)
                target.style.top = `${pos.y - targetPos.y}px`;
                target.style.left = `${pos.x - targetPos.x}px`;
            }
        })

and result:

image

cewebdesigner commented 1 year ago

thanks dude, it worked