Git Product home page Git Product logo

flowy's Introduction

Flowy

Demo
A javascript library to create pretty flowcharts with ease ✨

Dribbble | Twitter | Live demo

Flowy makes creating WebApps with flowchart functionality an incredibly simple task. Build automation software, mind mapping tools, or simple programming platforms in minutes by implementing the library into your project.

You can support this project (and many others) through GitHub Sponsors! ❤️

Made by Alyssa X

Table of contents

Features

Currently, Flowy supports the following:

  • Responsive drag and drop
  • Automatic snapping
  • Automatic scrolling
  • Block rearrangement
  • Delete blocks
  • Automatic block centering
  • Conditional snapping
  • Conditional block removal
  • Import saved files
  • Mobile support
  • Vanilla javascript (no dependencies)
  • npm install

You can suggest new features here

Installation

Adding Flowy to your WebApp is incredibly simple:

  1. Link flowy.min.js and flowy.min.css to your project. Through jsDelivr:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/alyssaxuu/flowy/flowy.min.css"> 
<script src="https://cdn.jsdelivr.net/gh/alyssaxuu/flowy/flowy.min.js"></script>
  1. Create a canvas element that will contain the flowchart (for example, <div id="canvas"></div>)
  2. Create the draggable blocks with the .create-flowy class (for example, <div class="create-flowy">Grab me</div>)

Running Flowy

Initialization

flowy(canvas, ongrab, onrelease, onsnap, onrearrange, spacing_x, spacing_y);
Parameter Type Description
canvas javascript DOM element The element that will contain the blocks
ongrab function (optional) Function that gets triggered when a block is dragged
onrelease function (optional) Function that gets triggered when a block is released
onsnap function (optional) Function that gets triggered when a block snaps with another one
onrearrange function (optional) Function that gets triggered when blocks are rearranged
spacing_x integer (optional) Horizontal spacing between blocks (default 20px)
spacing_y integer (optional) Vertical spacing between blocks (default 80px)

To define the blocks that can be dragged, you need to add the class .create-flowy

Example

HTML

<div class="create-flowy">The block to be dragged</div>
<div id="canvas"></div>

Javascript

var spacing_x = 40;
var spacing_y = 100;
// Initialize Flowy
flowy(document.getElementById("canvas"), onGrab, onRelease, onSnap, onRearrange, spacing_x, spacing_y);
function onGrab(block){
	// When the user grabs a block
}
function onRelease(){
	// When the user releases a block
}
function onSnap(block, first, parent){
	// When a block snaps with another one
}
function onRearrange(block, parent){
	// When a block is rearranged
}

Callbacks

In order to use callbacks, you need to add the functions when initializing Flowy, as explained before.

On grab

function onGrab(block){
	// When the user grabs a block
}

Gets triggered when a user grabs a block with the class create-flowy

Parameter Type Description
block javascript DOM element The block that has been grabbed

On release

function onRelease(){
	// When the user lets go of a block
}

Gets triggered when a user lets go of a block, regardless of whether it attaches or even gets released in the canvas.

On snap

function onSnap(block, first, parent){
	// When a block can attach to a parent
	return true;
}

Gets triggered when a block can attach to another parent block. You can either prevent the attachment, or allow it by using return true;

Parameter Type Description
block javascript DOM element The block that has been grabbed
first boolean If true, the block that has been dragged is the first one in the canvas
parent javascript DOM element The parent the block can attach to

On rearrange

function onRearrange(block, parent){
	// When a block is rearranged
	return true;
}

Gets triggered when blocks are rearranged and are dropped anywhere in the canvas, without a parent to attach to. You can either allow the blocks to be deleted, or prevent it and thus have them re-attach to their previous parent using return true;

Parameter Type Description
block javascript DOM element The block that has been grabbed
parent javascript DOM element The parent the block can attach to

Methods

Get the flowchart data

// As an object
flowy.output();
// As a JSON string
JSON.stringify(flowy.output());

