Coder Social home page Coder Social logo

open-source-labs / svelvet Goto Github PK

View Code? Open in Web Editor NEW
2.5K 28.0 158.0 38.48 MB

🎛 A Svelte library for building dynamic, infinitely customizable node-based user interfaces and flowcharts

Home Page: https://svelvet.io

JavaScript 0.60% TypeScript 27.98% HTML 0.05% Svelte 71.37%
diagrams flowcharts library npm svelte sveltekit opensource devtool typescript

svelvet's Introduction

banner

MIT License NPM Downloads GitHub Stars GitHub Forks NPM Version


Infinitely Customizable Node-Based User Interfaces with Svelvet!

Svelvet is a lightweight Svelte component library for building interactive node-based user interfaces and diagrams.

⚡ Website | 📚 Documentation | ⌨️ Blog | 💬 Twitter | 💼 LinkedIn


Version Updates

Shout out to our contributors! Here's what's new:

Changelog

🛸 v10.0.0 🛸
  • Features:

    • Accessibility Enhancement: Now users can navigate the canvas using the keyboard.
      • Press 'l' to turn on light/dark mode.
      • Press 'd' to show drawer component, and 'D' to open/close drawer component.
      • Press Option + Tab || Ctrl + Tab for Node selection.
      • Press 'm' to toggle the minimap component.
      • Press 'c' to toggle control component.
      • Press 'e' to bring up editor component.
    • Persistent Canvas State: Added the ability to save the state persistently to local storage.
    • High Contrast Mode: Introduced a new high contrast accessibility component tailored for the visually impaired.
  • Refactoring:

    • Improved Keyboard Accessibility: Enhanced the keyboard accessibility of the drawer component through refactoring.
  • Documentation:

    • Updated Guidance: Documentation now includes instructions on utilizing keyboard accessibility features.
  • Miscellaneous:

    • Test Enhancements: Added comprehensive testing for drawer components.
    • Maintenance: Updated Playwright tests and configuration for improved stability.
🚀 v9.0.0 🚀
  • feat: migrated Svelvet library from Svelte 3 to Svelte 4
  • feat: built out/added a flowchart feature that generates dynamic flowchart diagrams from a formatted string
  • feat: added a new arrow edge style to the existing collection of edge styles allowing one-way and two-way data flow visualization
  • feat: added a new component called toggle to the existing library of data flow components
  • refactor: overhauled the Editor component to allow for dynamic deletion and resizing of existing nodes
  • docs: updated documentation to include the addition of an example that illustrates how a user might create customizable node shapes
  • docs: updated documentation to include the addition of an example that illustrates how to use the new flowchart feature
  • docs: updated the documentation page on the website to include newest version release
  • test: added to the E2E testing suite using Playwright, nearly doubling test coverage
v8.0.0
  • feat: added a new drag-and-drop Drawer component that can take custom Nodes, Anchors and Edges as props and add them to the canvas via the UI
  • feat: added a new input component, Knob, to the collection of already existing data flow system components that can be composed in custom nodes and customized by users
  • docs: updated documentation to include an Example section that features a usecase of Svelvet as a Database Visualization tool
  • docs: updated the documentation page on the website to include newest version release
  • test: added Unit and Component testing using Vitest and Svelte Testing Library
  • refactor: updated website styling: consolidated redundant CSS classes, fixed broken links and styling issues
  • chore: updated home page to include newest collaborators
  • chore: updated testing suite package versions
