alyssaxuu / flowy Goto Github PK
View Code? Open in Web Editor NEWThe minimal javascript library to create flowcharts ✨
License: MIT License
The minimal javascript library to create flowcharts ✨
License: MIT License
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:
<!DOCTYPE html>
to first line of demo/index.htmlIt would be great and very useful if for larger diagrams we could zoom in/out. This would make it easier to visualize larger flows.
I have a specific requirement to be able to add one or more nodes to a group.
----------------
| |
| ------- |
| | A | |
| ------- |
| | |
| \/ |
| ------- |
| | B | |
| ------- |
| | |
--------|--------
|
----------------------
| |
| |
-------|-------- -------|--------
| \/ | | \/ |
| ------- | | ------- |
| | C | | | | E | |
| ------- | | ------- |
| | | | | |
| \/ | | \/ |
| ------- | | ------- |
| | D | | | | F | |
| ------- | | ------- |
| | | |
---------------- ----------------
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
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 :
`
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!
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.
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?
Currently (as can be seen on this demo: https://alyssax.com/x/flowy/), if we add:
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.
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.
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.
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.
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 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.
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 :
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
.
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
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.
In flowy.beginDrag offset calculation is resulting in incorrect behavior in a scenario where the editor is positioned inside an absolutely positioned container. Offset calculated here is relative to parent node here whereas it should be relative to the document, because of this in such scenarios there is a large gap between draggable clone and mouse pointer.
Thank you for this awesome library. Keep up the good work!
Do you plan to make it works with Angular?
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:
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:
{ "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});
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
Current behavior:
Drag a new block between 2 existing blocks (parent and child) and the new block becomes another child of the parent.
Desired behavior:
Drag a new block between 2 existing blocks (parent and child) and the new block inserts between the parent and child.
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.
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 😅
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.
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.
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?
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.
The Mentioned Error is being displayed while running the Index.html File in Demo Folder. @alyssaxuu
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": { ... }
}
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:
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
+-+---+-+
| |
+-------+
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).
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?
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 。
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.
Then as soon as you try to drag another block, the previous one (the lost one) move to the top of the window.
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.
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:
Do you think it's possible to rebuild the tree without the HTML ? How to do it ?
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.
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.
I’m trying to use the demo with iPad 2018 but it’s not working
We can use flowy.output to get the json data. Can we also initialize flowy with the data saved?
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')
.
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:
Maybe it was hard to have a clear description only with words. For example, is Flowy able to describe the following flowchart?
Ok, this maybe an overhaul feature that consists of:
function snapping(drag, first)
), may provide a function to do soDoes not appear the demo works on mobile.
Would love to be able to npm install flowy
to use with bundlers and unpkg.com
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.