The JSON object that gets outputted looks like this:

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

Here's what each property means:

Key Value type Description
html string Contains the canvas data
blockarr array Contains the block array generated by the library (for import purposes)
blocks array Contains the readable block array
id integer Unique value that identifies a block
parent integer The id of the parent a block is attached to (-1 means the block has no parent)
data array of objects An array of all the inputs within a certain block
name string The name attribute of the input
value string The value attribute of the input
attr array of objects Contains all the data attributes of a certain block

Import the flowchart data

flowy.import(output)

Allows you to import entire flowcharts initially exported using the previous method, flowy.output()

Parameter Type Description
output javascript DOM element The data from flowy.output()

Warning

This method accepts raw HTML and does not sanitize it, therefore this method is vulnerable to XSS. The only safe use for this method is when the input is absolutely trusted, if the input is not to be trusted the use this method can introduce a vulnerability in your system.

Delete all blocks

To remove all blocks at once use:

flowy.deleteBlocks()

Currently there is no method to individually remove blocks. The only way to go about it is by splitting branches manually.

Feel free to reach out to me through email at [email protected] or on Twitter if you have any questions or feedback! Hope you find this useful 💜

flowy's People

Contributors

aelassas avatar alyssaxuu avatar jofont avatar shikunx avatar webdevsimplified avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flowy's Issues

Blocks don't snap correctly after flowchart becomes large in size (blocks do not update positions correctly)

Hello Alyssa X,
Thanks for the awesome work.

I was testing out Flowy, and I noticed that after the flowchart becomes relatively large, Flowy is unable to correctly snap the dragged block with the intended block. I noticed that this issue happens when you start scrolling back and forth (usually horizontally).
For example, try attaching 12 children to one parent block, and you will notice that the dragged block will not correctly determine its position with the block you are trying to snap it to. (assuming you scroll right to try and attach to parent block.)

once you start scrolling back and forth the blocks position does not update correctly.

I think the problem is with window.scrollX and window.scrollY. I tried changing them to canvas_div.scrollX but it would not work. I also tried changing some of the style as overflow attribute could cause some problems. I was using chrome if it matters. I was not able to fix this problem and spent a lot of time trying to fix it.
Any help is greatly appreciated!
Thank you

Flowy broken since 7 days

As I said in the issue #17 I have a bug, but I create that issue because I want it to be independant bug report.

Since the commit 600edfcbbf890a6529dd6cee43c957daf6693fc6 the demo isn't working anymore as the live demo shows it.
When I try to link a block with another and interact with the first one after that, it makes an error in the console :
image
This error come from the line 364, basically it crashes because the array blackstemp that you're filtering have one undefined element in it.

It works fine before the commit 600edfcbbf890a6529dd6cee43c957daf6693fc6.

Conditional snap / connection

Hi,

In real life usage, a block may/may not be able to connect to another block due to biz requirements.

I notice there is "onSnap()" function, best bet may have built-in support to determine the snap is allowed or not based on some rules.

Alternatively, provide the ability to cancel the snap by exposing source/target blocks would help.

Add prefix to css class to avoid conflicts

Right now some of the class names flowy uses seem to be quite generic (such as dragging, etc...). I think it would be nice to either:

  1. Add a prefix flowy- in front of all the classes
  2. Or, to avoid breaking changes with old codes, we can use multiple classes such as "flowy dragging". This allows us to specify the rules by using .flow.dragging for example while still keeping old code works.

Customized block template with links, actions and configurations

Ok, this maybe an overhaul feature that consists of:

  • developer can define any number of blocks (currently it is doing similar thing in function snapping(drag, first) ), may provide a function to do so
  • each block can have its own template
  • each template can have any number of links / actions (like the current "new visitor")
  • each link/action can trigger different user-defined function
  • and the right hand property window can also be customized per block, with good support of dynamic lists etc.

Multiple parent blocks

