GithubHelp home page GithubHelp logo

Zoom in/out about flowy HOT 30 OPEN

alyssaxuu avatar alyssaxuu commented on May 19, 2024 10
Zoom in/out

from flowy.

Comments (30)

alyssaxuu avatar alyssaxuu commented on May 19, 2024 7

That could definitely be a good idea, I'll look into it.

from flowy.

yellow1912 avatar yellow1912 commented on May 19, 2024 2

I see what you mean, can it work the same way with the import to make things consistent?

{
	"html": "",
	"blockarr": [],
	"blocks": [
		{
			"id": 1,
			"parent": 0,
			"data": [
				{
				"name": "blockid",
				"value": "1"
				}
			],
			"attr": [
				{
				"id": "block-id",
				"class": "block-class"
				}
			]
		}
	]
}

Regarding the HTML, I think we should avoid touching any HTML if possible and only deal with json data. There could be a render callback that accept a block data then return a rendered HTML string perhaps?

from flowy.

cdebattista avatar cdebattista commented on May 19, 2024 2

Finally got it ! next step panning.
screencast-crm-preprod fboard app-2020 10 19-15_36_04

var zoom = 1;
...
...
flowy.zoom = function(value = 0, restore = false){
	zoom += value;
	if(zoom > 1 || zoom < 0.1 || restore){
		zoom = 1;
	}
	canvas_div.style.zoom = zoom;
	canvas_div.childNodes.forEach(function(node){
		if (node.className.indexOf("arrowblock") < 0) {
			let id = parseInt(node.querySelector(".blockid").value);
			let block = blocks.filter(a => a.id == id)[0];
			block.x = ((node.getBoundingClientRect().left + window.scrollX) + (parseInt(window.getComputedStyle(node).width) / 2) + canvas.scrollLeft);
			block.y = ((node.getBoundingClientRect().top + window.scrollY) + (parseInt(window.getComputedStyle(node).height) / 2) + canvas.scrollTop);
		}
	});
}
...
...
var xpos = ((drag.getBoundingClientRect().left + window.scrollX) + (parseInt(window.getComputedStyle(drag).width) / 2) + canvas_div.scrollLeft) / zoom;
var ypos = ((drag.getBoundingClientRect().top + window.scrollY) + canvas_div.scrollTop) / zoom
zoom: function(){

        document.querySelector('.zoom-in').addEventListener('click', () => {
            flowy.zoom(+0.1);
        });
        document.querySelector('.zoom-out').addEventListener('click', () => {
            flowy.zoom(-0.1);
        });
        document.querySelector('.zoom-restore').addEventListener('click', () => {
            flowy.zoom(null, true);
        });
    },

from flowy.

yellow1912 avatar yellow1912 commented on May 19, 2024 1

I think right now all the "actions" require interaction from the user (drag and drop). There is an import method but it would affect the whole tree. Perhaps we could extend the import and allow specifying the root of the import, would that work?

from flowy.

yellow1912 avatar yellow1912 commented on May 19, 2024

In addition to zooming in and out, perhaps this is more useful: module. I find this concept really useful on Botstar.com which has a comprehensive UI to build bot flows. The module allow you to group multiple steps and hide them by default.
image

from flowy.

yellow1912 avatar yellow1912 commented on May 19, 2024

NVM, I found #29 which proposes the idea of a wrapper outside of flowy to keep things simple. I think that's quite amazing to be honest. It would be nice if we do have the api to addBlock and removeBlock exposed, that would help alot.

from flowy.

alyssaxuu avatar alyssaxuu commented on May 19, 2024

NVM, I found #29 which proposes the idea of a wrapper outside of flowy to keep things simple. I think that's quite amazing to be honest. It would be nice if we do have the api to addBlock and removeBlock exposed, that would help alot.

What would "addBlock" being exposed look like? There is currently onSnap which gets triggered when a block is able to be attached to another block, which lets you to either prevent or allow the attachment. Just added a method for the block removal.

from flowy.

alyssaxuu avatar alyssaxuu commented on May 19, 2024

I think right now all the "actions" require interaction from the user (drag and drop). There is an import method but it would affect the whole tree. Perhaps we could extend the import and allow specifying the root of the import, would that work?

