Compare commits
409 Commits
2.1.4
...
react_canv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c730a9fd1 | ||
|
|
a086bc785e | ||
|
|
a7b6012a50 | ||
|
|
4117af8a33 | ||
|
|
eb7f0642a5 | ||
|
|
a8c73115ac | ||
|
|
404e12c4e8 | ||
|
|
aa6d1c336c | ||
|
|
204e05a2a1 | ||
|
|
d12220baa0 | ||
|
|
91c1ee0169 | ||
|
|
4806805037 | ||
|
|
22f4062f56 | ||
|
|
32a3c33916 | ||
|
|
75ef02dd4d | ||
|
|
665c8b3443 | ||
|
|
ccf425676f | ||
|
|
1ff3abf3ef | ||
|
|
0b1dab0de6 | ||
|
|
0988e625b1 | ||
|
|
dbaf03662f | ||
|
|
55f62587bd | ||
|
|
98bcd60396 | ||
|
|
8467d8e7ca | ||
|
|
40b4e14f15 | ||
|
|
7a78aaa9fd | ||
|
|
47214df76b | ||
|
|
cc40c398b7 | ||
|
|
188f63979b | ||
|
|
468bcea8b2 | ||
|
|
54b9feb62e | ||
|
|
9f397b1453 | ||
|
|
445702dd43 | ||
|
|
bb6a6227e2 | ||
|
|
afff63e46a | ||
|
|
03e8348a14 | ||
|
|
2c6d02f101 | ||
|
|
327dcc190d | ||
|
|
c40c5c5919 | ||
|
|
388b9931b1 | ||
|
|
ae04b5a07f | ||
|
|
9d2f450440 | ||
|
|
45d2ea0c70 | ||
|
|
94fe0fc854 | ||
|
|
adf268697a | ||
|
|
2c478db23f | ||
|
|
3ea6375011 | ||
|
|
64ec2dd0a4 | ||
|
|
e84c2e4e3e | ||
|
|
5f5f13a818 | ||
|
|
2b1a39f236 | ||
|
|
4402068a93 | ||
|
|
ed50438744 | ||
|
|
9a651c3ecc | ||
|
|
1af2f8cbe9 | ||
|
|
2c74a5cf9a | ||
|
|
140817f8c6 | ||
|
|
1debc9c891 | ||
|
|
2ee0211994 | ||
|
|
86047f69fd | ||
|
|
036d8dddcf | ||
|
|
08b81fff56 | ||
|
|
fce1e0c7fe | ||
|
|
d69f61e39d | ||
|
|
eb6fac30e0 | ||
|
|
446cc8cdff | ||
|
|
b8fd5a0690 | ||
|
|
30195af8ca | ||
|
|
8566c12ccc | ||
|
|
ac741d63a6 | ||
|
|
9b4f7d28d6 | ||
|
|
bee07d1be2 | ||
|
|
259782ecfa | ||
|
|
ec3e022ca3 | ||
|
|
60e620539e | ||
|
|
06510c208c | ||
|
|
ff8a9c2e40 | ||
|
|
1854130a99 | ||
|
|
e2285cec16 | ||
|
|
070ed985f6 | ||
|
|
3f27f99a8f | ||
|
|
23b4a9cb2d | ||
|
|
fd33ab44c3 | ||
|
|
67ac9d1923 | ||
|
|
4d3ad389df | ||
|
|
9b3ad7a47f | ||
|
|
942a0c3894 | ||
|
|
6980fa091e | ||
|
|
a318b71ef1 | ||
|
|
6dea182ab8 | ||
|
|
20675cbf38 | ||
|
|
9f78dbba19 | ||
|
|
1b4bbf6493 | ||
|
|
317eabb42a | ||
|
|
32fd0000d2 | ||
|
|
29ca66989c | ||
|
|
76fb35f6d1 | ||
|
|
85f97a63fa | ||
|
|
f811f12206 | ||
|
|
183390ab60 | ||
|
|
b243d661c4 | ||
|
|
724b1d3e56 | ||
|
|
088230d100 | ||
|
|
afa34ae4cf | ||
|
|
4ea968da26 | ||
|
|
2fdf944e0f | ||
|
|
de40b3841d | ||
|
|
7d867dac97 | ||
|
|
372af4341d | ||
|
|
16523dac85 | ||
|
|
181b2f8122 | ||
|
|
a365d9eb23 | ||
|
|
f66c7a6011 | ||
|
|
6dc3a45851 | ||
|
|
4d6097a1d0 | ||
|
|
b7698ca53a | ||
|
|
e22d9929e5 | ||
|
|
f1e5a657ba | ||
|
|
c447103f0f | ||
|
|
c6ac076204 | ||
|
|
266eb85436 | ||
|
|
070696724c | ||
|
|
929790e807 | ||
|
|
54c4be43d3 | ||
|
|
cebd81f000 | ||
|
|
b92641a113 | ||
|
|
72adca100b | ||
|
|
455f46ada0 | ||
|
|
8fadbb5d39 | ||
|
|
dbdcd4a7ce | ||
|
|
e6506d673a | ||
|
|
2c0c5ffaff | ||
|
|
4c7daa223b | ||
|
|
74d172f904 | ||
|
|
75412dfb2e | ||
|
|
e103b55e7d | ||
|
|
518f481776 | ||
|
|
e47a929ff6 | ||
|
|
a7ac7d1c1c | ||
|
|
6b55811312 | ||
|
|
3a39137b82 | ||
|
|
fb5a7f9bf2 | ||
|
|
eebafbef64 | ||
|
|
16bb31770c | ||
|
|
32738688a6 | ||
|
|
ecd7202fb5 | ||
|
|
5bb9591478 | ||
|
|
ad9b98516b | ||
|
|
4598855145 | ||
|
|
2f048d6a94 | ||
|
|
0291bd41fd | ||
|
|
0be7157cd2 | ||
|
|
83d5d50a3b | ||
|
|
d41b523480 | ||
|
|
bbf88ca951 | ||
|
|
c057168a56 | ||
|
|
c9523a107a | ||
|
|
3e3b284ed5 | ||
|
|
f258371bc6 | ||
|
|
ee64e037b1 | ||
|
|
97a92f6d33 | ||
|
|
760c37e20c | ||
|
|
139442cbf3 | ||
|
|
b71f82bc73 | ||
|
|
0fd20981bf | ||
|
|
a744b26c29 | ||
|
|
73724ef55a | ||
|
|
bb7bff529f | ||
|
|
f41a842807 | ||
|
|
9a90a5e8f5 | ||
|
|
7a0898f189 | ||
|
|
c24c05597c | ||
|
|
94388f4aef | ||
|
|
83f130c013 | ||
|
|
6aced36e5b | ||
|
|
a034b5f950 | ||
|
|
a57fa33a24 | ||
|
|
8e6ebcf44f | ||
|
|
a3ef7a089f | ||
|
|
f040d46e53 | ||
|
|
9b047ca4e4 | ||
|
|
a1369453c1 | ||
|
|
23b5689ef4 | ||
|
|
f7aa626783 | ||
|
|
3d3a977037 | ||
|
|
dff4ea4c1e | ||
|
|
5ba8b42a77 | ||
|
|
985c22df2a | ||
|
|
9694f99827 | ||
|
|
ceff0cb74e | ||
|
|
a92ea0da97 | ||
|
|
a9e47be079 | ||
|
|
0ef0584ed3 | ||
|
|
45eaafffa2 | ||
|
|
42642d6070 | ||
|
|
a131680dc3 | ||
|
|
1fd302a4e1 | ||
|
|
7372ad075d | ||
|
|
9965bd1066 | ||
|
|
9523d64113 | ||
|
|
cd7306e0d8 | ||
|
|
e68e1474ea | ||
|
|
13d828e18c | ||
|
|
c1ee66d192 | ||
|
|
75e52e4508 | ||
|
|
6cb9181408 | ||
|
|
7f06610356 | ||
|
|
a8727f7f22 | ||
|
|
beff431b6a | ||
|
|
e1c5014207 | ||
|
|
bbe1e19710 | ||
|
|
4e102a109e | ||
|
|
600a386f32 | ||
|
|
8b7b32f4ed | ||
|
|
e93bf76167 | ||
|
|
0ac691910a | ||
|
|
0cf0cee501 | ||
|
|
4eca7ad122 | ||
|
|
e9307ffe97 | ||
|
|
1a1b47e085 | ||
|
|
bf9a20adbc | ||
|
|
55030b9358 | ||
|
|
a2dc9c77f5 | ||
|
|
e5f6877a77 | ||
|
|
c1a4273302 | ||
|
|
5f7f8bcad3 | ||
|
|
59fa06debf | ||
|
|
47fcae619a | ||
|
|
05f7c06227 | ||
|
|
3a52d4a852 | ||
|
|
ad7ccf07e5 | ||
|
|
c8116e12ca | ||
|
|
5c07f1cd17 | ||
|
|
a22f8814cf | ||
|
|
44d46fa029 | ||
|
|
f5b2d8662c | ||
|
|
404b73eeba | ||
|
|
bb1f4e1c4c | ||
|
|
3db0fcb85c | ||
|
|
4920523c48 | ||
|
|
955f9d8a58 | ||
|
|
babac6efc0 | ||
|
|
57a0d63d9c | ||
|
|
55eb201850 | ||
|
|
a6cc3b32dd | ||
|
|
89df144775 | ||
|
|
6996f8c6cd | ||
|
|
0903ccd5cf | ||
|
|
52f82a47c1 | ||
|
|
d5112c2218 | ||
|
|
b976e28c8b | ||
|
|
d1b551c370 | ||
|
|
0b761b14ab | ||
|
|
fbdcbc0ad1 | ||
|
|
6182bbc1d1 | ||
|
|
2cb0b53bd9 | ||
|
|
d452f10906 | ||
|
|
ad6e37450b | ||
|
|
8ae521a585 | ||
|
|
d27567af70 | ||
|
|
bc8e91682c | ||
|
|
b6737514bf | ||
|
|
341615a2ff | ||
|
|
10e68c8fb7 | ||
|
|
9c234fd97b | ||
|
|
c721a8ba01 | ||
|
|
5955df954b | ||
|
|
780c2b5528 | ||
|
|
efb26a899e | ||
|
|
0e49a6ec1d | ||
|
|
c411325f45 | ||
|
|
98b58cca5b | ||
|
|
e2d2a8e884 | ||
|
|
92111b8f1c | ||
|
|
ab6b93c12d | ||
|
|
892706af3c | ||
|
|
e76df52232 | ||
|
|
d5673bfa05 | ||
|
|
98c38c688b | ||
|
|
6d653aa0b6 | ||
|
|
9a14dc668c | ||
|
|
a2efd631a9 | ||
|
|
62ff649007 | ||
|
|
e600da1895 | ||
|
|
4d7c6fdaa2 | ||
|
|
caadbf4a9a | ||
|
|
5ed6a3995f | ||
|
|
8b6d23032a | ||
|
|
75b7da3a60 | ||
|
|
75de4be2a6 | ||
|
|
601c1e0d5a | ||
|
|
4c9a9d2f3e | ||
|
|
4b4871bb2f | ||
|
|
147465f9d9 | ||
|
|
0fedb85ca2 | ||
|
|
fef15ae0e5 | ||
|
|
ae205ea62c | ||
|
|
456271bf20 | ||
|
|
f836eb236e | ||
|
|
e095c525ff | ||
|
|
8abf696cc0 | ||
|
|
2f3eb1020c | ||
|
|
5dbd402a38 | ||
|
|
2f82b3d190 | ||
|
|
a0d00362aa | ||
|
|
578abcb639 | ||
|
|
d5b464c23b | ||
|
|
bf8256bbd3 | ||
|
|
a984b342b0 | ||
|
|
cb69177533 | ||
|
|
25f93bb285 | ||
|
|
01485add5c | ||
|
|
a8722353c3 | ||
|
|
eb16d7bc96 | ||
|
|
7cd3a01380 | ||
|
|
d789a64650 | ||
|
|
349a1976d9 | ||
|
|
fa596a389b | ||
|
|
222c55ae8e | ||
|
|
232ec4fc48 | ||
|
|
147c9c14bd | ||
|
|
bbc38a5e53 | ||
|
|
69f4aa27f7 | ||
|
|
cdfebfc695 | ||
|
|
6df989d1b6 | ||
|
|
a174093405 | ||
|
|
a74b3584df | ||
|
|
da6cb5fab1 | ||
|
|
b08c92e75c | ||
|
|
6cd360b946 | ||
|
|
d626dbcabe | ||
|
|
a9efdad4aa | ||
|
|
682675e545 | ||
|
|
7322b5e246 | ||
|
|
b23078f4a0 | ||
|
|
1e7b51df49 | ||
|
|
230f48ebda | ||
|
|
9e846a4648 | ||
|
|
99c47d9ec9 | ||
|
|
a12a79e8ba | ||
|
|
fca019c54b | ||
|
|
6a677027ba | ||
|
|
f961ae1b7f | ||
|
|
b290f20929 | ||
|
|
82a594880d | ||
|
|
fc021a288c | ||
|
|
43e156cc31 | ||
|
|
9acc2dffec | ||
|
|
60d03686b3 | ||
|
|
3c74fbd476 | ||
|
|
d99ccbabba | ||
|
|
18cb19fee9 | ||
|
|
20cc9d55f3 | ||
|
|
e414452e94 | ||
|
|
1e3b058cf0 | ||
|
|
3b28da8fef | ||
|
|
7b949cfac3 | ||
|
|
ab49f4406f | ||
|
|
daf41b86d9 | ||
|
|
7f60339972 | ||
|
|
fef20ab19e | ||
|
|
9eb65ec9d3 | ||
|
|
f36a8cf304 | ||
|
|
27c0883dab | ||
|
|
2e461a3dc7 | ||
|
|
b4b53431de | ||
|
|
256a3825ee | ||
|
|
91c4fa12ab | ||
|
|
c7b584f46b | ||
|
|
562ed2c7ba | ||
|
|
22af4628a6 | ||
|
|
21a121bc3e | ||
|
|
097b20adc0 | ||
|
|
cbdc29299e | ||
|
|
4e40edc516 | ||
|
|
e4d5fa80b8 | ||
|
|
a04d52b37a | ||
|
|
0e187e1761 | ||
|
|
f57ac0e0e3 | ||
|
|
c2f219bbc3 | ||
|
|
434151f715 | ||
|
|
bb57443908 | ||
|
|
90f4215081 | ||
|
|
c473b556de | ||
|
|
46fccab2f0 | ||
|
|
793a692f56 | ||
|
|
948b8492db | ||
|
|
27e5e147f7 | ||
|
|
c00eccba06 | ||
|
|
ff866b9664 | ||
|
|
01cf73b066 | ||
|
|
dbc9647e42 | ||
|
|
4cdd52b7d6 | ||
|
|
79274b0845 | ||
|
|
e2c8887145 | ||
|
|
6275594334 | ||
|
|
e06106123c | ||
|
|
fe4409dd34 | ||
|
|
8fb9f781d4 | ||
|
|
c20af4750a | ||
|
|
03f03d2fa7 | ||
|
|
54181ba410 | ||
|
|
f4ddb9cc3b | ||
|
|
28681b898f | ||
|
|
b8f83aa766 | ||
|
|
2a5f6f5d3c | ||
|
|
1ef6c70668 | ||
|
|
e3942880e0 | ||
|
|
e88feda716 |
31
.circleci/config.yml
Normal file
@@ -0,0 +1,31 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: projectstorm/react-diagrams-ci
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
# Download and cache dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
|
||||
- run: yarn install
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
|
||||
# test building project
|
||||
- run: yarn run prepublishOnly
|
||||
|
||||
# test building storybook
|
||||
- run: yarn run storybook:build
|
||||
|
||||
# test e2e tests and jest snapshots
|
||||
- run: yarn run test:ci
|
||||
27
.circleci/images/Dockerfile
Normal file
@@ -0,0 +1,27 @@
|
||||
FROM node:8-slim
|
||||
|
||||
# Install latest chrome dev package.
|
||||
# Note: this installs the necessary libs to make the bundled version of Chromium that Pupppeteer
|
||||
# installs, work.
|
||||
RUN apt-get update && apt-get install -y wget --no-install-recommends \
|
||||
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
|
||||
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y google-chrome-unstable \
|
||||
--no-install-recommends \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get purge --auto-remove -y curl \
|
||||
&& rm -rf /src/*.deb
|
||||
|
||||
RUN yarn add puppeteer
|
||||
|
||||
# Add pptr user.
|
||||
RUN groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
|
||||
&& mkdir -p /home/pptruser/Downloads \
|
||||
&& chown -R pptruser:pptruser /home/pptruser \
|
||||
&& chown -R pptruser:pptruser /node_modules
|
||||
|
||||
# Run user as non privileged.
|
||||
USER pptruser
|
||||
|
||||
CMD ["google-chrome-unstable"]
|
||||
9
.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
[*]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# Some exceptions
|
||||
[{package.json}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
27
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Checklist
|
||||
|
||||
- [ ] The code has been run through pretty `yarn run pretty`
|
||||
- [ ] 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
|
||||
|
||||
## 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:
|
||||
|
||||
(Add your own one below :])
|
||||
|
||||

|
||||
|
||||
|
||||
9
.gitignore
vendored
@@ -1,3 +1,11 @@
|
||||
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
|
||||
|
||||
@@ -183,3 +191,4 @@ jspm_packages
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
.idea
|
||||
|
||||
194
.npmignore
Normal file
@@ -0,0 +1,194 @@
|
||||
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
|
||||
14
.storybook/addon-code/react.js
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
|
||||
export class WithCode extends React.Component {
|
||||
render() {
|
||||
const { children, code } = this.props;
|
||||
const channel = addons.getChannel();
|
||||
|
||||
// send the notes to the channel.
|
||||
channel.emit('storybook/code/set_code', code);
|
||||
// return children elements.
|
||||
return children;
|
||||
}
|
||||
}
|
||||
69
.storybook/addon-code/register.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import addons from '@storybook/addons';
|
||||
import SyntaxHighlighter from 'react-syntax-highlighter';
|
||||
import { github } from 'react-syntax-highlighter/styles/hljs';
|
||||
|
||||
/**
|
||||
* @author Dylan
|
||||
*
|
||||
* Simple little addon for displaying code, might make this a seperate project at some point
|
||||
*/
|
||||
export class CodePreview extends React.Component {
|
||||
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
this.state = {
|
||||
code: ''
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { channel, api } = this.props;
|
||||
// Listen to the notes and render it.
|
||||
channel.on('storybook/code/set_code', (code) => {
|
||||
this.onAddCode(code);
|
||||
});
|
||||
|
||||
// Clear the current notes on every story change.
|
||||
this.stopListeningOnStory = api.onStory(() => {
|
||||
this.onAddCode('');
|
||||
});
|
||||
}
|
||||
|
||||
// This is some cleanup tasks when the Notes panel is unmounting.
|
||||
componentWillUnmount() {
|
||||
if (this.stopListeningOnStory) {
|
||||
this.stopListeningOnStory();
|
||||
}
|
||||
|
||||
this.unmounted = true;
|
||||
const { channel } = this.props;
|
||||
channel.removeListener('storybook/notes/add_notes', this.onAddCode);
|
||||
}
|
||||
|
||||
onAddCode(code) {
|
||||
this.setState({ code: code });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SyntaxHighlighter
|
||||
customStyle={{width: '100%', overflowX:'hidden', tabSize: 4}}
|
||||
showLineNumbers={true}
|
||||
language='language-tsx'
|
||||
style={github}
|
||||
>
|
||||
{this.state.code}
|
||||
</SyntaxHighlighter>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Register the addon with a unique name.
|
||||
addons.register('storybook/code', api => {
|
||||
// Also need to set a unique name to the panel.
|
||||
addons.addPanel('storybook/code/panel', {
|
||||
title: 'Code preview',
|
||||
render: () => <CodePreview channel={addons.getChannel()} api={api} />,
|
||||
});
|
||||
});
|
||||
3
.storybook/addons.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import './addon-code/register';
|
||||
import '@storybook/addon-actions/register';
|
||||
import '@storybook/addon-options/register';
|
||||
8
.storybook/config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { configure } from '@storybook/react';
|
||||
|
||||
function loadStories() {
|
||||
require('../demos/index.tsx');
|
||||
// You can require as many demos as you need.
|
||||
}
|
||||
|
||||
configure(loadStories, module);
|
||||
39
.storybook/webpack.config.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const path = require('path');
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.scss$/,
|
||||
loaders: ["style-loader", "css-loader", "sass-loader"],
|
||||
include: path.resolve(__dirname, '../')
|
||||
},
|
||||
{
|
||||
test: /\.css/,
|
||||
loaders: ["style-loader", "css-loader"],
|
||||
include: path.resolve(__dirname, '../')
|
||||
},
|
||||
{
|
||||
enforce: 'pre',
|
||||
test: /\.js$/,
|
||||
loader: "source-map-loader",
|
||||
exclude: [
|
||||
/node_modules\//
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
loader: 'awesome-typescript-loader?declaration=false',
|
||||
},
|
||||
{
|
||||
test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
|
||||
loader: "file-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'storm-react-diagrams': path.join(__dirname, "..", "src", "main")
|
||||
},
|
||||
extensions: [".tsx", ".ts", ".js"]
|
||||
}
|
||||
};
|
||||
76
CHANGELOG.md
Normal file
@@ -0,0 +1,76 @@
|
||||
__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
|
||||
|
||||
__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!
|
||||
|
||||
__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
|
||||
|
||||
__3.2.0__ http://dylanv.blog/2017/11/22/storm-react-diagrams-3-2-0/
|
||||
* [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
|
||||
* updated dependencies
|
||||
* [bugs] swapping diagram models in engines
|
||||
* [bugs] issues with the rendering pipeline #107
|
||||
* added ci badge to Readme
|
||||
|
||||
__3.1.3__
|
||||
* Refactor links slightly
|
||||
* use min extension for css
|
||||
* bump package versions
|
||||
* export more classes
|
||||
|
||||
__3.1.2__
|
||||
* Hotfix: fix zooming when canvas not in the top left corner
|
||||
(https://github.com/projectstorm/react-diagrams/pull/88)
|
||||
|
||||
__3.1.0__ http://dylanv.blog/2017/09/15/storm-react-diagrams-3-1-0/
|
||||
* Zoom relative to mouse location
|
||||
* Fixed links not connecting when grid is larger than port size
|
||||
* Prevented points from dragging when connected to a port and the node itself is not selected
|
||||
* API fixes
|
||||
* Code cleanup
|
||||
|
||||
__3.0.0__ http://dylanv.blog/2017/09/13/storm-react-diagrams-v3/
|
||||
* Massive performance updates
|
||||
* Complete rewrite
|
||||
* Started a changelog and design documents for each revision
|
||||
27
CONTRIBUTING.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Contributing
|
||||
|
||||
See below for guidelines on house keeping:
|
||||
|
||||
### Always add a PR
|
||||
|
||||
Since the project runs on GitHub, the best way to contribute is to fork and then submit a PR.
|
||||
You will find a template that you will need to fill out
|
||||
|
||||
### Adding new demos
|
||||
|
||||
Add a new folder in the ./demos directory and make sure that it is named correctly like the other demos.
|
||||
A new demo should conform to the standard of either `demo-simple` in which it contains a markdown file that
|
||||
clearly explains 'whats going on', or the code sample should have very clear comments that almost always should ready
|
||||
like an instruction manual such as the simple demo.
|
||||
|
||||
Finally, you should link up your demo to the __index.tsx__ file in the __demos__ directory. It should be quite
|
||||
self explanatory on how it works, but ultimately I have a helper method that makes it easy to link source code
|
||||
to the demo itself, hence the 'require' statements. The third parameter is if you want to place your demo
|
||||
inside a markdown guide (again: see simple demo for how that is done).
|
||||
|
||||
### Make the demo testable
|
||||
|
||||
Similar procedure, except link your demo in the __index.tsx__ file sitting in the __tests__ directory.
|
||||
Running `yarn run test` will fire up jest (hopefully) and then it will render your demo to a snapshot directory
|
||||
which when run again (for a second time), should compare the output to the newely generated snapshot. Make sure
|
||||
to commit the updated snapshot file with your PR!
|
||||
106
README.md
@@ -1,102 +1,46 @@
|
||||
# STORM React Diagrams
|
||||
|
||||
**PSA**: React Diagrams is currently 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).
|
||||
|
||||
---
|
||||
|
||||
**DEMO**: [http://www.projectstorm.io/react-diagrams](http://www.projectstorm.io/react-diagrams)
|
||||
|
||||
**DOCS:** [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/)
|
||||
|
||||
A super simple, no-nonsense diagramming library written in React that just works.
|
||||
|
||||
[](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://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)
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Introduction
|
||||
|
||||
A no-nonsense diagramming library written entirely in React with the help of Lodash. It aims to be:
|
||||
A no-nonsense diagramming library written entirely in React with the help of a few small libraries. It aims to be:
|
||||
|
||||
* Simple, and void of any fuss/complications when implementing it into your own application
|
||||
* Customizable without having to hack the core (adapters/factories etc..)
|
||||
* 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
|
||||
|
||||
## How to install
|
||||
#### Run the demos
|
||||
|
||||
```
|
||||
npm install storm-react-diagrams
|
||||
```
|
||||
or
|
||||
```
|
||||
yarn add storm-react-diagrams
|
||||
```
|
||||
After running `yarn install` you must then run: `yarn run storybook`
|
||||
|
||||
* Its only dependency is Lodash and obviously React so it will install that too.
|
||||
#### Building from source
|
||||
|
||||
#### How to see the examples
|
||||
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.
|
||||
We use webpack for this because TSC cannot compile a single UMD file \(TSC can currently only output multiple UMD files\).
|
||||
|
||||
simply navigate to the __demos__ directory and load up the corresponding index.html
|
||||
|
||||
#### How to build
|
||||
|
||||
Simply run ```tsc``` in the root directory and it will spit out the transpiled code and typescript definitions
|
||||
into the dist directory.
|
||||
## [Checkout the docs](https://projectstorm.gitbooks.io/react-diagrams)
|
||||
|
||||
|
||||
## How does it work
|
||||
|
||||
The library uses a Model Graph to represent the virtual diagram and then renders the diagram using
|
||||
2 layers:
|
||||
* Node Layer -> which is responsible for rendering nodes as HTML components
|
||||
* Link Layer -> which renders the links as SVG paths
|
||||
|
||||
Each node and link is fed into a factory that then generates the corresponding node or link react widget.
|
||||
Therefore, to create custom nodes and links, register your own factories that return your own widgets.
|
||||
|
||||
As long as a node contains at least one port and the corresponding NodeWidget contains at least one PortWidget,
|
||||
a link can be connected to it.
|
||||
|
||||
## Questions
|
||||
|
||||
#### Why didn’t I render the nodes as SVG's?
|
||||
|
||||
Because its vastly better to render nodes as standard HTML so that we can embed input controls and not have
|
||||
to deal with the complexities of trying to get SVG to work like we want it to. I also created this primarily to embed into
|
||||
enterprise applications where the nodes themselves are highly interactive with buttons and other controls that cave when I try to use SVG.
|
||||
|
||||
#### Why Typescript?
|
||||
|
||||
Because it can transpile into any level of ECMA Script, and the library got really complicated, so I ported it to Typescript
|
||||
to accommodate the heavy architectural changes I was starting to make. <3 Type Script
|
||||
|
||||
#### Why is there no JSX?
|
||||
|
||||
Because most of the library is 95% all logic anyway, and I construct very complex DOM elements with many dynamic properties. JSX
|
||||
Would just get in the way, and I personally hate JSX for a multitude of reasons anyway.
|
||||
|
||||
#### How do I make my own elements?
|
||||
|
||||
Take a look at the __defaults__ directory, with specific attention to the __DefaultNodeWidget__
|
||||
|
||||
#### How do I use the library?
|
||||
|
||||
Take a look at the demo folders, they have simple and complex examples of the complete usage.
|
||||
|
||||
## Usage Demo and Guide
|
||||
|
||||
This is a demo of the interaction taken directly from the test folder.
|
||||
|
||||

|
||||
|
||||
#### Key commands
|
||||
|
||||
__del key__ will remove anything selected including links
|
||||
|
||||
__shift and drag__ will trigger a multi selection box
|
||||
|
||||
__shift and select nodes/links/points__ will select multiple nodes
|
||||
|
||||
__drag canvas__ will drag the complete diagram
|
||||
|
||||
__mouse wheel__ will zoom in or out the entire diagram
|
||||
|
||||
__click link and drag__ will create a new link anchor/point that you can then drag around
|
||||
|
||||
__click node-port and drag__ will create a new link that is anchored to the port, allowing you
|
||||
to drag the link to another connecting port
|
||||
|
||||
11
SUMMARY.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Summary
|
||||
|
||||
* [Introduction](README.md)
|
||||
* [Interacting with diagrams](/docs/Interactive Usage.md)
|
||||
* [Getting Started](/docs/Getting Started.md)
|
||||
* [About the project](about-the-project.md)
|
||||
* [Testing](/docs/Testing.md)
|
||||
* [Architecture Questions](/docs/Architecture Questions.md)
|
||||
|
||||
|
||||
|
||||
23
demos/.helpers/DemoWorkspaceWidget.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
37
demos/.helpers/Helper.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as React from "react";
|
||||
import { withDocs } from "storybook-readme";
|
||||
import { WithCode } from "../../.storybook/addon-code/react.js";
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
static makeDemo(widget, code, markdown?) {
|
||||
let container = () => <WithCode code={code}>{widget}</WithCode>;
|
||||
if (markdown) {
|
||||
return withDocs({
|
||||
PreviewComponent: ({ children }) => {
|
||||
return <div className="docs-preview-wrapper">{children}</div>;
|
||||
}
|
||||
})(markdown, container);
|
||||
}
|
||||
return container;
|
||||
}
|
||||
}
|
||||
80
demos/.helpers/demo.scss
Normal file
@@ -0,0 +1,80 @@
|
||||
@import "../../src/sass/main";
|
||||
|
||||
.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%;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-preview-wrapper{
|
||||
background: rgb(60,60,60);
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.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);
|
||||
}
|
||||
|
||||
}
|
||||
88
demos/demo-cloning/index.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
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";
|
||||
|
||||
/**
|
||||
* Tests cloning
|
||||
*/
|
||||
class CloneSelected extends React.Component<any, any> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.cloneSelected = this.cloneSelected.bind(this);
|
||||
}
|
||||
|
||||
cloneSelected() {
|
||||
let { engine } = this.props;
|
||||
let offset = { x: 100, y: 100 };
|
||||
let model = engine.getDiagramModel();
|
||||
|
||||
let itemMap = {};
|
||||
_.forEach(model.getSelectedItems(), (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);
|
||||
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 });
|
||||
});
|
||||
model.addLink(newItem);
|
||||
}
|
||||
newItem.selected = false;
|
||||
});
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { engine } = this.props;
|
||||
return (
|
||||
<DemoWorkspaceWidget buttons={<button onClick={this.cloneSelected}>Clone Selected</button>}>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaults();
|
||||
|
||||
//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");
|
||||
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 <CloneSelected engine={engine} model={model} />;
|
||||
};
|
||||
157
demos/demo-custom-link1/index.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
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";
|
||||
|
||||
export class AdvancedLinkModel extends DefaultLinkModel {
|
||||
constructor() {
|
||||
super("advanced");
|
||||
this.width = 10;
|
||||
}
|
||||
}
|
||||
|
||||
export class AdvancedPortModel extends DefaultPortModel {
|
||||
createLinkModel(): AdvancedLinkModel | null {
|
||||
return new AdvancedLinkModel();
|
||||
}
|
||||
}
|
||||
|
||||
export class AdvancedLinkSegment extends React.Component<{ model: AdvancedLinkModel; path: string }> {
|
||||
path: SVGPathElement;
|
||||
circle: SVGCircleElement;
|
||||
callback: () => any;
|
||||
percent: number;
|
||||
handle: any;
|
||||
mounted: boolean;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.percent = 0;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.mounted = true;
|
||||
this.callback = () => {
|
||||
if (!this.circle || !this.path) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.percent += 2;
|
||||
if (this.percent > 100) {
|
||||
this.percent = 0;
|
||||
}
|
||||
|
||||
let point = this.path.getPointAtLength(this.path.getTotalLength() * (this.percent / 100.0));
|
||||
|
||||
this.circle.setAttribute("cx", "" + point.x);
|
||||
this.circle.setAttribute("cy", "" + point.y);
|
||||
|
||||
if (this.mounted) {
|
||||
requestAnimationFrame(this.callback);
|
||||
}
|
||||
};
|
||||
requestAnimationFrame(this.callback);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<>
|
||||
<path
|
||||
ref={ref => {
|
||||
this.path = ref;
|
||||
}}
|
||||
strokeWidth={this.props.model.width}
|
||||
stroke="rgba(255,0,0,0.5)"
|
||||
d={this.props.path}
|
||||
/>
|
||||
<circle
|
||||
ref={ref => {
|
||||
this.circle = ref;
|
||||
}}
|
||||
r={10}
|
||||
fill="orange"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class AdvancedLinkFactory extends DefaultLinkFactory {
|
||||
constructor() {
|
||||
super();
|
||||
this.type = "advanced";
|
||||
}
|
||||
|
||||
getNewInstance(initialConfig?: any): AdvancedLinkModel {
|
||||
return new AdvancedLinkModel();
|
||||
}
|
||||
|
||||
generateLinkSegment(model: AdvancedLinkModel, widget: DefaultLinkWidget, selected: boolean, path: string) {
|
||||
return (
|
||||
<g>
|
||||
<AdvancedLinkSegment model={model} path={path} />
|
||||
</g>
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Simple link styling demo
|
||||
*
|
||||
* @Author kfrajtak
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaults();
|
||||
engine.registerLinkFactory(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"));
|
||||
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"));
|
||||
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"));
|
||||
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"));
|
||||
node4.setPosition(300, 200);
|
||||
|
||||
var model = new DiagramModel();
|
||||
|
||||
model.addAll(port1.link(port3), port2.link(port4));
|
||||
|
||||
// add everything else
|
||||
model.addAll(node1, node2, node3, node4);
|
||||
|
||||
// load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
// render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
18
demos/demo-custom-node1/DiamondNodeFactory.tsx
Normal file
@@ -0,0 +1,18 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
12
demos/demo-custom-node1/DiamondNodeModel.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
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"));
|
||||
}
|
||||
}
|
||||
105
demos/demo-custom-node1/DiamondNodeWidget.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
26
demos/demo-custom-node1/DiamondPortModel.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
14
demos/demo-custom-node1/SimplePortFactory.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
57
demos/demo-custom-node1/index.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
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.installDefaults();
|
||||
|
||||
// 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.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
56
demos/demo-dagre/dagre-utils.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
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;
|
||||
modelNode.y = node.y;
|
||||
});
|
||||
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)
|
||||
);
|
||||
}
|
||||
120
demos/demo-dagre/index.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
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.setModel(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.installDefaults();
|
||||
|
||||
//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.setModel(model2);
|
||||
|
||||
return <Demo8Widget engine={engine} />;
|
||||
};
|
||||
44
demos/demo-drag-and-drop/Application.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import * as SRD from "storm-react-diagrams";
|
||||
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export class Application {
|
||||
protected activeModel: SRD.DiagramModel;
|
||||
protected diagramEngine: SRD.DiagramEngine;
|
||||
|
||||
constructor() {
|
||||
this.diagramEngine = new SRD.DiagramEngine();
|
||||
this.diagramEngine.installDefaults();
|
||||
|
||||
this.newModel();
|
||||
}
|
||||
|
||||
public newModel() {
|
||||
this.activeModel = new SRD.DiagramModel();
|
||||
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");
|
||||
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");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// link the ports
|
||||
let link1 = port.link(port2);
|
||||
|
||||
this.activeModel.addAll(node1, node2, link1);
|
||||
}
|
||||
|
||||
public getActiveDiagram(): SRD.DiagramModel {
|
||||
return this.activeModel;
|
||||
}
|
||||
|
||||
public getDiagramEngine(): SRD.DiagramEngine {
|
||||
return this.diagramEngine;
|
||||
}
|
||||
}
|
||||
72
demos/demo-drag-and-drop/components/BodyWidget.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
31
demos/demo-drag-and-drop/components/TrayItemWidget.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
21
demos/demo-drag-and-drop/components/TrayWidget.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
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>;
|
||||
}
|
||||
}
|
||||
12
demos/demo-drag-and-drop/index.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
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} />;
|
||||
};
|
||||
47
demos/demo-drag-and-drop/sass/main.scss
Normal file
@@ -0,0 +1,47 @@
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
demos/demo-grid/index.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
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.installDefaults();
|
||||
|
||||
//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 <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
73
demos/demo-labelled-links/index.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
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.installDefaults();
|
||||
|
||||
// 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.setTargetPort(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={
|
||||
<button
|
||||
onClick={() => {
|
||||
action("Serialized Graph")(JSON.stringify(model.serializeDiagram(), null, 2));
|
||||
}}
|
||||
>
|
||||
Serialize Graph
|
||||
</button>
|
||||
}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</DemoWorkspaceWidget>
|
||||
);
|
||||
};
|
||||
49
demos/demo-limit-points/index.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
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.installDefaults();
|
||||
|
||||
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.setModel(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>
|
||||
);
|
||||
};
|
||||
62
demos/demo-listeners/index.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
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.installDefaults();
|
||||
|
||||
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.setModel(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>
|
||||
);
|
||||
};
|
||||
69
demos/demo-locks/index.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
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.installDefaults();
|
||||
|
||||
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);
|
||||
var props = {
|
||||
diagramEngine: engine,
|
||||
allowLooseLinks: false,
|
||||
allowCanvasTranslation: false,
|
||||
allowCanvasZoom: false
|
||||
} as DiagramProps;
|
||||
|
||||
//!========================================= <<<<<<<
|
||||
|
||||
return <DiagramWidget className="srd-demo-canvas" {...props} />;
|
||||
};
|
||||
86
demos/demo-mutate-graph/index.tsx
Normal file
@@ -0,0 +1,86 @@
|
||||
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.setModel(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.installDefaults();
|
||||
|
||||
//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} />;
|
||||
};
|
||||
48
demos/demo-performance/index.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel, DiagramWidget } from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple stress test of the system, shows that it can handle many nodes, and
|
||||
* retain good performance
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaults();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
for (var i = 0; i < 8; i++) {
|
||||
for (var j = 0; j < 8; j++) {
|
||||
generateNodes(model, i * 200, j * 100);
|
||||
}
|
||||
}
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
|
||||
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");
|
||||
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");
|
||||
node2.setPosition(200 + offsetX, 100 + offsetY);
|
||||
|
||||
//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);
|
||||
}
|
||||
60
demos/demo-serializing/index.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import { DiagramEngine, DiagramModel, DefaultNodeModel, LinkModel } 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";
|
||||
import {DeserializeEvent} from "../../../react-canvas/src/models/BaseModel";
|
||||
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaults();
|
||||
|
||||
//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.deSerialize(new DeserializeEvent(JSON.parse(str), engine));
|
||||
engine.setModel(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>
|
||||
);
|
||||
};
|
||||
38
demos/demo-simple-flow/index.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
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.installDefaults();
|
||||
|
||||
//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 <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} allowLooseLinks={false} />;
|
||||
};
|
||||
9
demos/demo-simple/docs.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# 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.
|
||||
41
demos/demo-simple/index.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
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.installDefaults();
|
||||
|
||||
//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.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return <DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />;
|
||||
};
|
||||
68
demos/demo-smart-routing/index.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
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.installDefaults();
|
||||
|
||||
// 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.setModel(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>
|
||||
);
|
||||
};
|
||||
61
demos/demo-zoom-to-fit/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import {
|
||||
DiagramEngine,
|
||||
DiagramModel,
|
||||
DefaultNodeModel,
|
||||
LinkModel,
|
||||
DefaultPortModel,
|
||||
DiagramWidget
|
||||
} from "storm-react-diagrams";
|
||||
import * as React from "react";
|
||||
import { DemoWorkspaceWidget } from "../.helpers/DemoWorkspaceWidget";
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple stress test of the system plus zoom to fit function
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
export default () => {
|
||||
//1) setup the diagram engine
|
||||
var engine = new DiagramEngine();
|
||||
engine.installDefaults();
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new DiagramModel();
|
||||
|
||||
for (var i = 0; i < 8; i++) {
|
||||
for (var j = 0; j < 8; j++) {
|
||||
generateNodes(model, i * 200, j * 100);
|
||||
}
|
||||
}
|
||||
|
||||
//5) load model into engine
|
||||
engine.setModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
return (
|
||||
<DemoWorkspaceWidget
|
||||
buttons={<button onClick={() => engine.getCanvasWidget().zoomToFit()}>Zoom to fit</button>}
|
||||
>
|
||||
<DiagramWidget className="srd-demo-canvas" diagramEngine={engine} />
|
||||
</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");
|
||||
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");
|
||||
node2.setPosition(200 + offsetX, 100 + offsetY);
|
||||
|
||||
//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);
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>STORM React Diagrams Test 2</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
|
||||
<script src="https://unpkg.com/lodash@4.17.4/lodash.min.js"></script>
|
||||
<script src="./bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,69 +0,0 @@
|
||||
import * as SRD from "../../src/main";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
declare var require: {
|
||||
<T>(path: string): T;
|
||||
(paths: string[], callback: (...modules: any[]) => void): void;
|
||||
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
|
||||
};
|
||||
|
||||
require("../test.scss");
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple test showing the Object oriented way of using this library.
|
||||
* It creates 2 nodes and links them together with a single link
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
window.onload = () => {
|
||||
|
||||
//1) setup the diagram engine
|
||||
var engine = new SRD.DiagramEngine();
|
||||
engine.registerNodeFactory(new SRD.DefaultNodeFactory());
|
||||
engine.registerLinkFactory(new SRD.DefaultLinkFactory());
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new SRD.DiagramModel();
|
||||
|
||||
//3-A) create a default node
|
||||
var node1 = new SRD.NodeModel();
|
||||
node1.extras= {
|
||||
name:"Node 1",
|
||||
color: 'rgb(0,192,255)',
|
||||
outPorts: ['out-1']
|
||||
};
|
||||
node1.x = 100;
|
||||
node1.y = 100;
|
||||
var port1 = node1.addPort(new SRD.PortModel("out-1"));
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new SRD.NodeModel();
|
||||
node2.extras= {
|
||||
name:"Node 2",
|
||||
color: 'rgb(192,255,0)',
|
||||
inPorts: ['in-1']
|
||||
};
|
||||
node2.x = 400;
|
||||
node2.y = 100;
|
||||
var port2 = node2.addPort(new SRD.PortModel("in-1"));
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = new SRD.LinkModel();
|
||||
link1.setSourcePort(port1);
|
||||
link1.setTargetPort(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addNode(node1);
|
||||
model.addNode(node2);
|
||||
model.addLink(link1);
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
ReactDOM.render(React.createElement(SRD.DiagramWidget,{diagramEngine: engine}), document.body);
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>STORM React Diagrams Test 1</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>
|
||||
<script src="https://unpkg.com/lodash@4.17.4/lodash.min.js"></script>
|
||||
<script src="./bundle.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,79 +0,0 @@
|
||||
import * as SRD from "../../src/main";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
|
||||
declare var require: {
|
||||
<T>(path: string): T;
|
||||
(paths: string[], callback: (...modules: any[]) => void): void;
|
||||
ensure: (paths: string[], callback: (require: <T>(path: string) => T) => void) => void;
|
||||
};
|
||||
|
||||
require("../test.scss");
|
||||
|
||||
/**
|
||||
*
|
||||
* Simple stress test of the system, shows that it can handle many nodes, and
|
||||
* retain good performance
|
||||
*
|
||||
* @Author Dylan Vorster
|
||||
*/
|
||||
window.onload = () => {
|
||||
|
||||
//1) setup the diagram engine
|
||||
var engine = new SRD.DiagramEngine();
|
||||
engine.registerNodeFactory(new SRD.DefaultNodeFactory());
|
||||
engine.registerLinkFactory(new SRD.DefaultLinkFactory());
|
||||
|
||||
|
||||
function generateNodes(model: SRD.DiagramModel, offsetX: number,offsetY: number){
|
||||
//3-A) create a default node
|
||||
var node1 = new SRD.NodeModel();
|
||||
node1.extras= {
|
||||
name:"Node 1",
|
||||
color: 'rgb(0,192,255)',
|
||||
outPorts: ['out-1']
|
||||
};
|
||||
node1.x = 100 + offsetX;
|
||||
node1.y = 100 + offsetY;
|
||||
var port1 = node1.addPort(new SRD.PortModel("out-1"));
|
||||
|
||||
//3-B) create another default node
|
||||
var node2 = new SRD.NodeModel();
|
||||
node2.extras= {
|
||||
name:"Node 2",
|
||||
color: 'rgb(192,255,0)',
|
||||
inPorts: ['in-1']
|
||||
};
|
||||
node2.x = 200 + offsetX;
|
||||
node2.y = 100 + offsetY;
|
||||
var port2 = node2.addPort(new SRD.PortModel("in-1"));
|
||||
|
||||
//3-C) link the 2 nodes together
|
||||
var link1 = new SRD.LinkModel();
|
||||
link1.setSourcePort(port1);
|
||||
link1.setTargetPort(port2);
|
||||
|
||||
//4) add the models to the root graph
|
||||
model.addNode(node1);
|
||||
model.addNode(node2);
|
||||
model.addLink(link1);
|
||||
}
|
||||
|
||||
//2) setup the diagram model
|
||||
var model = new SRD.DiagramModel();
|
||||
|
||||
for(var i =0;i < 8;i++){
|
||||
for(var j = 0;j < 8;j++){
|
||||
generateNodes(model,i*200,j*100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//5) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
|
||||
//6) render the diagram!
|
||||
ReactDOM.render(React.createElement(SRD.DiagramWidget,{diagramEngine: engine}), document.body);
|
||||
|
||||
}
|
||||
129
demos/index.tsx
Normal file
@@ -0,0 +1,129 @@
|
||||
import * as React from "react";
|
||||
import { storiesOf, addDecorator } from "@storybook/react";
|
||||
import { setOptions } from "@storybook/addon-options";
|
||||
import { host } from "storybook-host";
|
||||
import { Helper } from "./.helpers/Helper";
|
||||
import { Toolkit } from "../src/Toolkit";
|
||||
|
||||
//include the SCSS for the demo
|
||||
import "./.helpers/demo.scss";
|
||||
|
||||
Toolkit.TESTING = true;
|
||||
|
||||
addDecorator(
|
||||
host({
|
||||
cropMarks: false,
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
padding: 20
|
||||
})
|
||||
);
|
||||
|
||||
setOptions({
|
||||
name: "STORM React Diagrams",
|
||||
url: "https://github.com/projectstorm/react-diagrams",
|
||||
addonPanelInRight: true
|
||||
});
|
||||
|
||||
storiesOf("Simple Usage", module)
|
||||
.add(
|
||||
"Simple example",
|
||||
Helper.makeDemo(
|
||||
require("./demo-simple/index").default(),
|
||||
require("!!raw-loader!./demo-simple/index"),
|
||||
require("./demo-simple/docs.md")
|
||||
)
|
||||
)
|
||||
// .add(
|
||||
// "Simple flow example",
|
||||
// Helper.makeDemo(require("./demo-simple-flow/index").default(), require("!!raw-loader!./demo-simple-flow/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Performance demo",
|
||||
// Helper.makeDemo(require("./demo-performance/index").default(), require("!!raw-loader!./demo-performance/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Locked widget",
|
||||
// Helper.makeDemo(require("./demo-locks/index").default(), require("!!raw-loader!./demo-locks/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Canvas grid size",
|
||||
// Helper.makeDemo(require("./demo-grid/index").default(), require("!!raw-loader!./demo-grid/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Limiting link points",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-limit-points/index").default(),
|
||||
// require("!!raw-loader!./demo-limit-points/index")
|
||||
// )
|
||||
// )
|
||||
// .add(
|
||||
// "Events and listeners",
|
||||
// Helper.makeDemo(require("./demo-listeners/index").default(), require("!!raw-loader!./demo-listeners/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Zoom to fit",
|
||||
// Helper.makeDemo(require("./demo-zoom-to-fit/index").default(), require("!!raw-loader!./demo-zoom-to-fit/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Links with labels",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-labelled-links/index").default(),
|
||||
// require("!!raw-loader!./demo-labelled-links/index")
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// storiesOf("Advanced Techniques", module)
|
||||
// .add(
|
||||
// "Clone Selected",
|
||||
// Helper.makeDemo(require("./demo-cloning/index").default(), require("!!raw-loader!./demo-cloning/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Serializing and de-serializing",
|
||||
// Helper.makeDemo(require("./demo-serializing/index").default(), require("!!raw-loader!./demo-serializing/index"))
|
||||
// )
|
||||
// .add(
|
||||
// "Programatically modifying graph",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-mutate-graph/index").default(),
|
||||
// require("!!raw-loader!./demo-mutate-graph/index")
|
||||
// )
|
||||
// )
|
||||
// .add(
|
||||
// "Large application",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-drag-and-drop/index").default(),
|
||||
// require("!!raw-loader!./demo-drag-and-drop/components/BodyWidget")
|
||||
// )
|
||||
// )
|
||||
// .add(
|
||||
// "Smart routing",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-smart-routing/index").default(),
|
||||
// require("!!raw-loader!./demo-smart-routing/index")
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// storiesOf("Custom Models", module)
|
||||
// .add(
|
||||
// "Custom diamond node",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-custom-node1/index").default(),
|
||||
// require("!!raw-loader!./demo-custom-node1/index")
|
||||
// )
|
||||
// )
|
||||
// .add(
|
||||
// "Custom animated links",
|
||||
// Helper.makeDemo(
|
||||
// require("./demo-custom-link1/index").default(),
|
||||
// require("!!raw-loader!./demo-custom-link1/index")
|
||||
// )
|
||||
// );
|
||||
//
|
||||
// storiesOf("3rd party libraries", module).add(
|
||||
// "Auto Distribute (Dagre)",
|
||||
// Helper.makeDemo(require("./demo-dagre/index").default(), require("!!raw-loader!./demo-dagre/index"))
|
||||
// );
|
||||
|
||||
// enable this to log mouse location when writing new puppeteer tests
|
||||
//Helper.logMousePosition()
|
||||
@@ -1,12 +0,0 @@
|
||||
*{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html,body{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgb(60,60,60);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@import "../src/sass.scss";
|
||||
10
demos/tslint.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": [
|
||||
"../tslint.json"
|
||||
],
|
||||
"rules": {
|
||||
"no-console": false,
|
||||
"max-classes-per-file": false,
|
||||
"no-var-requires": false
|
||||
}
|
||||
}
|
||||
0
dist/demos/demo2/index.d.ts
vendored
1623
dist/main.js
vendored
1
dist/main.js.map
vendored
17
dist/src/BaseEntity.d.ts
vendored
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class BaseListener {
|
||||
}
|
||||
export declare class BaseEnity<T extends BaseListener> {
|
||||
listeners: {
|
||||
[s: string]: T;
|
||||
};
|
||||
id: string;
|
||||
constructor();
|
||||
getID(): string;
|
||||
clearListeners(): void;
|
||||
itterateListeners(cb: (t: T) => any): void;
|
||||
removeListener(listener: string): boolean;
|
||||
addListener(listener: T): string;
|
||||
}
|
||||
91
dist/src/Common.d.ts
vendored
@@ -1,91 +0,0 @@
|
||||
import { BaseEnity, BaseListener } from "./BaseEntity";
|
||||
export interface BaseModelListener extends BaseListener {
|
||||
selectionChanged?(): any;
|
||||
entityRemoved?(): any;
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class BaseModel extends BaseEnity<BaseModelListener> {
|
||||
selected: boolean;
|
||||
constructor();
|
||||
getID(): string;
|
||||
isSelected(): boolean;
|
||||
setSelected(selected: boolean): void;
|
||||
remove(): void;
|
||||
}
|
||||
export declare class PointModel extends BaseModel {
|
||||
x: number;
|
||||
y: number;
|
||||
link: LinkModel;
|
||||
constructor(link: LinkModel, points: {
|
||||
x: number;
|
||||
y: number;
|
||||
});
|
||||
remove(): void;
|
||||
updateLocation(points: {
|
||||
x: number;
|
||||
y: number;
|
||||
}): void;
|
||||
getX(): number;
|
||||
getY(): number;
|
||||
getLink(): LinkModel;
|
||||
}
|
||||
export declare class LinkModel extends BaseModel {
|
||||
linkType: string;
|
||||
sourcePort: PortModel | null;
|
||||
targetPort: PortModel | null;
|
||||
points: PointModel[];
|
||||
extras: {};
|
||||
constructor();
|
||||
remove(): void;
|
||||
isLastPoint(point: PointModel): boolean;
|
||||
getPointIndex(point: PointModel): number;
|
||||
getPointModel(id: string): PointModel | null;
|
||||
getFirstPoint(): PointModel;
|
||||
getLastPoint(): PointModel;
|
||||
setSourcePort(port: PortModel): void;
|
||||
getSourcePort(): PortModel;
|
||||
getTargetPort(): PortModel;
|
||||
setTargetPort(port: PortModel): void;
|
||||
getPoints(): PointModel[];
|
||||
setPoints(points: PointModel[]): void;
|
||||
removePoint(pointModel: PointModel): void;
|
||||
addPoint(pointModel: PointModel, index?: number): void;
|
||||
getType(): string;
|
||||
}
|
||||
export declare class PortModel extends BaseModel {
|
||||
name: string;
|
||||
parentNode: NodeModel;
|
||||
links: {
|
||||
[id: string]: LinkModel;
|
||||
};
|
||||
constructor(name: string);
|
||||
getName(): string;
|
||||
getParent(): NodeModel;
|
||||
setParentNode(node: NodeModel): void;
|
||||
removeLink(link: LinkModel): void;
|
||||
addLink(link: LinkModel): void;
|
||||
getLinks(): {
|
||||
[id: string]: LinkModel;
|
||||
};
|
||||
}
|
||||
export declare class NodeModel extends BaseModel {
|
||||
nodeType: string;
|
||||
canDelete: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
extras: {};
|
||||
ports: {
|
||||
[s: string]: PortModel;
|
||||
};
|
||||
constructor();
|
||||
remove(): void;
|
||||
getPort(name: string): PortModel | null;
|
||||
getPorts(): {
|
||||
[s: string]: PortModel;
|
||||
};
|
||||
removePort(port: PortModel): void;
|
||||
addPort(port: PortModel): PortModel;
|
||||
getType(): string;
|
||||
}
|
||||
58
dist/src/DiagramEngine.d.ts
vendored
@@ -1,58 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import { NodeWidgetFactory, LinkWidgetFactory } from "./WidgetFactories";
|
||||
import { LinkModel, NodeModel, BaseModel, PortModel } from "./Common";
|
||||
import { BaseEnity, BaseListener } from "./BaseEntity";
|
||||
import { DiagramModel } from "./DiagramModel";
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export interface DiagramEngineListener extends BaseListener {
|
||||
nodeFactoriesUpdated(): any;
|
||||
linkFactoriesUpdated(): any;
|
||||
}
|
||||
/**
|
||||
* Passed as a parameter to the DiagramWidget
|
||||
*/
|
||||
export declare class DiagramEngine extends BaseEnity<DiagramEngineListener> {
|
||||
nodeFactories: {
|
||||
[s: string]: NodeWidgetFactory;
|
||||
};
|
||||
linkFactories: {
|
||||
[s: string]: LinkWidgetFactory;
|
||||
};
|
||||
diagramModel: DiagramModel;
|
||||
canvas: Element;
|
||||
paintableWidgets: {};
|
||||
constructor();
|
||||
clearRepaintEntities(): void;
|
||||
enableRepaintEntities(entities: BaseModel[]): void;
|
||||
canEntityRepaint(baseModel: BaseModel): boolean;
|
||||
setCanvas(canvas: Element | null): void;
|
||||
setDiagramModel(model: DiagramModel): void;
|
||||
getDiagramModel(): DiagramModel;
|
||||
getNodeFactories(): {
|
||||
[s: string]: NodeWidgetFactory;
|
||||
};
|
||||
getLinkFactories(): {
|
||||
[s: string]: LinkWidgetFactory;
|
||||
};
|
||||
registerNodeFactory(factory: NodeWidgetFactory): void;
|
||||
registerLinkFactory(factory: LinkWidgetFactory): void;
|
||||
getFactoryForNode(node: NodeModel): NodeWidgetFactory | null;
|
||||
getFactoryForLink(link: LinkModel): LinkWidgetFactory | null;
|
||||
generateWidgetForLink(link: LinkModel): JSX.Element | null;
|
||||
generateWidgetForNode(node: NodeModel): JSX.Element | null;
|
||||
getRelativeMousePoint(event: any): {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
getRelativePoint(x: any, y: any): {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
getNodePortElement(port: PortModel): any;
|
||||
getPortCenter(port: PortModel): {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
}
|
||||
47
dist/src/DiagramModel.d.ts
vendored
@@ -1,47 +0,0 @@
|
||||
import { LinkModel, NodeModel, BaseModel } from "./Common";
|
||||
import { BaseListener, BaseEnity } from "./BaseEntity";
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*
|
||||
*/
|
||||
export interface DiagramListener extends BaseListener {
|
||||
nodesUpdated(): any;
|
||||
linksUpdated(): any;
|
||||
controlsUpdated(): any;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
export declare class DiagramModel extends BaseEnity<DiagramListener> {
|
||||
links: {
|
||||
[s: string]: LinkModel;
|
||||
};
|
||||
nodes: {
|
||||
[s: string]: NodeModel;
|
||||
};
|
||||
offsetX: number;
|
||||
offsetY: number;
|
||||
zoom: number;
|
||||
constructor();
|
||||
clearSelection(ignore?: BaseModel | null): void;
|
||||
getSelectedItems(): BaseModel[];
|
||||
setZoomLevel(zoom: number): void;
|
||||
setOffset(offsetX: number, offsetY: number): void;
|
||||
setOffsetX(offsetX: number): void;
|
||||
setOffsetY(offsetY: number): void;
|
||||
getOffsetY(): number;
|
||||
getOffsetX(): number;
|
||||
getZoomLevel(): number;
|
||||
getNode(node: string | NodeModel): NodeModel | null;
|
||||
getLink(link: string | LinkModel): LinkModel | null;
|
||||
addLink(link: LinkModel): LinkModel;
|
||||
addNode(node: NodeModel): NodeModel;
|
||||
removeLink(link: LinkModel | string): void;
|
||||
removeNode(node: NodeModel | string): void;
|
||||
getLinks(): {
|
||||
[s: string]: LinkModel;
|
||||
};
|
||||
getNodes(): {
|
||||
[s: string]: NodeModel;
|
||||
};
|
||||
}
|
||||
10
dist/src/Toolkit.d.ts
vendored
@@ -1,10 +0,0 @@
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class Toolkit {
|
||||
/**
|
||||
* Generats a unique ID (thanks Stack overflow :3)
|
||||
* @returns {String}
|
||||
*/
|
||||
static UID(): string;
|
||||
}
|
||||
17
dist/src/WidgetFactories.d.ts
vendored
@@ -1,17 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import { NodeModel, LinkModel } from "./Common";
|
||||
import { DiagramEngine } from "./DiagramEngine";
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare abstract class WidgetFactory {
|
||||
type: string;
|
||||
constructor(name: string);
|
||||
getType(): string;
|
||||
}
|
||||
export declare abstract class NodeWidgetFactory extends WidgetFactory {
|
||||
abstract generateReactWidget(diagramEngine: DiagramEngine, node: NodeModel): JSX.Element;
|
||||
}
|
||||
export declare abstract class LinkWidgetFactory extends WidgetFactory {
|
||||
abstract generateReactWidget(diagramEngine: DiagramEngine, link: LinkModel): JSX.Element;
|
||||
}
|
||||
11
dist/src/defaults/DefaultLinkFactory.d.ts
vendored
@@ -1,11 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import { LinkWidgetFactory } from "../WidgetFactories";
|
||||
import { LinkModel } from "../Common";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class DefaultLinkFactory extends LinkWidgetFactory {
|
||||
constructor();
|
||||
generateReactWidget(diagramEngine: DiagramEngine, link: LinkModel): JSX.Element;
|
||||
}
|
||||
27
dist/src/defaults/DefaultLinkWidget.d.ts
vendored
@@ -1,27 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { LinkModel, PointModel } from "../Common";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
export interface DefaultLinkProps {
|
||||
color?: string;
|
||||
width?: number;
|
||||
link: LinkModel;
|
||||
smooth?: boolean;
|
||||
diagramEngine: DiagramEngine;
|
||||
pointAdded?: (point: PointModel, event) => any;
|
||||
}
|
||||
export interface DefaultLinkState {
|
||||
selected: boolean;
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class DefaultLinkWidget extends React.Component<DefaultLinkProps, DefaultLinkState> {
|
||||
static defaultProps: DefaultLinkProps;
|
||||
constructor(props: DefaultLinkProps);
|
||||
generatePoint(pointIndex: number): JSX.Element;
|
||||
generateLink(extraProps: {
|
||||
id: number;
|
||||
}): JSX.Element;
|
||||
render(): React.DOMElement<React.SVGAttributes<SVGElement>, SVGElement>;
|
||||
}
|
||||
11
dist/src/defaults/DefaultNodeFactory.d.ts
vendored
@@ -1,11 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import { NodeWidgetFactory } from "../WidgetFactories";
|
||||
import { NodeModel } from "../Common";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class DefaultNodeFactory extends NodeWidgetFactory {
|
||||
constructor();
|
||||
generateReactWidget(diagramEngine: DiagramEngine, node: NodeModel): JSX.Element;
|
||||
}
|
||||
26
dist/src/defaults/DefaultNodeWidget.d.ts
vendored
@@ -1,26 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { NodeModel } from "../Common";
|
||||
export interface DefaultNodeProps {
|
||||
name?: string;
|
||||
node: NodeModel;
|
||||
inPorts?: (string | {
|
||||
name: string;
|
||||
display: string;
|
||||
})[];
|
||||
outPorts?: (string | {
|
||||
name: string;
|
||||
display: string;
|
||||
})[];
|
||||
color?: string;
|
||||
}
|
||||
export interface DefaultNodeState {
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class DefaultNodeWidget extends React.Component<DefaultNodeProps, DefaultNodeState> {
|
||||
static defaultProps: DefaultNodeProps;
|
||||
constructor(props: DefaultNodeProps);
|
||||
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
}
|
||||
11
dist/src/main.d.ts
vendored
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export * from "./defaults/DefaultLinkFactory";
|
||||
export * from "./defaults/DefaultLinkWidget";
|
||||
export * from "./defaults/DefaultNodeFactory";
|
||||
export * from "./defaults/DefaultNodeWidget";
|
||||
export * from "./DiagramEngine";
|
||||
export * from "./DiagramModel";
|
||||
export * from "./Common";
|
||||
export * from "./widgets/DiagramWidget";
|
||||
35
dist/src/widgets/DiagramWidget.d.ts
vendored
@@ -1,35 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
import { BaseModel } from "../Common";
|
||||
export declare class BaseAction {
|
||||
mouseX: number;
|
||||
mouseY: number;
|
||||
ms: number;
|
||||
constructor(mouseX: number, mouseY: number);
|
||||
}
|
||||
export interface DiagramProps {
|
||||
diagramEngine: DiagramEngine;
|
||||
}
|
||||
export interface DiagramState {
|
||||
action: BaseAction | null;
|
||||
renderedNodes: boolean;
|
||||
windowListener: any;
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class DiagramWidget extends React.Component<DiagramProps, DiagramState> {
|
||||
constructor(props: DiagramProps);
|
||||
componentWillUnmount(): void;
|
||||
componentWillReceiveProps(nextProps: DiagramProps): void;
|
||||
/**
|
||||
* Gets a model and element under the mouse cursor
|
||||
*/
|
||||
getMouseElement(event: any): {
|
||||
model: BaseModel;
|
||||
element: Element;
|
||||
};
|
||||
componentDidMount(): void;
|
||||
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
}
|
||||
18
dist/src/widgets/LinkLayerWidget.d.ts
vendored
@@ -1,18 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
import { PointModel } from "../Common";
|
||||
export interface LinkLayerProps {
|
||||
diagramEngine: DiagramEngine;
|
||||
pointAdded: (point: PointModel, event) => any;
|
||||
}
|
||||
export interface LinkLayerState {
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class LinkLayerWidget extends React.Component<LinkLayerProps, LinkLayerState> {
|
||||
constructor(props: LinkLayerProps);
|
||||
componentDidMount(): void;
|
||||
render(): React.DOMElement<React.SVGAttributes<SVGElement>, SVGElement>;
|
||||
}
|
||||
19
dist/src/widgets/LinkWidget.d.ts
vendored
@@ -1,19 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { LinkModel } from "../Common";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
export interface LinkProps {
|
||||
link: LinkModel;
|
||||
diagramEngine: DiagramEngine;
|
||||
children?: any;
|
||||
}
|
||||
export interface LinkState {
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class LinkWidget extends React.Component<LinkProps, LinkState> {
|
||||
constructor(props: LinkProps);
|
||||
shouldComponentUpdate(): boolean;
|
||||
render(): any;
|
||||
}
|
||||
15
dist/src/widgets/NodeLayerWidget.d.ts
vendored
@@ -1,15 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
export interface NodeLayerProps {
|
||||
diagramEngine: DiagramEngine;
|
||||
}
|
||||
export interface NodeLayerState {
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class NodeLayerWidget extends React.Component<NodeLayerProps, NodeLayerState> {
|
||||
constructor(props: NodeLayerProps);
|
||||
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
}
|
||||
19
dist/src/widgets/NodeWidget.d.ts
vendored
@@ -1,19 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { NodeModel } from "../Common";
|
||||
import { DiagramEngine } from "../DiagramEngine";
|
||||
export interface NodeProps {
|
||||
node: NodeModel;
|
||||
children?: any;
|
||||
diagramEngine: DiagramEngine;
|
||||
}
|
||||
export interface NodeState {
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class NodeWidget extends React.Component<NodeProps, NodeState> {
|
||||
constructor(props: NodeProps);
|
||||
shouldComponentUpdate(): boolean;
|
||||
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
}
|
||||
17
dist/src/widgets/PortWidget.d.ts
vendored
@@ -1,17 +0,0 @@
|
||||
/// <reference types="react" />
|
||||
import * as React from "react";
|
||||
import { NodeModel } from "../Common";
|
||||
export interface PortProps {
|
||||
name: string;
|
||||
node: NodeModel;
|
||||
}
|
||||
export interface PortState {
|
||||
selected: boolean;
|
||||
}
|
||||
/**
|
||||
* @author Dylan Vorster
|
||||
*/
|
||||
export declare class PortWidget extends React.Component<PortProps, PortState> {
|
||||
constructor(props: PortProps);
|
||||
render(): React.DOMElement<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||
}
|
||||
76
docs/Architecture Questions.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Architecture Questions
|
||||
|
||||
Here I will try to answer any questions relating to the design of the system
|
||||
|
||||
### What was the inspiration for this library?
|
||||
|
||||
Joint JS (a fantastic library) + my need for rich HTML nodes + LabView + Blender Composite sub system
|
||||
|
||||
### Why render the nodes as HTML Elements and not SVG's?
|
||||
|
||||
My original requirement for this library stemmed from the requirement of wanting HTML nodes that would allow me to
|
||||
embed rich controls such as input fields, drop downs and have the system treat such nodes as first class citizens.
|
||||
I originally tried to make this work in JointJS, but ran into a number of problems of which this was a relatively big one.
|
||||
|
||||
JointJS does allow you to do this, but at the time of writing this library originally, I was having a lot of trouble
|
||||
to make it work exactly like I needed it, and therefore decided from the very beginning that I would attempt this
|
||||
with an HTML first mindset.
|
||||
|
||||
|
||||
### Why Typescript?
|
||||
|
||||
Firstly, because it can transpile into any level of ECMAScript. This means that I don't need to break our the refactor tractor
|
||||
every time ECMAScript decides it wants to add features which it should have done years ago.
|
||||
|
||||
I also ported it to Typescript to accommodate the heavy architectural changes I was starting to make. Since porting
|
||||
the library to typescript, and seeing the project explode in size and complexity, I consider this the best decision
|
||||
made with regards to this library so far.
|
||||
|
||||
Porting to typescript also afforded us a set of powerful features such as generics and static analysis that
|
||||
all the project contributors have made exclusive use of.
|
||||
|
||||
Typescript is <3 typescript is life.
|
||||
|
||||
### Why not Flow instead of Typescript?
|
||||
|
||||
At the time when I first started evaluating languages that could transpile to ECMAScript, I was not so sold
|
||||
on the supporting environment surrounding flow, and and found that there was better tooling to support
|
||||
typescript, they are ultimately trying to do the same thing though, and I guess in the end, typescript just made
|
||||
more sense.
|
||||
|
||||
### Why React ?
|
||||
|
||||
React is really efficient at rendering and managing HTML in a declarative manner. React has also become
|
||||
one of the bigger industry standards and has a rich eco system that plays really well with typescript.
|
||||
Apart from these notable points, I am really fond of React and wanted a diagramming library that takes full advantage of it,
|
||||
and makes it easy for engineers to use its power as well, when extending this library.
|
||||
|
||||
### Why cant the Default models and widgets do this or that ?
|
||||
|
||||
They are intended to illustrate __how__ to use this library and act as a good starting point
|
||||
to extend and show the capability. Ultimately I designed this library to be completely
|
||||
pluggable in a way that you can use it as a library and not a framework. If the default widgets
|
||||
are not good enough, then a good place to start is with creating your own models/factories/widgets.
|
||||
|
||||
### Model vs Widget
|
||||
|
||||
For those that are new to [Scene Graphs](https://en.wikipedia.org/wiki/Scene_graph) or are not familiar with concepts
|
||||
such as [MVC](https://en.wikipedia.org/wiki/Model–view–controller), this library represents your entire graph as a model.
|
||||
The model is a traversable graph that represents the nodes and links between them in a virtual manner. Your program (aka the business logic/layer)
|
||||
can mutate this model imperatively or store snapshots decoratively of the complete model (via serialization) and then the engine and react
|
||||
widgets will take care of the rendering. For this reason every model in the library is represented by a widget, and the factories glue it all together.
|
||||
|
||||
|
||||
### How do I make my own elements?
|
||||
|
||||
Take a look at the __demos__ directory, with specific attention to the __DefaultNodeWidget__
|
||||
|
||||
That being said, the demos directory is an _example_ of how you can create your own elements.
|
||||
A number of people want to use the defaults as is, which is cool,
|
||||
but is recommended to create your own models/factories/widgets.
|
||||
|
||||
### How do I use the library?
|
||||
|
||||
Take a look at the demo folders, they have simple and complex examples of the complete usage.
|
||||
|
||||
A good example of a real-world example is Demo 5
|
||||
142
docs/Getting Started.md
Normal file
@@ -0,0 +1,142 @@
|
||||
# Getting started
|
||||
|
||||
## Installation via NPM
|
||||
|
||||
The first thing you need to do, is grab the distribution files on NPM. You can do this either using yarn or npm
|
||||
|
||||
**Via yarn:**
|
||||
|
||||
```
|
||||
yarn install storm-react-diagrams
|
||||
```
|
||||
|
||||
**Via npm:**
|
||||
|
||||
```
|
||||
npm install storm-react-diagrams
|
||||
```
|
||||
|
||||
When you run this in your project directory, this will install the library into node\_modules/storm-react-diagrams. You will then find a dist folder that contains all the minified and production ready code.
|
||||
|
||||
This will also install React and a few other dependencies that you need in order to use this library.
|
||||
|
||||
## Including the library
|
||||
|
||||
When including the library you will need both the javascript files as well as the raw BEM styles. Both are included in the dist folder and there are numerous ways to integrate them into your project:
|
||||
|
||||
#### Getting the javascript files
|
||||
|
||||
**Using Typescript / ES6: \(recommended\)**
|
||||
|
||||
```js
|
||||
import * as SRD from "storm-react-diagrams"
|
||||
```
|
||||
|
||||
**Using RequireJS:**
|
||||
|
||||
```js
|
||||
var SRD = require("storm-react-diagrams)
|
||||
```
|
||||
|
||||
**As a script tag \(not recommended\)**
|
||||
|
||||
```html
|
||||
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
|
||||
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
|
||||
<script src="node_modules/storm-react-diagrams/dist/main.js">
|
||||
```
|
||||
|
||||
#### Getting the CSS
|
||||
|
||||
**Using RequireJS / Typescript/ ES6 \(recommended\)**
|
||||
|
||||
Make sure you have the style-loader enabled and then:
|
||||
|
||||
```js
|
||||
require("storm-react-diagrams/dist/style.min.css");
|
||||
```
|
||||
|
||||
or make sure you have the sass-loader enabled and then:
|
||||
|
||||
```js
|
||||
require("storm-react-diagrams/src/sass/main.scss");
|
||||
```
|
||||
|
||||
If you are using typescript and get a "require function not found" then make sure to
|
||||
|
||||
```
|
||||
yarn add @types/node
|
||||
```
|
||||
|
||||
which will give you the typescript definition files for requireJS
|
||||
|
||||
**Using SASS:**
|
||||
|
||||
setup your include paths on webpack or lib sass using the following option
|
||||
|
||||
```
|
||||
includePaths: ["node_modules"]
|
||||
```
|
||||
|
||||
and then if you want the raw sass source code:
|
||||
|
||||
```sass
|
||||
@import "~storm-react-diagrams/src/sass/main";
|
||||
```
|
||||
|
||||
or if you want the minified css
|
||||
|
||||
```sass
|
||||
@import "~storm-react-diagrams/dist/style.min";
|
||||
```
|
||||
|
||||
**Using a style tag**
|
||||
|
||||
or if you want the minified css
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="node_modules/dist/style.min.css">
|
||||
```
|
||||
|
||||
## Render your first diagram
|
||||
|
||||
In your library code
|
||||
|
||||
```js
|
||||
// 1) setup the diagram engine
|
||||
var engine = new SRD.DiagramEngine();
|
||||
engine.installDefaultFactories();
|
||||
|
||||
// 2) setup the diagram model
|
||||
var model = new SRD.DiagramModel();
|
||||
|
||||
// 3) create a default node
|
||||
var node1 = new SRD.DefaultNodeModel("Node 1", "rgb(0,192,255)");
|
||||
let port1 = node1.addOutPort("Out");
|
||||
node1.setPosition(100, 100);
|
||||
|
||||
// 4) create another default node
|
||||
var node2 = new SRD.DefaultNodeModel("Node 2", "rgb(192,255,0)");
|
||||
let port2 = node2.addInPort("In");
|
||||
node2.setPosition(400, 100);
|
||||
|
||||
// 5) link the ports
|
||||
let link1 = port1.link(port2);
|
||||
|
||||
// 6) add the models to the root graph
|
||||
model.addAll(node1, node2, link1);
|
||||
|
||||
// 7) load model into engine
|
||||
engine.setDiagramModel(model);
|
||||
```
|
||||
|
||||
And then create an instance of the diagram widget. An example of the simplest possible react widget to do this would be:
|
||||
|
||||
```jsx
|
||||
function SimpleDiagramWidget(props) {
|
||||
return <SRD.DiagramWidget diagramEngine={props.engine} />;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
22
docs/Interactive Usage.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# End user usage
|
||||
|
||||
__Delete__ removes any selected items
|
||||

|
||||
|
||||
__Shift + Mouse Drag__ triggers a multi-selection box
|
||||

|
||||
|
||||
__Shift + Mouse Click__ selects the item (items can be multi-selected)
|
||||

|
||||
|
||||
__Mouse Drag__ drags the entire diagram
|
||||

|
||||
|
||||
__Mouse Wheel__ zooms the diagram in / out
|
||||

|
||||
|
||||
__Click Link + Drag__ creates a new link point
|
||||

|
||||
|
||||
__Click Node Port + Drag__ creates a new link
|
||||

|
||||
33
docs/Testing.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Testing
|
||||
|
||||
STORM React diagrams is tested two main ways.
|
||||
|
||||
## JEST Snapshot testing
|
||||
|
||||
With Jest snapshots, we render all the demos in the demo folder by automatically
|
||||
looking into each `demo-*` folder and searching for an __index.tsx__ file.
|
||||
|
||||
For each file we find, we dynamically include it as a storybook story and assemble one big test.
|
||||
This test then renders each demo in a deterministic way and compares it to the snapshot file
|
||||
situated in __snapshots__. If the snapshots don't match, then something has changed and either the snapshot
|
||||
needs to be updated, or the test is failing in which case we need to fix the code.
|
||||
|
||||
Snapshot testing does not test the functionality of the program but it is a first important step
|
||||
to make sure that changes aren't having a drastic effect on the overall system.
|
||||
|
||||
In the event that the snapshot needs to be updated, please run `yarn run test -u` to overwrite
|
||||
the snapshot file, and then make sure to your branch.
|
||||
|
||||
## End to end testing
|
||||
|
||||
To test the functionality of the library, we make use of e2e tests (end to end tests).
|
||||
In this library, we spin up a headless chrome using pupeteer and interactively and programmatically
|
||||
tell the mouse pointer to click and drag on various elements while making assertions along the way.
|
||||
|
||||
We use Jest for the assertions and the interactivity is handled by puppeteer. Due to the laborious nature
|
||||
of writing e2e tests, there is a helper method that is provided in each test that makes interacting
|
||||
with the diagrams a lot easier. Using this helper, you cna easily tell the mouse to drag links between nodes,
|
||||
select them and also easily assert information about them. The important thing here, is that this helper
|
||||
does not touch the model in any way, but is purely a helper for writing the tests themselves. Please
|
||||
make use of this helper when writing tests, as it ensure that the tests are defensive in nature, and also
|
||||
reduces the overhead of physically writing them.
|
||||
BIN
images/canvasDrag.gif
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
images/createLink.gif
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
images/createPoint.gif
Normal file
|
After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
BIN
images/example1.jpg
Normal file
|
After Width: | Height: | Size: 438 KiB |
BIN
images/example2.jpg
Normal file
|
After Width: | Height: | Size: 313 KiB |
BIN
images/example3.jpg
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
images/example3.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
images/mouseDrag.gif
Normal file
|
After Width: | Height: | Size: 354 KiB |
BIN
images/mouseWheel.gif
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
images/rjdDelete.gif
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
images/shiftClick.gif
Normal file
|
After Width: | Height: | Size: 113 KiB |
27
jest.config.js
Normal file
@@ -0,0 +1,27 @@
|
||||
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"
|
||||
]
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
auxiliary.org-netbeans-modules-css-prep.sass_2e_compiler_2e_options=
|
||||
auxiliary.org-netbeans-modules-css-prep.sass_2e_configured=true
|
||||
auxiliary.org-netbeans-modules-css-prep.sass_2e_enabled=false
|
||||
auxiliary.org-netbeans-modules-css-prep.sass_2e_mappings=/scss:/css
|
||||
files.encoding=UTF-8
|
||||
site.root.folder=
|
||||
source.folder=
|
||||