In some cases, components may have two or more parents, which potentially could lead to these scenarios (not currently supported by flowy):

    +-------+ +-------+
    |       | |       |
    +-+---+-+ +---+---+
      |   |       |
      |   |       |
   +--+   +--+ +--+
   v         v v
+--+--+    +-+-+-+
|     |    |     |
+-----+    +-----+
    +-------+      +-------+
    |       |      |       |
    +-+---+-+      +---+---+
      |   |            |
      |   |            |
   +--+   +--+         |
   v         v         v
+--+--+   +--+--+   +--+--+
|     |   |     |   |     |
+-----+   +--+--+   +--+--+
             |         |
             |         |
             +--+   +--+
                v   v
              +-+---+-+
              |       |
              +-------+

States Language Support

This may be way outside the scope of the project but it would be awesome to reuse data specs already available like States Language and augment the spec with the presentation set used in flowy e.g.

"States": {
  "BlockElem1": {
    "Type": "Trigger",
    "Parameters": {
      "flowy": {
        "x": 850,
        "y": 505,
        "width": 318,
        "height": 120
      }
    }
  },
  "BlockElem2": { ... }
}

Insert a block between 2 existing blocks

Current behavior:
Drag a new block between 2 existing blocks (parent and child) and the new block becomes another child of the parent.

image

Desired behavior:
Drag a new block between 2 existing blocks (parent and child) and the new block inserts between the parent and child.

image

Ideally a block can identify the behavior it wants when dropped, e.g. "split" or "insert". We're going to add this behavior ourselves ... and will likely submit a pull request.

The reason we need this is when you are designing a complex drip sequence, you may want to insert a block between 2 existing items.

We're going to do the same thing with removing a block. The removed block's child we auto re-attach to the removed block's parent.

expose rearrangeMe

It might be nice to expose rearrangeMe - or call this when importing. It's not always possible to export and then import exactly the same data. so for example if migrating from an existing data-structure to flowy it would be nice to not need the html part of output when calling import.

Prevent Drag on Click

Hello,

I know this is already related to one issue, regarding minor moves.
The thing is, Im having kind of the same issue, which cannot exactly be fixed with the onRearrange function.

Is there a simple way to prevent the dragging behaviour of any block, when clicking on one element of the block?

Regards

Snap a block above the root block

I tried to drag and drop a block on top of the root and it did not "snapped" there. I would like to add a new root to entire three.

example: After setting up the example in the image, try to add a new block above the root one. You will not be able to do so.
image

Custom action when dettaching children element

Following up on #26 :

As per the blocks getting removed, I've currently kept it that way for simplicity

Would it be possible to override the default behaviour in the "onRelease()" function ? Or in a new "onRemoveSnap()" function ?

Use cases :

  • If we want to display an alert (asking for confirmation) before removing the block (and its children) ?
  • If we want to snap it back to the previous block instead of removing it ?
  • If we want to trigger custom actions (e.g. save in database) before and/or after a block (and its children) are removed.

Dragging problem after importing data

Hello Alyssa: Congrat and thanks!!!! for your great plugin, I think best of this kind. I´m checking it and I got a problem with the drag performing after flowy. importing data: Data is displayed well but drag stopped working, I mean, when you click on an object this remains stocked in the mouse cursor and never is released. This issue happens under only one condition: on importing after start the page. I recycle output->import and works fine, I publish to database and read it rightaway and works fine, only happens when I restart and import the data from database. it is not a parsing problem, I tryed with a flowy.output string constant as data and when it is imported after page start the fails come out. Message in console is: TypeError: tempblock2 is undefined. You use two functions in main.js drag(block) and release() I "consoled" them inside with some text, and the problem is drag(block) never runs. I reclarify: this issue only happens after reloading the page and flowy.import data. Thanks in advance Alyssa for your help.

Add copy-paste-able tags to README?

It'd be nice to give people the convenient option to copy-paste CDN links into their HTML:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/alyssaxuu/flowy@master/flowy.min.css"></link>