v7.0.0
  • Changed primary API. Developers now pass Node and other exposed components directly as children to Svelvet
  • Added the ability to specify Anchors as inputs, outputs or any, enabling connection logic and "directionality" of Edge curvature
  • Added the ability to dynamically attach/reattach Edges
  • All new Anchor component that developers can add anywhere within custom nodes. Can be wrapped around custom anchor elements or customized via props
  • All new Edge component for developer customization
  • All new Node component for developer customization
  • Added ability to rotate nodes via the top left corner
  • All new Resizer component used when composing custom nodes
  • Improved reliability and DX around Edge click events
  • Node connections can be specified at the Node or Anchor level. Improved flexibility of input options
  • Improved consistency of touch events on mobile devices. Added touch support for controls component
  • Nodes and Edges no longer require specified IDs. Defaults to incrementing value
  • Added Controls component with zoom, reset, lock and unhide functionality plus the ability to pass custom control buttons as children
  • Added the ability to specify an arbitrary number of Anchors on default nodes
  • Added z-index stacking logic when interacting with Nodes
  • Improved step path algorithm, which now connects Anchors regardless of their position. Exposed corner radius as prop
  • Added keyboard navigation to canvas when focused
  • Added selection box functionality via Shift + Click. Color can be controlled via the selectionColor prop on the Svelvet component.
  • Added node grouping functionality via Shift + CMD + Click
  • Added the ability to pass custom edges at the Graph, Node and Anchor level
  • No longer required to pass width/height to Svelvet component. Will fill wrapping container by default
  • Added the ability to specify canvas/node direction as top-down TD or left-right LR. Controls placement of input/output anchors on default nodes
  • All new Minimap component that accepts props for placement, dimensions and styling the background and nodes (defaults to node color) and features dramatically improved tracking/visualization plus the ability to hide nodes
  • All new Theme Toggle component that can toggle between a main and alt theme
  • Enabled two way data binding for some parameters when creating default Nodes
  • All new Background component allowing customization of grid size and color
  • Exposed custom events on the Node component for on:nodeClicked, on:connection and on:disconnection that developers can listen for when implementing custom nodes
  • Added theme prop to Svelvet component. Defaults to light. Accepts parameters like "dark", "purple", "parchment"
  • Removed frontend website code from library repository
  • Added E2E tests using Playwright
  • Simplified bezier curve logic and added the ability to specify anchor "direction"
  • Added ability to parse Mermaid strings into node graphs + edges
  • Added a series of accessible input components (Slider, RadioGroup, TextField, ColorWheel) that can be composed in custom nodes and are linked with our data flow system
  • Library now features 100% TypeScript coverage and fully exported types
  • Removed D3-zoom dependency
  • Removed redundant window and event listeners
  • Added dynamic data flow/state management system that tracks Anchor connections
  • Updated home page to include newest collaborators
  • Temporarily removed dynamic anchor logic due to library re-write. May re-add
  • Made progress on restoring graph state from local storage. Coming soon!
v6.0.0
  • Added adaptive anchors. Anchors now automatically arrange themselves in an aesthetically pleasing way without user input. Adaptive anchors are now the default anchor mode.
  • Added dynamic anchors. Anchors now automatically shift position when nodes are moved to preserve aesthetics.
  • Added custom positioning of anchors. Users are able to specify custom positions of anchors using callbacks
  • Added accessibiilty features for edges. Edges now highlight on hover to make edge interactions easier.
  • Added functionality to resize nodes by dragging their bottom-right corner
  • Added custom classes for edges to allow for uniform styling
  • Added click event for edges that execute a user-defined callback
  • Added functionality to edit edges by right-clicking on a node to bring up a modal
  • Added feature to expand and collapse tree nodes.
  • Updated documentation page on website to include new features
  • Updated home page to include newest collaborators
  • Solved github issue #s:
v5.0.0
  • Now compatible with Safari (5.0.7 update)
  • Added interactive node linking & creation
  • Added ability to load custom Svelte components as nodes
  • Added an optional minimap that allows you to visualize larger diagrams
  • Added progammatic initial zoom and location
  • Added custom classes for nodes to allow for uniform styling
  • Added a feature that allows you to export and import diagrams
  • Added an optional boundary to the diagram
  • Added functionality to edit nodes by right-clicking on a node to bring up a modal
  • Added an optional feature that allows users to delete nodes
  • NOTE: Please make sure to give nodes and edges unique IDs to prevent forEach key duplicate error!
  • Solved github issue #s: 65, 78, 80, 81, 85, 86, 104, 105, 146, 147, 148, 151, 153, 158
  • Updated documentation page on website to include new features
  • Updated home page to include newest collaborators
