open-source-labs / svelvet Goto Github PK
View Code? Open in Web Editor NEW🎛 A Svelte library for building dynamic, infinitely customizable node-based user interfaces and flowcharts
Home Page: https://svelvet.io
🎛 A Svelte library for building dynamic, infinitely customizable node-based user interfaces and flowcharts
Home Page: https://svelvet.io
If {x: Int, y: Int}
is unspecified auto position nodes.
How to make the node graph reactive to data change?
[Example Svelte REPL] (https://svelte.dev/repl/0e9cb2fb95224a5cb049e0e8c945885f?version=3.48.0)
Feature request: A Node can be a svelte component.
Example:
<script lang="ts">
import CustomSvelteComponent from '$lib/components/CustomSvelteComponent';
const initialNodes: Node[] = [{
id: 1,
position: { x: 100, y: 100 },
data: { component: CustomSvelteComponent},
width: 80,
height: 80,
bgColor: 'white',
borderColor: 'transparent',
borderRadius: 5,
sourcePosition: 'right',
targetPosition: 'left',
}];
</script>
I saw your announcement on hackernews.
While playing around on your landing page I noticed that when dragging nodes, depending on the zoom level, the dragged node moves faster (when zoomed in) or slower (when zoomed out) than the cursor.
With the introduction of either 3.0 or 4.0, mobile functionality has decreased. As seen in the video (running Chrome), the Svelvet container initially works, but after a few events the Svelvet component ceases to function. I was able to replicate it on my Android phone running Firefox. The Svelvet component immediately becomes unresponsive as soon as a touch event is triggered on a Node.
Relevant issues on Svelvet:
Version 3 breaking sveltekit #119
remove unnecessary dependencies package #118
The Svelvet dependency node.env
is causing issues. What is it doing here?
Not only is it crashing my app, but it's a 5-year-old library with hardly any usage and I can't tell what it's even for. Looking at the source code, it doesn't contain much code other than:
.cn
urlnode.env
program source:function Api(settings) {
function Result() {
this.status = null ;
this.info = '' ;
this.data = null ;
this.done = function(data, status) {
this.status = status ? status : 200 ;
this.data = 'undefined' == typeof data ? null : data ;
return this ;
}
this.fail = function(info, data, status) {
this.status = status ? status : 204 ;
this.info = info ;
this.data = data ;
return this ;
}
this.miss = function(info, data, status) { // 未登录
this.status = status ? status : 110 ;
this.info = info ;
this.data = data ;
}
this.err = function(info, data, status) {
this.status = status ? status : 500 ;
this.info = info ;
this.data = data ;
return this ;
}
}
sleep = function(timer) {
return function(fn) {
setTimeout(function() {
fn() ;
}, timer) ;
}
}
function Storage() { // 存储器
var _storage = this ;
this.delete_files = function(dir, keys) {
return function(fn) {
async(function() {
try {
for(var i = 0; i < keys.length; i++) {
var _key = keys[i] ;
await(_storage.delete_file(dir, _key)) ;
}
fn() ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
this.delete_file = function(dir, key) { // 删除一个目录
return function(fn) {
async(function() {
try {
var _v = await(send({
url : "http://127.0.0.1:120/file",
method : "delete",
body : sify({dir : dir, key : key}),
parse : "json"
})) ;
fn(null, _v) ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
this.delete_dir = function(name) { // 删除一个目录
return function(fn) {
async(function() {
try {
var _v = await(send({
url : "http://127.0.0.1:120/dir",
method : "delete",
body : sify({name : name}),
parse : "json"
})) ;
fn(null, _v) ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
this.mask_dir = function(name) { // 创建一个文件夹
return function(fn) {
async(function() {
try {
var _v = await(send({
url : "http://127.0.0.1:120/dir",
method : "put",
body : sify({name : name}),
parse : "json"
})) ;
fn(null, _v) ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
}
utils = {
simple_ip : function(ip) {
return ip.replace('::ffff:', '') ;
}
} ;
this.Result = Result ; // 扩展对象
this.Storage = Storage ;
path = require("path") ;
fs = require('fs') ;
Promise = require('bluebird');
uuid = require('node-uuid') ;
this.storage = new Storage() ;
global.storage = this.storage ;
_ = require("underscore") ;
body_parse = require('body-parser') ;
async = require('asyncawait/async') ;
await = require('asyncawait/await') ;
express = require('express') ;
mongoose = require("mongoose") ;
baseschema = new (require("./base.schema")) ;
http = require('http') ;
util = require('util') ;
Readable = require('stream').Readable ;
Writable = require('stream').Writable ;
events = require ( 'events' ) ;
superagent = require('superagent') ;
var _app = express() ;
_app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*") ;
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS') ;
res.header("Access-Control-Allow-Headers", "X-Requested-With") ;
res.header('Access-Control-Allow-Headers', 'Content-Type') ;
next() ;
}) ;
var _request = require('request') ;
_request = _request.defaults({ jar : true}) ;
request = _request ; // 设置全局请求
function sify(data) {
return JSON.stringify(data) ;
}
function short_url(url) {
return new Promise(function(next, fail) {
var _url = 'http://50r.cn/urls/add.json?url={url}' ;
_url = _url.replace('{url}', encodeURIComponent(url)) ;
request.get(_url, function(err, res) {
if(err) {
fail(err)
} else {
var _body = JSON.parse(res.body) ;
next(_body.url) ;
}
}) ;
}) ;
}
/*
请求
*/
function send(options) {
return function(fn) {
try {
_request(options, function(err, res, body) {
if(err) {
fn(err.message) ;
} else {
if(200 == res.statusCode) {
if("json" === options.parse) {
body = JSON.parse(body) ;
}
fn(err, body) ;
} else {
fn("请求错误,原因:" + res.statusCode) ;
}
}
}) ;
} catch(e) {
fn(e) ;
}
}
}
function download(url) { // 下载
return function(fn) {
async(function() {
try {
http.get(url, function(res) {
res.setEncoding('binary') ;//转成二进制
var _data = '' ;
res.on('data', function (data) {
_data += data ;
}).on('end', function() {
fn(null, new Buffer(_data, 'binary')) ;
}) ;
}) ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
function downloads(urls) {
return function(fn) {
async(function() {
try {
var _list = [] ;
for(var i = 0; i < urls.length; i++) {
_list.push(await(download(urls[i]))) ;
}
fn(null, _list) ;
} catch(e) {
fn(e) ;
}
})() ;
}
}
function extract(req, type) {
return function(fn) {
var _data = '' ;
req.on('data', function(data) {
_data += data ;
}) ;
req.on('end', function() {
var _body = null ;
if('json' == type) {
_body = JSON.parse(_data) ;
req.body = _body ;
fn(null, _body) ;
}
}) ;
req.on('error', function(err) {
fn(err) ;
}) ;
}
}
global.send = send ;
global.sify = sify ;
global.download = download ;
global.downloads = downloads ;
global.extract = extract ;
global.short_url = short_url ;
this.init = function() {
var _mongodb = settings.mongodb ;
if(_mongodb) {
mongoose.connect(_mongodb.path) ; // 如果存在 mongodb
}
if(!settings.port) return _app ;
var _compress = require('compression');
_app.use(_compress());
_app.use(express.static(settings.static_dir)) ;
_app.use(body_parse.json({limit: '50mb'})) ;
_app.use(body_parse.urlencoded({limit:'50mb', extended : true, keepExtensions : true})) ;
http.createServer(_app).listen(settings.port, function() {
console.log('listen port: ', settings.port) ;
}) ;
_app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*") ;
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With") ;
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS") ;
var _authorization = req.headers.authorization ;
if(_authorization) { // 存在
_authorization = JSON.parse(_authorization) ;
req.$attach = _authorization ;
} else {
req.$attach = {} ;
}
next() ;
}) ;
return _app ;
}
function _init() {
// 扩展
Date.prototype.format = function (fmt) { //author: meizz
var o = {
"M+": this.getMonth() + 1, //月份
"d+": this.getDate(), //日
"h+": this.getHours(), //小时
"m+": this.getMinutes(), //分
"s+": this.getSeconds(), //秒
"q+": Math.floor((this.getMonth() + 3) / 3), //季度
"S": this.getMilliseconds() //毫秒
} ;
if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
for (var k in o)
if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
return fmt ;
}
Array.prototype.contains = function(item) {
return RegExp(item).test(this) ;
} ;
Array.prototype.insert = function (index, item) {
this.splice(index, 0, item);
} ;
Array.prototype.remove = function(item) {
for(var i = 0; i < this.length; i++) {
if(this[i] == item) {
this.splice(i, 1) ;
break ;
}
}
return this ;
}
Array.prototype.empty = function() {
var _counter = 0 ;
for(var i = 0; i < this.length; i++) {
if(null === this[i]) {
_counter ++ ;
}
}
return _counter ;
}
}
_init() ;
}
module.exports = Api ;
The whole thing is suspicious, and the url in this part, http://50r.cn/urls/add.json
:
function short_url(url) {
return new Promise(function(next, fail) {
var _url = 'http://50r.cn/urls/add.json?url={url}' ;
_url = _url.replace('{url}', encodeURIComponent(url)) ;
request.get(_url, function(err, res) {
if(err) {
fail(err)
} else {
var _body = JSON.parse(res.body) ;
next(_body.url) ;
}
}) ;
}) ;
}
Turns up this on whois:
Domain Name: 50r.cn
ROID: 20170924s10001s96011509-cn
Domain Status: ok
Registrant: 陈世强
Registrant Contact Email: email@qq.com
Sponsoring Registrar: 阿里云计算有限公司(万网)
Name Server: dns13.hichina.com
Name Server: dns14.hichina.com
Registration Time: 2017-09-24 18:43:40
Expiration Time: 2023-09-24 18:43:40
DNSSEC: unsigned
What is this dependency? Why is it shipped with Svelvet? Perhaps the commiter @jeffreywentworth who added this dep in 0c902cd can explain it.
I reported this to NPM because to my untrained eye it looks like it could be a security threat. Please help me understand what it is, and please remove it from Svelvet.
When dragging a node past the edges of the visible grid, the node becomes magnetized to the cursor and cannot be dropped thereafter. See attached video.
I'm currently running into an issue where after clicking on a node, the clickCallBack associated with the node seems to persist. After the first click of the node, when the user clicks on anywhere outside the svelvet component window the clickCallBack seems to continue to fire again. It was recently working find similar to the demo pieces listed on the example page but within the last 10-15 days this error seemed to pop up.
Has there been any new releases that might coincide with this problem?
Congratulations with 2.02, and thank you for your work! 🎉🤩
I would like to have a snap to grid option if possible.
<Svelvet {nodes} {edges} grid gridSnap={true} />
or
<Svelvet {nodes} {edges} background backgroundSnap={true} />
The new props that have been added to the Svelvet container component seem to be missing from the type declaration.
There needs to be a property on Node to change the cursor type like a pointer, pencil, etc.
Awesome library!
Simply adding a custom class to containers and to edges is all that is needed to make svelvet much more customizable. I think most use cases for svelvet have different "categories" (classes) of containers and edges. I would love things like opacity, cursor, dashed border, box-shadow, and many more on my nodes!
Any thought on this? Worth it for me to work on a PR? Or are you more interested in going all the way (Svelte component or HTML template)
Version: Svelvet 4.0.3
When svelvet
is initialized with movement={false}
, nodes still have the attribute cursor: move;
set. This should not be set on nodes when movement is false. On the latest version of Firefox, this causes the cursor to look like a gloved hand, which indicates that a component can be dragged, which is obviously not the desired behavior in this case.
<Svelvet
nodes={initialNodes}
edges={initialEdges}
bgColor="transparent"
background={false}
movement={false}
/>
When you zoom out and drag and drop, you have a delta between the distance travelled by your mouse and the distance travelled by the node. This is known and discussed in 64.
But the 1.0.3 release introduced a bug related to it: if you zoom out, click to drag, drag until your mouse is out of the node, then release, the node will continue moving with your mouse.
How to reproduce:
It was not present in 1.0.2:
If you go directly to the CodeSandbox you will see this demo uses 1.0.2. Change the version to 1.0.3 and the bug will happen. That's how I discovered it was happening.
Might be related to this PR.
Would it be possible to make svelvet compatible with Sveltekit, as an SSR component?
Hi, far from an expert in this area - I just discovered d3 and your library.
First and foremost, it looks neat, and the code seems super simple/clean.
A simple newbie question: what would it take to enable "Edit node name on double click" ?
Ty
Hi everyone and thanks for quality software!
I've notices that nodes comes w/ hardcoded classnames w/o ability to pass custom node classname via config:
https://github.com/oslabs-beta/Svelvet/blob/1cd0841bf666691c83cb2f396043727ad4715848/src/lib/Nodes/index.svelte#L22-L36
So the question - is there any possibilities to customize nodes besides passing config values>
I cloned the repo and installed dependencies.
When i run npm run test
or npm run test:unit
, I get errors.
❯ npm run test:unit
> [email protected] test:unit
> vitest tests/unit
DEV v0.12.10 /Users/shinichiokada/Svelte/Svelvet-test
❯ tests/unit/SimpleBezierEdge.test.ts (0)
❯ tests/unit/GraphView.test.ts (0)
❯ tests/unit/Node.test.ts (0)
❯ tests/unit/BaseEdge.test.ts (0)
❯ tests/unit/Svelvet.test.ts (0)
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Suites 5 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
FAIL tests/unit/SimpleBezierEdge.test.ts [ tests/unit/SimpleBezierEdge.test.ts ]
Error: [vite-node] Failed to load $lib/Edges/SimpleBezierEdge.svelte
❯ async tests/unit/SimpleBezierEdge.test.ts:1:256
9| targetY: 200,
10| source: 1,
11| target: 2,
| ^
12| data: {
13| label: 'this is the test edge'
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/5]⎯
FAIL tests/unit/GraphView.test.ts [ tests/unit/GraphView.test.ts ]
Error: [vite-node] Failed to load $lib/Containers/GraphView/index.svelte
❯ async tests/unit/GraphView.test.ts:1:256
4| test('should mount the svg element'…
5| // render(GraphView)
6| // expect(screen.getByTitle('svg …
| ^
7| // const nodesStore = [
8| // // {
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/5]⎯
FAIL tests/unit/Node.test.ts [ tests/unit/Node.test.ts ]
Error: [vite-node] Failed to load $lib/Nodes/index.svelte
❯ async tests/unit/Node.test.ts:1:256
7| {
8| id: 1,
9| position: { x: 100, y: 50 },
| ^
10| data: { label: 'test-node-1' },
11| width: 175,
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/5]⎯
FAIL tests/unit/BaseEdge.test.ts [ tests/unit/BaseEdge.test.ts ]
Error: [vite-node] Failed to load $lib/Edges/BaseEdge.svelte
❯ async tests/unit/BaseEdge.test.ts:1:256
7| });
8|
9| test('should mount the path element…
| ^
10| const pathElement = screen.getByL…
11|
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/5]⎯
FAIL tests/unit/Svelvet.test.ts [ tests/unit/Svelvet.test.ts ]
Error: [vite-node] Failed to load $lib/Containers/Svelvet/index.svelte
❯ async tests/unit/Svelvet.test.ts:1:256
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/5]⎯
Test Files 5 failed (5)
Tests no tests
Time 884ms (in thread 0ms, Infinity%)
FAIL Tests failed. Watching for file changes...
What am I doing wrong?
Steps to reproduce: create a new fork, npm i, npm run dev, localhost:3000
Error: supabaseUrl is required.|
Might be related to v2.02 features:
Hi! I'm not sure if that's me or not, but when I tried to render another nodes by pressing button - new nodes didn't appear (yet in console it changed). And also when I updated Svelvet version to 5.0.7 from 4.0.3 - nodes stuctured as {data: {html: htmlString}} didn't seem to work either (dynamic change), but if I install version 4.0.3 - htmlStrings are working and dynamic render too
But if I change node content in .svelte component (not passing new array of nodes into Svelvet) - it works
dotenv
and node.env
are requiring extra packages, while these packages are not necessary as the component library. so , consider to remove these packages, or move to devDependencies , thx
Reading some of the comments, it seems that the team is working on version 5.0.
Could you share a roadmap with the expected features and an expected timeline for the release? I see that many people are keen to contribute (myself included) and doing so would allow contributors to better know:
Ideally, we could label the issues necessary for 5.0 with a specific label.
H
Hi there!
I’m trying to use this library to generate a graph visualization of a data-flow. I would like to generate this graph using some existing components that take props.
I know I can use custom components without props using data: { custom: MyComponent }
, but is it possible to pass props to MyComponent? Maybe using something like data: { custom: MyComponent, props: { ... } }
?
Is it possible to export to interactive file formats such as xmind and html
Updating svelvet to version 3 breaks sveltekit. When starting a server just throws 11 cound not resolve "<package_name>"
errors. Downgrading to a version <3
fixes the problem.
Steps to reproduce:
npm create svelte@latest test-svelvet
cd test-svelvet
npm install
npm install svelvet
npm run dev -- --open
Error:
> [email protected] dev
> vite dev "--open"
VITE v3.1.1 ready in 481 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
✘ [ERROR] Could not resolve "bluebird"
node_modules/node.env/api.js:122:19:
122 │ Promise = require('bluebird');
╵ ~~~~~~~~~~
You can mark the path "bluebird" as external to exclude it from the bundle, which will remove this
error. You can also surround this "require" call with a try/catch block to handle this failure at
run-time instead of bundle-time.
Great App! I had to try it out as soon as I learned about it.
While the library is very simple and great for what is explicitly intended for, it also has little flexibility to out side of the box use case.I have some feature requests that I believe would make it really flexible without too much work.
Again my use case is particular. If your your mind set is do one job and do it well then yes very good job on this app.
svelvet.io has terrible performance where the widget is in some browsers.
There are no console errors/warnings.
My specs are
i7 12700k, 64gb DDR4, RTX 2080ti - all drivers up to date.
Problem exists for
No problem with
I made a video showing the behavior of the homepage vs the REPL.
https://www.youtube.com/watch?v=IB_Kd1FU-H0
It might possibly be something to do with hardware acceleration settings in the browsers - but the fact that the REPL runs flawlessly is a little concerning.
Without monospace fonts, code alignment ends up being very poor - it may be a good idea to either use codemirror (is it using codemirror already?) or switch to a common monospace font.
I didn't find anything in the docs about disabling the dragging of nodes, so feel free to close the issue if it's an implemented feature.
I would like to have the option to disable the dragging on the individual nodes, but still keep the paning and zooming on the wrapper.
I propose two ways to achieve this:
locked
for example):{
id: 1,
position: { x: 0, y: 0},
data: { label: "Label" },
width: 100,
height: 40,
locked: true
}
Svelvet
component itself (lockNodes
for example):<Svelvet {nodes} {edges} background lockNodes />
And I thought that it would be really helpful to have a feature of creating custom nodes: like nodes with lists in it, with some svgs/images and different styled texts, different nodes with different styles (for example in React Flow it could be made with the help of node types). Also a little bit more possibilities to edit Hadlers (connection dots) would be helpful too. For example: be able to prescribe its border and background-color :)
Is it possible to create nodes interactively by right clicking in the canvas and choosing a node type?
Some thing similar to what rete.js
does...
https://rete.js.org/
There were some attempts to create a Svelte render plugin here
https://github.com/c0bra/rete-svelte-render-plugin
BTW, thanks for this awesome tool 👍
Possible bug:
As shown in the video, it's possible to link a node to itself. In that case the animation edge stays active and is fixed to the position in the scene.
Cannot send a PR since the change is in the embedded Sandbox code.
File: https://github.com/oslabs-beta/Svelvet/blob/main/src/routes/docs/custom-nodes.svelte
Sandbox: https://codesandbox.io/embed/custom-nodes-gl35z6
I'm upgrading from 2.0.2
to 4.0.3
and I noticed a change in the node.clickCallback
function.
In 2.0.2, when I click on a node the event fire, and I get the right node.id
. If I click somewhere else, nothing happen.
In 4.0.3, when I click on a node the event fire, and I get the right node.id
. If I click somewhere else (anywhere), an even fire again with the last node.id
.
I'm staying on v2.0.2 for now.
Hi (-:
A-M-A-Z-I-N-G project.
Can you zoom to a specific node via code?
For example: zoomOnNode(nodeId).
Hi :) I think there is a problem with dynamic change of data in Svelvet. For example: I created two array of nodes and two arrays of edges, there is a button which changes a value of nodesToRender variable (which is array of nodes to render), when I press it - I can see in console that nodesToRender array changed, but Svelvet didn't render these new nodes.
Example code: https://svelte.dev/repl/327b6dbe12584691956698ae28a3fe6b?version=3.49.0
I think that current default zoom is good when there are not much of nodes, but if its gonna be hundred of them - it would be helpful to have a possibility to prescribe default zoom level
Hi :) I got a suggestion about Svelvet.
For now there is a possibility to click on a node to do some actions with it. But there is no functionality to press on empty space like in React Flow. For example: I want some popup node to appear near clicked node (I can simulate its appearing by putting popup-node far-far-away and changing the position of it when clicked), but I cannot put it away when I don't want to see it anymore - when I click empty space in Svelvet container. It would be helpful to add such feature.
Hi again :) I got another suggestion for you.
For now Svelvet has default width which is ~600px, and I can set its width manually to a size I need. But that's it - I must create different options to choose its width depending on user's screenWidth. Is there an option to set its width like 100% by default?
I would love to be able to provide functions for on click/tap. I also would like to add hooks for styles like class:active={my_condition}
First of all this is an excellent library, thank you all for your work
I would like to propose a new feature, a toolbar palette component that could be instantiated by default and customized.
This toolbar component would include several buttons by default:
The toolbar component would be floating so that it could be moved around the canvas, and it could be minimized to take up little space.
We as developers and consumers could add and remove components to this toolbar in our applications to customize it via a property palette or something similar. The palette could have an entries property where we could add new toolbar items.
<Svelvet {nodes} {edges} {palette} />
Hey,
Is there a way to fix the graph in place? i.e. to disable mousemove
and touchmove
events.
I'd be happy to open a PR that would implement export movementEnabled = true
if you agree that this would be a good addition.
When the user moves a node its new position is not getting updated back In the input JSON data.
I have tried to bind it and use stores, but it seems the data update is not supported.
This feature is helpful because I want to render back the same flowchart that the user has customized when he visits the app next time.
I am unable to find this info in the docs.
How to group nodes?
I really love what this project is doing, one feature I'd really love is the ability to designate a "side" of the node to anchor an edge to (top/bottom/left/right). Currently it seems like one can only assume top down which is somewhat limiting from a drawing space.
{
id: "e1-3",
source: 1,
target: 3,
type: "straight",
anchors: {
source: "left",
target: "top"
}
}
Thoughts?
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.