and

<script src="https://cdn.jsdelivr.net/gh/alyssaxuu/flowy@master/flowy.min.js"></script>

and then if you make a release you can change the @master to something like @1.0.0 so the code stays stable on websites that use it, even when updates are made to those files in this repo.

I'm also working on a minimal demo: https://codepen.io/hchiam/pen/qBEogMR

<!DOCTYPE html> Breaks drag and drop

When adding <!DOCTYPE html> to as the first line in demo/index.html drag and drop interaction will break. Child elements will not reposition to parent and connectors will be offset.

To reproduce:

  1. Add <!DOCTYPE html> to first line of demo/index.html
  2. Drag element to canvas, add second element to canvas connected to first
  3. Click hold and drag first element then release

how do the flowy use in the vue project?

`

The block to be dragged

<script src="https://cdn.jsdelivr.net/gh/alyssaxuu/flowy/flowy.min.js"></script> <script> var spacing_x = 40 var spacing_y = 100 // Initialize Flowy flowy( document.getElementById('canvas'), onGrab, onRelease, onSnap, onRearrange, spacing_x, spacing_y ) function onGrab(block) { // When the user grabs a block } function onRelease() { // When the user releases a block } function onSnap(block, first, parent) { // When a block snaps with another one } function onRearrange(block, parent) { // When a block is rearranged } </script>` why can't ran

Conditional Blocks

Hi Alyssa X,

Thanks for the amazing work ! Flowy looks awesome.

Would it be possible to create "Conditional Blocks" (one with one input and two outputs) ?

Screenshot example :
image

Thank you in advance

Submenu item disabled

Wasn't sure if this was intended in demo but the submenu toggle item Triggers becomes permanently disabled (class .navdisabled) once the other items Actions, Loggers are selected (class .navactive).

Strange behaviour when dettaching children element

How to reproduce: drop an element, then drop another element as a child, then a third one as child of the second one, now we hace three connected elements.

Now dettach the second element from the first one by moving it away from the parent. The 2nd and 3rd elements disappear when you release the mouse button. This seemed a bit strange to me, I was expecting those two elements to remain connected and on screen, just independent from the first element.

But the real problem is that form this point on you can't drop another element. You can drag it to the canvas, but upon releasing the mouse button the element stays "glued" to the cursor.

Here's a video of this behaviour

Unusable mobile view (iPhone X)

Congrats on the Smashing Magazine feature.

I wanted to try the tool on my iPhone X, but the canvas is barely visible, and I couldn't maximize it by collapsing the menu. Am I missing something?

ES6 over jQuery

One of the beauties of this project is to have minimum dependency, if we can use ES6 APIs to replace jQuery, it would be even more slim.

Like Element.querySelector over 1 element $('selector'), or Element.querySelectorAll() for multiple element $('selector').

OnSnap not working properly

Hello,

When trying to prevent the snap from one block using the onsnap function and returning false,
it does not work as expected.

I tried also on the demo page just returning false, and once the bloc is released, it is not attached to the parent one (good), but the dragged block itself stay on the canvas kind of lost.

Attached a screenshot.
image

Then as soon as you try to drag another block, the previous one (the lost one) move to the top of the window.

image

There is no javascript error, but you can see in the dom that the lost/dragged block is added in the dom at the root at the dom, whereas it should simply not be there.

image

Prevent accidental removal