v4.0.0
  • Added ability to include HTML in inside of nodes (i.e. videos, sounds, etc)
  • Added NPM Package folder in root directory of GitHub repo
  • this folder is used for adding changes to library & pushing updates to NPM; included here to have version control through GitHub
  • Added snap-to-grid functionality for use during runtime in the canvas (GitHub Issue 107)
  • Corrected issue where nodes become magnetized when moved outside of the visible canvas boundaries (GitHub Issues 120 & 125)
  • Removed unused dotenv & node.env dependency from NPM Package package.json (GitHub Issue 118)
  • Moved all dependancies in devDependancies to regular dependancies object, except for d3-zoom which is used by the client during runtime
  • Added group nodes functionality
  • Updated main website page to include newest set of collaborators
  • Added CSS option for canvas background
  • Added documentation for HTML in nodes, snap-to-grid, canvas background coloring, and node grouping to website documents
  • General refactoring throughout application to improve responsiveness and decrease size
  • Created documentation to assist future developers in understanding the flow of data in Svelvet and provide list of potential updates/upgrades
v3.0.0
  • Added right-click context menu functionality on REPL playground page
  • Added capability to add custom nodes and edges via context menu
  • Added custom node/edge shortcuts for optimized user experience
  • Incorporated dynamic addition of custom node/edge via predictive algorithm
  • Added ability to copy text from code editor
  • Node diagrams now have the option to be fixed in place
  • Added tutorial overlay for REPL playground page
  • Added ability to access quick view documentation via popup modal
  • Updated documentation to allow easier contributor access('.env' file setup)
  • Updated Community link on website to redirect to Svelvet thread on Stackoverflow
  • Implemented skeleton codebase for a Community Forum with full database/route accessibility(for future contributors)
v2.0.2
  • Added left and right anchor points
  • Added step and smoothstep edge types
  • Incorporated mixed edge functionality
  • Refactored how edge text and labels render for every edge
  • Fixed D3Zoom bias bug
  • Expanded styling options, including label color, label background, and edge color
  • Nodes are now able to contain images and will render differently based on the presence of label text
  • Nodes are now draggable on touch screens and reposition themselves to center on your touch
  • Implemented data reactivity
  • Expanded TypeScripting
  • Added E2E testing using Cypress
  • Expanded unit tests
  • Added a REPL to our documentation site
  • Added SQL database to our REPL
  • Added GitHub OAuth to enable users to save their custom diagrams created in our new REPL
  • Expanded documentation for new features
  • Added full CI/CD pipeline
v1.0.3
  • Fixed bug with running tests
  • Added ability to render multiple unique Svelvet components
  • Added a 'clickCallback' customization option for nodes
v1.0.2
  • Fixed bug with importing types for TypeScript applications
  • Added a 'borderRadius' customization option for nodes
  • Fixed SVG zoom/pan bug (zoom/pan is now limited to Svelvet component only)

Key Features

  • Easy to use: To get started with Svelvet, all you need is data for nodes and edges. Visit our documentation website for streamlined, user-friendly tutorials and examples on how to get the most out of your Svelvet interfaces!
  • Interactive: Elegant and smooth interface when selecting a node to drag it across the graph.
  • Customizable: Fully customizable Edges, Nodes, Backgrounds and components
  • Reliable: Svelvet is written in TypeScript and tested with Vitest, Playwright and Svelte Testing Library. Svelvet is maintained by motivated engineers seeking to contribute to the larger Svelte developer community and library ecosystem.
  • Room to Grow: There is so much we can do to improve, add features and make Svelvet the best version of itself - we welcome feedback and contributions! Scroll below for suggestions on how to contribute.

Installation

Svelvet is available as both an npm and a yarn package. You can install it by running one of the two commands:

npm install svelvet
yarn add svelvet

Quick Start

Start by importing the Svelvet and Node components into your application:

import { Svelvet, Node, Anchor, Edge, Controls } from 'svelvet';

A Svelvet canvas primarily consists of Nodes. You can pass any number of Nodes as children to the Svelvet wrapper. You can use all the standard conditional rendering syntax to populate nodes within the Svelvet component. Basic parameters like color, input and output count, label and more can be specified and feature two-way data binding with passed props. For greater customization, wrap your own custom components in our Node component and pass the whole thing to Svelvet.