I see, so you suggest a way to import blocks under a certain parent? I can definitely make it so that blocks can be added programmatically (and not just individual blocks, also trees), but the problem is, how would that work? Blocks can be 100% custom - so would it be a method that accepts some HTML, an array of blocks, and the ID of the desired parent? Not sure what would be the most intuitive here.

from flowy.

pilootchoum avatar pilootchoum commented on May 19, 2024

Hello,
I was thinking about implementing this feature as well,
Do you think using the scale property on all dom element on the canvas, and updating the blocks array would be enough?
I mean scaling with the same ratio the blocks? As it did not succeed so far.
If you have a direction, that would be great ;)

from flowy.

alyssaxuu avatar alyssaxuu commented on May 19, 2024

Hello,
I was thinking about implementing this feature as well,
Do you think using the scale property on all dom element on the canvas, and updating the blocks array would be enough?
I mean scaling with the same ratio the blocks? As it did not succeed so far.
If you have a direction, that would be great ;)

I assume you mean using transform: scale()? It's certainly possible, I would just need to make sure this doesn't cause any conflicts with the block positioning/dimensions.

I haven't been prioritizing this feature simply because I see a potential problem - if the canvas area is scaled up/down, how would it look/feel like dragging and dropping a differently sized block there (e.g. in the demo, from the left panel)? I'm just not sure if it would feel smooth or intuitive.

Screen Shot 2020-04-24 at 8 22 19 AM

Here's an image of what I mean. It might just feel weird, but I'm open to hearing your thoughts.

from flowy.

pilootchoum avatar pilootchoum commented on May 19, 2024

Sure I thought about this too, maybe, I would have forced the user then to reset the zoom before dropping a new element on the canvas, but that would be out of Flowy charge I mean.

Its just that after adding a few blocks, it seems to me that it becomes quite hard to see properly the canvas and maybe rearrange the blocks if needed.

But one can also just use the browser zoom feature if needed. Anyway that feature would be awesome I think ;)

from flowy.

alyssaxuu avatar alyssaxuu commented on May 19, 2024

Sure I thought about this too, maybe, I would have forced the user then to reset the zoom before dropping a new element on the canvas, but that would be out of Flowy charge I mean.

Its just that after adding a few blocks, it seems to me that it becomes quite hard to see properly the canvas and maybe rearrange the blocks if needed.

But one can also just use the browser zoom feature if needed. Anyway that feature would be awesome I think ;)

Hmm in that case the developer could simply use transform: scale() on the canvas themselves, since either way the block snapping / dragging functionality would be off when resizing. So I don't see it being useful as a method, in that sense. Like I said, unless someone thinks of a better way to go about it - maybe it could work when resized, just that when the block is dropped into the flowchart it would resize to match automatically?

from flowy.

pilootchoum avatar pilootchoum commented on May 19, 2024

Yes that would be the best I think,
Once dropped the block should resize automaticlly to the new scale.

from flowy.

pilootchoum avatar pilootchoum commented on May 19, 2024

Hello @alyssaxuu,

I tried to implement it myself doing the following :

on zoom in I am changing the scale of every childNode of the canvas except the arrows :
document.getElementById("canvas").childNodes.forEach((node) => { if (node.className.indexOf("arrowblock") < 0) { node.style.transform = "scale(" + this.currentScale + ")"; } });

Then in flowy, I am updating the height and witdth of every block :

flowy.scale = function (scale) { blocks.forEach(function (block) { block.width = block.width * scale; block.height = block.height * scale; }); if (blocks.length > 1) { rearrangeMe(); } };

I thought that the rearrangeMe function would update then the childWidth properties, and redraw the arrows to fit the new size of the element, however it does not seem to work properly.

Do you have any hint on how to do that in a better way?

from flowy.

alyssaxuu avatar alyssaxuu commented on May 19, 2024

Hello @alyssaxuu,

I tried to implement it myself doing the following :

on zoom in I am changing the scale of every childNode of the canvas except the arrows :
document.getElementById("canvas").childNodes.forEach((node) => { if (node.className.indexOf("arrowblock") < 0) { node.style.transform = "scale(" + this.currentScale + ")"; } });