Currently (as can be seen on this demo: https://alyssax.com/x/flowy/), if we add:

  1. 1 parent block
  2. 1 child block

Then if we move the child block a bit outside of the perimeter then the child block will be deleted. This can be a disaster if you have a huge tree and you accidentally deleted 1 big branch in that tree (happened to me). I think there should be an option to prevent that to happen, and somehow allow manually trigger a method like flowy.deleteBlock.

Semantic Versionning flowy

I'm currently trying to run locally the project on my PC in order to contribute.
The thing is, I have a bug when I try to link a block to another on the demo project and the error comes from flowy.js itself (line 364 if you wondering).

I assume that the current live demo isn't running on the last master's commit but I'm not able to check it myself since the flowy.js is not signed with a header that could allow us to check the version of the file.

What do you think about beginning to do that?

Ability to group sections

I have a specific requirement to be able to add one or more nodes to a group.

             ----------------
             |               |
             |    -------    |
             |    |  A  |    |
             |    -------    |
             |       |       |
             |       \/      |
             |    -------    |
             |    |  B  |    |
             |    -------    | 
             |       |       |
             --------|--------
                     |
         ----------------------
         |                    |
         |                    |
  -------|--------     -------|--------
 |       \/      |    |       \/      |
 |    -------    |    |    -------    |
 |    |  C  |    |    |    |  E  |    |
 |    -------    |    |    -------    |
 |       |       |    |       |       |
 |       \/      |    |       \/      |
 |    -------    |    |    -------    |
 |    |  D  |    |    |    |  F  |    |
 |    -------    |    |    -------    | 
 |               |    |               |
 ----------------     ---------------- 

Performance & code quality improvement

For example, we have:

document.querySelector(".blockid[value='" + blockstemp[w].id + "']"

where can get a reference and reused within the same scope, there are two scopes with 9 instances each, which means 16 of them can have the same reference, like this:

document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.style.left = (document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().left + window.scrollX) - (canvas_div.getBoundingClientRect().left + window.scrollX) + canvas_div.scrollLeft;
document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.style.top = (document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().top + window.scrollY) - (canvas_div.getBoundingClientRect().top + window.scrollY) + canvas_div.scrollTop;
document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode.style.left = (document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().left + window.scrollX) - (canvas_div.getBoundingClientRect().left + window.scrollX) + canvas_div.scrollLeft;
document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode.style.top = (document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().top + window.scrollY) - (canvas_div.getBoundingClientRect().top + canvas_div.scrollTop) + "px";
canvas_div.appendChild(document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode);
canvas_div.appendChild(document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode);
blockstemp[w].x = (document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().left + window.scrollX) + (parseInt(document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.offsetWidth) / 2) + canvas_div.scrollLeft;
blockstemp[w].y = (document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.getBoundingClientRect().top + window.scrollY) + (parseInt(document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode.offsetHeight) / 2) + canvas_div.scrollTop;

becomes:

const blockParent = document.querySelector(".blockid[value='" + blockstemp[w].id + "']").parentNode;
const arrowParent = document.querySelector(".arrowid[value='" + blockstemp[w].id + "']").parentNode;
blockParent.style.left = (blockParent.getBoundingClientRect().left + window.scrollX) - (canvas_div.getBoundingClientRect().left + window.scrollX) + canvas_div.scrollLeft;
blockParent.style.top = (blockParent.getBoundingClientRect().top + window.scrollY) - (canvas_div.getBoundingClientRect().top + window.scrollY) + canvas_div.scrollTop;
arrowParent.style.left = (arrowParent.getBoundingClientRect().left + window.scrollX) - (canvas_div.getBoundingClientRect().left + window.scrollX) + canvas_div.scrollLeft;
arrowParent.style.top = (arrowParent.getBoundingClientRect().top + window.scrollY) - (canvas_div.getBoundingClientRect().top + canvas_div.scrollTop) + "px";
canvas_div.appendChild(blockParent);
canvas_div.appendChild(arrowParent);
blockstemp[w].x = (blockParent.getBoundingClientRect().left + window.scrollX) + (parseInt(blockParent.offsetWidth) / 2) + canvas_div.scrollLeft;
blockstemp[w].y = (blockParent.getBoundingClientRect().top + window.scrollY) + (parseInt(blockParent.offsetHeight) / 2) + canvas_div.scrollTop;

By doing so, the codebase will be neater, and should perform better.

Drag and drop replacement off

With the recent change to the library when moving linked items repeatedly each release offsets the connector and the parent block slightly. If you drag and drop the same two blocks about 20 times its easy to see. I believe this is related to the <!DOCTYPE html> change.

To reproduce:

  1. Add block
  2. Connect single child block
  3. Drag parent block and reposition (5 or more times), each drag and drop will offset the connector and parent by a couple pixels.

Unable to complete import due to child width error on rearrange

I have exported a configuration with a single block and imported back in. When importing back in I am getting the error TypeError: Cannot set property 'childwidth' of undefined.

This stake traces to:

                if (result[z] != -1) {
                    blocks.filter(a => a.id == result[z])[0].childwidth = totalwidth;
                }

My import configuration is:

{
    "html": "CUSTOM...<input class=\"blockelemtype\" name=\"blockelemtype\" type=\"hidden\" value=\"MY_ID\" task_type=\"automated\">CUSTOM...",
    "blockarr": [{
        "parent": -1,
        "childwidth": 0,
        "id": 0,
        "x": 947,
        "y": 234.171875,
        "width": 318,
        "height": 132
    }],
    "blocks": [{
        "id": 0,
        "parent": -1,
        "data": [{
            "name": "blockelemtype",
            "value": "MY_ID"
        }, {
            "name": "blockid",
            "value": "0"
        }],
        "attr": [{
            "class": "blockelem noselect block"
        }, {
            "style": "left: 427px; top: 114.875px;"
        }]
    }]
}

Unsure if this is something in the library or my import/export.

Join multiple nodes to one

It is great project. I want to use in a open source project , but It can't join/link multiple nodes/flows to one . it seem quick hard to enhance for a backend developer. Any help would be appreciated 。

Angular Support

Thank you for this awesome library. Keep up the good work!
Do you plan to make it works with Angular?

.dragging not being removed

Have a condition in which the .dragging class is not being removed. I've been trying to reproduce, while I can replicate I can't put my finger on a series of moves to make it occur.

Alyssaxuu, you may know better of an edge condition that may make this occur, I'll keep trying to reproduce.

Enhancement - Allow snapping of blocks by type

This is not an issue but more of a feature request, could there be a way to only allow certain types of blocks to attach to others, like in your demo only allow Actions and Loggers to be attached to a Trigger block.
Thank you!

iPad support

I’m trying to use the demo with iPad 2018 but it’s not working

Add a dedicated render method

I understand that this request has been posted and closed here: #40

However, I would like to bring it up and present some reasons why I think it will be very useful:

  1. In many cases we will need to save the tree in a relational database, only to query and re-build it on demand. Having to store the whole tree in html is not efficient in term of storage.
  2. What if we change our design/presentation at some point? It also makes it almost impossible (or very difficult) to change the tree structure via other methods (such as database query) because you will have to somehow re-render the html tree.
  3. Right now it seems like the snapping callback is where we can update the presentation of the snapped blocks. I would argue that having a dedicated render method allow us to break free from the need to rely on snap event (and thus also makes adding blocks manually via API possible).

And while we are at it, I would also argue that we should NOT pass the attr together with the blocks (at least not to the render function, because render function only expects the block information and data which can be passed manually).
I do understand why we have attr: right now we have the draggable blocks initialized as dom elements which is good but at the same time limited.

We should not mix dom objects with block objects. A block object should have:

  1. Id
  2. Parent id
  3. Name
  4. Additional meta data if any

{ "id": 1, "parent": 0, "data": {"name": "blockid", "value": "1" } }

For the html dom based draggable blocks, they can still be coded like this:

<div class="create-flowy" data-id="1" data-parent="0" data-data='{"name": "blockid", "value": "1"}'>Grab me</div>

or perhaps:

<div class="create-flowy" data-id="1" data-parent="0" data-name="blockid" data-value="value">Grab me</div>

One last thing is regarding the current api, perhaps if we switch to this it will be easier to allow easier change in the future:

flowy(canvas, ongrab, onrelease, onsnap, onrearrange, spacing_x, spacing_y);

to

flowy({canvas: element, onGrab: function, onRelease: function, onSnap: function, onRearrange: function, render: function, spacingX: number, spacingY: number});

or (only canvas is a must, all other things are optional)

flowy(canvas, {onGrab: function, onRelease: function, onSnap: function, onRearrange: function, render: function, spacingX: number, spacingY: number});

Console error at end of dragging action

Hello, and congratulation for your library which is awesome.

I am using the onRearrange with return false to avoid deleting blocks.
When moving quickly one block from another (so detaching it), it goes back to its original place as desired, but sometimes not to say often, this error pops in the console :

ERROR TypeError: Cannot read property 'x' of undefined at HTMLDocument.flowy.endDrag (flowy.min.js:393) at ZoneDelegate.invokeTask (zone-evergreen.js:391) at Object.onInvokeTask (core.js:39680) at ZoneDelegate.invokeTask (zone-evergreen.js:390) at Zone.runTask (zone-evergreen.js:168) at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:465) at invokeTask (zone-evergreen.js:1603) at HTMLDocument.globalZoneAwareCallback (zone-evergreen.js:1640)

Only happening when I am dragging quite fast.

Disable action if minor move

Would like to see an optional feature to disable block deletes if the drag/release action is minimal. I'm finding that when clicking a block I often move it by a few pixels and cause it to be deleted (Likely because my mouse sensitive is set to super high and I'm using a trackball =)). Would be nice to see some error tolerance here.

