Compare commits
107 Commits
v5.2.2-0
...
v6.0.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2c5bac65c | ||
|
|
5fc17b6217 | ||
|
|
d2e1cf2dd1 | ||
|
|
9e2f6ffb0f | ||
|
|
cc900b2a90 | ||
|
|
51c6bd2391 | ||
|
|
a8c6031166 | ||
|
|
a6655dbf2d | ||
|
|
37532edd01 | ||
|
|
4538884a96 | ||
|
|
c9f7d2c516 | ||
|
|
5c66c84a31 | ||
|
|
4a57ecdc97 | ||
|
|
9fc65b7d7f | ||
|
|
2573c5d8cc | ||
|
|
a46e17306b | ||
|
|
7045d75ae7 | ||
|
|
47e4a14520 | ||
|
|
58eee117e9 | ||
|
|
09d5b65e59 | ||
|
|
ea6adbe61b | ||
|
|
5f74600157 | ||
|
|
3590245f6c | ||
|
|
46aa99b2ea | ||
|
|
80f86867fd | ||
|
|
52f9105b1b | ||
|
|
e9558919fb | ||
|
|
dd5a0b7d8d | ||
|
|
0f7930e132 | ||
|
|
3823adc8e8 | ||
|
|
fce011a11b | ||
|
|
4962343b54 | ||
|
|
45649146c9 | ||
|
|
74e24331ed | ||
|
|
0cc469fa44 | ||
|
|
0b78ba69c6 | ||
|
|
ca301b9d4d | ||
|
|
ad6c77da28 | ||
|
|
66b72b4465 | ||
|
|
bb878657ba | ||
|
|
1db1e21fc2 | ||
|
|
f4920ab4d0 | ||
|
|
ccfd8e026c | ||
|
|
702290d9b3 | ||
|
|
347377d3b4 | ||
|
|
44fd2ad91b | ||
|
|
39d49c9ee0 | ||
|
|
61c6d4b161 | ||
|
|
b324154eff | ||
|
|
17350a740a | ||
|
|
d7fc5370ab | ||
|
|
5fbe7ce9e4 | ||
|
|
3e37e34155 | ||
|
|
f46680596c | ||
|
|
3a2d3ccb73 | ||
|
|
f4aa1852ed | ||
|
|
e167885038 | ||
|
|
619e8a2347 | ||
|
|
4c1e67106a | ||
|
|
d08be537e1 | ||
|
|
8e5243da95 | ||
|
|
22236f8420 | ||
|
|
99fe94ae29 | ||
|
|
3b0c19d998 | ||
|
|
fc67d477a9 | ||
|
|
e4d427e0d3 | ||
|
|
bc2d444aee | ||
|
|
b15a326dab | ||
|
|
b54feb03e4 | ||
|
|
39eddc0a2a | ||
|
|
85a1fde2e5 | ||
|
|
c0dae87d02 | ||
|
|
fddec93370 | ||
|
|
01ffbce479 | ||
|
|
30790682d3 | ||
|
|
dc9c2eae66 | ||
|
|
969152a814 | ||
|
|
2e38a7cfd5 | ||
|
|
e3fe7319c1 | ||
|
|
c3a332ebab | ||
|
|
314bb908f9 | ||
|
|
9b16b3f4ed | ||
|
|
722b6d98f3 | ||
|
|
2c6971be9a | ||
|
|
ea0160cbcf | ||
|
|
efc53eec9b | ||
|
|
b5c86159d1 | ||
|
|
ea2070ec98 | ||
|
|
39c3611686 | ||
|
|
1ff63d4117 | ||
|
|
e80da8853f | ||
|
|
a06e23eaf6 | ||
|
|
4b599fc37f | ||
|
|
def92af022 | ||
|
|
01e9f5f2db | ||
|
|
aa1a02774d | ||
|
|
e60aac56db | ||
|
|
b2e74d8b97 | ||
|
|
e333a4f168 | ||
|
|
1d316409e1 | ||
|
|
9d947d40b7 | ||
|
|
7d80f15358 | ||
|
|
28844b86eb | ||
|
|
70c9aeac66 | ||
|
|
12a7bfbda5 | ||
|
|
650061db4a | ||
|
|
48c6d1f038 |
@@ -2,30 +2,22 @@ version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: projectstorm/react-diagrams-ci
|
||||
|
||||
- image: buildkite/puppeteer
|
||||
working_directory: ~/repo
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
|
||||
- v1-dependencies-{{ checksum "yarn.lock" }}
|
||||
- run: yarn install
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
key: v1-dependencies-{{ checksum "yarn.lock" }}
|
||||
|
||||
# test building project
|
||||
- run: yarn run prepublishOnly
|
||||
|
||||
# test building storybook
|
||||
- run: yarn run storybook:build
|
||||
- run: yarn run build
|
||||
|
||||
# test e2e tests and jest snapshots
|
||||
- run: yarn run test:ci
|
||||
- run: cd packages/diagrams-demo-gallery && yarn run test --ci
|
||||
- run: cd packages/react-diagrams-routing && yarn run test --ci
|
||||
|
||||
@@ -4,6 +4,6 @@ indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Some exceptions
|
||||
[{package.json}]
|
||||
[{package.json,*.yml}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -4,21 +4,18 @@
|
||||
- [ ] The tests pass on CircleCI
|
||||
- [ ] You have referenced the issue(s) or other PR(s) this fixes/relates-to
|
||||
- [ ] The PR Template has been filled out (see below)
|
||||
- [ ] Had a beer because you are awesome
|
||||
- [ ] Had a beer/coffee because you are awesome
|
||||
|
||||
## What?
|
||||
|
||||
(My awesome new feature does this really cool thing.)
|
||||
|
||||
## Why?
|
||||
|
||||
(Because obviously it could not do it before)
|
||||
|
||||
## How?
|
||||
|
||||
|
||||
(Basically I did this and that because im a super 1337 hacker)
|
||||
|
||||
## Feel-Good "programming lol" image:
|
||||
## Feel good image:
|
||||
|
||||
(Add your own one below :])
|
||||
|
||||
|
||||
200
.gitignore
vendored
@@ -1,194 +1,8 @@
|
||||
dist/
|
||||
dist/main.js
|
||||
dist/main.js.map
|
||||
/package
|
||||
*.tgz
|
||||
@types/
|
||||
|
||||
.out
|
||||
|
||||
# Created by https://www.gitignore.io/api/net,netbeans,sublimetext,phpstorm,windows,osx,node
|
||||
|
||||
#!! ERROR: net is undefined. Use list command to see defined gitignore types !!#
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
.nb-gradle/
|
||||
|
||||
|
||||
### SublimeText ###
|
||||
# cache files for sublime text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using SublimeText
|
||||
# *.sublime-project
|
||||
|
||||
# sftp configuration file
|
||||
sftp-config.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
|
||||
### PhpStorm ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/vcs.xml
|
||||
.idea/jsLibraryMappings.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
.idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
### PhpStorm Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
|
||||
|
||||
### Windows ###
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
|
||||
### OSX ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
dist
|
||||
.DS_Store
|
||||
.idea
|
||||
.out
|
||||
*.zip
|
||||
.env
|
||||
node_modules
|
||||
yarn-error.log
|
||||
|
||||
194
.npmignore
@@ -1,194 +0,0 @@
|
||||
demos
|
||||
images
|
||||
docs
|
||||
.out
|
||||
.storybook
|
||||
.circleci
|
||||
tests
|
||||
*.md
|
||||
|
||||
# Created by https://www.gitignore.io/api/net,netbeans,sublimetext,phpstorm,windows,osx,node
|
||||
|
||||
#!! ERROR: net is undefined. Use list command to see defined gitignore types !!#
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/
|
||||
nbbuild/
|
||||
nbdist/
|
||||
nbactions.xml
|
||||
.nb-gradle/
|
||||
|
||||
|
||||
### SublimeText ###
|
||||
# cache files for sublime text
|
||||
*.tmlanguage.cache
|
||||
*.tmPreferences.cache
|
||||
*.stTheme.cache
|
||||
|
||||
# workspace files are user-specific
|
||||
*.sublime-workspace
|
||||
|
||||
# project files should be checked into the repository, unless a significant
|
||||
# proportion of contributors will probably not be using SublimeText
|
||||
# *.sublime-project
|
||||
|
||||
# sftp configuration file
|
||||
sftp-config.json
|
||||
|
||||
# Package control specific files
|
||||
Package Control.last-run
|
||||
Package Control.ca-list
|
||||
Package Control.ca-bundle
|
||||
Package Control.system-ca-bundle
|
||||
Package Control.cache/
|
||||
Package Control.ca-certs/
|
||||
bh_unicode_properties.cache
|
||||
|
||||
# Sublime-github package stores a github token in this file
|
||||
# https://packagecontrol.io/packages/sublime-github
|
||||
GitHub.sublime-settings
|
||||
|
||||
|
||||
### PhpStorm ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/workspace.xml
|
||||
.idea/tasks.xml
|
||||
.idea/dictionaries
|
||||
.idea/vcs.xml
|
||||
.idea/jsLibraryMappings.xml
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/dataSources.ids
|
||||
.idea/dataSources.xml
|
||||
.idea/dataSources.local.xml
|
||||
.idea/sqlDataSources.xml
|
||||
.idea/dynamic.xml
|
||||
.idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/gradle.xml
|
||||
.idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
### PhpStorm Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
|
||||
|
||||
### Windows ###
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Folder config file
|
||||
Desktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
||||
|
||||
### OSX ###
|
||||
*.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
|
||||
### Node ###
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
.idea
|
||||
3
.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
dist
|
||||
.out
|
||||
7
.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"jsxBracketSameLine": true,
|
||||
"useTabs": true,
|
||||
"printWidth": 120
|
||||
}
|
||||
129
CHANGELOG.md
@@ -1,64 +1,107 @@
|
||||
__6.0.0__
|
||||
|
||||
Note: This is a complete rewrite of the library, a good place to start to see how the new system works
|
||||
is with the new demo project which illustrates the new capability.
|
||||
|
||||
I would also recommend taking a look at the new updated DiamondPort widget which shows more capability.
|
||||
|
||||
* Break up library into monorepo
|
||||
* Introduce react-canvas-core as a new framework
|
||||
* Use geometry classes instead of raw X and Y primitives so we can do matrix stuff in the future
|
||||
* move testing framework to a name based system instead of ID's
|
||||
* Introduce multiple layers (can now have multiple node and link layers)
|
||||
* Rewrote the deserialization system to be promise based
|
||||
* Completely overhauled the observer framework on the models
|
||||
* Moved all the logic in the DiagramWidget into a a new hierarchical state machine
|
||||
* Introduces new states for editing
|
||||
* Introduced faster layout rendering when transforming the canvas directly
|
||||
* Moved all canvas smart routing into its own link-type under routing package
|
||||
* Broke up link rendering into a much more modular system that is much easier to extend
|
||||
* Introduced port alignment allowing the developer to specify how enter it
|
||||
* Improved generics throughout the entire model system with Mapped Types
|
||||
* Rewrote all the styles using emotion instead of sass
|
||||
* Fixed up all the demos to use the new API
|
||||
* Introduced a demo project that illustrates how to use the library with ES6 as well as with Typescript
|
||||
* Improved the grid rendering system to allow graphical elements to specify how they get transformed
|
||||
* Introduced a performance widget for improving performance in a more deterministic way by comparing the serialization of the model (with a way of opting out)
|
||||
* Renamed a bunch of methods to be more consistent and more understandable
|
||||
* Completely removed the double render state system that required nodes to render before links, this is done when ports report their new positions
|
||||
* Ports can now dynamically be added and removed without having to tell the system it happeend
|
||||
* Port widgets are now containers dumb containers for you own ports
|
||||
* Port widgets report new sizing information to their target links when they change position, you no longer need to invalidate them
|
||||
|
||||
__5.3.2__
|
||||
|
||||
* (maintenance) Upgrade :allthethings: (all the build tooling was upgrade)
|
||||
* (api) move to ES6 (JS now contains native classes)
|
||||
* (api) changed package name to @projectstorm/react-diagrams
|
||||
* (bug) (PR259)(https://github.com/projectstorm/react-diagrams/pull/259) Fixes #258
|
||||
* (refactor) (PR 306)(https://github.com/projectstorm/react-diagrams/pull/306) `:any` fix
|
||||
* (feature) (PR 178)(https://github.com/projectstorm/react-diagrams/pull/178) Trigger a positionChanged event when moving a Node that has the listener assigned.
|
||||
* (fix) (PR 356)(https://github.com/projectstorm/react-diagrams/pull/356) Fixed Type issue with 'PointModel()'
|
||||
* (demo) dark mode and upgrade storybook
|
||||
|
||||
__5.2.1__
|
||||
|
||||
* [fix] Always remove link from old source/target port on port change
|
||||
* [maintenance] upgrade node modules
|
||||
* [refactor] https://github.com/projectstorm/react-diagrams/commit/55f62587bd3b12513c7d37eff59edfc8bdb8d6c9
|
||||
* [bug] https://github.com/projectstorm/react-diagrams/commit/75ef02dd4d131a0e7c08b2680c69efc390e50b84
|
||||
* (fix) Always remove link from old source/target port on port change
|
||||
* (maintenance) upgrade node modules
|
||||
* (refactor) https://github.com/projectstorm/react-diagrams/commit/55f62587bd3b12513c7d37eff59edfc8bdb8d6c9
|
||||
* (bug) https://github.com/projectstorm/react-diagrams/commit/75ef02dd4d131a0e7c08b2680c69efc390e50b84
|
||||
-> and other improvements, also checkout the foundation work happening over at https://github.com/projectstorm/react-canvas
|
||||
|
||||
__5.1.0__
|
||||
|
||||
* [api] Rename XXXFactory into AbstractXXXFactory
|
||||
* [refactor] tslint and prettier are now the same
|
||||
* [refactor] Each class now explicitely has its own class file (consistency)
|
||||
* [feature] Smooth vertical links (no longer limited to horizontal)
|
||||
* [feature] Dedicated documentation via gitbook
|
||||
* [bug] forgot to export some
|
||||
* [refactor] consistently use lodash where possible
|
||||
* [maintenance] upgrade node modules
|
||||
* (api) Rename XXXFactory into AbstractXXXFactory
|
||||
* (refactor) tslint and prettier are now the same
|
||||
* (refactor) Each class now explicitely has its own class file (consistency)
|
||||
* (feature) Smooth vertical links (no longer limited to horizontal)
|
||||
* (feature) Dedicated documentation via gitbook
|
||||
* (bug) forgot to export some
|
||||
* (refactor) consistently use lodash where possible
|
||||
* (maintenance) upgrade node modules
|
||||
|
||||
__5.0.0__ http://dylanv.blog/2018/03/03/storm-react-diagrams-5-0-0/
|
||||
|
||||
PR: https://github.com/projectstorm/react-diagrams/pull/145
|
||||
|
||||
* [refactor] Links completely overhauled
|
||||
* [feature] Smart Routing
|
||||
* [feature] Flow support
|
||||
* [demo] Smart Routing
|
||||
* [demo] Animated links
|
||||
* [api] Bootstrapping Improvements
|
||||
* [feature] add custom properties to all widgets
|
||||
* [refactor] use BEM for all css
|
||||
* [feature] Default Link factory hooks
|
||||
* [tests] e2e tests + helper framework
|
||||
* [tests] automatically load JEST Snapshots
|
||||
* [feature] Link labels!
|
||||
* (refactor) Links completely overhauled
|
||||
* (feature) Smart Routing
|
||||
* (feature) Flow support
|
||||
* (demo) Smart Routing
|
||||
* (demo) Animated links
|
||||
* (api) Bootstrapping Improvements
|
||||
* (feature) add custom properties to all widgets
|
||||
* (refactor) use BEM for all css
|
||||
* (feature) Default Link factory hooks
|
||||
* (tests) e2e tests + helper framework
|
||||
* (tests) automatically load JEST Snapshots
|
||||
* (feature) Link labels!
|
||||
|
||||
__4.0.0__ http://dylanv.blog/2018/01/18/storm-react-diagrams-v4-0-0/
|
||||
|
||||
* [refactor] Events system was completely overhauled
|
||||
* [demo] Custom Link Sizes
|
||||
* [refactor] Demos are now much more verbose and better managed
|
||||
* [update] node packages
|
||||
* [bug] Fix #129
|
||||
* [feature] Control link creation through ports
|
||||
* [refactor] Models are now in seperate files
|
||||
* [refactor] Merged the concept of instance factories and widget factories into one
|
||||
* [feature] Models can now be cloned at various parts of the model graph
|
||||
* [demo] Cloning
|
||||
* [feature] models control isLocked
|
||||
* (refactor) Events system was completely overhauled
|
||||
* (demo) Custom Link Sizes
|
||||
* (refactor) Demos are now much more verbose and better managed
|
||||
* (update) node packages
|
||||
* (bug) Fix #129
|
||||
* (feature) Control link creation through ports
|
||||
* (refactor) Models are now in seperate files
|
||||
* (refactor) Merged the concept of instance factories and widget factories into one
|
||||
* (feature) Models can now be cloned at various parts of the model graph
|
||||
* (demo) Cloning
|
||||
* (feature) models control isLocked
|
||||
|
||||
__3.2.0__ http://dylanv.blog/2017/11/22/storm-react-diagrams-3-2-0/
|
||||
* [feature] zoom to fit
|
||||
* (feature) zoom to fit
|
||||
* added Circle CI tests
|
||||
* [demo] dagre automatic layouts
|
||||
* [demo] zoom to fit
|
||||
* [demo] selection events
|
||||
* [demo] limit number of points
|
||||
* [demo] programmatic node updating
|
||||
* (demo) dagre automatic layouts
|
||||
* (demo) zoom to fit
|
||||
* (demo) selection events
|
||||
* (demo) limit number of points
|
||||
* (demo) programmatic node updating
|
||||
* updated dependencies
|
||||
* [bugs] swapping diagram models in engines
|
||||
* [bugs] issues with the rendering pipeline #107
|
||||
* (bugs) swapping diagram models in engines
|
||||
* (bugs) issues with the rendering pipeline #107
|
||||
* added ci badge to Readme
|
||||
|
||||
__3.1.3__
|
||||
|
||||
84
README.md
@@ -1,46 +1,84 @@
|
||||
# STORM React Diagrams
|
||||
# STORM React Diagrams __6__ [beta]
|
||||
|
||||
__PSA 2018__: React Diagrams ~is currently~ was getting a bit of a rewrite to enable much more advanced features. To see the new foundation WIP visit [https://github.com/projectstorm/react-canvas](https://github.com/projectstorm/react-canvas).
|
||||
[](https://gitter.im/projectstorm/react-diagrams?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://npmjs.org/package/@projectstorm/react-diagrams) [](http://packagequality.com/#?package=storm-react-diagrams) [](https://circleci.com/gh/projectstorm/react-diagrams/tree/master) [](https://lerna.js.org/)
|
||||
|
||||
__PSA 2019__: I still want to jump onto the rewrite, but it is a much larger project than anticipated, so going to try maintain this one in the mean time.
|
||||

|
||||
|
||||
[pssst! Looking for the old version 5?](https://github.com/projectstorm/react-diagrams/tree/v5.3.2)
|
||||
|
||||
---
|
||||
|
||||
**DEMO**: [http://projectstorm.cloud/react-diagrams](http://projectstorm.cloud/react-diagrams)
|
||||
|
||||
**(SOME) DOCS:** [https://projectstorm.gitbooks.io/react-diagrams](https://projectstorm.gitbooks.io/react-diagrams)
|
||||
**DOCS (incomplete)** [https://projectstorm.gitbooks.io/react-diagrams](https://projectstorm.gitbooks.io/react-diagrams)
|
||||
|
||||
**RELEASE NOTES** : [http://dylanv.blog/2018/03/03/storm-react-diagrams-5-0-0/](http://dylanv.blog/2018/03/03/storm-react-diagrams-5-0-0/)
|
||||
## What
|
||||
|
||||
A super simple, no-nonsense diagramming library written in React that just works.
|
||||
A flow & process orientated diagramming library inspired by __Blender__, __Labview__ and __Unreal engine__.
|
||||
|
||||
[](https://gitter.im/projectstorm/react-diagrams?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://npmjs.org/package/storm-react-diagrams) [](https://npmjs.org/package/storm-react-diagrams) [](http://packagequality.com/#?package=storm-react-diagrams) [](https://circleci.com/gh/projectstorm/react-diagrams/tree/master)
|
||||
* __Modern Codebase__ written entirely in Typescript and React, the library makes use of powerful generics, advanced software engineering principles and is broken up into multiple modules.
|
||||
* __Hackable and extensible__ the entire library including its core can be extended, rewired and re-assembled into fundamentally different software to suit your own software needs.
|
||||
* __HTML nodes as a first class citizen__ the library was originally written to represent advanced dynamic nodes, that are difficult to represent as SVG's due to complex input requirements ux requirements.
|
||||
* __Designed for process__ the library is aimed for software engineers that want to rewire their programs at runtime, and that want to make their software more dynamic.
|
||||
* __Fast diagram editing__ the defaults provided give the heighest priority to editing diagrams as fast as possible.
|
||||
|
||||
## Gallery
|
||||
|
||||
Example implementation using custom models: (Dylan's personal code)
|
||||
|
||||

|
||||

|
||||
|
||||
Example implementation using custom models:
|
||||

|
||||

|
||||
Get started with the default models right out of the box:
|
||||

|
||||
|
||||

|
||||
|
||||
## Introduction
|
||||
## Installing
|
||||
|
||||
A no-nonsense diagramming library written entirely in React with the help of a few small libraries. It aims to be:
|
||||
For all the bells and whistles:
|
||||
|
||||
* Simple, and void of any fuss/complications when implementing it into your own application
|
||||
* Customizable without having to hack the core \(adapters/factories etc..\)
|
||||
* Simple to operate and understand without sugar and magic
|
||||
* Fast and optimized to handle large diagrams with hundreds of nodes/links
|
||||
* Super easy to use, and should work as you expect it to
|
||||
* Perfect for creating declarative systems such as programmatic pipelines and visual programming languages
|
||||
yarn add @projectstorm/react-diagrams@next
|
||||
|
||||
#### Run the demos
|
||||
This includes all the packages listed below (and works (mostly and conceptually) like it used to in version 5.0)
|
||||
|
||||
After running `yarn install` you must then run: `yarn run storybook`
|
||||
### A more modular approach
|
||||
|
||||
#### Building from source
|
||||
This library now has a more modular design and you can import just the core (contains no default factories or routing)
|
||||
|
||||
Simply run `webpack` in the root directory \(or `export NODE_ENV=production && webpack` if you want a production build\) and it will spit out the transpiled code and typescript definitions into the dist directory as a single file.
|
||||
yarn add @projectstorm/react-diagrams-core@next
|
||||
|
||||
this is built ontop of the evolving __react-canvas-core__ library
|
||||
|
||||
```
|
||||
yarn add @projectstorm/react-diagrams-core@next
|
||||
```
|
||||
|
||||
which makes use of
|
||||
|
||||
```
|
||||
yarn add @projectstorm/react-geometry@next
|
||||
```
|
||||
|
||||
and of course, you can add some extras:
|
||||
|
||||
yarn add @projectstorm/react-diagrams-defaults@next
|
||||
yarn add @projectstorm/react-diagrams-routing@next
|
||||
|
||||
## How to use
|
||||
|
||||
Take a look at the [demos](packages/diagrams-demo-gallery)
|
||||
|
||||
__or__
|
||||
|
||||
Take a look at the [demo project](packages/diagrams-demo-project) which contains an example for ES6 as well as Typescript
|
||||
|
||||
## Run the demos
|
||||
|
||||
After running `yarn install` you must then run: `cd packages/diagrams-demo-gallery && yarn run start`
|
||||
|
||||
## Building from source
|
||||
|
||||
Simply run `yarn build` in the root directory \(or `NODE_ENV=production yarn build` if you want a production build\) and it will spit out the transpiled code and typescript definitions into the dist directory as a single file.
|
||||
We use webpack for this because TSC cannot compile a single UMD file \(TSC can currently only output multiple UMD files\).
|
||||
|
||||
## [Checkout the docs](https://projectstorm.gitbooks.io/react-diagrams)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface DemoWorkspaceWidgetProps {
|
||||
buttons?: any;
|
||||
}
|
||||
|
||||
export interface DemoWorkspaceWidgetState {}
|
||||
|
||||
export class DemoWorkspaceWidget extends React.Component<DemoWorkspaceWidgetProps, DemoWorkspaceWidgetState> {
|
||||
constructor(props: DemoWorkspaceWidgetProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="srd-demo-workspace">
|
||||
<div className="srd-demo-workspace__toolbar">{this.props.buttons}</div>
|
||||
<div className="srd-demo-workspace__content">{this.props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export class Helper {
|
||||
/**
|
||||
* Logs the mouse position in the console, but overlays a div that consumes all events
|
||||
* since the actual story book stories are rendered as an iFrame.
|
||||
*/
|
||||
static logMousePosition() {
|
||||
let element = window.parent.document.createElement("mouse-position");
|
||||
element.style.position = "absolute";
|
||||
element.style.top = "0px";
|
||||
element.style.left = "0px";
|
||||
element.style.bottom = "0px";
|
||||
element.style.right = "0px";
|
||||
element.style.zIndex = "10";
|
||||
window.parent.document.body.appendChild(element);
|
||||
|
||||
window.parent.window.addEventListener("mousemove", event => {
|
||||
console.clear();
|
||||
console.log(event.clientX, event.clientY);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
@import "../../src/sass/main";
|
||||
|
||||
html, body, #root{
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.srd-demo-workspace{
|
||||
background: black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
|
||||
&__toolbar{
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
||||
button{
|
||||
background: rgb(60,60,60);
|
||||
font-size: 14px;
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
color: white;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
margin: 2px;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover{
|
||||
background: rgb(0,192,255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__content{
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.srd-demo-canvas{
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
background-color: rgb(60,60,60) !important;
|
||||
$color: rgba(white, .05);
|
||||
background-image:
|
||||
linear-gradient(0deg,
|
||||
transparent 24%,
|
||||
$color 25%,
|
||||
$color 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
$color 75%,
|
||||
$color 76%,
|
||||
transparent 77%,
|
||||
transparent),
|
||||
linear-gradient(90deg,
|
||||
transparent 24%,
|
||||
$color 25%,
|
||||
$color 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
$color 75%,
|
||||
$color 76%,
|
||||
transparent 77%,
|
||||
transparent);
|
||||
background-size:50px 50px;
|
||||
|
||||
.pointui{
|
||||
fill: rgba(white,0.5);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import * as SRD from "storm-react-diagrams";
|
||||
import { DiamonNodeWidget } from "./DiamondNodeWidget";
|
||||
import { DiamondNodeModel } from "./DiamondNodeModel";
|
||||
import * as React from "react";
|
||||
|
||||
export class DiamondNodeFactory extends SRD.AbstractNodeFactory {
|
||||
constructor() {
|
||||
super("diamond");
|
||||
}
|
||||
|
||||
generateReactWidget(diagramEngine: SRD.DiagramEngine, node: SRD.NodeModel): JSX.Element {
|
||||
return <DiamonNodeWidget node={node} />;
|
||||
}
|
||||
|
||||
getNewInstance() {
|
||||
return new DiamondNodeModel();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import { NodeModel } from "storm-react-diagrams";
|
||||
import { DiamondPortModel } from "./DiamondPortModel";
|
||||
|
||||
export class DiamondNodeModel extends NodeModel {
|
||||
constructor() {
|
||||
super("diamond");
|
||||
this.addPort(new DiamondPortModel("top"));
|
||||
this.addPort(new DiamondPortModel("left"));
|
||||
this.addPort(new DiamondPortModel("bottom"));
|
||||
this.addPort(new DiamondPortModel("right"));
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { DiamondNodeModel } from "./DiamondNodeModel";
|
||||
import { PortWidget } from "storm-react-diagrams";
|
||||
|
||||
export interface DiamonNodeWidgetProps {
|
||||
node: DiamondNodeModel;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export interface DiamonNodeWidgetState {}
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export class DiamonNodeWidget extends React.Component<DiamonNodeWidgetProps, DiamonNodeWidgetState> {
|
||||
public static defaultProps: DiamonNodeWidgetProps = {
|
||||
size: 150,
|
||||
node: null
|
||||
};
|
||||
|
||||
constructor(props: DiamonNodeWidgetProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
className={"diamond-node"}
|
||||
style={{
|
||||
position: "relative",
|
||||
width: this.props.size,
|
||||
height: this.props.size
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
width={this.props.size}
|
||||
height={this.props.size}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
`
|
||||
<g id="Layer_1">
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<polygon fill="purple" stroke="#000000" stroke-width="3" stroke-miterlimit="10" points="10,` +
|
||||
this.props.size / 2 +
|
||||
` ` +
|
||||
this.props.size / 2 +
|
||||
`,10 ` +
|
||||
(this.props.size - 10) +
|
||||
`,` +
|
||||
this.props.size / 2 +
|
||||
` ` +
|
||||
this.props.size / 2 +
|
||||
`,` +
|
||||
(this.props.size - 10) +
|
||||
` "/>
|
||||
</g>
|
||||
`
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 10,
|
||||
top: this.props.size / 2 - 8,
|
||||
left: -8
|
||||
}}
|
||||
>
|
||||
<PortWidget name="left" node={this.props.node} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 10,
|
||||
left: this.props.size / 2 - 8,
|
||||
top: -8
|
||||
}}
|
||||
>
|
||||
<PortWidget name="top" node={this.props.node} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 10,
|
||||
left: this.props.size - 8,
|
||||
top: this.props.size / 2 - 8
|
||||
}}
|
||||
>
|
||||
<PortWidget name="right" node={this.props.node} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
zIndex: 10,
|
||||
left: this.props.size / 2 - 8,
|
||||
top: this.props.size - 8
|
||||
}}
|
||||
>
|
||||
<PortWidget name="bottom" node={this.props.node} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import * as _ from "lodash";
|
||||
import { LinkModel, DiagramEngine, PortModel, DefaultLinkModel } from "storm-react-diagrams";
|
||||
|
||||
export class DiamondPortModel extends PortModel {
|
||||
position: string | "top" | "bottom" | "left" | "right";
|
||||
|
||||
constructor(pos: string = "top") {
|
||||
super(pos, "diamond");
|
||||
this.position = pos;
|
||||
}
|
||||
|
||||
serialize() {
|
||||
return _.merge(super.serialize(), {
|
||||
position: this.position
|
||||
});
|
||||
}
|
||||
|
||||
deSerialize(data: any, engine: DiagramEngine) {
|
||||
super.deSerialize(data, engine);
|
||||
this.position = data.position;
|
||||
}
|
||||
|
||||
createLinkModel(): LinkModel {
|
||||
return new DefaultLinkModel();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { PortModel, AbstractPortFactory } from "storm-react-diagrams";
|
||||
|
||||
export class SimplePortFactory extends AbstractPortFactory {
|
||||
cb: (initialConfig?: any) => PortModel;
|
||||
|
||||
constructor(type: string, cb: (initialConfig?: any) => PortModel) {
|
||||
super(type);
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
getNewInstance(initialConfig?: any): PortModel {
|
||||
return this.cb(initialConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
|
||||
// import the custom models
|
||||
import { DiamondNodeModel } from "./DiamondNodeModel";
|
||||
import { DiamondNodeFactory } from "./DiamondNodeFactory";
|
||||
import { SimplePortFactory } from "./SimplePortFactory";
|
||||
import { DiamondPortModel } from "./DiamondPortModel";
|
||||
|
||||
/**
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
// register some other factories as well
|
||||
engine.registerPortFactory(new SimplePortFactory("diamond", config => new DiamondPortModel()));
|
||||
engine.registerNodeFactory(new DiamondNodeFactory());
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 150);
|
||||
|
||||
//3-B) create our new custom node
|
||||
var node2 = new DiamondNodeModel();
|
||||
node2.setPosition(250, 108);
|
||||
|
||||
var node3 = new DefaultNodeModel("Node 3", "red");
|
||||
var port3 = node3.addInPort("In");
|
||||
node3.setPosition(500, 150);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(node2.getPort("left"));
|
||||
var link2 = port3.link(node2.getPort("right"));
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, node3, link1, link2);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
@@ -1,56 +0,0 @@
|
||||
import * as dagre from "dagre";
|
||||
import * as _ from "lodash";
|
||||
|
||||
const size = {
|
||||
width: 60,
|
||||
height: 60
|
||||
};
|
||||
|
||||
export function distributeElements(model) {
|
||||
let clonedModel = _.cloneDeep(model);
|
||||
let nodes = distributeGraph(clonedModel);
|
||||
nodes.forEach(node => {
|
||||
let modelNode = clonedModel.nodes.find(item => item.id === node.id);
|
||||
modelNode.x = node.x - node.width / 2;
|
||||
modelNode.y = node.y - node.height / 2;
|
||||
});
|
||||
return clonedModel;
|
||||
}
|
||||
|
||||
function distributeGraph(model) {
|
||||
let nodes = mapElements(model);
|
||||
let edges = mapEdges(model);
|
||||
let graph = new dagre.graphlib.Graph();
|
||||
graph.setGraph({});
|
||||
graph.setDefaultEdgeLabel(() => ({}));
|
||||
//add elements to dagre graph
|
||||
nodes.forEach(node => {
|
||||
graph.setNode(node.id, node.metadata);
|
||||
});
|
||||
edges.forEach(edge => {
|
||||
if (edge.from && edge.to) {
|
||||
graph.setEdge(edge.from, edge.to);
|
||||
}
|
||||
});
|
||||
//auto-distribute
|
||||
dagre.layout(graph);
|
||||
return graph.nodes().map(node => graph.node(node));
|
||||
}
|
||||
|
||||
function mapElements(model) {
|
||||
// dagre compatible format
|
||||
return model.nodes.map(node => ({ id: node.id, metadata: { ...size, id: node.id } }));
|
||||
}
|
||||
|
||||
function mapEdges(model) {
|
||||
// returns links which connects nodes
|
||||
// we check are there both from and to nodes in the model. Sometimes links can be detached
|
||||
return model.links
|
||||
.map(link => ({
|
||||
from: link.source,
|
||||
to: link.target
|
||||
}))
|
||||
.filter(
|
||||
item => model.nodes.find(node => node.id === item.from) && model.nodes.find(node => node.id === item.to)
|
||||
);
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DefaultNodeFactory,
|
||||
DefaultLinkFactory,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
import { distributeElements } from "./dagre-utils";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
|
||||
function createNode(name) {
|
||||
return new DefaultNodeModel(name, "rgb(0,192,255)");
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
|
||||
function connectNodes(nodeFrom, nodeTo) {
|
||||
//just to get id-like structure
|
||||
count++;
|
||||
const portOut = nodeFrom.addPort(new DefaultPortModel(true, `${nodeFrom.name}-out-${count}`, "Out"));
|
||||
const portTo = nodeTo.addPort(new DefaultPortModel(false, `${nodeFrom.name}-to-${count}`, "IN"));
|
||||
return portOut.link(portTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests auto distribution
|
||||
*/
|
||||
class Demo8Widget extends React.Component<any, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
this.autoDistribute = this.autoDistribute.bind(this);
|
||||
}
|
||||
|
||||
autoDistribute() {
|
||||
const { engine } = this.props;
|
||||
const model = engine.getDiagramModel();
|
||||
let distributedModel = getDistributedModel(engine, model);
|
||||
engine.setDiagramModel(distributedModel);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<button onClick={this.autoDistribute}>Re-distribute</button>}>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getDistributedModel(engine, model) {
|
||||
const serialized = model.serializeDiagram();
|
||||
const distributedSerializedDiagram = distributeElements(serialized);
|
||||
|
||||
//deserialize the model
|
||||
let deSerializedModel = new DiagramModel();
|
||||
deSerializedModel.deSerializeDiagram(distributedSerializedDiagram, engine);
|
||||
return deSerializedModel;
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
let engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
let model = new DiagramModel();
|
||||
|
||||
//3) create a default nodes
|
||||
let nodesFrom = [];
|
||||
let nodesTo = [];
|
||||
|
||||
nodesFrom.push(createNode("from-1"));
|
||||
nodesFrom.push(createNode("from-2"));
|
||||
nodesFrom.push(createNode("from-3"));
|
||||
|
||||
nodesTo.push(createNode("to-1"));
|
||||
nodesTo.push(createNode("to-2"));
|
||||
nodesTo.push(createNode("to-3"));
|
||||
|
||||
//4) link nodes together
|
||||
let links = nodesFrom.map((node, index) => {
|
||||
return connectNodes(node, nodesTo[index]);
|
||||
});
|
||||
|
||||
// more links for more complicated diagram
|
||||
links.push(connectNodes(nodesFrom[0], nodesTo[1]));
|
||||
links.push(connectNodes(nodesTo[0], nodesFrom[1]));
|
||||
links.push(connectNodes(nodesFrom[1], nodesTo[2]));
|
||||
|
||||
// initial random position
|
||||
nodesFrom.forEach((node, index) => {
|
||||
node.x = index * 70;
|
||||
model.addNode(node);
|
||||
});
|
||||
|
||||
nodesTo.forEach((node, index) => {
|
||||
node.x = index * 70;
|
||||
node.y = 100;
|
||||
model.addNode(node);
|
||||
});
|
||||
|
||||
links.forEach(link => {
|
||||
model.addLink(link);
|
||||
});
|
||||
|
||||
//5) load model into engine
|
||||
let model2 = getDistributedModel(engine, model);
|
||||
|
||||
engine.setDiagramModel(model2);
|
||||
|
||||
return <Demo8Widget engine={engine} />;
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import * as React from "react";
|
||||
import * as _ from "lodash";
|
||||
import { TrayWidget } from "./TrayWidget";
|
||||
import { Application } from "../Application";
|
||||
import { TrayItemWidget } from "./TrayItemWidget";
|
||||
import { DefaultNodeModel, DiagramWidget } from "storm-react-diagrams";
|
||||
|
||||
export interface BodyWidgetProps {
|
||||
app: Application;
|
||||
}
|
||||
|
||||
export interface BodyWidgetState {}
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export class BodyWidget extends React.Component<BodyWidgetProps, BodyWidgetState> {
|
||||
constructor(props: BodyWidgetProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="body">
|
||||
<div className="header">
|
||||
<div className="title">Storm React Diagrams - Demo 5</div>
|
||||
</div>
|
||||
<div className="content">
|
||||
<TrayWidget>
|
||||
<TrayItemWidget model={{ type: "in" }} name="In Node" color="rgb(192,255,0)" />
|
||||
<TrayItemWidget model={{ type: "out" }} name="Out Node" color="rgb(0,192,255)" />
|
||||
</TrayWidget>
|
||||
<div
|
||||
className="diagram-layer"
|
||||
onDrop={event => {
|
||||
var data = JSON.parse(event.dataTransfer.getData("storm-diagram-node"));
|
||||
var nodesCount = _.keys(
|
||||
this.props.app
|
||||
.getDiagramEngine()
|
||||
.getDiagramModel()
|
||||
.getNodes()
|
||||
).length;
|
||||
|
||||
var node = null;
|
||||
if (data.type === "in") {
|
||||
node = new DefaultNodeModel("Node " + (nodesCount + 1), "rgb(192,255,0)");
|
||||
node.addInPort("In");
|
||||
} else {
|
||||
node = new DefaultNodeModel("Node " + (nodesCount + 1), "rgb(0,192,255)");
|
||||
node.addOutPort("Out");
|
||||
}
|
||||
var points = this.props.app.getDiagramEngine().getRelativeMousePoint(event);
|
||||
node.x = points.x;
|
||||
node.y = points.y;
|
||||
this.props.app
|
||||
.getDiagramEngine()
|
||||
.getDiagramModel()
|
||||
.addNode(node);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
onDragOver={event => {
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={this.props.app.getDiagramEngine()} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface TrayItemWidgetProps {
|
||||
model: any;
|
||||
color?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface TrayItemWidgetState {}
|
||||
|
||||
export class TrayItemWidget extends React.Component<TrayItemWidgetProps, TrayItemWidgetState> {
|
||||
constructor(props: TrayItemWidgetProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
style={{ borderColor: this.props.color }}
|
||||
draggable={true}
|
||||
onDragStart={event => {
|
||||
event.dataTransfer.setData("storm-diagram-node", JSON.stringify(this.props.model));
|
||||
}}
|
||||
className="tray-item"
|
||||
>
|
||||
{this.props.name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
export interface TrayWidgetProps {}
|
||||
|
||||
export interface TrayWidgetState {}
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export class TrayWidget extends React.Component<TrayWidgetProps, TrayWidgetState> {
|
||||
public static defaultProps: TrayWidgetProps = {};
|
||||
|
||||
constructor(props: TrayWidgetProps) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div className="tray">{this.props.children}</div>;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { BodyWidget } from "./components/BodyWidget";
|
||||
import { Application } from "./Application";
|
||||
|
||||
import "./sass/main.scss";
|
||||
|
||||
export default () => {
|
||||
var app = new Application();
|
||||
|
||||
return <BodyWidget app={app} />;
|
||||
};
|
||||
@@ -1,47 +0,0 @@
|
||||
.body{
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
|
||||
.header{
|
||||
display: flex;
|
||||
background: rgb(30,30,30);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
font-family: Helvetica, Arial;
|
||||
padding: 10px;
|
||||
>*{
|
||||
align-self:center;
|
||||
}
|
||||
}
|
||||
|
||||
.content{
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
||||
.diagram-layer{
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tray{
|
||||
min-width: 200px;
|
||||
background: rgb(20,20,20);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
|
||||
.tray-item{
|
||||
color: white;
|
||||
font-family: Helvetica, Arial;
|
||||
padding: 5px;
|
||||
margin: 0px 10px;
|
||||
border: solid 1px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
|
||||
/**
|
||||
* Tests the grid size
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
model.setGridSize(50);
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
@@ -1,72 +0,0 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget,
|
||||
DefaultLinkModel
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
const engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
// setup the diagram model
|
||||
const model = new DiagramModel();
|
||||
|
||||
// create four nodes
|
||||
const node1 = new DefaultNodeModel("Node A", "rgb(0,192,255)");
|
||||
const port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
const node2 = new DefaultNodeModel("Node B", "rgb(255,255,0)");
|
||||
const port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 50);
|
||||
|
||||
const node3 = new DefaultNodeModel("Node C (no label)", "rgb(192,255,255)");
|
||||
const port3 = node3.addInPort("In");
|
||||
node3.setPosition(450, 180);
|
||||
|
||||
const node4 = new DefaultNodeModel("Node D", "rgb(192,0,255)");
|
||||
const port4 = node4.addInPort("In");
|
||||
node4.setPosition(300, 250);
|
||||
|
||||
// link node A and B together and give it a label
|
||||
const link1 = port1.link(port2);
|
||||
(link1 as DefaultLinkModel).addLabel("Custom label 1");
|
||||
(link1 as DefaultLinkModel).addLabel("Custom label 2");
|
||||
|
||||
// no label for A and C, just a link
|
||||
const link2 = port1.link(port3);
|
||||
|
||||
// also a label for A and D
|
||||
const link3 = port1.link(port4);
|
||||
(link3 as DefaultLinkModel).addLabel("Emoji label: 🎉");
|
||||
|
||||
// add all to the main model
|
||||
model.addAll(node1, node2, node3, node4, link1, link2, link3);
|
||||
|
||||
// load model into engine and render
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<button
|
||||
onClick={() => {
|
||||
action("Serialized Graph")(JSON.stringify(model.serializeDiagram(), null, 2));
|
||||
}}
|
||||
>
|
||||
Serialize Graph
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DiagramWidget,
|
||||
DiagramProps
|
||||
} from "storm-react-diagrams";
|
||||
|
||||
/**
|
||||
* Shows that a limit of points can be set for links
|
||||
*/
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port.link(port2);
|
||||
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
var props = {
|
||||
diagramEngine: engine,
|
||||
maxNumberPointsPerLink: 5
|
||||
} as DiagramProps;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>A maximum of 5 points can be created per link.</p>
|
||||
<DiagramWidget className="srd-demo-canvas" {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DiagramProps,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
|
||||
/**
|
||||
* Shows some of the events triggered when elements are selected
|
||||
*/
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
// sample for link with simple line
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(255,99,66)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 40);
|
||||
|
||||
var node3 = new DefaultNodeModel("Node 3", "rgb(128,99,255)");
|
||||
var port3 = node3.addInPort("In");
|
||||
node3.setPosition(300, 160);
|
||||
|
||||
//link the nodes
|
||||
let link1 = port1.link(port2);
|
||||
let link2 = port1.link(port3);
|
||||
|
||||
// add all the models
|
||||
let models = model.addAll(node1, node2, node3, link1, link2);
|
||||
|
||||
// add a selection listener to each
|
||||
models.forEach(item => {
|
||||
item.addListener({
|
||||
selectionChanged: action("selectionChanged")
|
||||
});
|
||||
});
|
||||
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
var props = {
|
||||
diagramEngine: engine,
|
||||
maxNumberPointsPerLink: 0 // no extra points so link selection is fired straight away
|
||||
} as DiagramProps;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Click the diagram elements to inspect some of the possible events.</p>
|
||||
<DiagramWidget className="srd-demo-canvas" {...props} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,69 +0,0 @@
|
||||
import * as React from "react";
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
PointModel,
|
||||
DiagramWidget,
|
||||
DiagramProps
|
||||
} from "storm-react-diagrams";
|
||||
|
||||
/**
|
||||
*
|
||||
* Shows how you can lock down the system so that the entire scene cant be interacted with.
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
// sample for link with simple line (no additional points)
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
let link1 = port1.link(port2);
|
||||
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
// sample for link with complex line (additional points)
|
||||
var node3 = new DefaultNodeModel("Node 3", "rgb(0,192,255)");
|
||||
var port3 = node3.addOutPort("Out");
|
||||
node3.setPosition(100, 250);
|
||||
|
||||
var node4 = new DefaultNodeModel("Node 4", "rgb(192,255,0)");
|
||||
var port4 = node4.addInPort("In");
|
||||
node4.setPosition(400, 250);
|
||||
|
||||
var link2 = port3.link(port4);
|
||||
|
||||
link2.point(350, 225);
|
||||
link2.point(200, 225);
|
||||
|
||||
model.addAll(node3, node4, link2);
|
||||
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//!========================================= <<<<<<<
|
||||
|
||||
model.setLocked(true);
|
||||
var props = {
|
||||
diagramEngine: engine,
|
||||
allowLooseLinks: false,
|
||||
allowCanvasTranslation: false,
|
||||
allowCanvasZoom: false
|
||||
} as DiagramProps;
|
||||
|
||||
//!========================================= <<<<<<<
|
||||
|
||||
return <DiagramWidget className="srd-demo-canvas" {...props} />;
|
||||
};
|
||||
@@ -1,86 +0,0 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
|
||||
/**
|
||||
* Tests the grid size
|
||||
*/
|
||||
class NodeDelayedPosition extends React.Component<any, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.updatePosition = this.updatePosition.bind(this);
|
||||
this.updatePositionViaSerialize = this.updatePositionViaSerialize.bind(this);
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
const { engine } = this.props;
|
||||
let model = engine.getDiagramModel();
|
||||
const nodes = model.getNodes();
|
||||
let node = nodes[Object.keys(nodes)[0]];
|
||||
node.setPosition(node.x + 30, node.y + 30);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
updatePositionViaSerialize() {
|
||||
let { engine } = this.props;
|
||||
let model = engine.getDiagramModel();
|
||||
let str = JSON.stringify(model.serializeDiagram());
|
||||
let model2 = new DiagramModel();
|
||||
let obj = JSON.parse(str);
|
||||
let node = obj.nodes[0];
|
||||
node.x += 30;
|
||||
node.y += 30;
|
||||
model2.deSerializeDiagram(obj, engine);
|
||||
engine.setDiagramModel(model2);
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={[
|
||||
<button key={1} onClick={this.updatePosition}>
|
||||
Update position
|
||||
</button>,
|
||||
<button key={2} onClick={this.updatePositionViaSerialize}>
|
||||
Update position via serialize
|
||||
</button>
|
||||
]}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <NodeDelayedPosition engine={engine} model={model} />;
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import * as beautify from "json-beautify";
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//!------------- SERIALIZING ------------------
|
||||
|
||||
var str = JSON.stringify(model.serializeDiagram());
|
||||
|
||||
//!------------- DESERIALIZING ----------------
|
||||
|
||||
var model2 = new DiagramModel();
|
||||
model2.deSerializeDiagram(JSON.parse(str), engine);
|
||||
engine.setDiagramModel(model2);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<button
|
||||
onClick={() => {
|
||||
action("Serialized Graph")(beautify(model2.serializeDiagram(), null, 2, 80));
|
||||
}}
|
||||
>
|
||||
Serialize Graph
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//3-D) create an orphaned node
|
||||
var node3 = new DefaultNodeModel("Node 3", "rgb(0,192,255)");
|
||||
node3.addOutPort("Out");
|
||||
node3.setPosition(100, 200);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, node3, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} allowLooseLinks={false} />;
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
# Simple Usage
|
||||
|
||||
Welcome to STORM React Diagrams (SRD). SRD is a no-nonsense easy to use library for creating
|
||||
flow diagrams in the web that can ultimately represent any type of process/network/graph etc..
|
||||
|
||||
<!-- STORY -->
|
||||
|
||||
Try moving around one of the nodes or clicking and dragging the links to create new link anchors (points).
|
||||
You can also zoom the canvas using the mouse wheel / scroll gesture and drag to select multiple entities on the graph by shift + dragging the mouse.
|
||||
@@ -1,41 +0,0 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DiagramWidget,
|
||||
DefaultLinkModel
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port1.link(port2);
|
||||
(link1 as DefaultLinkModel).addLabel("Hello World!");
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
@@ -1,68 +0,0 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
const engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
// setup the diagram model
|
||||
const model = new DiagramModel();
|
||||
|
||||
// create four nodes in a way that straight links wouldn't work
|
||||
const node1 = new DefaultNodeModel("Node A", "rgb(0,192,255)");
|
||||
const port1 = node1.addPort(new DefaultPortModel(false, "out-1", "Out"));
|
||||
node1.setPosition(340, 350);
|
||||
|
||||
const node2 = new DefaultNodeModel("Node B", "rgb(255,255,0)");
|
||||
const port2 = node2.addPort(new DefaultPortModel(false, "out-1", "Out"));
|
||||
node2.setPosition(240, 80);
|
||||
const node3 = new DefaultNodeModel("Node C", "rgb(192,255,255)");
|
||||
const port3 = node3.addPort(new DefaultPortModel(true, "in-1", "In"));
|
||||
node3.setPosition(540, 180);
|
||||
const node4 = new DefaultNodeModel("Node D", "rgb(192,0,255)");
|
||||
const port4 = node4.addPort(new DefaultPortModel(true, "in-1", "In"));
|
||||
node4.setPosition(95, 185);
|
||||
const node5 = new DefaultNodeModel("Node E", "rgb(192,255,0)");
|
||||
node5.setPosition(250, 180);
|
||||
|
||||
// linking things together
|
||||
const link1 = port1.link(port4);
|
||||
const link2 = port2.link(port3);
|
||||
|
||||
// add all to the main model
|
||||
model.addAll(node1, node2, node3, node4, node5, link1, link2);
|
||||
|
||||
// load model into engine and render
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<button
|
||||
onClick={() => {
|
||||
action("Serialized Graph")(JSON.stringify(model.serializeDiagram(), null, 2));
|
||||
}}
|
||||
>
|
||||
Serialize Graph
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<DiagramWidget
|
||||
className="srd-demo-canvas"
|
||||
diagramEngine={engine}
|
||||
smartRouting={true}
|
||||
maxNumberPointsPerLink={0}
|
||||
/>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
import * as React from "react";
|
||||
import {storiesOf, addDecorator, addParameters} from "@storybook/react";
|
||||
import {setOptions} from "@storybook/addon-options";
|
||||
import {host} from "storybook-host";
|
||||
import {Helper} from "./.helpers/Helper";
|
||||
import {Toolkit} from "../src/Toolkit";
|
||||
import {themes} from '@storybook/theming';
|
||||
|
||||
addParameters({
|
||||
options: {
|
||||
theme: themes.dark,
|
||||
},
|
||||
});
|
||||
|
||||
//include the SCSS for the demo
|
||||
import "./.helpers/demo.scss";
|
||||
|
||||
setOptions({
|
||||
name: "STORM React Diagrams",
|
||||
url: "https://github.com/projectstorm/react-diagrams",
|
||||
addonPanelInRight: true
|
||||
});
|
||||
|
||||
import demo_simple from "./demo-simple";
|
||||
import demo_flow from "./demo-simple-flow";
|
||||
import demo_performance from "./demo-performance";
|
||||
import demo_locks from "./demo-locks";
|
||||
import demo_grid from "./demo-grid";
|
||||
import demo_limit_points from "./demo-limit-points";
|
||||
import demo_listeners from "./demo-listeners";
|
||||
import demo_zoom from "./demo-zoom-to-fit";
|
||||
import demo_labels from "./demo-labelled-links";
|
||||
|
||||
storiesOf("Simple Usage", module)
|
||||
.add("Simple example", demo_simple)
|
||||
.add("Simple flow example", demo_flow)
|
||||
.add("Performance demo", demo_performance)
|
||||
.add("Locked widget", demo_locks)
|
||||
.add("Canvas grid size", demo_grid)
|
||||
.add("Limiting link points", demo_limit_points)
|
||||
.add("Events and listeners", demo_listeners)
|
||||
.add("Zoom to fit", demo_zoom)
|
||||
.add("Links with labels", demo_labels);
|
||||
|
||||
import demo_adv_clone_selected from "./demo-cloning";
|
||||
import demo_adv_ser_des from "./demo-serializing";
|
||||
import demo_adv_prog from "./demo-mutate-graph";
|
||||
import demo_adv_dnd from "./demo-drag-and-drop";
|
||||
import demo_smart_routing from "./demo-smart-routing";
|
||||
|
||||
storiesOf("Advanced Techniques", module)
|
||||
.add("Clone Selected", demo_adv_clone_selected)
|
||||
.add("Serializing and de-serializing", demo_adv_ser_des)
|
||||
.add("Programatically modifying graph", demo_adv_prog)
|
||||
.add("Drag and drop", demo_adv_dnd)
|
||||
.add("Smart routing", demo_smart_routing);
|
||||
|
||||
import demo_cust_nodes from "./demo-custom-node1";
|
||||
import demo_cust_links from "./demo-custom-link1";
|
||||
|
||||
storiesOf("Custom Models", module)
|
||||
.add("Custom diamond node", demo_cust_nodes)
|
||||
.add("Custom animated links", demo_cust_links);
|
||||
|
||||
import demo_3rd_dagre from "./demo-dagre";
|
||||
|
||||
storiesOf("3rd party libraries", module)
|
||||
.add("Auto Distribute (Dagre)", demo_3rd_dagre);
|
||||
|
||||
// enable this to log mouse location when writing new puppeteer tests
|
||||
//Helper.logMousePosition()
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"../tslint.json"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": false,
|
||||
"max-classes-per-file": false,
|
||||
"no-var-requires": false
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 94 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 438 KiB After Width: | Height: | Size: 438 KiB |
|
Before Width: | Height: | Size: 313 KiB After Width: | Height: | Size: 313 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
BIN
docs/images/logo.jpg
Normal file
|
After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 354 KiB |
|
Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 113 KiB After Width: | Height: | Size: 113 KiB |
@@ -1,27 +0,0 @@
|
||||
const path = require("path");
|
||||
// jest.config.js
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
moduleFileExtensions: [
|
||||
"ts",
|
||||
"tsx",
|
||||
"js",
|
||||
"jsx",
|
||||
"json",
|
||||
"node"
|
||||
],
|
||||
transform: {
|
||||
".*test_loader.*": path.join(__dirname, "tests", "helpers", "storybook-loader.js" ),
|
||||
"^.+\\.tsx?$": "ts-jest",
|
||||
},
|
||||
moduleNameMapper:{
|
||||
"\\.(scss|css|png)$": path.join(__dirname,"tests","helpers","css-mock.js"),
|
||||
"storm-react-diagrams": path.join(__dirname, "src", "main")
|
||||
},
|
||||
roots:[
|
||||
__dirname+'/tests'
|
||||
],
|
||||
testMatch: [
|
||||
"**/*\.test\.tsx"
|
||||
]
|
||||
};
|
||||
5
lerna.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "6.0.0-beta.0"
|
||||
}
|
||||
53
package.json
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"name": "storm-react-diagrams",
|
||||
"version": "5.2.2-0",
|
||||
"name": "@projectstorm/react-diagrams",
|
||||
"version": "5.3.2",
|
||||
"author": "dylanvorster",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/projectstorm/react-diagrams.git"
|
||||
},
|
||||
"workspaces": ["packages/*"],
|
||||
"keywords": [
|
||||
"web",
|
||||
"diagram",
|
||||
@@ -16,21 +19,16 @@
|
||||
"links",
|
||||
"nodes"
|
||||
],
|
||||
"main": "./dist/main.js",
|
||||
"typings": "./dist/@types/main",
|
||||
"author": "dylanvorster",
|
||||
"scripts": {
|
||||
"build:ts": "webpack",
|
||||
"build:ts:prod": "cross-env NODE_ENV=production webpack",
|
||||
"build:sass:prod": "node-sass --output-style compressed ./src/sass/main.scss > ./dist/style.min.css",
|
||||
"storybook": "start-storybook -p 9001 -c .storybook",
|
||||
"storybook:build": "build-storybook -c .storybook -o .out",
|
||||
"storybook:github": "storybook-to-ghpages",
|
||||
"pretty": "prettier --use-tabs --write \"{src,demos,tests}/**/*.{ts,tsx}\" --print-width 120",
|
||||
"lint": "tslint -p .",
|
||||
"test:ci": "rm -rf ./dist && node ./tests/e2e/generate-e2e.js && jest --no-cache",
|
||||
"test": "jest --no-cache",
|
||||
"prepublishOnly": "yarn run build:ts:prod && yarn run build:sass:prod"
|
||||
"build": "yarn build:clean && lerna run build --stream",
|
||||
"build:prod": "yarn build:clean && lerna run build:prod --stream",
|
||||
"watch": "yarn build:clean && lerna run watch --stream",
|
||||
"publish:dev": "yarn build:prod && lerna publish --force-publish --dist-tag=next",
|
||||
"publish:prod": "yarn build:prod && lerna publish --force-publish",
|
||||
"publish:storybook": "cd packages/diagrams-demo-gallery && yarn storybook:build && ../../node_modules/.bin/storybook-to-ghpages --existing-output-dir .out",
|
||||
"build:clean": "lerna run clean --stream",
|
||||
"test:ci": "lerna run test --stream -- --runInBand --ci ",
|
||||
"pretty": "prettier --write \"packages/**/*.{ts,tsx,scss,js,jsx}\""
|
||||
},
|
||||
"peerDependencies": {
|
||||
"closest": "^0.0.1",
|
||||
@@ -41,22 +39,27 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@emotion/core": "^10.0.14",
|
||||
"@emotion/styled": "^10.0.14",
|
||||
"@storybook/addon-actions": "^5.1.9",
|
||||
"@storybook/addon-options": "^5.1.9",
|
||||
"@storybook/addon-storyshots": "^5.1.9",
|
||||
"@storybook/addons": "^5.1.9",
|
||||
"@storybook/react": "^5.1.9",
|
||||
"@storybook/storybook-deployer": "^2.8.1",
|
||||
"@storybook/theming": "^5.1.9",
|
||||
"@types/jest": "^24.0.15",
|
||||
"@types/dagre": "^0.7.42",
|
||||
"@types/jest": "^24.0.16",
|
||||
"@types/jest-environment-puppeteer": "^4.0.0",
|
||||
"@types/lodash": "^4.14.136",
|
||||
"@types/mathjs": "^6.0.1",
|
||||
"@types/node": "^12.6.8",
|
||||
"@types/promise": "^7.1.30",
|
||||
"@types/puppeteer": "^1.12.4",
|
||||
"@types/puppeteer": "^1.19.0",
|
||||
"@types/react": "^16.8.23",
|
||||
"babel-loader": "^8.0.6",
|
||||
"closest": "^0.0.1",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"cross-env": "^5.2.0",
|
||||
"css-loader": "^3.1.0",
|
||||
"dagre": "^0.8.4",
|
||||
@@ -65,20 +68,21 @@
|
||||
"glob": "^7.1.4",
|
||||
"jest": "^24.8.0",
|
||||
"jest-cli": "^24.8.0",
|
||||
"jest-puppeteer": "^4.3.0",
|
||||
"json-beautify": "^1.1.0",
|
||||
"lerna": "^3.16.4",
|
||||
"lodash": "4.*",
|
||||
"node-sass": "^4.12.0",
|
||||
"mathjs": "^6.0.3",
|
||||
"pathfinding": "^0.4.18",
|
||||
"paths-js": "^0.4.9",
|
||||
"prettier": "^1.18.2",
|
||||
"puppeteer": "^1.18.1",
|
||||
"puppeteer": "^1.19.0",
|
||||
"raf": "^3.4.1",
|
||||
"raw-loader": "^3.1.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react-syntax-highlighter": "^11.0.2",
|
||||
"react-test-renderer": "^16.8.6",
|
||||
"sass-loader": "^7.1.0",
|
||||
"source-map-loader": "^0.2.4",
|
||||
"storybook-host": "^5.1.0",
|
||||
"storybook-readme": "^5.0.5",
|
||||
@@ -88,8 +92,9 @@
|
||||
"ts-loader": "^6.0.4",
|
||||
"typescript": "^3.5.3",
|
||||
"val-loader": "^1.1.1",
|
||||
"webpack": "^4.36.1",
|
||||
"webpack": "^4.38.0",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.7.2",
|
||||
"webpack-node-externals": "^1.7.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { configure } from '@storybook/react';
|
||||
|
||||
function loadStories() {
|
||||
require('../demos/index.tsx');
|
||||
require('../index.tsx');
|
||||
// You can require as many demos as you need.
|
||||
}
|
||||
|
||||
configure(loadStories, module);
|
||||
configure(loadStories, module);
|
||||
@@ -1,14 +1,10 @@
|
||||
const path = require('path');
|
||||
module.exports = async ({config, mode}) => {
|
||||
module.exports = async ({ config, mode }) => {
|
||||
return {
|
||||
...config,
|
||||
resolve: {
|
||||
...config.resolve,
|
||||
extensions: ['.tsx', '.ts', '.js'],
|
||||
alias: {
|
||||
...config.resolve.alias,
|
||||
'storm-react-diagrams': path.join(__dirname, "..", "src", "main")
|
||||
}
|
||||
extensions: ['.tsx', '.ts', '.js']
|
||||
},
|
||||
module: {
|
||||
...config.module,
|
||||
@@ -22,9 +18,8 @@ module.exports = async ({config, mode}) => {
|
||||
'css-loader',
|
||||
{
|
||||
loader: 'postcss-loader',
|
||||
options: {config: {path: path.join(__dirname, '..')}}
|
||||
},
|
||||
'sass-loader'
|
||||
options: { config: { path: path.join(__dirname, '..') } }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -40,7 +35,7 @@ module.exports = async ({config, mode}) => {
|
||||
options: {
|
||||
transpileOnly: true
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
@@ -1,15 +1,9 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
NodeModel,
|
||||
DiagramWidget,
|
||||
BaseModel
|
||||
} from "storm-react-diagrams";
|
||||
import * as _ from "lodash";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, LinkModel, NodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { BaseModel, CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
* Tests cloning
|
||||
@@ -23,24 +17,24 @@ class CloneSelected extends React.Component<any, any> {
|
||||
cloneSelected() {
|
||||
let { engine } = this.props;
|
||||
let offset = { x: 100, y: 100 };
|
||||
let model = engine.getDiagramModel();
|
||||
let model = engine.getModel();
|
||||
|
||||
let itemMap = {};
|
||||
_.forEach(model.getSelectedItems(), (item: BaseModel<any>) => {
|
||||
_.forEach(model.getSelectedEntities(), (item: BaseModel<any>) => {
|
||||
let newItem = item.clone(itemMap);
|
||||
|
||||
// offset the nodes slightly
|
||||
if (newItem instanceof NodeModel) {
|
||||
newItem.setPosition(newItem.x + offset.x, newItem.y + offset.y);
|
||||
newItem.setPosition(newItem.getX() + offset.x, newItem.getY() + offset.y);
|
||||
model.addNode(newItem);
|
||||
} else if (newItem instanceof LinkModel) {
|
||||
// offset the link points
|
||||
newItem.getPoints().forEach(p => {
|
||||
p.updateLocation({ x: p.getX() + offset.x, y: p.getY() + offset.y });
|
||||
p.setPosition(p.getX() + offset.x, p.getY() + offset.y);
|
||||
});
|
||||
model.addLink(newItem);
|
||||
}
|
||||
newItem.selected = false;
|
||||
(newItem as BaseModel).setSelected(false);
|
||||
});
|
||||
|
||||
this.forceUpdate();
|
||||
@@ -49,8 +43,10 @@ class CloneSelected extends React.Component<any, any> {
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<button onClick={this.cloneSelected}>Clone Selected</button>}>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
<DemoWorkspaceWidget buttons={<DemoButton onClick={this.cloneSelected}>Clone Selected</DemoButton>}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
@@ -58,20 +54,19 @@ class CloneSelected extends React.Component<any, any> {
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port = node1.addOutPort("Out");
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
let port = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
let port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
@@ -81,7 +76,7 @@ export default () => {
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <CloneSelected engine={engine} model={model} />;
|
||||
@@ -1,23 +1,20 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
import createEngine, {
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget,
|
||||
LinkWidget,
|
||||
LinkProps,
|
||||
DefaultLinkWidget,
|
||||
DefaultLinkModel,
|
||||
DefaultLinkFactory
|
||||
} from "storm-react-diagrams";
|
||||
import { action } from "@storybook/addon-actions";
|
||||
import * as React from "react";
|
||||
DefaultLinkFactory,
|
||||
DefaultLinkModel
|
||||
} from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export class AdvancedLinkModel extends DefaultLinkModel {
|
||||
constructor() {
|
||||
super("advanced");
|
||||
this.width = 10;
|
||||
super({
|
||||
type: 'advanced',
|
||||
width: 10
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +51,8 @@ export class AdvancedLinkSegment extends React.Component<{ model: AdvancedLinkMo
|
||||
|
||||
let point = this.path.getPointAtLength(this.path.getTotalLength() * (this.percent / 100.0));
|
||||
|
||||
this.circle.setAttribute("cx", "" + point.x);
|
||||
this.circle.setAttribute("cy", "" + point.y);
|
||||
this.circle.setAttribute('cx', '' + point.x);
|
||||
this.circle.setAttribute('cy', '' + point.y);
|
||||
|
||||
if (this.mounted) {
|
||||
requestAnimationFrame(this.callback);
|
||||
@@ -72,10 +69,11 @@ export class AdvancedLinkSegment extends React.Component<{ model: AdvancedLinkMo
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
fill="none"
|
||||
ref={ref => {
|
||||
this.path = ref;
|
||||
}}
|
||||
strokeWidth={this.props.model.width}
|
||||
strokeWidth={this.props.model.getOptions().width}
|
||||
stroke="rgba(255,0,0,0.5)"
|
||||
d={this.props.path}
|
||||
/>
|
||||
@@ -93,15 +91,14 @@ export class AdvancedLinkSegment extends React.Component<{ model: AdvancedLinkMo
|
||||
|
||||
export class AdvancedLinkFactory extends DefaultLinkFactory {
|
||||
constructor() {
|
||||
super();
|
||||
this.type = "advanced";
|
||||
super('advanced');
|
||||
}
|
||||
|
||||
getNewInstance(initialConfig?: any): AdvancedLinkModel {
|
||||
generateModel(): AdvancedLinkModel {
|
||||
return new AdvancedLinkModel();
|
||||
}
|
||||
|
||||
generateLinkSegment(model: AdvancedLinkModel, widget: DefaultLinkWidget, selected: boolean, path: string) {
|
||||
generateLinkSegment(model: AdvancedLinkModel, selected: boolean, path: string) {
|
||||
return (
|
||||
<g>
|
||||
<AdvancedLinkSegment model={model} path={path} />
|
||||
@@ -117,29 +114,28 @@ export class AdvancedLinkFactory extends DefaultLinkFactory {
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
engine.registerLinkFactory(new AdvancedLinkFactory());
|
||||
var engine = createEngine();
|
||||
engine.getLinkFactories().registerFactory(new AdvancedLinkFactory());
|
||||
|
||||
// create some nodes
|
||||
var node1 = new DefaultNodeModel("Source", "rgb(0,192,255)");
|
||||
let port1 = node1.addPort(new AdvancedPortModel(false, "out-1", "Out thick"));
|
||||
let port2 = node1.addPort(new DefaultPortModel(false, "out-2", "Out default"));
|
||||
var node1 = new DefaultNodeModel('Source', 'rgb(0,192,255)');
|
||||
let port1 = node1.addPort(new AdvancedPortModel(false, 'out-1', 'Out thick'));
|
||||
let port2 = node1.addPort(new DefaultPortModel(false, 'out-2', 'Out default'));
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
var node2 = new DefaultNodeModel("Target", "rgb(192,255,0)");
|
||||
var port3 = node2.addPort(new AdvancedPortModel(true, "in-1", "In thick"));
|
||||
var port4 = node2.addPort(new DefaultPortModel(true, "in-2", "In default"));
|
||||
var node2 = new DefaultNodeModel('Target', 'rgb(192,255,0)');
|
||||
var port3 = node2.addPort(new AdvancedPortModel(true, 'in-1', 'In thick'));
|
||||
var port4 = node2.addPort(new DefaultPortModel(true, 'in-2', 'In default'));
|
||||
node2.setPosition(300, 100);
|
||||
|
||||
var node3 = new DefaultNodeModel("Source", "rgb(0,192,255)");
|
||||
node3.addPort(new AdvancedPortModel(false, "out-1", "Out thick"));
|
||||
node3.addPort(new DefaultPortModel(false, "out-2", "Out default"));
|
||||
var node3 = new DefaultNodeModel('Source', 'rgb(0,192,255)');
|
||||
node3.addPort(new AdvancedPortModel(false, 'out-1', 'Out thick'));
|
||||
node3.addPort(new DefaultPortModel(false, 'out-2', 'Out default'));
|
||||
node3.setPosition(100, 200);
|
||||
|
||||
var node4 = new DefaultNodeModel("Target", "rgb(192,255,0)");
|
||||
node4.addPort(new AdvancedPortModel(true, "in-1", "In thick"));
|
||||
node4.addPort(new DefaultPortModel(true, "in-2", "In default"));
|
||||
var node4 = new DefaultNodeModel('Target', 'rgb(192,255,0)');
|
||||
node4.addPort(new AdvancedPortModel(true, 'in-1', 'In thick'));
|
||||
node4.addPort(new DefaultPortModel(true, 'in-2', 'In default'));
|
||||
node4.setPosition(300, 200);
|
||||
|
||||
var model = new DiagramModel();
|
||||
@@ -150,8 +146,12 @@ export default () => {
|
||||
model.addAll(node1, node2, node3, node4);
|
||||
|
||||
// load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
engine.setModel(model);
|
||||
|
||||
// render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { DiamonNodeWidget } from './DiamondNodeWidget';
|
||||
import { DiamondNodeModel } from './DiamondNodeModel';
|
||||
import * as React from 'react';
|
||||
import { AbstractReactFactory } from '@projectstorm/react-canvas-core';
|
||||
import { DiagramEngine } from '@projectstorm/react-diagrams-core';
|
||||
|
||||
export class DiamondNodeFactory extends AbstractReactFactory<DiamondNodeModel, DiagramEngine> {
|
||||
constructor() {
|
||||
super('diamond');
|
||||
}
|
||||
|
||||
generateReactWidget(event): JSX.Element {
|
||||
return <DiamonNodeWidget engine={this.engine} size={50} node={event.model} />;
|
||||
}
|
||||
|
||||
generateModel(event) {
|
||||
return new DiamondNodeModel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { NodeModel, NodeModelGenerics, PortModelAlignment } from '@projectstorm/react-diagrams';
|
||||
import { DiamondPortModel } from './DiamondPortModel';
|
||||
|
||||
export interface DiamondNodeModelGenerics {
|
||||
PORT: DiamondPortModel;
|
||||
}
|
||||
|
||||
export class DiamondNodeModel extends NodeModel<NodeModelGenerics & DiamondNodeModelGenerics> {
|
||||
constructor() {
|
||||
super({
|
||||
type: 'diamond'
|
||||
});
|
||||
this.addPort(new DiamondPortModel(PortModelAlignment.TOP));
|
||||
this.addPort(new DiamondPortModel(PortModelAlignment.LEFT));
|
||||
this.addPort(new DiamondPortModel(PortModelAlignment.BOTTOM));
|
||||
this.addPort(new DiamondPortModel(PortModelAlignment.RIGHT));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import * as React from 'react';
|
||||
import { DiamondNodeModel } from './DiamondNodeModel';
|
||||
import { DiagramEngine, PortModelAlignment, PortWidget } from '@projectstorm/react-diagrams';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export interface DiamonNodeWidgetProps {
|
||||
node: DiamondNodeModel;
|
||||
engine: DiagramEngine;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
namespace S {
|
||||
export const Port = styled.div`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
z-index: 10;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 1);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export class DiamonNodeWidget extends React.Component<DiamonNodeWidgetProps> {
|
||||
render() {
|
||||
return (
|
||||
<div
|
||||
className={'diamond-node'}
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: this.props.size,
|
||||
height: this.props.size
|
||||
}}>
|
||||
<svg
|
||||
width={this.props.size}
|
||||
height={this.props.size}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
`
|
||||
<g id="Layer_1">
|
||||
</g>
|
||||
<g id="Layer_2">
|
||||
<polygon fill="mediumpurple" stroke="${
|
||||
this.props.node.isSelected() ? 'white' : '#000000'
|
||||
}" stroke-width="3" stroke-miterlimit="10" points="10,` +
|
||||
this.props.size / 2 +
|
||||
` ` +
|
||||
this.props.size / 2 +
|
||||
`,10 ` +
|
||||
(this.props.size - 10) +
|
||||
`,` +
|
||||
this.props.size / 2 +
|
||||
` ` +
|
||||
this.props.size / 2 +
|
||||
`,` +
|
||||
(this.props.size - 10) +
|
||||
` "/>
|
||||
</g>
|
||||
`
|
||||
}}
|
||||
/>
|
||||
<PortWidget
|
||||
style={{
|
||||
top: this.props.size / 2 - 8,
|
||||
left: -8,
|
||||
position: 'absolute'
|
||||
}}
|
||||
port={this.props.node.getPort(PortModelAlignment.LEFT)}
|
||||
engine={this.props.engine}>
|
||||
<S.Port />
|
||||
</PortWidget>
|
||||
<PortWidget
|
||||
style={{
|
||||
left: this.props.size / 2 - 8,
|
||||
top: -8,
|
||||
position: 'absolute'
|
||||
}}
|
||||
port={this.props.node.getPort(PortModelAlignment.TOP)}
|
||||
engine={this.props.engine}>
|
||||
<S.Port />
|
||||
</PortWidget>
|
||||
<PortWidget
|
||||
style={{
|
||||
left: this.props.size - 8,
|
||||
top: this.props.size / 2 - 8,
|
||||
position: 'absolute'
|
||||
}}
|
||||
port={this.props.node.getPort(PortModelAlignment.RIGHT)}
|
||||
engine={this.props.engine}>
|
||||
<S.Port />
|
||||
</PortWidget>
|
||||
<PortWidget
|
||||
style={{
|
||||
left: this.props.size / 2 - 8,
|
||||
top: this.props.size - 8,
|
||||
position: 'absolute'
|
||||
}}
|
||||
port={this.props.node.getPort(PortModelAlignment.BOTTOM)}
|
||||
engine={this.props.engine}>
|
||||
<S.Port />
|
||||
</PortWidget>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { LinkModel, PortModel, DefaultLinkModel, PortModelAlignment } from '@projectstorm/react-diagrams';
|
||||
|
||||
export class DiamondPortModel extends PortModel {
|
||||
constructor(alignment: PortModelAlignment) {
|
||||
super({
|
||||
type: 'diamond',
|
||||
name: alignment,
|
||||
alignment: alignment
|
||||
});
|
||||
}
|
||||
|
||||
createLinkModel(): LinkModel {
|
||||
return new DefaultLinkModel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { DiagramEngine, PortModel } from '@projectstorm/react-diagrams';
|
||||
import { AbstractModelFactory } from '@projectstorm/react-canvas-core';
|
||||
|
||||
export class SimplePortFactory extends AbstractModelFactory<PortModel, DiagramEngine> {
|
||||
cb: (initialConfig?: any) => PortModel;
|
||||
|
||||
constructor(type: string, cb: (initialConfig?: any) => PortModel) {
|
||||
super(type);
|
||||
this.cb = cb;
|
||||
}
|
||||
|
||||
generateModel(event): PortModel {
|
||||
return this.cb(event.initialConfig);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import createEngine, { DefaultNodeModel, DiagramModel, PortModelAlignment } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
// import the custom models
|
||||
import { DiamondNodeModel } from './DiamondNodeModel';
|
||||
import { DiamondNodeFactory } from './DiamondNodeFactory';
|
||||
import { SimplePortFactory } from './SimplePortFactory';
|
||||
import { DiamondPortModel } from './DiamondPortModel';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
// register some other factories as well
|
||||
engine
|
||||
.getPortFactories()
|
||||
.registerFactory(new SimplePortFactory('diamond', config => new DiamondPortModel(PortModelAlignment.LEFT)));
|
||||
engine.getNodeFactories().registerFactory(new DiamondNodeFactory());
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 200);
|
||||
|
||||
//3-B) create our new custom node
|
||||
var node2 = new DiamondNodeModel();
|
||||
node2.setPosition(250, 108);
|
||||
|
||||
var node3 = new DefaultNodeModel('Node 3', 'red');
|
||||
var port3 = node3.addInPort('In');
|
||||
node3.setPosition(500, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(node2.getPort(PortModelAlignment.LEFT));
|
||||
var link2 = port3.link(node2.getPort(PortModelAlignment.RIGHT));
|
||||
|
||||
var node4 = new DefaultNodeModel('Node 4', 'rgb(0,192,255)');
|
||||
var port4 = node4.addOutPort('Out');
|
||||
node4.setPosition(200, 10);
|
||||
|
||||
var link3 = port4.link(node2.getPort(PortModelAlignment.TOP));
|
||||
|
||||
var node5 = new DefaultNodeModel('Node 5', 'mediumpurple');
|
||||
var port5 = node5.addInPort('In');
|
||||
node5.setPosition(400, 300);
|
||||
|
||||
var link4 = port5.link(node2.getPort(PortModelAlignment.BOTTOM));
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, node3, link1, link2, node4, link3, link4, node5);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
129
packages/diagrams-demo-gallery/demos/demo-dagre/index.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import createEngine, {
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
DefaultPortModel,
|
||||
NodeModel,
|
||||
DagreEngine,
|
||||
DiagramEngine,
|
||||
PathFindingLinkFactory
|
||||
} from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
function createNode(name): any {
|
||||
return new DefaultNodeModel(name, 'rgb(0,192,255)');
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
|
||||
function connectNodes(nodeFrom, nodeTo, engine: DiagramEngine) {
|
||||
//just to get id-like structure
|
||||
count++;
|
||||
const portOut = nodeFrom.addPort(new DefaultPortModel(true, `${nodeFrom.name}-out-${count}`, 'Out'));
|
||||
const portTo = nodeTo.addPort(new DefaultPortModel(false, `${nodeFrom.name}-to-${count}`, 'IN'));
|
||||
return portOut.link(portTo);
|
||||
|
||||
// ################# UNCOMMENT THIS LINE FOR PATH FINDING #############################
|
||||
// return portOut.link(portTo, engine.getLinkFactories().getFactory(PathFindingLinkFactory.NAME));
|
||||
// #####################################################################################
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests auto distribution
|
||||
*/
|
||||
class DemoWidget extends React.Component<{ model: DiagramModel; engine: DiagramEngine }, any> {
|
||||
engine: DagreEngine;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.engine = new DagreEngine({
|
||||
graph: {
|
||||
rankdir: 'RL',
|
||||
ranker: 'longest-path'
|
||||
},
|
||||
includeLinks: true
|
||||
});
|
||||
}
|
||||
|
||||
autoDistribute = () => {
|
||||
this.engine.redistribute(this.props.model);
|
||||
|
||||
// only happens if pathfing is enabled (check line 25)
|
||||
this.reroute();
|
||||
this.props.engine.repaintCanvas();
|
||||
};
|
||||
|
||||
componentDidMount(): void {
|
||||
setTimeout(() => {
|
||||
this.autoDistribute();
|
||||
}, 500);
|
||||
}
|
||||
|
||||
reroute() {
|
||||
this.props.engine
|
||||
.getLinkFactories()
|
||||
.getFactory<PathFindingLinkFactory>(PathFindingLinkFactory.NAME)
|
||||
.calculateRoutingMatrix();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<DemoButton onClick={this.autoDistribute}>Re-distribute</DemoButton>}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={this.props.engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
let engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
let model = new DiagramModel();
|
||||
|
||||
//3) create a default nodes
|
||||
let nodesFrom: NodeModel[] = [];
|
||||
let nodesTo: NodeModel[] = [];
|
||||
|
||||
nodesFrom.push(createNode('from-1'));
|
||||
nodesFrom.push(createNode('from-2'));
|
||||
nodesFrom.push(createNode('from-3'));
|
||||
|
||||
nodesTo.push(createNode('to-1'));
|
||||
nodesTo.push(createNode('to-2'));
|
||||
nodesTo.push(createNode('to-3'));
|
||||
|
||||
//4) link nodes together
|
||||
let links = nodesFrom.map((node, index) => {
|
||||
return connectNodes(node, nodesTo[index], engine);
|
||||
});
|
||||
|
||||
// more links for more complicated diagram
|
||||
links.push(connectNodes(nodesFrom[0], nodesTo[1], engine));
|
||||
links.push(connectNodes(nodesTo[0], nodesFrom[1], engine));
|
||||
links.push(connectNodes(nodesFrom[1], nodesTo[2], engine));
|
||||
|
||||
// initial random position
|
||||
nodesFrom.forEach((node, index) => {
|
||||
node.setPosition(index * 70, index * 70);
|
||||
model.addNode(node);
|
||||
});
|
||||
|
||||
nodesTo.forEach((node, index) => {
|
||||
node.setPosition(index * 70, 100);
|
||||
model.addNode(node);
|
||||
});
|
||||
|
||||
links.forEach(link => {
|
||||
model.addLink(link);
|
||||
});
|
||||
|
||||
engine.setModel(model);
|
||||
|
||||
return <DemoWidget model={model} engine={engine} />;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as SRD from "storm-react-diagrams";
|
||||
import * as SRD from '@projectstorm/react-diagrams';
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
@@ -8,24 +8,22 @@ export class Application {
|
||||
protected diagramEngine: SRD.DiagramEngine;
|
||||
|
||||
constructor() {
|
||||
this.diagramEngine = new SRD.DiagramEngine();
|
||||
this.diagramEngine.installDefaultFactories();
|
||||
|
||||
this.diagramEngine = SRD.default();
|
||||
this.newModel();
|
||||
}
|
||||
|
||||
public newModel() {
|
||||
this.activeModel = new SRD.DiagramModel();
|
||||
this.diagramEngine.setDiagramModel(this.activeModel);
|
||||
this.diagramEngine.setModel(this.activeModel);
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new SRD.DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port = node1.addOutPort("Out");
|
||||
var node1 = new SRD.DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
let port = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new SRD.DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
var node2 = new SRD.DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
let port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
@@ -0,0 +1,94 @@
|
||||
import * as React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { TrayWidget } from './TrayWidget';
|
||||
import { Application } from '../Application';
|
||||
import { TrayItemWidget } from './TrayItemWidget';
|
||||
import { DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../../helpers/DemoCanvasWidget';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export interface BodyWidgetProps {
|
||||
app: Application;
|
||||
}
|
||||
|
||||
namespace S {
|
||||
export const Body = styled.div`
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100%;
|
||||
`;
|
||||
|
||||
export const Header = styled.div`
|
||||
display: flex;
|
||||
background: rgb(30, 30, 30);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
padding: 10px;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
export const Content = styled.div`
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
export const Layer = styled.div`
|
||||
position: relative;
|
||||
flex-grow: 1;
|
||||
`;
|
||||
}
|
||||
|
||||
export class BodyWidget extends React.Component<BodyWidgetProps> {
|
||||
render() {
|
||||
return (
|
||||
<S.Body>
|
||||
<S.Header>
|
||||
<div className="title">Storm React Diagrams - DnD demo</div>
|
||||
</S.Header>
|
||||
<S.Content>
|
||||
<TrayWidget>
|
||||
<TrayItemWidget model={{ type: 'in' }} name="In Node" color="rgb(192,255,0)" />
|
||||
<TrayItemWidget model={{ type: 'out' }} name="Out Node" color="rgb(0,192,255)" />
|
||||
</TrayWidget>
|
||||
<S.Layer
|
||||
onDrop={event => {
|
||||
var data = JSON.parse(event.dataTransfer.getData('storm-diagram-node'));
|
||||
var nodesCount = _.keys(
|
||||
this.props.app
|
||||
.getDiagramEngine()
|
||||
.getModel()
|
||||
.getNodes()
|
||||
).length;
|
||||
|
||||
var node: DefaultNodeModel = null;
|
||||
if (data.type === 'in') {
|
||||
node = new DefaultNodeModel('Node ' + (nodesCount + 1), 'rgb(192,255,0)');
|
||||
node.addInPort('In');
|
||||
} else {
|
||||
node = new DefaultNodeModel('Node ' + (nodesCount + 1), 'rgb(0,192,255)');
|
||||
node.addOutPort('Out');
|
||||
}
|
||||
var point = this.props.app.getDiagramEngine().getRelativeMousePoint(event);
|
||||
node.setPosition(point);
|
||||
this.props.app
|
||||
.getDiagramEngine()
|
||||
.getModel()
|
||||
.addNode(node);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
onDragOver={event => {
|
||||
event.preventDefault();
|
||||
}}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={this.props.app.getDiagramEngine()} />
|
||||
</DemoCanvasWidget>
|
||||
</S.Layer>
|
||||
</S.Content>
|
||||
</S.Body>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export interface TrayItemWidgetProps {
|
||||
model: any;
|
||||
color?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
namespace S {
|
||||
export const Tray = styled.div<{ color: string }>`
|
||||
color: white;
|
||||
font-family: Helvetica, Arial;
|
||||
padding: 5px;
|
||||
margin: 0px 10px;
|
||||
border: solid 1px ${p => p.color};
|
||||
border-radius: 5px;
|
||||
margin-bottom: 2px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
}
|
||||
|
||||
export class TrayItemWidget extends React.Component<TrayItemWidgetProps> {
|
||||
render() {
|
||||
return (
|
||||
<S.Tray
|
||||
color={this.props.color}
|
||||
draggable={true}
|
||||
onDragStart={event => {
|
||||
event.dataTransfer.setData('storm-diagram-node', JSON.stringify(this.props.model));
|
||||
}}
|
||||
className="tray-item">
|
||||
{this.props.name}
|
||||
</S.Tray>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
namespace S {
|
||||
export const Tray = styled.div`
|
||||
min-width: 200px;
|
||||
background: rgb(20, 20, 20);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
}
|
||||
|
||||
export class TrayWidget extends React.Component {
|
||||
render() {
|
||||
return <S.Tray>{this.props.children}</S.Tray>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { BodyWidget } from './components/BodyWidget';
|
||||
import { Application } from './Application';
|
||||
|
||||
export default () => {
|
||||
var app = new Application();
|
||||
return <BodyWidget app={app} />;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, DiagramEngine } from '@projectstorm/react-diagrams';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
class CloneSelected extends React.Component<{ model: DiagramModel; engine: DiagramEngine }, any> {
|
||||
addPorts = () => {
|
||||
const nodes: DefaultNodeModel[] = _.values(this.props.model.getNodes()) as DefaultNodeModel[];
|
||||
for (let node of nodes) {
|
||||
if (node.getOptions().name === 'Node 2') {
|
||||
node.addInPort(`in-${node.getInPorts().length + 1}`, false);
|
||||
} else {
|
||||
node.addOutPort(`out-${node.getOutPorts().length + 1}`, false);
|
||||
}
|
||||
}
|
||||
this.props.engine.repaintCanvas();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<DemoButton onClick={this.addPorts}>Add more ports</DemoButton>}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <CloneSelected engine={engine} model={model} />;
|
||||
};
|
||||
42
packages/diagrams-demo-gallery/demos/demo-grid/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
* Tests the grid size
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
model.setGridSize(50);
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
let port = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
let port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, DefaultLinkModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
const engine = createEngine();
|
||||
|
||||
// setup the diagram model
|
||||
const model = new DiagramModel();
|
||||
|
||||
// create four nodes
|
||||
const node1 = new DefaultNodeModel('Node A', 'rgb(0,192,255)');
|
||||
const port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
const node2 = new DefaultNodeModel('Node B', 'rgb(255,255,0)');
|
||||
const port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 50);
|
||||
|
||||
const node3 = new DefaultNodeModel('Node C (no label)', 'rgb(192,255,255)');
|
||||
const port3 = node3.addInPort('In');
|
||||
node3.setPosition(450, 180);
|
||||
|
||||
const node4 = new DefaultNodeModel('Node D', 'rgb(192,0,255)');
|
||||
const port4 = node4.addInPort('In');
|
||||
node4.setPosition(300, 250);
|
||||
|
||||
// link node A and B together and give it a label
|
||||
const link1 = port1.link(port2);
|
||||
(link1 as DefaultLinkModel).addLabel('Custom label 1');
|
||||
(link1 as DefaultLinkModel).addLabel('Custom label 2');
|
||||
|
||||
// no label for A and C, just a link
|
||||
const link2 = port1.link(port3);
|
||||
|
||||
// also a label for A and D
|
||||
const link3 = port1.link(port4);
|
||||
(link3 as DefaultLinkModel).addLabel('Emoji label: 🎉');
|
||||
|
||||
// add all to the main model
|
||||
model.addAll(node1, node2, node3, node4, link1, link2, link3);
|
||||
|
||||
// load model into engine and render
|
||||
engine.setModel(model);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<DemoButton
|
||||
onClick={() => {
|
||||
action('Serialized Graph')(JSON.stringify(model.serializeDiagram(), null, 2));
|
||||
}}>
|
||||
Serialize Graph
|
||||
</DemoButton>
|
||||
}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import * as React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
* Shows some of the events triggered when elements are selected
|
||||
*/
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
// sample for link with simple line
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(255,99,66)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 40);
|
||||
|
||||
var node3 = new DefaultNodeModel('Node 3', 'rgb(128,99,255)');
|
||||
var port3 = node3.addInPort('In');
|
||||
node3.setPosition(300, 160);
|
||||
|
||||
//link the nodes
|
||||
let link1 = port1.link(port2);
|
||||
let link2 = port1.link(port3);
|
||||
|
||||
// add all the models
|
||||
let models = model.addAll(node1, node2, node3, link1, link2);
|
||||
|
||||
// add a selection listener to each
|
||||
models.forEach(item => {
|
||||
item.registerListener({
|
||||
eventDidFire: action('eventDidFired')
|
||||
});
|
||||
});
|
||||
|
||||
engine.setModel(model);
|
||||
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
60
packages/diagrams-demo-gallery/demos/demo-locks/index.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import * as React from 'react';
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
*
|
||||
* Shows how you can lock down the system so that the entire scene cant be interacted with.
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
// sample for link with simple line (no additional points)
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
let link1 = port1.link(port2);
|
||||
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
// sample for link with complex line (additional points)
|
||||
var node3 = new DefaultNodeModel('Node 3', 'rgb(0,192,255)');
|
||||
var port3 = node3.addOutPort('Out');
|
||||
node3.setPosition(100, 250);
|
||||
|
||||
var node4 = new DefaultNodeModel('Node 4', 'rgb(192,255,0)');
|
||||
var port4 = node4.addInPort('In');
|
||||
node4.setPosition(400, 250);
|
||||
|
||||
var link2 = port3.link(port4);
|
||||
|
||||
link2.point(350, 225);
|
||||
link2.point(200, 225);
|
||||
|
||||
model.addAll(node3, node4, link2);
|
||||
|
||||
engine.setModel(model);
|
||||
|
||||
//!========================================= <<<<<<<
|
||||
|
||||
model.setLocked(true);
|
||||
|
||||
//!========================================= <<<<<<<
|
||||
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, NodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import * as _ from 'lodash';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
* Tests the grid size
|
||||
*/
|
||||
class NodeDelayedPosition extends React.Component<any, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.updatePosition = this.updatePosition.bind(this);
|
||||
this.updatePositionViaSerialize = this.updatePositionViaSerialize.bind(this);
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
const { engine } = this.props;
|
||||
let model = engine.getModel();
|
||||
const nodes = model.getNodes();
|
||||
let node = nodes[Object.keys(nodes)[0]];
|
||||
node.setPosition(node.getX() + 30, node.getY() + 30);
|
||||
engine.repaintCanvas();
|
||||
}
|
||||
|
||||
updatePositionViaSerialize() {
|
||||
let { engine } = this.props;
|
||||
let model = engine.getModel();
|
||||
let str = JSON.stringify(model.serialize());
|
||||
let model2 = new DiagramModel();
|
||||
let obj: ReturnType<DiagramModel['serialize']> = JSON.parse(str);
|
||||
let node: ReturnType<NodeModel['serialize']> = _.values(obj.layers[1].models)[0] as any;
|
||||
node.x += 30;
|
||||
node.y += 30;
|
||||
|
||||
model2.deserializeModel(obj, engine);
|
||||
engine.setModel(model2);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={[
|
||||
<DemoButton key={1} onClick={this.updatePosition}>
|
||||
Update position
|
||||
</DemoButton>,
|
||||
<DemoButton key={2} onClick={this.updatePositionViaSerialize}>
|
||||
Update position via serialize
|
||||
</DemoButton>
|
||||
]}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <NodeDelayedPosition engine={engine} model={model} />;
|
||||
};
|
||||
@@ -1,5 +1,7 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -10,8 +12,7 @@ import * as React from "react";
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
@@ -23,21 +24,25 @@ export default () => {
|
||||
}
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
|
||||
function generateNodes(model: DiagramModel, offsetX: number, offsetY: number) {
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100 + offsetX, 100 + offsetY);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(200 + offsetX, 100 + offsetY);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
@@ -0,0 +1,60 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import * as beautify from 'json-beautify';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//!------------- SERIALIZING ------------------
|
||||
|
||||
var str = JSON.stringify(model.serialize());
|
||||
|
||||
//!------------- DESERIALIZING ----------------
|
||||
|
||||
var model2 = new DiagramModel();
|
||||
model2.deserializeModel(JSON.parse(str), engine);
|
||||
engine.setModel(model2);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<DemoButton
|
||||
onClick={() => {
|
||||
action('Serialized Graph')(beautify(model2.serialize(), null, 2, 80));
|
||||
}}>
|
||||
Serialize Graph
|
||||
</DemoButton>
|
||||
}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, DefaultDiagramState } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
// ############################################ MAGIC HAPPENS HERE
|
||||
const state = engine.getStateMachine().getCurrentState();
|
||||
if (state instanceof DefaultDiagramState) {
|
||||
state.dragNewLink.config.allowLooseLinks = false;
|
||||
}
|
||||
// ############################################ MAGIC HAPPENS HERE
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = port1.link(port2);
|
||||
|
||||
//3-D) create an orphaned node
|
||||
var node3 = new DefaultNodeModel('Node 3', 'rgb(0,192,255)');
|
||||
node3.addOutPort('Out');
|
||||
node3.setPosition(100, 200);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, node3, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
40
packages/diagrams-demo-gallery/demos/demo-simple/index.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import createEngine, { DiagramModel, DefaultNodeModel, DefaultLinkModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
let port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
let port2 = node2.addInPort('In');
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port1.link<DefaultLinkModel>(port2);
|
||||
link1.getOptions().testName = 'Test';
|
||||
link1.addLabel('Hello World!');
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,72 @@
|
||||
import createEngine, {
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
DefaultPortModel,
|
||||
PathFindingLinkFactory,
|
||||
DefaultLabelModel
|
||||
} from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { DemoButton, DemoWorkspaceWidget } from '../helpers/DemoWorkspaceWidget';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
export default () => {
|
||||
// setup the diagram engine
|
||||
const engine = createEngine();
|
||||
|
||||
// setup the diagram model
|
||||
const model = new DiagramModel();
|
||||
|
||||
// create four nodes in a way that straight links wouldn't work
|
||||
const node1 = new DefaultNodeModel('Node A', 'rgb(0,192,255)');
|
||||
const port1 = node1.addPort(new DefaultPortModel(false, 'out-1', 'Out'));
|
||||
node1.setPosition(340, 350);
|
||||
|
||||
const node2 = new DefaultNodeModel('Node B', 'rgb(255,255,0)');
|
||||
const port2 = node2.addPort(new DefaultPortModel(false, 'out-1', 'Out'));
|
||||
node2.setPosition(240, 80);
|
||||
const node3 = new DefaultNodeModel('Node C', 'rgb(192,255,255)');
|
||||
const port3 = node3.addPort(new DefaultPortModel(true, 'in-1', 'In'));
|
||||
node3.setPosition(540, 180);
|
||||
const node4 = new DefaultNodeModel('Node D', 'rgb(192,0,255)');
|
||||
const port4 = node4.addPort(new DefaultPortModel(true, 'in-1', 'In'));
|
||||
node4.setPosition(95, 185);
|
||||
const node5 = new DefaultNodeModel('Node E', 'rgb(192,255,0)');
|
||||
node5.setPosition(250, 180);
|
||||
|
||||
const pathfinding = engine.getLinkFactories().getFactory<PathFindingLinkFactory>(PathFindingLinkFactory.NAME);
|
||||
|
||||
// linking things together (specifically using the pathfinding link)
|
||||
const link1 = port1.link(port4, pathfinding);
|
||||
const link2 = port2.link(port3, pathfinding);
|
||||
|
||||
link1.addLabel(
|
||||
new DefaultLabelModel({
|
||||
label: 'I am a label!',
|
||||
offsetY: 20
|
||||
})
|
||||
);
|
||||
|
||||
// add all to the main model
|
||||
model.addAll(node1, node2, node3, node4, node5, link1, link2);
|
||||
|
||||
// load model into engine and render
|
||||
engine.setModel(model);
|
||||
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={
|
||||
<DemoButton
|
||||
onClick={() => {
|
||||
action('Serialized Graph')(JSON.stringify(model.serialize(), null, 2));
|
||||
}}>
|
||||
Serialize Graph
|
||||
</DemoButton>
|
||||
}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
@@ -1,13 +1,8 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
import createEngine, { DiagramModel, DefaultNodeModel } from '@projectstorm/react-diagrams';
|
||||
import * as React from 'react';
|
||||
import { DemoWorkspaceWidget, DemoButton } from '../helpers/DemoWorkspaceWidget';
|
||||
import { CanvasWidget } from '@projectstorm/react-canvas-core';
|
||||
import { DemoCanvasWidget } from '../helpers/DemoCanvasWidget';
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -17,8 +12,7 @@ import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
var engine = createEngine();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
@@ -30,25 +24,27 @@ export default () => {
|
||||
}
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<button onClick={() => engine.zoomToFit()}>Zoom to fit</button>}>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
<DemoWorkspaceWidget buttons={<DemoButton onClick={() => engine.zoomToFit()}>Zoom to fit</DemoButton>}>
|
||||
<DemoCanvasWidget>
|
||||
<CanvasWidget engine={engine} />
|
||||
</DemoCanvasWidget>
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
|
||||
function generateNodes(model: DiagramModel, offsetX: number, offsetY: number) {
|
||||
//3-A) create a default node
|
||||
var node1 = new DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
var port1 = node1.addOutPort("Out");
|
||||
var node1 = new DefaultNodeModel('Node 1', 'rgb(0,192,255)');
|
||||
var port1 = node1.addOutPort('Out');
|
||||
node1.setPosition(100 + offsetX, 100 + offsetY);
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
var port2 = node2.addInPort("In");
|
||||
var node2 = new DefaultNodeModel('Node 2', 'rgb(192,255,0)');
|
||||
var port2 = node2.addInPort('In');
|
||||
node2.setPosition(200 + offsetX, 100 + offsetY);
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
@@ -0,0 +1,58 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export interface DemoCanvasWidgetProps {
|
||||
color?: string;
|
||||
background?: string;
|
||||
}
|
||||
|
||||
namespace S {
|
||||
export const Container = styled.div<{ color: string; background: string }>`
|
||||
height: 100%;
|
||||
background-color: rgb(60, 60, 60) !important;
|
||||
background-size: 50px 50px;
|
||||
display: flex;
|
||||
|
||||
> * {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
background-image: linear-gradient(
|
||||
0deg,
|
||||
transparent 24%,
|
||||
${p => p.color} 25%,
|
||||
${p => p.color} 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
${p => p.color} 75%,
|
||||
${p => p.color} 76%,
|
||||
transparent 77%,
|
||||
transparent
|
||||
),
|
||||
linear-gradient(
|
||||
90deg,
|
||||
transparent 24%,
|
||||
${p => p.color} 25%,
|
||||
${p => p.color} 26%,
|
||||
transparent 27%,
|
||||
transparent 74%,
|
||||
${p => p.color} 75%,
|
||||
${p => p.color} 76%,
|
||||
transparent 77%,
|
||||
transparent
|
||||
);
|
||||
`;
|
||||
}
|
||||
|
||||
export class DemoCanvasWidget extends React.Component<DemoCanvasWidgetProps> {
|
||||
render() {
|
||||
return (
|
||||
<S.Container
|
||||
background={this.props.background || 'rgb(60, 60, 60)'}
|
||||
color={this.props.color || 'rgba(255,255,255, 0.05)'}>
|
||||
{this.props.children}
|
||||
</S.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import * as React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
export interface DemoWorkspaceWidgetProps {
|
||||
buttons?: any;
|
||||
}
|
||||
|
||||
namespace S {
|
||||
export const Toolbar = styled.div`
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
export const Content = styled.div`
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
`;
|
||||
|
||||
export const Container = styled.div`
|
||||
background: black;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
border-radius: 5px;
|
||||
overflow: hidden;
|
||||
`;
|
||||
}
|
||||
|
||||
export const DemoButton = styled.button`
|
||||
background: rgb(60, 60, 60);
|
||||
font-size: 14px;
|
||||
padding: 5px 10px;
|
||||
border: none;
|
||||
color: white;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
margin: 2px;
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover {
|
||||
background: rgb(0, 192, 255);
|
||||
}
|
||||
`;
|
||||
|
||||
export class DemoWorkspaceWidget extends React.Component<DemoWorkspaceWidgetProps> {
|
||||
render() {
|
||||
return (
|
||||
<S.Container>
|
||||
<S.Toolbar>{this.props.buttons}</S.Toolbar>
|
||||
<S.Content>{this.props.children}</S.Content>
|
||||
</S.Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
23
packages/diagrams-demo-gallery/demos/helpers/Helper.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export class Helper {
|
||||
/**
|
||||
* Logs the mouse position in the console, but overlays a div that consumes all events
|
||||
* since the actual story book stories are rendered as an iFrame.
|
||||
*/
|
||||
static logMousePosition() {
|
||||
let element = window.parent.document.createElement('mouse-position');
|
||||
element.style.position = 'absolute';
|
||||
element.style.top = '0px';
|
||||
element.style.left = '0px';
|
||||
element.style.bottom = '0px';
|
||||
element.style.right = '0px';
|
||||
element.style.zIndex = '10';
|
||||
window.parent.document.body.appendChild(element);
|
||||
|
||||
window.parent.window.addEventListener('mousemove', event => {
|
||||
console.clear();
|
||||
console.log(event.clientX, event.clientY);
|
||||
});
|
||||
}
|
||||
}
|
||||
7
packages/diagrams-demo-gallery/demos/helpers/index.css
Normal file
@@ -0,0 +1,7 @@
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
71
packages/diagrams-demo-gallery/index.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import * as React from 'react';
|
||||
import { storiesOf, addParameters, addDecorator } from '@storybook/react';
|
||||
import { setOptions } from '@storybook/addon-options';
|
||||
import { themes } from '@storybook/theming';
|
||||
import './demos/helpers/index.css';
|
||||
import { Toolkit } from '@projectstorm/react-canvas-core';
|
||||
|
||||
Toolkit.TESTING = true;
|
||||
|
||||
addParameters({
|
||||
options: {
|
||||
theme: themes.dark
|
||||
}
|
||||
});
|
||||
|
||||
setOptions({
|
||||
name: 'STORM React Diagrams',
|
||||
url: 'https://github.com/projectstorm/react-diagrams',
|
||||
addonPanelInRight: true
|
||||
});
|
||||
|
||||
addDecorator(fn => {
|
||||
Toolkit.TESTING_UID = 0;
|
||||
return fn();
|
||||
});
|
||||
|
||||
import demo_simple from './demos/demo-simple';
|
||||
import demo_flow from './demos/demo-simple-flow';
|
||||
import demo_performance from './demos/demo-performance';
|
||||
import demo_locks from './demos/demo-locks';
|
||||
import demo_grid from './demos/demo-grid';
|
||||
import demo_listeners from './demos/demo-listeners';
|
||||
import demo_zoom from './demos/demo-zoom-to-fit';
|
||||
import demo_labels from './demos/demo-labelled-links';
|
||||
import demo_dynamic_ports from './demos/demo-dynamic-ports';
|
||||
|
||||
storiesOf('Simple Usage', module)
|
||||
.add('Simple example', demo_simple)
|
||||
.add('Simple flow example', demo_flow)
|
||||
.add('Performance demo', demo_performance)
|
||||
.add('Locked widget', demo_locks)
|
||||
.add('Canvas grid size', demo_grid)
|
||||
.add('Events and listeners', demo_listeners)
|
||||
.add('Zoom to fit', demo_zoom)
|
||||
.add('Dynamic ports', demo_dynamic_ports)
|
||||
.add('Links with labels', demo_labels);
|
||||
|
||||
import demo_adv_clone_selected from './demos/demo-cloning';
|
||||
import demo_adv_ser_des from './demos/demo-serializing';
|
||||
import demo_adv_prog from './demos/demo-mutate-graph';
|
||||
import demo_adv_dnd from './demos/demo-drag-and-drop';
|
||||
import demo_smart_routing from './demos/demo-smart-routing';
|
||||
|
||||
storiesOf('Advanced Techniques', module)
|
||||
.add('Clone Selected', demo_adv_clone_selected)
|
||||
.add('Serializing and de-serializing', demo_adv_ser_des)
|
||||
.add('Programatically modifying graph', demo_adv_prog)
|
||||
.add('Drag and drop', demo_adv_dnd)
|
||||
.add('Smart routing', demo_smart_routing);
|
||||
|
||||
import demo_cust_nodes from './demos/demo-custom-node1';
|
||||
import demo_cust_links from './demos/demo-custom-link1';
|
||||
|
||||
storiesOf('Custom Models', module)
|
||||
.add('Custom diamond node', demo_cust_nodes)
|
||||
.add('Custom animated links', demo_cust_links);
|
||||
|
||||
import demo_3rd_dagre from './demos/demo-dagre';
|
||||
import { Toolkit } from '@projectstorm/react-canvas-core';
|
||||
|
||||
storiesOf('3rd party libraries', module).add('Auto Distribute (Dagre)', demo_3rd_dagre);
|
||||
7
packages/diagrams-demo-gallery/jest-puppeteer.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
launch: {
|
||||
dumpio: true,
|
||||
headless: process.env.CI === 'true'
|
||||
},
|
||||
browserContext: 'default'
|
||||
};
|
||||
9
packages/diagrams-demo-gallery/jest.config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const path = require('path');
|
||||
module.exports = {
|
||||
preset: 'jest-puppeteer',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': 'ts-jest'
|
||||
},
|
||||
roots: [path.join(__dirname, 'tests-e2e')],
|
||||
testMatch: ['**/*.test.{ts,tsx}']
|
||||
};
|
||||
29
packages/diagrams-demo-gallery/package.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@projectstorm/react-diagrams-gallery",
|
||||
"version": "6.0.0-beta.0",
|
||||
"author": "dylanvorster",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/projectstorm/react-diagrams.git"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "../../node_modules/.bin/start-storybook",
|
||||
"storybook:build": "../../node_modules/.bin/build-storybook -c .storybook -o .out",
|
||||
"github": "../../node_modules/.bin/storybook-to-ghpages",
|
||||
"test:run": "../../node_modules/.bin/jest --no-cache",
|
||||
"test": "yarn storybook:build && yarn test:run"
|
||||
},
|
||||
"keywords": [
|
||||
"web",
|
||||
"diagram",
|
||||
"diagrams",
|
||||
"react",
|
||||
"typescript",
|
||||
"flowchart",
|
||||
"simple",
|
||||
"links",
|
||||
"nodes"
|
||||
]
|
||||
}
|
||||
28
packages/diagrams-demo-gallery/tests-e2e/helpers/E2EBase.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { ElementHandle, FrameBase } from 'puppeteer';
|
||||
|
||||
export abstract class E2EBase {
|
||||
name: string;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
async getSelector(): Promise<FrameBase> {
|
||||
return page as FrameBase;
|
||||
}
|
||||
|
||||
async getElement(): Promise<ElementHandle> {
|
||||
if (!(await this.getSelector())) {
|
||||
return null;
|
||||
}
|
||||
return (await this.getSelector()).$(this.selector());
|
||||
}
|
||||
|
||||
async waitForElement(): Promise<ElementHandle | null> {
|
||||
return (await this.getSelector()).waitForSelector(this.selector(), {
|
||||
timeout: 1000
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract selector(): string;
|
||||
}
|
||||
27
packages/diagrams-demo-gallery/tests-e2e/helpers/E2ELink.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { E2EBase } from './E2EBase';
|
||||
|
||||
export class E2ELink extends E2EBase {
|
||||
isID: boolean;
|
||||
|
||||
async select(): Promise<any> {
|
||||
const point = await page.evaluate(id => {
|
||||
const path = document.querySelector(id) as SVGPathElement;
|
||||
const point = path.getPointAtLength(path.getTotalLength() / 2);
|
||||
return {
|
||||
x: point.x,
|
||||
y: point.y
|
||||
};
|
||||
}, this.selector());
|
||||
await page.keyboard.down('Shift');
|
||||
await page.mouse.move(point.x, point.y);
|
||||
await page.mouse.down();
|
||||
await page.keyboard.up('Shift');
|
||||
}
|
||||
|
||||
protected selector(): string {
|
||||
if (this.isID) {
|
||||
return `[data-linkid="${this.name}"] path`;
|
||||
}
|
||||
return `[data-default-link-test="${this.name}"] path`;
|
||||
}
|
||||
}
|
||||
12
packages/diagrams-demo-gallery/tests-e2e/helpers/E2ENode.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { E2EBase } from './E2EBase';
|
||||
import { E2EPort } from './E2EPort';
|
||||
|
||||
export class E2ENode extends E2EBase {
|
||||
async port(id: string): Promise<E2EPort> {
|
||||
return new E2EPort(id, this);
|
||||
}
|
||||
|
||||
selector(): string {
|
||||
return `[data-default-node-name="${this.name}"]`;
|
||||
}
|
||||
}
|
||||
83
packages/diagrams-demo-gallery/tests-e2e/helpers/E2EPort.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import * as _ from 'lodash';
|
||||
import { FrameBase } from 'puppeteer';
|
||||
import { E2EBase } from './E2EBase';
|
||||
import { E2ENode } from './E2ENode';
|
||||
import { E2ELink } from './E2ELink';
|
||||
|
||||
export class E2EPort extends E2EBase {
|
||||
parent: E2ENode;
|
||||
|
||||
constructor(name: string, parent: E2ENode) {
|
||||
super(name);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
async getLinks(): Promise<E2ELink[]> {
|
||||
const attribute = await page.evaluate(id => {
|
||||
return document.querySelector(id).getAttribute('data-links');
|
||||
}, this.selector());
|
||||
if (attribute.trim() === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.map(attribute.split(','), id => {
|
||||
const e = new E2ELink(id);
|
||||
e.isID = true;
|
||||
return e;
|
||||
});
|
||||
}
|
||||
|
||||
async link(port: E2EPort): Promise<E2ELink> {
|
||||
let currentLinks = _.map(await this.getLinks(), 'name');
|
||||
|
||||
let bounds = await (await this.getElement()).boundingBox();
|
||||
|
||||
// click on this port
|
||||
page.mouse.move(bounds.x, bounds.y);
|
||||
page.mouse.down();
|
||||
//
|
||||
let bounds2 = await (await port.getElement()).boundingBox();
|
||||
|
||||
// drag to other port
|
||||
page.mouse.move(bounds2.x, bounds2.y);
|
||||
page.mouse.up();
|
||||
|
||||
let newLinks = _.map(await this.getLinks(), 'name');
|
||||
|
||||
const s = new E2ELink(_.difference(newLinks, currentLinks)[0]);
|
||||
s.isID = true;
|
||||
return s;
|
||||
}
|
||||
|
||||
async linkToPoint(x: number, y: number): Promise<E2ELink> {
|
||||
let currentLinks = _.map(await this.getLinks(), 'id');
|
||||
|
||||
let bounds = await (await this.getElement()).boundingBox();
|
||||
|
||||
// click on this port
|
||||
page.mouse.move(bounds.x, bounds.y);
|
||||
page.mouse.down();
|
||||
|
||||
// drag to point
|
||||
page.mouse.move(x, y);
|
||||
page.mouse.up();
|
||||
|
||||
let newLinks = _.map(await this.getLinks(), 'id');
|
||||
|
||||
const link = _.difference(newLinks, currentLinks)[0];
|
||||
if (!link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the parent to get the link
|
||||
return new E2ELink(link);
|
||||
}
|
||||
|
||||
async getSelector(): Promise<FrameBase> {
|
||||
return (await this.parent.getElement()) as any;
|
||||
}
|
||||
|
||||
protected selector(): string {
|
||||
return `${this.parent.selector()} .port[data-name="${this.name}"]`;
|
||||
}
|
||||
}
|
||||
33
packages/diagrams-demo-gallery/tests-e2e/simple-flow.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'jest';
|
||||
import { E2ENode } from './helpers/E2ENode';
|
||||
|
||||
describe('simple flow test', () => {
|
||||
beforeEach(async () => {
|
||||
await page.goto(`file://${__dirname}/../.out/iframe.html?path=/story/simple-usage--simple-flow-example`);
|
||||
});
|
||||
|
||||
it('drag link to port adds a link', async () => {
|
||||
// create a new link
|
||||
let node1 = new E2ENode('Node 3');
|
||||
let node2 = new E2ENode('Node 2');
|
||||
|
||||
let port1 = await node1.port('Out');
|
||||
let port2 = await node2.port('In');
|
||||
|
||||
let newlink = await port1.link(port2);
|
||||
await expect(await newlink.waitForElement()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('drag link to node does not add a link', async () => {
|
||||
// create a new link
|
||||
let node1 = new E2ENode('Node 3');
|
||||
let node2 = new E2ENode('Node 2');
|
||||
|
||||
let port1 = await node1.port('Out');
|
||||
|
||||
let node2Bounds = await (await node2.waitForElement()).boundingBox();
|
||||
let newlink = await port1.linkToPoint(node2Bounds.x, node2Bounds.y);
|
||||
|
||||
await expect(newlink).toBeFalsy();
|
||||
});
|
||||
});
|
||||
31
packages/diagrams-demo-gallery/tests-e2e/simple.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'jest';
|
||||
import { E2ELink } from './helpers/E2ELink';
|
||||
import { E2ENode } from './helpers/E2ENode';
|
||||
|
||||
describe('simple test', () => {
|
||||
beforeAll(async () => {
|
||||
await page.goto(`file://${__dirname}/../.out/iframe.html?path=/story/simple-usage--simple-example`);
|
||||
});
|
||||
|
||||
it('should delete a link and create a new one', async () => {
|
||||
// get the existing link
|
||||
let link = new E2ELink('Test');
|
||||
await expect(await link.waitForElement()).toBeTruthy();
|
||||
|
||||
// remove it
|
||||
await link.select();
|
||||
await page.keyboard.press('Delete');
|
||||
|
||||
await expect(await link.getElement()).toBeFalsy();
|
||||
|
||||
// create a new link
|
||||
let node1 = new E2ENode('Node 1');
|
||||
let node2 = new E2ENode('Node 2');
|
||||
|
||||
let port1 = await node1.port('Out');
|
||||
let port2 = await node2.port('In');
|
||||
|
||||
let newlink = await port1.link(port2);
|
||||
await expect(await newlink.waitForElement()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
6
packages/diagrams-demo-gallery/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"include": [
|
||||
"./demos"
|
||||
]
|
||||
}
|
||||