Then in flowy, I am updating the height and witdth of every block :

flowy.scale = function (scale) { blocks.forEach(function (block) { block.width = block.width * scale; block.height = block.height * scale; }); if (blocks.length > 1) { rearrangeMe(); } };

I thought that the rearrangeMe function would update then the childWidth properties, and redraw the arrows to fit the new size of the element, however it does not seem to work properly.

Do you have any hint on how to do that in a better way?

I believe the best way to go about it would be to use transform scale to resize the canvas' contents, and then immediately after replace all the array properties of the blocks (I see you updated height and width, but there's also the X and Y properties that are important which you're missing. Childwidth is used to store how much space all the children elements one next to the other (including spacing in between) takes in order to then calculate how much offset a new block being dragged in should have. I suppose if you changed all those properties and ran the rearrangeMe function it should work (haven't tested it though).

from flowy.

cdebattista avatar cdebattista commented on May 19, 2024

Someone have a solution ?
screencast-crm-preprod fboard app-2020 10 19-10_20_38

One solution works but arrows are !@{"#

        let _this = this;
        let ratio = this.scale / this.previousScale;
        let canvas = document.getElementById("canvas");
        //console.log(ratio);

        canvas.childNodes.forEach(function(node){

            let nodeX = parseFloat(window.getComputedStyle(node).left);
            let nodeY = parseFloat(window.getComputedStyle(node).top);

            let style = window.getComputedStyle(node);
            let matrix = new WebKitCSSMatrix(style.transform);

            let previousTx = (- matrix.m41 * _this.previousScale);
            let previousTy = (- matrix.m42 * _this.previousScale);

            let previousDx = (nodeX * _this.previousScale);
            let previousDy = (nodeY * _this.previousScale);

            let newTx = ((previousTx * ratio + previousDx * (ratio - 1)) / _this.scale);
            let newTy = ((previousTy * ratio + previousDy * (ratio - 1)) / _this.scale);

            let newX = nodeX - newTx;
            let newY = nodeY - newTy;

            //node.style.transform = "scale(" + _this.scale + ")";

            //node.style.transform = "scale(" + _this.scale + ") translate(" + newTx + "px, " + newTy + "px)";
            //node.style.transformOrigin = "0 0";


            if (node.className.indexOf("arrowblock") < 0) {
                let blockProperties = {
                    id: parseInt(node.querySelector(".blockid").value),
                    x: ((node.getBoundingClientRect().left + window.scrollX) + (parseInt(window.getComputedStyle(node).width) / 2) + canvas.scrollLeft) * _this.scale,
                    y: ((node.getBoundingClientRect().top + window.scrollY) + (parseInt(window.getComputedStyle(node).height) / 2) + canvas.scrollTop) * _this.scale,
                    width: (parseInt(window.getComputedStyle(node).width)) * _this.scale,
                    height: (parseInt(window.getComputedStyle(node).height)) * _this.scale
                }
                let blocStyles = {
                    top : ((node.getBoundingClientRect().top + window.scrollY) - (canvas.getBoundingClientRect().top + window.scrollY) + canvas.scrollTop) * _this.scale,
                    left : ((node.getBoundingClientRect().left + window.scrollX) - (canvas.getBoundingClientRect().left + window.scrollX) + canvas.scrollLeft) * _this.scale
                }
                console.log(blockProperties, blocStyles);
                node.style.left = blocStyles.left + 'px';
                node.style.top = blocStyles.top + 'px';
                //node.style.transform = "scale(" + _this.scale + ")";
                node.style.transform = "scale(" + _this.scale + ") translate(" + newTx + "px, " + newTy + "px)";
                //node.style.transformOrigin = "0 0";
                //node.style.left = newX + 'px';
                //node.style.top = newY + 'px';
                flowy.transformBlocks(blockProperties.id, 'x', blockProperties.x);
                flowy.transformBlocks(blockProperties.id, 'y', blockProperties.y);
                flowy.transformBlocks(blockProperties.id, 'width', blockProperties.width);
                flowy.transformBlocks(blockProperties.id, 'height', blockProperties.height);

            }else{
                node.style.transform = "scale(" + _this.scale + ")";
            }

            /*console.log(nodeX, nodeY);
            console.log(previousTx, previousTy);
            console.log(previousDx, previousDy);
            console.log(newTx, newTy);
            console.log(newX, newY);*/

        });
        //flowy.scale(this.scale);
        console.log(flowy.output());

I tried a CSS trick and it works but now have to changes the x,y,width,height,childwitdh and the code above don't work

        canvas.style.transform = "scale(" + this.scale + ")";
        canvas.style.width = "calc(" + 100 / this.scale  + "% - 0px)"
        canvas.style.height = "calc(" + 100 / this.scale  + "% - 0px)"
        canvas.style.top = (100 - (100 / this.scale)) / 2 + "%"
        canvas.style.left = (100 - (100 / this.scale)) / 2 + "%"

from flowy.

ebrahimahmadi avatar ebrahimahmadi commented on May 19, 2024

@cdebattista in the approach you mentioned, when the tree becomes big and wide the indicator will not attach to the target node and will distance far away from the node you want. As zoom increases the distance will be increased more. Do you have any idea about that?

In my opinion, the indicator's left property should be tied to the canvas left property as well as so.

from flowy.

robhoward avatar robhoward commented on May 19, 2024

So I had planned to implement this as well, we came almost to the same implementation. My UX is a little different. I've also been going through and refactoring the code into more functions.

Still a few issues with scroll position for large workflows.

image

image

from flowy.

ravikoppula avatar ravikoppula commented on May 19, 2024

Hi Rob Howard

I am using flowy.js script and at the moment I failed to implement the ZOOM IN & OUT feature.

I really don't have idea how to implement. I gone through the Git comments but it does help me out any luck.

Can any one please share the piece of logic with.

Thank you so much in advance.

from flowy.

robhoward avatar robhoward commented on May 19, 2024

Sure:

  1. I have a global var:
    var zoom = 100;

  2. Some Zoom functions:

     // ┌────────────────────────────────────────────────────────────────────
     // │ Zooms the display out making the blocks smaller
     // └────────────────────────────────────────────────────────────────────
     flowy.zoomOut = function () {
         let scale_factor = 5;
         zoom = zoom - scale_factor;
    
         flowy.setZoom();
         flowy.draw();
     }
    
     // ┌────────────────────────────────────────────────────────────────────
     // │ Zooms the display in making the blocks larger
     // └────────────────────────────────────────────────────────────────────
     flowy.zoomIn = function () {
         let scale_factor = 5;
         zoom = zoom + scale_factor;
    
         flowy.setZoom();
         flowy.draw();
     }
    
     // ┌────────────────────────────────────────────────────────────────────
     // │ Sets the current zoom
     // └────────────────────────────────────────────────────────────────────
     flowy.setZoom = function () {
         flowy.getZoom();
         canvas_div.style.zoom = `${zoom}%`;
     }
    
     // ┌────────────────────────────────────────────────────────────────────
     // │ Gets the current zoom
     // └────────────────────────────────────────────────────────────────────
     flowy.getZoom = function () {
    
         if (zoom > 100) {
             zoom = 100;
         }
    
         if (zoom < 40) {
             zoom = 40;
         }
    
         return zoom;
     }
    
  3. In flowy.moveBlock I recalculate the mouse position:

         if (zoom < 1) {
             mouse_x = mouse_x * (zoom / 100);
             mouse_y = mouse_y * (zoom / 100);
         }
    

Also in moveBlock (but refactored into another function:

        let z = zoom / 100;

        // Get the center point position of the dragged block and offset with zoom
        var xpos = ((drag.getBoundingClientRect().left + window.scrollX) + (parseInt(window.getComputedStyle(drag).width) / 2) + canvas_div.scrollLeft) / z;
        var ypos = ((drag.getBoundingClientRect().top + window.scrollY) + canvas_div.scrollTop) / z;

Then in my UX I have this wired up with the plus/minus keys and the UX in screen shot above. Hope that helps!

from flowy.

robhoward avatar robhoward commented on May 19, 2024

You might want to instead look at #105. Scroll to the bottom and @cdebattista posted a solid update. I found it this morning and have been converting my zoom behavior to use his.

from flowy.

ravikoppula avatar ravikoppula commented on May 19, 2024

Hi Rob Howard

Thank you so much for the response.

Can you please assist me how can I use the user interface part +/- as shown in the above image.

Do you attached the code? I cant see any out come after I apply the code you had attached.

Please assist me.

from flowy.

robhoward avatar robhoward commented on May 19, 2024

from flowy.

ravikoppula avatar ravikoppula commented on May 19, 2024

Thank you for the response.

Let me explain to you the way I added your code in my project.

step 1. Downloaded the code from the Git repo https://github.com/alyssaxuu/flowy
step 2: In the flowy.min.js file I had added the below strip
var zoom = 100; Global variable.
// ┌────────────────────────────────────────────────────────────────────
// │ Zooms the display out making the blocks smaller
// └────────────────────────────────────────────────────────────────────
flowy.zoomOut = function () {
let scale_factor = 5;
zoom = zoom - scale_factor;

               flowy.setZoom();
               flowy.draw();
           }
          
           // ┌────────────────────────────────────────────────────────────────────
           // │ Zooms the display in making the blocks larger
           // └────────────────────────────────────────────────────────────────────
           flowy.zoomIn = function () {
               let scale_factor = 5;
               zoom = zoom + scale_factor;
          
               flowy.setZoom();
               flowy.draw();
           }
          
           // ┌────────────────────────────────────────────────────────────────────
           // │ Sets the current zoom
           // └────────────────────────────────────────────────────────────────────
           flowy.setZoom = function () {
               flowy.getZoom();
               canvas_div.style.zoom = `${zoom}%`;
           }
          
           // ┌────────────────────────────────────────────────────────────────────
           // │ Gets the current zoom
           // └────────────────────────────────────────────────────────────────────
           flowy.getZoom = function () {
          
               if (zoom > 100) {
                   zoom = 100;
               }
          
               if (zoom < 40) {
                   zoom = 40;
               }
          
               return zoom;
           }

  In the **flowy.moveBlock** 
  
       if (zoom < 1) {
           mouse_x = mouse_x * (zoom / 100);
           mouse_y = mouse_y * (zoom / 100);
       }

@NOTE: I have No Idea about the below code ( getBoundingClientRect() is returning an error method name not found ) but I have used the same method name many times in the flowy.min.js file. Indeed I added this code in the flowy.moveBlock
let z = zoom / 100;
// Get the center point position of the dragged block and offset with zoom
var xpos = ((drag.getBoundingClientRect().left + window.scrollX) + (parseInt(window.getComputedStyle(drag).width) / 2)

  • canvas_div.scrollLeft) / z;
    var ypos = ((drag.getBoundingClientRect().top + window.scrollY) + canvas_div.scrollTop) / z;

Step 3: In the index.html page inside the canvas div, I added the below code.

Zoom 100% |

Step4: Based on Id triggered the Zoom IN/ Out functions from the main.js.

These are the steps I followed to implement but still not working.

Can you please advice on this. I really want to implement this feature and release in the production.

If possible can you please hang-up on the skype call or any alternative channel for this fix to be done.

I really apricated your time for replying me back.

Have a great day :)

from flowy.

robhoward avatar robhoward commented on May 19, 2024

from flowy.

sabatale avatar sabatale commented on May 19, 2024

Rob has its own flowy.draw() function so you'd have to build an equivalent to make it work.

You should be able to make cdebattista's code work fairly easily though.

from flowy.

robhoward avatar robhoward commented on May 19, 2024

Yes, that's correct. I ended up doing a massive merge over the last few months of my changes with @cdebattista's code. I just finished it last month.

from flowy.

DrewWeth avatar DrewWeth commented on May 19, 2024

@robhoward I know it's a year later, but if you have it working could you link an example repo or fork? I would love to use this and it seems non-trivial from above!

from flowy.

robhoward avatar robhoward commented on May 19, 2024

from flowy.

belthaZornv avatar belthaZornv commented on May 19, 2024

Would be nice to see a PR of a zoom done tbh

from flowy.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.