Nodes, Edges and Anchors all feature click events, properties and functions to allow developers to fully customize the state of their graphs.

When creating custom Nodes, you can position any number of our Anchor components to enable dynamic connections. You can also wrap Nodes in a Group component to limit their boundaries and move them as one. These groups can be created dynamically by Shift + Click and dragging.

Finally, you can render our Controls, Minimap, Background and Theme Toggle components via props or named slots. In the latter use case, you can pass props to further customize them. The Controls component can wrap your own set of buttons as we expose the zoom/reset/lock actions using a let directive.

Svelvet is focused on dynamic edge connections, but if you'd like to specify edges ahead of time, you can pass an array of connections to any Anchor component. You can also pass a custom Edge component!

For more detailed use cases and examples, please visit our website.

<Svelvet width={500} height={500} theme="dark" initialZoom={0.6} minimap>
	<Node />
	<Node label="Demo Node" TD />
	<Node id="node-id" inputs={2} />
	<Node bgColor="red" inputs={10} outputs={5} height={200} position={{ x: 100, y: 100 }} />
	<Controls slot="controls" horizontal />
</Svelvet>

Testing

Testing is done with Playwright, Vitest, and the Svelte Testing Library. You can find tests in the /tests folder. We dramatically expanded test coverage, but there are still opportunities to improve it. In order to run the tests use the command:

For End-to-End testing

npx playwright test

For unit testing

npm run test:unit [filename]

The Svelvet Team

How to Contribute

Please refer to the roadmap for the full list of ideas for iteration.
Some ideas inspired by v10.0.0 include:

  • Example Showcase: we've added a new section to the documentation which will contain example sandboxes of features and potential usecases of Svelvet. If you would like to contribute to the showcase with an example of how you’re using Svelvet, reach out to the team with your project via Github discussion.

  • Importing/Exporting canvas as JSON: we had planned to look into this as a way to maintain state through a page refresh.

  • Additional Data Input Components: we plan on creating additional input/parameter components that integrate with our data flow system and can be used when composing custom Nodes.

  • Extensive Test Converage: We expect to have full E2E and unit test coverage relatively soon. Especially the newly added features in contrast themes.

  • Accessibility Linter: We aim to ensure our components are accessible and compliant with accessibility standards. Implementation of an accessibility linter would streamline the process of identifying and rectifying accessibility issues within our components.

  • Persistent Canvas State saveStore.ts and reloadStore.ts lay the foundation for the save feature. They work together to get the state object of the canvas by turning it into a JSON string for storage and then parsing it into a JSON object for reconstruction. But they need further development as they only save the camera position and theme. Specifically, the traverse function in saveStore.ts needs to properly detect and expand each element inside the canvas (graph) state object. A good place to start on this would be addressing the anchors and edges property of the graph's state object. Use the "nodes" property on this object for reference on how this data should be unraveled and stored. Additionally, the createGraph function is used in reloadStore.ts to render a graph onMount of the Svelvet component according to the state object that was saved last in local storage on the user's browser. This implementation is simplified, however, so it only recreates the graph from partially saved data.

GET CREATIVE!! Svelvet is an amazing project that has so much room to grow.

Credits

Inspired by React Flow, Svelvet expands the tools available to Svelte developers and makes Svelte more inviting to both new and seasoned software engineers.

License

Svelvet is developed under the MIT license.

svelvet's People

Contributors

alabhyajindal avatar bittermelonsam avatar bojit avatar brean avatar briangregoryholmes avatar chobo91 avatar dawidjaniga avatar dejavu333 avatar henry-sweat avatar isaacb0 avatar jdave1125 avatar johnlcos avatar jpedley avatar julianb12 avatar justinmccann14 avatar madvib avatar mayson124 avatar rathna-git avatar rohanrajpal avatar ruxinz avatar spencerhuey avatar thomaskady avatar tobiaskohlbau avatar tomfaulkner avatar trackhe avatar wesley-waters 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

svelvet's Issues

Performance issue on svelvet.io with Brave

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

  • Windows 11 with Brave
  • Ubuntu with Brave
  • Ubuntu with Firefox - (not as bad, but the REPL has bad performance here too)

