jerosoler / Drawflow

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

How to add a node at the center of the screen? #229

Closed ElHex closed 3 years ago

ElHex commented 3 years ago

I've been trying to retrieve the viewport's coordinates relative to the drawflow DOM element (keeping in mind the transform property)

My goal is to add a node in the center of the screen whatever the user is looking atm

jerosoler commented 3 years ago

Hello @ElHex

View a simple funcion:

        function addNodeButton() {
            const { width, height } = editor.container.getBoundingClientRect();
            const x = width / 2;
            const y = height /2;

            let pos_x = x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)) - (editor.precanvas.getBoundingClientRect().x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)));
            let pos_y = y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)) - (editor.precanvas.getBoundingClientRect().y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)));

            pos_x = pos_x - 97;     // 97 is a div witdh / 2 of node
            pos_y = pos_y - 37;     // 37 is a div height / 2 of node

            editor.addNode('test', 1,1, pos_x, pos_y, 'test', {}, `<div>Hi!!</div>`);
        }

This function contemplates: Canvas translate, canvas zoom.

The only problem is here:

pos_x = pos_x - 97;     // 97 is a div witdh / 2 of node
pos_y = pos_y - 37;     // 37 is a div height / 2 of node

We cannot know the width and height of the node before inserting it.

Normally the nodes have a maximum width in these applications but maybe not a height. Even though the height might not be so necessary.

Other option is watch dom changes. We can already get the height and width of the node

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

          editor.start();

          const callback = function(mutationsList, observer) {
          for(const mutation of mutationsList) {
            if (mutation.type === 'childList') {
              if(mutation.addedNodes[0]) {
                if(mutation.addedNodes[0].nodeName === "DIV" && mutation.addedNodes[0].classList[0] === "parent-node") {
                  const idNode = mutation.addedNodes[0].children[0].id.slice(5);

                  const { width, height } = editor.container.getBoundingClientRect();
                    const x = width / 2;
                    const y = height /2;

                    let pos_x = x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)) - (editor.precanvas.getBoundingClientRect().x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)));
                    let pos_y = y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)) - (editor.precanvas.getBoundingClientRect().y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)));

                    pos_x = pos_x - ( mutation.addedNodes[0].children[0].getBoundingClientRect().width / 2);    
                    pos_y = pos_y - ( mutation.addedNodes[0].children[0].getBoundingClientRect().height / 2);  

                    editor.drawflow.drawflow[editor.module].data[idNode].pos_x = pos_x;
                    editor.drawflow.drawflow[editor.module].data[idNode].pos_y = pos_y;
                    mutation.addedNodes[0].children[0].style.top =  pos_y+"px"
                    mutation.addedNodes[0].children[0].style.left =  pos_x+"px"
                } 
              }
            }
          }
        }
        const observer = new MutationObserver(callback);
        const config = { attributes: true, childList: true, subtree: true };
        observer.observe(id, config);

        function addNodeButton() {
            editor.addNode('test', 1,1, 0, 0, 'test', {}, `<div>Hi!!</div>`);
        }

This second option can bring more problems when importing ... The function would have to be adjusted ...

It may be that the functions still need to adjust some pixels.

rsvidevince commented 3 years ago

I saved the translation coordinates every time:

        editor.on('translate', function(position) {
          current_x = (-1 * position.x) + 50
          current_y = -1 * position.y - 50
        })

Then, when I create a new node, I use this positioning:

editor.addNode('novo_segmento', 1, 1, current_x, (current_y + 100), 'some-class', {}, blockTemplate)

This way, the blocks are always created in the top left. If you know your container width and height, I bet you can adapt that so they are always created in the center (:

ElHex commented 3 years ago

@jerosoler

            const { width, height } = editor.container.getBoundingClientRect();
            const x = width / 2;
            const y = height /2;

            let pos_x = x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)) - (editor.precanvas.getBoundingClientRect().x * ( editor.precanvas.clientWidth / (editor.precanvas.clientWidth * editor.zoom)));
            let pos_y = y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)) - (editor.precanvas.getBoundingClientRect().y * ( editor.precanvas.clientHeight / (editor.precanvas.clientHeight * editor.zoom)));

            pos_x = pos_x - 97;     // 97 is a div witdh / 2 of node
            pos_y = pos_y - 37;     // 37 is a div height / 2 of node

works as intended! my nodes all have a constant width and height! thanks!