mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-16 06:49:31 +02:00
Compare commits
653 Commits
@mermaid-j
...
5824-diff-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4693aa2749 | ||
![]() |
468b6a55b6 | ||
![]() |
df636c6d0a | ||
![]() |
64554a6c60 | ||
![]() |
becadf0a7d | ||
![]() |
54d485f173 | ||
![]() |
b4f5b8ddaf | ||
![]() |
cb5c1ae367 | ||
![]() |
b29081d4e8 | ||
![]() |
654097c438 | ||
![]() |
1e672868c4 | ||
![]() |
c7880d7281 | ||
![]() |
bff32827b5 | ||
![]() |
f27ca07371 | ||
![]() |
65f9b29b86 | ||
![]() |
9868f3a4c3 | ||
![]() |
b4879d13b8 | ||
![]() |
95964b5487 | ||
![]() |
4e17da0a30 | ||
![]() |
d8bf155f0e | ||
![]() |
0b4f85230a | ||
![]() |
0dff4ca438 | ||
![]() |
cc29437ede | ||
![]() |
dfaaf361f3 | ||
![]() |
37538310d3 | ||
![]() |
c7ae08abc3 | ||
![]() |
69973eaa02 | ||
![]() |
d3b2c7ea18 | ||
![]() |
68f41f685d | ||
![]() |
255279eb22 | ||
![]() |
fe3cffbb67 | ||
![]() |
2a91849a38 | ||
![]() |
082de76eef | ||
![]() |
570ae78b15 | ||
![]() |
885ac6f947 | ||
![]() |
8328f74751 | ||
![]() |
01b5079562 | ||
![]() |
6b23647bec | ||
![]() |
193fdb225e | ||
![]() |
c8ce416aba | ||
![]() |
1388662132 | ||
![]() |
757627427b | ||
![]() |
7cbd80af33 | ||
![]() |
16c448b89b | ||
![]() |
c218e365bd | ||
![]() |
f507dbbe00 | ||
![]() |
9966beb99b | ||
![]() |
f4713332c0 | ||
![]() |
63ff5b1d98 | ||
![]() |
cb0a4703bd | ||
![]() |
7e71b85668 | ||
![]() |
1dd7bcb0a6 | ||
![]() |
bbf6ab1206 | ||
![]() |
56f522ec50 | ||
![]() |
d4e5acc530 | ||
![]() |
ef9cbb61e5 | ||
![]() |
8a0ecc1fe9 | ||
![]() |
c6e1271ef7 | ||
![]() |
b02294376a | ||
![]() |
97c61d818c | ||
![]() |
1c66237fa8 | ||
![]() |
8ef5d324fd | ||
![]() |
c1ca3511c4 | ||
![]() |
953d288957 | ||
![]() |
143806b360 | ||
![]() |
a381ab6c41 | ||
![]() |
93e20fdaa3 | ||
![]() |
ece3b254db | ||
![]() |
dd42305e8c | ||
![]() |
c34fd152d5 | ||
![]() |
8f0e0b9c39 | ||
![]() |
fe8932e906 | ||
![]() |
73bbde8476 | ||
![]() |
01a41ef530 | ||
![]() |
124d2f72dd | ||
![]() |
34e8946c58 | ||
![]() |
0197c08916 | ||
![]() |
ef30283fe9 | ||
![]() |
dffaf9fa8f | ||
![]() |
9168d5d1f4 | ||
![]() |
f33ebfaf7a | ||
![]() |
054f929150 | ||
![]() |
8cb1c68166 | ||
![]() |
d752240efc | ||
![]() |
8d0902de4c | ||
![]() |
f6c32b6da4 | ||
![]() |
bdf145ffe3 | ||
![]() |
75ca802b62 | ||
![]() |
3f85b6179d | ||
![]() |
b315d70af5 | ||
![]() |
848be3d129 | ||
![]() |
5fabd414fb | ||
![]() |
17e2f9e0d4 | ||
![]() |
7fa8b35bdc | ||
![]() |
e6ea4eae50 | ||
![]() |
7401cb8f6a | ||
![]() |
e765007b21 | ||
![]() |
b5cd101d86 | ||
![]() |
da12ace593 | ||
![]() |
2c676b6222 | ||
![]() |
0af08276d2 | ||
![]() |
d790e353b0 | ||
![]() |
e07e9b9daf | ||
![]() |
948ec4d1ce | ||
![]() |
e62d268c89 | ||
![]() |
742ad7c130 | ||
![]() |
56cc3728c5 | ||
![]() |
fb86e5c689 | ||
![]() |
f8746bee04 | ||
![]() |
bb97fdbd1e | ||
![]() |
e3ec6ed993 | ||
![]() |
6df1fa1a03 | ||
![]() |
fd6b875f87 | ||
![]() |
be3da0b39d | ||
![]() |
64bc7f4bd9 | ||
![]() |
75e796f183 | ||
![]() |
6cc0132e0a | ||
![]() |
4bc70b7325 | ||
![]() |
bfdd0f244d | ||
![]() |
0e819ae050 | ||
![]() |
10f11e016f | ||
![]() |
b7d66bb975 | ||
![]() |
74695d2e88 | ||
![]() |
38eed7c988 | ||
![]() |
d16e46a386 | ||
![]() |
97820a50c2 | ||
![]() |
df948bcf2c | ||
![]() |
cfd097b029 | ||
![]() |
ffc1fef599 | ||
![]() |
1e8e4e4b73 | ||
![]() |
606ecf8990 | ||
![]() |
16a5fc05d6 | ||
![]() |
62fd359c0e | ||
![]() |
b0f4ace3a1 | ||
![]() |
6f506c30eb | ||
![]() |
cf2c7f7f8c | ||
![]() |
6041729ae2 | ||
![]() |
b7ef8b2b5a | ||
![]() |
bfea287b44 | ||
![]() |
9afb181d06 | ||
![]() |
cfe7cce41d | ||
![]() |
33029c8bd2 | ||
![]() |
e54d10c706 | ||
![]() |
86c7532f46 | ||
![]() |
8aa87c7091 | ||
![]() |
e1024838e8 | ||
![]() |
4cce43f0a1 | ||
![]() |
c69ab34eac | ||
![]() |
7353be3b16 | ||
![]() |
02be63ed72 | ||
![]() |
742531a2c2 | ||
![]() |
991d403d7f | ||
![]() |
290c678dc7 | ||
![]() |
2c31a599af | ||
![]() |
2655be0bad | ||
![]() |
4f97c8c70e | ||
![]() |
f85977246c | ||
![]() |
a4fd42214b | ||
![]() |
ca885027d4 | ||
![]() |
9f6f1e96e5 | ||
![]() |
351ce30d8a | ||
![]() |
2933eb5c28 | ||
![]() |
09ecf76034 | ||
![]() |
2b86750cb3 | ||
![]() |
b45224755e | ||
![]() |
14524e1b0e | ||
![]() |
efa47e3176 | ||
![]() |
1bc45405e0 | ||
![]() |
3720e1a894 | ||
![]() |
76138cf3b9 | ||
![]() |
2506c29f6b | ||
![]() |
463ba6ed6d | ||
![]() |
17b783135f | ||
![]() |
8df2729bd4 | ||
![]() |
a001619464 | ||
![]() |
3c5a19d297 | ||
![]() |
a98290a6e2 | ||
![]() |
9bac464442 | ||
![]() |
11fb806992 | ||
![]() |
d424a4473a | ||
![]() |
4062813d44 | ||
![]() |
29b9d3069b | ||
![]() |
c38d9a6620 | ||
![]() |
2f65429aa4 | ||
![]() |
c24028f2a4 | ||
![]() |
a20c292653 | ||
![]() |
1c6304b3fb | ||
![]() |
3ac93af80c | ||
![]() |
ce586e1b31 | ||
![]() |
926f97124b | ||
![]() |
0f2301f2d6 | ||
![]() |
58e8f65135 | ||
![]() |
1b51fbfcca | ||
![]() |
1296840696 | ||
![]() |
f99e2c9366 | ||
![]() |
c71b56ebe3 | ||
![]() |
9904afce64 | ||
![]() |
a827fb1202 | ||
![]() |
51be99c9de | ||
![]() |
b83b778f2a | ||
![]() |
86a91597f9 | ||
![]() |
1b12ac133e | ||
![]() |
e55880a9c4 | ||
![]() |
9cc309b69c | ||
![]() |
d3308232e8 | ||
![]() |
0b8f27e1d2 | ||
![]() |
93f2c241b8 | ||
![]() |
fb44e769f2 | ||
![]() |
fabdfd9ae8 | ||
![]() |
72d60d2633 | ||
![]() |
2d7686eb65 | ||
![]() |
d9a26ff193 | ||
![]() |
2401eea725 | ||
![]() |
ddf18dd233 | ||
![]() |
4b98dabc3f | ||
![]() |
5a3e0ccc3d | ||
![]() |
38a3ad3370 | ||
![]() |
b777c12094 | ||
![]() |
8fc36d2684 | ||
![]() |
e2474049d8 | ||
![]() |
6e0fe03552 | ||
![]() |
cda48a7143 | ||
![]() |
e5a28de26e | ||
![]() |
0ae4f97036 | ||
![]() |
218bfe1603 | ||
![]() |
339c670839 | ||
![]() |
c5a19f6e85 | ||
![]() |
be57484573 | ||
![]() |
0cb88c21dc | ||
![]() |
0bc1f5296f | ||
![]() |
4776f97f82 | ||
![]() |
460db0aea7 | ||
![]() |
02cf111995 | ||
![]() |
14d9d92112 | ||
![]() |
fce77a19b0 | ||
![]() |
719685b930 | ||
![]() |
0cbc000bfa | ||
![]() |
ef8c0025fd | ||
![]() |
16847ea06c | ||
![]() |
be0bbe9950 | ||
![]() |
b503c2c758 | ||
![]() |
1d14f4658d | ||
![]() |
c7382af161 | ||
![]() |
f6adca902f | ||
![]() |
d50a6cf75c | ||
![]() |
2cebf09cf2 | ||
![]() |
46419f7bfe | ||
![]() |
43e8f831c0 | ||
![]() |
760ea1e020 | ||
![]() |
07d7704ef4 | ||
![]() |
a4878d05f0 | ||
![]() |
c5bcd2f22c | ||
![]() |
df1fba7fc5 | ||
![]() |
bb521f7af8 | ||
![]() |
f9818b8bd7 | ||
![]() |
dfcb4af18b | ||
![]() |
5c67e42a55 | ||
![]() |
7441be09b5 | ||
![]() |
a75665c7bf | ||
![]() |
4cb0f87b72 | ||
![]() |
1e8cd63645 | ||
![]() |
3860a99951 | ||
![]() |
226b3bfa74 | ||
![]() |
a5559c6588 | ||
![]() |
de2c05cd54 | ||
![]() |
6d916fb66f | ||
![]() |
90b6df24a1 | ||
![]() |
3e807e0131 | ||
![]() |
e2e2caa0e9 | ||
![]() |
b3dee343d1 | ||
![]() |
608f7afa70 | ||
![]() |
58ef0ee174 | ||
![]() |
2a76dc6409 | ||
![]() |
91e3da1293 | ||
![]() |
fa46267c14 | ||
![]() |
dc7e32eb10 | ||
![]() |
10679297f9 | ||
![]() |
3e697e2ea4 | ||
![]() |
6a649d347d | ||
![]() |
fd372941c7 | ||
![]() |
1c8c95367d | ||
![]() |
f031abcec2 | ||
![]() |
dd62322ae5 | ||
![]() |
48e5dee963 | ||
![]() |
b3dfc60fff | ||
![]() |
bb3b95f0bd | ||
![]() |
4fc9028dc1 | ||
![]() |
02cadd87ff | ||
![]() |
1c105154a6 | ||
![]() |
daaeded0b5 | ||
![]() |
ed7d41a3cb | ||
![]() |
f052a3f686 | ||
![]() |
11da07b735 | ||
![]() |
d01e180caf | ||
![]() |
4c400966b4 | ||
![]() |
bd0a00d373 | ||
![]() |
3b8bd6b979 | ||
![]() |
f849c36942 | ||
![]() |
c83fc753a1 | ||
![]() |
eeeb5fcdd9 | ||
![]() |
41f22864b4 | ||
![]() |
6a99a1a40a | ||
![]() |
1fcebab9ed | ||
![]() |
bed301a485 | ||
![]() |
31546b08ff | ||
![]() |
25337dc453 | ||
![]() |
cb85d50f61 | ||
![]() |
a52949318a | ||
![]() |
745495c2d5 | ||
![]() |
dd261a54df | ||
![]() |
94d2a0ee89 | ||
![]() |
f035db2feb | ||
![]() |
b105c7b35e | ||
![]() |
149f991c1d | ||
![]() |
a43ee60942 | ||
![]() |
5f11cd417f | ||
![]() |
3782b69744 | ||
![]() |
ca93280b17 | ||
![]() |
2ec9f0af2e | ||
![]() |
3eb338df04 | ||
![]() |
b7790ba6b5 | ||
![]() |
b67c931f18 | ||
![]() |
97186504b5 | ||
![]() |
bd4ca9af1b | ||
![]() |
9ac20a5cb8 | ||
![]() |
20a58d6dbb | ||
![]() |
191e4217fc | ||
![]() |
8745daa701 | ||
![]() |
27f7b615cc | ||
![]() |
e3c426de86 | ||
![]() |
c6410472c8 | ||
![]() |
d807466780 | ||
![]() |
c8b9c4cebc | ||
![]() |
741072a126 | ||
![]() |
be9123ee2b | ||
![]() |
3f5afe8daf | ||
![]() |
522de3abd8 | ||
![]() |
d37d77cc1a | ||
![]() |
4740be6562 | ||
![]() |
a07f1f3337 | ||
![]() |
02851fd672 | ||
![]() |
233e36c988 | ||
![]() |
2b12a658f6 | ||
![]() |
b74842ceb3 | ||
![]() |
ca84f7d4a9 | ||
![]() |
1892277273 | ||
![]() |
f12df395f8 | ||
![]() |
89e82e4d97 | ||
![]() |
af2340d889 | ||
![]() |
775a6381b4 | ||
![]() |
38c6ad5ad6 | ||
![]() |
d63dc319c7 | ||
![]() |
c5539e0aa0 | ||
![]() |
14601b7871 | ||
![]() |
7a86fd7b44 | ||
![]() |
0b3522894a | ||
![]() |
aa0836aecc | ||
![]() |
78f9238865 | ||
![]() |
5ca4fccbb0 | ||
![]() |
7f2044024b | ||
![]() |
d2de9702c5 | ||
![]() |
92a8783d95 | ||
![]() |
4bd1e5c524 | ||
![]() |
10826055f3 | ||
![]() |
6cf050e6e5 | ||
![]() |
52e1a36ffe | ||
![]() |
e83a95d3ed | ||
![]() |
44561f57d3 | ||
![]() |
4c26fe224b | ||
![]() |
61af74609a | ||
![]() |
9f2f3bd780 | ||
![]() |
38bcbcdd0a | ||
![]() |
d8c340d9c5 | ||
![]() |
8456d7b100 | ||
![]() |
2fa044d484 | ||
![]() |
4162a25425 | ||
![]() |
e26a38b619 | ||
![]() |
92aa2859a0 | ||
![]() |
1d8f524913 | ||
![]() |
59991b70a1 | ||
![]() |
a6b877676e | ||
![]() |
3c49c00f2b | ||
![]() |
c97716e780 | ||
![]() |
355e218837 | ||
![]() |
a3145a32e7 | ||
![]() |
8b6fb94835 | ||
![]() |
83ea81d975 | ||
![]() |
aae9db92ee | ||
![]() |
6c5b7ce9f4 | ||
![]() |
8bb70ea493 | ||
![]() |
bff9f65c88 | ||
![]() |
88607e8aa0 | ||
![]() |
17c6ed6303 | ||
![]() |
bfd8c63daa | ||
![]() |
6de7f1b088 | ||
![]() |
3359d87115 | ||
![]() |
e8fdc965a2 | ||
![]() |
67bcd3e0d6 | ||
![]() |
9421f63775 | ||
![]() |
01bf7af360 | ||
![]() |
4754ed01ab | ||
![]() |
a2c262f940 | ||
![]() |
7963ad9b20 | ||
![]() |
5e34810335 | ||
![]() |
e44eb5258b | ||
![]() |
e564c395ba | ||
![]() |
3d1af09090 | ||
![]() |
1cc2f323de | ||
![]() |
194684e27b | ||
![]() |
ee17e020cf | ||
![]() |
2b8ef765e7 | ||
![]() |
dbe965303b | ||
![]() |
3d9e919545 | ||
![]() |
30eb02510b | ||
![]() |
06aa72ec16 | ||
![]() |
cf45a35971 | ||
![]() |
a601d3bccf | ||
![]() |
f46a135458 | ||
![]() |
82cc473801 | ||
![]() |
9c41708d9e | ||
![]() |
a51d3aa2ad | ||
![]() |
797d72b716 | ||
![]() |
dd0304387e | ||
![]() |
80903ec281 | ||
![]() |
1f373c8430 | ||
![]() |
02d3bec856 | ||
![]() |
e111965411 | ||
![]() |
41cf1262b2 | ||
![]() |
ddb51cdcbc | ||
![]() |
d053284536 | ||
![]() |
acc1e500d3 | ||
![]() |
c0187101e9 | ||
![]() |
303f1f4545 | ||
![]() |
750f58d7db | ||
![]() |
e5532c3418 | ||
![]() |
a881d46178 | ||
![]() |
edb99c2842 | ||
![]() |
4d04d1a8c3 | ||
![]() |
1d1766b5c3 | ||
![]() |
0ade03c4de | ||
![]() |
2aa5089930 | ||
![]() |
2259a59ac6 | ||
![]() |
d8d56df272 | ||
![]() |
ec29f749af | ||
![]() |
1951a0cdc8 | ||
![]() |
cc61629a8c | ||
![]() |
5e75320d49 | ||
![]() |
b830e6151b | ||
![]() |
fd3c3fc022 | ||
![]() |
94deacb1b5 | ||
![]() |
571dfda629 | ||
![]() |
6a3f1d194a | ||
![]() |
e5aebf3df6 | ||
![]() |
c95a0c7de4 | ||
![]() |
bf9842000f | ||
![]() |
35c08985ee | ||
![]() |
ba95f394a3 | ||
![]() |
2879f3775b | ||
![]() |
f7be983199 | ||
![]() |
58524aceaa | ||
![]() |
ab25e9ea7d | ||
![]() |
57d2d905ef | ||
![]() |
64abf29ea8 | ||
![]() |
73147196b1 | ||
![]() |
c895109497 | ||
![]() |
145acd0ee4 | ||
![]() |
4c43d21196 | ||
![]() |
b4941aa4ce | ||
![]() |
aa259e03f2 | ||
![]() |
0d7aaae0ff | ||
![]() |
9467735fab | ||
![]() |
9e3aa705ae | ||
![]() |
0f8cc48d03 | ||
![]() |
95bd5dfdab | ||
![]() |
e6ce370cdd | ||
![]() |
78346cbe84 | ||
![]() |
9a953f7f80 | ||
![]() |
14bb09a3db | ||
![]() |
89fb65913d | ||
![]() |
41a75005c8 | ||
![]() |
54ecd7d423 | ||
![]() |
352194c942 | ||
![]() |
30e4ab99d9 | ||
![]() |
5f0160c036 | ||
![]() |
443c886050 | ||
![]() |
b7fd21e17a | ||
![]() |
2f24f6271a | ||
![]() |
6507624232 | ||
![]() |
e337331122 | ||
![]() |
1d5f7ce08f | ||
![]() |
adedb5f803 | ||
![]() |
9774c08336 | ||
![]() |
525dcd4760 | ||
![]() |
d75661e49d | ||
![]() |
52d6035c23 | ||
![]() |
5a9221680f | ||
![]() |
3a5fef3e50 | ||
![]() |
8883008ca1 | ||
![]() |
0eec89255f | ||
![]() |
3d4c5d1a41 | ||
![]() |
826faad37b | ||
![]() |
c078840c63 | ||
![]() |
105b11fca2 | ||
![]() |
a259aeba27 | ||
![]() |
8462f21c01 | ||
![]() |
5d3a175ed6 | ||
![]() |
69bec16080 | ||
![]() |
bfc4abeae2 | ||
![]() |
cd67fdf89d | ||
![]() |
958fb6da2b | ||
![]() |
a6dbf0a9ee | ||
![]() |
31b4ec3e10 | ||
![]() |
f7e4ee61c7 | ||
![]() |
8e0bb994bb | ||
![]() |
b56fe796d6 | ||
![]() |
7156cf4c71 | ||
![]() |
426d311faa | ||
![]() |
55aff88e9f | ||
![]() |
336c3127ed | ||
![]() |
0b672e2636 | ||
![]() |
6209165b32 | ||
![]() |
f3bb5c0c26 | ||
![]() |
9cb09f1fb4 | ||
![]() |
cfeb794b34 | ||
![]() |
1b7433b637 | ||
![]() |
73f8d70b86 | ||
![]() |
6a97f80cc3 | ||
![]() |
3e922c83f0 | ||
![]() |
a45588ce7c | ||
![]() |
a176d64389 | ||
![]() |
e519686f01 | ||
![]() |
59d6f04e4b | ||
![]() |
f4d4c784e4 | ||
![]() |
eb341bdfb6 | ||
![]() |
ee84ed4236 | ||
![]() |
f27feb268a | ||
![]() |
56e9095619 | ||
![]() |
b3495219ae | ||
![]() |
71753671e0 | ||
![]() |
9746497673 | ||
![]() |
882a2cc63e | ||
![]() |
f29f5eb207 | ||
![]() |
600247df79 | ||
![]() |
8fa1fed8b5 | ||
![]() |
63e9194c5d | ||
![]() |
06310faa32 | ||
![]() |
c9c821da5c | ||
![]() |
c2c65b4df2 | ||
![]() |
9b7f5ed963 | ||
![]() |
75f755b823 | ||
![]() |
1cfe987fa1 | ||
![]() |
4cf7c97b8f | ||
![]() |
3715254a78 | ||
![]() |
ab44053ba4 | ||
![]() |
5c6f3e66a6 | ||
![]() |
5e5265c8b0 | ||
![]() |
13719aa694 | ||
![]() |
9d9109a68c | ||
![]() |
cb91c3f8a8 | ||
![]() |
c08fad6487 | ||
![]() |
23329f1ee9 | ||
![]() |
e842b72aaa | ||
![]() |
7c26148252 | ||
![]() |
7d6a97e264 | ||
![]() |
99f7d65f47 | ||
![]() |
db1db1ab0e | ||
![]() |
cec28464ec | ||
![]() |
a2fba0284e | ||
![]() |
f424a51133 | ||
![]() |
46b8faddae | ||
![]() |
19cce07ab5 | ||
![]() |
439dcb10b2 | ||
![]() |
98cb8b998e | ||
![]() |
1654a4b01c | ||
![]() |
8e72611922 | ||
![]() |
a857d3807f | ||
![]() |
3dc0af3159 | ||
![]() |
abf7ecd2ca | ||
![]() |
8d8b6c1c33 | ||
![]() |
262790b22d | ||
![]() |
4e8a7e0b4c | ||
![]() |
121e27e850 | ||
![]() |
0152ed7027 | ||
![]() |
f233bfd75e | ||
![]() |
4298a57297 | ||
![]() |
6e8ea148bc | ||
![]() |
777522e8d5 | ||
![]() |
a4007ffb80 | ||
![]() |
de875c9e27 | ||
![]() |
3cfcb2da41 | ||
![]() |
4c3db653f5 | ||
![]() |
90b7a3be63 | ||
![]() |
0fbe5f2f10 | ||
![]() |
36f2989249 | ||
![]() |
99956b4283 | ||
![]() |
9c5a8f7ef1 | ||
![]() |
e2f3041aa2 | ||
![]() |
9926ae4e74 | ||
![]() |
58463b5e80 | ||
![]() |
7b51327b24 | ||
![]() |
06dd350aab | ||
![]() |
4f2085765d | ||
![]() |
eceae9b64c | ||
![]() |
98754b9fc6 | ||
![]() |
f813870e7d | ||
![]() |
763a0c0d83 | ||
![]() |
d30444dae7 | ||
![]() |
c983c0605e | ||
![]() |
2fa03ea369 | ||
![]() |
6c1ae90972 | ||
![]() |
a17e7d92d9 | ||
![]() |
b3a4e3f40e | ||
![]() |
b7acf94b41 | ||
![]() |
9e5c3ec1b5 | ||
![]() |
5550753193 | ||
![]() |
394c6aea74 | ||
![]() |
3febd7dfdf | ||
![]() |
ef895a3d8c | ||
![]() |
8f5f7fc2a8 | ||
![]() |
c673cf22bd | ||
![]() |
4d401c127d | ||
![]() |
3c119e4a52 | ||
![]() |
303a160359 | ||
![]() |
3cd5244949 | ||
![]() |
31b8707819 | ||
![]() |
a0893b8e6c | ||
![]() |
e1c8eb8a72 | ||
![]() |
bc546ef562 | ||
![]() |
251b94647b | ||
![]() |
4aeb2ae9a2 | ||
![]() |
0f635ed344 | ||
![]() |
efe6affe64 | ||
![]() |
f140d1ab45 | ||
![]() |
89e4de1dd0 | ||
![]() |
ac48f01e25 | ||
![]() |
4c48b8cc54 | ||
![]() |
b807e330c8 | ||
![]() |
04b15e7ece | ||
![]() |
575c39e8a5 | ||
![]() |
933f3f391c | ||
![]() |
cfb5b88ee6 | ||
![]() |
9cd44eb92c | ||
![]() |
d0942d4897 | ||
![]() |
3d789a0675 | ||
![]() |
1d3f214109 | ||
![]() |
e51077c765 | ||
![]() |
809fc1ce30 | ||
![]() |
f176b71c7c | ||
![]() |
4d8e519298 | ||
![]() |
958204e831 | ||
![]() |
82c247bb11 | ||
![]() |
2a56b640c0 | ||
![]() |
eae67a9696 |
@@ -1,3 +1,9 @@
|
||||
export interface PackageOptions {
|
||||
name: string;
|
||||
packageName: string;
|
||||
file: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared common options for both ESBuild and Vite
|
||||
*/
|
||||
@@ -27,4 +33,4 @@ export const packageOptions = {
|
||||
packageName: 'mermaid-layout-elk',
|
||||
file: 'layouts.ts',
|
||||
},
|
||||
} as const;
|
||||
} as const satisfies Record<string, PackageOptions>;
|
||||
|
@@ -19,6 +19,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
|
||||
'xyChart',
|
||||
'requirement',
|
||||
'mindmap',
|
||||
'kanban',
|
||||
'timeline',
|
||||
'gitGraph',
|
||||
'c4',
|
||||
|
5
.changeset/angry-bags-brake.md
Normal file
5
.changeset/angry-bags-brake.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: architecture diagrams no longer grow to extreme heights due to conflicting alignments
|
5
.changeset/gold-ducks-sort.md
Normal file
5
.changeset/gold-ducks-sort.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'mermaid': patch
|
||||
---
|
||||
|
||||
fix: Proper separation between strings and markdown strings
|
@@ -26,6 +26,7 @@ concat
|
||||
controlx
|
||||
controly
|
||||
CSSCLASS
|
||||
curv
|
||||
CYLINDEREND
|
||||
CYLINDERSTART
|
||||
DAGA
|
||||
|
@@ -28,6 +28,9 @@ dictionaryDefinitions:
|
||||
- name: suggestions
|
||||
words:
|
||||
- none
|
||||
- disp
|
||||
- subproc
|
||||
- tria
|
||||
suggestWords:
|
||||
- seperator:separator
|
||||
- vertice:vertex
|
||||
|
@@ -5,12 +5,14 @@ bmatrix
|
||||
braintree
|
||||
catmull
|
||||
compositTitleSize
|
||||
curv
|
||||
doublecircle
|
||||
elems
|
||||
gantt
|
||||
gitgraph
|
||||
gzipped
|
||||
handDrawn
|
||||
kanban
|
||||
knsv
|
||||
Knut
|
||||
marginx
|
||||
@@ -24,6 +26,7 @@ multigraph
|
||||
nodesep
|
||||
NOTEGROUP
|
||||
Pinterest
|
||||
procs
|
||||
rankdir
|
||||
ranksep
|
||||
rect
|
||||
|
@@ -8,7 +8,10 @@ import { defaultOptions, getBuildConfig } from './util.js';
|
||||
const shouldVisualize = process.argv.includes('--visualize');
|
||||
|
||||
const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
||||
const commonOptions: MermaidBuildOptions = { ...defaultOptions, entryName } as const;
|
||||
const commonOptions: MermaidBuildOptions = {
|
||||
...defaultOptions,
|
||||
options: packageOptions[entryName],
|
||||
} as const;
|
||||
const buildConfigs: MermaidBuildOptions[] = [
|
||||
// package.mjs
|
||||
{ ...commonOptions },
|
||||
@@ -40,7 +43,7 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
|
||||
continue;
|
||||
}
|
||||
const fileName = Object.keys(metafile.outputs)
|
||||
.find((file) => !file.includes('chunks') && file.endsWith('js'))
|
||||
.find((file) => !file.includes('chunks') && file.endsWith('js'))!
|
||||
.replace('dist/', '');
|
||||
// Upload metafile into https://esbuild.github.io/analyze/
|
||||
await writeFile(`stats/${fileName}.meta.json`, JSON.stringify(metafile));
|
||||
|
@@ -9,13 +9,18 @@ import { generateLangium } from '../.build/generateLangium.js';
|
||||
import { defaultOptions, getBuildConfig } from './util.js';
|
||||
|
||||
const configs = Object.values(packageOptions).map(({ packageName }) =>
|
||||
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: packageName })
|
||||
getBuildConfig({
|
||||
...defaultOptions,
|
||||
minify: false,
|
||||
core: false,
|
||||
options: packageOptions[packageName],
|
||||
})
|
||||
);
|
||||
const mermaidIIFEConfig = getBuildConfig({
|
||||
...defaultOptions,
|
||||
minify: false,
|
||||
core: false,
|
||||
entryName: 'mermaid',
|
||||
options: packageOptions.mermaid,
|
||||
format: 'iife',
|
||||
});
|
||||
configs.push(mermaidIIFEConfig);
|
||||
|
@@ -3,7 +3,7 @@ import { fileURLToPath } from 'url';
|
||||
import type { BuildOptions } from 'esbuild';
|
||||
import { readFileSync } from 'fs';
|
||||
import jsonSchemaPlugin from './jsonSchemaPlugin.js';
|
||||
import { packageOptions } from '../.build/common.js';
|
||||
import type { PackageOptions } from '../.build/common.js';
|
||||
import { jisonPlugin } from './jisonPlugin.js';
|
||||
|
||||
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
||||
@@ -13,10 +13,10 @@ export interface MermaidBuildOptions extends BuildOptions {
|
||||
core: boolean;
|
||||
metafile: boolean;
|
||||
format: 'esm' | 'iife';
|
||||
entryName: keyof typeof packageOptions;
|
||||
options: PackageOptions;
|
||||
}
|
||||
|
||||
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName'> = {
|
||||
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
|
||||
minify: false,
|
||||
metafile: false,
|
||||
core: false,
|
||||
@@ -52,9 +52,14 @@ const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOpt
|
||||
};
|
||||
|
||||
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
|
||||
const { core, entryName, metafile, format, minify } = options;
|
||||
const {
|
||||
core,
|
||||
metafile,
|
||||
format,
|
||||
minify,
|
||||
options: { name, file, packageName },
|
||||
} = options;
|
||||
const external: string[] = ['require', 'fs', 'path'];
|
||||
const { name, file, packageName } = packageOptions[entryName];
|
||||
const outFileName = getFileName(name, options);
|
||||
const output: BuildOptions = buildOptions({
|
||||
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
|
||||
|
5
.github/lychee.toml
vendored
5
.github/lychee.toml
vendored
@@ -44,7 +44,10 @@ exclude = [
|
||||
"https://chromewebstore.google.com",
|
||||
|
||||
# Drupal 403
|
||||
"https://(www.)?drupal.org"
|
||||
"https://(www.)?drupal.org",
|
||||
|
||||
# Swimm returns 404, eventhough the link is valid
|
||||
"https://docs.swimm.io"
|
||||
]
|
||||
|
||||
# Exclude all private IPs from checking.
|
||||
|
2
.github/workflows/autofix.yml
vendored
2
.github/workflows/autofix.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
2
.github/workflows/build-docs.yml
vendored
2
.github/workflows/build-docs.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5
|
||||
uses: github/codeql-action/init@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
||||
with:
|
||||
config-file: ./.github/codeql/codeql-config.yml
|
||||
languages: ${{ matrix.language }}
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5
|
||||
uses: github/codeql-action/autobuild@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -62,4 +62,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@2c779ab0d087cd7fe7b826087247c2c81f27bfa6 # v3.26.5
|
||||
uses: github/codeql-action/analyze@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
||||
|
2
.github/workflows/e2e-applitools.yml
vendored
2
.github/workflows/e2e-applitools.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
|
||||
|
53
.github/workflows/e2e-timings.yml
vendored
Normal file
53
.github/workflows/e2e-timings.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
name: E2E - Generate Timings
|
||||
|
||||
on:
|
||||
# run this workflow every night at 3am
|
||||
schedule:
|
||||
- cron: '28 3 * * *'
|
||||
# or when the user triggers it from GitHub Actions page
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
timings:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: cypress/browsers:node-20.11.0-chrome-121.0.6167.85-1-ff-120.0-edge-121.0.2277.83-1
|
||||
options: --user 1001
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
||||
with:
|
||||
runTests: false
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
||||
id: cypress
|
||||
with:
|
||||
install: false
|
||||
start: pnpm run dev:coverage
|
||||
wait-on: 'http://localhost:9000'
|
||||
browser: chrome
|
||||
publish-summary: false
|
||||
env:
|
||||
VITEST_COVERAGE: true
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
SPLIT: 1
|
||||
SPLIT_INDEX: 0
|
||||
SPLIT_FILE: 'cypress/timings.json'
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@a94899bca583c204427a224a7af87c02f9b325d5 # v9.1.4
|
||||
with:
|
||||
add: 'cypress/timings.json'
|
||||
author_name: 'github-actions[bot]'
|
||||
author_email: '41898282+github-actions[bot]@users.noreply.github.com'
|
||||
message: 'chore: update E2E timings'
|
26
.github/workflows/e2e.yml
vendored
26
.github/workflows/e2e.yml
vendored
@@ -28,7 +28,6 @@ env:
|
||||
) ||
|
||||
github.event.before
|
||||
}}
|
||||
shouldRunParallel: ${{ secrets.CYPRESS_RECORD_KEY != '' && !(github.event_name == 'push' && github.ref == 'refs/heads/develop') }}
|
||||
jobs:
|
||||
cache:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -39,7 +38,7 @@ jobs:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
- name: Cache snapshots
|
||||
@@ -59,7 +58,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
if: ${{ steps.cache-snapshot.outputs.cache-hit != 'true' }}
|
||||
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2
|
||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
||||
with:
|
||||
# just perform install
|
||||
runTests: false
|
||||
@@ -80,7 +79,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
containers: [1, 2, 3, 4]
|
||||
containers: [1, 2, 3, 4, 5]
|
||||
steps:
|
||||
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
|
||||
@@ -88,7 +87,7 @@ jobs:
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
node-version-file: '.node-version'
|
||||
|
||||
@@ -101,7 +100,7 @@ jobs:
|
||||
key: ${{ runner.os }}-snapshots-${{ env.targetHash }}
|
||||
|
||||
- name: Install dependencies
|
||||
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2
|
||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
||||
with:
|
||||
runTests: false
|
||||
|
||||
@@ -117,11 +116,8 @@ jobs:
|
||||
# Install NPM dependencies, cache them correctly
|
||||
# and run all Cypress tests
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@df7484c5ba85def7eef30db301afa688187bc378 # v6.7.2
|
||||
uses: cypress-io/github-action@0da3c06ed8217b912deea9d8ee69630baed1737e # v6.7.6
|
||||
id: cypress
|
||||
# If CYPRESS_RECORD_KEY is set, run in parallel on all containers
|
||||
# Otherwise (e.g. if running from fork), we run on a single container only
|
||||
if: ${{ env.shouldRunParallel == 'true' || ( matrix.containers == 1 ) }}
|
||||
with:
|
||||
install: false
|
||||
start: pnpm run dev:coverage
|
||||
@@ -129,16 +125,18 @@ jobs:
|
||||
browser: chrome
|
||||
# Disable recording if we don't have an API key
|
||||
# e.g. if this action was run from a fork
|
||||
record: ${{ env.shouldRunParallel == 'true' }}
|
||||
parallel: ${{ env.shouldRunParallel == 'true' }}
|
||||
record: ${{ secrets.CYPRESS_RECORD_KEY != '' }}
|
||||
env:
|
||||
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
|
||||
VITEST_COVERAGE: true
|
||||
CYPRESS_COMMIT: ${{ github.sha }}
|
||||
ARGOS_TOKEN: ${{ secrets.ARGOS_TOKEN }}
|
||||
ARGOS_PARALLEL: ${{ env.shouldRunParallel == 'true' }}
|
||||
ARGOS_PARALLEL_TOTAL: 4
|
||||
ARGOS_PARALLEL: true
|
||||
ARGOS_PARALLEL_TOTAL: ${{ strategy.job-total }}
|
||||
ARGOS_PARALLEL_INDEX: ${{ matrix.containers }}
|
||||
SPLIT: ${{ strategy.job-total }}
|
||||
SPLIT_INDEX: ${{ strategy.job-index }}
|
||||
SPLIT_FILE: 'cypress/timings.json'
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
||||
|
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
2
.github/workflows/publish-docs.yml
vendored
2
.github/workflows/publish-docs.yml
vendored
@@ -28,7 +28,7 @@ jobs:
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
@@ -16,7 +16,7 @@ jobs:
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
43
.github/workflows/release-preview.yml
vendored
Normal file
43
.github/workflows/release-preview.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Preview release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [develop]
|
||||
types: [opened, synchronize, labeled, ready_for_review]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
preview:
|
||||
if: ${{ github.repository_owner == 'mermaid-js' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
issues: write
|
||||
pull-requests: write
|
||||
name: Publish preview release
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
|
||||
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
|
||||
- name: Install Packages
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Publish packages
|
||||
run: pnpx pkg-pr-new publish --pnpm './packages/*'
|
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
- uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # v4.0.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@aba318e9165b45b7948c60273e0b72fce0a64eb9 # v1.4.7
|
||||
uses: changesets/action@3de3850952bec538fde60aac71731376e57b9b57 # v1.4.8
|
||||
with:
|
||||
version: pnpm changeset:version
|
||||
publish: pnpm changeset:publish
|
||||
|
6
.github/workflows/scorecard.yml
vendored
6
.github/workflows/scorecard.yml
vendored
@@ -16,11 +16,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run analysis
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -32,6 +32,6 @@ jobs:
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
- name: Upload to code-scanning
|
||||
uses: github/codeql-action/upload-sarif@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4
|
||||
uses: github/codeql-action/upload-sarif@c36620d31ac7c881962c3d9dd939c40ec9434f2b # v3.26.12
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
# uses version from "packageManager" field in package.json
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
|
||||
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
|
||||
with:
|
||||
cache: pnpm
|
||||
node-version-file: '.node-version'
|
||||
@@ -38,6 +38,10 @@ jobs:
|
||||
run: |
|
||||
pnpm exec vitest run ./packages/mermaid/src/diagrams/gantt/ganttDb.spec.ts --coverage
|
||||
|
||||
- name: Verify out-of-tree build with TypeScript
|
||||
run: |
|
||||
pnpm test:check:tsc
|
||||
|
||||
- name: Upload Coverage to Codecov
|
||||
uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0
|
||||
# Run step only pushes to develop and pull_requests
|
||||
|
@@ -5,6 +5,9 @@ USER 0:0
|
||||
RUN corepack enable \
|
||||
&& corepack enable pnpm
|
||||
|
||||
RUN apk add --no-cache git~=2.43.4 \
|
||||
&& git config --add --system safe.directory /mermaid
|
||||
|
||||
ENV NODE_OPTIONS="--max_old_space_size=8192"
|
||||
|
||||
EXPOSE 9000 3333
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { defineConfig } from 'cypress';
|
||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
|
||||
import coverage from '@cypress/code-coverage/task';
|
||||
import eyesPlugin from '@applitools/eyes-cypress';
|
||||
import { registerArgosTask } from '@argos-ci/cypress/task';
|
||||
import coverage from '@cypress/code-coverage/task';
|
||||
import { defineConfig } from 'cypress';
|
||||
import { addMatchImageSnapshotPlugin } from 'cypress-image-snapshot/plugin';
|
||||
import cypressSplit from 'cypress-split';
|
||||
|
||||
export default eyesPlugin(
|
||||
defineConfig({
|
||||
@@ -13,6 +14,7 @@ export default eyesPlugin(
|
||||
specPattern: 'cypress/integration/**/*.{js,ts}',
|
||||
setupNodeEvents(on, config) {
|
||||
coverage(on, config);
|
||||
cypressSplit(on, config);
|
||||
on('before:browser:launch', (browser, launchOptions) => {
|
||||
if (browser.name === 'chrome' && browser.isHeadless) {
|
||||
launchOptions.args.push('--window-size=1440,1024', '--force-device-scale-factor=1');
|
||||
|
@@ -29,6 +29,7 @@ export const mermaidUrl = (
|
||||
options: CypressMermaidConfig,
|
||||
api: boolean
|
||||
): string => {
|
||||
options.handDrawnSeed = 1;
|
||||
const codeObject: CodeObject = {
|
||||
code: graphStr,
|
||||
mermaid: options,
|
||||
|
@@ -171,9 +171,62 @@ describe.skip('architecture diagram', () => {
|
||||
`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render an architecture diagram with a resonable height', () => {
|
||||
imgSnapshotTest(
|
||||
`architecture-beta
|
||||
group federated(cloud)[Federated Environment]
|
||||
service server1(server)[System] in federated
|
||||
service edge(server)[Edge Device] in federated
|
||||
server1:R -- L:edge
|
||||
|
||||
group on_prem(cloud)[Hub]
|
||||
service firewall(server)[Firewall Device] in on_prem
|
||||
service server(server)[Server] in on_prem
|
||||
firewall:R -- L:server
|
||||
|
||||
service db1(database)[db1] in on_prem
|
||||
service db2(database)[db2] in on_prem
|
||||
service db3(database)[db3] in on_prem
|
||||
service db4(database)[db4] in on_prem
|
||||
service db5(database)[db5] in on_prem
|
||||
service db6(database)[db6] in on_prem
|
||||
|
||||
junction mid in on_prem
|
||||
server:B -- T:mid
|
||||
|
||||
junction 1Leftofmid in on_prem
|
||||
1Leftofmid:R -- L:mid
|
||||
1Leftofmid:B -- T:db1
|
||||
|
||||
junction 2Leftofmid in on_prem
|
||||
2Leftofmid:R -- L:1Leftofmid
|
||||
2Leftofmid:B -- T:db2
|
||||
|
||||
junction 3Leftofmid in on_prem
|
||||
3Leftofmid:R -- L:2Leftofmid
|
||||
3Leftofmid:B -- T:db3
|
||||
|
||||
junction 1RightOfMid in on_prem
|
||||
mid:R -- L:1RightOfMid
|
||||
1RightOfMid:B -- T:db4
|
||||
|
||||
junction 2RightOfMid in on_prem
|
||||
1RightOfMid:R -- L:2RightOfMid
|
||||
2RightOfMid:B -- T:db5
|
||||
|
||||
junction 3RightOfMid in on_prem
|
||||
2RightOfMid:R -- L:3RightOfMid
|
||||
3RightOfMid:B -- T:db6
|
||||
|
||||
edge:R -- L:firewall
|
||||
`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('architecture - external', () => {
|
||||
// Skipped as the layout is not deterministic, and causes issues in E2E tests.
|
||||
describe.skip('architecture - external', () => {
|
||||
it('should allow adding external icons', () => {
|
||||
urlSnapshotTest('http://localhost:9000/architecture-external.html');
|
||||
});
|
||||
|
1037
cypress/integration/rendering/classDiagram-elk-v3.spec.js
Normal file
1037
cypress/integration/rendering/classDiagram-elk-v3.spec.js
Normal file
File diff suppressed because it is too large
Load Diff
1041
cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js
Normal file
1041
cypress/integration/rendering/classDiagram-handDrawn-v3.spec.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -581,4 +581,63 @@ class C13["With Città foreign language"]
|
||||
{ logLevel: 1, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
|
||||
it('renders a class diagram with a generic class in a namespace', () => {
|
||||
const diagramDefinition = `
|
||||
classDiagram-v2
|
||||
namespace Company.Project.Module {
|
||||
class GenericClass~T~ {
|
||||
+addItem(item: T)
|
||||
+getItem() T
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
imgSnapshotTest(diagramDefinition);
|
||||
});
|
||||
|
||||
it('renders a class diagram with nested namespaces and relationships', () => {
|
||||
const diagramDefinition = `
|
||||
classDiagram-v2
|
||||
namespace Company.Project.Module.SubModule {
|
||||
class Report {
|
||||
+generatePDF(data: List)
|
||||
+generateCSV(data: List)
|
||||
}
|
||||
}
|
||||
namespace Company.Project.Module {
|
||||
class Admin {
|
||||
+generateReport()
|
||||
}
|
||||
}
|
||||
Admin --> Report : generates
|
||||
`;
|
||||
|
||||
imgSnapshotTest(diagramDefinition);
|
||||
});
|
||||
|
||||
it('renders a class diagram with multiple classes and relationships in a namespace', () => {
|
||||
const diagramDefinition = `
|
||||
classDiagram-v2
|
||||
namespace Company.Project.Module {
|
||||
class User {
|
||||
+login(username: String, password: String)
|
||||
+logout()
|
||||
}
|
||||
class Admin {
|
||||
+addUser(user: User)
|
||||
+removeUser(user: User)
|
||||
+generateReport()
|
||||
}
|
||||
class Report {
|
||||
+generatePDF(reportData: List)
|
||||
+generateCSV(reportData: List)
|
||||
}
|
||||
}
|
||||
Admin --> User : manages
|
||||
Admin --> Report : generates
|
||||
`;
|
||||
|
||||
imgSnapshotTest(diagramDefinition);
|
||||
});
|
||||
});
|
||||
|
1031
cypress/integration/rendering/classDiagram-v3.spec.js
Normal file
1031
cypress/integration/rendering/classDiagram-v3.spec.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
import { imgSnapshotTest, renderGraph } from '../../helpers/util.ts';
|
||||
|
||||
describe.skip('Flowchart ELK', () => {
|
||||
describe('Flowchart ELK', () => {
|
||||
it('1-elk: should render a simple flowchart', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart-elk TD
|
||||
@@ -857,6 +857,196 @@ flowchart LR
|
||||
D --> E
|
||||
A["A"]
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
it('6080: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-1: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph S2
|
||||
subgraph s1["APA"]
|
||||
D{"Use the editor"}
|
||||
end
|
||||
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
end
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-2: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
subgraph s0["APA"]
|
||||
subgraph s8["APA"]
|
||||
subgraph s1["APA"]
|
||||
D{"X"}
|
||||
E[Q]
|
||||
end
|
||||
subgraph s3["BAPA"]
|
||||
F[Q]
|
||||
I
|
||||
end
|
||||
D --> I
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
I{"X"}
|
||||
end
|
||||
end
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-3: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
D{"Use the editor"}
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D-->I
|
||||
D-->I
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-4: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
it('6088-5: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
});
|
||||
it('6088-6: should handle diamond shape intersections', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
subgraph "subbe"
|
||||
A
|
||||
end
|
||||
|
||||
`,
|
||||
{ flowchart: { titleTopMargin: 0 } }
|
||||
);
|
||||
|
@@ -12,7 +12,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -30,7 +29,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: true },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -47,7 +45,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -62,7 +60,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[\\iPhone\\]
|
||||
C -->|Three| F[Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -78,7 +76,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
classDef processHead fill:#888888,color:white,font-weight:bold,stroke-width:3px,stroke:#001f3f
|
||||
class 1A,1B,D,E processHead
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -107,7 +105,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
35(SAM.CommonFA.PopulationFME)-->39(SAM.CommonFA.ChargeDetails)
|
||||
36(SAM.CommonFA.PremetricCost)-->39(SAM.CommonFA.ChargeDetails)
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -178,7 +176,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
9a072290_1ec3_e711_8c5a_005056ad0002-->d6072290_1ec3_e711_8c5a_005056ad0002
|
||||
9a072290_1ec3_e711_8c5a_005056ad0002-->71082290_1ec3_e711_8c5a_005056ad0002
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -187,7 +185,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
`
|
||||
graph TB;subgraph "number as labels";1;end;
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -199,7 +197,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
a1-->a2
|
||||
end
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -211,7 +209,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
a1-->a2
|
||||
end
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -246,7 +244,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
style foo fill:#F99,stroke-width:2px,stroke:#F0F,color:darkred
|
||||
style bar fill:#999,stroke-width:10px,stroke:#0F0,color:blue
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -348,7 +346,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4DA958A0-26D9-4D47-93A7-70F39FD7D51A;
|
||||
sid-7CE72B24-E0C1-46D3-8132-8BA66BE05AA7-->sid-4FC27B48-A6F9-460A-A675-021F5854FE22;
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -364,7 +362,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
listUrl: false,
|
||||
listId: 'color styling',
|
||||
fontFamily: 'courier',
|
||||
@@ -390,7 +387,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
listUrl: false,
|
||||
listId: 'color styling',
|
||||
fontFamily: 'courier',
|
||||
@@ -411,7 +407,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -435,7 +430,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -457,7 +451,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -471,7 +464,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -485,7 +477,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -500,7 +491,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -527,7 +517,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
class A someclass;`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -544,7 +533,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', flowchart: { nodeSpacing: 50 }, fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -560,7 +549,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { rankSpacing: '100' },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -578,7 +566,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -603,7 +590,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
click E "notes://do-your-thing/id" "other protocol test"
|
||||
click F "javascript:alert('test')" "script test"
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, securityLevel: 'loose', fontFamily: 'courier' }
|
||||
{ look: 'handDrawn', securityLevel: 'loose', fontFamily: 'courier' }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -623,7 +610,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
click B "index.html#link-clicked" "link test"
|
||||
click D testClick "click test"
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } }
|
||||
{ look: 'handDrawn', flowchart: { htmlLabels: true } }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -645,7 +632,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -664,7 +650,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
class A myClass1
|
||||
class D myClass2
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { htmlLabels: true } }
|
||||
{ look: 'handDrawn', flowchart: { htmlLabels: true } }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -682,7 +668,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -711,7 +696,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -728,7 +712,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -752,7 +735,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: false },
|
||||
fontFamily: 'courier',
|
||||
}
|
||||
@@ -769,7 +751,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { diagramPadding: 0 } }
|
||||
{ look: 'handDrawn', flowchart: { diagramPadding: 0 } }
|
||||
);
|
||||
});
|
||||
|
||||
@@ -804,7 +786,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
`graph TD
|
||||
a["<strong>Haiya</strong>"]-->b
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, htmlLabels: false, flowchart: { htmlLabels: false } }
|
||||
{ look: 'handDrawn', htmlLabels: false, flowchart: { htmlLabels: false } }
|
||||
);
|
||||
});
|
||||
it('FDH37: should render non-escaped with html labels', () => {
|
||||
@@ -814,7 +796,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -830,7 +811,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: true } }
|
||||
{ look: 'handDrawn', flowchart: { useMaxWidth: true } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
expect(svg).to.have.attr('width', '100%');
|
||||
@@ -853,7 +834,7 @@ describe('Flowchart HandDrawn', () => {
|
||||
C -->|Two| E[iPhone]
|
||||
C -->|Three| F[fa:fa-car Car]
|
||||
`,
|
||||
{ look: 'handDrawn', handDrawnSeed: 1, flowchart: { useMaxWidth: false } }
|
||||
{ look: 'handDrawn', flowchart: { useMaxWidth: false } }
|
||||
);
|
||||
cy.get('svg').should((svg) => {
|
||||
// const height = parseFloat(svg.attr('height'));
|
||||
@@ -874,7 +855,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -904,7 +884,6 @@ describe('Flowchart HandDrawn', () => {
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -919,7 +898,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -937,7 +915,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -977,7 +954,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -999,7 +975,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -1016,7 +991,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -1032,7 +1006,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
htmlLabels: true,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
@@ -1051,7 +1024,6 @@ graph TD
|
||||
`,
|
||||
{
|
||||
look: 'handDrawn',
|
||||
handDrawnSeed: 1,
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
}
|
||||
|
142
cypress/integration/rendering/flowchart-shape-alias.spec.ts
Normal file
142
cypress/integration/rendering/flowchart-shape-alias.spec.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||
|
||||
const aliasSet1 = ['process', 'rect', 'proc', 'rectangle'] as const;
|
||||
|
||||
const aliasSet2 = ['event', 'rounded'] as const;
|
||||
|
||||
const aliasSet3 = ['stadium', 'pill', 'terminal'] as const;
|
||||
|
||||
const aliasSet4 = ['fr-rect', 'subproc', 'subprocess', 'framed-rectangle', 'subroutine'] as const;
|
||||
|
||||
const aliasSet5 = ['db', 'database', 'cylinder', 'cyl'] as const;
|
||||
|
||||
const aliasSet6 = ['diam', 'decision', 'diamond'] as const;
|
||||
|
||||
const aliasSet7 = ['hex', 'hexagon', 'prepare'] as const;
|
||||
|
||||
const aliasSet8 = ['lean-r', 'lean-right', 'in-out'] as const;
|
||||
|
||||
const aliasSet9 = ['lean-l', 'lean-left', 'out-in'] as const;
|
||||
|
||||
const aliasSet10 = ['trap-b', 'trapezoid-bottom', 'priority'] as const;
|
||||
|
||||
const aliasSet11 = ['trap-t', 'trapezoid-top', 'manual'] as const;
|
||||
|
||||
const aliasSet12 = ['dbl-circ', 'double-circle'] as const;
|
||||
|
||||
const aliasSet13 = ['notched-rectangle', 'card', 'notch-rect'] as const;
|
||||
|
||||
const aliasSet14 = [
|
||||
'lin-rect',
|
||||
'lined-rectangle',
|
||||
'lin-proc',
|
||||
'lined-process',
|
||||
'shaded-process',
|
||||
] as const;
|
||||
|
||||
const aliasSet15 = ['sm-circ', 'small-circle', 'start'] as const;
|
||||
|
||||
const aliasSet16 = ['fr-circ', 'framed-circle', 'stop'] as const;
|
||||
|
||||
const aliasSet17 = ['fork', 'join'] as const;
|
||||
// brace-r', 'braces'
|
||||
const aliasSet18 = ['comment', 'brace-l'] as const;
|
||||
|
||||
const aliasSet19 = ['bolt', 'com-link', 'lightning-bolt'] as const;
|
||||
|
||||
const aliasSet20 = ['doc', 'document'] as const;
|
||||
|
||||
const aliasSet21 = ['delay', 'half-rounded-rectangle'] as const;
|
||||
|
||||
const aliasSet22 = ['h-cyl', 'das', 'horizontal-cylinder'] as const;
|
||||
|
||||
const aliasSet23 = ['lin-cyl', 'disk', 'lined-cylinder'] as const;
|
||||
|
||||
const aliasSet24 = ['curv-trap', 'display', 'curved-trapezoid'] as const;
|
||||
|
||||
const aliasSet25 = ['div-rect', 'div-proc', 'divided-rectangle', 'divided-process'] as const;
|
||||
|
||||
const aliasSet26 = ['extract', 'tri', 'triangle'] as const;
|
||||
|
||||
const aliasSet27 = ['win-pane', 'internal-storage', 'window-pane'] as const;
|
||||
|
||||
const aliasSet28 = ['f-circ', 'junction', 'filled-circle'] as const;
|
||||
|
||||
const aliasSet29 = ['lin-doc', 'lined-document'] as const;
|
||||
|
||||
const aliasSet30 = ['notch-pent', 'loop-limit', 'notched-pentagon'] as const;
|
||||
|
||||
const aliasSet31 = ['flip-tri', 'manual-file', 'flipped-triangle'] as const;
|
||||
|
||||
const aliasSet32 = ['sl-rect', 'manual-input', 'sloped-rectangle'] as const;
|
||||
|
||||
const aliasSet33 = ['docs', 'documents', 'st-doc', 'stacked-document'] as const;
|
||||
|
||||
const aliasSet34 = ['procs', 'processes', 'st-rect', 'stacked-rectangle'] as const;
|
||||
|
||||
const aliasSet35 = ['flag', 'paper-tape'] as const;
|
||||
|
||||
const aliasSet36 = ['bow-rect', 'stored-data', 'bow-tie-rectangle'] as const;
|
||||
|
||||
const aliasSet37 = ['cross-circ', 'summary', 'crossed-circle'] as const;
|
||||
|
||||
const aliasSet38 = ['tag-doc', 'tagged-document'] as const;
|
||||
|
||||
const aliasSet39 = ['tag-rect', 'tag-proc', 'tagged-rectangle', 'tagged-process'] as const;
|
||||
|
||||
const aliasSet40 = ['collate', 'hourglass'] as const;
|
||||
|
||||
// Aggregate all alias sets into a single array
|
||||
const aliasSets = [
|
||||
aliasSet1,
|
||||
aliasSet2,
|
||||
aliasSet3,
|
||||
aliasSet4,
|
||||
aliasSet5,
|
||||
aliasSet6,
|
||||
aliasSet7,
|
||||
aliasSet8,
|
||||
aliasSet9,
|
||||
aliasSet10,
|
||||
aliasSet11,
|
||||
aliasSet12,
|
||||
aliasSet13,
|
||||
aliasSet14,
|
||||
aliasSet15,
|
||||
aliasSet16,
|
||||
aliasSet17,
|
||||
aliasSet18,
|
||||
aliasSet19,
|
||||
aliasSet20,
|
||||
aliasSet21,
|
||||
aliasSet22,
|
||||
aliasSet23,
|
||||
aliasSet24,
|
||||
aliasSet25,
|
||||
aliasSet26,
|
||||
aliasSet27,
|
||||
aliasSet28,
|
||||
aliasSet29,
|
||||
aliasSet30,
|
||||
aliasSet31,
|
||||
aliasSet32,
|
||||
aliasSet33,
|
||||
aliasSet34,
|
||||
aliasSet35,
|
||||
aliasSet36,
|
||||
aliasSet37,
|
||||
aliasSet38,
|
||||
aliasSet39,
|
||||
] as const;
|
||||
|
||||
aliasSets.forEach((aliasSet) => {
|
||||
describe(`Test ${aliasSet.join(',')} `, () => {
|
||||
it(`All ${aliasSet.join(',')} should render same shape`, () => {
|
||||
let flowchartCode = `flowchart \n`;
|
||||
aliasSet.forEach((alias, index) => {
|
||||
flowchartCode += ` n${index}@{ shape: ${alias}, label: "${alias}" }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode);
|
||||
});
|
||||
});
|
||||
});
|
@@ -786,7 +786,7 @@ A ~~~ B
|
||||
`---
|
||||
title: Subgraph nodeSpacing and rankSpacing example
|
||||
config:
|
||||
flowchart:
|
||||
flowchart:
|
||||
nodeSpacing: 250
|
||||
rankSpacing: 250
|
||||
---
|
||||
@@ -1052,5 +1052,28 @@ end
|
||||
}
|
||||
);
|
||||
});
|
||||
it('Should render self-loops', () => {
|
||||
imgSnapshotTest(
|
||||
`flowchart
|
||||
A --> A
|
||||
subgraph B
|
||||
B1 --> B1
|
||||
end
|
||||
subgraph C
|
||||
subgraph C1
|
||||
C2 --> C2
|
||||
subgraph D
|
||||
D1 --> D1
|
||||
end
|
||||
D --> D
|
||||
end
|
||||
C1 --> C1
|
||||
end
|
||||
`,
|
||||
{
|
||||
flowchart: { subGraphTitleMargin: { top: 10, bottom: 5 } },
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -895,7 +895,7 @@ graph TD
|
||||
imgSnapshotTest(
|
||||
`
|
||||
graph TD
|
||||
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
|
||||
classDef default fill:#a34,stroke:#000,stroke-width:4px,color:#fff
|
||||
hello --> default
|
||||
`,
|
||||
{ htmlLabels: true, flowchart: { htmlLabels: true }, securityLevel: 'loose' }
|
||||
@@ -917,4 +917,24 @@ graph TD
|
||||
}
|
||||
);
|
||||
});
|
||||
it('68: should be able to render string and markdown labels (#5824)', () => {
|
||||
imgSnapshotTest(
|
||||
`
|
||||
flowchart TB
|
||||
mermaid{"What is\nyourmermaid version?"} --> v10["<11"] --"\`<**1**1\`"--> fine["No bug"]
|
||||
mermaid --> v11[">= v11"] -- ">= v11" --> broken["Affected by https://github.com/mermaid-js/mermaid/issues/5824"]
|
||||
subgraph subgraph1["\`How to fix **fix**\`"]
|
||||
broken --> B["B"]
|
||||
end
|
||||
githost["Github, Gitlab, BitBucket, etc."]
|
||||
githost2["\`Github, Gitlab, BitBucket, etc.\`"]
|
||||
a["1."]
|
||||
b["- x"]
|
||||
`,
|
||||
{
|
||||
flowchart: { htmlLabels: true },
|
||||
securityLevel: 'loose',
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
143
cypress/integration/rendering/iconShape.spec.ts
Normal file
143
cypress/integration/rendering/iconShape.spec.ts
Normal file
@@ -0,0 +1,143 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
const looks = ['classic', 'handDrawn'] as const;
|
||||
const directions = [
|
||||
'TB',
|
||||
//'BT',
|
||||
'LR',
|
||||
// 'RL'
|
||||
] as const;
|
||||
const forms = [undefined, 'square', 'circle', 'rounded'] as const;
|
||||
const labelPos = [undefined, 't', 'b'] as const;
|
||||
|
||||
looks.forEach((look) => {
|
||||
directions.forEach((direction) => {
|
||||
forms.forEach((form) => {
|
||||
labelPos.forEach((pos) => {
|
||||
describe(`Test iconShape in ${form ? `${form} form,` : ''} ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => {
|
||||
it(`without label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a label for icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with very long label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is a very very very very very long long long label for icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold** </br>and <strong>strong</strong> for icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'This is **bold** </br>and <strong>strong</strong> for icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with classDef`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`;
|
||||
flowchartCode += ` nA --> nAA@{ icon: 'fa:bell', label: 'new icon shape'`;
|
||||
if (form) {
|
||||
flowchartCode += `, form: '${form}'`;
|
||||
}
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
flowchartCode += ` nAA:::customClazz\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test iconShape with different h', () => {
|
||||
it('with different h', () => {
|
||||
let flowchartCode = `flowchart TB\n`;
|
||||
const icon = 'fa:bell';
|
||||
const iconHeight = 64;
|
||||
flowchartCode += ` nA --> nAA@{ icon: '${icon}', label: 'icon with different h', h: ${iconHeight} }\n`;
|
||||
imgSnapshotTest(flowchartCode);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test colored iconShape', () => {
|
||||
it('with no styles', () => {
|
||||
let flowchartCode = `flowchart TB\n`;
|
||||
const icon = 'fluent-emoji:tropical-fish';
|
||||
flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`;
|
||||
imgSnapshotTest(flowchartCode);
|
||||
});
|
||||
|
||||
it('with styles', () => {
|
||||
let flowchartCode = `flowchart TB\n`;
|
||||
const icon = 'fluent-emoji:tropical-fish';
|
||||
flowchartCode += ` nA --> nAA@{ icon: '${icon}', form: 'square', label: 'icon with color' }\n`;
|
||||
flowchartCode += ` style nAA fill:#f9f,stroke:#333,stroke-width:4px \n`;
|
||||
imgSnapshotTest(flowchartCode);
|
||||
});
|
||||
});
|
103
cypress/integration/rendering/imageShape.spec.ts
Normal file
103
cypress/integration/rendering/imageShape.spec.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
const looks = ['classic', 'handDrawn'] as const;
|
||||
const directions = [
|
||||
'TB',
|
||||
//'BT',
|
||||
'LR',
|
||||
// 'RL'
|
||||
] as const;
|
||||
const labelPos = [undefined, 't', 'b'] as const;
|
||||
|
||||
looks.forEach((look) => {
|
||||
directions.forEach((direction) => {
|
||||
labelPos.forEach((pos) => {
|
||||
describe(`Test imageShape in ${look} look and dir ${direction} with label position ${pos ? pos : 'not defined'}`, () => {
|
||||
it(`without label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', w: '100', h: '100' }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a label for image shape'`;
|
||||
|
||||
flowchartCode += `, w: '100', h: '200'`;
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with very long label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is a very very very very very long long long label for image shape'`;
|
||||
|
||||
flowchartCode += `, w: '100', h: '250'`;
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold** </br>and <strong>strong</strong> for image shape'`;
|
||||
|
||||
flowchartCode += `, w: '550', h: '200'`;
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, { look, htmlLabels: true });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'This is **bold** </br>and <strong>strong</strong> for image shape'`;
|
||||
flowchartCode += `, w: '250', h: '200'`;
|
||||
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
imgSnapshotTest(flowchartCode, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`;
|
||||
flowchartCode += `, w: '550', h: '200'`;
|
||||
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
flowchartCode += ` style A fill:#f9f,stroke:#333,stroke-width:4px \n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with classDef`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#000000,stroke-dasharray: 5 5\n`;
|
||||
flowchartCode += ` nA --> A@{ img: 'https://cdn.pixabay.com/photo/2020/02/22/18/49/paper-4871356_1280.jpg', label: 'new image shape'`;
|
||||
|
||||
flowchartCode += `, w: '500', h: '550'`;
|
||||
if (pos) {
|
||||
flowchartCode += `, pos: '${pos}'`;
|
||||
}
|
||||
flowchartCode += ` }\n`;
|
||||
flowchartCode += ` A:::customClazz\n`;
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
136
cypress/integration/rendering/kanban.spec.ts
Normal file
136
cypress/integration/rendering/kanban.spec.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||
|
||||
describe('Kanban diagram', () => {
|
||||
it('1: should render a kanban with a single section', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
docs[Create Documentation]
|
||||
docs[Create Blog about the new diagram]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('2: should render a kanban with multiple sections', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
docs[Create Documentation]
|
||||
id2
|
||||
docs[Create Blog about the new diagram]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('3: should render a kanban with a single wrapping node', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char, wrapping]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('4: should handle the height of a section with a wrapping node at the end', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
id2[One line]
|
||||
id3[Title of diagram is more than 100 chars when user duplicates diagram with 100 char, wrapping]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('5: should handle the height of a section with a wrapping node at the top', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char, wrapping]
|
||||
id3[One line]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('6: should handle the height of a section with a wrapping node in the middle', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
id2[One line]
|
||||
id3[Title of diagram is more than 100 chars when user duplicates diagram with 100 char, wrapping]
|
||||
id4[One line]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('6: should handle assigments', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
docs[Create Documentation]
|
||||
id2[In progress]
|
||||
docs[Create Blog about the new diagram]@{ assigned: 'knsv' }
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('7: should handle prioritization', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id2[In progress]
|
||||
vh[Very High]@{ priority: 'Very High' }
|
||||
h[High]@{ priority: 'High' }
|
||||
m[Default priority]
|
||||
l[Low]@{ priority: 'Low' }
|
||||
vl[Very Low]@{ priority: 'Very Low' }
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('7: should handle external tickets', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id1[Todo]
|
||||
docs[Create Documentation]
|
||||
id2[In progress]
|
||||
docs[Create Blog about the new diagram]@{ ticket: MC-2037 }
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('8: should handle assignments, prioritization and tickets ids in the same item', () => {
|
||||
imgSnapshotTest(
|
||||
`kanban
|
||||
id2[In progress]
|
||||
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
it('10: Full example', () => {
|
||||
imgSnapshotTest(
|
||||
`---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://abc123.atlassian.net/browse/#TICKET#'
|
||||
---
|
||||
kanban
|
||||
id1[Todo]
|
||||
docs[Create Documentation]
|
||||
docs[Create Blog about the new diagram]
|
||||
id7[In progress]
|
||||
id6[Create renderer so that it works in all cases. We also add som extra text here for testing purposes. And some more just for the extra flare.]
|
||||
id8[Design grammar]@{ assigned: 'knsv' }
|
||||
id9[Ready for deploy]
|
||||
id10[Ready for test]
|
||||
id11[Done]
|
||||
id5[define getData]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
|
||||
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
|
||||
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
|
||||
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
|
||||
id12[Can't reproduce]
|
||||
`,
|
||||
{}
|
||||
);
|
||||
});
|
||||
});
|
146
cypress/integration/rendering/newShapes.spec.ts
Normal file
146
cypress/integration/rendering/newShapes.spec.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util.ts';
|
||||
|
||||
const looks = ['classic', 'handDrawn'] as const;
|
||||
const directions = [
|
||||
'TB',
|
||||
//'BT',
|
||||
'LR',
|
||||
//'RL'
|
||||
] as const;
|
||||
const newShapesSet1 = [
|
||||
'triangle',
|
||||
'sloped-rectangle',
|
||||
'horizontal-cylinder',
|
||||
'flipped-triangle',
|
||||
'hourglass',
|
||||
] as const;
|
||||
const newShapesSet2 = [
|
||||
'tagged-rectangle',
|
||||
'documents',
|
||||
'lightning-bolt',
|
||||
'filled-circle',
|
||||
'window-pane',
|
||||
] as const;
|
||||
|
||||
const newShapesSet3 = [
|
||||
'curved-trapezoid',
|
||||
'bow-rect',
|
||||
'tagged-document',
|
||||
'divided-rectangle',
|
||||
'crossed-circle',
|
||||
] as const;
|
||||
|
||||
const newShapesSet4 = [
|
||||
'document',
|
||||
'notched-pentagon',
|
||||
'lined-cylinder',
|
||||
'stacked-document',
|
||||
'half-rounded-rectangle',
|
||||
] as const;
|
||||
|
||||
const newShapesSet5 = [
|
||||
'lined-document',
|
||||
'tagged-document',
|
||||
'brace-l',
|
||||
'comment',
|
||||
'braces',
|
||||
'brace-r',
|
||||
] as const;
|
||||
|
||||
const newShapesSet6 = ['brace-r', 'braces'] as const;
|
||||
// Aggregate all shape sets into a single array
|
||||
const newShapesSets = [
|
||||
newShapesSet1,
|
||||
newShapesSet2,
|
||||
newShapesSet3,
|
||||
newShapesSet4,
|
||||
newShapesSet5,
|
||||
newShapesSet6,
|
||||
];
|
||||
|
||||
looks.forEach((look) => {
|
||||
directions.forEach((direction) => {
|
||||
newShapesSets.forEach((newShapesSet) => {
|
||||
describe(`Test ${newShapesSet.join(', ')} in ${look} look and dir ${direction}`, () => {
|
||||
it(`without label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`connect all shapes with each other`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`;
|
||||
});
|
||||
for (let i = 0; i < newShapesSet.length; i++) {
|
||||
for (let j = i + 1; j < newShapesSet.length; j++) {
|
||||
flowchartCode += ` n${i}${i} --> n${j}${j}\n`;
|
||||
}
|
||||
}
|
||||
if (!(direction === 'TB' && look === 'handDrawn' && newShapesSet === newShapesSet1)) {
|
||||
//skip this test, works in real. Need to look
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
}
|
||||
});
|
||||
|
||||
it(`with very long label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** </br>and <strong>strong</strong> for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** </br>and <strong>strong</strong> for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`;
|
||||
flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with classDef`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`;
|
||||
newShapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`;
|
||||
flowchartCode += ` n${index}${index}:::customClazz\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
107
cypress/integration/rendering/oldShapes.spec.ts
Normal file
107
cypress/integration/rendering/oldShapes.spec.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { imgSnapshotTest } from '../../helpers/util';
|
||||
|
||||
const looks = ['classic', 'handDrawn'] as const;
|
||||
const directions = [
|
||||
'TB',
|
||||
//'BT',
|
||||
'LR',
|
||||
//'RL'
|
||||
] as const;
|
||||
|
||||
const shapesSet1 = ['text', 'card', 'lin-rect', 'diamond', 'hexagon'] as const;
|
||||
|
||||
// removing labelRect, need have alias for it
|
||||
const shapesSet2 = ['rounded', 'rect', 'start', 'stop'] as const;
|
||||
|
||||
const shapesSet3 = ['fork', 'choice', 'note', 'stadium', 'odd'] as const;
|
||||
|
||||
const shapesSet4 = ['subroutine', 'cylinder', 'circle', 'doublecircle', 'odd'] as const;
|
||||
|
||||
const shapesSet5 = ['anchor', 'lean-r', 'lean-l', 'trap-t', 'trap-b'] as const;
|
||||
|
||||
// Aggregate all shape sets into a single array
|
||||
const shapesSets = [shapesSet1, shapesSet2, shapesSet3, shapesSet4, shapesSet5] as const;
|
||||
|
||||
looks.forEach((look) => {
|
||||
directions.forEach((direction) => {
|
||||
shapesSets.forEach((shapesSet) => {
|
||||
describe(`Test ${shapesSet.join(', ')} in ${look} look and dir ${direction}`, () => {
|
||||
it(`without label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape} }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`connect all shapes with each other`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index}${index}@{ shape: ${newShape}, label: 'This is a label for ${newShape} shape' }\n`;
|
||||
});
|
||||
for (let i = 0; i < shapesSet.length; i++) {
|
||||
for (let j = i + 1; j < shapesSet.length; j++) {
|
||||
flowchartCode += ` n${i}${i} --> n${j}${j}\n`;
|
||||
}
|
||||
}
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with very long label`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is a very very very very very long long long label for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:true`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** </br>and <strong>strong</strong> for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with markdown htmlLabels:false`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'This is **bold** </br>and <strong>strong</strong> for ${newShape} shape' }\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, {
|
||||
look,
|
||||
htmlLabels: false,
|
||||
flowchart: { htmlLabels: false },
|
||||
});
|
||||
});
|
||||
|
||||
it(`with styles`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`;
|
||||
flowchartCode += ` style n${index}${index} fill:#f9f,stroke:#333,stroke-width:4px \n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
|
||||
it(`with classDef`, () => {
|
||||
let flowchartCode = `flowchart ${direction}\n`;
|
||||
flowchartCode += ` classDef customClazz fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5\n`;
|
||||
shapesSet.forEach((newShape, index) => {
|
||||
flowchartCode += ` n${index} --> n${index}${index}@{ shape: ${newShape}, label: 'new ${newShape} shape' }\n`;
|
||||
flowchartCode += ` n${index}${index}:::customClazz\n`;
|
||||
});
|
||||
imgSnapshotTest(flowchartCode, { look });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -10,6 +10,10 @@
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
@@ -34,6 +38,7 @@
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* color: white; */
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
@@ -83,279 +88,302 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="flex">
|
||||
<pre id="diagram" class="mermaid">
|
||||
---
|
||||
title: hello2
|
||||
config:
|
||||
look: handDrawn
|
||||
layout: elk
|
||||
elk:
|
||||
<!-- nodePlacementStrategy: INTERACTIVE -->
|
||||
<!-- mergeEdges: true -->
|
||||
---
|
||||
stateDiagram-v2
|
||||
direction LR
|
||||
accTitle: An idealized Open Source supply-chain graph
|
||||
|
||||
%%
|
||||
state "🟦 Importer" as author_importer
|
||||
state "🟥 Supplier, Owner" as author_owner
|
||||
state "🟨🟥 Maintainer, Author\n🟨 Custodian" as author
|
||||
state "🟩 Distributor" as repository_distributor
|
||||
state "🟦 Importer" as language_importer
|
||||
state "🟦🟨 Packager" as language_packager
|
||||
state "🟦🟨 OSS Steward" as language_steward
|
||||
state "🟨 Curator" as language_curator
|
||||
state "🟩 Distributor" as language_distributor
|
||||
state "🟦 Contributor" as contributor
|
||||
state "🟦 Importer" as package_importer
|
||||
state "🟨 Patcher" as package_patcher
|
||||
state "🟨🟦 Builder\n🟨🟦 Packager\n🟨🟦 Containerizer" as package_packager
|
||||
state "🟨 Curator" as package_curator
|
||||
state "🟩 Distributor" as package_distributor
|
||||
state "🟦 Importer" as integrator_importer
|
||||
state "🟥 Supplier, Manufacturer, Owner" as integrator_owner
|
||||
state "🟦🟨🟥 Integrator, Developer" as integrator_developer
|
||||
state "🟩🟨 SBOM Redactor\n🟩 Publisher" as integrator_publisher
|
||||
state "🟦🟨 Builder" as integrator_builder
|
||||
state "🟨 Deployer" as deployer
|
||||
state "🟦 Vuln. Checker" as integrator_checker
|
||||
state "🟩🟨 SBOM Redactor" as redactor
|
||||
state "🟦 Consumer\n🟦 User" as consumer
|
||||
state "🟦 Auditor" as auditor_internal
|
||||
state "🟦 Auditor" as auditor_external
|
||||
|
||||
%%
|
||||
classDef createsSBOM stroke:red,stroke-width:3px;
|
||||
classDef updatesSBOM stroke:yellow,stroke-width:3px;
|
||||
classDef assemblesSBOM stroke:yellow,stroke-width:3px;
|
||||
classDef distributesSBOM stroke:green,stroke-width:3px;
|
||||
classDef verifiesSBOM stroke:#07f,stroke-width:3px;
|
||||
|
||||
%%
|
||||
class author_importer verifiesSBOM
|
||||
class author_owner createsSBOM
|
||||
class manufacturer_owner createsSBOM
|
||||
class author assemblesSBOM
|
||||
class package_importer verifiesSBOM
|
||||
class package_patcher updatesSBOM
|
||||
class package_packager assemblesSBOM
|
||||
class package_curator distributesSBOM
|
||||
class package_distributor distributesSBOM
|
||||
class language_importer verifiesSBOM
|
||||
class language_packager assemblesSBOM
|
||||
class language_steward updatesSBOM
|
||||
class language_curator distributesSBOM
|
||||
class language_distributor distributesSBOM
|
||||
class repository_distributor distributesSBOM
|
||||
class integrator_importer verifiesSBOM
|
||||
class integrator_owner createsSBOM
|
||||
class integrator_developer assemblesSBOM
|
||||
class integrator_publisher distributesSBOM
|
||||
class integrator_builder assemblesSBOM
|
||||
class integrator_checker verifiesSBOM
|
||||
class deployer assemblesSBOM
|
||||
class redactor distributesSBOM
|
||||
class auditor_internal verifiesSBOM
|
||||
class auditor_external verifiesSBOM
|
||||
|
||||
state "Maintainer Environment" as environment_maintainer {
|
||||
[*] --> author_importer
|
||||
[*] --> author
|
||||
author_importer --> author
|
||||
author_owner --> author
|
||||
author --> language_packager
|
||||
}
|
||||
|
||||
[*] --> environment_maintainer
|
||||
|
||||
state "Language Ecosystem" as ecosystem_lang {
|
||||
[*] --> language_importer
|
||||
[*] --> language_steward
|
||||
[*] --> language_curator
|
||||
[*] --> language_distributor
|
||||
language_importer --> language_distributor
|
||||
language_importer --> language_curator
|
||||
language_steward --> language_curator
|
||||
language_curator --> language_distributor
|
||||
}
|
||||
|
||||
language_packager --> ecosystem_lang
|
||||
ecosystem_lang --> ecosystem_lang
|
||||
|
||||
state "Public Collaboration Ecosystem" as ecosystem_repo {
|
||||
[*] --> repository_distributor
|
||||
}
|
||||
|
||||
author --> ecosystem_repo
|
||||
ecosystem_repo --> author
|
||||
|
||||
repository_distributor --> contributor
|
||||
contributor --> repository_distributor
|
||||
|
||||
state "Package Ecosystem" as ecosystem_package {
|
||||
[*] --> package_importer
|
||||
[*] --> package_packager
|
||||
[*] --> package_patcher
|
||||
package_importer --> package_patcher
|
||||
package_importer --> package_packager
|
||||
package_patcher --> package_packager
|
||||
package_packager --> package_curator
|
||||
package_packager --> package_distributor
|
||||
package_curator --> package_distributor
|
||||
}
|
||||
|
||||
repository_distributor --> ecosystem_package
|
||||
language_distributor --> ecosystem_package
|
||||
ecosystem_package --> ecosystem_package
|
||||
|
||||
state "Integrator Environment" as environment_integrator {
|
||||
[*] --> integrator_developer
|
||||
[*] --> integrator_importer
|
||||
integrator_importer --> integrator_developer
|
||||
integrator_owner --> integrator_developer
|
||||
integrator_builder --> integrator_publisher
|
||||
integrator_developer --> integrator_checker
|
||||
integrator_checker --> integrator_developer
|
||||
auditor_internal --> integrator_developer
|
||||
integrator_developer --> integrator_builder
|
||||
integrator_developer --> auditor_internal
|
||||
}
|
||||
|
||||
repository_distributor --> environment_integrator
|
||||
language_distributor --> environment_integrator
|
||||
package_distributor --> environment_integrator
|
||||
|
||||
state "Production Environment" as environment_prod {
|
||||
[*] --> deployer
|
||||
deployer --> redactor
|
||||
}
|
||||
|
||||
integrator_publisher --> [*]
|
||||
integrator_developer --> environment_prod
|
||||
integrator_builder --> environment_prod
|
||||
integrator_publisher --> environment_prod
|
||||
|
||||
deployer --> auditor_external
|
||||
deployer --> consumer
|
||||
redactor --> consumer
|
||||
|
||||
|
||||
|
||||
</pre>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
---
|
||||
title: hello2
|
||||
config:
|
||||
look: handDrawn
|
||||
layout: dagre
|
||||
elk:
|
||||
nodePlacementStrategy: BRANDES_KOEPF
|
||||
---
|
||||
stateDiagram-v2
|
||||
A --> A
|
||||
state A {
|
||||
B --> D
|
||||
state B {
|
||||
C
|
||||
}
|
||||
state D {
|
||||
E
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
---
|
||||
title: hello2
|
||||
config:
|
||||
look: handDrawn
|
||||
layout: dagre
|
||||
elk:
|
||||
nodePlacementStrategy: BRANDES_KOEPF
|
||||
---
|
||||
flowchart
|
||||
A --> A
|
||||
subgraph A
|
||||
B --> B
|
||||
subgraph B
|
||||
C
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: handdrawn
|
||||
flowchart:
|
||||
htmlLabels: true
|
||||
layout: elk
|
||||
---
|
||||
flowchart
|
||||
A[I am a long text, where do I go??? handdrawn - true]
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<pre id="diagram" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
flowchart:
|
||||
htmlLabels: false
|
||||
---
|
||||
flowchart
|
||||
A[I am a long text, where do I go??? classic - false]
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
flowchart:
|
||||
htmlLabels: true
|
||||
---
|
||||
flowchart
|
||||
A[I am a long text, where do I go??? classic - true]
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
<pre id="diagram2" class="mermaid2">
|
||||
flowchart LR
|
||||
id1(Start)-->id2(Stop)
|
||||
style id1 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
style id2 fill:#bbf,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
|
||||
|
||||
|
||||
</pre>
|
||||
|
||||
<pre id="diagram3" class="mermaid2">
|
||||
flowchart LR
|
||||
A:::foo & B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
classDef ash color:red
|
||||
class C ash
|
||||
style C stroke:#00f, fill:black
|
||||
subgraph S2
|
||||
subgraph s1["APA"]
|
||||
D{"Use the editor"}
|
||||
end
|
||||
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
subgraph s0["APA"]
|
||||
subgraph s8["APA"]
|
||||
subgraph s1["APA"]
|
||||
D{"X"}
|
||||
E[Q]
|
||||
end
|
||||
subgraph s3["BAPA"]
|
||||
F[Q]
|
||||
I
|
||||
end
|
||||
D --> I
|
||||
D --> I
|
||||
D --> I
|
||||
|
||||
I{"X"}
|
||||
end
|
||||
end
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
a
|
||||
D{"Use the editor"}
|
||||
|
||||
D -- Mermaid js --> I{"fa:fa-code Text"}
|
||||
D-->I
|
||||
D-->I
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
stateDiagram
|
||||
A:::foo
|
||||
B:::bar --> C:::foobar
|
||||
classDef foo stroke:#f00
|
||||
classDef bar stroke:#0f0
|
||||
style C stroke:#00f, fill:black, color:white
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
subgraph s1["Untitled subgraph"]
|
||||
n1["Evaluate"]
|
||||
n2["Option 1"]
|
||||
n3["Option 2"]
|
||||
n4["fa:fa-car Option 3"]
|
||||
end
|
||||
subgraph s2["Untitled subgraph"]
|
||||
n5["Evaluate"]
|
||||
n6["Option 1"]
|
||||
n7["Option 2"]
|
||||
n8["fa:fa-car Option 3"]
|
||||
end
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
n1 -- One --> n2
|
||||
n1 -- Two --> n3
|
||||
n1 -- Three --> n4
|
||||
n5 -- One --> n6
|
||||
n5 -- Two --> n7
|
||||
n5 -- Three --> n8
|
||||
n1@{ shape: diam}
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
n5@{ shape: diam}
|
||||
n6@{ shape: rect}
|
||||
n7@{ shape: rect}
|
||||
n8@{ shape: rect}
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
title: https://github.com/mermaid-js/mermaid/issues/5824
|
||||
---
|
||||
%% 6048, 5824
|
||||
flowchart TB
|
||||
mermaid{"What is\nyourmermaid version?"} --> v10["<11"] --"`<**1**1`"--> fine["No bug"]
|
||||
mermaid --> v11[">= v11"] -- ">= v11" --> broken["Affected by https://github.com/mermaid-js/mermaid/issues/5824"]
|
||||
subgraph subgraph1["`How to fix **fix**`"]
|
||||
broken --> B["B"]
|
||||
end
|
||||
githost["Github, Gitlab, BitBucket, etc."]
|
||||
githost2["`Github, Gitlab, BitBucket, etc.`"]
|
||||
a["1."]
|
||||
b["- x"]
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
A{A} --> B & C
|
||||
subgraph "subbe"
|
||||
A
|
||||
end
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
flowchart LR
|
||||
n2@{ shape: rect}
|
||||
n3@{ shape: rect}
|
||||
n4@{ shape: rect}
|
||||
A["Start"] -- Some text --> B("Continue")
|
||||
B --> C{"Evaluate"}
|
||||
C -- One --> D["Option 1"]
|
||||
C -- Two --> E["Option 2"]
|
||||
C -- Three --> F["fa:fa-car Option 3"]
|
||||
%% C@{ shape: hexagon}
|
||||
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://github.com/your-repo/issues/#TICKET#'
|
||||
---
|
||||
kanban
|
||||
Backlog
|
||||
task1[📝 Define project requirements]@{ ticket: a101 }
|
||||
To Do
|
||||
task2[🔍 Research technologies]@{ ticket: a102 }
|
||||
Review
|
||||
task4[🔍 Code review for login feature]@{ ticket: a104 }
|
||||
Done
|
||||
task5[✅ Deploy initial version]@{ ticket: a105 }
|
||||
In Progress
|
||||
task3[💻 Develop login feature]@{ ticket: 103 }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'rounded' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'rounded' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'square' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'square' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Default] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'fa:bell', form: 'circle' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Class] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||
A:::AClass
|
||||
classDef AClass fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart LR
|
||||
nA[Style] --> A@{ icon: 'logos:aws', form: 'circle' }
|
||||
style A fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
kanban
|
||||
id2[In progress]
|
||||
docs[Create Blog about the new diagram]@{ priority: 'Very Low', ticket: MC-2037, assigned: 'knsv' }
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
|
||||
# sectionWidth: 300
|
||||
---
|
||||
kanban
|
||||
Todo
|
||||
[Create Documentation]
|
||||
docs[Create Blog about the new diagram]
|
||||
id7[In progress]
|
||||
id6[Create renderer so that it works in all cases. We also add som extra text here for testing purposes. And some more just for the extra flare.]
|
||||
id9[Ready for deploy]
|
||||
id8[Design grammar]@{ assigned: 'knsv' }
|
||||
id10[Ready for test]
|
||||
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
|
||||
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
|
||||
id11[Done]
|
||||
id5[define getData]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
|
||||
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
|
||||
|
||||
id12[Can't reproduce]
|
||||
id3[Weird flickering in Firefox]
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
|
||||
const staticBellIconPack = {
|
||||
prefix: 'fa6-regular',
|
||||
icons: {
|
||||
bell: {
|
||||
body: '<path fill="currentColor" d="M224 0c-17.7 0-32 14.3-32 32v19.2C119 66 64 130.6 64 208v25.4c0 45.4-15.5 89.5-43.8 124.9L5.3 377c-5.8 7.2-6.9 17.1-2.9 25.4S14.8 416 24 416h400c9.2 0 17.6-5.3 21.6-13.6s2.9-18.2-2.9-25.4l-14.9-18.6c-28.3-35.5-43.8-79.6-43.8-125V208c0-77.4-55-142-128-156.8V32c0-17.7-14.3-32-32-32m0 96c61.9 0 112 50.1 112 112v25.4c0 47.9 13.9 94.6 39.7 134.6H72.3c25.8-40 39.7-86.7 39.7-134.6V208c0-61.9 50.1-112 112-112m64 352H160c0 17 6.7 33.3 18.7 45.3S207 512 224 512s33.3-6.7 45.3-18.7S288 465 288 448"/>',
|
||||
width: 448,
|
||||
},
|
||||
},
|
||||
width: 512,
|
||||
height: 512,
|
||||
};
|
||||
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () => staticBellIconPack,
|
||||
},
|
||||
]);
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
@@ -365,6 +393,8 @@ flowchart LR
|
||||
};
|
||||
mermaid.initialize({
|
||||
// theme: 'base',
|
||||
// theme: 'default',
|
||||
// theme: 'forest',
|
||||
// handDrawnSeed: 12,
|
||||
// look: 'handDrawn',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
@@ -381,8 +411,11 @@ flowchart LR
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
kanban: {
|
||||
htmlLabels: false,
|
||||
},
|
||||
fontSize: 12,
|
||||
logLevel: 3,
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
|
174
cypress/platform/saurabh.html
Normal file
174
cypress/platform/saurabh.html
Normal file
@@ -0,0 +1,174 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet" />
|
||||
<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"
|
||||
/>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css?family=Noto+Sans+SC&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Caveat:wght@400..700&family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&family=Rubik+Mono+One&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<style>
|
||||
body {
|
||||
/* background: rgb(221, 208, 208); */
|
||||
/* background: #333; */
|
||||
font-family: 'Arial';
|
||||
/* font-size: 18px !important; */
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.mermaid2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mermaid svg {
|
||||
/* font-size: 18px !important; */
|
||||
|
||||
/* background-color: #efefef;
|
||||
background-image: radial-gradient(#fff 51%, transparent 91%),
|
||||
radial-gradient(#fff 51%, transparent 91%);
|
||||
background-size: 20px 20px;
|
||||
background-position:
|
||||
0 0,
|
||||
10px 10px;
|
||||
background-repeat: repeat; */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="display: flex; gap: 2rem; flex-direction: row">
|
||||
<pre id="diagram4" class="mermaid">
|
||||
flowchart LR
|
||||
A@{ icon: "fa:window-minimize", form: circle }
|
||||
E@{ icon: "fa:window-minimize", form: circle }
|
||||
B@{ icon: "fa:bell", form: circle }
|
||||
B2@{ icon: "fa:bell", form: circle }
|
||||
C@{ icon: "fa:address-book", form: square }
|
||||
D@{ icon: "fa:star-half", form: square }
|
||||
A --> E
|
||||
B --> B2
|
||||
|
||||
|
||||
</pre>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart TB
|
||||
A --test2--> B2@{ icon: "fa:bell", form: "rounded", label: "B2 aiduaid uyawduad uaduabd uyduadb", pos: "b" }
|
||||
B2 --test--> C
|
||||
D --> B2 --> E
|
||||
style B2 fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram43" class="mermaid2">
|
||||
flowchart BT
|
||||
A --test2--> B2@{ icon: "fa:bell", form: "square", label: "B2", pos: "t", h: 40, w: 30 }
|
||||
B2 --test--> C
|
||||
D --> B2 --> E
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram4" class="mermaid2">
|
||||
flowchart BT
|
||||
A --test2--> B2@{ icon: "fa:bell", label: "B2 awiugdawu uydgayuiwd wuydguy", pos: "b", h: 40, w: 30 }
|
||||
B2 --test--> C
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram43" class="mermaid2">
|
||||
flowchart BT
|
||||
A --test2--> B2@{ icon: "fa:bell", label: "B2 dawuygd ayuwgd uy", pos: "t", h: 40, w: 30 }
|
||||
B2 --test--> C
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram6" class="mermaid2">
|
||||
flowchart TB
|
||||
A --> B2@{ icon: "fa:bell", form: "circle", label: "test augfuyfavf ydvaubfuac", pos: "t", w: 200, h: 100 } --> C
|
||||
</pre
|
||||
>
|
||||
<pre id="diagram6" class="mermaid2">
|
||||
flowchart TB
|
||||
A --> B2@{ icon: "fa:bell", form: "circle", label: "test augfuyfavf ydvaubfuac", pos: "b", w: 200, h: 100 } --> C
|
||||
D --> B2 --> E
|
||||
</pre
|
||||
>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
{
|
||||
name: 'fa',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/fa6-solid/icons.json').then((res) => res.json()),
|
||||
},
|
||||
]);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
window.callback = function () {
|
||||
alert('A callback was triggered');
|
||||
};
|
||||
mermaid.initialize({
|
||||
// theme: 'base',
|
||||
// handdrawnSeed: 12,
|
||||
look: 'classic',
|
||||
// 'elk.nodePlacement.strategy': 'NETWORK_SIMPLEX',
|
||||
// 'elk.nodePlacement.strategy': 'SIMPLE',
|
||||
// 'elk.nodePlacement.strategy': 'LAYERED',
|
||||
// 'elk.mergeEdges': true,
|
||||
// layout: 'dagre',
|
||||
// layout: 'elk',
|
||||
// layout: 'fixed',
|
||||
// htmlLabels: false,
|
||||
flowchart: { titleTopMargin: 10, padding: 0, htmlLabels: true },
|
||||
// fontFamily: 'Caveat',
|
||||
// fontFamily: 'Kalam',
|
||||
fontFamily: 'courier',
|
||||
sequence: {
|
||||
actorFontFamily: 'courier',
|
||||
noteFontFamily: 'courier',
|
||||
messageFontFamily: 'courier',
|
||||
},
|
||||
themeVariables: {
|
||||
fontSize: 50,
|
||||
fontFamily: 'courier',
|
||||
},
|
||||
logLevel: 0,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
function callback() {
|
||||
alert('It worked');
|
||||
}
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
663
cypress/platform/yari.html
Normal file
663
cypress/platform/yari.html
Normal file
@@ -0,0 +1,663 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1 class="header">Class Nodes</h1>
|
||||
<div class="node-showcase">
|
||||
<div class="test">
|
||||
<h2>Basic Class</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
htmlLabels: false
|
||||
---
|
||||
classDiagram
|
||||
class _Duck_ {
|
||||
+String beakColor
|
||||
_+_swim_()a_
|
||||
__+quack() test__
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Basic Class</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
htmlLabels: false
|
||||
---
|
||||
classDiagram
|
||||
class Class10:::exClass2 {
|
||||
int[] id
|
||||
List~int~ ids
|
||||
test(List~int~ ids) List~bool~
|
||||
testArray() bool[]
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Basic Class</h2>
|
||||
<pre class="mermaid">
|
||||
flowchart TD
|
||||
Start --> Stop
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Complex Class</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Square~Shape~{
|
||||
int id
|
||||
List~int~ position
|
||||
setPoints(List~int~ points)
|
||||
getPoints() List~int~
|
||||
}
|
||||
|
||||
Square : -List~string~ messages
|
||||
Square : +setMessages(List~string~ messages)
|
||||
Square : +getMessages() List~string~
|
||||
Square : +getDistanceMatrix() List~List~int~~
|
||||
</pre
|
||||
>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>No Attributes</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Duck {
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>No Methods</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Only Class Name</h2>
|
||||
<p>Empty line as attribute</p>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
class:
|
||||
hideEmptyMembersBox: false
|
||||
---
|
||||
classDiagram
|
||||
class Duck {
|
||||
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Visibility and Types</h2>
|
||||
<p>(Further tilde testing)</p>
|
||||
<div class="mermaid">
|
||||
classDiagram class Duck { ~interface~~~ +String beakColor #swim() ~quack()~~~
|
||||
-test()~~~~~~~ +deposit(amount) bool }
|
||||
</div>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Additional Classifiers</h2>
|
||||
<p>(* Abstract | $ Static)</p>
|
||||
<div class="mermaid">
|
||||
classDiagram class Square~Shape~ { int id* List~int~ position* setPoints(List~int~points)*
|
||||
getPoints()* List~int~ } Square : -List~string~ messages$ Square :
|
||||
+setMessages(List~string~ messages)* Square : +getMessages()$ List~string~ Square :
|
||||
+getDistanceMatrix() List~List~int~~$
|
||||
</div>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Label</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Animal~test~["Animal with a label"]
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Spacing</h2>
|
||||
<p>(Fix ensures consistent spacing rules)</p>
|
||||
<p>(No space or single space?)</p>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class ClassName {
|
||||
-attribute:type
|
||||
- attribute : type
|
||||
test
|
||||
|
||||
+ GetAttribute() type
|
||||
+ GetAttribute() type
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Annotation</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
<<interface>> Shape
|
||||
Shape : noOfVertices
|
||||
Shape : draw()
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Long Class Name Text</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class ThisIsATestForALongClassName {
|
||||
<<interface>>
|
||||
noOfLetters
|
||||
delete()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Long Annotation Text</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
<<superlongannotationtext>> Shape
|
||||
Shape : noOfVertices
|
||||
Shape : draw()
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Long Member Text</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
<<interface>> Shape
|
||||
Shape : noOfVertices
|
||||
Shape : longtexttestkeepgoingandgoing
|
||||
Shape : draw()
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Link</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
link Shape "https://www.github.com" "This is a tooltip for a link"
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Click</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Shape
|
||||
click Shape href "https://www.github.com" "This is a tooltip for a link"
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Hand Drawn</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: handDrawn
|
||||
htmlLabels: true
|
||||
---
|
||||
classDiagram
|
||||
class Hand {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
style Hand fill:#f9f,stroke:#29f,stroke-width:2px
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Neutral Theme</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: neutral
|
||||
---
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Dark Theme</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: dark
|
||||
---
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Forest Theme</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: forest
|
||||
---
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Base Theme</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: base
|
||||
---
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Custom Theme</h2>
|
||||
<pre class="mermaid">
|
||||
%%{
|
||||
init: {
|
||||
'theme': 'base',
|
||||
'themeVariables': {
|
||||
'primaryColor': '#BB2528',
|
||||
'primaryTextColor': '#fff',
|
||||
'primaryBorderColor': '#7C0000',
|
||||
'lineColor': '#F83d29',
|
||||
'secondaryColor': '#006100',
|
||||
'tertiaryColor': '#fff'
|
||||
}
|
||||
}
|
||||
}%%
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
Duck--Dog
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Styling within Diagram</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
style Duck fill:#f9f,stroke:#333,stroke-width:8px
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Styling with classDef Statement</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Duck:::bold {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
|
||||
class Dog {
|
||||
+int numTeeth
|
||||
+bark()
|
||||
}
|
||||
|
||||
cssClass "Duck,Dog" pink
|
||||
|
||||
classDef pink fill:#f9f
|
||||
classDef default color:#f1e
|
||||
classDef bold stroke:#333,stroke-width:6px,color:#fff
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Styling with Class in Stylesheet</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Duck {
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Duck:::styleClass
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<h1 class="header">Diagram Testing</h1>
|
||||
<div class="diagram-showcase">
|
||||
<div class="test">
|
||||
<h2>Class Nodes Only</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Animal example
|
||||
---
|
||||
classDiagram
|
||||
Animal : +int age
|
||||
Animal : +String gender
|
||||
Animal: +isMammal()
|
||||
Animal: +mate()
|
||||
class Duck{
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
+bool is_wild
|
||||
+run()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Class Nodes LR</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Animal example
|
||||
---
|
||||
classDiagram
|
||||
direction LR
|
||||
Animal : +int age
|
||||
Animal : +String gender
|
||||
Animal: +isMammal()
|
||||
Animal: +mate()
|
||||
class Duck{
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
+bool is_wild
|
||||
+run()
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Relations</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
classA <|-- classB
|
||||
classC *-- classD
|
||||
classE o-- classF
|
||||
classG <-- classH
|
||||
classI -- classJ
|
||||
classK <.. classL
|
||||
classM <|.. classN
|
||||
classO .. classP
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Two Way Relation</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
class Animal {
|
||||
int size
|
||||
walk()
|
||||
}
|
||||
class Zebra {
|
||||
int size
|
||||
walk()
|
||||
}
|
||||
Animal o--|> Zebra
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Relations with Labels</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
classA <|-- classB : implements
|
||||
classC *-- classD : composition
|
||||
classE o-- classF : aggregation
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Cardinality / Multiplicity</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
Customer "1" --> "*" Ticket
|
||||
Student "1" --> "1..*" Course
|
||||
Galaxy --> "many" Star : Contains
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Complex Relations with Theme</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: forest
|
||||
look: handDrawns
|
||||
layout: elk
|
||||
---
|
||||
classDiagram
|
||||
direction RL
|
||||
class Student {
|
||||
-idCard : IdCard
|
||||
}
|
||||
class IdCard{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
class Bike{
|
||||
-id : int
|
||||
-name : string
|
||||
}
|
||||
Student "1" o--o "1" IdCard : carries
|
||||
Student "1" o--o "1" Bike : rides
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Notes</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
note "This is a general note"
|
||||
note for MyClass "This is a note for a class"
|
||||
class MyClass
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Namespaces</h2>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
namespace BaseShapes {
|
||||
class Triangle
|
||||
class Rectangle {
|
||||
double width
|
||||
double height
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Namespaces</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
layout: elk
|
||||
---
|
||||
classDiagram
|
||||
namespace Namespace1 {
|
||||
class C1
|
||||
class C2
|
||||
}
|
||||
C1 --> C2
|
||||
class C3
|
||||
class C4
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Full Example</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
title: Animal example
|
||||
config:
|
||||
layout: dagre
|
||||
---
|
||||
classDiagram
|
||||
note "From Duck till Zebra"
|
||||
Animal <|--|> Duck
|
||||
note for Duck "can fly<br>can swim<br>can dive<br>can help in debugging"
|
||||
Animal <|-- Fish
|
||||
Animal <|--|> Zebra
|
||||
Animal : +int age
|
||||
Animal : +String gender
|
||||
Animal: +isMammal()
|
||||
Animal: +mate()
|
||||
class Duck{
|
||||
+String beakColor
|
||||
+swim()
|
||||
+quack()
|
||||
}
|
||||
class Fish{
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
class Zebra{
|
||||
+bool is_wild
|
||||
+run()
|
||||
}
|
||||
cssClass "Duck" test
|
||||
classDef test fill:#f71
|
||||
%%classDef default fill:#f93
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<h2>Full Example</h2>
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
theme: forest
|
||||
look: handDrawn
|
||||
---
|
||||
classDiagram
|
||||
note for Outside "Note testing"
|
||||
namespace Test {
|
||||
class Outside
|
||||
}
|
||||
namespace BaseShapes {
|
||||
class Triangle
|
||||
class Rectangle {
|
||||
double width
|
||||
double height
|
||||
}
|
||||
}
|
||||
Outside <|--|> Rectangle
|
||||
style Triangle fill:#f9f,stroke:#333,stroke-width:4px
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<pre class="mermaid">
|
||||
---
|
||||
config:
|
||||
look: handDrawn
|
||||
layout: elk
|
||||
---
|
||||
classDiagram
|
||||
Class01 "1" <|--|> "*" AveryLongClass : Cool
|
||||
<<interface>> Class01
|
||||
Class03 "1" *-- "*" Class04
|
||||
Class05 "1" o-- "many" Class06
|
||||
Class07 "1" .. "*" Class08
|
||||
Class09 "1" --> "*" C2 : Where am i?
|
||||
Class09 "*" --* "*" C3
|
||||
Class09 "1" --|> "1" Class07
|
||||
NewClass ()--() Class04
|
||||
Class09 <|--|> AveryLongClass
|
||||
Class07 : equals()
|
||||
Class07 : Object[] elementData
|
||||
Class01 : size()
|
||||
Class01 : int chimp
|
||||
Class01 : int gorilla
|
||||
Class08 "1" <--> "*" C2: Cool label
|
||||
class Class10 {
|
||||
<<service>>
|
||||
int id
|
||||
test()
|
||||
}
|
||||
Class10 o--o AveryLongClass
|
||||
Class10 <--> Class07
|
||||
</pre>
|
||||
</div>
|
||||
<div class="test">
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
test ()--() test2
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
import layouts from './mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('Mermaid error: ', err);
|
||||
};
|
||||
mermaid.initialize();
|
||||
mermaid.parseError = function (err, hash) {
|
||||
console.error('In parse error:');
|
||||
console.error(err);
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
<style>
|
||||
.header {
|
||||
text-decoration: underline;
|
||||
text-align: center;
|
||||
}
|
||||
.node-showcase {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
.test {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
}
|
||||
.test > h2 {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.test > p {
|
||||
margin-top: -6px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.diagram-showcase {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.styleClass > * > path {
|
||||
fill: #ff0000 !important;
|
||||
stroke: #ffff00 !important;
|
||||
stroke-width: 4px !important;
|
||||
stroke-dasharray: 2 !important;
|
||||
}
|
||||
</style>
|
||||
</html>
|
152
cypress/timings.json
Normal file
152
cypress/timings.json
Normal file
@@ -0,0 +1,152 @@
|
||||
{
|
||||
"durations": [
|
||||
{
|
||||
"spec": "cypress/integration/other/configuration.spec.js",
|
||||
"duration": 4989
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/external-diagrams.spec.js",
|
||||
"duration": 1382
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/ghsa.spec.js",
|
||||
"duration": 3178
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/iife.spec.js",
|
||||
"duration": 1372
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/interaction.spec.js",
|
||||
"duration": 8998
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/rerender.spec.js",
|
||||
"duration": 1249
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/other/xss.spec.js",
|
||||
"duration": 25664
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/appli.spec.js",
|
||||
"duration": 1928
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/architecture.spec.ts",
|
||||
"duration": 2330
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/block.spec.js",
|
||||
"duration": 11156
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/c4.spec.js",
|
||||
"duration": 3418
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram-v2.spec.js",
|
||||
"duration": 14866
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/classDiagram.spec.js",
|
||||
"duration": 9894
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/conf-and-directives.spec.js",
|
||||
"duration": 5778
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/current.spec.js",
|
||||
"duration": 1690
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/erDiagram.spec.js",
|
||||
"duration": 9144
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/errorDiagram.spec.js",
|
||||
"duration": 1951
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-elk.spec.js",
|
||||
"duration": 2196
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-handDrawn.spec.js",
|
||||
"duration": 21029
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-shape-alias.spec.ts",
|
||||
"duration": 16087
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart-v2.spec.js",
|
||||
"duration": 27465
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/flowchart.spec.js",
|
||||
"duration": 20035
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/gantt.spec.js",
|
||||
"duration": 11366
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/gitGraph.spec.js",
|
||||
"duration": 34025
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/iconShape.spec.ts",
|
||||
"duration": 185902
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/imageShape.spec.ts",
|
||||
"duration": 41631
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/info.spec.ts",
|
||||
"duration": 1736
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/journey.spec.js",
|
||||
"duration": 2247
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/katex.spec.js",
|
||||
"duration": 2144
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/marker_unique_id.spec.js",
|
||||
"duration": 1646
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/mindmap.spec.ts",
|
||||
"duration": 6406
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/newShapes.spec.ts",
|
||||
"duration": 107219
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/stateDiagram.spec.js",
|
||||
"duration": 15834
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/theme.spec.js",
|
||||
"duration": 33240
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/timeline.spec.ts",
|
||||
"duration": 7122
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/xyChart.spec.js",
|
||||
"duration": 11127
|
||||
},
|
||||
{
|
||||
"spec": "cypress/integration/rendering/zenuml.spec.js",
|
||||
"duration": 2391
|
||||
}
|
||||
]
|
||||
}
|
@@ -159,30 +159,87 @@
|
||||
class People List~List~Person~~
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
A1 --> B1
|
||||
namespace A {
|
||||
class A1 {
|
||||
+foo : string
|
||||
}
|
||||
class A2 {
|
||||
+bar : int
|
||||
namespace Company.Project.Module {
|
||||
class GenericClass~T~ {
|
||||
+addItem(item: T)
|
||||
+getItem() T
|
||||
}
|
||||
}
|
||||
namespace B {
|
||||
class B1 {
|
||||
+foo : bool
|
||||
}
|
||||
class B2 {
|
||||
+bar : float
|
||||
}
|
||||
}
|
||||
A2 --> B2
|
||||
</pre>
|
||||
<hr />
|
||||
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
namespace Company.Project.Module.SubModule {
|
||||
class Report {
|
||||
+generatePDF(data: List)
|
||||
+generateCSV(data: List)
|
||||
}
|
||||
}
|
||||
namespace Company.Project.Module {
|
||||
class Admin {
|
||||
+generateReport()
|
||||
}
|
||||
}
|
||||
Admin --> Report : generates
|
||||
</pre>
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
namespace Company.Project.Module {
|
||||
class User {
|
||||
+login(username: String, password: String)
|
||||
+logout()
|
||||
}
|
||||
class Admin {
|
||||
+addUser(user: User)
|
||||
+removeUser(user: User)
|
||||
+generateReport()
|
||||
}
|
||||
class Report {
|
||||
+generatePDF(reportData: List)
|
||||
+generateCSV(reportData: List)
|
||||
}
|
||||
}
|
||||
Admin --> User : manages
|
||||
Admin --> Report : generates
|
||||
</pre>
|
||||
<hr />
|
||||
<pre class="mermaid">
|
||||
classDiagram
|
||||
namespace Shapes {
|
||||
class Shape {
|
||||
+calculateArea() double
|
||||
}
|
||||
class Circle {
|
||||
+double radius
|
||||
}
|
||||
class Square {
|
||||
+double side
|
||||
}
|
||||
}
|
||||
|
||||
Shape <|-- Circle
|
||||
Shape <|-- Square
|
||||
|
||||
namespace Vehicles {
|
||||
class Vehicle {
|
||||
+String brand
|
||||
}
|
||||
class Car {
|
||||
+int horsepower
|
||||
}
|
||||
class Bike {
|
||||
+boolean hasGears
|
||||
}
|
||||
}
|
||||
|
||||
Vehicle <|-- Car
|
||||
Vehicle <|-- Bike
|
||||
Car --> Circle : "Logo Shape"
|
||||
Bike --> Square : "Logo Shape"
|
||||
|
||||
</pre>
|
||||
<script type="module">
|
||||
import mermaid from './mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
|
@@ -39,8 +39,8 @@ graph TB
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
import flowchartELK from '/mermaid-flowchart-elk.esm.mjs';
|
||||
await mermaid.registerExternalDiagrams([flowchartELK]);
|
||||
import layouts from '/mermaid-layout-elk.esm.mjs';
|
||||
mermaid.registerLayoutLoaders(layouts);
|
||||
async function render(str) {
|
||||
const { svg } = await mermaid.render('dynamic', str);
|
||||
document.getElementById('dynamicDiagram').innerHTML = svg;
|
||||
|
233
docs/adding-new-shape.md
Normal file
233
docs/adding-new-shape.md
Normal file
@@ -0,0 +1,233 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/adding-new-shape.md](../packages/mermaid/src/docs/adding-new-shape.md).
|
||||
|
||||
# Custom SVG Shapes Library
|
||||
|
||||
This library provides a collection of custom SVG shapes, utilities, and helpers for generating diagram components. The shapes are designed to be used within an SVG container and include a variety of common and complex shapes.
|
||||
|
||||
## Overview
|
||||
|
||||
## Shape Helpers and Utilities
|
||||
|
||||
Before starting with shape creation, it's essential to familiarize yourself with the utilities provided in the `utils.ts` file from `packages/mermaid/src/rendering-util/rendering-elements/shapes/util.js`. These utilities are designed to assist with various aspects of SVG shape manipulation and ensure consistent and accurate rendering.
|
||||
|
||||
## Available Utilities
|
||||
|
||||
### 1. `labelHelper`
|
||||
|
||||
- **Purpose**: This function creates and inserts labels inside SVG shapes.
|
||||
- **Features**:
|
||||
- Handles both HTML labels and plain text.
|
||||
- Calculates the bounding box dimensions of the label.
|
||||
- Ensures proper positioning of labels within shapes.
|
||||
|
||||
### 2. `updateNodeBounds`
|
||||
|
||||
- **Purpose**: Updates the bounding box dimensions (width and height) of a node.
|
||||
- **Usage**:
|
||||
- Adjusts the size of the node to fit the content or shape.
|
||||
- Useful for ensuring that shapes resize appropriately based on their content.
|
||||
|
||||
### 3. `insertPolygonShape`
|
||||
|
||||
- **Purpose**: Inserts a polygon shape into an SVG container.
|
||||
- **Features**:
|
||||
- Handles the creation and insertion of complex polygonal shapes.
|
||||
- Configures the shape's appearance and positioning within the SVG container.
|
||||
|
||||
### 4. `getNodeClasses`
|
||||
|
||||
- **Purpose**: Returns the appropriate CSS classes for a node based on its configuration.
|
||||
- **Usage**:
|
||||
- Dynamically applies CSS classes to nodes for styling purposes.
|
||||
- Ensures that nodes adhere to the desired design and theme.
|
||||
|
||||
### 5. `createPathFromPoints`
|
||||
|
||||
- **Purpose**: Generates an SVG path string from an array of points.
|
||||
- **Usage**:
|
||||
- Converts a list of points into a smooth path.
|
||||
- Useful for creating custom shapes or paths within the SVG.
|
||||
|
||||
### 6. `generateFullSineWavePoints`
|
||||
|
||||
- **Purpose**: Generates points for a sine wave, useful for creating wavy-edged shapes.
|
||||
- **Usage**:
|
||||
- Facilitates the creation of shapes with wavy or sine-wave edges.
|
||||
- Can be used to add decorative or dynamic edges to shapes.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To utilize these utilities, simply import them from the `utils.ts` file into your shape creation script. These helpers will streamline the process of building and customizing SVG shapes, ensuring consistent results across your projects.
|
||||
|
||||
```typescript
|
||||
import {
|
||||
labelHelper,
|
||||
updateNodeBounds,
|
||||
insertPolygonShape,
|
||||
getNodeClasses,
|
||||
createPathFromPoints,
|
||||
generateFullSineWavePoints,
|
||||
} from './utils.ts';
|
||||
```
|
||||
|
||||
## Example Usage
|
||||
|
||||
Here’s a basic example of how you might use some of these utilities:
|
||||
|
||||
```typescript
|
||||
import { labelHelper, insertPolygonShape } from './utils.ts';
|
||||
|
||||
const svgContainer = document.getElementById('svgContainer');
|
||||
|
||||
// Insert a polygon shape
|
||||
insertPolygonShape(svgContainer /* shape-specific parameters */);
|
||||
|
||||
// Create and insert a label inside the shape
|
||||
labelHelper(svgContainer /* label-specific parameters */);
|
||||
```
|
||||
|
||||
## Adding New Shapes
|
||||
|
||||
### 1. Create the Shape Function
|
||||
|
||||
To add a new shape:
|
||||
|
||||
- **Create the shape function**: Create a new file of name of the shape and export a function in the `shapes` directory that generates your shape. The file and function should follow the pattern used in existing shapes and return an SVG element.
|
||||
|
||||
- **Example**:
|
||||
|
||||
```typescript
|
||||
import { Node, RenderOptions } from '../../types.ts';
|
||||
|
||||
export const myNewShape = async (
|
||||
parent: SVGAElement,
|
||||
node: Node,
|
||||
renderOptions: RenderOptions
|
||||
) => {
|
||||
// Create your shape here
|
||||
const shape = parent.insert('g').attr('class', 'my-new-shape');
|
||||
// Add other elements or styles as needed
|
||||
return shape;
|
||||
};
|
||||
```
|
||||
|
||||
### 2. Register the Shape
|
||||
|
||||
- **Register the shape**: Add your shape to the `shapes` object in the [main shapes module](../rendering-util/rendering-elements/shapes.ts). This allows your shape to be recognized and used within the system.
|
||||
|
||||
- **Example**:
|
||||
|
||||
```typescript
|
||||
import { myNewShape } from './shapes/myNewShape';
|
||||
|
||||
const shapes = {
|
||||
...,
|
||||
{
|
||||
semanticName: 'My Shape',
|
||||
name: 'Shape Name',
|
||||
shortName: '<short-name>',
|
||||
description: '<Description for the shape>',
|
||||
aliases: ['<alias-one>', '<al-on>', '<alias-two>', '<al-two>'],
|
||||
handler: myNewShape,
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
# Shape Intersection Algorithms
|
||||
|
||||
This contains algorithms and utilities for calculating intersection points for various shapes in SVG. Arrow intersection points are crucial for accurately determining where arrows connect with shapes. Ensuring precise intersection points enhances the clarity and accuracy of flowcharts and diagrams.
|
||||
|
||||
## Shape Intersection Functions
|
||||
|
||||
### 1. `Ellipse`
|
||||
|
||||
Calculates the intersection points for an ellipse.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```javascript
|
||||
import intersectEllipse from './intersect-ellipse.js';
|
||||
|
||||
const intersection = intersectEllipse(node, rx, ry, point);
|
||||
```
|
||||
|
||||
- **Parameters**:
|
||||
- `node`: The SVG node element.
|
||||
- `rx`: The x-radius of the ellipse.
|
||||
- `ry`: The y-radius of the ellipse.
|
||||
- `point`: The point from which the intersection is calculated.
|
||||
|
||||
### 2. `intersectRect`
|
||||
|
||||
Calculates the intersection points for a rectangle.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```javascript
|
||||
import intersectRect from './intersect-rect.js';
|
||||
|
||||
const intersection = intersectRect(node, point);
|
||||
```
|
||||
|
||||
- **Parameters**:
|
||||
- `node`: The SVG node element.
|
||||
- `point`: The point from which the intersection is calculated.
|
||||
|
||||
### 3. `intersectPolygon`
|
||||
|
||||
Calculates the intersection points for a polygon.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```javascript
|
||||
import intersectPolygon from './intersect-polygon.js';
|
||||
|
||||
const intersection = intersectPolygon(node, polyPoints, point);
|
||||
```
|
||||
|
||||
- **Parameters**:
|
||||
- `node`: The SVG node element.
|
||||
- `polyPoints`: Array of points defining the polygon.
|
||||
- `point`: The point from which the intersection is calculated.
|
||||
|
||||
## Cypress Tests
|
||||
|
||||
To ensure the robustness of the flowchart shapes, there are implementation of comprehensive Cypress test cases in `newShapes.spec.ts` file. These tests cover various aspects such as:
|
||||
|
||||
- **Shapes**: Testing new shapes like `bowTieRect`, `waveRectangle`, `trapezoidalPentagon`, etc.
|
||||
- **Looks**: Verifying shapes under different visual styles (`classic` and `handDrawn`).
|
||||
- **Directions**: Ensuring correct rendering in all flow directions of arrows :
|
||||
- `TB` `(Top -> Bottom)`
|
||||
- `BT` `(Bottom -> Top)`
|
||||
- `LR` `(Left -> Right)`
|
||||
- `RL` `(Right -> Left)`
|
||||
- **Labels**: Testing shapes with different labels, including:
|
||||
- No labels
|
||||
- Short labels
|
||||
- Very long labels
|
||||
- Markdown with `htmlLabels:true` and `htmlLabels:false`
|
||||
- **Styles**: Applying custom styles to shapes and verifying correct rendering.
|
||||
- **Class Definitions**: Using `classDef` to apply custom classes and testing their impact.
|
||||
|
||||
### Running the Tests
|
||||
|
||||
To run the Cypress tests, follow these steps:
|
||||
|
||||
1. Ensure you have all dependencies installed by running:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
2. Start the Cypress test runner:
|
||||
|
||||
```bash
|
||||
cypress open --env updateSnapshots=true
|
||||
|
||||
```
|
||||
|
||||
3. Select the test suite from the Cypress interface to run all the flowchart shape tests.
|
55
docs/config/icons.md
Normal file
55
docs/config/icons.md
Normal file
@@ -0,0 +1,55 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/config/icons.md](../../packages/mermaid/src/docs/config/icons.md).
|
||||
|
||||
# Registering icon pack in mermaid
|
||||
|
||||
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
|
||||
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
|
||||
|
||||
Using JSON file directly from CDN:
|
||||
|
||||
```js
|
||||
import mermaid from 'CDN/mermaid.esm.mjs';
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos@1/icons.json').then((res) => res.json()),
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
Using packages and a bundler:
|
||||
|
||||
```bash
|
||||
npm install @iconify-json/logos@1
|
||||
```
|
||||
|
||||
With lazy loading
|
||||
|
||||
```js
|
||||
import mermaid from 'mermaid';
|
||||
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () => import('@iconify-json/logos').then((module) => module.icons),
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
Without lazy loading
|
||||
|
||||
```js
|
||||
import mermaid from 'mermaid';
|
||||
import { icons } from '@iconify-json/logos';
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: icons.prefix, // To use the prefix defined in the icon pack
|
||||
icons,
|
||||
},
|
||||
]);
|
||||
```
|
@@ -127,7 +127,7 @@ Error.prepareStackTrace
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/@types/node/globals.d.ts:28
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:98
|
||||
|
||||
---
|
||||
|
||||
@@ -141,7 +141,7 @@ Error.stackTraceLimit
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/@types/node/globals.d.ts:30
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:100
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -168,4 +168,4 @@ Error.captureStackTrace
|
||||
|
||||
#### Defined in
|
||||
|
||||
node_modules/@types/node/globals.d.ts:21
|
||||
node_modules/.pnpm/@types+node\@20.16.11/node_modules/@types/node/globals.d.ts:91
|
||||
|
@@ -16,11 +16,11 @@
|
||||
|
||||
### config
|
||||
|
||||
• **config**: `MermaidConfig`
|
||||
• **config**: [`MermaidConfig`](mermaid.MermaidConfig.md)
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.d.ts:118](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.d.ts#L118)
|
||||
[packages/mermaid/src/rendering-util/types.ts:144](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L144)
|
||||
|
||||
---
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.d.ts:117](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.d.ts#L117)
|
||||
[packages/mermaid/src/rendering-util/types.ts:143](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L143)
|
||||
|
||||
---
|
||||
|
||||
@@ -40,4 +40,4 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/rendering-util/types.d.ts:116](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.d.ts#L116)
|
||||
[packages/mermaid/src/rendering-util/types.ts:142](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/rendering-util/types.ts#L142)
|
||||
|
@@ -49,7 +49,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L200)
|
||||
[packages/mermaid/src/config.type.ts:201](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L201)
|
||||
|
||||
---
|
||||
|
||||
@@ -59,7 +59,7 @@ This matters if you are using base tag settings.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:197](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L197)
|
||||
[packages/mermaid/src/config.type.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L198)
|
||||
|
||||
---
|
||||
|
||||
@@ -121,7 +121,7 @@ should not change unless content is changed.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:201](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L201)
|
||||
[packages/mermaid/src/config.type.ts:202](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L202)
|
||||
|
||||
---
|
||||
|
||||
@@ -183,7 +183,7 @@ See <https://developer.mozilla.org/en-US/docs/Web/CSS/font-family>
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:203](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L203)
|
||||
[packages/mermaid/src/config.type.ts:204](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L204)
|
||||
|
||||
---
|
||||
|
||||
@@ -217,7 +217,7 @@ If set to true, ignores legacyMathML.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:196](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L196)
|
||||
[packages/mermaid/src/config.type.ts:197](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L197)
|
||||
|
||||
---
|
||||
|
||||
@@ -253,6 +253,16 @@ Defines the seed to be used when using handDrawn look. This is important for the
|
||||
|
||||
---
|
||||
|
||||
### kanban
|
||||
|
||||
• `Optional` **kanban**: `KanbanDiagramConfig`
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:196](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L196)
|
||||
|
||||
---
|
||||
|
||||
### layout
|
||||
|
||||
• `Optional` **layout**: `string`
|
||||
@@ -310,7 +320,7 @@ Defines which main look to use for the diagram.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:204](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L204)
|
||||
[packages/mermaid/src/config.type.ts:205](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L205)
|
||||
|
||||
---
|
||||
|
||||
@@ -354,7 +364,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L199)
|
||||
[packages/mermaid/src/config.type.ts:200](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L200)
|
||||
|
||||
---
|
||||
|
||||
@@ -394,7 +404,7 @@ The maximum allowed size of the users text diagram
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:198](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L198)
|
||||
[packages/mermaid/src/config.type.ts:199](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L199)
|
||||
|
||||
---
|
||||
|
||||
@@ -465,7 +475,7 @@ This is useful when you want to control how to handle syntax errors in your appl
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:210](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L210)
|
||||
[packages/mermaid/src/config.type.ts:211](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L211)
|
||||
|
||||
---
|
||||
|
||||
@@ -518,7 +528,7 @@ You may also use `themeCSS` to override this value.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/config.type.ts:202](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L202)
|
||||
[packages/mermaid/src/config.type.ts:203](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/config.type.ts#L203)
|
||||
|
||||
---
|
||||
|
||||
|
@@ -19,4 +19,4 @@ The `parseError` function will not be called.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:43](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L43)
|
||||
[packages/mermaid/src/types.ts:59](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L59)
|
||||
|
@@ -10,6 +10,18 @@
|
||||
|
||||
## Properties
|
||||
|
||||
### config
|
||||
|
||||
• **config**: [`MermaidConfig`](mermaid.MermaidConfig.md)
|
||||
|
||||
The config passed as YAML frontmatter or directives
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:70](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L70)
|
||||
|
||||
---
|
||||
|
||||
### diagramType
|
||||
|
||||
• **diagramType**: `string`
|
||||
@@ -18,4 +30,4 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:50](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L50)
|
||||
[packages/mermaid/src/types.ts:66](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L66)
|
||||
|
@@ -39,7 +39,7 @@ bindFunctions?.(div); // To call bindFunctions only if it's present.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:73](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L73)
|
||||
[packages/mermaid/src/types.ts:98](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L98)
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@ The diagram type, e.g. 'flowchart', 'sequence', etc.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:63](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L63)
|
||||
[packages/mermaid/src/types.ts:88](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L88)
|
||||
|
||||
---
|
||||
|
||||
@@ -63,4 +63,4 @@ The svg code for the rendered graph.
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/types.ts:59](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L59)
|
||||
[packages/mermaid/src/types.ts:84](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/types.ts#L84)
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
#### Defined in
|
||||
|
||||
[packages/mermaid/src/defaultConfig.ts:266](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L266)
|
||||
[packages/mermaid/src/defaultConfig.ts:270](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L270)
|
||||
|
||||
---
|
||||
|
||||
|
@@ -64,7 +64,7 @@ To add an integration to this list, see the [Integrations - create page](./integ
|
||||
- [Mermaid Flow Visual Editor](https://www.mermaidflow.app) ✅
|
||||
- [Mermerd](https://github.com/KarnerTh/mermerd)
|
||||
- [Slab](https://slab.com) ✅
|
||||
- [Swimm](https://docs.swimm.io/features/diagrams-and-charts/#mermaid--swimm--up-to-date-diagrams-) ✅
|
||||
- [Swimm](https://docs.swimm.io/features/diagrams-and-charts) ✅
|
||||
- [NotesHub](https://noteshub.app) ✅
|
||||
- [Notion](https://notion.so) ✅
|
||||
- [Observable](https://observablehq.com/@observablehq/mermaid) ✅
|
||||
@@ -145,7 +145,7 @@ Communication tools and platforms
|
||||
- [Mermaid Extension](https://www.mediawiki.org/wiki/Extension:Mermaid)
|
||||
- [PmWiki](https://www.pmwiki.org)
|
||||
- [MermaidJs Cookbook recipe](https://www.pmwiki.org/wiki/Cookbook/MermaidJs)
|
||||
- [Semantic Media Wiki](https://semantic-mediawiki.org)
|
||||
- [Semantic Media Wiki](https://www.semantic-mediawiki.org)
|
||||
- [Mermaid Plugin](https://github.com/SemanticMediaWiki/Mermaid)
|
||||
- [TiddlyWiki](https://tiddlywiki.com/)
|
||||
- [mermaid-tw5: wrapper for Mermaid Live](https://github.com/efurlanm/mermaid-tw5)
|
||||
@@ -185,8 +185,6 @@ Communication tools and platforms
|
||||
- [=Diagram block](https://github.com/zag/podlite/tree/main/packages/podlite-diagrams)
|
||||
- [Standard Notes](https://standardnotes.com/)
|
||||
- [Mermaid Extension](https://github.com/nienow/sn-mermaid)
|
||||
- [Sublime Text 3](https://sublimetext.com)
|
||||
- [Mermaid Package](https://packagecontrol.io/packages/Mermaid)
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Mermaid Editor](https://marketplace.visualstudio.com/items?itemName=tomoyukim.vscode-mermaid-editor)
|
||||
- [Mermaid Export](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.mermaid-export)
|
||||
@@ -200,15 +198,22 @@ Communication tools and platforms
|
||||
- [Vim](https://www.vim.org)
|
||||
- [Vim Diagram Syntax](https://github.com/zhaozg/vim-diagram)
|
||||
- [Official Vim Syntax and ft plugin](https://github.com/craigmac/vim-mermaid)
|
||||
- [Zed](https://zed.dev)
|
||||
- [zed-mermaid](https://github.com/gabeidx/zed-mermaid)
|
||||
|
||||
### Document Generation
|
||||
|
||||
- [Astro](https://astro.build/)
|
||||
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
|
||||
- [Codedoc](https://codedoc.cc/)
|
||||
- [codedoc-mermaid-plugin](https://www.npmjs.com/package/codedoc-mermaid-plugin)
|
||||
- [Docsy Hugo Theme](https://www.docsy.dev/docs/adding-content/lookandfeel/#diagrams-with-mermaid) ✅
|
||||
- [Docusaurus](https://docusaurus.io/docs/markdown-features/diagrams) ✅
|
||||
- [Gatsby](https://www.gatsbyjs.com/)
|
||||
- [gatsby-remark-mermaid](https://github.com/remcohaszing/gatsby-remark-mermaid)
|
||||
- [Jekyll](https://jekyllrb.com/)
|
||||
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
|
||||
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
|
||||
- [JSDoc](https://jsdoc.app/)
|
||||
- [jsdoc-mermaid](https://github.com/Jellyvision/jsdoc-mermaid)
|
||||
- [Madness](https://madness.dannyb.co/)
|
||||
@@ -217,7 +222,7 @@ Communication tools and platforms
|
||||
- [MkDocs](https://www.mkdocs.org)
|
||||
- [mkdocs-mermaid2-plugin](https://github.com/fralau/mkdocs-mermaid2-plugin)
|
||||
- [mkdocs-material](https://github.com/squidfunk/mkdocs-material), check the [docs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/)
|
||||
- [Quarto](https://quarto.org/)
|
||||
- [Quarto](https://quarto.org/) ✅
|
||||
- [rehype](https://github.com/rehypejs/rehype)
|
||||
- [rehype-mermaid](https://github.com/remcohaszing/rehype-mermaid)
|
||||
- [remark](https://remark.js.org/)
|
||||
@@ -246,17 +251,12 @@ Communication tools and platforms
|
||||
|
||||
### Other
|
||||
|
||||
- [Astro](https://astro.build/)
|
||||
- [Adding diagrams to your Astro site with MermaidJS and Playwright](https://agramont.net/blog/diagraming-with-mermaidjs-astro/)
|
||||
- [Bisheng](https://www.npmjs.com/package/bisheng)
|
||||
- [bisheng-plugin-mermaid](https://github.com/yct21/bisheng-plugin-mermaid)
|
||||
- [Blazorade Mermaid: Render Mermaid diagrams in Blazor applications](https://github.com/Blazorade/Blazorade-Mermaid/wiki)
|
||||
- [Codemia: A tool to practice system design problems](https://codemia.io) ✅
|
||||
- [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||
- [Rendering Mermaid graphs](https://github.com/elixir-lang/ex_doc#rendering-mermaid-graphs)
|
||||
- [Jekyll](https://jekyllrb.com/)
|
||||
- [jekyll-mermaid](https://rubygems.org/gems/jekyll-mermaid)
|
||||
- [jekyll-mermaid-diagrams](https://github.com/fuzhibo/jekyll-mermaid-diagrams)
|
||||
- [MarkChart: Preview Mermaid diagrams on macOS](https://markchart.app/)
|
||||
- [mermaid-isomorphic](https://github.com/remcohaszing/mermaid-isomorphic)
|
||||
- [mermaid-server: Generate diagrams using a HTTP request](https://github.com/TomWright/mermaid-server)
|
||||
|
@@ -22,17 +22,20 @@ Try the Ultimate AI, Mermaid, and Visual Diagramming Suite by creating an accoun
|
||||
|
||||
- **Editor** - A web based editor for creating and editing Mermaid diagrams.
|
||||
|
||||
- **Visual Editor** - The Visual Editor enables users of all skill levels to create diagrams easily and efficiently, with both GUI and code-based editing options.
|
||||
- **Mermaid AI** - Use our embedded AI Chat to generate diagrams from natural language descriptions.
|
||||
|
||||
- **AI Chat** - Use our embedded AI Chat to generate diagrams from natural language descriptions.
|
||||
- **Whiteboard** - A virtual whiteboard for creating and editing Mermaid diagrams.
|
||||
|
||||
- **Plugins** - A plugin system for extending the functionality of Mermaid.
|
||||
|
||||
Official Mermaid Chart plugins:
|
||||
|
||||
- [Mermaid Chart GPT](https://chat.openai.com/g/g-1IRFKwq4G-mermaid-chart)
|
||||
- [Confluence](https://marketplace.atlassian.com/apps/1234056/mermaid-chart-for-confluence?hosting=cloud&tab=overview)
|
||||
- [Jira](https://marketplace.atlassian.com/apps/1234810/mermaid-chart-for-jira?tab=overview&hosting=cloud)
|
||||
- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MermaidChart.vscode-mermaid-chart)
|
||||
- [JetBrains IDE](https://plugins.jetbrains.com/plugin/23043-mermaid-chart)
|
||||
- [Google Docs](https://gsuite.google.com/marketplace/app/mermaidchart/947683068472)
|
||||
- [Microsoft PowerPoint and Word](https://appsource.microsoft.com/en-us/product/office/WA200006214?tab=Overview)
|
||||
|
||||
Visit our [Plugins](https://www.mermaidchart.com/plugins) page for more information.
|
||||
|
@@ -94,10 +94,8 @@ Mermaid offers a variety of styles or “looks” for your diagrams, allowing yo
|
||||
|
||||
**Available Looks:**
|
||||
|
||||
```
|
||||
• Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
|
||||
• Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. It’s great for consistency across projects or when you want to keep the familiar aesthetic.
|
||||
```
|
||||
- Hand-Drawn Look: For a more personal, creative touch, the hand-drawn look brings a sketch-like quality to your diagrams. This style is perfect for informal settings or when you want to add a bit of personality to your diagrams.
|
||||
- Classic Look: If you prefer the traditional Mermaid style, the classic look maintains the original appearance that many users are familiar with. It’s great for consistency across projects or when you want to keep the familiar aesthetic.
|
||||
|
||||
**How to Select a Look:**
|
||||
|
||||
@@ -133,10 +131,8 @@ In addition to customizing the look of your diagrams, Mermaid Chart now allows y
|
||||
|
||||
#### Supported Layout Algorithms:
|
||||
|
||||
```
|
||||
• Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
|
||||
• ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
|
||||
```
|
||||
- Dagre (default): This is the classic layout algorithm that has been used in Mermaid for a long time. It provides a good balance of simplicity and visual clarity, making it ideal for most diagrams.
|
||||
- ELK: For those who need more sophisticated layout capabilities, especially when working with large or intricate diagrams, the ELK (Eclipse Layout Kernel) layout offers advanced options. It provides a more optimized arrangement, potentially reducing overlapping and improving readability. This is not included out the box but needs to be added when integrating mermaid for sites/applications that want to have elk support.
|
||||
|
||||
#### How to Select a Layout Algorithm:
|
||||
|
||||
|
@@ -6,6 +6,30 @@
|
||||
|
||||
# Blog
|
||||
|
||||
## [Mermaid 11.4 is out: New Features and Kanban Diagramming](https://www.mermaidchart.com/blog/posts/mermaid-11-4-is-out-new-features-and-kanban-diagramming)
|
||||
|
||||
Mermaid 11.4 brings enhanced functionality with the introduction of Kanban diagrams, allowing users to create visual workflows with status columns and task details.
|
||||
|
||||
October 31, 2024 · 2 mins
|
||||
|
||||
## [How To Build an ER Diagram with Mermaid Chart](https://www.mermaidchart.com/blog/posts/how-to-build-an-er-diagram-with-mermaid-chart)
|
||||
|
||||
An entity relationship (ER) diagram acts like a blueprint for your database. This makes ER diagrams effective tools for anyone dealing with complex databases, data modeling, and AI model training.
|
||||
|
||||
October 24, 2024 · 4 mins
|
||||
|
||||
## [Expanding the Horizons of Mermaid Flowcharts: Introducing 30 New Shapes!](https://www.mermaidchart.com/blog/posts/new-mermaid-flowchart-shapes/)
|
||||
|
||||
24 September 2024 · 5 mins
|
||||
|
||||
Discover 30 new shapes in Mermaid flowcharts, offering enhanced clarity, customization, and versatility for more dynamic and expressive visualizations.
|
||||
|
||||
## [Introducing Architecture Diagrams in Mermaid](https://www.mermaidchart.com/blog/posts/mermaid-supports-architecture-diagrams/)
|
||||
|
||||
2 September 2024 · 2 mins
|
||||
|
||||
Discover the fresh new and unique Neo and Hand-Drawn looks for Mermaid Diagrams, while still offering the classic look you love.
|
||||
|
||||
## [Mermaid v11 is out!](https://www.mermaidchart.com/blog/posts/mermaid-v11/)
|
||||
|
||||
23 August 2024 · 2 mins
|
||||
|
@@ -79,15 +79,15 @@ service {service id}({icon name})[{title}] (in {parent id})?
|
||||
Put together:
|
||||
|
||||
```
|
||||
service database(db)[Database]
|
||||
service database1(database)[My Database]
|
||||
```
|
||||
|
||||
creates the service identified as `database`, using the icon `db`, with the label `Database`.
|
||||
creates the service identified as `database1`, using the icon `database`, with the label `My Database`.
|
||||
|
||||
If the service belongs to a group, it can be placed inside it through the optional `in` keyword
|
||||
|
||||
```
|
||||
service database(db)[Database] in private_api
|
||||
service database1(database)[My Database] in private_api
|
||||
```
|
||||
|
||||
### Edges
|
||||
@@ -194,55 +194,7 @@ architecture-beta
|
||||
## Icons
|
||||
|
||||
By default, architecture diagram supports the following icons: `cloud`, `database`, `disk`, `internet`, `server`.
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps below.
|
||||
|
||||
The icon packs available can be found at [icones.js.org](https://icones.js.org/).
|
||||
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.
|
||||
|
||||
Using JSON file directly from CDN:
|
||||
|
||||
```js
|
||||
import mermaid from 'CDN/mermaid.esm.mjs';
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () =>
|
||||
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
Using packages and a bundler:
|
||||
|
||||
```bash
|
||||
npm install @iconify-json/logos
|
||||
```
|
||||
|
||||
With lazy loading
|
||||
|
||||
```js
|
||||
import mermaid from 'mermaid';
|
||||
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: 'logos',
|
||||
loader: () => import('@iconify-json/logos').then((module) => module.icons),
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
Without lazy loading
|
||||
|
||||
```js
|
||||
import mermaid from 'mermaid';
|
||||
import { icons } from '@iconify-json/logos';
|
||||
mermaid.registerIconPacks([
|
||||
{
|
||||
name: icons.prefix, // To use the prefix defined in the icon pack
|
||||
icons,
|
||||
},
|
||||
]);
|
||||
```
|
||||
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps [here](../config/icons.md).
|
||||
|
||||
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.
|
||||
|
||||
|
@@ -141,7 +141,7 @@ block-beta
|
||||
a["A label"] b:2 c:2 d
|
||||
```
|
||||
|
||||
In this example, the block labeled "A wide one" spans two columns, while blocks 'b', 'c', and 'd' are allocated their own columns. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
|
||||
In this example, the block labeled "A labels" spans one column, while blocks 'b', 'c' span 2 columns, and 'd' is again allocated its own column. This flexibility in block sizing is crucial for accurately representing systems with components of varying significance or size.
|
||||
|
||||
### Creating Composite Blocks
|
||||
|
||||
@@ -211,6 +211,27 @@ block-beta
|
||||
|
||||
This example demonstrates how Mermaid dynamically adjusts the width of the columns to accommodate the widest block, in this case, 'a' and the composite block 'e'. This dynamic adjustment is essential for creating visually balanced and easy-to-understand diagrams.
|
||||
|
||||
**Merging Blocks Horizontally:**
|
||||
In scenarios where you need to stack blocks horizontally, you can use column width to accomplish the task. Blocks can be arranged vertically by putting them in a single column. Here is how you can create a block diagram in which 4 blocks are stacked on top of each other:
|
||||
|
||||
```mermaid-example
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
a["A label"] b c d
|
||||
end
|
||||
```
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
block
|
||||
columns 1
|
||||
a["A label"] b c d
|
||||
end
|
||||
```
|
||||
|
||||
In this example, the width of the merged block dynamically adjusts to the width of the largest child block.
|
||||
|
||||
With these advanced configuration options, Mermaid's block diagrams can be tailored to represent a wide array of complex systems and structures. The flexibility offered by these features enables users to create diagrams that are both informative and visually appealing. In the following sections, we will explore further capabilities, including different block shapes and linking options.
|
||||
|
||||
## 4. Block Varieties and Shapes
|
||||
|
@@ -427,6 +427,51 @@ And `Link` can be one of:
|
||||
| -- | Solid |
|
||||
| .. | Dashed |
|
||||
|
||||
### Lollipop Interfaces
|
||||
|
||||
Classes can also be given a special relation type that defines a lollipop interface on the class. A lollipop interface is defined using the following syntax:
|
||||
|
||||
- `bar ()-- foo`
|
||||
- `foo --() bar`
|
||||
|
||||
The interface (bar) with the lollipop connects to the class (foo).
|
||||
|
||||
Note: Each interface that is defined is unique and is meant to not be shared between classes / have multiple edges connecting to it.
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
bar ()-- foo
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
bar ()-- foo
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Class01 {
|
||||
int amount
|
||||
draw()
|
||||
}
|
||||
Class01 --() bar
|
||||
Class02 --() bar
|
||||
|
||||
foo ()-- Class01
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Class01 {
|
||||
int amount
|
||||
draw()
|
||||
}
|
||||
Class01 --() bar
|
||||
Class02 --() bar
|
||||
|
||||
foo ()-- Class01
|
||||
```
|
||||
|
||||
## Define Namespace
|
||||
|
||||
A namespace groups classes.
|
||||
@@ -776,10 +821,12 @@ Beginner's tip—a full example using interactive links in an HTML page:
|
||||
|
||||
## Styling
|
||||
|
||||
### Styling a node (v10.7.0+)
|
||||
### Styling a node
|
||||
|
||||
It is possible to apply specific styles such as a thicker border or a different background color to an individual node using the `style` keyword.
|
||||
|
||||
Note that notes and namespaces cannot be styled individually but do support themes.
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Animal
|
||||
@@ -799,11 +846,102 @@ classDiagram
|
||||
#### Classes
|
||||
|
||||
More convenient than defining the style every time is to define a class of styles and attach this class to the nodes that
|
||||
should have a different look. This is done by predefining classes in css styles that can be applied from the graph definition using the `cssClass` statement or the `:::` short hand.
|
||||
should have a different look.
|
||||
|
||||
A class definition looks like the example below:
|
||||
|
||||
```
|
||||
classDef className fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
```
|
||||
|
||||
Also, it is possible to define style to multiple classes in one statement:
|
||||
|
||||
```
|
||||
classDef firstClassName,secondClassName font-size:12pt;
|
||||
```
|
||||
|
||||
Attachment of a class to a node is done as per below:
|
||||
|
||||
```
|
||||
cssClass "nodeId1" className;
|
||||
```
|
||||
|
||||
It is also possible to attach a class to a list of nodes in one statement:
|
||||
|
||||
```
|
||||
cssClass "nodeId1,nodeId2" className;
|
||||
```
|
||||
|
||||
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Animal:::someclass
|
||||
classDef someclass fill:#f96
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Animal:::someclass
|
||||
classDef someclass fill:#f96
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Animal:::someclass {
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
classDef someclass fill:#f96
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Animal:::someclass {
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
classDef someclass fill:#f96
|
||||
```
|
||||
|
||||
### Default class
|
||||
|
||||
If a class is named default it will be applied to all nodes. Specific styles and classes should be defined afterwards to override the applied default styling.
|
||||
|
||||
```
|
||||
classDef default fill:#f9f,stroke:#333,stroke-width:4px;
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Animal:::pink
|
||||
class Mineral
|
||||
|
||||
classDef default fill:#f96,color:red
|
||||
classDef pink color:#f9f
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Animal:::pink
|
||||
class Mineral
|
||||
|
||||
classDef default fill:#f96,color:red
|
||||
classDef pink color:#f9f
|
||||
```
|
||||
|
||||
### CSS Classes
|
||||
|
||||
It is also possible to predefine classes in CSS styles that can be applied from the graph definition as in the example
|
||||
below:
|
||||
|
||||
**Example style**
|
||||
|
||||
```html
|
||||
<style>
|
||||
.styleClass > rect {
|
||||
.styleClass > * > g {
|
||||
fill: #ff0000;
|
||||
stroke: #ffff00;
|
||||
stroke-width: 4px;
|
||||
@@ -811,19 +949,7 @@ should have a different look. This is done by predefining classes in css styles
|
||||
</style>
|
||||
```
|
||||
|
||||
Then attaching that class to a specific node:
|
||||
|
||||
```
|
||||
cssClass "nodeId1" styleClass;
|
||||
```
|
||||
|
||||
It is also possible to attach a class to a list of nodes in one statement:
|
||||
|
||||
```
|
||||
cssClass "nodeId1,nodeId2" styleClass;
|
||||
```
|
||||
|
||||
A shorter form of adding a class is to attach the classname to the node using the `:::` operator:
|
||||
**Example definition**
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
@@ -835,136 +961,32 @@ classDiagram
|
||||
class Animal:::styleClass
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```mermaid-example
|
||||
classDiagram
|
||||
class Animal:::styleClass {
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Animal:::styleClass {
|
||||
-int sizeInFeet
|
||||
-canEat()
|
||||
}
|
||||
```
|
||||
|
||||
?> cssClasses cannot be added using this shorthand method at the same time as a relation statement.
|
||||
|
||||
?> Due to limitations with existing markup for class diagrams, it is not currently possible to define css classes within the diagram itself. **_Coming soon!_**
|
||||
|
||||
### Default Styles
|
||||
|
||||
The main styling of the class diagram is done with a preset number of css classes. During rendering these classes are extracted from the file located at src/themes/class.scss. The classes used here are described below:
|
||||
|
||||
| Class | Description |
|
||||
| ------------------ | ----------------------------------------------------------------- |
|
||||
| g.classGroup text | Styles for general class text |
|
||||
| classGroup .title | Styles for general class title |
|
||||
| g.classGroup rect | Styles for class diagram rectangle |
|
||||
| g.classGroup line | Styles for class diagram line |
|
||||
| .classLabel .box | Styles for class label box |
|
||||
| .classLabel .label | Styles for class label text |
|
||||
| composition | Styles for composition arrow head and arrow line |
|
||||
| aggregation | Styles for aggregation arrow head and arrow line(dashed or solid) |
|
||||
| dependency | Styles for dependency arrow head and arrow line |
|
||||
|
||||
#### Sample stylesheet
|
||||
|
||||
```scss
|
||||
body {
|
||||
background: white;
|
||||
}
|
||||
|
||||
g.classGroup text {
|
||||
fill: $nodeBorder;
|
||||
stroke: none;
|
||||
font-family: 'trebuchet ms', verdana, arial;
|
||||
font-family: var(--mermaid-font-family);
|
||||
font-size: 10px;
|
||||
|
||||
.title {
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
|
||||
g.classGroup rect {
|
||||
fill: $nodeBkg;
|
||||
stroke: $nodeBorder;
|
||||
}
|
||||
|
||||
g.classGroup line {
|
||||
stroke: $nodeBorder;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.classLabel .box {
|
||||
stroke: none;
|
||||
stroke-width: 0;
|
||||
fill: $nodeBkg;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.classLabel .label {
|
||||
fill: $nodeBorder;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.relation {
|
||||
stroke: $nodeBorder;
|
||||
stroke-width: 1;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
@mixin composition {
|
||||
fill: $nodeBorder;
|
||||
stroke: $nodeBorder;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#compositionStart {
|
||||
@include composition;
|
||||
}
|
||||
|
||||
#compositionEnd {
|
||||
@include composition;
|
||||
}
|
||||
|
||||
@mixin aggregation {
|
||||
fill: $nodeBkg;
|
||||
stroke: $nodeBorder;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
#aggregationStart {
|
||||
@include aggregation;
|
||||
}
|
||||
|
||||
#aggregationEnd {
|
||||
@include aggregation;
|
||||
}
|
||||
|
||||
#dependencyStart {
|
||||
@include composition;
|
||||
}
|
||||
|
||||
#dependencyEnd {
|
||||
@include composition;
|
||||
}
|
||||
|
||||
#extensionStart {
|
||||
@include composition;
|
||||
}
|
||||
|
||||
#extensionEnd {
|
||||
@include composition;
|
||||
}
|
||||
```
|
||||
> cssClasses cannot be added using this shorthand method at the same time as a relation statement.
|
||||
|
||||
## Configuration
|
||||
|
||||
`Coming soon!`
|
||||
### Members Box
|
||||
|
||||
It is possible to hide the empty members box of a class node.
|
||||
|
||||
This is done by changing the **hideEmptyMembersBox** value of the class diagram configuration. For more information on how to edit the Mermaid configuration see the [configuration page.](https://mermaid.js.org/config/configuration.html)
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
config:
|
||||
class:
|
||||
hideEmptyMembersBox: true
|
||||
---
|
||||
classDiagram
|
||||
class Duck
|
||||
```
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
class:
|
||||
hideEmptyMembersBox: true
|
||||
---
|
||||
classDiagram
|
||||
class Duck
|
||||
```
|
||||
|
@@ -298,6 +298,694 @@ flowchart TD
|
||||
id1(((This is the text in the circle)))
|
||||
```
|
||||
|
||||
## Expanded Node Shapes in Mermaid Flowcharts (v11.3.0+)
|
||||
|
||||
Mermaid introduces 30 new shapes to enhance the flexibility and precision of flowchart creation. These new shapes provide more options to represent processes, decisions, events, data storage visually, and other elements within your flowcharts, improving clarity and semantic meaning.
|
||||
|
||||
New Syntax for Shape Definition
|
||||
|
||||
Mermaid now supports a general syntax for defining shape types to accommodate the growing number of shapes. This syntax allows you to assign specific shapes to nodes using a clear and flexible format:
|
||||
|
||||
```
|
||||
A@{ shape: rect }
|
||||
```
|
||||
|
||||
This syntax creates a node A as a rectangle. It renders in the same way as `A["A"]`, or `A`.
|
||||
|
||||
### Complete List of New Shapes
|
||||
|
||||
Below is a comprehensive list of the newly introduced shapes and their corresponding semantic meanings, short names, and aliases:
|
||||
|
||||
| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** |
|
||||
| --------------------------------- | ---------------------- | -------------- | ------------------------------ | ---------------------------------------------------------------- |
|
||||
| Card | Notched Rectangle | `notch-rect` | Represents a card | `card`, `notched-rectangle` |
|
||||
| Collate | Hourglass | `hourglass` | Represents a collate operation | `collate`, `hourglass` |
|
||||
| Com Link | Lightning Bolt | `bolt` | Communication link | `com-link`, `lightning-bolt` |
|
||||
| Comment | Curly Brace | `brace` | Adds a comment | `brace-l`, `comment` |
|
||||
| Comment Right | Curly Brace | `brace-r` | Adds a comment | |
|
||||
| Comment with braces on both sides | Curly Braces | `braces` | Adds a comment | |
|
||||
| Data Input/Output | Lean Right | `lean-r` | Represents input or output | `in-out`, `lean-right` |
|
||||
| Data Input/Output | Lean Left | `lean-l` | Represents output or input | `lean-left`, `out-in` |
|
||||
| Database | Cylinder | `cyl` | Database storage | `cylinder`, `database`, `db` |
|
||||
| Decision | Diamond | `diam` | Decision-making step | `decision`, `diamond`, `question` |
|
||||
| Delay | Half-Rounded Rectangle | `delay` | Represents a delay | `half-rounded-rectangle` |
|
||||
| Direct Access Storage | Horizontal Cylinder | `h-cyl` | Direct access storage | `das`, `horizontal-cylinder` |
|
||||
| Disk Storage | Lined Cylinder | `lin-cyl` | Disk storage | `disk`, `lined-cylinder` |
|
||||
| Display | Curved Trapezoid | `curv-trap` | Represents a display | `curved-trapezoid`, `display` |
|
||||
| Divided Process | Divided Rectangle | `div-rect` | Divided process shape | `div-proc`, `divided-process`, `divided-rectangle` |
|
||||
| Document | Document | `doc` | Represents a document | `doc`, `document` |
|
||||
| Event | Rounded Rectangle | `rounded` | Represents an event | `event` |
|
||||
| Extract | Triangle | `tri` | Extraction process | `extract`, `triangle` |
|
||||
| Fork/Join | Filled Rectangle | `fork` | Fork or join in process flow | `join` |
|
||||
| Internal Storage | Window Pane | `win-pane` | Internal storage | `internal-storage`, `window-pane` |
|
||||
| Junction | Filled Circle | `f-circ` | Junction point | `filled-circle`, `junction` |
|
||||
| Lined Document | Lined Document | `lin-doc` | Lined document | `lined-document` |
|
||||
| Lined/Shaded Process | Lined Rectangle | `lin-rect` | Lined process shape | `lin-proc`, `lined-process`, `lined-rectangle`, `shaded-process` |
|
||||
| Loop Limit | Trapezoidal Pentagon | `notch-pent` | Loop limit step | `loop-limit`, `notched-pentagon` |
|
||||
| Manual File | Flipped Triangle | `flip-tri` | Manual file operation | `flipped-triangle`, `manual-file` |
|
||||
| Manual Input | Sloped Rectangle | `sl-rect` | Manual input step | `manual-input`, `sloped-rectangle` |
|
||||
| Manual Operation | Trapezoid Base Top | `trap-t` | Represents a manual task | `inv-trapezoid`, `manual`, `trapezoid-top` |
|
||||
| Multi-Document | Stacked Document | `docs` | Multiple documents | `documents`, `st-doc`, `stacked-document` |
|
||||
| Multi-Process | Stacked Rectangle | `st-rect` | Multiple processes | `processes`, `procs`, `stacked-rectangle` |
|
||||
| Odd | Odd | `odd` | Odd shape | |
|
||||
| Paper Tape | Flag | `flag` | Paper tape | `paper-tape` |
|
||||
| Prepare Conditional | Hexagon | `hex` | Preparation or condition step | `hexagon`, `prepare` |
|
||||
| Priority Action | Trapezoid Base Bottom | `trap-b` | Priority action | `priority`, `trapezoid`, `trapezoid-bottom` |
|
||||
| Process | Rectangle | `rect` | Standard process shape | `proc`, `process`, `rectangle` |
|
||||
| Start | Circle | `circle` | Starting point | `circ` |
|
||||
| Start | Small Circle | `sm-circ` | Small starting point | `small-circle`, `start` |
|
||||
| Stop | Double Circle | `dbl-circ` | Represents a stop point | `double-circle` |
|
||||
| Stop | Framed Circle | `fr-circ` | Stop point | `framed-circle`, `stop` |
|
||||
| Stored Data | Bow Tie Rectangle | `bow-rect` | Stored data | `bow-tie-rectangle`, `stored-data` |
|
||||
| Subprocess | Framed Rectangle | `fr-rect` | Subprocess | `framed-rectangle`, `subproc`, `subprocess`, `subroutine` |
|
||||
| Summary | Crossed Circle | `cross-circ` | Summary | `crossed-circle`, `summary` |
|
||||
| Tagged Document | Tagged Document | `tag-doc` | Tagged document | `tag-doc`, `tagged-document` |
|
||||
| Tagged Process | Tagged Rectangle | `tag-rect` | Tagged process | `tag-proc`, `tagged-process`, `tagged-rectangle` |
|
||||
| Terminal Point | Stadium | `stadium` | Terminal point | `pill`, `terminal` |
|
||||
| Text Block | Text Block | `text` | Text block | |
|
||||
|
||||
### Example Flowchart with New Shapes
|
||||
|
||||
Here’s an example flowchart that utilizes some of the newly introduced shapes:
|
||||
|
||||
```mermaid-example
|
||||
flowchart RL
|
||||
A@{ shape: manual-file, label: "File Handling"}
|
||||
B@{ shape: manual-input, label: "User Input"}
|
||||
C@{ shape: docs, label: "Multiple Documents"}
|
||||
D@{ shape: procs, label: "Process Automation"}
|
||||
E@{ shape: paper-tape, label: "Paper Records"}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart RL
|
||||
A@{ shape: manual-file, label: "File Handling"}
|
||||
B@{ shape: manual-input, label: "User Input"}
|
||||
C@{ shape: docs, label: "Multiple Documents"}
|
||||
D@{ shape: procs, label: "Process Automation"}
|
||||
E@{ shape: paper-tape, label: "Paper Records"}
|
||||
```
|
||||
|
||||
### Process
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: rect, label: "This is a process" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: rect, label: "This is a process" }
|
||||
```
|
||||
|
||||
### Event
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: rounded, label: "This is an event" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: rounded, label: "This is an event" }
|
||||
```
|
||||
|
||||
### Terminal Point (Stadium)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: stadium, label: "Terminal point" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: stadium, label: "Terminal point" }
|
||||
```
|
||||
|
||||
### Subprocess
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: subproc, label: "This is a subprocess" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: subproc, label: "This is a subprocess" }
|
||||
```
|
||||
|
||||
### Database (Cylinder)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: cyl, label: "Database" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: cyl, label: "Database" }
|
||||
```
|
||||
|
||||
### Start (Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: circle, label: "Start" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: circle, label: "Start" }
|
||||
```
|
||||
|
||||
### Odd
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: odd, label: "Odd shape" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: odd, label: "Odd shape" }
|
||||
```
|
||||
|
||||
### Decision (Diamond)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: diamond, label: "Decision" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: diamond, label: "Decision" }
|
||||
```
|
||||
|
||||
### Prepare Conditional (Hexagon)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: hex, label: "Prepare conditional" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: hex, label: "Prepare conditional" }
|
||||
```
|
||||
|
||||
### Data Input/Output (Lean Right)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: lean-r, label: "Input/Output" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: lean-r, label: "Input/Output" }
|
||||
```
|
||||
|
||||
### Data Input/Output (Lean Left)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: lean-l, label: "Output/Input" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: lean-l, label: "Output/Input" }
|
||||
```
|
||||
|
||||
### Priority Action (Trapezoid Base Bottom)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: trap-b, label: "Priority action" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: trap-b, label: "Priority action" }
|
||||
```
|
||||
|
||||
### Manual Operation (Trapezoid Base Top)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: trap-t, label: "Manual operation" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: trap-t, label: "Manual operation" }
|
||||
```
|
||||
|
||||
### Stop (Double Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: dbl-circ, label: "Stop" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: dbl-circ, label: "Stop" }
|
||||
```
|
||||
|
||||
### Text Block
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: text, label: "This is a text block" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: text, label: "This is a text block" }
|
||||
```
|
||||
|
||||
### Card (Notched Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: notch-rect, label: "Card" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: notch-rect, label: "Card" }
|
||||
```
|
||||
|
||||
### Lined/Shaded Process
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: lin-rect, label: "Lined process" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: lin-rect, label: "Lined process" }
|
||||
```
|
||||
|
||||
### Start (Small Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: sm-circ, label: "Small start" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: sm-circ, label: "Small start" }
|
||||
```
|
||||
|
||||
### Stop (Framed Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: framed-circle, label: "Stop" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: framed-circle, label: "Stop" }
|
||||
```
|
||||
|
||||
### Fork/Join (Long Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: fork, label: "Fork or Join" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: fork, label: "Fork or Join" }
|
||||
```
|
||||
|
||||
### Collate (Hourglass)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: hourglass, label: "Collate" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: hourglass, label: "Collate" }
|
||||
```
|
||||
|
||||
### Comment (Curly Brace)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: comment, label: "Comment" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: comment, label: "Comment" }
|
||||
```
|
||||
|
||||
### Comment Right (Curly Brace Right)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: brace-r, label: "Comment" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: brace-r, label: "Comment" }
|
||||
```
|
||||
|
||||
### Comment with braces on both sides
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: braces, label: "Comment" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: braces, label: "Comment" }
|
||||
```
|
||||
|
||||
### Com Link (Lightning Bolt)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: bolt, label: "Communication link" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: bolt, label: "Communication link" }
|
||||
```
|
||||
|
||||
### Document
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: doc, label: "Document" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: doc, label: "Document" }
|
||||
```
|
||||
|
||||
### Delay (Half-Rounded Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: delay, label: "Delay" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: delay, label: "Delay" }
|
||||
```
|
||||
|
||||
### Direct Access Storage (Horizontal Cylinder)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: das, label: "Direct access storage" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: das, label: "Direct access storage" }
|
||||
```
|
||||
|
||||
### Disk Storage (Lined Cylinder)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: lin-cyl, label: "Disk storage" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: lin-cyl, label: "Disk storage" }
|
||||
```
|
||||
|
||||
### Display (Curved Trapezoid)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: curv-trap, label: "Display" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: curv-trap, label: "Display" }
|
||||
```
|
||||
|
||||
### Divided Process (Divided Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: div-rect, label: "Divided process" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: div-rect, label: "Divided process" }
|
||||
```
|
||||
|
||||
### Extract (Small Triangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: tri, label: "Extract" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: tri, label: "Extract" }
|
||||
```
|
||||
|
||||
### Internal Storage (Window Pane)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: win-pane, label: "Internal storage" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: win-pane, label: "Internal storage" }
|
||||
```
|
||||
|
||||
### Junction (Filled Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: f-circ, label: "Junction" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: f-circ, label: "Junction" }
|
||||
```
|
||||
|
||||
### Lined Document
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: lin-doc, label: "Lined document" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: lin-doc, label: "Lined document" }
|
||||
```
|
||||
|
||||
### Loop Limit (Notched Pentagon)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: notch-pent, label: "Loop limit" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: notch-pent, label: "Loop limit" }
|
||||
```
|
||||
|
||||
### Manual File (Flipped Triangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: flip-tri, label: "Manual file" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: flip-tri, label: "Manual file" }
|
||||
```
|
||||
|
||||
### Manual Input (Sloped Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: sl-rect, label: "Manual input" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: sl-rect, label: "Manual input" }
|
||||
```
|
||||
|
||||
### Multi-Document (Stacked Document)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: docs, label: "Multiple documents" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: docs, label: "Multiple documents" }
|
||||
```
|
||||
|
||||
### Multi-Process (Stacked Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: processes, label: "Multiple processes" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: processes, label: "Multiple processes" }
|
||||
```
|
||||
|
||||
### Paper Tape (Flag)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: flag, label: "Paper tape" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: flag, label: "Paper tape" }
|
||||
```
|
||||
|
||||
### Stored Data (Bow Tie Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: bow-rect, label: "Stored data" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: bow-rect, label: "Stored data" }
|
||||
```
|
||||
|
||||
### Summary (Crossed Circle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: cross-circ, label: "Summary" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: cross-circ, label: "Summary" }
|
||||
```
|
||||
|
||||
### Tagged Document
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: tag-doc, label: "Tagged document" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: tag-doc, label: "Tagged document" }
|
||||
```
|
||||
|
||||
### Tagged Process (Tagged Rectangle)
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ shape: tag-rect, label: "Tagged process" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ shape: tag-rect, label: "Tagged process" }
|
||||
```
|
||||
|
||||
## Special shapes in Mermaid Flowcharts (v11.3.0+)
|
||||
|
||||
Mermaid also introduces 2 special shapes to enhance your flowcharts: **icon** and **image**. These shapes allow you to include icons and images directly within your flowcharts, providing more visual context and clarity.
|
||||
|
||||
### Icon Shape
|
||||
|
||||
You can use the `icon` shape to include an icon in your flowchart. To use icons, you need to register the icon pack first. Follow the instructions provided [here](../config/icons.md). The syntax for defining an icon shape is as follows:
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ icon: "fa:user", form: "square", label: "User Icon", pos: "t", h: 60 }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ icon: "fa:user", form: "square", label: "User Icon", pos: "t", h: 60 }
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **icon**: The name of the icon from the registered icon pack.
|
||||
- **form**: Specifies the background shape of the icon. If not defined there will be no background to icon. Options include:
|
||||
- `square`
|
||||
- `circle`
|
||||
- `rounded`
|
||||
- **label**: The text label associated with the icon. This can be any string. If not defined, no label will be displayed.
|
||||
- **pos**: The position of the label. If not defined label will default to bottom of icon. Possible values are:
|
||||
- `t`
|
||||
- `b`
|
||||
- **h**: The height of the icon. If not defined this will default to 48 which is minimum.
|
||||
|
||||
### Image Shape
|
||||
|
||||
You can use the `image` shape to include an image in your flowchart. The syntax for defining an image shape is as follows:
|
||||
|
||||
```mermaid-example
|
||||
flowchart TD
|
||||
A@{ img: "https://example.com/image.png", label: "Image Label", pos: "t", w: 60, h: 60, constraint: "off" }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A@{ img: "https://example.com/image.png", label: "Image Label", pos: "t", w: 60, h: 60, constraint: "off" }
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- **img**: The URL of the image to be displayed.
|
||||
- **label**: The text label associated with the image. This can be any string. If not defined, no label will be displayed.
|
||||
- **pos**: The position of the label. If not defined, the label will default to the bottom of the image. Possible values are:
|
||||
- `t`
|
||||
- `b`
|
||||
- **w**: The width of the image. If not defined, this will default to the natural width of the image.
|
||||
- **h**: The height of the image. If not defined, this will default to the natural height of the image.
|
||||
- **constraint**: Determines if the image should constrain the node size. This setting also ensures the image maintains its original aspect ratio, adjusting the height (`h`) accordingly to the width (`w`). If not defined, this will default to `off` Possible values are:
|
||||
- `on`
|
||||
- `off`
|
||||
|
||||
These new shapes provide additional flexibility and visual appeal to your flowcharts, making them more informative and engaging.
|
||||
|
||||
## Links between nodes
|
||||
|
||||
Nodes can be connected with links/edges. It is possible to have different types of links or attach a text string to a link.
|
||||
|
@@ -500,7 +500,7 @@ mermaid.ganttConfig = {
|
||||
sectionFontSize: 24, // Font size for sections
|
||||
numberSectionStyles: 1, // The number of alternating section styles
|
||||
axisFormat: '%d/%m', // Date/time format of the axis
|
||||
tickInterval: '1 week', // Axis ticks
|
||||
tickInterval: '1week', // Axis ticks
|
||||
topAxis: true, // When this flag is set, date labels will be added to the top of the chart
|
||||
displayMode: 'compact', // Turns compact mode on
|
||||
weekday: 'sunday', // On which day a week-based interval should start
|
||||
|
161
docs/syntax/kanban.md
Normal file
161
docs/syntax/kanban.md
Normal file
@@ -0,0 +1,161 @@
|
||||
> **Warning**
|
||||
>
|
||||
> ## THIS IS AN AUTOGENERATED FILE. DO NOT EDIT.
|
||||
>
|
||||
> ## Please edit the corresponding file in [/packages/mermaid/src/docs/syntax/kanban.md](../../packages/mermaid/src/docs/syntax/kanban.md).
|
||||
|
||||
# Mermaid Kanban Diagram Documentation
|
||||
|
||||
Mermaid’s Kanban diagram allows you to create visual representations of tasks moving through different stages of a workflow. This guide explains how to use the Kanban diagram syntax, based on the provided example.
|
||||
|
||||
## Overview
|
||||
|
||||
A Kanban diagram in Mermaid starts with the kanban keyword, followed by the definition of columns (stages) and tasks within those columns.
|
||||
|
||||
```mermaid-example
|
||||
kanban
|
||||
column1[Column Title]
|
||||
task1[Task Description]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
kanban
|
||||
column1[Column Title]
|
||||
task1[Task Description]
|
||||
```
|
||||
|
||||
## Defining Columns
|
||||
|
||||
Columns represent the different stages in your workflow, such as “Todo,” “In Progress,” “Done,” etc. Each column is defined using a unique identifier and a title enclosed in square brackets.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```
|
||||
columnId[Column Title]
|
||||
```
|
||||
|
||||
- columnId: A unique identifier for the column.
|
||||
- \[Column Title]: The title displayed on the column header.
|
||||
|
||||
Like this `id1[Todo]`
|
||||
|
||||
## Adding Tasks to Columns
|
||||
|
||||
Tasks are listed under their respective columns with an indentation. Each task also has a unique identifier and a description enclosed in square brackets.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```
|
||||
taskId[Task Description]
|
||||
```
|
||||
|
||||
```
|
||||
• taskId: A unique identifier for the task.
|
||||
• [Task Description]: The description of the task.
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
docs[Create Documentation]
|
||||
```
|
||||
|
||||
## Adding Metadata to Tasks
|
||||
|
||||
You can include additional metadata for each task using the @{ ... } syntax. Metadata can contain key-value pairs like assigned, ticket, priority, etc. This will be rendered added to the rendering of the node.
|
||||
|
||||
## Supported Metadata Keys
|
||||
|
||||
```
|
||||
• assigned: Specifies who is responsible for the task.
|
||||
• ticket: Links the task to a ticket or issue number.
|
||||
• priority: Indicates the urgency of the task. Allowed values: 'Very High', 'High', 'Low' and 'Very Low'
|
||||
```
|
||||
|
||||
```mermaid-example
|
||||
kanban
|
||||
todo[Todo]
|
||||
id3[Update Database Function]@{ ticket: MC-2037, assigned: 'knsv', priority: 'High' }
|
||||
```
|
||||
|
||||
```mermaid
|
||||
kanban
|
||||
todo[Todo]
|
||||
id3[Update Database Function]@{ ticket: MC-2037, assigned: 'knsv', priority: 'High' }
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
You can customize the Kanban diagram using a configuration block at the beginning of your markdown file. This is useful for setting global settings like a base URL for tickets. Currently there is one configuration option for kanban diagrams `ticketBaseUrl`. This can be set as in the the following example:
|
||||
|
||||
```yaml
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://yourproject.atlassian.net/browse/#TICKET#'
|
||||
---
|
||||
```
|
||||
|
||||
When the kanban item has an assigned ticket number the ticket number in the diagram will have a link to an external system where the ticket is defined. The `ticketBaseUrl` sets the base URL to the external system and #TICKET# is replaced with the ticket value from task metadata to create a valid link.
|
||||
|
||||
## Full Example
|
||||
|
||||
Below is the full Kanban diagram based on the provided example:
|
||||
|
||||
```mermaid-example
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
|
||||
---
|
||||
kanban
|
||||
Todo
|
||||
[Create Documentation]
|
||||
docs[Create Blog about the new diagram]
|
||||
[In progress]
|
||||
id6[Create renderer so that it works in all cases. We also add som extra text here for testing purposes. And some more just for the extra flare.]
|
||||
id9[Ready for deploy]
|
||||
id8[Design grammar]@{ assigned: 'knsv' }
|
||||
id10[Ready for test]
|
||||
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
|
||||
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
|
||||
id11[Done]
|
||||
id5[define getData]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
|
||||
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
|
||||
|
||||
id12[Can't reproduce]
|
||||
id3[Weird flickering in Firefox]
|
||||
```
|
||||
|
||||
```mermaid
|
||||
---
|
||||
config:
|
||||
kanban:
|
||||
ticketBaseUrl: 'https://mermaidchart.atlassian.net/browse/#TICKET#'
|
||||
---
|
||||
kanban
|
||||
Todo
|
||||
[Create Documentation]
|
||||
docs[Create Blog about the new diagram]
|
||||
[In progress]
|
||||
id6[Create renderer so that it works in all cases. We also add som extra text here for testing purposes. And some more just for the extra flare.]
|
||||
id9[Ready for deploy]
|
||||
id8[Design grammar]@{ assigned: 'knsv' }
|
||||
id10[Ready for test]
|
||||
id4[Create parsing tests]@{ ticket: MC-2038, assigned: 'K.Sveidqvist', priority: 'High' }
|
||||
id66[last item]@{ priority: 'Very Low', assigned: 'knsv' }
|
||||
id11[Done]
|
||||
id5[define getData]
|
||||
id2[Title of diagram is more than 100 chars when user duplicates diagram with 100 char]@{ ticket: MC-2036, priority: 'Very High'}
|
||||
id3[Update DB function]@{ ticket: MC-2037, assigned: knsv, priority: 'High' }
|
||||
|
||||
id12[Can't reproduce]
|
||||
id3[Weird flickering in Firefox]
|
||||
```
|
||||
|
||||
In conclusion, creating a Kanban diagram in Mermaid is a straightforward process that effectively visualizes your workflow. Start by using the kanban keyword to initiate the diagram. Define your columns with unique identifiers and titles to represent different stages of your project. Under each column, list your tasks—also with unique identifiers—and provide detailed descriptions as needed. Remember that proper indentation is crucial; tasks must be indented under their parent columns to maintain the correct structure.
|
||||
|
||||
You can enhance your diagram by adding optional metadata to tasks using the @{ ... } syntax, which allows you to include additional context such as assignee, ticket numbers, and priority levels. For further customization, utilize the configuration block at the top of your file to set global options like ticketBaseUrl for linking tickets directly from your diagram.
|
||||
|
||||
By adhering to these guidelines—ensuring unique identifiers, proper indentation, and utilizing metadata and configuration options—you can create a comprehensive and customized Kanban board that effectively maps out your project’s workflow using Mermaid.
|
@@ -155,6 +155,9 @@ end
|
||||
box rgb(33,66,99)
|
||||
... actors ...
|
||||
end
|
||||
box rgba(33,66,99,0.5)
|
||||
... actors ...
|
||||
end
|
||||
```
|
||||
|
||||
> **Note**
|
||||
@@ -217,7 +220,7 @@ There are ten types of arrows currently supported:
|
||||
| `<<->>` | Solid line with bidirectional arrowheads (v11.0.0+) |
|
||||
| `<<-->>` | Dotted line with bidirectional arrowheads (v11.0.0+) |
|
||||
| `-x` | Solid line with a cross at the end |
|
||||
| `--x` | Dotted line with a cross at the end. |
|
||||
| `--x` | Dotted line with a cross at the end |
|
||||
| `-)` | Solid line with an open arrow at the end (async) |
|
||||
| `--)` | Dotted line with a open arrow at the end (async) |
|
||||
|
||||
@@ -580,6 +583,12 @@ sequenceDiagram
|
||||
|
||||
It is possible to highlight flows by providing colored background rects. This is done by the notation
|
||||
|
||||
```
|
||||
rect COLOR
|
||||
... content ...
|
||||
end
|
||||
```
|
||||
|
||||
The colors are defined using rgb and rgba syntax.
|
||||
|
||||
```
|
||||
|
@@ -23,6 +23,7 @@ export default tseslint.config(
|
||||
'**/generated/',
|
||||
'**/coverage/',
|
||||
'packages/mermaid/src/config.type.ts',
|
||||
'packages/mermaid/src/docs/.vitepress/components.d.ts',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
13
package.json
13
package.json
@@ -42,6 +42,7 @@
|
||||
"test": "pnpm lint && vitest run",
|
||||
"test:watch": "vitest --watch",
|
||||
"test:coverage": "vitest --coverage",
|
||||
"test:check:tsc": "tsx scripts/tsc-check.ts",
|
||||
"prepare": "husky && pnpm build",
|
||||
"pre-commit": "lint-staged"
|
||||
},
|
||||
@@ -63,7 +64,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@applitools/eyes-cypress": "^3.44.4",
|
||||
"@argos-ci/cypress": "^2.1.0",
|
||||
"@argos-ci/cypress": "^2.2.2",
|
||||
"@changesets/changelog-github": "^0.5.0",
|
||||
"@changesets/cli": "^2.27.7",
|
||||
"@cspell/eslint-plugin": "^8.8.4",
|
||||
@@ -90,19 +91,20 @@
|
||||
"cspell": "^8.6.0",
|
||||
"cypress": "^13.14.1",
|
||||
"cypress-image-snapshot": "^4.0.1",
|
||||
"cypress-split": "^1.24.0",
|
||||
"esbuild": "^0.21.5",
|
||||
"eslint": "^9.4.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-cypress": "^3.3.0",
|
||||
"eslint-plugin-html": "^8.1.1",
|
||||
"eslint-plugin-jest": "^28.6.0",
|
||||
"eslint-plugin-jsdoc": "^48.2.9",
|
||||
"eslint-plugin-jsdoc": "^50.0.0",
|
||||
"eslint-plugin-json": "^4.0.0",
|
||||
"eslint-plugin-lodash": "^8.0.0",
|
||||
"eslint-plugin-markdown": "^5.0.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
"eslint-plugin-tsdoc": "^0.3.0",
|
||||
"eslint-plugin-unicorn": "^55.0.0",
|
||||
"eslint-plugin-unicorn": "^56.0.0",
|
||||
"express": "^4.19.1",
|
||||
"globals": "^15.4.0",
|
||||
"globby": "^14.0.1",
|
||||
@@ -130,5 +132,10 @@
|
||||
},
|
||||
"nyc": {
|
||||
"report-dir": "coverage/cypress"
|
||||
},
|
||||
"pnpm": {
|
||||
"patchedDependencies": {
|
||||
"roughjs": "patches/roughjs.patch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,12 +1,42 @@
|
||||
# @mermaid-js/layout-elk
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6090](https://github.com/mermaid-js/mermaid/pull/6090) [`654097c`](https://github.com/mermaid-js/mermaid/commit/654097c43801b2d606bc3d2bef8c6fbc3301e9e4) Thanks [@knsv](https://github.com/knsv)! - fix: Updated offset calculations for diamond shape when handling intersections
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6081](https://github.com/mermaid-js/mermaid/pull/6081) [`68f41f6`](https://github.com/mermaid-js/mermaid/commit/68f41f685d2afe7d12f63aabf3de0c3461898471) Thanks [@knsv](https://github.com/knsv)! - fix: Elk rendering of Diamond shape intersections
|
||||
|
||||
- Updated dependencies [[`01b5079`](https://github.com/mermaid-js/mermaid/commit/01b5079562ec8d34ce9964910f168873843c68f8), [`1388662`](https://github.com/mermaid-js/mermaid/commit/1388662132cc829f9820c2e9970ae04e2dd90588), [`fe3cffb`](https://github.com/mermaid-js/mermaid/commit/fe3cffbb673a25b81989aacb06e5d0eda35326db)]:
|
||||
- mermaid@11.4.1
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5825](https://github.com/mermaid-js/mermaid/pull/5825) [`233e36c`](https://github.com/mermaid-js/mermaid/commit/233e36c9884fcce141a72ce7c845179781e18632) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - chore: Update render options
|
||||
|
||||
- Updated dependencies [[`6c5b7ce`](https://github.com/mermaid-js/mermaid/commit/6c5b7ce9f41c0fbd59fe03dbefc8418d97697f0a), [`9e3aa70`](https://github.com/mermaid-js/mermaid/commit/9e3aa705ae21fd4898504ab22d775a9e437b898e), [`de2c05c`](https://github.com/mermaid-js/mermaid/commit/de2c05cd5463af68d19dd7b6b3f1303d69ddb2dd)]:
|
||||
- mermaid@11.3.0
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5847](https://github.com/mermaid-js/mermaid/pull/5847) [`dd03043`](https://github.com/mermaid-js/mermaid/commit/dd0304387e85fc57a9ebb666f89ef788c012c2c5) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: fix render types
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - fix: Updates to the default elk configuration
|
||||
- [#5810](https://github.com/mermaid-js/mermaid/pull/5810) [`33a809f`](https://github.com/mermaid-js/mermaid/commit/33a809f09a9aa1f84ba06201ab550bad81c3ff65) Thanks [@knsv](https://github.com/knsv)! - fix: Updates to the default elk configuration
|
||||
feat: exposing cycleBreakingStrategy to the configuration so that it can be modified suing the configuration.
|
||||
- Updated dependencies [[`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989), [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989), [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989), [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989), [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989)]:
|
||||
- Updated dependencies [[`6ecdf7b`](https://github.com/mermaid-js/mermaid/commit/6ecdf7be688efdc53c52fea3ba891327242bc890), [`28bd07f`](https://github.com/mermaid-js/mermaid/commit/28bd07fdeb4fc981107d21317ec6160b31f80116), [`8e640da`](https://github.com/mermaid-js/mermaid/commit/8e640da5436e8ae013b11b1c1821a9afcc15d0d3), [`256a148`](https://github.com/mermaid-js/mermaid/commit/256a148bbf484fc7db6c19f94dd69d5d268ee048), [`16faef4`](https://github.com/mermaid-js/mermaid/commit/16faef4613b91a7d3a98a1563c25b57f9238acc7)]:
|
||||
- mermaid@11.1.0
|
||||
|
||||
## 0.1.2
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@mermaid-js/layout-elk",
|
||||
"version": "0.1.3",
|
||||
"version": "0.1.7",
|
||||
"description": "ELK layout engine for mermaid",
|
||||
"module": "dist/mermaid-layout-elk.core.mjs",
|
||||
"types": "dist/layouts.d.ts",
|
||||
|
@@ -3,6 +3,21 @@ import ELK from 'elkjs/lib/elk.bundled.js';
|
||||
import type { InternalHelpers, LayoutData, RenderOptions, SVG, SVGGroup } from 'mermaid';
|
||||
import { type TreeData, findCommonAncestor } from './find-common-ancestor.js';
|
||||
|
||||
type Node = LayoutData['nodes'][number];
|
||||
|
||||
interface LabelData {
|
||||
width: number;
|
||||
height: number;
|
||||
wrappingWidth?: number;
|
||||
labelNode?: SVGGElement | null;
|
||||
}
|
||||
|
||||
interface NodeWithVertex extends Omit<Node, 'domId'> {
|
||||
children?: unknown[];
|
||||
labelData?: LabelData;
|
||||
domId?: Node['domId'] | SVGGroup | d3.Selection<SVGAElement, unknown, Element | null, unknown>;
|
||||
}
|
||||
|
||||
export const render = async (
|
||||
data4Layout: LayoutData,
|
||||
svg: SVG,
|
||||
@@ -24,33 +39,44 @@ export const render = async (
|
||||
const nodeDb: Record<string, any> = {};
|
||||
const clusterDb: Record<string, any> = {};
|
||||
|
||||
const addVertex = async (nodeEl: any, graph: { children: any[] }, nodeArr: any, node: any) => {
|
||||
const labelData: any = { width: 0, height: 0 };
|
||||
const addVertex = async (
|
||||
nodeEl: SVGGroup,
|
||||
graph: { children: NodeWithVertex[] },
|
||||
nodeArr: Node[],
|
||||
node: Node
|
||||
) => {
|
||||
const labelData: LabelData = { width: 0, height: 0 };
|
||||
|
||||
let boundingBox;
|
||||
const child = {
|
||||
...node,
|
||||
};
|
||||
graph.children.push(child);
|
||||
nodeDb[node.id] = child;
|
||||
const config = getConfig();
|
||||
|
||||
// Add the element to the DOM
|
||||
if (!node.isGroup) {
|
||||
const childNodeEl = await insertNode(nodeEl, node, node.dir);
|
||||
boundingBox = childNodeEl.node().getBBox();
|
||||
const child: NodeWithVertex = {
|
||||
...node,
|
||||
};
|
||||
graph.children.push(child);
|
||||
nodeDb[node.id] = child;
|
||||
|
||||
const childNodeEl = await insertNode(nodeEl, node, { config, dir: node.dir });
|
||||
const boundingBox = childNodeEl.node()!.getBBox();
|
||||
child.domId = childNodeEl;
|
||||
child.width = boundingBox.width;
|
||||
child.height = boundingBox.height;
|
||||
} else {
|
||||
// A subgraph
|
||||
child.children = [];
|
||||
const child: NodeWithVertex & { children: NodeWithVertex[] } = {
|
||||
...node,
|
||||
children: [],
|
||||
};
|
||||
graph.children.push(child);
|
||||
nodeDb[node.id] = child;
|
||||
await addVertices(nodeEl, nodeArr, child, node.id);
|
||||
|
||||
if (node.label) {
|
||||
// @ts-ignore TODO: fix this
|
||||
const { shapeSvg, bbox } = await labelHelper(nodeEl, node, undefined, true);
|
||||
labelData.width = bbox.width;
|
||||
labelData.wrappingWidth = getConfig().flowchart!.wrappingWidth;
|
||||
labelData.wrappingWidth = config.flowchart!.wrappingWidth;
|
||||
// Give some padding for elk
|
||||
labelData.height = bbox.height - 2;
|
||||
labelData.labelNode = shapeSvg.node();
|
||||
@@ -67,28 +93,16 @@ export const render = async (
|
||||
};
|
||||
|
||||
const addVertices = async function (
|
||||
nodeEl: any,
|
||||
nodeArr: any[],
|
||||
graph: {
|
||||
id: string;
|
||||
layoutOptions: {
|
||||
'elk.hierarchyHandling': string;
|
||||
'elk.algorithm': any;
|
||||
'nodePlacement.strategy': any;
|
||||
'elk.layered.mergeEdges': any;
|
||||
'elk.direction': string;
|
||||
'spacing.baseValue': number;
|
||||
};
|
||||
children: never[];
|
||||
edges: never[];
|
||||
},
|
||||
parentId?: undefined
|
||||
nodeEl: SVGGroup,
|
||||
nodeArr: Node[],
|
||||
graph: { children: NodeWithVertex[] },
|
||||
parentId?: string
|
||||
) {
|
||||
const siblings = nodeArr.filter((node: { parentId: any }) => node.parentId === parentId);
|
||||
const siblings = nodeArr.filter((node) => node?.parentId === parentId);
|
||||
log.info('addVertices APA12', siblings, parentId);
|
||||
// Iterate through each item in the vertex object (containing all the vertices found) in the graph definition
|
||||
await Promise.all(
|
||||
siblings.map(async (node: any) => {
|
||||
siblings.map(async (node) => {
|
||||
await addVertex(nodeEl, graph, nodeArr, node);
|
||||
})
|
||||
);
|
||||
@@ -135,6 +149,7 @@ export const render = async (
|
||||
const clusterNode = JSON.parse(JSON.stringify(node));
|
||||
clusterNode.x = node.offset.posX + node.width / 2;
|
||||
clusterNode.y = node.offset.posY + node.height / 2;
|
||||
clusterNode.width = Math.max(clusterNode.width, node.labelData.width);
|
||||
await insertCluster(subgraphEl, clusterNode);
|
||||
|
||||
log.debug('Id (UIO)= ', node.id, node.width, node.shape, node.labels);
|
||||
@@ -224,7 +239,7 @@ export const render = async (
|
||||
* Add edges to graph based on parsed graph definition
|
||||
*/
|
||||
const addEdges = async function (
|
||||
dataForLayout: { edges: any; direction: string },
|
||||
dataForLayout: { edges: any; direction?: string },
|
||||
graph: {
|
||||
id?: string;
|
||||
layoutOptions?: {
|
||||
@@ -261,6 +276,8 @@ export const render = async (
|
||||
interpolate: undefined;
|
||||
style: undefined;
|
||||
labelType: any;
|
||||
startLabelRight?: string;
|
||||
endLabelLeft?: string;
|
||||
}) {
|
||||
// Identify Link
|
||||
const linkIdBase = edge.id; // 'L-' + edge.start + '-' + edge.end;
|
||||
@@ -314,6 +331,9 @@ export const render = async (
|
||||
let style = '';
|
||||
let labelStyle = '';
|
||||
|
||||
edgeData.startLabelRight = edge.startLabelRight;
|
||||
edgeData.endLabelLeft = edge.endLabelLeft;
|
||||
|
||||
switch (edge.stroke) {
|
||||
case 'normal':
|
||||
style = 'fill:none;';
|
||||
@@ -464,6 +484,8 @@ export const render = async (
|
||||
const r3 = a1 * q1.x + b1 * q1.y + c1;
|
||||
const r4 = a1 * q2.x + b1 * q2.y + c1;
|
||||
|
||||
const epsilon = 1e-6;
|
||||
|
||||
// Check signs of r3 and r4. If both point 3 and point 4 lie on
|
||||
// same side of line 1, the line segments do not intersect.
|
||||
if (r3 !== 0 && r4 !== 0 && sameSign(r3, r4)) {
|
||||
@@ -482,7 +504,7 @@ export const render = async (
|
||||
// Check signs of r1 and r2. If both point 1 and point 2 lie
|
||||
// on same side of second line segment, the line segments do
|
||||
// not intersect.
|
||||
if (r1 !== 0 && r2 !== 0 && sameSign(r1, r2)) {
|
||||
if (Math.abs(r1) < epsilon && Math.abs(r2) < epsilon && sameSign(r1, r2)) {
|
||||
return /*DON'T_INTERSECT*/;
|
||||
}
|
||||
|
||||
@@ -527,11 +549,11 @@ export const render = async (
|
||||
{ x: x1 - w / 2, y: y1 },
|
||||
];
|
||||
log.debug(
|
||||
`UIO diamondIntersection calc abc89:
|
||||
`APA16 diamondIntersection calc abc89:
|
||||
outsidePoint: ${JSON.stringify(outsidePoint)}
|
||||
insidePoint : ${JSON.stringify(insidePoint)}
|
||||
node : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||
polyPoints
|
||||
node-bounds : x:${bounds.x} y:${bounds.y} w:${bounds.width} h:${bounds.height}`,
|
||||
JSON.stringify(polyPoints)
|
||||
);
|
||||
|
||||
const intersections = [];
|
||||
@@ -544,8 +566,8 @@ export const render = async (
|
||||
minY = Math.min(minY, entry.y);
|
||||
});
|
||||
|
||||
// const left = x1 - w / 2;
|
||||
// const top = y1 + h / 2;
|
||||
const left = x1 - w / 2 - minX;
|
||||
const top = y1 - h / 2 - minY;
|
||||
|
||||
for (let i = 0; i < polyPoints.length; i++) {
|
||||
const p1 = polyPoints[i];
|
||||
@@ -553,8 +575,8 @@ export const render = async (
|
||||
const intersect = intersectLine(
|
||||
bounds,
|
||||
outsidePoint,
|
||||
{ x: p1.x, y: p1.y },
|
||||
{ x: p2.x, y: p2.y }
|
||||
{ x: left + p1.x, y: top + p1.y },
|
||||
{ x: left + p2.x, y: top + p2.y }
|
||||
);
|
||||
|
||||
if (intersect) {
|
||||
@@ -683,14 +705,11 @@ export const render = async (
|
||||
bounds: { x: any; y: any; width: any; height: any; padding: any },
|
||||
isDiamond: boolean
|
||||
) => {
|
||||
log.debug('UIO cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||
log.debug('APA18 cutPathAtIntersect Points:', _points, 'node:', bounds, 'isDiamond', isDiamond);
|
||||
const points: any[] = [];
|
||||
let lastPointOutside = _points[0];
|
||||
let isInside = false;
|
||||
_points.forEach((point: any) => {
|
||||
// const node = clusterDb[edge.toCluster].node;
|
||||
log.debug(' checking point', point, bounds);
|
||||
|
||||
// check if point is inside the boundary rect
|
||||
if (!outsideNode(bounds, point) && !isInside) {
|
||||
// First point inside the rect found
|
||||
@@ -733,7 +752,6 @@ export const render = async (
|
||||
}
|
||||
}
|
||||
});
|
||||
log.debug('returning points', points);
|
||||
return points;
|
||||
};
|
||||
|
||||
@@ -749,12 +767,12 @@ export const render = async (
|
||||
layoutOptions: {
|
||||
'elk.hierarchyHandling': 'INCLUDE_CHILDREN',
|
||||
'elk.algorithm': algorithm,
|
||||
'nodePlacement.strategy': data4Layout.config.elk.nodePlacementStrategy,
|
||||
'elk.layered.mergeEdges': data4Layout.config.elk.mergeEdges,
|
||||
'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
||||
'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
|
||||
'elk.direction': 'DOWN',
|
||||
'spacing.baseValue': 35,
|
||||
'elk.layered.unnecessaryBendpoints': true,
|
||||
'elk.layered.cycleBreaking.strategy': data4Layout.config.elk.cycleBreakingStrategy,
|
||||
'elk.layered.cycleBreaking.strategy': data4Layout.config.elk?.cycleBreakingStrategy,
|
||||
// 'spacing.nodeNode': 20,
|
||||
// 'spacing.nodeNodeBetweenLayers': 25,
|
||||
// 'spacing.edgeNode': 20,
|
||||
@@ -837,8 +855,8 @@ export const render = async (
|
||||
...node.layoutOptions,
|
||||
'elk.algorithm': algorithm,
|
||||
'elk.direction': dir2ElkDirection(node.dir),
|
||||
'nodePlacement.strategy': data4Layout.config['elk.nodePlacement.strategy'],
|
||||
'elk.layered.mergeEdges': data4Layout.config['elk.mergeEdges'],
|
||||
'nodePlacement.strategy': data4Layout.config.elk?.nodePlacementStrategy,
|
||||
'elk.layered.mergeEdges': data4Layout.config.elk?.mergeEdges,
|
||||
'elk.hierarchyHandling': 'SEPARATE_CHILDREN',
|
||||
};
|
||||
}
|
||||
@@ -885,7 +903,7 @@ export const render = async (
|
||||
|
||||
const offset = calcOffset(sourceId, targetId, parentLookupDb);
|
||||
log.debug(
|
||||
'offset',
|
||||
'APA18 offset',
|
||||
offset,
|
||||
sourceId,
|
||||
' ==> ',
|
||||
@@ -948,48 +966,41 @@ export const render = async (
|
||||
startNode.innerHTML
|
||||
);
|
||||
}
|
||||
if (startNode.shape === 'diamond') {
|
||||
if (startNode.shape === 'diamond' || startNode.shape === 'diam') {
|
||||
edge.points.unshift({
|
||||
x: startNode.x + startNode.width / 2 + offset.x,
|
||||
y: startNode.y + startNode.height / 2 + offset.y,
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
});
|
||||
}
|
||||
if (endNode.shape === 'diamond') {
|
||||
const x = endNode.x + endNode.width / 2 + offset.x;
|
||||
// Add a point at the center of the diamond
|
||||
if (
|
||||
Math.abs(edge.points[edge.points.length - 1].y - endNode.y - offset.y) > 0.001 ||
|
||||
Math.abs(edge.points[edge.points.length - 1].x - x) > 0.001
|
||||
) {
|
||||
edge.points.push({
|
||||
x: endNode.x + endNode.width / 2 + offset.x,
|
||||
y: endNode.y + endNode.height / 2 + offset.y,
|
||||
});
|
||||
}
|
||||
if (endNode.shape === 'diamond' || endNode.shape === 'diam') {
|
||||
edge.points.push({
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
});
|
||||
}
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points.reverse(),
|
||||
{
|
||||
x: startNode.x + startNode.width / 2 + offset.x,
|
||||
y: startNode.y + startNode.height / 2 + offset.y,
|
||||
x: startNode.offset.posX + startNode.width / 2,
|
||||
y: startNode.offset.posY + startNode.height / 2,
|
||||
width: sw,
|
||||
height: startNode.height,
|
||||
padding: startNode.padding,
|
||||
},
|
||||
startNode.shape === 'diamond'
|
||||
startNode.shape === 'diamond' || startNode.shape === 'diam'
|
||||
).reverse();
|
||||
|
||||
edge.points = cutPathAtIntersect(
|
||||
edge.points,
|
||||
{
|
||||
x: endNode.x + ew / 2 + endNode.offset.x,
|
||||
y: endNode.y + endNode.height / 2 + endNode.offset.y,
|
||||
x: endNode.offset.posX + endNode.width / 2,
|
||||
y: endNode.offset.posY + endNode.height / 2,
|
||||
width: ew,
|
||||
height: endNode.height,
|
||||
padding: endNode.padding,
|
||||
},
|
||||
endNode.shape === 'diamond'
|
||||
endNode.shape === 'diamond' || endNode.shape === 'diam'
|
||||
);
|
||||
|
||||
const paths = insertEdge(
|
||||
|
@@ -1,25 +1,109 @@
|
||||
# mermaid
|
||||
|
||||
## 11.4.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#6059](https://github.com/mermaid-js/mermaid/pull/6059) [`01b5079`](https://github.com/mermaid-js/mermaid/commit/01b5079562ec8d34ce9964910f168873843c68f8) Thanks [@knsv](https://github.com/knsv)! - fix: Kanban diagrams will not render when adding a number as ticket id or assigned for a task
|
||||
|
||||
- [#6038](https://github.com/mermaid-js/mermaid/pull/6038) [`1388662`](https://github.com/mermaid-js/mermaid/commit/1388662132cc829f9820c2e9970ae04e2dd90588) Thanks [@knsv](https://github.com/knsv)! - fix: Intersection calculations for tilted cylinder/DAS when using handdrawn look. Some random seeds could cause the calculations to break.
|
||||
|
||||
- [#6079](https://github.com/mermaid-js/mermaid/pull/6079) [`fe3cffb`](https://github.com/mermaid-js/mermaid/commit/fe3cffbb673a25b81989aacb06e5d0eda35326db) Thanks [@aloisklink](https://github.com/aloisklink)! - Bump dompurify to `^3.2.1`. This removes the need for `@types/dompurify`.
|
||||
|
||||
## 11.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5999](https://github.com/mermaid-js/mermaid/pull/5999) [`742ad7c`](https://github.com/mermaid-js/mermaid/commit/742ad7c130964df1fb5544e909d9556081285f68) Thanks [@knsv](https://github.com/knsv)! - Adding Kanban board, a new diagram type
|
||||
|
||||
- [#5880](https://github.com/mermaid-js/mermaid/pull/5880) [`bdf145f`](https://github.com/mermaid-js/mermaid/commit/bdf145ffe362462176d9c1e68d5f3ff5c9d962b0) Thanks [@yari-dewalt](https://github.com/yari-dewalt)! - Class diagram changes:
|
||||
|
||||
- Updates the class diagram to the new unified way of rendering.
|
||||
- Includes a new "classBox" shape to be used in diagrams
|
||||
- Other updates such as:
|
||||
- the option to hide the empty members box in class diagrams,
|
||||
- support for handDrawn look,
|
||||
- the introduction of the classDef statement into class diagrams,
|
||||
- support for styling the default class,
|
||||
- support lollipop interfaces.
|
||||
- Includes fixes / additions for #5562 #3139 and #4037
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5937](https://github.com/mermaid-js/mermaid/pull/5937) [`17b7831`](https://github.com/mermaid-js/mermaid/commit/17b783135f9b2b7748b620dbf81d0f56ab4755f1) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: Jagged edge fix for icon shape
|
||||
|
||||
- [#5933](https://github.com/mermaid-js/mermaid/pull/5933) [`72d60d2`](https://github.com/mermaid-js/mermaid/commit/72d60d2633584eb59bccdb6cf30b9522db645db2) Thanks [@remcohaszing](https://github.com/remcohaszing)! - Add missing TypeScript dependencies
|
||||
|
||||
- [#5937](https://github.com/mermaid-js/mermaid/pull/5937) [`17b7831`](https://github.com/mermaid-js/mermaid/commit/17b783135f9b2b7748b620dbf81d0f56ab4755f1) Thanks [@saurabhg772244](https://github.com/saurabhg772244)! - fix: Icon color fix for colored icons.
|
||||
|
||||
- [#6002](https://github.com/mermaid-js/mermaid/pull/6002) [`5fabd41`](https://github.com/mermaid-js/mermaid/commit/5fabd414fbee01e43bf6c900907ffc1511ca7440) Thanks [@aloisklink](https://github.com/aloisklink)! - fix: error `mermaid.parse` on an invalid shape, so that it matches the errors thrown by `mermaid.render`
|
||||
|
||||
## 11.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5825](https://github.com/mermaid-js/mermaid/pull/5825) [`9e3aa70`](https://github.com/mermaid-js/mermaid/commit/9e3aa705ae21fd4898504ab22d775a9e437b898e) Thanks [@ashishjain0512](https://github.com/ashishjain0512)! - New Flowchart Shapes (with new syntax)
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5849](https://github.com/mermaid-js/mermaid/pull/5849) [`6c5b7ce`](https://github.com/mermaid-js/mermaid/commit/6c5b7ce9f41c0fbd59fe03dbefc8418d97697f0a) Thanks [@ReneLombard](https://github.com/ReneLombard)! - Fixed an issue when the mermaid classdiagram crashes when adding a . to the namespace.
|
||||
Forexample
|
||||
|
||||
```mermaid
|
||||
|
||||
classDiagram
|
||||
namespace Company.Project.Module {
|
||||
class GenericClass~T~ {
|
||||
+addItem(item: T)
|
||||
+getItem() T
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [#5914](https://github.com/mermaid-js/mermaid/pull/5914) [`de2c05c`](https://github.com/mermaid-js/mermaid/commit/de2c05cd5463af68d19dd7b6b3f1303d69ddb2dd) Thanks [@aloisklink](https://github.com/aloisklink)! - Ban DOMPurify v3.1.7 as a dependency
|
||||
|
||||
## 11.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5856](https://github.com/mermaid-js/mermaid/pull/5856) [`bfd8c63`](https://github.com/mermaid-js/mermaid/commit/bfd8c63daaa8420e57da9953922b9f0c94123064) Thanks [@knsv](https://github.com/knsv)! - Fix for issue with calculation of label width when using in firefox
|
||||
|
||||
## 11.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#5831](https://github.com/mermaid-js/mermaid/pull/5831) [`64abf29`](https://github.com/mermaid-js/mermaid/commit/64abf29ea870eaa47148197f95ce714f85bd7eea) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Return parsed config from mermaid.parse
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5838](https://github.com/mermaid-js/mermaid/pull/5838) [`5e75320`](https://github.com/mermaid-js/mermaid/commit/5e75320d49eab65aca630dcc3c04c8d620a8bbf7) Thanks [@bollwyvl](https://github.com/bollwyvl)! - fix: Replace $root with relative paths
|
||||
|
||||
## 11.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#5828](https://github.com/mermaid-js/mermaid/pull/5828) [`4c43d21`](https://github.com/mermaid-js/mermaid/commit/4c43d21196f784b6f483ae635fc462329f3d176f) Thanks [@knsv](https://github.com/knsv)! - fix: Fix for issue where self-loops in the root of diagrams break the rendering
|
||||
|
||||
## 11.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - feat: Add support for iconify icons
|
||||
- [#5793](https://github.com/mermaid-js/mermaid/pull/5793) [`6ecdf7b`](https://github.com/mermaid-js/mermaid/commit/6ecdf7be688efdc53c52fea3ba891327242bc890) Thanks [@sidharthv96](https://github.com/sidharthv96)! - feat: Add support for iconify icons
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - feat(er): allow multi-line relationship labels
|
||||
- [#5711](https://github.com/mermaid-js/mermaid/pull/5711) [`8e640da`](https://github.com/mermaid-js/mermaid/commit/8e640da5436e8ae013b11b1c1821a9afcc15d0d3) Thanks [@NicolasNewman](https://github.com/NicolasNewman)! - feat(er): allow multi-line relationship labels
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - New Diagram: Architecture
|
||||
- [#5452](https://github.com/mermaid-js/mermaid/pull/5452) [`256a148`](https://github.com/mermaid-js/mermaid/commit/256a148bbf484fc7db6c19f94dd69d5d268ee048) Thanks [@NicolasNewman](https://github.com/NicolasNewman)! - New Diagram: Architecture
|
||||
|
||||
Adds architecture diagrams which allows users to show relations between services.
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - Fix for self loops in cluster
|
||||
- [#5810](https://github.com/mermaid-js/mermaid/pull/5810) [`28bd07f`](https://github.com/mermaid-js/mermaid/commit/28bd07fdeb4fc981107d21317ec6160b31f80116) Thanks [@knsv](https://github.com/knsv)! - Fix for self loops in cluster
|
||||
Supporting legacy defaultRenderer directive
|
||||
|
||||
- [#2](https://github.com/calvinvette/mermaid/pull/2) [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989) Thanks [@calvinvette](https://github.com/calvinvette)! - chore: Move icons to architecture, remove full icon sets to reduce bundle size
|
||||
- [#5789](https://github.com/mermaid-js/mermaid/pull/5789) [`16faef4`](https://github.com/mermaid-js/mermaid/commit/16faef4613b91a7d3a98a1563c25b57f9238acc7) Thanks [@sidharthv96](https://github.com/sidharthv96)! - chore: Move icons to architecture, remove full icon sets to reduce bundle size
|
||||
|
||||
- Updated dependencies [[`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989), [`10795b1`](https://github.com/mermaid-js/mermaid/commit/10795b1d89ecdf43a6414baa2cb37f585549b989)]:
|
||||
- Updated dependencies [[`256a148`](https://github.com/mermaid-js/mermaid/commit/256a148bbf484fc7db6c19f94dd69d5d268ee048), [`7d8143b`](https://github.com/mermaid-js/mermaid/commit/7d8143b917ee3562149a0e0a821ed2d6f29cc05d)]:
|
||||
- @mermaid-js/parser@0.3.0
|
||||
|
||||
## 11.0.2
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mermaid",
|
||||
"version": "11.1.0",
|
||||
"version": "11.4.1",
|
||||
"description": "Markdown-ish syntax for generating flowcharts, mindmaps, sequence diagrams, class diagrams, gantt charts, git graphs and more.",
|
||||
"type": "module",
|
||||
"module": "./dist/mermaid.core.mjs",
|
||||
@@ -35,8 +35,8 @@
|
||||
"clean": "rimraf dist",
|
||||
"dev": "pnpm -w dev",
|
||||
"docs:code": "typedoc src/defaultConfig.ts src/config.ts src/mermaid.ts && prettier --write ./src/docs/config/setup",
|
||||
"docs:build": "rimraf ../../docs && pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts",
|
||||
"docs:verify": "pnpm docs:spellcheck && pnpm docs:code && tsx scripts/docs.cli.mts --verify",
|
||||
"docs:build": "rimraf ../../docs && pnpm docs:code && pnpm docs:spellcheck && tsx scripts/docs.cli.mts",
|
||||
"docs:verify": "pnpm docs:code && pnpm docs:spellcheck && tsx scripts/docs.cli.mts --verify",
|
||||
"docs:pre:vitepress": "pnpm --filter ./src/docs prefetch && rimraf src/vitepress && pnpm docs:code && tsx scripts/docs.cli.mts --vitepress && pnpm --filter ./src/vitepress install --no-frozen-lockfile --ignore-scripts",
|
||||
"docs:build:vitepress": "pnpm docs:pre:vitepress && (cd src/vitepress && pnpm run build) && cpy --flat src/docs/landing/ ./src/vitepress/.vitepress/dist/landing",
|
||||
"docs:dev": "pnpm docs:pre:vitepress && concurrently \"pnpm --filter ./src/vitepress dev\" \"tsx scripts/docs.cli.mts --watch --vitepress\"",
|
||||
@@ -70,14 +70,15 @@
|
||||
"@braintree/sanitize-url": "^7.0.1",
|
||||
"@iconify/utils": "^2.1.32",
|
||||
"@mermaid-js/parser": "workspace:^",
|
||||
"@types/d3": "^7.4.3",
|
||||
"cytoscape": "^3.29.2",
|
||||
"cytoscape-cose-bilkent": "^4.1.0",
|
||||
"cytoscape-fcose": "^2.2.0",
|
||||
"d3": "^7.9.0",
|
||||
"d3-sankey": "^0.12.3",
|
||||
"dagre-d3-es": "7.0.10",
|
||||
"dagre-d3-es": "7.0.11",
|
||||
"dayjs": "^1.11.10",
|
||||
"dompurify": "^3.0.11",
|
||||
"dompurify": "^3.2.1",
|
||||
"katex": "^0.16.9",
|
||||
"khroma": "^2.1.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
@@ -92,13 +93,11 @@
|
||||
"@iconify/types": "^2.0.0",
|
||||
"@types/cytoscape": "^3.21.4",
|
||||
"@types/cytoscape-fcose": "^2.2.4",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/d3-sankey": "^0.12.4",
|
||||
"@types/d3-scale": "^4.0.8",
|
||||
"@types/d3-scale-chromatic": "^3.0.3",
|
||||
"@types/d3-selection": "^3.0.10",
|
||||
"@types/d3-shape": "^3.1.6",
|
||||
"@types/dompurify": "^3.0.5",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/katex": "^0.16.7",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
|
@@ -41,7 +41,8 @@ import { exec } from 'child_process';
|
||||
import { globby } from 'globby';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import { dump, load, JSON_SCHEMA } from 'js-yaml';
|
||||
import type { Code, ListItem, Root, Text, YAML } from 'mdast';
|
||||
import type { Code, ListItem, PhrasingContent, Root, Text, YAML } from 'mdast';
|
||||
import { register } from 'node:module';
|
||||
import { posix, dirname, relative, join } from 'path';
|
||||
import prettier from 'prettier';
|
||||
import { remark } from 'remark';
|
||||
@@ -53,6 +54,10 @@ import mm from 'micromatch';
|
||||
import flatmap from 'unist-util-flatmap';
|
||||
import { visit } from 'unist-util-visit';
|
||||
|
||||
// short-circuit `.schema.yaml` imports, so that we can safely import `shapes.js`
|
||||
register('./loadHook.mjs', import.meta.url);
|
||||
const { shapesDefs } = await import('../src/rendering-util/rendering-elements/shapes.js');
|
||||
|
||||
export const MERMAID_RELEASE_VERSION = JSON.parse(readFileSync('../mermaid/package.json', 'utf8'))
|
||||
.version as string;
|
||||
const MERMAID_MAJOR_VERSION = MERMAID_RELEASE_VERSION.split('.')[0];
|
||||
@@ -103,6 +108,60 @@ const generateHeader = (file: string): string => {
|
||||
> ## Please edit the corresponding file in [${filePathFromRoot}](${sourcePathRelativeToGenerated}).`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds a markdown list of shapes supported in flowcharts.
|
||||
*/
|
||||
export function buildShapeDoc() {
|
||||
const data = shapesDefs
|
||||
.sort((a, b) => a.semanticName.localeCompare(b.semanticName))
|
||||
.map((shape): PhrasingContent[][] => {
|
||||
const { name, semanticName, description, shortName, aliases = [] } = shape;
|
||||
return [
|
||||
[{ type: 'text', value: semanticName }],
|
||||
[{ type: 'text', value: name }],
|
||||
[{ type: 'inlineCode', value: shortName }],
|
||||
[{ type: 'text', value: description }],
|
||||
aliases.sort().flatMap((alias, index) => [
|
||||
...(index !== 0 ? ([{ type: 'text', value: ', ' }] as const) : []),
|
||||
{
|
||||
type: 'inlineCode',
|
||||
value: alias,
|
||||
},
|
||||
]),
|
||||
];
|
||||
});
|
||||
|
||||
// don't prettify this table, since we'd do it later
|
||||
return remark()
|
||||
.use(remarkGfm)
|
||||
.stringify({
|
||||
type: 'root',
|
||||
children: [
|
||||
{
|
||||
type: 'table',
|
||||
children: [
|
||||
['Semantic Name', 'Shape Name', 'Short Name', 'Description', 'Alias Supported'].map(
|
||||
(s): PhrasingContent[] => [
|
||||
{
|
||||
type: 'strong',
|
||||
children: [{ type: 'text', value: s }],
|
||||
},
|
||||
]
|
||||
),
|
||||
...data,
|
||||
].map((row) => ({
|
||||
type: 'tableRow',
|
||||
children: row.map((cell) => ({
|
||||
type: 'tableCell',
|
||||
children: cell,
|
||||
})),
|
||||
})),
|
||||
},
|
||||
],
|
||||
})
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a source file name and path, return the documentation destination full path and file name
|
||||
* Create the destination path if it does not already exist.
|
||||
@@ -192,10 +251,22 @@ export const transformToBlockQuote = (
|
||||
const injectPlaceholders = (text: string): string =>
|
||||
text.replace(/<MERMAID_VERSION>/g, MERMAID_MAJOR_VERSION).replace(/<CDN_URL>/g, CDN_URL);
|
||||
|
||||
const virtualGenerators: Record<string, () => string> = {
|
||||
shapesTable: buildShapeDoc,
|
||||
};
|
||||
|
||||
const transformIncludeStatements = (file: string, text: string): string => {
|
||||
// resolve includes - src https://github.com/vuejs/vitepress/blob/428eec3750d6b5648a77ac52d88128df0554d4d1/src/node/markdownToVue.ts#L65-L76
|
||||
return text.replace(includesRE, (m, m1) => {
|
||||
return text.replace(includesRE, (m, m1: string) => {
|
||||
try {
|
||||
if (m1.startsWith('virtual:')) {
|
||||
const key = m1.replace('virtual:', '');
|
||||
const generator = virtualGenerators[key];
|
||||
if (!generator) {
|
||||
throw new Error(`Unknown virtual generator: ${key} in "${file}"`);
|
||||
}
|
||||
return generator();
|
||||
}
|
||||
const includePath = join(dirname(file), m1).replaceAll('\\', '/');
|
||||
const content = readSyncedUTF8file(includePath);
|
||||
includedFiles.add(changeToFinalDocDir(includePath));
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { transformMarkdownAst, transformToBlockQuote } from './docs.mjs';
|
||||
import { buildShapeDoc, transformMarkdownAst, transformToBlockQuote } from './docs.mjs';
|
||||
|
||||
import { remark } from 'remark'; // import it this way so we can mock it
|
||||
import remarkFrontmatter from 'remark-frontmatter';
|
||||
@@ -165,4 +165,59 @@ This Markdown should be kept.
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildShapeDoc', () => {
|
||||
it('should build shapesTable based on the shapeDefs', () => {
|
||||
expect(buildShapeDoc()).toMatchInlineSnapshot(`
|
||||
"| **Semantic Name** | **Shape Name** | **Short Name** | **Description** | **Alias Supported** |
|
||||
| --------------------------------- | ---------------------- | -------------- | ------------------------------ | ---------------------------------------------------------------- |
|
||||
| Card | Notched Rectangle | \`notch-rect\` | Represents a card | \`card\`, \`notched-rectangle\` |
|
||||
| Collate | Hourglass | \`hourglass\` | Represents a collate operation | \`collate\`, \`hourglass\` |
|
||||
| Com Link | Lightning Bolt | \`bolt\` | Communication link | \`com-link\`, \`lightning-bolt\` |
|
||||
| Comment | Curly Brace | \`brace\` | Adds a comment | \`brace-l\`, \`comment\` |
|
||||
| Comment Right | Curly Brace | \`brace-r\` | Adds a comment | |
|
||||
| Comment with braces on both sides | Curly Braces | \`braces\` | Adds a comment | |
|
||||
| Data Input/Output | Lean Right | \`lean-r\` | Represents input or output | \`in-out\`, \`lean-right\` |
|
||||
| Data Input/Output | Lean Left | \`lean-l\` | Represents output or input | \`lean-left\`, \`out-in\` |
|
||||
| Database | Cylinder | \`cyl\` | Database storage | \`cylinder\`, \`database\`, \`db\` |
|
||||
| Decision | Diamond | \`diam\` | Decision-making step | \`decision\`, \`diamond\`, \`question\` |
|
||||
| Delay | Half-Rounded Rectangle | \`delay\` | Represents a delay | \`half-rounded-rectangle\` |
|
||||
| Direct Access Storage | Horizontal Cylinder | \`h-cyl\` | Direct access storage | \`das\`, \`horizontal-cylinder\` |
|
||||
| Disk Storage | Lined Cylinder | \`lin-cyl\` | Disk storage | \`disk\`, \`lined-cylinder\` |
|
||||
| Display | Curved Trapezoid | \`curv-trap\` | Represents a display | \`curved-trapezoid\`, \`display\` |
|
||||
| Divided Process | Divided Rectangle | \`div-rect\` | Divided process shape | \`div-proc\`, \`divided-process\`, \`divided-rectangle\` |
|
||||
| Document | Document | \`doc\` | Represents a document | \`doc\`, \`document\` |
|
||||
| Event | Rounded Rectangle | \`rounded\` | Represents an event | \`event\` |
|
||||
| Extract | Triangle | \`tri\` | Extraction process | \`extract\`, \`triangle\` |
|
||||
| Fork/Join | Filled Rectangle | \`fork\` | Fork or join in process flow | \`join\` |
|
||||
| Internal Storage | Window Pane | \`win-pane\` | Internal storage | \`internal-storage\`, \`window-pane\` |
|
||||
| Junction | Filled Circle | \`f-circ\` | Junction point | \`filled-circle\`, \`junction\` |
|
||||
| Lined Document | Lined Document | \`lin-doc\` | Lined document | \`lined-document\` |
|
||||
| Lined/Shaded Process | Lined Rectangle | \`lin-rect\` | Lined process shape | \`lin-proc\`, \`lined-process\`, \`lined-rectangle\`, \`shaded-process\` |
|
||||
| Loop Limit | Trapezoidal Pentagon | \`notch-pent\` | Loop limit step | \`loop-limit\`, \`notched-pentagon\` |
|
||||
| Manual File | Flipped Triangle | \`flip-tri\` | Manual file operation | \`flipped-triangle\`, \`manual-file\` |
|
||||
| Manual Input | Sloped Rectangle | \`sl-rect\` | Manual input step | \`manual-input\`, \`sloped-rectangle\` |
|
||||
| Manual Operation | Trapezoid Base Top | \`trap-t\` | Represents a manual task | \`inv-trapezoid\`, \`manual\`, \`trapezoid-top\` |
|
||||
| Multi-Document | Stacked Document | \`docs\` | Multiple documents | \`documents\`, \`st-doc\`, \`stacked-document\` |
|
||||
| Multi-Process | Stacked Rectangle | \`st-rect\` | Multiple processes | \`processes\`, \`procs\`, \`stacked-rectangle\` |
|
||||
| Odd | Odd | \`odd\` | Odd shape | |
|
||||
| Paper Tape | Flag | \`flag\` | Paper tape | \`paper-tape\` |
|
||||
| Prepare Conditional | Hexagon | \`hex\` | Preparation or condition step | \`hexagon\`, \`prepare\` |
|
||||
| Priority Action | Trapezoid Base Bottom | \`trap-b\` | Priority action | \`priority\`, \`trapezoid\`, \`trapezoid-bottom\` |
|
||||
| Process | Rectangle | \`rect\` | Standard process shape | \`proc\`, \`process\`, \`rectangle\` |
|
||||
| Start | Circle | \`circle\` | Starting point | \`circ\` |
|
||||
| Start | Small Circle | \`sm-circ\` | Small starting point | \`small-circle\`, \`start\` |
|
||||
| Stop | Double Circle | \`dbl-circ\` | Represents a stop point | \`double-circle\` |
|
||||
| Stop | Framed Circle | \`fr-circ\` | Stop point | \`framed-circle\`, \`stop\` |
|
||||
| Stored Data | Bow Tie Rectangle | \`bow-rect\` | Stored data | \`bow-tie-rectangle\`, \`stored-data\` |
|
||||
| Subprocess | Framed Rectangle | \`fr-rect\` | Subprocess | \`framed-rectangle\`, \`subproc\`, \`subprocess\`, \`subroutine\` |
|
||||
| Summary | Crossed Circle | \`cross-circ\` | Summary | \`crossed-circle\`, \`summary\` |
|
||||
| Tagged Document | Tagged Document | \`tag-doc\` | Tagged document | \`tag-doc\`, \`tagged-document\` |
|
||||
| Tagged Process | Tagged Rectangle | \`tag-rect\` | Tagged process | \`tag-proc\`, \`tagged-process\`, \`tagged-rectangle\` |
|
||||
| Terminal Point | Stadium | \`stadium\` | Terminal point | \`pill\`, \`terminal\` |
|
||||
| Text Block | Text Block | \`text\` | Text block | |
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
22
packages/mermaid/scripts/loadHook.mjs
Normal file
22
packages/mermaid/scripts/loadHook.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
import { fileURLToPath } from 'node:url';
|
||||
/** @import import { LoadHook } from "node:module"; */
|
||||
/**
|
||||
* @type {LoadHook}
|
||||
*
|
||||
* Load hook that short circuits the loading of `.schema.yaml` files with `export default {}`.
|
||||
* These would normally be loaded using ESBuild, but that doesn't work for these local scripts.
|
||||
*
|
||||
* @see https://nodejs.org/api/module.html#loadurl-context-nextload
|
||||
*/
|
||||
export const load = async (url, context, nextLoad) => {
|
||||
const filePath = url.startsWith('file://') ? fileURLToPath(url) : url;
|
||||
if (filePath.endsWith('.schema.yaml')) {
|
||||
return {
|
||||
format: 'module',
|
||||
shortCircuit: true,
|
||||
source: `export default {}`,
|
||||
};
|
||||
} else {
|
||||
return await nextLoad(url, context);
|
||||
}
|
||||
};
|
@@ -193,6 +193,7 @@ export interface MermaidConfig {
|
||||
requirement?: RequirementDiagramConfig;
|
||||
architecture?: ArchitectureDiagramConfig;
|
||||
mindmap?: MindmapDiagramConfig;
|
||||
kanban?: KanbanDiagramConfig;
|
||||
gitGraph?: GitGraphDiagramConfig;
|
||||
c4?: C4DiagramConfig;
|
||||
sankey?: SankeyDiagramConfig;
|
||||
@@ -716,6 +717,7 @@ export interface ClassDiagramConfig extends BaseDiagramConfig {
|
||||
*/
|
||||
diagramPadding?: number;
|
||||
htmlLabels?: boolean;
|
||||
hideEmptyMembersBox?: boolean;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for entity relationship diagrams
|
||||
@@ -1023,6 +1025,17 @@ export interface MindmapDiagramConfig extends BaseDiagramConfig {
|
||||
padding?: number;
|
||||
maxNodeWidth?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for kanban diagrams
|
||||
*
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "KanbanDiagramConfig".
|
||||
*/
|
||||
export interface KanbanDiagramConfig extends BaseDiagramConfig {
|
||||
padding?: number;
|
||||
sectionWidth?: number;
|
||||
ticketBaseUrl?: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "GitGraphDiagramConfig".
|
||||
|
@@ -87,7 +87,7 @@ const recursiveRender = async (_elem, graph, diagramType, id, parentCluster, sit
|
||||
// insertCluster(clusters, graph.node(v));
|
||||
} else {
|
||||
log.info('Node - the non recursive path', v, node.id, node);
|
||||
await insertNode(nodes, graph.node(v), dir);
|
||||
await insertNode(nodes, graph.node(v), { config: siteConfig, dir });
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -1131,7 +1131,7 @@ const shapes = {
|
||||
|
||||
let nodeElems = {};
|
||||
|
||||
export const insertNode = async (elem, node, dir) => {
|
||||
export const insertNode = async (elem, node, renderOptions) => {
|
||||
let newEl;
|
||||
let el;
|
||||
|
||||
@@ -1144,9 +1144,9 @@ export const insertNode = async (elem, node, dir) => {
|
||||
target = node.linkTarget || '_blank';
|
||||
}
|
||||
newEl = elem.insert('svg:a').attr('xlink:href', node.link).attr('target', target);
|
||||
el = await shapes[node.shape](newEl, node, dir);
|
||||
el = await shapes[node.shape](newEl, node, renderOptions);
|
||||
} else {
|
||||
el = await shapes[node.shape](elem, node, dir);
|
||||
el = await shapes[node.shape](elem, node, renderOptions);
|
||||
newEl = el;
|
||||
}
|
||||
if (node.tooltip) {
|
||||
|
@@ -21,8 +21,9 @@ const config: RequiredDeep<MermaidConfig> = {
|
||||
// TODO: Should we replace these with `null` so that they can go in the JSON Schema?
|
||||
deterministicIDSeed: undefined,
|
||||
elk: {
|
||||
// mergeEdges is needed here to be considered
|
||||
mergeEdges: false,
|
||||
nodePlacementStrategy: 'SIMPLE',
|
||||
nodePlacementStrategy: 'BRANDES_KOEPF',
|
||||
},
|
||||
themeCSS: undefined,
|
||||
|
||||
@@ -52,6 +53,9 @@ const config: RequiredDeep<MermaidConfig> = {
|
||||
};
|
||||
},
|
||||
},
|
||||
class: {
|
||||
hideEmptyMembersBox: false,
|
||||
},
|
||||
gantt: {
|
||||
...defaultConfigJson.gantt,
|
||||
tickInterval: undefined,
|
||||
|
@@ -19,6 +19,7 @@ import errorDiagram from '../diagrams/error/errorDiagram.js';
|
||||
import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
||||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import kanban from '../diagrams/kanban/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
import { packet } from '../diagrams/packet/detector.js';
|
||||
import block from '../diagrams/block/blockDetector.js';
|
||||
@@ -70,6 +71,7 @@ export const addDiagrams = () => {
|
||||
// Ordering of detectors is important. The first one to return true will be used.
|
||||
registerLazyLoadedDiagrams(
|
||||
c4,
|
||||
kanban,
|
||||
classDiagramV2,
|
||||
classDiagram,
|
||||
er,
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
setDiagramTitle,
|
||||
} from '../common/commonDb.js';
|
||||
import type {
|
||||
ArchitectureAlignment,
|
||||
ArchitectureDB,
|
||||
ArchitectureDirectionPair,
|
||||
ArchitectureDirectionPairMap,
|
||||
@@ -25,6 +26,7 @@ import type {
|
||||
ArchitectureState,
|
||||
} from './architectureTypes.js';
|
||||
import {
|
||||
getArchitectureDirectionAlignment,
|
||||
getArchitectureDirectionPair,
|
||||
isArchitectureDirection,
|
||||
isArchitectureJunction,
|
||||
@@ -211,12 +213,18 @@ const addEdge = function ({
|
||||
const getEdges = (): ArchitectureEdge[] => state.records.edges;
|
||||
|
||||
/**
|
||||
* Returns the current diagram's adjacency list & spatial map.
|
||||
* Returns the current diagram's adjacency list, spatial map, & group alignments.
|
||||
* If they have not been created, run the algorithms to generate them.
|
||||
* @returns
|
||||
*/
|
||||
const getDataStructures = () => {
|
||||
if (state.records.dataStructures === undefined) {
|
||||
// Tracks how groups are aligned with one another. Generated while creating the adj list
|
||||
const groupAlignments: Record<
|
||||
string,
|
||||
Record<string, Exclude<ArchitectureAlignment, 'bend'>>
|
||||
> = {};
|
||||
|
||||
// Create an adjacency list of the diagram to perform BFS on
|
||||
// Outer reduce applied on all services
|
||||
// Inner reduce applied on the edges for a service
|
||||
@@ -224,6 +232,19 @@ const getDataStructures = () => {
|
||||
Record<string, ArchitectureDirectionPairMap>
|
||||
>((prevOuter, [id, service]) => {
|
||||
prevOuter[id] = service.edges.reduce<ArchitectureDirectionPairMap>((prevInner, edge) => {
|
||||
// track the direction groups connect to one another
|
||||
const lhsGroupId = getNode(edge.lhsId)?.in;
|
||||
const rhsGroupId = getNode(edge.rhsId)?.in;
|
||||
if (lhsGroupId && rhsGroupId && lhsGroupId !== rhsGroupId) {
|
||||
const alignment = getArchitectureDirectionAlignment(edge.lhsDir, edge.rhsDir);
|
||||
if (alignment !== 'bend') {
|
||||
groupAlignments[lhsGroupId] ??= {};
|
||||
groupAlignments[lhsGroupId][rhsGroupId] = alignment;
|
||||
groupAlignments[rhsGroupId] ??= {};
|
||||
groupAlignments[rhsGroupId][lhsGroupId] = alignment;
|
||||
}
|
||||
}
|
||||
|
||||
if (edge.lhsId === id) {
|
||||
// source is LHS
|
||||
const pair = getArchitectureDirectionPair(edge.lhsDir, edge.rhsDir);
|
||||
@@ -245,6 +266,7 @@ const getDataStructures = () => {
|
||||
// Configuration for the initial pass of BFS
|
||||
const firstId = Object.keys(adjList)[0];
|
||||
const visited = { [firstId]: 1 };
|
||||
// If a key is present in this object, it has not been visited
|
||||
const notVisited = Object.keys(adjList).reduce(
|
||||
(prev, id) => (id === firstId ? prev : { ...prev, [id]: 1 }),
|
||||
{} as Record<string, number>
|
||||
@@ -283,6 +305,7 @@ const getDataStructures = () => {
|
||||
state.records.dataStructures = {
|
||||
adjList,
|
||||
spatialMaps,
|
||||
groupAlignments,
|
||||
};
|
||||
}
|
||||
return state.records.dataStructures;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { unknownIcon } from '$root/rendering-util/icons.js';
|
||||
import { unknownIcon } from '../../rendering-util/icons.js';
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
|
||||
const wrapIcon = (icon: string) => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { registerIconPacks } from '$root/rendering-util/icons.js';
|
||||
import { registerIconPacks } from '../../rendering-util/icons.js';
|
||||
import type { Position } from 'cytoscape';
|
||||
import cytoscape from 'cytoscape';
|
||||
import type { FcoseLayoutOptions } from 'cytoscape-fcose';
|
||||
@@ -12,7 +12,9 @@ import { setupGraphViewbox } from '../../setupGraphViewbox.js';
|
||||
import { getConfigField } from './architectureDb.js';
|
||||
import { architectureIcons } from './architectureIcons.js';
|
||||
import type {
|
||||
ArchitectureAlignment,
|
||||
ArchitectureDataStructures,
|
||||
ArchitectureGroupAlignments,
|
||||
ArchitectureJunction,
|
||||
ArchitectureSpatialMap,
|
||||
EdgeSingular,
|
||||
@@ -149,25 +151,91 @@ function addEdges(edges: ArchitectureEdge[], cy: cytoscape.Core) {
|
||||
});
|
||||
}
|
||||
|
||||
function getAlignments(spatialMaps: ArchitectureSpatialMap[]): fcose.FcoseAlignmentConstraint {
|
||||
function getAlignments(
|
||||
db: ArchitectureDB,
|
||||
spatialMaps: ArchitectureSpatialMap[],
|
||||
groupAlignments: ArchitectureGroupAlignments
|
||||
): fcose.FcoseAlignmentConstraint {
|
||||
/**
|
||||
* Flattens the alignment object so nodes in different groups will be in the same alignment array IFF their groups don't connect in a conflicting alignment
|
||||
*
|
||||
* i.e., two groups which connect horizontally should not have nodes with vertical alignments to one another
|
||||
*
|
||||
* See: #5952
|
||||
*
|
||||
* @param alignmentObj - alignment object with the outer key being the row/col # and the inner key being the group name mapped to the nodes on that axis in the group
|
||||
* @param alignmentDir - alignment direction
|
||||
* @returns flattened alignment object with an arbitrary key mapping to nodes in the same row/col
|
||||
*/
|
||||
const flattenAlignments = (
|
||||
alignmentObj: Record<number, Record<string, string[]>>,
|
||||
alignmentDir: ArchitectureAlignment
|
||||
): Record<string, string[]> => {
|
||||
return Object.entries(alignmentObj).reduce(
|
||||
(prev, [dir, alignments]) => {
|
||||
// prev is the mapping of x/y coordinate to an array of the nodes in that row/column
|
||||
let cnt = 0;
|
||||
const arr = Object.entries(alignments); // [group name, array of nodes within the group on axis dir]
|
||||
if (arr.length === 1) {
|
||||
// If only one group exists in the row/column, we don't need to do anything else
|
||||
prev[dir] = arr[0][1];
|
||||
return prev;
|
||||
}
|
||||
for (let i = 0; i < arr.length - 1; i++) {
|
||||
for (let j = i + 1; j < arr.length; j++) {
|
||||
const [aGroupId, aNodeIds] = arr[i];
|
||||
const [bGroupId, bNodeIds] = arr[j];
|
||||
const alignment = groupAlignments[aGroupId]?.[bGroupId]; // Get how the two groups are intended to align (undefined if they aren't)
|
||||
|
||||
if (alignment === alignmentDir) {
|
||||
// If the intended alignment between the two groups is the same as the alignment we are parsing
|
||||
prev[dir] ??= [];
|
||||
prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds]; // add the node ids of both groups to the axis array in prev
|
||||
} else if (aGroupId === 'default' || bGroupId === 'default') {
|
||||
// If either of the groups are in the default space (not in a group), use the same behavior as above
|
||||
prev[dir] ??= [];
|
||||
prev[dir] = [...prev[dir], ...aNodeIds, ...bNodeIds];
|
||||
} else {
|
||||
// Otherwise, the nodes in the two groups are not intended to align
|
||||
const keyA = `${dir}-${cnt++}`;
|
||||
prev[keyA] = aNodeIds;
|
||||
const keyB = `${dir}-${cnt++}`;
|
||||
prev[keyB] = bNodeIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
},
|
||||
{} as Record<string, string[]>
|
||||
);
|
||||
};
|
||||
|
||||
const alignments = spatialMaps.map((spatialMap) => {
|
||||
const horizontalAlignments: Record<number, string[]> = {};
|
||||
const verticalAlignments: Record<number, string[]> = {};
|
||||
const horizontalAlignments: Record<number, Record<string, string[]>> = {};
|
||||
const verticalAlignments: Record<number, Record<string, string[]>> = {};
|
||||
|
||||
// Group service ids in an object with their x and y coordinate as the key
|
||||
Object.entries(spatialMap).forEach(([id, [x, y]]) => {
|
||||
if (!horizontalAlignments[y]) {
|
||||
horizontalAlignments[y] = [];
|
||||
}
|
||||
if (!verticalAlignments[x]) {
|
||||
verticalAlignments[x] = [];
|
||||
}
|
||||
horizontalAlignments[y].push(id);
|
||||
verticalAlignments[x].push(id);
|
||||
const nodeGroup = db.getNode(id)?.in ?? 'default';
|
||||
|
||||
horizontalAlignments[y] ??= {};
|
||||
horizontalAlignments[y][nodeGroup] ??= [];
|
||||
horizontalAlignments[y][nodeGroup].push(id);
|
||||
|
||||
verticalAlignments[x] ??= {};
|
||||
verticalAlignments[x][nodeGroup] ??= [];
|
||||
verticalAlignments[x][nodeGroup].push(id);
|
||||
});
|
||||
|
||||
// Merge the values of each object into a list if the inner list has at least 2 elements
|
||||
return {
|
||||
horiz: Object.values(horizontalAlignments).filter((arr) => arr.length > 1),
|
||||
vert: Object.values(verticalAlignments).filter((arr) => arr.length > 1),
|
||||
horiz: Object.values(flattenAlignments(horizontalAlignments, 'horizontal')).filter(
|
||||
(arr) => arr.length > 1
|
||||
),
|
||||
vert: Object.values(flattenAlignments(verticalAlignments, 'vertical')).filter(
|
||||
(arr) => arr.length > 1
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -244,7 +312,8 @@ function layoutArchitecture(
|
||||
junctions: ArchitectureJunction[],
|
||||
groups: ArchitectureGroup[],
|
||||
edges: ArchitectureEdge[],
|
||||
{ spatialMaps }: ArchitectureDataStructures
|
||||
db: ArchitectureDB,
|
||||
{ spatialMaps, groupAlignments }: ArchitectureDataStructures
|
||||
): Promise<cytoscape.Core> {
|
||||
return new Promise((resolve) => {
|
||||
const renderEl = select('body').append('div').attr('id', 'cy').attr('style', 'display:none');
|
||||
@@ -318,9 +387,8 @@ function layoutArchitecture(
|
||||
addServices(services, cy);
|
||||
addJunctions(junctions, cy);
|
||||
addEdges(edges, cy);
|
||||
|
||||
// Use the spatial map to create alignment arrays for fcose
|
||||
const alignmentConstraint = getAlignments(spatialMaps);
|
||||
const alignmentConstraint = getAlignments(db, spatialMaps, groupAlignments);
|
||||
|
||||
// Create the relative constraints for fcose by using an inverse of the spatial map and performing BFS on it
|
||||
const relativePlacementConstraint = getRelativeConstraints(spatialMaps);
|
||||
@@ -454,7 +522,7 @@ export const draw: DrawDefinition = async (text, id, _version, diagObj: Diagram)
|
||||
await drawServices(db, servicesElem, services);
|
||||
drawJunctions(db, servicesElem, junctions);
|
||||
|
||||
const cy = await layoutArchitecture(services, junctions, groups, edges, ds);
|
||||
const cy = await layoutArchitecture(services, junctions, groups, edges, db, ds);
|
||||
|
||||
await drawEdges(edgesElem, cy);
|
||||
await drawGroups(groupElem, cy);
|
||||
|
@@ -7,6 +7,8 @@ import type cytoscape from 'cytoscape';
|
||||
| Architecture Diagram Types |
|
||||
\*=======================================*/
|
||||
|
||||
export type ArchitectureAlignment = 'vertical' | 'horizontal' | 'bend';
|
||||
|
||||
export type ArchitectureDirection = 'L' | 'R' | 'T' | 'B';
|
||||
export type ArchitectureDirectionX = Extract<ArchitectureDirection, 'L' | 'R'>;
|
||||
export type ArchitectureDirectionY = Extract<ArchitectureDirection, 'T' | 'B'>;
|
||||
@@ -170,6 +172,18 @@ export const getArchitectureDirectionXYFactors = function (
|
||||
}
|
||||
};
|
||||
|
||||
export const getArchitectureDirectionAlignment = function (
|
||||
a: ArchitectureDirection,
|
||||
b: ArchitectureDirection
|
||||
): ArchitectureAlignment {
|
||||
if (isArchitectureDirectionXY(a, b)) {
|
||||
return 'bend';
|
||||
} else if (isArchitectureDirectionX(a)) {
|
||||
return 'horizontal';
|
||||
}
|
||||
return 'vertical';
|
||||
};
|
||||
|
||||
export interface ArchitectureStyleOptions {
|
||||
archEdgeColor: string;
|
||||
archEdgeArrowColor: string;
|
||||
@@ -249,9 +263,27 @@ export interface ArchitectureDB extends DiagramDB {
|
||||
|
||||
export type ArchitectureAdjacencyList = Record<string, ArchitectureDirectionPairMap>;
|
||||
export type ArchitectureSpatialMap = Record<string, number[]>;
|
||||
|
||||
/**
|
||||
* Maps the direction that groups connect from.
|
||||
*
|
||||
* **Outer key**: ID of group A
|
||||
*
|
||||
* **Inner key**: ID of group B
|
||||
*
|
||||
* **Value**: 'vertical' or 'horizontal'
|
||||
*
|
||||
* Note: tmp[groupA][groupB] == tmp[groupB][groupA]
|
||||
*/
|
||||
export type ArchitectureGroupAlignments = Record<
|
||||
string,
|
||||
Record<string, Exclude<ArchitectureAlignment, 'bend'>>
|
||||
>;
|
||||
|
||||
export interface ArchitectureDataStructures {
|
||||
adjList: ArchitectureAdjacencyList;
|
||||
spatialMaps: ArchitectureSpatialMap[];
|
||||
groupAlignments: ArchitectureGroupAlignments;
|
||||
}
|
||||
|
||||
export interface ArchitectureState extends Record<string, unknown> {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { getIconSVG } from '$root/rendering-util/icons.js';
|
||||
import { getIconSVG } from '../../rendering-util/icons.js';
|
||||
import type cytoscape from 'cytoscape';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import { createText } from '../../rendering-util/createText.js';
|
||||
@@ -170,8 +170,8 @@ export const drawEdges = async function (edgesEl: D3Element, cy: cytoscape.Core)
|
||||
textElem.attr(
|
||||
'transform',
|
||||
`
|
||||
translate(${midX}, ${midY - bboxOrig.height / 2})
|
||||
translate(${(x * bboxNew.width) / 2}, ${(y * bboxNew.height) / 2})
|
||||
translate(${midX}, ${midY - bboxOrig.height / 2})
|
||||
translate(${(x * bboxNew.width) / 2}, ${(y * bboxNew.height) / 2})
|
||||
rotate(${-1 * x * y * 45}, 0, ${bboxOrig.height / 2})
|
||||
`
|
||||
);
|
||||
|
@@ -124,7 +124,8 @@ async function calculateBlockSize(
|
||||
}
|
||||
|
||||
// Add the element to the DOM to size it
|
||||
const nodeEl = await insertNode(elem, node);
|
||||
const config = getConfig();
|
||||
const nodeEl = await insertNode(elem, node, { config });
|
||||
const boundingBox = nodeEl.node().getBBox();
|
||||
const obj = db.getBlock(node.id);
|
||||
obj.size = { width: boundingBox.width, height: boundingBox.height, x: 0, y: 0, node: nodeEl };
|
||||
@@ -138,7 +139,8 @@ export async function insertBlockPositioned(elem: any, block: Block, db: any) {
|
||||
// Add the element to the DOM to size it
|
||||
const obj = db.getBlock(node.id);
|
||||
if (obj.type !== 'space') {
|
||||
await insertNode(elem, node);
|
||||
const config = getConfig();
|
||||
await insertNode(elem, node, { config });
|
||||
block.intersect = node?.intersect;
|
||||
positionNode(node);
|
||||
}
|
||||
|
@@ -1,9 +1,8 @@
|
||||
import type { Selection } from 'd3';
|
||||
import { select } from 'd3';
|
||||
import { select, type Selection } from 'd3';
|
||||
import { log } from '../../logger.js';
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import common from '../common/common.js';
|
||||
import utils from '../../utils.js';
|
||||
import utils, { getEdgeId } from '../../utils.js';
|
||||
import {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
@@ -21,13 +20,18 @@ import type {
|
||||
ClassMap,
|
||||
NamespaceMap,
|
||||
NamespaceNode,
|
||||
StyleClass,
|
||||
Interface,
|
||||
} from './classTypes.js';
|
||||
import type { Node, Edge } from '../../rendering-util/types.js';
|
||||
|
||||
const MERMAID_DOM_ID_PREFIX = 'classId-';
|
||||
|
||||
let relations: ClassRelation[] = [];
|
||||
let classes = new Map<string, ClassNode>();
|
||||
const styleClasses = new Map<string, StyleClass>();
|
||||
let notes: ClassNote[] = [];
|
||||
let interfaces: Interface[] = [];
|
||||
let classCounter = 0;
|
||||
let namespaces = new Map<string, NamespaceNode>();
|
||||
let namespaceCounter = 0;
|
||||
@@ -58,6 +62,8 @@ export const setClassLabel = function (_id: string, label: string) {
|
||||
|
||||
const { className } = splitClassNameAndType(id);
|
||||
classes.get(className)!.label = label;
|
||||
classes.get(className)!.text =
|
||||
`${label}${classes.get(className)!.type ? `<${classes.get(className)!.type}>` : ''}`;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -80,7 +86,9 @@ export const addClass = function (_id: string) {
|
||||
id: name,
|
||||
type: type,
|
||||
label: name,
|
||||
cssClasses: [],
|
||||
text: `${name}${type ? `<${type}>` : ''}`,
|
||||
shape: 'classBox',
|
||||
cssClasses: 'default',
|
||||
methods: [],
|
||||
members: [],
|
||||
annotations: [],
|
||||
@@ -91,6 +99,16 @@ export const addClass = function (_id: string) {
|
||||
classCounter++;
|
||||
};
|
||||
|
||||
const addInterface = function (label: string, classId: string) {
|
||||
const classInterface: Interface = {
|
||||
id: `interface${interfaces.length}`,
|
||||
label,
|
||||
classId,
|
||||
};
|
||||
|
||||
interfaces.push(classInterface);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function to lookup domId from id in the graph definition.
|
||||
*
|
||||
@@ -109,6 +127,7 @@ export const clear = function () {
|
||||
relations = [];
|
||||
classes = new Map();
|
||||
notes = [];
|
||||
interfaces = [];
|
||||
functions = [];
|
||||
functions.push(setupToolTips);
|
||||
namespaces = new Map();
|
||||
@@ -133,19 +152,50 @@ export const getNotes = function () {
|
||||
return notes;
|
||||
};
|
||||
|
||||
export const addRelation = function (relation: ClassRelation) {
|
||||
log.debug('Adding relation: ' + JSON.stringify(relation));
|
||||
addClass(relation.id1);
|
||||
addClass(relation.id2);
|
||||
export const addRelation = function (classRelation: ClassRelation) {
|
||||
log.debug('Adding relation: ' + JSON.stringify(classRelation));
|
||||
// Due to relationType cannot just check if it is equal to 'none' or it complains, can fix this later
|
||||
const invalidTypes = [
|
||||
relationType.LOLLIPOP,
|
||||
relationType.AGGREGATION,
|
||||
relationType.COMPOSITION,
|
||||
relationType.DEPENDENCY,
|
||||
relationType.EXTENSION,
|
||||
];
|
||||
|
||||
relation.id1 = splitClassNameAndType(relation.id1).className;
|
||||
relation.id2 = splitClassNameAndType(relation.id2).className;
|
||||
if (
|
||||
classRelation.relation.type1 === relationType.LOLLIPOP &&
|
||||
!invalidTypes.includes(classRelation.relation.type2)
|
||||
) {
|
||||
addClass(classRelation.id2);
|
||||
addInterface(classRelation.id1, classRelation.id2);
|
||||
classRelation.id1 = `interface${interfaces.length - 1}`;
|
||||
} else if (
|
||||
classRelation.relation.type2 === relationType.LOLLIPOP &&
|
||||
!invalidTypes.includes(classRelation.relation.type1)
|
||||
) {
|
||||
addClass(classRelation.id1);
|
||||
addInterface(classRelation.id2, classRelation.id1);
|
||||
classRelation.id2 = `interface${interfaces.length - 1}`;
|
||||
} else {
|
||||
addClass(classRelation.id1);
|
||||
addClass(classRelation.id2);
|
||||
}
|
||||
|
||||
relation.relationTitle1 = common.sanitizeText(relation.relationTitle1.trim(), getConfig());
|
||||
classRelation.id1 = splitClassNameAndType(classRelation.id1).className;
|
||||
classRelation.id2 = splitClassNameAndType(classRelation.id2).className;
|
||||
|
||||
relation.relationTitle2 = common.sanitizeText(relation.relationTitle2.trim(), getConfig());
|
||||
classRelation.relationTitle1 = common.sanitizeText(
|
||||
classRelation.relationTitle1.trim(),
|
||||
getConfig()
|
||||
);
|
||||
|
||||
relations.push(relation);
|
||||
classRelation.relationTitle2 = common.sanitizeText(
|
||||
classRelation.relationTitle2.trim(),
|
||||
getConfig()
|
||||
);
|
||||
|
||||
relations.push(classRelation);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -229,11 +279,37 @@ export const setCssClass = function (ids: string, className: string) {
|
||||
}
|
||||
const classNode = classes.get(id);
|
||||
if (classNode) {
|
||||
classNode.cssClasses.push(className);
|
||||
classNode.cssClasses += ' ' + className;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const defineClass = function (ids: string[], style: string[]) {
|
||||
for (const id of ids) {
|
||||
let styleClass = styleClasses.get(id);
|
||||
if (styleClass === undefined) {
|
||||
styleClass = { id, styles: [], textStyles: [] };
|
||||
styleClasses.set(id, styleClass);
|
||||
}
|
||||
|
||||
if (style) {
|
||||
style.forEach(function (s) {
|
||||
if (/color/.exec(s)) {
|
||||
const newStyle = s.replace('fill', 'bgFill'); // .replace('color', 'fill');
|
||||
styleClass.textStyles.push(newStyle);
|
||||
}
|
||||
styleClass.styles.push(s);
|
||||
});
|
||||
}
|
||||
|
||||
classes.forEach((value) => {
|
||||
if (value.cssClasses.includes(id)) {
|
||||
value.styles.push(...style.flatMap((s) => s.split(',')));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by parser when a tooltip is found, e.g. a clickable element.
|
||||
*
|
||||
@@ -389,7 +465,6 @@ const setupToolTips = function (element: Element) {
|
||||
// @ts-ignore - getBoundingClientRect is not part of the d3 type definition
|
||||
const rect = this.getBoundingClientRect();
|
||||
|
||||
// @ts-expect-error - Incorrect types
|
||||
tooltipElem.transition().duration(200).style('opacity', '.9');
|
||||
tooltipElem
|
||||
.text(el.attr('title'))
|
||||
@@ -399,7 +474,6 @@ const setupToolTips = function (element: Element) {
|
||||
el.classed('hover', true);
|
||||
})
|
||||
.on('mouseout', function () {
|
||||
// @ts-expect-error - Incorrect types
|
||||
tooltipElem.transition().duration(500).style('opacity', 0);
|
||||
const el = select(this);
|
||||
el.classed('hover', false);
|
||||
@@ -474,6 +548,152 @@ export const setCssStyle = function (id: string, styles: string[]) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the arrow marker for a type index
|
||||
*
|
||||
* @param type - The type to look for
|
||||
* @returns The arrow marker
|
||||
*/
|
||||
function getArrowMarker(type: number) {
|
||||
let marker;
|
||||
switch (type) {
|
||||
case 0:
|
||||
marker = 'aggregation';
|
||||
break;
|
||||
case 1:
|
||||
marker = 'extension';
|
||||
break;
|
||||
case 2:
|
||||
marker = 'composition';
|
||||
break;
|
||||
case 3:
|
||||
marker = 'dependency';
|
||||
break;
|
||||
case 4:
|
||||
marker = 'lollipop';
|
||||
break;
|
||||
default:
|
||||
marker = 'none';
|
||||
}
|
||||
return marker;
|
||||
}
|
||||
|
||||
export const getData = () => {
|
||||
const nodes: Node[] = [];
|
||||
const edges: Edge[] = [];
|
||||
const config = getConfig();
|
||||
|
||||
for (const namespaceKey of namespaces.keys()) {
|
||||
const namespace = namespaces.get(namespaceKey);
|
||||
if (namespace) {
|
||||
const node: Node = {
|
||||
id: namespace.id,
|
||||
label: namespace.id,
|
||||
isGroup: true,
|
||||
padding: config.class!.padding ?? 16,
|
||||
// parent node must be one of [rect, roundedWithTitle, noteGroup, divider]
|
||||
shape: 'rect',
|
||||
cssStyles: ['fill: none', 'stroke: black'],
|
||||
look: config.look,
|
||||
};
|
||||
nodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
for (const classKey of classes.keys()) {
|
||||
const classNode = classes.get(classKey);
|
||||
if (classNode) {
|
||||
const node = classNode as unknown as Node;
|
||||
node.parentId = classNode.parent;
|
||||
node.look = config.look;
|
||||
nodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
let cnt = 0;
|
||||
for (const note of notes) {
|
||||
cnt++;
|
||||
const noteNode: Node = {
|
||||
id: note.id,
|
||||
label: note.text,
|
||||
isGroup: false,
|
||||
shape: 'note',
|
||||
padding: config.class!.padding ?? 6,
|
||||
cssStyles: [
|
||||
'text-align: left',
|
||||
'white-space: nowrap',
|
||||
`fill: ${config.themeVariables.noteBkgColor}`,
|
||||
`stroke: ${config.themeVariables.noteBorderColor}`,
|
||||
],
|
||||
look: config.look,
|
||||
};
|
||||
nodes.push(noteNode);
|
||||
|
||||
const noteClassId = classes.get(note.class)?.id ?? '';
|
||||
|
||||
if (noteClassId) {
|
||||
const edge: Edge = {
|
||||
id: `edgeNote${cnt}`,
|
||||
start: note.id,
|
||||
end: noteClassId,
|
||||
type: 'normal',
|
||||
thickness: 'normal',
|
||||
classes: 'relation',
|
||||
arrowTypeStart: 'none',
|
||||
arrowTypeEnd: 'none',
|
||||
arrowheadStyle: '',
|
||||
labelStyle: [''],
|
||||
style: ['fill: none'],
|
||||
pattern: 'dotted',
|
||||
look: config.look,
|
||||
};
|
||||
edges.push(edge);
|
||||
}
|
||||
}
|
||||
|
||||
for (const _interface of interfaces) {
|
||||
const interfaceNode: Node = {
|
||||
id: _interface.id,
|
||||
label: _interface.label,
|
||||
isGroup: false,
|
||||
shape: 'rect',
|
||||
cssStyles: ['opacity: 0;'],
|
||||
look: config.look,
|
||||
};
|
||||
nodes.push(interfaceNode);
|
||||
}
|
||||
|
||||
cnt = 0;
|
||||
for (const classRelation of relations) {
|
||||
cnt++;
|
||||
const edge: Edge = {
|
||||
id: getEdgeId(classRelation.id1, classRelation.id2, {
|
||||
prefix: 'id',
|
||||
counter: cnt,
|
||||
}),
|
||||
start: classRelation.id1,
|
||||
end: classRelation.id2,
|
||||
type: 'normal',
|
||||
label: classRelation.title,
|
||||
labelpos: 'c',
|
||||
thickness: 'normal',
|
||||
classes: 'relation',
|
||||
arrowTypeStart: getArrowMarker(classRelation.relation.type1),
|
||||
arrowTypeEnd: getArrowMarker(classRelation.relation.type2),
|
||||
startLabelRight: classRelation.relationTitle1 === 'none' ? '' : classRelation.relationTitle1,
|
||||
endLabelLeft: classRelation.relationTitle2 === 'none' ? '' : classRelation.relationTitle2,
|
||||
arrowheadStyle: '',
|
||||
labelStyle: ['display: inline-block'],
|
||||
style: classRelation.style || '',
|
||||
pattern: classRelation.relation.lineType == 1 ? 'dashed' : 'solid',
|
||||
look: config.look,
|
||||
};
|
||||
edges.push(edge);
|
||||
}
|
||||
|
||||
return { nodes, edges, other: {}, config, direction: getDirection() };
|
||||
};
|
||||
|
||||
export default {
|
||||
setAccTitle,
|
||||
getAccTitle,
|
||||
@@ -499,6 +719,7 @@ export default {
|
||||
relationType,
|
||||
setClickEvent,
|
||||
setCssClass,
|
||||
defineClass,
|
||||
setLink,
|
||||
getTooltip,
|
||||
setTooltip,
|
||||
@@ -511,4 +732,5 @@ export default {
|
||||
getNamespace,
|
||||
getNamespaces,
|
||||
setCssStyle,
|
||||
getData,
|
||||
};
|
||||
|
@@ -13,7 +13,7 @@ describe('class diagram, ', function () {
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses[0]).toBe('exClass');
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default exClass');
|
||||
});
|
||||
|
||||
it('should be possible to apply a css class to a class directly with struct', function () {
|
||||
@@ -28,7 +28,7 @@ describe('class diagram, ', function () {
|
||||
parser.parse(str);
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.cssClasses[0]).toBe('exClass');
|
||||
expect(testClass.cssClasses).toBe('default exClass');
|
||||
});
|
||||
|
||||
it('should be possible to apply a css class to a class with relations', function () {
|
||||
@@ -36,7 +36,7 @@ describe('class diagram, ', function () {
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses[0]).toBe('exClass');
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default exClass');
|
||||
});
|
||||
|
||||
it('should be possible to apply a cssClass to a class', function () {
|
||||
@@ -44,7 +44,7 @@ describe('class diagram, ', function () {
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses[0]).toBe('exClass');
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default exClass');
|
||||
});
|
||||
|
||||
it('should be possible to apply a cssClass to a comma separated list of classes', function () {
|
||||
@@ -53,8 +53,8 @@ describe('class diagram, ', function () {
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses[0]).toBe('exClass');
|
||||
expect(parser.yy.getClass('Class02').cssClasses[0]).toBe('exClass');
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default exClass');
|
||||
expect(parser.yy.getClass('Class02').cssClasses).toBe('default exClass');
|
||||
});
|
||||
it('should be possible to apply a style to an individual node', function () {
|
||||
const str =
|
||||
@@ -69,5 +69,47 @@ describe('class diagram, ', function () {
|
||||
expect(styleElements[1]).toBe('stroke:#333');
|
||||
expect(styleElements[2]).toBe('stroke-width:4px');
|
||||
});
|
||||
it('should be possible to define and assign a class inside the diagram', function () {
|
||||
const str =
|
||||
'classDiagram\n' + 'class Class01\n cssClass "Class01" pink\n classDef pink fill:#f9f';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default pink');
|
||||
});
|
||||
it('should be possible to define and assign a class using shorthand inside the diagram', function () {
|
||||
const str = 'classDiagram\n' + 'class Class01:::pink\n classDef pink fill:#f9f';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default pink');
|
||||
});
|
||||
it('should properly assign styles from a class defined inside the diagram', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class01:::pink\n classDef pink fill:#f9f,stroke:#333,stroke-width:6px';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').styles).toStrictEqual([
|
||||
'fill:#f9f',
|
||||
'stroke:#333',
|
||||
'stroke-width:6px',
|
||||
]);
|
||||
});
|
||||
it('should properly assign multiple classes and styles from classes defined inside the diagram', function () {
|
||||
const str =
|
||||
'classDiagram\n' +
|
||||
'class Class01:::pink\n cssClass "Class01" bold\n classDef pink fill:#f9f\n classDef bold stroke:#333,stroke-width:6px';
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
expect(parser.yy.getClass('Class01').styles).toStrictEqual([
|
||||
'fill:#f9f',
|
||||
'stroke:#333',
|
||||
'stroke-width:6px',
|
||||
]);
|
||||
expect(parser.yy.getClass('Class01').cssClasses).toBe('default pink bold');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -3,7 +3,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import parser from './parser/classDiagram.jison';
|
||||
import db from './classDb.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './classRenderer-v2.js';
|
||||
import renderer from './classRenderer-v3-unified.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
|
@@ -14,6 +14,78 @@ describe('given a basic class diagram, ', function () {
|
||||
classDb.clear();
|
||||
parser.yy = classDb;
|
||||
});
|
||||
it('should handle classes within namespaces', () => {
|
||||
const str = `classDiagram
|
||||
namespace Company.Project {
|
||||
class User {
|
||||
+login(username: String, password: String)
|
||||
+logout()
|
||||
}
|
||||
}
|
||||
namespace Company.Project.Module {
|
||||
class Admin {
|
||||
+addUser(user: User)
|
||||
+removeUser(user: User)
|
||||
}
|
||||
}`;
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const user = classDb.getClass('User');
|
||||
const admin = classDb.getClass('Admin');
|
||||
|
||||
// Check if the classes are correctly registered under their respective namespaces
|
||||
expect(user.parent).toBe('Company.Project');
|
||||
expect(admin.parent).toBe('Company.Project.Module');
|
||||
expect(user.methods.length).toBe(2);
|
||||
expect(admin.methods.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should handle generic classes within namespaces', () => {
|
||||
const str = `classDiagram
|
||||
namespace Company.Project.Module {
|
||||
class GenericClass~T~ {
|
||||
+addItem(item: T)
|
||||
+getItem() T
|
||||
}
|
||||
}`;
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const genericClass = classDb.getClass('GenericClass');
|
||||
expect(genericClass.type).toBe('T');
|
||||
expect(genericClass.methods[0].getDisplayDetails().displayText).toBe('+addItem(item: T)');
|
||||
expect(genericClass.methods[1].getDisplayDetails().displayText).toBe('+getItem() : T');
|
||||
});
|
||||
|
||||
it('should handle nested namespaces and relationships', () => {
|
||||
const str = ` classDiagram
|
||||
namespace Company.Project.Module.SubModule {
|
||||
class Report {
|
||||
+generatePDF(data: List)
|
||||
+generateCSV(data: List)
|
||||
}
|
||||
}
|
||||
namespace Company.Project.Module {
|
||||
class Admin {
|
||||
+generateReport()
|
||||
}
|
||||
}
|
||||
Admin --> Report : generates`;
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const report = classDb.getClass('Report');
|
||||
const admin = classDb.getClass('Admin');
|
||||
const relations = classDb.getRelations();
|
||||
|
||||
expect(report.parent).toBe('Company.Project.Module.SubModule');
|
||||
expect(admin.parent).toBe('Company.Project.Module');
|
||||
expect(relations[0].id1).toBe('Admin');
|
||||
expect(relations[0].id2).toBe('Report');
|
||||
expect(relations[0].title).toBe('generates');
|
||||
});
|
||||
|
||||
it('should handle accTitle and accDescr', function () {
|
||||
const str = `classDiagram
|
||||
accTitle: My Title
|
||||
@@ -48,6 +120,22 @@ describe('given a basic class diagram, ', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('should handle fully qualified class names in relationships', () => {
|
||||
const str = `classDiagram
|
||||
namespace Company.Project.Module {
|
||||
class User
|
||||
class Admin
|
||||
}
|
||||
Admin --> User : manages`;
|
||||
|
||||
parser.parse(str);
|
||||
|
||||
const relations = classDb.getRelations();
|
||||
expect(relations[0].id1).toBe('Admin');
|
||||
expect(relations[0].id2).toBe('User');
|
||||
expect(relations[0].title).toBe('manages');
|
||||
});
|
||||
|
||||
it('should handle backquoted class names', function () {
|
||||
const str = 'classDiagram\n' + 'class `Car`';
|
||||
|
||||
@@ -158,7 +246,7 @@ describe('given a basic class diagram, ', function () {
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
});
|
||||
|
||||
it('should parse a class with text label and css class', () => {
|
||||
@@ -173,7 +261,7 @@ describe('given a basic class diagram, ', function () {
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.members[0].getDisplayDetails().displayText).toBe('int member1');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css classes', () => {
|
||||
@@ -188,11 +276,11 @@ describe('given a basic class diagram, ', function () {
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Long long long long long long long long long long label');
|
||||
expect(c2.cssClasses[0]).toBe('styleClass');
|
||||
expect(c2.cssClasses).toBe('default styleClass');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css class shorthands', () => {
|
||||
@@ -205,11 +293,11 @@ describe('given a basic class diagram, ', function () {
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses[0]).toBe('styleClass1');
|
||||
expect(c1.cssClasses).toBe('default styleClass1');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Class 2 !@#$%^&*() label');
|
||||
expect(c2.cssClasses[0]).toBe('styleClass2');
|
||||
expect(c2.cssClasses).toBe('default styleClass2');
|
||||
});
|
||||
|
||||
it('should parse multiple classes with same text labels', () => {
|
||||
@@ -393,12 +481,27 @@ class C13["With Città foreign language"]
|
||||
Student "1" --o "1" IdCard : carries
|
||||
Student "1" --o "1" Bike : rides`);
|
||||
|
||||
expect(classDb.getClasses().size).toBe(3);
|
||||
const studentClass = classDb.getClasses().get('Student');
|
||||
// Check that the important properties match, but ignore the domId
|
||||
expect(studentClass).toMatchObject({
|
||||
id: 'Student',
|
||||
label: 'Student',
|
||||
members: [
|
||||
expect.objectContaining({
|
||||
id: 'idCard : IdCard',
|
||||
visibility: '-',
|
||||
}),
|
||||
],
|
||||
methods: [],
|
||||
annotations: [],
|
||||
cssClasses: 'default',
|
||||
});
|
||||
|
||||
expect(classDb.getClasses().get('Student')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"annotations": [],
|
||||
"cssClasses": [],
|
||||
"domId": "classId-Student-134",
|
||||
"cssClasses": "default",
|
||||
"domId": "classId-Student-141",
|
||||
"id": "Student",
|
||||
"label": "Student",
|
||||
"members": [
|
||||
@@ -406,11 +509,14 @@ class C13["With Città foreign language"]
|
||||
"classifier": "",
|
||||
"id": "idCard : IdCard",
|
||||
"memberType": "attribute",
|
||||
"text": "\\-idCard : IdCard",
|
||||
"visibility": "-",
|
||||
},
|
||||
],
|
||||
"methods": [],
|
||||
"shape": "classBox",
|
||||
"styles": [],
|
||||
"text": "Student",
|
||||
"type": "",
|
||||
}
|
||||
`);
|
||||
@@ -654,7 +760,7 @@ foo()
|
||||
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.link).toBe('google.com');
|
||||
expect(actual.cssClasses[0]).toBe('clickable');
|
||||
expect(actual.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should handle href link with tooltip', function () {
|
||||
@@ -670,7 +776,7 @@ foo()
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.link).toBe('google.com');
|
||||
expect(actual.tooltip).toBe('A Tooltip');
|
||||
expect(actual.cssClasses[0]).toBe('clickable');
|
||||
expect(actual.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should handle href link with tooltip and target', function () {
|
||||
@@ -689,7 +795,7 @@ foo()
|
||||
const actual = parser.yy.getClass('Class1');
|
||||
expect(actual.link).toBe('google.com');
|
||||
expect(actual.tooltip).toBe('A tooltip');
|
||||
expect(actual.cssClasses[0]).toBe('clickable');
|
||||
expect(actual.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should handle function call', function () {
|
||||
@@ -1384,8 +1490,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
expect(testClass.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link and css appropriately', function () {
|
||||
@@ -1398,8 +1503,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
expect(testClass.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should associate link with tooltip', function () {
|
||||
@@ -1413,8 +1517,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.tooltip).toBe('A tooltip');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
expect(testClass.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link with tooltip', function () {
|
||||
@@ -1428,8 +1531,7 @@ describe('given a class diagram with relationships, ', function () {
|
||||
const testClass = parser.yy.getClass('Class1');
|
||||
expect(testClass.link).toBe('google.com');
|
||||
expect(testClass.tooltip).toBe('A tooltip');
|
||||
expect(testClass.cssClasses.length).toBe(1);
|
||||
expect(testClass.cssClasses[0]).toBe('clickable');
|
||||
expect(testClass.cssClasses).toBe('default clickable');
|
||||
});
|
||||
|
||||
it('should associate click and href link with tooltip and target appropriately', function () {
|
||||
@@ -1686,8 +1788,7 @@ C1 --> C2
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
});
|
||||
@@ -1703,8 +1804,7 @@ cssClass "C1" styleClass
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
const member = c1.members[0];
|
||||
expect(member.getDisplayDetails().displayText).toBe('+member1');
|
||||
});
|
||||
@@ -1721,13 +1821,11 @@ cssClass "C1,C2" styleClass
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass');
|
||||
expect(c1.cssClasses).toBe('default styleClass');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Long long long long long long long long long long label');
|
||||
expect(c2.cssClasses.length).toBe(1);
|
||||
expect(c2.cssClasses[0]).toBe('styleClass');
|
||||
expect(c2.cssClasses).toBe('default styleClass');
|
||||
});
|
||||
|
||||
it('should parse two classes with text labels and css class shorthands', () => {
|
||||
@@ -1741,13 +1839,11 @@ C1 --> C2
|
||||
|
||||
const c1 = classDb.getClass('C1');
|
||||
expect(c1.label).toBe('Class 1 with text label');
|
||||
expect(c1.cssClasses.length).toBe(1);
|
||||
expect(c1.cssClasses[0]).toBe('styleClass1');
|
||||
expect(c1.cssClasses).toBe('default styleClass1');
|
||||
|
||||
const c2 = classDb.getClass('C2');
|
||||
expect(c2.label).toBe('Class 2 !@#$%^&*() label');
|
||||
expect(c2.cssClasses.length).toBe(1);
|
||||
expect(c2.cssClasses[0]).toBe('styleClass2');
|
||||
expect(c2.cssClasses).toBe('default styleClass2');
|
||||
});
|
||||
|
||||
it('should parse multiple classes with same text labels', () => {
|
||||
|
@@ -3,7 +3,7 @@ import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import parser from './parser/classDiagram.jison';
|
||||
import db from './classDb.js';
|
||||
import styles from './styles.js';
|
||||
import renderer from './classRenderer.js';
|
||||
import renderer from './classRenderer-v3-unified.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
|
@@ -0,0 +1,79 @@
|
||||
import { getConfig } from '../../diagram-api/diagramAPI.js';
|
||||
import type { DiagramStyleClassDef } from '../../diagram-api/types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import { getDiagramElement } from '../../rendering-util/insertElementsForSize.js';
|
||||
import { getRegisteredLayoutAlgorithm, render } from '../../rendering-util/render.js';
|
||||
import { setupViewPortForSVG } from '../../rendering-util/setupViewPortForSVG.js';
|
||||
import type { LayoutData } from '../../rendering-util/types.js';
|
||||
import utils from '../../utils.js';
|
||||
|
||||
/**
|
||||
* Get the direction from the statement items.
|
||||
* Look through all of the documents (docs) in the parsedItems
|
||||
* Because is a _document_ direction, the default direction is not necessarily the same as the overall default _diagram_ direction.
|
||||
* @param parsedItem - the parsed statement item to look through
|
||||
* @param defaultDir - the direction to use if none is found
|
||||
* @returns The direction to use
|
||||
*/
|
||||
export const getDir = (parsedItem: any, defaultDir = 'TB') => {
|
||||
if (!parsedItem.doc) {
|
||||
return defaultDir;
|
||||
}
|
||||
|
||||
let dir = defaultDir;
|
||||
|
||||
for (const parsedItemDoc of parsedItem.doc) {
|
||||
if (parsedItemDoc.stmt === 'dir') {
|
||||
dir = parsedItemDoc.value;
|
||||
}
|
||||
}
|
||||
|
||||
return dir;
|
||||
};
|
||||
|
||||
export const getClasses = function (
|
||||
text: string,
|
||||
diagramObj: any
|
||||
): Map<string, DiagramStyleClassDef> {
|
||||
return diagramObj.db.getClasses();
|
||||
};
|
||||
|
||||
export const draw = async function (text: string, id: string, _version: string, diag: any) {
|
||||
log.info('REF0:');
|
||||
log.info('Drawing class diagram (v3)', id);
|
||||
const { securityLevel, state: conf, layout } = getConfig();
|
||||
// Extracting the data from the parsed structure into a more usable form
|
||||
// Not related to the refactoring, but this is the first step in the rendering process
|
||||
// diag.db.extract(diag.db.getRootDocV2());
|
||||
|
||||
// The getData method provided in all supported diagrams is used to extract the data from the parsed structure
|
||||
// into the Layout data format
|
||||
const data4Layout = diag.db.getData() as LayoutData;
|
||||
|
||||
// Create the root SVG - the element is the div containing the SVG element
|
||||
const svg = getDiagramElement(id, securityLevel);
|
||||
|
||||
data4Layout.type = diag.type;
|
||||
data4Layout.layoutAlgorithm = getRegisteredLayoutAlgorithm(layout);
|
||||
|
||||
data4Layout.nodeSpacing = conf?.nodeSpacing || 50;
|
||||
data4Layout.rankSpacing = conf?.rankSpacing || 50;
|
||||
data4Layout.markers = ['aggregation', 'extension', 'composition', 'dependency', 'lollipop'];
|
||||
data4Layout.diagramId = id;
|
||||
await render(data4Layout, svg);
|
||||
const padding = 8;
|
||||
utils.insertTitle(
|
||||
svg,
|
||||
'classDiagramTitleText',
|
||||
conf?.titleTopMargin ?? 25,
|
||||
diag.db.getDiagramTitle()
|
||||
);
|
||||
|
||||
setupViewPortForSVG(svg, padding, 'classDiagram', conf?.useMaxWidth ?? true);
|
||||
};
|
||||
|
||||
export default {
|
||||
getClasses,
|
||||
draw,
|
||||
getDir,
|
||||
};
|
@@ -5,7 +5,9 @@ export interface ClassNode {
|
||||
id: string;
|
||||
type: string;
|
||||
label: string;
|
||||
cssClasses: string[];
|
||||
shape: string;
|
||||
text: string;
|
||||
cssClasses: string;
|
||||
methods: ClassMember[];
|
||||
members: ClassMember[];
|
||||
annotations: string[];
|
||||
@@ -16,6 +18,7 @@ export interface ClassNode {
|
||||
linkTarget?: string;
|
||||
haveCallback?: boolean;
|
||||
tooltip?: string;
|
||||
look?: string;
|
||||
}
|
||||
|
||||
export type Visibility = '#' | '+' | '~' | '-' | '';
|
||||
@@ -30,6 +33,7 @@ export class ClassMember {
|
||||
cssStyle!: string;
|
||||
memberType!: 'method' | 'attribute';
|
||||
visibility!: Visibility;
|
||||
text: string;
|
||||
/**
|
||||
* denote if static or to determine which css class to apply to the node
|
||||
* @defaultValue ''
|
||||
@@ -50,6 +54,7 @@ export class ClassMember {
|
||||
this.memberType = memberType;
|
||||
this.visibility = '';
|
||||
this.classifier = '';
|
||||
this.text = '';
|
||||
const sanitizedInput = sanitizeText(input, getConfig());
|
||||
this.parseMember(sanitizedInput);
|
||||
}
|
||||
@@ -85,7 +90,7 @@ export class ClassMember {
|
||||
this.visibility = detectedVisibility as Visibility;
|
||||
}
|
||||
|
||||
this.id = match[2].trim();
|
||||
this.id = match[2];
|
||||
this.parameters = match[3] ? match[3].trim() : '';
|
||||
potentialClassifier = match[4] ? match[4].trim() : '';
|
||||
this.returnType = match[5] ? match[5].trim() : '';
|
||||
@@ -118,6 +123,14 @@ export class ClassMember {
|
||||
}
|
||||
|
||||
this.classifier = potentialClassifier;
|
||||
// Preserve one space only
|
||||
this.id = this.id.startsWith(' ') ? ' ' + this.id.trim() : this.id.trim();
|
||||
|
||||
const combinedText = `${this.visibility ? '\\' + this.visibility : ''}${parseGenericTypes(this.id)}${this.memberType === 'method' ? `(${parseGenericTypes(this.parameters)})${this.returnType ? ' : ' + parseGenericTypes(this.returnType) : ''}` : ''}`;
|
||||
this.text = combinedText.replaceAll('<', '<').replaceAll('>', '>');
|
||||
if (this.text.startsWith('\\<')) {
|
||||
this.text = this.text.replace('\\<', '~');
|
||||
}
|
||||
}
|
||||
|
||||
parseClassifier() {
|
||||
@@ -154,6 +167,12 @@ export interface ClassRelation {
|
||||
};
|
||||
}
|
||||
|
||||
export interface Interface {
|
||||
id: string;
|
||||
label: string;
|
||||
classId: string;
|
||||
}
|
||||
|
||||
export interface NamespaceNode {
|
||||
id: string;
|
||||
domId: string;
|
||||
@@ -161,5 +180,11 @@ export interface NamespaceNode {
|
||||
children: NamespaceMap;
|
||||
}
|
||||
|
||||
export interface StyleClass {
|
||||
id: string;
|
||||
styles: string[];
|
||||
textStyles: string[];
|
||||
}
|
||||
|
||||
export type ClassMap = Map<string, ClassNode>;
|
||||
export type NamespaceMap = Map<string, NamespaceNode>;
|
||||
|
@@ -61,6 +61,7 @@ Function arguments are optional: 'call <callback_name>()' simply executes 'callb
|
||||
<string>[^"]* return "STR";
|
||||
<*>["] this.begin("string");
|
||||
"style" return 'STYLE';
|
||||
"classDef" return 'CLASSDEF';
|
||||
|
||||
<INITIAL,namespace>"namespace" { this.begin('namespace'); return 'NAMESPACE'; }
|
||||
<namespace>\s*(\r?\n)+ { this.popState(); return 'NEWLINE'; }
|
||||
@@ -241,11 +242,13 @@ classLabel
|
||||
|
||||
namespaceName
|
||||
: alphaNumToken { $$=$1; }
|
||||
| alphaNumToken DOT namespaceName { $$=$1+'.'+$3; }
|
||||
| alphaNumToken namespaceName { $$=$1+$2; }
|
||||
;
|
||||
|
||||
className
|
||||
: alphaNumToken { $$=$1; }
|
||||
| alphaNumToken DOT className { $$=$1+'.'+$3; }
|
||||
| classLiteralName { $$=$1; }
|
||||
| alphaNumToken className { $$=$1+$2; }
|
||||
| alphaNumToken GENERICTYPE { $$=$1+'~'+$2+'~'; }
|
||||
@@ -263,6 +266,7 @@ statement
|
||||
| styleStatement
|
||||
| cssClassStatement
|
||||
| noteStatement
|
||||
| classDefStatement
|
||||
| direction
|
||||
| acc_title acc_title_value { $$=$2.trim();yy.setAccTitle($$); }
|
||||
| acc_descr acc_descr_value { $$=$2.trim();yy.setAccDescription($$); }
|
||||
@@ -270,12 +274,12 @@ statement
|
||||
;
|
||||
|
||||
namespaceStatement
|
||||
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $3);}
|
||||
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP {yy.addClassesToNamespace($1, $4);}
|
||||
: namespaceIdentifier STRUCT_START classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $3); }
|
||||
| namespaceIdentifier STRUCT_START NEWLINE classStatements STRUCT_STOP { yy.addClassesToNamespace($1, $4); }
|
||||
;
|
||||
|
||||
namespaceIdentifier
|
||||
: NAMESPACE namespaceName {$$=$2; yy.addNamespace($2);}
|
||||
: NAMESPACE namespaceName { $$=$2; yy.addNamespace($2); }
|
||||
;
|
||||
|
||||
classStatements
|
||||
@@ -324,6 +328,15 @@ noteStatement
|
||||
| NOTE noteText { yy.addNote($2); }
|
||||
;
|
||||
|
||||
classDefStatement
|
||||
: CLASSDEF classList stylesOpt {$$ = $CLASSDEF;yy.defineClass($classList,$stylesOpt);}
|
||||
;
|
||||
|
||||
classList
|
||||
: ALPHA { $$ = [$ALPHA]; }
|
||||
| classList COMMA ALPHA = { $$ = $classList.concat([$ALPHA]); }
|
||||
;
|
||||
|
||||
direction
|
||||
: direction_tb
|
||||
{ yy.setDirection('TB');}
|
||||
|
223
packages/mermaid/src/diagrams/class/shapeUtil.ts
Normal file
223
packages/mermaid/src/diagrams/class/shapeUtil.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
import { select } from 'd3';
|
||||
import { getConfig } from '../../config.js';
|
||||
import { getNodeClasses } from '../../rendering-util/rendering-elements/shapes/util.js';
|
||||
import { calculateTextWidth, decodeEntities } from '../../utils.js';
|
||||
import type { ClassMember, ClassNode } from './classTypes.js';
|
||||
import { sanitizeText } from '../../diagram-api/diagramAPI.js';
|
||||
import { createText } from '../../rendering-util/createText.js';
|
||||
import { evaluate, hasKatex } from '../common/common.js';
|
||||
import type { Node } from '../../rendering-util/types.js';
|
||||
import type { MermaidConfig } from '../../config.type.js';
|
||||
import type { D3Selection } from '../../types.js';
|
||||
|
||||
// Creates the shapeSvg and inserts text
|
||||
export async function textHelper<T extends SVGGraphicsElement>(
|
||||
parent: D3Selection<T>,
|
||||
node: any,
|
||||
config: MermaidConfig,
|
||||
useHtmlLabels: boolean,
|
||||
GAP = config.class!.padding ?? 12
|
||||
) {
|
||||
const TEXT_PADDING = !useHtmlLabels ? 3 : 0;
|
||||
const shapeSvg = parent
|
||||
// @ts-ignore: Ignore error for using .insert on SVGAElement
|
||||
.insert('g')
|
||||
.attr('class', getNodeClasses(node))
|
||||
.attr('id', node.domId || node.id);
|
||||
|
||||
let annotationGroup = null;
|
||||
let labelGroup = null;
|
||||
let membersGroup = null;
|
||||
let methodsGroup = null;
|
||||
|
||||
let annotationGroupHeight = 0;
|
||||
let labelGroupHeight = 0;
|
||||
let membersGroupHeight = 0;
|
||||
|
||||
annotationGroup = shapeSvg.insert('g').attr('class', 'annotation-group text');
|
||||
if (node.annotations.length > 0) {
|
||||
const annotation = node.annotations[0];
|
||||
await addText(annotationGroup, { text: `«${annotation}»` } as unknown as ClassMember, 0);
|
||||
|
||||
const annotationGroupBBox = annotationGroup.node()!.getBBox();
|
||||
annotationGroupHeight = annotationGroupBBox.height;
|
||||
}
|
||||
|
||||
labelGroup = shapeSvg.insert('g').attr('class', 'label-group text');
|
||||
await addText(labelGroup, node, 0, ['font-weight: bolder']);
|
||||
const labelGroupBBox = labelGroup.node()!.getBBox();
|
||||
labelGroupHeight = labelGroupBBox.height;
|
||||
|
||||
membersGroup = shapeSvg.insert('g').attr('class', 'members-group text');
|
||||
let yOffset = 0;
|
||||
for (const member of node.members) {
|
||||
const height = await addText(membersGroup, member, yOffset, [member.parseClassifier()]);
|
||||
yOffset += height + TEXT_PADDING;
|
||||
}
|
||||
membersGroupHeight = membersGroup.node()!.getBBox().height;
|
||||
if (membersGroupHeight <= 0) {
|
||||
membersGroupHeight = GAP / 2;
|
||||
}
|
||||
|
||||
methodsGroup = shapeSvg.insert('g').attr('class', 'methods-group text');
|
||||
let methodsYOffset = 0;
|
||||
for (const method of node.methods) {
|
||||
const height = await addText(methodsGroup, method, methodsYOffset, [method.parseClassifier()]);
|
||||
methodsYOffset += height + TEXT_PADDING;
|
||||
}
|
||||
|
||||
let bbox = shapeSvg.node()!.getBBox();
|
||||
|
||||
// Center annotation
|
||||
if (annotationGroup !== null) {
|
||||
const annotationGroupBBox = annotationGroup.node()!.getBBox();
|
||||
annotationGroup.attr('transform', `translate(${-annotationGroupBBox.width / 2})`);
|
||||
}
|
||||
|
||||
// Adjust label
|
||||
labelGroup.attr('transform', `translate(${-labelGroupBBox.width / 2}, ${annotationGroupHeight})`);
|
||||
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
|
||||
membersGroup.attr(
|
||||
'transform',
|
||||
`translate(${0}, ${annotationGroupHeight + labelGroupHeight + GAP * 2})`
|
||||
);
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
methodsGroup.attr(
|
||||
'transform',
|
||||
`translate(${0}, ${annotationGroupHeight + labelGroupHeight + (membersGroupHeight ? membersGroupHeight + GAP * 4 : GAP * 2)})`
|
||||
);
|
||||
|
||||
bbox = shapeSvg.node()!.getBBox();
|
||||
|
||||
return { shapeSvg, bbox };
|
||||
}
|
||||
|
||||
// Modified version of labelHelper() to help create and place text for classes
|
||||
async function addText<T extends SVGGraphicsElement>(
|
||||
parentGroup: D3Selection<T>,
|
||||
node: Node | ClassNode | ClassMember,
|
||||
yOffset: number,
|
||||
styles: string[] = []
|
||||
) {
|
||||
const textEl = parentGroup.insert('g').attr('class', 'label').attr('style', styles.join('; '));
|
||||
const config = getConfig();
|
||||
let useHtmlLabels =
|
||||
'useHtmlLabels' in node ? node.useHtmlLabels : (evaluate(config.htmlLabels) ?? true);
|
||||
|
||||
let textContent = '';
|
||||
// Support regular node type (.label) and classNodes (.text)
|
||||
if ('text' in node) {
|
||||
textContent = node.text;
|
||||
} else {
|
||||
textContent = node.label!;
|
||||
}
|
||||
|
||||
// createText() will cause unwanted behavior because of classDiagram syntax so workarounds are needed
|
||||
|
||||
if (!useHtmlLabels && textContent.startsWith('\\')) {
|
||||
textContent = textContent.substring(1);
|
||||
}
|
||||
|
||||
if (hasKatex(textContent)) {
|
||||
useHtmlLabels = true;
|
||||
}
|
||||
|
||||
const text = await createText(
|
||||
textEl,
|
||||
sanitizeText(decodeEntities(textContent)),
|
||||
{
|
||||
width: calculateTextWidth(textContent, config) + 50, // Add room for error when splitting text into multiple lines
|
||||
classes: 'markdown-node-label',
|
||||
useHtmlLabels,
|
||||
},
|
||||
config
|
||||
);
|
||||
let bbox;
|
||||
let numberOfLines = 1;
|
||||
|
||||
if (!useHtmlLabels) {
|
||||
// Undo font-weight normal
|
||||
if (styles.includes('font-weight: bolder')) {
|
||||
select(text).selectAll('tspan').attr('font-weight', '');
|
||||
}
|
||||
|
||||
numberOfLines = text.children.length;
|
||||
|
||||
const textChild = text.children[0];
|
||||
if (text.textContent === '' || text.textContent.includes('>')) {
|
||||
textChild.textContent =
|
||||
textContent[0] +
|
||||
textContent.substring(1).replaceAll('>', '>').replaceAll('<', '<').trim();
|
||||
|
||||
// Text was improperly removed due to spaces (preserve one space if present)
|
||||
const preserveSpace = textContent[1] === ' ';
|
||||
if (preserveSpace) {
|
||||
textChild.textContent = textChild.textContent[0] + ' ' + textChild.textContent.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
// To support empty boxes
|
||||
if (textChild.textContent === 'undefined') {
|
||||
textChild.textContent = '';
|
||||
}
|
||||
|
||||
// Get the bounding box after the text update
|
||||
bbox = text.getBBox();
|
||||
} else {
|
||||
const div = text.children[0];
|
||||
const dv = select(text);
|
||||
|
||||
numberOfLines = div.innerHTML.split('<br>').length;
|
||||
// Katex math support
|
||||
if (div.innerHTML.includes('</math>')) {
|
||||
numberOfLines += div.innerHTML.split('<mrow>').length - 1;
|
||||
}
|
||||
|
||||
// Support images
|
||||
const images = div.getElementsByTagName('img');
|
||||
if (images) {
|
||||
const noImgText = textContent.replace(/<img[^>]*>/g, '').trim() === '';
|
||||
await Promise.all(
|
||||
[...images].map(
|
||||
(img) =>
|
||||
new Promise((res) => {
|
||||
function setupImage() {
|
||||
img.style.display = 'flex';
|
||||
img.style.flexDirection = 'column';
|
||||
|
||||
if (noImgText) {
|
||||
// default size if no text
|
||||
const bodyFontSize =
|
||||
config.fontSize?.toString() ?? window.getComputedStyle(document.body).fontSize;
|
||||
const enlargingFactor = 5;
|
||||
const width = parseInt(bodyFontSize, 10) * enlargingFactor + 'px';
|
||||
img.style.minWidth = width;
|
||||
img.style.maxWidth = width;
|
||||
} else {
|
||||
img.style.width = '100%';
|
||||
}
|
||||
res(img);
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (img.complete) {
|
||||
setupImage();
|
||||
}
|
||||
});
|
||||
img.addEventListener('error', setupImage);
|
||||
img.addEventListener('load', setupImage);
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bbox = div.getBoundingClientRect();
|
||||
dv.attr('width', bbox.width);
|
||||
dv.attr('height', bbox.height);
|
||||
}
|
||||
|
||||
// Center text and offset by yOffset
|
||||
textEl.attr('transform', 'translate(0,' + (-bbox.height / (2 * numberOfLines) + yOffset) + ')');
|
||||
return bbox.height;
|
||||
}
|
@@ -20,6 +20,10 @@ const getStyles = (options) =>
|
||||
.label text {
|
||||
fill: ${options.classText};
|
||||
}
|
||||
|
||||
.labelBkg {
|
||||
background: ${options.mainBkg};
|
||||
}
|
||||
.edgeLabel .label span {
|
||||
background: ${options.mainBkg};
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user