No problem with

  • Windows 11 Edge
  • Windows 11 Chrome

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.

default zoom

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

Not an issue : Edit on double click

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

Click Event handlers

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}

clickCallback of svelvet nodes is called even when clicking outside of the Svelvet Component

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?

Version 3 breaking sveltekit

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.

Programatic location & zoom

First, thx a lot for this great project 🥳
I built a visual selection tree that look like:
image
Where users can extend alone the tree with custom rules & co! Quite fun :)

The issue is that today, it's always opening on "top left". Could we set the location & zoom on load?

Thx for your help

Suspicious dependency in Svelvet

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:

  • an express server
  • a mongoose connection
  • requests to a random .cn url
This is the whole node.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.

Support for Sveltekit

Would it be possible to make svelvet compatible with Sveltekit, as an SSR component?

Magnetic nodes

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.

Screen.Recording.2022-10-08.at.4.12.29.PM.mov

Can not run a local version [bug]

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:

  • Added a REPL to our documentation site
  • Added SQL database to our REPL
  • Added GitHub OAuth to enable users to save their custom diagrams created in our new REPL

Disable node dragging

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:

  1. Set a property on each Node (locked for example):
{
  id: 1,
  position: { x: 0, y: 0},
  data: { label: "Label" },
  width: 100,
  height: 40,
  locked: true
}
  1. Set an attribute on the Svelvet component itself (lockNodes for example):
<Svelvet {nodes} {edges} background lockNodes />

Snap to Grid (enhancement)

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} />

allow customization of edge anchoring on node?

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?

movement={false} should not set css attribute cursor: move;

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}
/>

image

Breaking Change: Svelvet component becomes unresponsive with touch events

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.

Svelvet.mp4

default size

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?

Pass props to custom Svelte components

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: { ... } }?

Regression/bug in 1.0.3 not present in 1.0.2 : continued dragging after mouse click release outside of node

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:

  • Go to https://svelvet.io/
  • In the first demo, zoom out, drag a node until the pointer is out of the node, release the click.
  • Move the mouse, the node will continue moving.
  • You can reproduce this problem with multiple nodes.

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.

REPL doesn't use monospace font

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.

Default Toolbar

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:

  1. Arrow that would be used to select elements and if the mouse is located on the canvas it would be a hand to be able to drag the canvas. The ESC key would select this tool if other is selected.
  2. Rhombus
  3. Circle/Ellipse
  4. Square/Rectangle
  5. Label to create texts
  6. Eraser
  7. Cross that would be used to make connections between components
  8. Multiple selection tool to select some elements
  9. Group elements. This tool would draw a square, and all the elements that are inside will belong to the same group leaving this square visible
  10. Tooltip to add to components in the canvas

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} />

Feature request - add `className` to Containers and Edges

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)

Feature Requests; edge and node events, etc

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.

  • More events or reactions$. The edges don't emit anything. And the only event the node has is a click.
  • cancel edge creation if criteria not met.
  • user resizable nodes by dragging edge
  • API documentation. While the docs now are very helpful... API docs would be very helpful for a developer that needs more granular control.

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.

clickCallback event giving the wrong node

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.

BUG - dynamic render

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

Fixed graphs

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.

remove unnecessary dependencies package

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

Tests not working

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?

How to read the new position of nodes after drag

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.

Feature:Load custom svelte component as Node

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>

drag distance is biased by zoom level

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.

empty space click

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.

Feature: Multiple connectors on same side

It does not currently seem possible to have multiple connection points on a side. Would love to see this as a feature as it would open up a lot of cool use-cases. Picture for demonstration:
image

Roadmap to 5.0

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:

  • what to prioritise
  • what to expect for the next release and by when

Ideally, we could label the issues necessary for 5.0 with a specific label.

custom nodes

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 :)

Box-sizing option for variable node title length

Node title length might benefit from adjustments for minimum padding (enhancement).

Here are two screenshots, in the first you can see that the longer title creates an unequal padding distribution. I believe here should be an option to set a padding size.

image

image

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.