How to present conditional and looping with flowy?

Hi, I would like to create a flowchart tool with flowy to describe the program process. Then I got 2 problems about how to initiate arrows between blocks:

  1. Conditional statement: suppose there was an if-else statement and 2 branches were created, then the subsequent blocks were not able to be merged into one since one block with 2 parents is not allowed.
  2. Looping: similar problem. Is it possible to represent a loop with Flowy?

Maybe it was hard to have a clear description only with words. For example, is Flowy able to describe the following flowchart?

Confusing Readme

Hello, I'm slightly confused as to what functionality does this codebase actually provide. Following the readme, the result (at least the one I arrived to) has nothing to do with what you see in the demo. So my question is:

Does this just provide bare-bones functionality for a system that needs custom implementation or, is this supposed to ship with some sort of UI resembling the demo?
In case of the latter, then I'm clearly doing something wrong. Otherwise, I feel like the Readme could provide a bit of clarification on how to implement this functionality.

I believe the case is the latter as the demo folder is way more complex than the engine one.

I case of doubt, my result after just following the read-me is just a div with text and a type error when trying to drag it.

Thank you very much,
Have a good one.

Get data from data attributes

Suggestion: It would be nice to be able to get reference to all data attributes within the context of a create-flowy container. This would highly improve the possibilities of custom logic with the output

Also, as I see it now, data from inputs is only working for the container's root level inputs, would be nice if it would instead traverse the container's tree and find all nested inputs. This would eliminate current styling limitations.

Thank you very much! :)

I want to make contributions but don't know on which codebase

Hi,
first of all, thank you for this great project. 👍

I would like to make a few changes and/or extensions. Now, however, i doesn't know on which code base this should happen. Since a "few" pull requests from @joelvh are still open.

Will they be merged or something similar?

Until then, I will be working in my own fork.

There is already a "minimal" demo for easy access in development and a plugin to use templates.

It's a plugin because of this "future codebasis is unknown" problem, here 😅

Syntax error in the README

The output json should be like this:

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

Some quotes 1 closing bracket were missing.

OnSnap trigger

Is the OnSnap function only triggered when droping a block from outside the canvas?
It seems the function is not triggered when moving some blocks inside the canvas,

Is there any way to catch this event?

Zoom in/out

It would be great and very useful if for larger diagrams we could zoom in/out. This would make it easier to visualize larger flows.

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.