Compare commits
703 Commits
ImageEleme
...
1.8.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da89e32213 | ||
|
|
b6d36e5076 | ||
|
|
90c377f125 | ||
|
|
df85138890 | ||
|
|
654b656a2f | ||
|
|
1d22dcb488 | ||
|
|
a42e907d0c | ||
|
|
353cad21d6 | ||
|
|
2b02f186a6 | ||
|
|
3e12d1e815 | ||
|
|
539bbdf07f | ||
|
|
b993b358fe | ||
|
|
0639ea5969 | ||
|
|
05b7bc6029 | ||
|
|
c9755be0e9 | ||
|
|
9526fb5726 | ||
|
|
c04587ab5c | ||
|
|
ab94fe304b | ||
|
|
b080fec85e | ||
|
|
c9972116b3 | ||
|
|
c254c8cc5d | ||
|
|
14c2ce3766 | ||
|
|
437a01c194 | ||
|
|
da98aca107 | ||
|
|
e81f4d3688 | ||
|
|
f280704744 | ||
|
|
9547ced85c | ||
|
|
356a0b7a63 | ||
|
|
171e37b4e5 | ||
|
|
cfb070cfe5 | ||
|
|
76e2a32998 | ||
|
|
23a4f42c27 | ||
|
|
8202cf0dde | ||
|
|
40f88bb900 | ||
|
|
e6f5f9469a | ||
|
|
0502ac3bb0 | ||
|
|
36125c9b83 | ||
|
|
cced2ca2e4 | ||
|
|
0de2c78cac | ||
|
|
7848c8f705 | ||
|
|
f6c135227b | ||
|
|
95ca41fcaa | ||
|
|
d7648d702a | ||
|
|
5033a7cccf | ||
|
|
1a83abb256 | ||
|
|
08f616b5d9 | ||
|
|
ca44699e8d | ||
|
|
e0111e264c | ||
|
|
c6196a86a9 | ||
|
|
3926e5c30b | ||
|
|
a1256422fa | ||
|
|
eeb47d4912 | ||
|
|
8ceac4ab31 | ||
|
|
225c6305d1 | ||
|
|
ba9ab61cc9 | ||
|
|
0940a8628a | ||
|
|
46ee9e9524 | ||
|
|
c044278a4a | ||
|
|
aa9118cdae | ||
|
|
d19b32d0c4 | ||
|
|
dd7f0750fd | ||
|
|
e1330cd8bb | ||
|
|
04367bd3cd | ||
|
|
7d139462bf | ||
|
|
d8e429d815 | ||
|
|
4685a6f014 | ||
|
|
03b389a2b5 | ||
|
|
024f7979a7 | ||
|
|
f9e9ac0728 | ||
|
|
c6eb5859b5 | ||
|
|
377268f30c | ||
|
|
b23afc9621 | ||
|
|
d92c95c3fd | ||
|
|
98b39ab2b0 | ||
|
|
431d5e1104 | ||
|
|
adaf6ee0ae | ||
|
|
3d7d6df2ec | ||
|
|
71d00e0c8d | ||
|
|
ed316fc2c4 | ||
|
|
83f12a8fc5 | ||
|
|
2b7253168e | ||
|
|
70a869fa05 | ||
|
|
e66c31618b | ||
|
|
91298190dc | ||
|
|
11b4091d34 | ||
|
|
78287ab5f3 | ||
|
|
f632c709a5 | ||
|
|
2499629f17 | ||
|
|
16f2240c5b | ||
|
|
f670e3db9d | ||
|
|
b5710033bc | ||
|
|
2117844fc2 | ||
|
|
650956054f | ||
|
|
5d24e4f063 | ||
|
|
994ed375b2 | ||
|
|
3acbe2c1bd | ||
|
|
8594fbc490 | ||
|
|
8b9aa8ccc4 | ||
|
|
b0bb5a00fb | ||
|
|
9bf3e899c2 | ||
|
|
db1f989f49 | ||
|
|
4c45a54ddd | ||
|
|
64d48ed867 | ||
|
|
e2d70687c1 | ||
|
|
1aac4ffdf3 | ||
|
|
b9e154330b | ||
|
|
56ae6baf2b | ||
|
|
64fd43abb8 | ||
|
|
31ae51a421 | ||
|
|
0d879b7a7e | ||
|
|
d8166bbf8c | ||
|
|
82bde38a4b | ||
|
|
36b679434f | ||
|
|
6fa90662b3 | ||
|
|
7f45dad610 | ||
|
|
0e1ee0dde2 | ||
|
|
6c7b63cbdf | ||
|
|
bca7010394 | ||
|
|
3565a5bf94 | ||
|
|
f089911e02 | ||
|
|
992af2b5ca | ||
|
|
f85fc124d9 | ||
|
|
961e75a12d | ||
|
|
3be592eeb8 | ||
|
|
5f094f3d95 | ||
|
|
a16fd53958 | ||
|
|
72d425715f | ||
|
|
4a6aed5dd0 | ||
|
|
f76964a7b7 | ||
|
|
161f7041ec | ||
|
|
334e8130eb | ||
|
|
fdb7e97b11 | ||
|
|
22b3769c20 | ||
|
|
cd96870f07 | ||
|
|
a76854d152 | ||
|
|
32319b2f6c | ||
|
|
38add10053 | ||
|
|
21dc29d1d1 | ||
|
|
e7444f5d8a | ||
|
|
cc9d7828c7 | ||
|
|
b67d70c519 | ||
|
|
5c861acea6 | ||
|
|
582c3dbf25 | ||
|
|
e38e21f3ee | ||
|
|
d946b6fbfa | ||
|
|
e6fd56d9ee | ||
|
|
de44b01e0c | ||
|
|
562f3d3f5b | ||
|
|
c0c2b0a014 | ||
|
|
16ff10b894 | ||
|
|
b4ddb7a8c9 | ||
|
|
96dcaf38c1 | ||
|
|
43176e59c3 | ||
|
|
9db43f6d4a | ||
|
|
c18262180f | ||
|
|
509b60cb69 | ||
|
|
6217a0601c | ||
|
|
be5d35e811 | ||
|
|
e759010ae0 | ||
|
|
8ff0d187df | ||
|
|
358ab82b85 | ||
|
|
92cda3b4f9 | ||
|
|
9fafbd82c2 | ||
|
|
37dadda342 | ||
|
|
b041088b59 | ||
|
|
1a04cd88bd | ||
|
|
d0e504c369 | ||
|
|
83005da1bb | ||
|
|
f574721574 | ||
|
|
a7af6b2421 | ||
|
|
e708be8eda | ||
|
|
ea39b8c6a1 | ||
|
|
e5fb705f0b | ||
|
|
8046b5dc1f | ||
|
|
08e4e1f131 | ||
|
|
108293ae5c | ||
|
|
73528596d2 | ||
|
|
d2284b8d14 | ||
|
|
7cd3ec40c6 | ||
|
|
80cbb41913 | ||
|
|
257f3d17ac | ||
|
|
2e6b76b0f3 | ||
|
|
9030a77914 | ||
|
|
461b472f20 | ||
|
|
6bacae16b2 | ||
|
|
fa0f388e4a | ||
|
|
afc4f614b7 | ||
|
|
9e05493a9d | ||
|
|
a20900749d | ||
|
|
461eeafd80 | ||
|
|
5ff8caa04f | ||
|
|
9051fe2c01 | ||
|
|
018e42b34b | ||
|
|
b29e79f2b4 | ||
|
|
1ce0051d4e | ||
|
|
c44a4a91b3 | ||
|
|
2c5a4c01d2 | ||
|
|
668c4d62e9 | ||
|
|
0ce4f5f16b | ||
|
|
56d0966d4e | ||
|
|
e000c6bf39 | ||
|
|
feb5b576cb | ||
|
|
2bd1f68276 | ||
|
|
22d1a9b90a | ||
|
|
00a6a3dcaf | ||
|
|
82061cd126 | ||
|
|
4bdd095ff0 | ||
|
|
f40ad62291 | ||
|
|
de4fc602ca | ||
|
|
f5faec8ac9 | ||
|
|
8834762004 | ||
|
|
48477c7ee9 | ||
|
|
f0f65fb9a3 | ||
|
|
26e12e8cec | ||
|
|
fa2fe5e462 | ||
|
|
83a70828ae | ||
|
|
b2e246bdf4 | ||
|
|
fd0f39c214 | ||
|
|
2862fbc983 | ||
|
|
5f42ed8f8d | ||
|
|
afe01bf660 | ||
|
|
646b63e3dd | ||
|
|
e0266c6731 | ||
|
|
d577c3d121 | ||
|
|
d6f2303160 | ||
|
|
9625b624d1 | ||
|
|
c330415ca8 | ||
|
|
e52c4c4403 | ||
|
|
d5c6ce5c33 | ||
|
|
0a3d49408a | ||
|
|
4b3c5e9859 | ||
|
|
1bbb785ce8 | ||
|
|
cef882642e | ||
|
|
560807285f | ||
|
|
a2f6801e5f | ||
|
|
1ca8e48278 | ||
|
|
c7acb45f85 | ||
|
|
902eda0d79 | ||
|
|
0141790985 | ||
|
|
7b98a48f5b | ||
|
|
f4bdc56d71 | ||
|
|
83eac25e6d | ||
|
|
dd144bd173 | ||
|
|
ce30c0db0b | ||
|
|
fe9a9d6aa2 | ||
|
|
58ed3f8e0a | ||
|
|
e5f04faa6e | ||
|
|
9753613ae2 | ||
|
|
3736c2ca5a | ||
|
|
083fdead73 | ||
|
|
7a2509911b | ||
|
|
d5e01a8c23 | ||
|
|
a25eebfa28 | ||
|
|
1aa092fcc4 | ||
|
|
23e6e2e33f | ||
|
|
e93684a555 | ||
|
|
226b7477a9 | ||
|
|
a8d9931477 | ||
|
|
d4e1737758 | ||
|
|
94adea8095 | ||
|
|
8492850d12 | ||
|
|
dc03fed415 | ||
|
|
2a0623cb93 | ||
|
|
ec4915e88c | ||
|
|
b60618c514 | ||
|
|
635930eccb | ||
|
|
654d12f2a1 | ||
|
|
51f7438fe7 | ||
|
|
13ed74bf73 | ||
|
|
2327b138eb | ||
|
|
87f91d5156 | ||
|
|
cbe6197782 | ||
|
|
5335dc0860 | ||
|
|
6096eefe06 | ||
|
|
18b755a937 | ||
|
|
8d9e62b621 | ||
|
|
5c303a5787 | ||
|
|
8b0c015359 | ||
|
|
8eee8ba69c | ||
|
|
70d0e0ec30 | ||
|
|
6c07235c9b | ||
|
|
62f4dddc8d | ||
|
|
61c6865ad2 | ||
|
|
a85b5f7a36 | ||
|
|
30350c6fec | ||
|
|
857f41ad07 | ||
|
|
b944b348fc | ||
|
|
196821371c | ||
|
|
746aa30ccc | ||
|
|
6ae5765691 | ||
|
|
538ecb959e | ||
|
|
51b96699f0 | ||
|
|
730d8ba675 | ||
|
|
71fbb3ecbe | ||
|
|
55ff6efb26 | ||
|
|
91da878e43 | ||
|
|
e547392dbe | ||
|
|
a6771c1c47 | ||
|
|
f6be4b096b | ||
|
|
90362b0fe2 | ||
|
|
7b917585d5 | ||
|
|
0d566e1998 | ||
|
|
b3f7ecfb8f | ||
|
|
d8e11f6068 | ||
|
|
f3c0808f7f | ||
|
|
043999417c | ||
|
|
ab4ebd1009 | ||
|
|
945411fffc | ||
|
|
ce8792815c | ||
|
|
447001554c | ||
|
|
09812c21d5 | ||
|
|
be2321191f | ||
|
|
be5a9a9c94 | ||
|
|
49940777ed | ||
|
|
211f6af563 | ||
|
|
658c04401e | ||
|
|
9c5331719b | ||
|
|
4be8adcc3e | ||
|
|
8434825706 | ||
|
|
1ca87741a5 | ||
|
|
463eb1d228 | ||
|
|
935febf337 | ||
|
|
e4c7fe7fc9 | ||
|
|
e98b1755ee | ||
|
|
bc71bde9b7 | ||
|
|
2dc10af004 | ||
|
|
46d21f53e5 | ||
|
|
44d9b44c88 | ||
|
|
5875f268f4 | ||
|
|
bc1120ac3a | ||
|
|
40a10620c1 | ||
|
|
28295deaa0 | ||
|
|
b783d9b992 | ||
|
|
98df940f52 | ||
|
|
ab3b84a765 | ||
|
|
5fc6905ac7 | ||
|
|
00c7a0e934 | ||
|
|
60ed7f21f6 | ||
|
|
9e0c5c48d4 | ||
|
|
7e76c2b693 | ||
|
|
dd9b363427 | ||
|
|
90b693151a | ||
|
|
d280c7e953 | ||
|
|
b227ad05fd | ||
|
|
cf07458fbb | ||
|
|
c191b7264d | ||
|
|
109fe05302 | ||
|
|
d55bb1a2c4 | ||
|
|
1362c7f416 | ||
|
|
dc718bbfe1 | ||
|
|
3ab2a3d7fc | ||
|
|
494556b501 | ||
|
|
76b767f505 | ||
|
|
8178328ce8 | ||
|
|
766bf25773 | ||
|
|
ccf81efa7b | ||
|
|
4e101f8786 | ||
|
|
05a7ee8270 | ||
|
|
0e5004ae08 | ||
|
|
77f103d46e | ||
|
|
e2ad92a19c | ||
|
|
0eb3bc6798 | ||
|
|
b11cf139a8 | ||
|
|
81ce31dfbf | ||
|
|
e3f7455511 | ||
|
|
321a5e8ea1 | ||
|
|
b16362a6fd | ||
|
|
a52f633755 | ||
|
|
65fe5282c4 | ||
|
|
4efa4866ef | ||
|
|
a11c195ea4 | ||
|
|
9d31de7674 | ||
|
|
bf9e6e0179 | ||
|
|
1638cb7fc7 | ||
|
|
96c4e9a56b | ||
|
|
bfffa9609f | ||
|
|
ba4e3652da | ||
|
|
bb0d49d94f | ||
|
|
55eb54d162 | ||
|
|
2c584b50ec | ||
|
|
830f51e1ec | ||
|
|
259176e7c8 | ||
|
|
4ae38c70bf | ||
|
|
0a2ef2d751 | ||
|
|
1d830526a7 | ||
|
|
71f1072822 | ||
|
|
8029c5d4cd | ||
|
|
962c6a71f7 | ||
|
|
3e0a6e839f | ||
|
|
7aa416766c | ||
|
|
3dae930201 | ||
|
|
379c2d0e52 | ||
|
|
d9a1113f25 | ||
|
|
d0d5677c81 | ||
|
|
a364c0fe45 | ||
|
|
bf9a917af3 | ||
|
|
7d98bf691c | ||
|
|
b927a48eb3 | ||
|
|
7f2af801a9 | ||
|
|
2c2bbc2d62 | ||
|
|
f66cf344da | ||
|
|
6c4169e9c9 | ||
|
|
92f8b68445 | ||
|
|
d0bfd834c8 | ||
|
|
b00737c40a | ||
|
|
59a8fbf909 | ||
|
|
95e3bb0ddf | ||
|
|
7107b478b4 | ||
|
|
cb43187738 | ||
|
|
de8a921c04 | ||
|
|
ef8f3497d2 | ||
|
|
90c66c411c | ||
|
|
bc8a2cb912 | ||
|
|
0429a76b39 | ||
|
|
46cbcc581c | ||
|
|
4fd5c13d1e | ||
|
|
a285e1aeee | ||
|
|
d342dae47d | ||
|
|
ab1e38da81 | ||
|
|
c71a5b2403 | ||
|
|
f8126709cc | ||
|
|
69abe47e9b | ||
|
|
9ea915339e | ||
|
|
b44125773a | ||
|
|
208284405b | ||
|
|
2193bcf5ce | ||
|
|
f35a5bc948 | ||
|
|
7a69fb3570 | ||
|
|
10a710127a | ||
|
|
7055f08c35 | ||
|
|
637174fe3d | ||
|
|
cabc05d2ce | ||
|
|
871d924289 | ||
|
|
b9d8c0fe44 | ||
|
|
656e551ac3 | ||
|
|
053f3fbc08 | ||
|
|
10c16b8df1 | ||
|
|
1fb233c27f | ||
|
|
43175d60f9 | ||
|
|
2d18aa1d73 | ||
|
|
20017f8e8b | ||
|
|
504db44273 | ||
|
|
ffa230e375 | ||
|
|
ac7266eefd | ||
|
|
bda7db0777 | ||
|
|
7605a105ee | ||
|
|
9705799adf | ||
|
|
340c96cfe4 | ||
|
|
114cad2256 | ||
|
|
b64ca8e43d | ||
|
|
94d234cffc | ||
|
|
e1135d13fd | ||
|
|
2bff6d87da | ||
|
|
1e8ef02944 | ||
|
|
d8a5e26030 | ||
|
|
d6c686d230 | ||
|
|
d7446d20dd | ||
|
|
541db2ca2f | ||
|
|
b0fc21b70a | ||
|
|
0b36759f09 | ||
|
|
c94ebb6bcd | ||
|
|
75e179041d | ||
|
|
3d41690359 | ||
|
|
e3d31f49de | ||
|
|
ee48840421 | ||
|
|
b8b08b3edb | ||
|
|
d1f994a8d1 | ||
|
|
2a8aafeab0 | ||
|
|
d1ab96f9d1 | ||
|
|
1bdf0a8089 | ||
|
|
d8f4d55b76 | ||
|
|
2d16b59ea3 | ||
|
|
b292ca0fa3 | ||
|
|
95c21c2d5e | ||
|
|
7e45a0f952 | ||
|
|
7c8460646a | ||
|
|
8badc3eb8f | ||
|
|
ad98d114e1 | ||
|
|
c90370a606 | ||
|
|
9889567798 | ||
|
|
70ee82bdb1 | ||
|
|
4effb42762 | ||
|
|
176248f33e | ||
|
|
dbb64e5044 | ||
|
|
be7c043871 | ||
|
|
ba69f4319f | ||
|
|
5b755db673 | ||
|
|
2e0ce819a9 | ||
|
|
be03026360 | ||
|
|
d0385563e2 | ||
|
|
91e84cc41a | ||
|
|
f308cfe907 | ||
|
|
0c4919547f | ||
|
|
c0eb85abf5 | ||
|
|
73b31627f3 | ||
|
|
241a1c7301 | ||
|
|
4182098730 | ||
|
|
389387aa6e | ||
|
|
381401f175 | ||
|
|
cca4158295 | ||
|
|
d4ebf68bb5 | ||
|
|
c9b9b64513 | ||
|
|
ea202763be | ||
|
|
1c86308ee3 | ||
|
|
66936975dd | ||
|
|
d70c290658 | ||
|
|
be45a0dfb6 | ||
|
|
98a76d464b | ||
|
|
2edd25c298 | ||
|
|
ca7d9576b4 | ||
|
|
110cb60e00 | ||
|
|
83764410f0 | ||
|
|
c7154d531f | ||
|
|
aafedba989 | ||
|
|
9269b52057 | ||
|
|
1ce44c2d55 | ||
|
|
1796402ced | ||
|
|
f350895817 | ||
|
|
46db9ccbbf | ||
|
|
1123a3bd81 | ||
|
|
79c62edbe7 | ||
|
|
76faf3011b | ||
|
|
d0d6fbad12 | ||
|
|
3ba6292d6f | ||
|
|
adad32b641 | ||
|
|
35bb2368fe | ||
|
|
2c63a24c81 | ||
|
|
db17b91418 | ||
|
|
47b9b16588 | ||
|
|
5194ced50c | ||
|
|
9eaf22305a | ||
|
|
6392bcd06e | ||
|
|
b6c5bfb20a | ||
|
|
4328537034 | ||
|
|
49f7c47064 | ||
|
|
fec9d083e7 | ||
|
|
b8374a6b0b | ||
|
|
a30c6bbf48 | ||
|
|
f85246f894 | ||
|
|
585640ff2e | ||
|
|
17f6c7d2ac | ||
|
|
896a31d02a | ||
|
|
c54c133ba0 | ||
|
|
7c01da8731 | ||
|
|
489b53f0f6 | ||
|
|
73dd39905e | ||
|
|
2e843f65ed | ||
|
|
b18ddc6407 | ||
|
|
2359dd7f56 | ||
|
|
060e86d7ff | ||
|
|
3995e792fe | ||
|
|
68391e5163 | ||
|
|
cce4475577 | ||
|
|
73c8b1aa33 | ||
|
|
b8d0b47a9d | ||
|
|
0684ff13cc | ||
|
|
1b28cd0e82 | ||
|
|
09e8e64a2f | ||
|
|
b166d3cef9 | ||
|
|
06c3ba0b8f | ||
|
|
ba7c39be74 | ||
|
|
a844244450 | ||
|
|
bd6f9b7a1d | ||
|
|
6b87016cb3 | ||
|
|
e632a3c665 | ||
|
|
d2b25441c3 | ||
|
|
41cca8e68d | ||
|
|
ca3394a2fc | ||
|
|
daeb61e858 | ||
|
|
c39ff3f3e2 | ||
|
|
f4a045b476 | ||
|
|
d7f8429d91 | ||
|
|
d4c16b7d04 | ||
|
|
e4f8506d24 | ||
|
|
4f82b5cb0d | ||
|
|
8298434f80 | ||
|
|
7336936fca | ||
|
|
5692006d19 | ||
|
|
9cd82dcd2e | ||
|
|
e6f011b641 | ||
|
|
70f7f0d938 | ||
|
|
3f5389cf29 | ||
|
|
c126920f25 | ||
|
|
8c1521be71 | ||
|
|
3c00fcaf80 | ||
|
|
53f7353fa3 | ||
|
|
446e8b12c5 | ||
|
|
78a5320df4 | ||
|
|
1a3b206398 | ||
|
|
1014934604 | ||
|
|
dd92b3b6d5 | ||
|
|
f9f2f6425c | ||
|
|
1a7f133773 | ||
|
|
179882543a | ||
|
|
45988df24a | ||
|
|
a0135b5942 | ||
|
|
9a8376bd93 | ||
|
|
b8af6e1447 | ||
|
|
a42f853c00 | ||
|
|
581013b1b3 | ||
|
|
4181c1e3f7 | ||
|
|
c6bd787700 | ||
|
|
fd8128599c | ||
|
|
c324ed9618 | ||
|
|
cc7227d164 | ||
|
|
c75e7fb76c | ||
|
|
6d3eb20ff1 | ||
|
|
a603e4eeac | ||
|
|
ac260925dd | ||
|
|
1a2e7ac23f | ||
|
|
1eb9b88f4b | ||
|
|
a7814f383a | ||
|
|
54e6d47df0 | ||
|
|
55ea1cf121 | ||
|
|
a2982f3406 | ||
|
|
633ff1fea8 | ||
|
|
3312df0743 | ||
|
|
0722bb8133 | ||
|
|
c9be4d95d7 | ||
|
|
023ddcec39 | ||
|
|
9255643646 | ||
|
|
36ead43102 | ||
|
|
f61d000326 | ||
|
|
9bb254dc48 | ||
|
|
5023ed46f5 | ||
|
|
73616e5084 | ||
|
|
f7bbe2e446 | ||
|
|
94c3011435 | ||
|
|
b348def6f6 | ||
|
|
d57c59e9eb | ||
|
|
3ed25c221e | ||
|
|
e0895d00ae | ||
|
|
9e5cce2f6f | ||
|
|
200c2631cb | ||
|
|
272204263d | ||
|
|
16b5472024 | ||
|
|
d6a4350e1e | ||
|
|
3602fbb807 | ||
|
|
ecce315924 | ||
|
|
eee470dad5 | ||
|
|
636c4bcafe | ||
|
|
4eb2b293e2 | ||
|
|
08528d9a88 | ||
|
|
3e9ef99226 | ||
|
|
f50ecd95c3 | ||
|
|
8b477a0e16 | ||
|
|
78891a1065 | ||
|
|
b428cb7eed | ||
|
|
b20c1bed5a | ||
|
|
f24c41eace | ||
|
|
d33cf5ddd5 | ||
|
|
41491079be | ||
|
|
5345c63672 | ||
|
|
06acf09a85 | ||
|
|
ce6d983b38 | ||
|
|
bb6c0b54ff | ||
|
|
571dae52d3 | ||
|
|
e6b5b0d125 | ||
|
|
8a1cf72095 | ||
|
|
f02425dcac | ||
|
|
6e3cf60eab | ||
|
|
32fdbf9dc2 | ||
|
|
1aed684ebe | ||
|
|
1ad791d9bc | ||
|
|
bb9925024d | ||
|
|
e676255d69 | ||
|
|
691c60be24 | ||
|
|
f4a458061a | ||
|
|
c88c898f4a | ||
|
|
d2da408a59 | ||
|
|
3b9a6404c5 | ||
|
|
d9306922c3 | ||
|
|
578cc7a99c | ||
|
|
aa9f9ba91f | ||
|
|
b9251d4f1d | ||
|
|
13a980afed | ||
|
|
c911e0118f | ||
|
|
eca02a5941 | ||
|
|
9a57db43f2 | ||
|
|
f6b65ac3e9 | ||
|
|
929348b390 | ||
|
|
57f1b9f8da | ||
|
|
fed106c811 | ||
|
|
739e919a43 | ||
|
|
e85cf4e196 | ||
|
|
0c42353fce | ||
|
|
7ebdec7713 | ||
|
|
1917dad8cd | ||
|
|
3100e2d70f | ||
|
|
7712cd49b6 | ||
|
|
856573763e | ||
|
|
3bbff7f8d5 | ||
|
|
034927ada0 | ||
|
|
0cccdad13f | ||
|
|
fe7f3f58c5 | ||
|
|
48fd854944 | ||
|
|
8f9746393f | ||
|
|
23da271b73 | ||
|
|
627775c6c3 | ||
|
|
59db43c3f0 | ||
|
|
597ee4f70e | ||
|
|
8222d8c146 | ||
|
|
f785d756be |
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules/
|
||||
.github/
|
||||
docs/
|
||||
images/
|
||||
7
.eslintrc.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": ["@excalidraw/eslint-config"],
|
||||
"rules": {
|
||||
"import/no-anonymous-default-export": "off",
|
||||
"no-restricted-globals": "off"
|
||||
}
|
||||
}
|
||||
68
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,38 +1,30 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help me improve Excalidraw
|
||||
title: 'BUG: '
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Your environment**
|
||||
Please run `Command Palette/Show Debug info` in Obsidian and paste the result here.
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
40
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: 'FR: '
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
|
||||
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '38 14 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# 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@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
5
.gitignore
vendored
@@ -12,3 +12,8 @@ main.js
|
||||
stats.html
|
||||
hot-reload.bat
|
||||
data.json
|
||||
lib
|
||||
|
||||
#VSCode
|
||||
.vscode
|
||||
yarn.lock
|
||||
|
||||
@@ -6,7 +6,7 @@ With a little work, using Excalidraw Automate you can generate simple mindmaps,
|
||||
|
||||
You can access Excalidraw Automate via the ExcalidrawAutomate object. I recommend starting your Automate scripts with the following code.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
const ea = ExcalidrawAutomate;
|
||||
ea.reset();
|
||||
@@ -27,7 +27,7 @@ You can change styling between adding different elements. My logic for separatin
|
||||
#### Create a new drawing with custom name, in a custom folder, using a template
|
||||
This simple script gives you significant additional flexibility over Excalidraw Plugin settings to name your drawings, place them into folders, and to apply templates.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -42,7 +42,7 @@ This simple script gives you significant additional flexibility over Excalidraw
|
||||
```
|
||||
|
||||
#### Create a simple drawing
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -63,7 +63,7 @@ The script will generate the following drawing:
|
||||
|
||||
## Attributes and functions at a glance
|
||||
Here's the interface implemented by ExcalidrawAutomate:
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
ExcalidrawAutomate: {
|
||||
style: {
|
||||
@@ -324,7 +324,7 @@ Returns a blob containing a PNG image of the generated drawing.
|
||||
### Insert new drawing into currently edited document
|
||||
This template will prompt you for the title of the drawing. It will create a new drawing with the provided title, and in the folder of the document you were editing. It will then transclude the new drawing at the cursor location and open the new drawing in a new workspace leaf by splitting the current leaf.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const defaultTitle = tp.date.now("HHmm")+' '+tp.file.title;
|
||||
@@ -345,7 +345,7 @@ This template will prompt you for the title of the drawing. It will create a new
|
||||
```
|
||||
|
||||
### Connect objects
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -362,7 +362,7 @@ This template will prompt you for the title of the drawing. It will create a new
|
||||
### Using a template
|
||||
This example is similar to the first one, but rotated 90°, and using a template, plus specifying a filename and folder to save the drawing, and opening the new drawing in a new pane.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -402,7 +402,7 @@ Example input:
|
||||
|
||||
The script:
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const IDX = Object.freeze({"depth":0, "text":1, "parent":2, "size":3, "children": 4, "objectId":5});
|
||||
|
||||
317
README.md
@@ -1,90 +1,275 @@
|
||||
# Excalidraw
|
||||
|
||||
The Obsidian-Excalidraw plugin integrates [Excalidraw](https://excalidraw.com/), a feature rich sketching tool, into Obsidian. You can store and edit Excalidraw files in your vault, you can embed drawings into your documents, and you can link to documents and other drawings to/and from Excalidraw. For a showcase of Excalidraw features, please read my blog post [here](https://www.zsolt.blog/2021/03/showcasing-excalidraw.html) and/or watch the videos below.
|
||||
|
||||

|
||||
## Video Walkthrough
|
||||
|
||||
# Important notice to the 1.2.0 update
|
||||
<a href="https://youtu.be/o0exK-xFP3k" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/156931370-aa4d88de-c4a8-46cc-aeb2-dc09aa0bea39.jpg" width="300"/></a>
|
||||
|
||||
This version comes with tons of new features and possibilities.
|
||||
<details><summary>10 Part (slightly outdated) Video Walkthrough</summary>
|
||||
<a href="https://youtu.be/sY4FoflGaiM" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160304-7f211180-e17c-11eb-8363-c52723de1ffd.jpg" width="100" style="vertical-align: middle;"/> 1 Getting Started</a><br>
|
||||
<a href="https://youtu.be/Iy_oVTq12Gw" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160312-8a743d00-e17c-11eb-9fa2-490ef4cbd59e.jpg" width="100" style="vertical-align: middle;"/> 2 Basic shapes and features</a><br>
|
||||
<a href="https://youtu.be/QOL1KF7-kdc" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160323-96f89580-e17c-11eb-9bce-8eb1067a51bb.jpg" width="100" style="vertical-align: middle;"/> 3 Grouping elements</a><br>
|
||||
<a href="https://youtu.be/aSgcbfspvfo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160332-9f50d080-e17c-11eb-98e9-fec60fe147d9.jpg" width="100" style="vertical-align: middle;"/> 4 The stencil-library</a><br>
|
||||
<a href="https://youtu.be/MaJ5jJwBRWs" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160341-a546b180-e17c-11eb-9de8-d87fdc844c9c.jpg" width="100" style="vertical-align: middle;"/> 5 Embedding</a><br>
|
||||
<a href="https://youtu.be/MXzeCOEExNo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160346-aa0b6580-e17c-11eb-930b-4024807040d1.jpg" width="100" style="vertical-align: middle;"/> 6 Links</a><br>
|
||||
<a href="https://youtu.be/R0IAg0s-wQE" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160354-b2fc3700-e17c-11eb-81af-9e71e461f6dd.jpg" width="100" style="vertical-align: middle;"/> 7 Markdown</a><br>
|
||||
<a href="https://youtu.be/ibdS7ykwpW4" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160360-b8f21800-e17c-11eb-8bd8-79d4e3f6e92d.jpg" width="100" style="vertical-align: middle;"/> 8 Templates</a><br>
|
||||
<a href="https://youtu.be/VRZVujfVab0" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160367-bdb6cc00-e17c-11eb-92f1-6f59faea85fd.jpg" width="100" style="vertical-align: middle;"/> 9 Excalidraw Automate</a><br>
|
||||
<a href="https://youtu.be/D1iBYo1_jjc" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/125160374-c3141680-e17c-11eb-8cc2-dfaffd903d15.jpg" width="100" style="vertical-align: middle;"/> 10 Miscellaneous</a><br>
|
||||
</details>
|
||||
<details><summary>Embedding stuff into Excalidraw</summary>
|
||||
<a href="https://www.youtube.com/watch?v=_c_0zpBJ4Xc&" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/138607067-ccb62f92-48a4-4880-ac6e-68c1bf86ac2c.png" width="100" style="vertical-align: middle;"/> Image Elements</a><br>
|
||||
<a href="https://youtu.be/r08wk-58DPk" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/143732412-1c65227e-4381-406d-847a-b001ab3506ca.jpg" width="100" style="vertical-align: middle;"/> LaTex Demo</a><br>
|
||||
<a href="https://youtu.be/tsecSfnTMow" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/143732440-90bfa029-8615-462e-ada3-c903d71a82c9.jpg" width="100" style="vertical-align: middle;"/> Markdown embeds</a><br>
|
||||
<a href="https://youtu.be/K6qZkTz8GHs" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/143783906-15cee494-c6d5-4495-a2ca-74634e4e7355.jpg" width="100" style="vertical-align: middle;"/> Markdown embeds advanced features</a><br>
|
||||
<a href="https://youtu.be/Etskjw7a5zo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/156931461-0979b821-315a-41dd-86f1-31d169b7c127.jpg" width="100" style="vertical-align: middle;"/> Link to Elements, Vertical text alignment, Markdown Styling</a><br>
|
||||
</details>
|
||||
<details><summary>The Script Engine Store - Excalidraw Automation</summary>
|
||||
<a href="https://youtu.be/hePJcObHIso" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/145684531-8d9c2992-59ac-4ebc-804a-4cce1777ded2.jpg" width="100" style="vertical-align: middle;"/> Introducing the Script Engine</a><br>
|
||||
<a href="https://youtu.be/lzYdOQ6z8F0" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/147889174-6c306d0d-2d29-46cc-a53f-3f0013cf14de.jpg" width="100" style="vertical-align: middle;"/> Script Enginge Store</a><br>
|
||||
</details>
|
||||
<details><summary>Working with colors</summary>
|
||||
<a href="https://youtu.be/6PLGHBH9VZ4" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/194773147-5418a0ab-6be5-4eb0-a8e4-d6af21b1b483.png" width="100" style="vertical-align: middle;"/> Colors - Excalidraw Basics (Custom)</a><br>
|
||||
<a href="https://youtu.be/epYNx2FSf2w" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/194773211-9e871be7-0795-4dc7-947e-c6c275e690d0.png" width="100" style="vertical-align: middle;"/> Excalidraw color palettes (Custom)</a><br>
|
||||
<a href="https://youtu.be/Amhlv6r9WvM" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/194773268-400cfb1b-6bde-45e0-9e4b-91bbaa461cf0.png" width="100" style="vertical-align: middle;"/> "Artistic" Color Gradients</a><br>
|
||||
<a href="https://youtu.be/r9oB1SlK1GU" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/194773527-ef35c8b9-1a6d-4415-9c7e-b667fb17535d.png" width="100" style="vertical-align: middle;"/> Simple rules for beautiful sketches</a><br>
|
||||
<a href="https://youtu.be/7gJDwNgQ6NU" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/195988535-a133a9b9-d094-45ba-ba64-c994b9a1e0ef.png" width="100" style="vertical-align: middle;"/> ColorMaster Scripting</a><br>
|
||||
</details>
|
||||
<details><summary>Links and block references</summary>
|
||||
<a href="https://youtu.be/qiKuqMcNWgU" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/171635214-30533c45-94fa-436e-83a9-b2ec99f190e2.jpg" width="100" style="vertical-align: middle;"/> 6 strategies for linking your visual thoughts v4</a><br>
|
||||
<a href="https://youtu.be/yZQoJg2RCKI" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/185791706-3d9983ab-7cb1-4b27-a016-30c039d84e34.jpg" width="100" style="vertical-align: middle;"/> Block reference parts of images</a><br>
|
||||
<a href="https://youtu.be/Etskjw7a5zo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/156931461-0979b821-315a-41dd-86f1-31d169b7c127.jpg" width="100" style="vertical-align: middle;"/> Link to Elements, Vertical text alignment, Markdown Styling</a><br>
|
||||
<a href="https://youtu.be/2Y8OhkGiTHg" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/152585752-7eb0371f-0bab-40f6-a194-3b48e5811735.jpg" width="100" style="vertical-align: middle;"/> How to guide for the Excalidraw-native hyperlinks</a><br>
|
||||
</details>
|
||||
<details><summary>Powertools</summary>
|
||||
<a href="https://youtu.be/NOuddK6xrr8" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/147283367-e5689385-ea51-4983-81a3-04d810d39f62.jpg" width="100" style="vertical-align: middle;"/> Sticky Notes (word wrapping)</a><br>
|
||||
<a href="https://youtu.be/eKFmrSQhFA4" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/149659524-2a4e0a24-40c9-4e66-a6b1-c92f3b88ecd5.jpg" width="100" style="vertical-align: middle;"/> Fourt Font</a><br>
|
||||
<a href="https://youtu.be/vlC1-iBvIfo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/199207784-8bbe14e0-7d10-47d7-971d-20dce8dbd659.png" width="100" style="vertical-align: middle;"/> SVG import</a><br>
|
||||
<a href="https://youtu.be/7gu4ETx7zro" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/202916770-28f2fa64-1ba2-4b40-a7fe-d721b42634f7.png" width="100" style="vertical-align: middle;"/> OCR</a><br>
|
||||
<a href="https://youtu.be/U2LkBRBk4LY" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/159369910-6371f08d-b5fa-454d-9c6c-948f7e7a7d26.jpg" width="100" style="vertical-align: middle;"/> Bind/unbind text from container, Frontmatter tags to customize export</a><br>
|
||||
</details>
|
||||
<details><summary>Quality of life improvements</summary>
|
||||
<a href="https://youtu.be/qbPIAZguJeo" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/151705333-54e9ffd2-0bd7-4d02-b99e-0bd4e4708d4d.jpg" width="100" style="vertical-align: middle;"/> Mobile Support</a><br>
|
||||
<a href="https://youtu.be/2v9TZmQNO8c" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/153676009-6f86b2d7-c248-49a2-b802-be21c6999e4f.jpg" width="100" style="vertical-align: middle;"/> Tray-mode and Customizable Color Palette</a><br>
|
||||
<a href="https://youtu.be/xHPGWR3m0c8" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/154821232-a404b6cf-72fb-4ce4-9d53-619132dce491.jpg" width="100" style="vertical-align: middle;"/> Compressed JSON and improved save/sync support</a><br>
|
||||
<a href="https://youtu.be/gMIKXyhS-dM" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/156931428-b2269fd9-87bd-43ab-8558-5572f40dff93.jpg" width="100" style="vertical-align: middle;"/> The Obsidian Tools Panel</a><br>
|
||||
<a href="https://youtu.be/4N6efq1DtH0" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/158008902-12c6a851-237e-4edd-a631-d48e81c904b2.jpg" width="100" style="vertical-align: middle;"/> Eraser, left-handed mode, improved filename configuration</a><br>
|
||||
</details>
|
||||
|
||||
Drawings you've created with version 1.1.x need to be converted to take advantage of the new features. If you want, you can also continue to use your exisiting drawings in compatibility mode (e.g. if you use Logseq and Obsidian in parallel). During conversion your existing `*.excalidraw` files will be replaced with new `*.excalidraw.md` files.
|
||||
---
|
||||
|
||||
## Conversion and compatibility
|
||||
To convert files you have the following options:
|
||||
- Click `CONVERT FILES` in the migration dialog when installing 1.2.0
|
||||
- In the Command Palette select `Excalidraw: Convert *.excalidraw files to *.excalidraw.md files` to convert all `*.excalidraw` files to `*.excalidraw.md` files.
|
||||
- To convert files individually:
|
||||
- Right click an `*.excalidraw` file in File Explorer and select one of the following options:
|
||||
- `*.excalidraw => *.excalidraw.md`
|
||||
- `*.excalidraw => *.md (Logseq compatibility)`: This option will retain the original *.excalidraw file next to the new Obsidian format. Make sure you also enable additional `Compatibility features` in `Settings` for a full solution.
|
||||
- Open a legacy `*.excalidraw` file and select `Convert to new format` from the `Options Menu` in the Excalidraw view.
|
||||
## Features
|
||||
|
||||
# Video walkthrough
|
||||
| | | |
|
||||
|----|----|----|
|
||||
|[](https://youtu.be/UxJLLYtgDKE)|[](https://youtu.be/sY4FoflGaiM)|[](https://youtu.be/Iy_oVTq12Gw)|
|
||||
|[](https://youtu.be/QOL1KF7-kdc)|[](https://youtu.be/aSgcbfspvfo)|[](https://youtu.be/MaJ5jJwBRWs)|
|
||||
|[](https://youtu.be/MXzeCOEExNo)|[](https://youtu.be/R0IAg0s-wQE)|[](https://youtu.be/ibdS7ykwpW4)|
|
||||
|[](https://youtu.be/VRZVujfVab0)|[](https://youtu.be/D1iBYo1_jjc)||
|
||||
- The plugin integrates Excalidraw seamlessly into Obsidian including Command Palette actions, File
|
||||
Explorer features, Option Menu commands, and the Ribbon Button.
|
||||
- <kbd>CTRL/CMD+Click</kbd> on the ribbon button, or in the file explorer to create / open drawings
|
||||
in a new pane.
|
||||
|
||||
# Key features
|
||||
- The plugin aims to integrate Excalidraw seemlessly into Obsidian including Command Palette actions, File Explorer features, Option Menu commands, and the Ribbon Button.
|
||||
- CTRL+Click on the ribbon button, or in the file explorer to create / open drawings in a new pane.
|
||||
- Settings will allow you to customzie Excalidraw to your needs:
|
||||
- Default folder for new drawings and define custom filename pattern for new drawings.
|
||||
- Template for new drawings. The template will restore stroke properties. This means you can set up defaults in your template for stroke color, stroke width, opacity, font family, font size, fill style, stroke style, etc. This also applies to ExcalidrawAutomate.
|
||||
- If portability is important to you: Auto-export SVG and/or PNG files including keep-in-sync feature so you can embed svg/png into your documents instead of embedding excalidraw files.
|
||||
- Specify the default width of embedded drawings.
|
||||
- Compatibility features to auto-export and keep in sync markdown excalidraw files and legacy .excalidraw files.
|
||||
- Experimental feature to add custom TAG to file expolorer to mark drawing files.
|
||||
- Enable / disable autosave.
|
||||
- You can customize the size and position of the embedded images using the `[[image.excalidraw|100]]`, `[[image.excalidraw|100x100]]`, `[[image.excalidraw|100|left]]`, `[[image.excalidraw|right-wrap]]`, formatting options. `[[<filename.excalidraw>|<width>x<height>|<alignment>]]`. You can add your custom alignment via css. Any text that appears in `<alignment>` will be added to the rendered SVG element style and to the wrapper DIV element. Check below and styles.css for more insight.
|
||||
- Supports hyperlinks e.g. `https://zsolt.blog`, `[Obsidian](https://obsidian.md)`, and internal links e.g. `[[My file in vault|Alias]]` in drawing text.
|
||||
- Links will update when files are moved or renamed, if you have the Obsidian setting Files & Links/Automatically Update Internal Links enalbled.
|
||||
- Links in drawings will show up in backlinks of documents
|
||||
- Transclusions are supported
|
||||
### Settings
|
||||
|
||||
Settings will allow you to customize Excalidraw to your needs:
|
||||
|
||||
- Default folder for new drawings and define custom filename pattern for new drawings.
|
||||
|
||||
#### Templates
|
||||
|
||||
- Template for new drawings. The template will restore stroke properties.
|
||||
This means you can set up defaults in your template for stroke color, stroke width,
|
||||
opacity, font family, font size, fill style, stroke style, etc.
|
||||
This also applies to ExcalidrawAutomate.
|
||||
- Via the template you can customize the color palette used by Excalidraw.
|
||||
- Switch to Markdown view.
|
||||
- Scroll down to the bottom of the file and find `"AppState": {`.
|
||||
- Find `"customColorPalette": {` at the end of the AppState section.
|
||||
- You may specify the 3 palettes used in Excalidraw by adding any or all of the following 3 variables:
|
||||
- `"canvasBackground":[], "elementBackground":[], "elementStroke": []`.
|
||||
- Add a comma separated list of valid HTML colors (e.g. `#FF0000` for red)
|
||||
in the array for each of the variables.
|
||||
- See my videos above for further help.
|
||||
|
||||
#### Export
|
||||
|
||||
- If portability is important to you:
|
||||
- Auto-export SVG and/or PNG files including keep-in-sync feature so you can
|
||||
embed SVG/PNG into your documents instead of embedding excalidraw files.
|
||||
- You can override export settings for an individual file by adding the `excalidraw-autoexport`
|
||||
frontmatter key. Valid values for this key are `none`, `both`, `png` and `svg`.
|
||||
|
||||
- Specify the default width of embedded drawings.
|
||||
- Compatibility features to auto-export and keep in sync markdown excalidraw files and legacy `.excalidraw` files.
|
||||
- Experimental feature to add custom TAG to file explorer to mark drawing files.
|
||||
- Enable / disable autosave.
|
||||
|
||||
### Embedded images
|
||||
|
||||
- You can customize the size and position of the embedded images using the
|
||||
- `![[image.excalidraw|100]]`,
|
||||
- `![[image.excalidraw|100x100]]`,
|
||||
- `![[image.excalidraw|100|left]]`,
|
||||
- `![[image.excalidraw|right-wrap]]`, formatting options.
|
||||
- `![[<filename.excalidraw>|<width>x<height>|<alignment>]]`.
|
||||
- You can add your custom [alignment via CSS](https://www.scaler.com/topics/align-image-in-html/).
|
||||
- Any text that appears in `<alignment>` will be added to the rendered SVG element style and to the wrapper DIV element.
|
||||
- See [styles.css](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/styles.css) for more insight.
|
||||
|
||||
### Hyperlinks
|
||||
|
||||
- Supports hyperlinks e.g.
|
||||
- `https://zsolt.blog`,
|
||||
- `[Obsidian](https://obsidian.md)`, and
|
||||
- internal links e.g. `[[My file in vault|Alias]]` in drawing text.
|
||||
- Links will update when files are moved or renamed, if you have the Obsidian
|
||||
setting Files & Links/Automatically Update Internal Links enabled.
|
||||
- Links in drawings will show up in backlinks of documents
|
||||
- Transclusions are supported
|
||||
- `![[myfile#^blockref]]` will convert in the drawing into the transcluded text of the block
|
||||
- `![[myfile#section]]` also works, this will transclude the section
|
||||
- you can also specify word wrapping for transcluded text by adding the max character count in curly brackets right after the transclusion e.g. `![[myfile#^blockref]]{40}` will wrap text at 40 characters.
|
||||
- For convenience you can also use the command palette to insert links into drawings
|
||||
- CTRL/META + hover to bring up the Obsidian quick preview for the link. (On Mac it is CTRL+CMD+hover).
|
||||
- CTRL/META + CLICK a text element to open it as a link.
|
||||
- CTRL/META + ALT + CLICK to create the file (if it does not yet exist) and open it
|
||||
- CTRL/META + SHIFT + CLICK to open the file in a new pane
|
||||
- CTRL/META + ALT + SHIFT + CLICK to create the file (if it does not yet exist) and open it in a new pane
|
||||
- you can also specify word wrapping for transcluded text by adding the max character count
|
||||
in curly brackets right after the transclusion e.g. `![[myfile#^blockref]]{40}` will wrap text at 40 characters.
|
||||
- For convenience you can also use the command palette to insert links into drawings
|
||||
- <kbd>CTRL/CMD + hover</kbd> to bring up the Obsidian quick preview for the link. (On Mac it is <kbd>CTRL+CMD+hover</kbd>).
|
||||
- <kbd>CTRL/CMD + CLICK</kbd> a text element to open it as a link.
|
||||
- <kbd>CTRL/CMD + ALT + CLICK</kbd> to create the file (if it does not yet exist) and open it
|
||||
- <kbd>CTRL/CMD + SHIFT + CLICK</kbd> to open the file in a new pane
|
||||
- <kbd>CTRL/CMD + ALT + SHIFT + CLICK</kbd> to create the file (if it does not yet exist) and open it in a new pane
|
||||
- Using the block reference you can also reference & transclude text that appears on drawings, in other documents
|
||||
- Insert LaTex symbols and simple formulas using the Command Palette action "Insert LaTeX-symbol". Some symbols may not display properly using the "Hand-drawn" font. If that is the case try using the "Normal" or "Code" fonts.
|
||||
|
||||
### LaTeX
|
||||
|
||||
Insert LaTeX formulas using the Command Palette action "Insert LaTeX formula".
|
||||
You can edit formulas either in Markdown view, or by <kbd>CTRL/CMD + Click</kbd> on the formula.
|
||||
|
||||
### Drag & Drop support
|
||||
|
||||
- You can drag files from the Obsidian file explorer and they will become links to those files in Excalidraw.
|
||||
- Dragging image files (PNG, SVG, JPG, ICO, GIF, WEBP, Excalidraw) from Obsidian's file explorer while pressing the
|
||||
<kbd>CTRL</kbd> (<kbd>SHIFT</kbd> on Mac) button will embed the image into your drawing.
|
||||
- If in addition to <kbd>CTRL</kbd> or <kbd>SHIFT</kbd> you also hold down <kbd>ALT</kbd>,
|
||||
the image will be inserted at 100% of its size.
|
||||
- Note: this is a very niche feature with a very particular behavior that I built primarily for myself
|
||||
- (even more so than other features in Excalidraw Obsidian - also built primarily for myself 😉).
|
||||
- This will reset your embedded image to 100% size every time you open the Excalidraw drawing,
|
||||
or in case you have embedded an Excalidraw drawing on your canvas inserted using this function,
|
||||
every time you update the embedded drawing, it will be scaled back to 100% size.
|
||||
- This means that even if you resize the image on the drawing, it will reset to 100% the next time you open
|
||||
the file or you modify the original embedded object. This feature is useful when you
|
||||
decompose a drawing into separate Excalidraw files, but when combined onto a single canvas
|
||||
you want the individual pieces to maintain their actual sizes. I use this feature to
|
||||
construct Book-on-a-Page summaries from atomic drawings.
|
||||
- You can drag and drop text from Markdown views onto Excalidraw.
|
||||
- You can drag and drop web addresses from your browser and they will become links.
|
||||
|
||||
### Image support
|
||||
|
||||
- On iOS and Android you can add images from your camera by pressing the add image button in Excalidraw.
|
||||
- You can copy/paste images into your drawing. Images will be saved in your vault.
|
||||
- You can drag and drop images as explained above.
|
||||
|
||||
### Block referencing parts of images
|
||||
|
||||
- When referencing an element on the canvas in a link pointing to an Excalidraw file using
|
||||
- the elementId or the section header (i.e. a Text Element containing the `# <Section title>`)
|
||||
- e.g. `[[file#^elementID]]`,
|
||||
- you can add the `group=` prefix,
|
||||
- e.g. `[[file#^group=elementID]]` or
|
||||
- the `area=` prefix,
|
||||
- e.g. `[[file#area=Section heading]]`.
|
||||
- If the `group=` prefix is found Excalidraw will select the group of elements in the
|
||||
same group as the element referenced by the elementID (block reference) or the section heading.
|
||||
- If the `area=` prefix is found Excalidraw will insert a cutout of the image around the referenced element.
|
||||
- Note that the `area=` selector is not supported when embedding Excalidraw as PNG into your markdown documents.
|
||||
- Referencing the elementID of a text element without the `group=` or `area=` prefix will
|
||||
transclude the element as plain text. Referencing a non-Text Element (e.g. rectangle,
|
||||
ellipse, etc.) without the `group=` or `area=` prefix will result in an Obsidian error
|
||||
since these elementIds are not present in the Excalidraw markdown file as block
|
||||
references.
|
||||
|
||||
### Markdown
|
||||
|
||||
- Since 1.2.0 Drawing files are stored in Markdown files
|
||||
- You can add tags to drawings
|
||||
- You can add metadata to the YAML front matter of drawings
|
||||
- Anything you add between the frontmatter and the `# Text Elements` heading will be ignored by Excalidraw, i.e. you can add whatever you like here, it will be preserved as part of the document.
|
||||
- Excalidraw documents now show in graph view.
|
||||
- The following front matter keys will customize how the drawing is displayed - overriding general settings:
|
||||
- `excalidraw-link-prefix: "📍"` preview prefix for internal links
|
||||
- `excalidraw-url-prefix: "🌐"` preview prefix for external links
|
||||
- `excalidraw-link-brackets: true|false` whether or not to display brackets around links in preview
|
||||
- Includes full [Templater](https://silentvoid13.github.io/Templater/) and [Dataview](https://blacksmithgu.github.io/obsidian-dataview/docs/api/intro/) support through ExcalidrawAutomate. Check out the [detailed help + examples](https://zsviczian.github.io/obsidian-excalidraw-plugin/)
|
||||
- You can add tags to drawings
|
||||
- You can add metadata to the YAML front matter of drawings
|
||||
- Anything you add between the frontmatter and the `# Text Elements` heading will be ignored by Excalidraw, i.e. you can add whatever you like here, it will be preserved as part of the document.
|
||||
- Excalidraw documents now show in graph view.
|
||||
- The following front matter keys will customize how the drawing is displayed - overriding general settings:
|
||||
- `excalidraw-link-prefix: "📍"` preview prefix for internal links
|
||||
- `excalidraw-url-prefix: "🌐"` preview prefix for external links
|
||||
- `excalidraw-link-brackets: true|false` whether or not to display brackets around links in preview
|
||||
- `excalidraw-default-mode: view|zen` Open this document in view mode or zen mode by defult. Default view mode is excellent for presentation slides.
|
||||
- Frontmatter tags to customize image export at a file level [519](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/519). If these keys are present they will override the default excalidraw embed and export settings.
|
||||
- `excalidraw-export-transparent: true`: true == Transparent / false == with background.
|
||||
- `excalidraw-export-dark`: true == Dark mode / false == light mode.
|
||||
- `excalidraw-export-padding`: Specify the export padding for the image
|
||||
- `excalidraw-export-pngscale`: This only affects export to PNG. Specify the export scale for the image. The typical range is between 0.5 and 5, but you can experiment with other values as well.
|
||||
|
||||
### Embed complete markdown files into your drawings
|
||||
|
||||
- Drag from the desired file from the Obsidian file explorer and hold down <kbd>CTRL/CMD</kbd> while dropping the file onto the canvas.
|
||||
- Use the command palette action: `Insert markdown file from vault`
|
||||
- Use custom woff, woff2 or TTF font to display the document, you can set the default font to use under Excalidraw Settings.
|
||||
- You can set a custom css for rendering the snapshot image of your markdown document.
|
||||
Only operating system standard fonts are supported as the font-family (
|
||||
[Win10](https://docs.microsoft.com/en-us/typography/fonts/windows_10_font_list),
|
||||
[Mac & iOS](https://developer.apple.com/fonts/system-fonts/)
|
||||
), plus you can set one additional custom font using the setting explained above.
|
||||
- (for a demonstration watch this [video](https://youtu.be/K6qZkTz8GHs) and check out this
|
||||
- [sample css](https://github.com/zsviczian/obsidian-excalidraw-plugin/discussions/281)).
|
||||
- To help with styling you can observe the SVG snapshot of the markdown document created by Excalidraw.
|
||||
- Open Obsidian Developer Console (<kbd>CTRL+Shift+i</kbd>) and
|
||||
- execute the following command: `ExcalidrawAutomate.mostRecentMarkdownSVG`
|
||||
- You can control appearance of the embedded markdown file on a file by file
|
||||
bases by adding the following front matter keys to your markdown document:
|
||||
- `excalidraw-font: Virgil|Cascadia|font_file_name.extension`
|
||||
- `excalidraw-font-color: css-color-name|#HEXcolor|any-other-html-standard-format`,
|
||||
- you can find css color names [here](https://www.w3schools.com/colors/colors_names.asp).
|
||||
- `excalidraw-border-color: css-color-name|#HEXcolor|any-other-html-standard-format`
|
||||
- `excalidraw-css: "css-filename|css snippet"`
|
||||
- Switch to markdown view or use <kbd>CTRL/CMD+ALT/OPT</kbd> click on the image to edit properties of the embed:
|
||||
- `[[filename#^blockref|WIDTHxMAXHEIGHT]]`
|
||||
|
||||
### Other
|
||||
|
||||
- Includes full
|
||||
- [QuickAdd](https://github.com/chhoumann/quickadd),
|
||||
- [Templater](https://silentvoid13.github.io/Templater/) and
|
||||
- [Dataview](https://blacksmithgu.github.io/obsidian-dataview/docs/api/intro/) support through ExcalidrawAutomate.
|
||||
- Check out the [detailed help + examples](https://zsviczian.github.io/obsidian-excalidraw-plugin/).
|
||||
- I also have a [YouTube ExcalidrawAutomate Playlist](https://www.youtube.com/playlist?list=PL6mqgtMZ4NP1IR4nXxSlMA4PA5E-qpyHZ) with lots of examples.
|
||||
- Since 1.5.0 you can easily execute ExcalidrawAutomate macros and assign command palette
|
||||
shortcuts to them, using the ScriptEngine. You will find an intro video and a growing library
|
||||
of ready to install scripts
|
||||
[here](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/ea-scripts).
|
||||
- REQUIRES AN OBSIDIAN SYNC SUBSCRIPTION: Full drawing file history and synchronization between devices
|
||||
- Multilanguage support: if you'd like to help out by translating the plugin, please get in contact with me.
|
||||
|
||||
# Known issues
|
||||
- Mobile support
|
||||
- Positioning of the pen gets misaligned after you open the command palette.
|
||||
- Partially mitigated in 1.0.10 by the introduction of autosave: Your drawing will not be saved when you terminate the mobile app by closing the Obsidian task.
|
||||
---
|
||||
|
||||
# Tips and tricks
|
||||
- If you want to sketch in fullscreen, I recommend installing the [Fullscreen Focus Mode](https://github.com/razumihin/obsidian-fullscreen-plugin) plugin.
|
||||
- [Ozan's Image in Editor Plugin](https://github.com/ozntel/oz-image-in-editor-obsidian). In a nice collaboration with Ozan, his Image-in-Editor plugin now supports Excalidraw. I recommend installing his plugin to display drawings also in Edit mode. Note that Ozan's plugin will only display Excalidraw drawings if the link ends with `.md` or `.excalidraw`. i.e. the following drawing will show in Edit Mode `![[My Drawing.md]]`, but wiki links such as `[[My Drawing]]` will not.
|
||||
## Feedback, questions, ideas, problems
|
||||
|
||||
# Feedback, questions, ideas, problems
|
||||
Join the conversation about the Excalidraw plugin on [forum.obsidian.md](https://forum.obsidian.md/t/excalidraw-full-featured-sketching-plugin-in-obsidian)
|
||||
Join the conversation about the Excalidraw plugin on
|
||||
[forum.obsidian.md](https://forum.obsidian.md/t/excalidraw-full-featured-sketching-plugin-in-obsidian)
|
||||
|
||||
Please head over to [GitHub](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues) to report a bug or request an enhancement.
|
||||
Please head over to [GitHub](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues) to
|
||||
report a bug or request an enhancement.
|
||||
|
||||
# Say Thank You
|
||||
If you are enjoying Excalidraw then please support my work and enthusiasm by buying me a coffee on [https://ko-fi/zsolt](https://ko-fi.com/zsolt).
|
||||
---
|
||||
|
||||
Please also help spread the word by sharing about the Obsidian Excalidraw Plugin on Twitter, Reddit, or any other social media platform you regularly use.
|
||||
## Say Thank You
|
||||
|
||||
If you are enjoying Excalidraw then please support my work and enthusiasm by buying me a coffee on
|
||||
[https://ko-fi/zsolt](https://ko-fi.com/zsolt).
|
||||
|
||||
Please also help spread the word by sharing about the Obsidian Excalidraw Plugin on Twitter, Reddit,
|
||||
or any other social media platform you regularly use.
|
||||
|
||||
You can find me on Twitter [@zsviczian](https://twitter.com/zsviczian), and on my blog [zsolt.blog](https://zsolt.blog).
|
||||
|
||||
[<img style="float:left" src="https://user-images.githubusercontent.com/14358394/115450238-f39e8100-a21b-11eb-89d0-fa4b82cdbce8.png" width="200">](https://ko-fi.com/zsolt)
|
||||
|
||||
---
|
||||
|
||||
## Friends of Excalidraw
|
||||
If you enjoy Excalidraw, consider giving [ExcaliBrain](https://github.com/zsviczian/excalibrain) a try (also available via Obsidian Community Plugins).
|
||||
|
||||
<a href="https://youtu.be/gOkniMkDPyM" target="_blank"><img src="https://user-images.githubusercontent.com/14358394/169708346-9e41289d-9536-43ec-8f70-2d2ad2d369d6.png" width="300"/></a>
|
||||
14
TODO.md
Normal file
@@ -0,0 +1,14 @@
|
||||
[x] do not embed font into SVG when embedding Excalidraw into other Excalidraw
|
||||
[x] add ```html <SVG>...</SVG> ``` codeblock to excalidraw markdown
|
||||
[x] read pre-saved `<SVG>` when generating image preview
|
||||
[x] update code to adopt change files moving from AppState to App
|
||||
- Add "files" to legacy excalidraw export
|
||||
|
||||
[x] PNG preview
|
||||
[x] markdown embed SVG 190
|
||||
[x] markdown embed PNG
|
||||
[x] embed Excalidraw into other Excalidraw
|
||||
|
||||
|
||||
|
||||
|
||||
36
dev.postprocess.config.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import fs from'fs';
|
||||
import LZString from 'lz-string';
|
||||
|
||||
const excalidraw_pkg = isProd
|
||||
? fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.production.min.js", "utf8")
|
||||
: fs.readFileSync("./node_modules/@zsviczian/excalidraw/dist/excalidraw.development.js", "utf8");
|
||||
const react_pkg = isProd
|
||||
? fs.readFileSync("./node_modules/react/umd/react.production.min.js", "utf8")
|
||||
: fs.readFileSync("./node_modules/react/umd/react.development.js", "utf8");
|
||||
const reactdom_pkg = isProd
|
||||
? fs.readFileSync("./node_modules/react-dom/umd/react-dom.production.min.js", "utf8")
|
||||
: fs.readFileSync("./node_modules/react-dom/umd/react-dom.development.js", "utf8");
|
||||
const lzstring_pkg = fs.readFileSync("./node_modules/lz-string/libs/lz-string.min.js", "utf8")
|
||||
|
||||
const packageString = lzstring_pkg+'const EXCALIDRAW_PACKAGES = "' + LZString.compressToBase64(react_pkg + reactdom_pkg + excalidraw_pkg) +'";var ExcalidrawPackageLoader=(d=document)=>{const excalidraw_id = "excalidraw-script";if(!d.getElementById(excalidraw_id)){const script=d.createElement("script");script.type="text/javascript";script.id=excalidraw_id;script.text=LZString.decompressFromBase64(EXCALIDRAW_PACKAGES);d.body.appendChild(script);}};ExcalidrawPackageLoader();';
|
||||
|
||||
const mainjs = fs.readFileSync("main.js", "utf8")
|
||||
|
||||
|
||||
fs.writeFileSync(
|
||||
"main2.js",
|
||||
mainjs
|
||||
.replace('(require("react"));','')
|
||||
.replace('"use strict";','"use strict";' + packageString),
|
||||
{
|
||||
encoding: "utf8",
|
||||
flag: "w",
|
||||
mode: 0o666
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
let config = {
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -3,136 +3,549 @@
|
||||
Here's the interface implemented by ExcalidrawAutomate:
|
||||
|
||||
```typescript
|
||||
export interface ExcalidrawAutomate extends Window {
|
||||
ExcalidrawAutomate: {
|
||||
plugin: ExcalidrawPlugin;
|
||||
elementsDict: {};
|
||||
style: {
|
||||
strokeColor: string;
|
||||
backgroundColor: string;
|
||||
angle: number;
|
||||
fillStyle: FillStyle;
|
||||
strokeWidth: number;
|
||||
storkeStyle: StrokeStyle;
|
||||
roughness: number;
|
||||
opacity: number;
|
||||
strokeSharpness: StrokeSharpness;
|
||||
fontFamily: number;
|
||||
fontSize: number;
|
||||
textAlign: string;
|
||||
verticalAlign: string;
|
||||
startArrowHead: string;
|
||||
endArrowHead: string;
|
||||
}
|
||||
canvas: {
|
||||
theme: string,
|
||||
viewBackgroundColor: string,
|
||||
gridSize: number
|
||||
};
|
||||
setFillStyle (val:number): void;
|
||||
setStrokeStyle (val:number): void;
|
||||
setStrokeSharpness (val:number): void;
|
||||
setFontFamily (val:number): void;
|
||||
setTheme (val:number): void;
|
||||
addToGroup (objectIds:[]):string;
|
||||
toClipboard (templatePath?:string): void;
|
||||
getElements ():ExcalidrawElement[];
|
||||
getElement (id:string):ExcalidrawElement;
|
||||
create (
|
||||
params?: {
|
||||
filename?: string,
|
||||
foldername?:string,
|
||||
templatePath?:string,
|
||||
onNewPane?: boolean,
|
||||
frontmatterKeys?:{
|
||||
"excalidraw-plugin"?: "raw"|"parsed",
|
||||
"excalidraw-link-prefix"?: string,
|
||||
"excalidraw-link-brackets"?: boolean,
|
||||
"excalidraw-url-prefix"?: string
|
||||
}
|
||||
}
|
||||
):Promise<string>;
|
||||
createSVG (templatePath?:string):Promise<SVGSVGElement>;
|
||||
createPNG (templatePath?:string):Promise<any>;
|
||||
wrapText (text:string, lineLen:number):string;
|
||||
addRect (topX:number, topY:number, width:number, height:number):string;
|
||||
addDiamond (topX:number, topY:number, width:number, height:number):string;
|
||||
addEllipse (topX:number, topY:number, width:number, height:number):string;
|
||||
addBlob (topX:number, topY:number, width:number, height:number):string;
|
||||
addText (
|
||||
topX:number,
|
||||
topY:number,
|
||||
text:string,
|
||||
formatting?: {
|
||||
wrapAt?:number,
|
||||
width?:number,
|
||||
height?:number,
|
||||
textAlign?: string,
|
||||
box?: "box"|"blob"|"ellipse"|"diamond",
|
||||
boxPadding?: number
|
||||
},
|
||||
id?:string
|
||||
):string;
|
||||
addLine(points: [[x:number,y:number]]):string;
|
||||
addArrow (
|
||||
points: [[x:number,y:number]],
|
||||
formatting?: {
|
||||
startArrowHead?:string,
|
||||
endArrowHead?:string,
|
||||
startObjectId?:string,
|
||||
endObjectId?:string
|
||||
}
|
||||
):string ;
|
||||
connectObjects (
|
||||
objectA: string,
|
||||
connectionA: ConnectionPoint,
|
||||
objectB: string,
|
||||
connectionB: ConnectionPoint,
|
||||
formatting?: {
|
||||
numberOfPoints?: number,
|
||||
startArrowHead?:string,
|
||||
endArrowHead?:string,
|
||||
padding?: number
|
||||
}
|
||||
):void;
|
||||
clear (): void;
|
||||
reset (): void;
|
||||
isExcalidrawFile (f:TFile): boolean;
|
||||
//view manipulation
|
||||
targetView: ExcalidrawView;
|
||||
setView (view:ExcalidrawView|"first"|"active"):ExcalidrawView;
|
||||
getExcalidrawAPI ():any;
|
||||
getViewElements ():ExcalidrawElement[];
|
||||
deleteViewElements (el: ExcalidrawElement[]):boolean;
|
||||
getViewSelectedElement( ):ExcalidrawElement;
|
||||
getViewSelectedElements ():ExcalidrawElement[];
|
||||
viewToggleFullScreen (forceViewMode?:boolean):void;
|
||||
connectObjectWithViewSelectedElement (
|
||||
objectA:string,
|
||||
connectionA: ConnectionPoint,
|
||||
connectionB: ConnectionPoint,
|
||||
formatting?: {
|
||||
numberOfPoints?: number,
|
||||
startArrowHead?:string,
|
||||
endArrowHead?:string,
|
||||
padding?: number
|
||||
}
|
||||
):boolean;
|
||||
addElementsToView (repositionToCursor:boolean, save:boolean):Promise<boolean>;
|
||||
onDropHook (data: {
|
||||
ea: ExcalidrawAutomate,
|
||||
event: React.DragEvent<HTMLDivElement>,
|
||||
draggable: any, //Obsidian draggable object
|
||||
type: "file"|"text"|"unknown",
|
||||
payload: {
|
||||
files: TFile[], //TFile[] array of dropped files
|
||||
text: string, //string
|
||||
},
|
||||
excalidrawFile: TFile, //the file receiving the drop event
|
||||
view: ExcalidrawView, //the excalidraw view receiving the drop
|
||||
pointerPosition: {x:number, y:number} //the pointer position on canvas at the time of drop
|
||||
}):boolean;
|
||||
export declare class ExcalidrawAutomate implements ExcalidrawAutomateInterface {
|
||||
plugin: ExcalidrawPlugin;
|
||||
targetView: ExcalidrawView = null; //the view currently edited
|
||||
elementsDict: {[key:string]:any}; //contains the ExcalidrawElements currently edited in Automate indexed by el.id
|
||||
imagesDict: {[key: FileId]: any}; //the images files including DataURL, indexed by fileId
|
||||
mostRecentMarkdownSVG:SVGSVGElement = null; //Markdown renderer will drop a copy of the most recent SVG here for debugging purposes
|
||||
style: {
|
||||
strokeColor: string; //https://www.w3schools.com/colors/default.asp
|
||||
backgroundColor: string;
|
||||
angle: number; //radian
|
||||
fillStyle: FillStyle; //type FillStyle = "hachure" | "cross-hatch" | "solid"
|
||||
strokeWidth: number;
|
||||
strokeStyle: StrokeStyle; //type StrokeStyle = "solid" | "dashed" | "dotted"
|
||||
roughness: number;
|
||||
opacity: number;
|
||||
strokeSharpness: StrokeSharpness; //type StrokeSharpness = "round" | "sharp"
|
||||
fontFamily: number; //1: Virgil, 2:Helvetica, 3:Cascadia, 4:LocalFont
|
||||
fontSize: number;
|
||||
textAlign: string; //"left"|"right"|"center"
|
||||
verticalAlign: string; //"top"|"bottom"|"middle" :for future use, has no effect currently
|
||||
startArrowHead: string; //"triangle"|"dot"|"arrow"|"bar"|null
|
||||
endArrowHead: string;
|
||||
};
|
||||
}
|
||||
```
|
||||
canvas: {
|
||||
theme: string; //"dark"|"light"
|
||||
viewBackgroundColor: string;
|
||||
gridSize: number;
|
||||
};
|
||||
constructor(plugin: ExcalidrawPlugin, view?: ExcalidrawView);
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
getAPI(view?: ExcalidrawView): ExcalidrawAutomate;
|
||||
/**
|
||||
* @param val //0:"hachure", 1:"cross-hatch" 2:"solid"
|
||||
* @returns
|
||||
*/
|
||||
setFillStyle(val: number): "hachure" | "cross-hatch" | "solid";
|
||||
/**
|
||||
* @param val //0:"solid", 1:"dashed", 2:"dotted"
|
||||
* @returns
|
||||
*/
|
||||
setStrokeStyle(val: number): "solid" | "dashed" | "dotted";
|
||||
/**
|
||||
* @param val //0:"round", 1:"sharp"
|
||||
* @returns
|
||||
*/
|
||||
setStrokeSharpness(val: number): "round" | "sharp";
|
||||
/**
|
||||
* @param val //1: Virgil, 2:Helvetica, 3:Cascadia
|
||||
* @returns
|
||||
*/
|
||||
setFontFamily(val: number): "Virgil, Segoe UI Emoji" | "Helvetica, Segoe UI Emoji" | "Cascadia, Segoe UI Emoji" | "LocalFont";
|
||||
/**
|
||||
* @param val //0:"light", 1:"dark"
|
||||
* @returns
|
||||
*/
|
||||
setTheme(val: number): "light" | "dark";
|
||||
/**
|
||||
* @param objectIds
|
||||
* @returns
|
||||
*/
|
||||
addToGroup(objectIds: string[]): string;
|
||||
/**
|
||||
* @param templatePath
|
||||
*/
|
||||
toClipboard(templatePath?: string): Promise<void>;
|
||||
/**
|
||||
* get all elements from ExcalidrawAutomate elementsDict
|
||||
* @returns elements from elemenetsDict
|
||||
*/
|
||||
getElements(): ExcalidrawElement[];
|
||||
/**
|
||||
* get single element from ExcalidrawAutomate elementsDict
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
getElement(id: string): ExcalidrawElement;
|
||||
/**
|
||||
* create a drawing and save it to filename
|
||||
* @param params
|
||||
* filename: if null, default filename as defined in Excalidraw settings
|
||||
* foldername: if null, default folder as defined in Excalidraw settings
|
||||
* @returns
|
||||
*/
|
||||
create(params?: {
|
||||
filename?: string;
|
||||
foldername?: string;
|
||||
templatePath?: string;
|
||||
onNewPane?: boolean;
|
||||
frontmatterKeys?: {
|
||||
"excalidraw-plugin"?: "raw" | "parsed";
|
||||
"excalidraw-link-prefix"?: string;
|
||||
"excalidraw-link-brackets"?: boolean;
|
||||
"excalidraw-url-prefix"?: string;
|
||||
"excalidraw-export-transparent"?: boolean;
|
||||
"excalidraw-export-dark"?: boolean;
|
||||
"excalidraw-export-svgpadding"?: number;
|
||||
"excalidraw-export-pngscale"?: number;
|
||||
"excalidraw-default-mode"?: "view" | "zen";
|
||||
};
|
||||
}): Promise<string>;
|
||||
/**
|
||||
*
|
||||
* @param templatePath
|
||||
* @param embedFont
|
||||
* @param exportSettings use ExcalidrawAutomate.getExportSettings(boolean,boolean)
|
||||
* @param loader use ExcalidrawAutomate.getEmbeddedFilesLoader(boolean?)
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
createSVG(templatePath?: string, embedFont?: boolean, exportSettings?: ExportSettings, loader?: EmbeddedFilesLoader, theme?: string, padding?: number): Promise<SVGSVGElement>;
|
||||
/**
|
||||
*
|
||||
* @param templatePath
|
||||
* @param scale
|
||||
* @param exportSettings use ExcalidrawAutomate.getExportSettings(boolean,boolean)
|
||||
* @param loader use ExcalidrawAutomate.getEmbeddedFilesLoader(boolean?)
|
||||
* @param theme
|
||||
* @returns
|
||||
*/
|
||||
createPNG(templatePath?: string, scale?: number, exportSettings?: ExportSettings, loader?: EmbeddedFilesLoader, theme?: string, padding?: number): Promise<any>;
|
||||
/**
|
||||
*
|
||||
* @param text
|
||||
* @param lineLen
|
||||
* @returns
|
||||
*/
|
||||
wrapText(text: string, lineLen: number): string;
|
||||
private boxedElement;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param width
|
||||
* @param height
|
||||
* @returns
|
||||
*/
|
||||
addRect(topX: number, topY: number, width: number, height: number): string;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param width
|
||||
* @param height
|
||||
* @returns
|
||||
*/
|
||||
addDiamond(topX: number, topY: number, width: number, height: number): string;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param width
|
||||
* @param height
|
||||
* @returns
|
||||
*/
|
||||
addEllipse(topX: number, topY: number, width: number, height: number): string;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param width
|
||||
* @param height
|
||||
* @returns
|
||||
*/
|
||||
addBlob(topX: number, topY: number, width: number, height: number): string;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param text
|
||||
* @param formatting
|
||||
* box: if !null, text will be boxed
|
||||
* @param id
|
||||
* @returns
|
||||
*/
|
||||
addText(topX: number, topY: number, text: string, formatting?: {
|
||||
wrapAt?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
textAlign?: string;
|
||||
box?: boolean | "box" | "blob" | "ellipse" | "diamond";
|
||||
boxPadding?: number;
|
||||
}, id?: string): string;
|
||||
/**
|
||||
*
|
||||
* @param points
|
||||
* @returns
|
||||
*/
|
||||
addLine(points: [[x: number, y: number]]): string;
|
||||
/**
|
||||
*
|
||||
* @param points
|
||||
* @param formatting
|
||||
* @returns
|
||||
*/
|
||||
addArrow(points: [x: number, y: number][], formatting?: {
|
||||
startArrowHead?: string;
|
||||
endArrowHead?: string;
|
||||
startObjectId?: string;
|
||||
endObjectId?: string;
|
||||
}): string;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param imageFile
|
||||
* @returns
|
||||
*/
|
||||
addImage(topX: number, topY: number, imageFile: TFile): Promise<string>;
|
||||
/**
|
||||
*
|
||||
* @param topX
|
||||
* @param topY
|
||||
* @param tex
|
||||
* @returns
|
||||
*/
|
||||
addLaTex(topX: number, topY: number, tex: string): Promise<string>;
|
||||
/**
|
||||
*
|
||||
* @param objectA
|
||||
* @param connectionA type ConnectionPoint = "top" | "bottom" | "left" | "right" | null
|
||||
* @param objectB
|
||||
* @param connectionB when passed null, Excalidraw will automatically decide
|
||||
* @param formatting
|
||||
* numberOfPoints: points on the line. Default is 0 ie. line will only have a start and end point
|
||||
* startArrowHead: "triangle"|"dot"|"arrow"|"bar"|null
|
||||
* endArrowHead: "triangle"|"dot"|"arrow"|"bar"|null
|
||||
* padding:
|
||||
* @returns
|
||||
*/
|
||||
connectObjects(objectA: string, connectionA: ConnectionPoint | null, objectB: string, connectionB: ConnectionPoint | null, formatting?: {
|
||||
numberOfPoints?: number;
|
||||
startArrowHead?: "triangle" | "dot" | "arrow" | "bar" | null;
|
||||
endArrowHead?: "triangle" | "dot" | "arrow" | "bar" | null;
|
||||
padding?: number;
|
||||
}): string;
|
||||
/**
|
||||
* Adds a text label to a line or arrow. Currently only works with a straight (2 point - start & end - line)
|
||||
* @param lineId id of the line or arrow object in elementsDict
|
||||
* @param label the label text
|
||||
* @returns undefined (if unsuccessful) or the id of the new text element
|
||||
*/
|
||||
addLabelToLine(lineId: string, label: string): string;
|
||||
/**
|
||||
* clear elementsDict and imagesDict only
|
||||
*/
|
||||
clear(): void;
|
||||
/**
|
||||
* clear() + reset all style values to default
|
||||
*/
|
||||
reset(): void;
|
||||
/**
|
||||
* returns true if MD file is an Excalidraw file
|
||||
* @param f
|
||||
* @returns
|
||||
*/
|
||||
isExcalidrawFile(f: TFile): boolean;
|
||||
/**
|
||||
*
|
||||
* @param view
|
||||
* @returns
|
||||
*/
|
||||
setView(view: ExcalidrawView | "first" | "active"): ExcalidrawView;
|
||||
/**
|
||||
*
|
||||
* @returns https://github.com/excalidraw/excalidraw/tree/master/src/packages/excalidraw#ref
|
||||
*/
|
||||
getExcalidrawAPI(): any;
|
||||
/**
|
||||
* get elements in View
|
||||
* @returns
|
||||
*/
|
||||
getViewElements(): ExcalidrawElement[];
|
||||
/**
|
||||
*
|
||||
* @param elToDelete
|
||||
* @returns
|
||||
*/
|
||||
deleteViewElements(elToDelete: ExcalidrawElement[]): boolean;
|
||||
/**
|
||||
* get the selected element in the view, if more are selected, get the first
|
||||
* @returns
|
||||
*/
|
||||
getViewSelectedElement(): any;
|
||||
/**
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
getViewSelectedElements(): any[];
|
||||
/**
|
||||
*
|
||||
* @param el
|
||||
* @returns TFile file handle for the image element
|
||||
*/
|
||||
getViewFileForImageElement(el: ExcalidrawElement): TFile | null;
|
||||
/**
|
||||
* copies elements from view to elementsDict for editing
|
||||
* @param elements
|
||||
*/
|
||||
copyViewElementsToEAforEditing(elements: ExcalidrawElement[]): void;
|
||||
/**
|
||||
*
|
||||
* @param forceViewMode
|
||||
* @returns
|
||||
*/
|
||||
viewToggleFullScreen(forceViewMode?: boolean): void;
|
||||
/**
|
||||
* connect an object to the selected element in the view
|
||||
* @param objectA ID of the element
|
||||
* @param connectionA
|
||||
* @param connectionB
|
||||
* @param formatting
|
||||
* @returns
|
||||
*/
|
||||
connectObjectWithViewSelectedElement(objectA: string, connectionA: ConnectionPoint | null, connectionB: ConnectionPoint | null, formatting?: {
|
||||
numberOfPoints?: number;
|
||||
startArrowHead?: "triangle" | "dot" | "arrow" | "bar" | null;
|
||||
endArrowHead?: "triangle" | "dot" | "arrow" | "bar" | null;
|
||||
padding?: number;
|
||||
}): boolean;
|
||||
/**
|
||||
* Adds elements from elementsDict to the current view
|
||||
* @param repositionToCursor default is false
|
||||
* @param save default is true
|
||||
* @param newElementsOnTop controls whether elements created with ExcalidrawAutomate
|
||||
* are added at the bottom of the stack or the top of the stack of elements already in the view
|
||||
* Note that elements copied to the view with copyViewElementsToEAforEditing retain their
|
||||
* position in the stack of elements in the view even if modified using EA
|
||||
* default is false, i.e. the new elements get to the bottom of the stack
|
||||
* @returns
|
||||
*/
|
||||
addElementsToView(repositionToCursor?: boolean, save?: boolean, newElementsOnTop?: boolean): Promise<boolean>;
|
||||
/**
|
||||
* Register instance of EA to use for hooks with TargetView
|
||||
* By default ExcalidrawViews will check window.ExcalidrawAutomate for event hooks.
|
||||
* Using this event you can set a different instance of Excalidraw Automate for hooks
|
||||
* @returns true if successful
|
||||
*/
|
||||
registerThisAsViewEA(): boolean;
|
||||
/**
|
||||
* Sets the targetView EA to window.ExcalidrawAutomate
|
||||
* @returns true if successful
|
||||
*/
|
||||
deregisterThisAsViewEA(): boolean;
|
||||
/**
|
||||
* If set, this callback is triggered when the user closes an Excalidraw view.
|
||||
*/
|
||||
onViewUnloadHook: (view: ExcalidrawView) => void;
|
||||
/**
|
||||
* If set, this callback is triggered, when the user changes the view mode.
|
||||
* You can use this callback in case you want to do something additional when the user switches to view mode and back.
|
||||
*/
|
||||
onViewModeChangeHook: (isViewModeEnabled: boolean, view: ExcalidrawView, ea: ExcalidrawAutomate) => void;
|
||||
/**
|
||||
* If set, this callback is triggered, when the user hovers a link in the scene.
|
||||
* You can use this callback in case you want to do something additional when the onLinkHover event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onLinkHover action you must return true, it will stop the native excalidraw onLinkHover management flow.
|
||||
*/
|
||||
onLinkHoverHook: (element: NonDeletedExcalidrawElement, linkText: string, view: ExcalidrawView, ea: ExcalidrawAutomate) => boolean;
|
||||
/**
|
||||
* If set, this callback is triggered, when the user clicks a link in the scene.
|
||||
* You can use this callback in case you want to do something additional when the onLinkClick event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onLinkClick action you must return false, it will stop the native excalidraw onLinkClick management flow.
|
||||
*/
|
||||
onLinkClickHook: (element: ExcalidrawElement, linkText: string, event: MouseEvent, view: ExcalidrawView, ea: ExcalidrawAutomate) => boolean;
|
||||
/**
|
||||
* If set, this callback is triggered, when Excalidraw receives an onDrop event.
|
||||
* You can use this callback in case you want to do something additional when the onDrop event occurs.
|
||||
* This callback must return a boolean value.
|
||||
* In case you want to prevent the excalidraw onDrop action you must return false, it will stop the native excalidraw onDrop management flow.
|
||||
*/
|
||||
onDropHook: (data: {
|
||||
ea: ExcalidrawAutomate;
|
||||
event: React.DragEvent<HTMLDivElement>;
|
||||
draggable: any;
|
||||
type: "file" | "text" | "unknown";
|
||||
payload: {
|
||||
files: TFile[];
|
||||
text: string;
|
||||
};
|
||||
excalidrawFile: TFile;
|
||||
view: ExcalidrawView;
|
||||
pointerPosition: {
|
||||
x: number;
|
||||
y: number;
|
||||
};
|
||||
}) => boolean;
|
||||
/**
|
||||
* utility function to generate EmbeddedFilesLoader object
|
||||
* @param isDark
|
||||
* @returns
|
||||
*/
|
||||
getEmbeddedFilesLoader(isDark?: boolean): EmbeddedFilesLoader;
|
||||
/**
|
||||
* utility function to generate ExportSettings object
|
||||
* @param withBackground
|
||||
* @param withTheme
|
||||
* @returns
|
||||
*/
|
||||
getExportSettings(withBackground: boolean, withTheme: boolean): ExportSettings;
|
||||
/**
|
||||
* get bounding box of elements
|
||||
* bounding box is the box encapsulating all of the elements completely
|
||||
* @param elements
|
||||
* @returns
|
||||
*/
|
||||
getBoundingBox(elements: ExcalidrawElement[]): {
|
||||
topX: number;
|
||||
topY: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
/**
|
||||
* elements grouped by the highest level groups
|
||||
* @param elements
|
||||
* @returns
|
||||
*/
|
||||
getMaximumGroups(elements: ExcalidrawElement[]): ExcalidrawElement[][];
|
||||
/**
|
||||
* gets the largest element from a group. useful when a text element is grouped with a box, and you want to connect an arrow to the box
|
||||
* @param elements
|
||||
* @returns
|
||||
*/
|
||||
getLargestElement(elements: ExcalidrawElement[]): ExcalidrawElement;
|
||||
/**
|
||||
* Gets the groupId for the group that contains all the elements, or null if such a group does not exist
|
||||
* @param elements
|
||||
* @returns null or the groupId
|
||||
*/
|
||||
getCommonGroupForElements(elements: ExcalidrawElement[]): string;
|
||||
/**
|
||||
* Gets all the elements from elements[] that share one or more groupIds with element.
|
||||
* @param element
|
||||
* @param elements - typically all the non-deleted elements in the scene
|
||||
* @returns
|
||||
*/
|
||||
getElementsInTheSameGroupWithElement(element: ExcalidrawElement, elements: ExcalidrawElement[]): ExcalidrawElement[];
|
||||
/**
|
||||
* @param element
|
||||
* @param a
|
||||
* @param b
|
||||
* @param gap
|
||||
* @returns 2 or 0 intersection points between line going through `a` and `b`
|
||||
* and the `element`, in ascending order of distance from `a`.
|
||||
*/
|
||||
intersectElementWithLine(element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap?: number): Point[];
|
||||
/**
|
||||
* See OCR plugin for example on how to use scriptSettings
|
||||
* Set by the ScriptEngine
|
||||
*/
|
||||
activeScript: string;
|
||||
/**
|
||||
*
|
||||
* @returns script settings. Saves settings in plugin settings, under the activeScript key
|
||||
*/
|
||||
getScriptSettings(): {};
|
||||
/**
|
||||
* sets script settings.
|
||||
* @param settings
|
||||
* @returns
|
||||
*/
|
||||
setScriptSettings(settings: any): Promise<void>;
|
||||
/**
|
||||
* Open a file in a new workspaceleaf or reuse an existing adjacent leaf depending on Excalidraw Plugin Settings
|
||||
* @param file
|
||||
* @returns
|
||||
*/
|
||||
openFileInNewOrAdjacentLeaf(file: TFile): WorkspaceLeaf;
|
||||
/**
|
||||
* measure text size based on current style settings
|
||||
* @param text
|
||||
* @returns
|
||||
*/
|
||||
measureText(text: string): {
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
/**
|
||||
* verifyMinimumPluginVersion returns true if plugin version is >= than required
|
||||
* recommended use:
|
||||
* if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.20")) {new Notice("message");return;}
|
||||
* @param requiredVersion
|
||||
* @returns
|
||||
*/
|
||||
verifyMinimumPluginVersion(requiredVersion: string): boolean;
|
||||
/**
|
||||
* Check if view is instance of ExcalidrawView
|
||||
* @param view
|
||||
* @returns
|
||||
*/
|
||||
isExcalidrawView(view: any): boolean;
|
||||
/**
|
||||
* sets selection in view
|
||||
* @param elements
|
||||
* @returns
|
||||
*/
|
||||
selectElementsInView(elements: ExcalidrawElement[]): void;
|
||||
/**
|
||||
* @returns an 8 character long random id
|
||||
*/
|
||||
generateElementId(): string;
|
||||
/**
|
||||
* @param element
|
||||
* @returns a clone of the element with a new id
|
||||
*/
|
||||
cloneElement(element: ExcalidrawElement): ExcalidrawElement;
|
||||
/**
|
||||
* Moves the element to a specific position in the z-index
|
||||
*/
|
||||
moveViewElementToZIndex(elementId: number, newZIndex: number): void;
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hexStringToRgb(color: string): number[];
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
rgbToHexString(color: number[]): string;
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
hslToRgb(color: number[]): number[];
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
rgbToHsl(color: number[]): number[];
|
||||
/**
|
||||
*
|
||||
* @param color
|
||||
* @returns
|
||||
*/
|
||||
colorNameToHex(color: string): string;
|
||||
}```
|
||||
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
# [◀ Excalidraw Automate How To](../readme.md)
|
||||
## Introduction to the API
|
||||
You can access Excalidraw Automate via the ExcalidrawAutomate object. I recommend starting your Automate scripts with the following code:
|
||||
You can access Excalidraw Automate via the ExcalidrawAutomate object. I recommend starting Templater, DataView and QuickAdd scripts with the following code:
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
const ea = ExcalidrawAutomate;
|
||||
ea.reset();
|
||||
```
|
||||
|
||||
The first line creates a practical constant so you can avoid writing ExcalidrawAutomate 100x times.
|
||||
The first line creates a constant so you can avoid writing ExcalidrawAutomate 100x times.
|
||||
|
||||
The second line resets ExcalidrawAutomate to defaults. This is important as you will not know which template you executed before, thus you won't know what state you left Excalidraw in.
|
||||
|
||||
**⚠ Note:** In case you are using the Excalidraw plugin's built in [Scripting Engine](../ExcalidrawScriptsEngine.md), the engine will take care of initializing the `ea` object.
|
||||
|
||||
### Basic logic of using Excalidraw Automate
|
||||
1. Set the styling of the elements you want to draw
|
||||
2. Add elements. As you add elements, each new element is added one layer above the previous, thus in case of overlapping objects the later one will be on the top of the prior one.
|
||||
@@ -19,11 +21,11 @@ The second line resets ExcalidrawAutomate to defaults. This is important as you
|
||||
|
||||
You can change the styling between adding different elements. My logic for separating element styling and creation is based on the assumption that you will probably set a stroke color, stroke style, stroke roughness, etc. and draw most of your elements using that. There would be no point in setting all these parameters each time you add an element.
|
||||
|
||||
### Before we dive deeper, here are three a simple example Templater scripts
|
||||
### Before we dive deeper, here are three a simple example [Templater](https://github.com/SilentVoid13/Templater) scripts
|
||||
#### Create a new drawing with custom name, in a custom folder, using a template
|
||||
This simple script gives you significant additional flexibility over Excalidraw Plugin settings to name your drawings, place them into folders, and to apply templates.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -38,7 +40,7 @@ This simple script gives you significant additional flexibility over Excalidraw
|
||||
```
|
||||
|
||||
#### Create a simple drawing
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
@@ -60,7 +62,7 @@ The script will generate the following drawing:
|
||||
#### Add a TextElement in a box to an open Excalidraw View.
|
||||
Position the new element under the currently selected element, with an arrow from the selected element to the added text.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
|
||||
@@ -143,7 +143,7 @@ getViewSelectedElement():ExcalidrawElement
|
||||
|
||||
You first need to set the view calling `setView()`.
|
||||
|
||||
If an element is selected in the targetView the function returns the selected element. If multiple elements are selected, either by SHIFT+Clicking to select multiple elements, or by selecting a group, the first of the elements will be selected. If you want to specify which element to select from a group, double click the desired element in the group.
|
||||
If an element is selected in the targetView the function returns the selected element. If multiple elements are selected, either by <kbd>SHIFT+Clicking</kbd> to select multiple elements, or by selecting a group, the first of the elements will be selected. If you want to specify which element to select from a group, double click the desired element in the group.
|
||||
|
||||
This function is helpful if you want to add a new element in relation to an existing element in your drawing.
|
||||
|
||||
@@ -218,4 +218,4 @@ ea.onDropHook = (data) => {
|
||||
console.log(data);
|
||||
return false;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Applying an Excalidraw Template to a New Drawing
|
||||
This example is similar to the one in the introduction, only rotated 90°, and using a template, plus specifying a filename and folder to save the drawing, and opening the new drawing in a new pane.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Connect Objects
|
||||
This [Templater](https://github.com/SilentVoid13/Templater) template demonstrates how to connect two objects using ExcalidrawAutomate.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const ea = ExcalidrawAutomate;
|
||||
|
||||
@@ -29,11 +29,11 @@ function crawl(subtasks) {
|
||||
return size;
|
||||
}
|
||||
|
||||
const tasks = dv.page("Demo.md").file.tasks[0];
|
||||
const tasks = dv.page("FamilyTree.md").file.tasks[0];
|
||||
tasks["size"] = crawl(tasks.subtasks);
|
||||
|
||||
const width = 300;
|
||||
const height = 100;
|
||||
const height = 150;
|
||||
const ea = ExcalidrawAutomate;
|
||||
ea.reset();
|
||||
|
||||
@@ -56,7 +56,7 @@ function buildMindmap(subtasks, depth, offset, parentObjectID) {
|
||||
|
||||
}
|
||||
|
||||
tasks["objectID"] = ea.addText(width*1.5,width,tasks.text,{box:true, textAlign:"center"});
|
||||
tasks["objectID"] = ea.addText(width*1.5,height*(tasks.size-1),tasks.text,{box:true, textAlign:"center"});
|
||||
buildMindmap(tasks.subtasks, 2, 0, tasks.objectID);
|
||||
|
||||
ea.createSVG().then((svg)=>dv.span(svg.outerHTML));
|
||||
|
||||
@@ -19,7 +19,7 @@ The input file is `Demo.md` with the following contents:
|
||||
|
||||
### dataviewjs script
|
||||
The `dataviewjs` script looks like this:
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
function crawl(subtasks) {
|
||||
let size = subtasks.length > 0 ? 0 : 1; //if no children then a leaf with size 1
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Insert new drawing into currently edited document
|
||||
This [Templater](https://github.com/SilentVoid13/Templater) template will prompt you for the title of the drawing. It will create a new drawing with the provided title, and in the folder of the document you were editing. It will then transclude the new drawing at the cursor location and open the new drawing in a new workspace leaf by splitting the current leaf.
|
||||
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const defaultTitle = tp.date.now("HHmm")+' '+tp.file.title;
|
||||
|
||||
@@ -22,7 +22,7 @@ Example input:
|
||||
```
|
||||
|
||||
### Templater script
|
||||
*Use CTRL+Shift+V to paste code into Obsidian!*
|
||||
*Use <kbd>CTRL+Shift+V</kbd> to paste code into Obsidian!*
|
||||
```javascript
|
||||
<%*
|
||||
const IDX = Object.freeze({"depth":0, "text":1, "parent":2, "size":3, "children": 4, "objectId":5});
|
||||
|
||||
401
docs/ExcalidrawScriptsEngine.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# [◀ Excalidraw Automate How To](./readme.md)
|
||||
|
||||
[](https://youtu.be/hePJcObHIso)
|
||||
|
||||
## Introduction
|
||||
Place your ExcalidrawAutomate Scripts into the folder defined in Excalidraw Settings. The Scripts folder may not be the root folder of your Vault.
|
||||
|
||||

|
||||
|
||||
EA scripts may be markdown files, plain text files, or .js files. The only requirement is that they must contain valid JavaScript code.
|
||||
|
||||

|
||||
|
||||
You will be able to access your scripts from Excalidraw via the Obsidian Command Palette.
|
||||
|
||||

|
||||
|
||||
This will allow you to assign hotkeys to your favorite scripts just like to any other Obsidian command.
|
||||
|
||||

|
||||
|
||||
## Script development
|
||||
An Excalidraw script will automatically receive two objects:
|
||||
- `ea`: The Script Enginge will initialize the `ea` object including setting the active view to the View from which the script was called.
|
||||
- `utils`: I have borrowed functions exposed on utils from [QuickAdd](https://github.com/chhoumann/quickadd/blob/master/docs/QuickAddAPI.md), though currently not all QuickAdd utility functions are implemented in Excalidraw. As of now, these are the available functions. See the example below for details.
|
||||
- `inputPrompt: (header: string, placeholder?: string, value?: string, buttons?: [{caption:string, action:Function}])`
|
||||
- Opens a prompt that asks for an input. Returns a string with the input.
|
||||
- You need to await the result of inputPrompt.
|
||||
- `buttons.action(input: string) => string`. The button action will receive the current input string. If action returns null, the input will be unchanged. If action returns a string, the inputPrompt will resolve to this value.
|
||||
```typescript
|
||||
let fileType = "";
|
||||
const filename = await utils.inputPrompt (
|
||||
"Filename for new document",
|
||||
"Placeholder",
|
||||
"DefaultFilename.md",
|
||||
[
|
||||
{
|
||||
caption: "Markdown",
|
||||
action: ()=>{fileType="md";return;}
|
||||
},
|
||||
{
|
||||
caption: "Excalidraw",
|
||||
action: ()=>{fileType="ex";return;}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
```
|
||||
- `suggester: (displayItems: string[], items: any[], hint?: string, instructions?:Instruction[])`
|
||||
- Opens a suggester. Displays the displayItems and returns the corresponding item from items[].
|
||||
- You need to await the result of suggester.
|
||||
- If the user cancels (ESC), suggester will return `undefined`
|
||||
- Hint and instructions are optional.
|
||||
```typescript
|
||||
interface Instruction {
|
||||
command: string;
|
||||
purpose: string;
|
||||
}
|
||||
```
|
||||
- Scripts may have settings. These settings are stored as part of plugin settings and may be also changed by the user via the Obsidian plugin settings window.
|
||||
- You can access settings for the active script using `ea.getScriptSettings()` and store settings values with `ea.setScriptSettings(settings:any)`
|
||||
- Rules for displaying script settings in plugin settings are:
|
||||
- If the setting is a simple literal (boolean, number, string) these will be displayed as such in settings. The name of the setting will be the key for the value.
|
||||
```javascript
|
||||
ea.setScriptSettings({
|
||||
"value 1": true,
|
||||
"value 2": 1,
|
||||
"value 3": "my string"
|
||||
})
|
||||
```
|
||||

|
||||
- If the setting is an object and follows the below structure then a description and a valueset may also be added. Values may also be hidden from the user using the `hidden` key.
|
||||
```javascript
|
||||
ea.setScriptSettings({
|
||||
"value 1": {
|
||||
"value": true,
|
||||
"description": "This is the description for my boolean value"
|
||||
},
|
||||
"value 2": {
|
||||
"value": 1,
|
||||
"description": "This is the description for my numeric value"
|
||||
},
|
||||
"value 3": {
|
||||
"value": "my string",
|
||||
"description": "This is the description for my string value",
|
||||
"valueset": ["allowed 1","allowed 2","allowed 3"]
|
||||
},
|
||||
"value 4": {
|
||||
"value": "my value",
|
||||
"hidden": true
|
||||
}
|
||||
});
|
||||
```
|
||||

|
||||
|
||||
---------
|
||||
|
||||
## Example Excalidraw Automate Scripts
|
||||
|
||||
These scripts are available as downloadable `.md` files on GitHub in [this](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/ea-scripts) folder 📂.
|
||||
|
||||
### Add box around selected elements
|
||||
|
||||

|
||||
|
||||
This script will add an encapsulating box around the currently selected elements in Excalidraw
|
||||
```javascript
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//check if settings exist. If not, set default values on first run
|
||||
if(!settings["Default padding"]) {
|
||||
settings = {
|
||||
"Prompt for padding?": true,
|
||||
"Default padding" : {
|
||||
value: 10,
|
||||
description: "Padding between the bounding box of the selected elements, and the box the script creates"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let padding = settings["Default padding"].value;
|
||||
|
||||
if(settings["Prompt for padding?"]) {
|
||||
padding = parseInt (await utils.inputPrompt("padding?","number",padding.toString()));
|
||||
}
|
||||
|
||||
if(isNaN(padding)) {
|
||||
new Notice("The padding value provided is not a number");
|
||||
return;
|
||||
}
|
||||
elements = ea.getViewSelectedElements();
|
||||
const box = ea.getBoundingBox(elements);
|
||||
color = ea
|
||||
.getExcalidrawAPI()
|
||||
.getAppState()
|
||||
.currentItemStrokeColor;
|
||||
//uncomment for random color:
|
||||
//color = '#'+(Math.random()*0xFFFFFF<<0).toString(16).padStart(6,"0");
|
||||
ea.style.strokeColor = color;
|
||||
id = ea.addRect(
|
||||
box.topX - padding,
|
||||
box.topY - padding,
|
||||
box.width + 2*padding,
|
||||
box.height + 2*padding
|
||||
);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
|
||||
ea.addElementsToView(false);
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Connect selected elements with an arrow
|
||||
|
||||

|
||||
|
||||
This script will connect two objects with an arrow. If either of the objects are a set of grouped elements (e.g. a text element grouped with an encapsulating rectangle), the script will identify these groups, and connect the arrow to the largest object in the group (assuming you want to connect the arrow to the box around the text element).
|
||||
```javascript
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Starting arrowhead"]) {
|
||||
settings = {
|
||||
"Starting arrowhead" : {
|
||||
value: "none",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Ending arrowhead" : {
|
||||
value: "triangle",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Line points" : {
|
||||
value: 1,
|
||||
description: "Number of line points between start and end"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const arrowStart = settings["Starting arrowhead"].value === "none" ? null : settings["Starting arrowhead"].value;
|
||||
const arrowEnd = settings["Ending arrowhead"].value === "none" ? null : settings["Ending arrowhead"].value;
|
||||
const linePoints = Math.floor(settings["Line points"].value);
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
groups = ea.getMaximumGroups(elements);
|
||||
|
||||
if(groups.length !== 2) {
|
||||
//unfortunately getMaxGroups returns duplicated resultset for sticky notes
|
||||
//needs additional filtering
|
||||
cleanGroups=[];
|
||||
idList = [];
|
||||
for (group of groups) {
|
||||
keep = true;
|
||||
for(item of group) if(idList.contains(item.id)) keep = false;
|
||||
if(keep) {
|
||||
cleanGroups.push(group);
|
||||
idList = idList.concat(group.map(el=>el.id))
|
||||
}
|
||||
}
|
||||
if(cleanGroups.length !== 2) return;
|
||||
groups = cleanGroups;
|
||||
}
|
||||
|
||||
els = [
|
||||
ea.getLargestElement(groups[0]),
|
||||
ea.getLargestElement(groups[1])
|
||||
];
|
||||
|
||||
ea.style.strokeColor = els[0].strokeColor;
|
||||
ea.style.strokeWidth = els[0].strokeWidth;
|
||||
ea.style.strokeStyle = els[0].strokeStyle;
|
||||
ea.style.strokeSharpness = els[0].strokeSharpness;
|
||||
|
||||
ea.connectObjects(
|
||||
els[0].id,
|
||||
null,
|
||||
els[1].id,
|
||||
null,
|
||||
{
|
||||
endArrowHead: arrowEnd,
|
||||
startArrowHead: arrowStart,
|
||||
numberOfPoints: linePoints
|
||||
}
|
||||
);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
### Reverse selected arrows
|
||||
|
||||

|
||||
|
||||
Reverse the direction of **arrows** within the scope of selected elements.
|
||||
|
||||
```javascript
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="arrow");
|
||||
if(!elements || elements.length===0) return;
|
||||
elements.forEach((el)=>{
|
||||
const start = el.startArrowhead;
|
||||
el.startArrowhead = el.endArrowhead;
|
||||
el.endArrowhead = start;
|
||||
});
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Set line width of selected elements
|
||||
|
||||

|
||||
|
||||
This is helpful, for example, when you scale freedraw sketches and want to reduce or increase their line width.
|
||||
```javascript
|
||||
let width = (ea.getViewSelectedElement().strokeWidth??1).toString();
|
||||
width = await utils.inputPrompt("Width?","number",width);
|
||||
const elements=ea.getViewSelectedElements();
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.getElements().forEach((el)=>el.strokeWidth=width);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Set grid size
|
||||
|
||||

|
||||
|
||||
The default grid size in Excalidraw is 20. Currently there is no way to change the grid size via the user interface.
|
||||
```javascript
|
||||
const grid = parseInt(await utils.inputPrompt("Grid size?",null,"20"));
|
||||
const api = ea.getExcalidrawAPI();
|
||||
let appState = api.getAppState();
|
||||
appState.gridSize = grid;
|
||||
api.updateScene({
|
||||
appState,
|
||||
commitToHistory:false
|
||||
});
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Set element dimensions and position
|
||||
|
||||

|
||||
|
||||
Currently there is no way to specify the exact location and size of objects in Excalidraw. You can bridge this gap with the following simple script.
|
||||
```javascript
|
||||
const elements = ea.getViewSelectedElements();
|
||||
if(elements.length === 0) return;
|
||||
const el = ea.getLargestElement(elements);
|
||||
const sizeIn = [el.x,el.y,el.width,el.height].join(",");
|
||||
let res = await utils.inputPrompt("x,y,width,height?",null,sizeIn);
|
||||
res = res.split(",");
|
||||
if(res.length !== 4) return;
|
||||
let size = [];
|
||||
for (v of res) {
|
||||
const i = parseInt(v);
|
||||
if(isNaN(i)) return;
|
||||
size.push(i);
|
||||
}
|
||||
el.x = size[0];
|
||||
el.y = size[1];
|
||||
el.width = size[2];
|
||||
el.height = size[3];
|
||||
ea.copyViewElementsToEAforEditing([el]);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Bullet points
|
||||
|
||||

|
||||
|
||||
This script will add a small circle to the top left of each text element in the selection and add the text and the "bullet point" into a group.
|
||||
```javascript
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
const padding = 10;
|
||||
elements.forEach((el)=>{
|
||||
ea.style.strokeColor = el.strokeColor;
|
||||
const size = el.fontSize/2;
|
||||
const ellipseId = ea.addEllipse(
|
||||
el.x-padding-size,
|
||||
el.y+size/2,
|
||||
size,
|
||||
size
|
||||
);
|
||||
ea.addToGroup([el.id,ellipseId]);
|
||||
});
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Split text by lines
|
||||
**!!!Requires Excalidraw 1.5.1 or higher**
|
||||
|
||||

|
||||
|
||||
Split lines of text into separate text elements for easier reorganization
|
||||
```javascript
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
elements.forEach((el)=>{
|
||||
ea.style.strokeColor = el.strokeColor;
|
||||
ea.style.fontFamily = el.fontFamily;
|
||||
ea.style.fontSize = el.fontSize;
|
||||
const text = el.text.split("\n");
|
||||
for(i=0;i<text.length;i++) {
|
||||
ea.addText(el.x,el.y+i*el.height/text.length,text[i]);
|
||||
}
|
||||
});
|
||||
ea.addElementsToView();
|
||||
ea.deleteViewElements(elements);
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Set Text Alignment
|
||||
|
||||

|
||||
|
||||
Sets text alignment of text block (cetner, right, left). Useful if you want to set a keyboard shortcut for selecting text alignment.
|
||||
```javascript
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
if(elements.length===0) return;
|
||||
let align = ["left","right","center"];
|
||||
align = await utils.suggester(align,align);
|
||||
elements.forEach((el)=>el.textAlign = align);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
### Set Font Family
|
||||
|
||||

|
||||
|
||||
Sets font family of the text block (Virgil, Helvetica, Cascadia). Useful if you want to set a keyboard shortcut for selecting font family.
|
||||
```javascript
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
if(elements.length===0) return;
|
||||
let font = ["Virgil","Helvetica","Cascadia"];
|
||||
font = parseInt(await utils.suggester(font,["1","2","3"]));
|
||||
if (isNaN(font)) return;
|
||||
elements.forEach((el)=>el.fontFamily = font);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addElementsToView();
|
||||
```
|
||||
@@ -1 +1 @@
|
||||
theme: jekyll-theme-leap-day
|
||||
theme: jekyll-theme-hacker
|
||||
@@ -1,18 +1,21 @@
|
||||
# Excalidraw Automate How To
|
||||
|
||||
Excalidraw Automate allows you to create Excalidraw drawings using the [Templater](https://silentvoid13.github.io/Templater/docs/) plugin, and to generate embedded SVG and PNG images using [DataviewJS](https://blacksmithgu.github.io/obsidian-dataview/docs/api/intro/)
|
||||
Use ExcalidrawAutomate to create or manipulate Excalidraw drawings using the [ExcalidrawAutomate Script Engine](ExcalidrawScriptsEngine.md), the [Templater](https://silentvoid13.github.io/Templater/docs/) or the [QuickAdd](https://github.com/chhoumann/quickadd) plugins, and to generate embedded SVG and PNG images using [DataviewJS](https://blacksmithgu.github.io/obsidian-dataview/docs/api/intro/)
|
||||
|
||||
With a little work, using Excalidraw Automate you can generate simple mindmaps, build a family tree, fill out SVG forms, create customized charts, etc. based on documents in your vault.
|
||||
With a little work, using ExcalidrawAutomate you can generate simple mindmaps, build a family tree, fill out SVG forms, create customized charts, or automate simple tasks (i.e. create macros) in Excalidraw.
|
||||

|
||||
|
||||
## API documentation
|
||||
- [Introduction to the API](API/introduction.md)
|
||||
- **start here** [Introduction to the API](API/introduction.md)
|
||||
- [Overview of Attributes and Functions](API/attributes_functions_overview.md)
|
||||
- [Element Sytle](API/element_style.md)
|
||||
- [Canvas Style](API/canvas_style.md)
|
||||
- [Adding Objects](API/objects.md)
|
||||
- [Utility Functions](API/utility.md)
|
||||
|
||||
## ExcalidrawAutomate Script Engine
|
||||
I recommend using the Scripts Engine for "Macro" like automation, when you want to automate a few simple steps, such as adding a box around a text element, or connecting two objects with an arrow, or setting line width or the grid to a custom value.
|
||||
- [ExcalidrawAutomate Script Engine](ExcalidrawScriptsEngine.md).
|
||||
|
||||
## Examples
|
||||
- **Templater**
|
||||
|
||||
25
ea-scripts/Add Connector Point.md
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||

|
||||
|
||||
This script will add a small circle to the top left of each text element in the selection and add the text and the "bullet point" into a group.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
const padding = 10;
|
||||
elements.forEach((el)=>{
|
||||
ea.style.strokeColor = el.strokeColor;
|
||||
const size = el.fontSize/2;
|
||||
const ellipseId = ea.addEllipse(
|
||||
el.x-padding-size,
|
||||
el.y+size/2,
|
||||
size,
|
||||
size
|
||||
);
|
||||
ea.addToGroup([el.id,ellipseId]);
|
||||
});
|
||||
ea.addElementsToView(false,false);
|
||||
1
ea-scripts/Add Connector Point.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 100 500 400"><path fill-rule="evenodd" d="M414.57 183.49a11.194 11.194 0 0 0-10.344 6.914 11.21 11.21 0 0 0-.851 4.285v74.086h-110.09c-5.57-47.172-45.852-83.945-94.48-83.945-52.418 0-95.2 42.715-95.2 95.145 0 52.43 42.782 95.141 95.2 95.141 48.629 0 88.91-36.773 94.48-83.945h110.09v74.145c0 1.465.293 2.93.851 4.285a11.184 11.184 0 0 0 10.344 6.91H585.2c1.465 0 2.93-.292 4.285-.85a11.184 11.184 0 0 0 6.91-10.344v-170.63c0-1.466-.293-2.93-.851-4.286a11.246 11.246 0 0 0-2.426-3.633c-1.035-1.035-2.277-1.867-3.633-2.43s-2.82-.851-4.285-.851z"/></svg>
|
||||
|
After Width: | Height: | Size: 604 B |
65
ea-scripts/Add Link to Existing File and Open.md
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||

|
||||
|
||||
Prompts for a file from the vault. Adds a link to the selected element pointing to the selected file. You can control in settings to open the file in the current active pane or an adjacent pane.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
|
||||
if(!settings["Open link in active pane"]) {
|
||||
settings = {
|
||||
"Open link in active pane": {
|
||||
value: false,
|
||||
description: "Open the link in the current active pane (on) or a new pane (off)."
|
||||
},
|
||||
...settings
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const openInCurrentPane = settings["Open link in active pane"].value;
|
||||
|
||||
elements = ea.getViewSelectedElements();
|
||||
if(elements.length === 0) {
|
||||
new Notice("No selected elements");
|
||||
return;
|
||||
}
|
||||
|
||||
const files = app.vault.getFiles()
|
||||
const filePaths = files.map((f)=>f.path);
|
||||
file = await utils.suggester(filePaths,files,"Select a file");
|
||||
|
||||
if(!file) return;
|
||||
|
||||
const link = `[[${app.metadataCache.fileToLinktext(file,ea.targetView.file.path,true)}]]`;
|
||||
|
||||
ea.style.backgroundColor = "transparent";
|
||||
ea.style.strokeColor = "rgba(70,130,180,0.05)"
|
||||
ea.style.strokeWidth = 2;
|
||||
ea.style.roughness = 0;
|
||||
|
||||
if(elements.length===1 && elements[0].type !== "text") {
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.getElements()[0].link = link;
|
||||
} else {
|
||||
const b = ea.getBoundingBox(elements);
|
||||
const id = ea.addEllipse(b.topX+b.width-5, b.topY, 5, 5);
|
||||
ea.getElement(id).link = link;
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addToGroup(elements.map((e)=>e.id).concat([id]));
|
||||
}
|
||||
await ea.addElementsToView(false,true,true);
|
||||
ea.selectElementsInView(ea.getElements());
|
||||
|
||||
if(openInCurrentPane) {
|
||||
app.workspace.openLinkText(file.path,ea.targetView.file.path,false);
|
||||
return;
|
||||
}
|
||||
ea.openFileInNewOrAdjacentLeaf(file);
|
||||
1
ea-scripts/Add Link to Existing File and Open.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 130 110" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 30h40m-40 0h40m0 0 20 20M50 30l20 20m0 0v60m0-60v60m0 0H10m60 0H10m0 0V30m0 80V30"/><path fill="none" stroke-linecap="round" stroke-width="2" d="M50 30v20m0-20v20m0 0h20m-20 0h20"/><path fill="none" stroke-linecap="round" stroke-width="4" d="M110 10H90m20 0H90m0 0v40m0-40v40m0 0h40m-40 0h40m0 0V30m0 20V30M110 30l20-20m-20 20 20-20M120 10h10m-10 0h10m0 0v10m0-10v10"/></svg>
|
||||
|
After Width: | Height: | Size: 519 B |
90
ea-scripts/Add Link to New Page and Open.md
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||

|
||||
|
||||
Prompts for filename. Offers option to create and open a new Markdown or Excalidraw document. Adds link pointing to the new file, to the selected objects in the drawing. You can control in settings to open the file in the current active pane or an adjacent pane.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.6.1")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
|
||||
if(!settings["Open link in active pane"]) {
|
||||
settings = {
|
||||
"Open link in active pane": {
|
||||
value: false,
|
||||
description: "Open the link in the current active pane (on) or a new pane (off)."
|
||||
},
|
||||
...settings
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const openInCurrentPane = settings["Open link in active pane"].value;
|
||||
|
||||
elements = ea.getViewSelectedElements();
|
||||
if(elements.length === 0) {
|
||||
new Notice("No selected elements");
|
||||
return;
|
||||
}
|
||||
|
||||
const activeFile = ea.targetView.file;
|
||||
const prefix = activeFile.basename;
|
||||
const timestamp = moment(Date.now()).format(ea.plugin.settings.drawingFilenameDateTime);
|
||||
|
||||
let fileType = "";
|
||||
const filename = await utils.inputPrompt (
|
||||
"Filename for new document",
|
||||
"",
|
||||
`${prefix} - ${timestamp}`,
|
||||
[
|
||||
{
|
||||
caption: "Markdown",
|
||||
action: ()=>{fileType="md";return;}
|
||||
},
|
||||
{
|
||||
caption: "Excalidraw",
|
||||
action: ()=>{fileType="ex";return;}
|
||||
}
|
||||
]
|
||||
);
|
||||
|
||||
if(!filename || filename === "") return;
|
||||
const filepath = activeFile.path.replace(activeFile.name,`${filename}.md`);
|
||||
|
||||
const file = await app.fileManager.createNewMarkdownFileFromLinktext(filepath);
|
||||
if(file && fileType==="ex") {
|
||||
const blank = await app.plugins.plugins["obsidian-excalidraw-plugin"].getBlankDrawing();
|
||||
await app.vault.modify(file,blank);
|
||||
await new Promise(r => setTimeout(r, 100)); //wait for metadata cache to update, so file opens as excalidraw
|
||||
}
|
||||
|
||||
const link = `[[${app.metadataCache.fileToLinktext(file,ea.targetView.file.path,true)}]]`;
|
||||
|
||||
ea.style.backgroundColor = "transparent";
|
||||
ea.style.strokeColor = "rgba(70,130,180,0.05)"
|
||||
ea.style.strokeWidth = 2;
|
||||
ea.style.roughness = 0;
|
||||
|
||||
if(elements.length===1 && elements[0].type !== "text") {
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.getElements()[0].link = link;
|
||||
} else {
|
||||
const b = ea.getBoundingBox(elements);
|
||||
const id = ea.addEllipse(b.topX+b.width-5, b.topY, 5, 5);
|
||||
ea.getElement(id).link = link;
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addToGroup(elements.map((e)=>e.id).concat([id]));
|
||||
}
|
||||
await ea.addElementsToView(false,true,true);
|
||||
ea.selectElementsInView(ea.getElements());
|
||||
|
||||
if(openInCurrentPane) {
|
||||
app.workspace.openLinkText(file.path,ea.targetView.file.path,false);
|
||||
return;
|
||||
}
|
||||
ea.openFileInNewOrAdjacentLeaf(file);
|
||||
1
ea-scripts/Add Link to New Page and Open.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 130 110" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 30h40m-40 0h40m0 0 20 20M50 30l20 20m0 0v60m0-60v60m0 0H10m60 0H10m0 0V30m0 80V30"/><path fill="none" stroke-linecap="round" stroke-width="2" d="M50 30v20m0-20v20m0 0h20m-20 0h20"/><path fill="none" stroke-linecap="round" stroke-width="4" d="M110 10H90m20 0H90m0 0v40m0-40v40m0 0h40m-40 0h40m0 0V30m0 20V30M110 30l20-20m-20 20 20-20M120 10h10m-10 0h10m0 0v10m0-10v10"/><path fill="none" stroke-linecap="round" stroke-width="8" d="M40.351 60.667v27m0-27v27M26.851 74.167h26.69m-26.69 0h26.69"/></svg>
|
||||
|
After Width: | Height: | Size: 643 B |
133
ea-scripts/Add Next Step in Process.md
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||

|
||||
|
||||
This script will prompt you for the title of the process step, then will create a stick note with the text. If an element is selected then the script will connect this new step with an arrow to the previous step (the selected element). If no element is selected, then the script assumes this is the first step in the process and will only output the sticky note with the text that was entered.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.24")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Starting arrowhead"]) {
|
||||
settings = {
|
||||
"Starting arrowhead" : {
|
||||
value: "none",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Ending arrowhead" : {
|
||||
value: "triangle",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Line points" : {
|
||||
value: 0,
|
||||
description: "Number of line points between start and end"
|
||||
},
|
||||
"Gap between elements": {
|
||||
value: 100
|
||||
},
|
||||
"Wrap text at (number of characters)": {
|
||||
value: 25,
|
||||
},
|
||||
"Fix width": {
|
||||
value: true,
|
||||
description: "The object around the text should have fix width to fit the wrapped text"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const arrowStart = settings["Starting arrowhead"].value === "none" ? null : settings["Starting arrowhead"].value;
|
||||
const arrowEnd = settings["Ending arrowhead"].value === "none" ? null : settings["Ending arrowhead"].value;
|
||||
|
||||
// workaround until https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/388 is fixed
|
||||
if (!arrowEnd) ea.style.endArrowHead = null;
|
||||
if (!arrowStart) ea.style.startArrowHead = null;
|
||||
|
||||
const linePoints = Math.floor(settings["Line points"].value);
|
||||
const gapBetweenElements = Math.floor(settings["Gap between elements"].value);
|
||||
const wrapLineLen = Math.floor(settings["Wrap text at (number of characters)"].value);
|
||||
const fixWidth = settings["Fix width"];
|
||||
|
||||
const textPadding = 10;
|
||||
const text = await utils.inputPrompt("Text?");
|
||||
const elements = ea.getViewSelectedElements();
|
||||
const isFirst = (!elements || elements.length === 0);
|
||||
|
||||
const width = ea.measureText("w".repeat(wrapLineLen)).width;
|
||||
|
||||
let id = "";
|
||||
|
||||
if(!isFirst) {
|
||||
const fromElement = ea.getLargestElement(elements);
|
||||
ea.copyViewElementsToEAforEditing([fromElement]);
|
||||
|
||||
const previousTextElements = elements.filter((el)=>el.type==="text");
|
||||
if(previousTextElements.length>0) {
|
||||
const el = previousTextElements[0];
|
||||
ea.style.strokeColor = el.strokeColor;
|
||||
ea.style.fontSize = el.fontSize;
|
||||
ea.style.fontFamily = el.fontFamily;
|
||||
}
|
||||
|
||||
textWidth = ea.measureText(text).width;
|
||||
|
||||
id = ea.addText(
|
||||
fixWidth
|
||||
? fromElement.x+fromElement.width/2-width/2
|
||||
: fromElement.x+fromElement.width/2-textWidth/2-textPadding,
|
||||
fromElement.y+fromElement.height+gapBetweenElements,
|
||||
text,
|
||||
{
|
||||
wrapAt: wrapLineLen,
|
||||
textAlign: "center",
|
||||
box: "rectangle",
|
||||
...fixWidth
|
||||
? {width: width, boxPadding:0}
|
||||
: {boxPadding: textPadding}
|
||||
}
|
||||
);
|
||||
|
||||
ea.connectObjects(
|
||||
fromElement.id,
|
||||
null,
|
||||
id,
|
||||
null,
|
||||
{
|
||||
endArrowHead: arrowEnd,
|
||||
startArrowHead: arrowStart,
|
||||
numberOfPoints: linePoints
|
||||
}
|
||||
);
|
||||
|
||||
const rect = ea.getElement(id);
|
||||
rect.strokeColor = fromElement.strokeColor;
|
||||
rect.strokeWidth = fromElement.strokeWidth;
|
||||
rect.strokeStyle = fromElement.strokeStyle;
|
||||
rect.roughness = fromElement.roughness;
|
||||
rect.strokeSharpness = fromElement.strokeSharpness;
|
||||
rect.backgroundColor = fromElement.backgroundColor;
|
||||
rect.fillStyle = fromElement.fillStyle;
|
||||
|
||||
await ea.addElementsToView(false,false);
|
||||
} else {
|
||||
id = ea.addText(
|
||||
0,
|
||||
0,
|
||||
text,
|
||||
{
|
||||
wrapAt: wrapLineLen,
|
||||
textAlign: "center",
|
||||
box: "rectangle",
|
||||
boxPadding: textPadding,
|
||||
...fixWidth?{width: width}:null
|
||||
}
|
||||
);
|
||||
await ea.addElementsToView(true,false);
|
||||
}
|
||||
|
||||
ea.selectElementsInView([ea.getElement(id)]);
|
||||
1
ea-scripts/Add Next Step in Process.svg
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
120
ea-scripts/Archive/OCR - Optical Character Recognition.md
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||

|
||||
|
||||
THIS SCRIPT REQUIRES EXCALIDRAW 1.5.15
|
||||
|
||||
The script will
|
||||
1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and
|
||||
2) will add the text to your drawing as a text element
|
||||
|
||||
I recommend also installing the [Transfer TextElements to Excalidraw markdown metadata](Transfer%20TextElements%20to%20Excalidraw%20markdown%20metadata.md) script as well.
|
||||
|
||||
The script is based on [@schlundd](https://github.com/schlundd)'s [Obsidian-OCR-Plugin](https://github.com/schlundd/obsidian-ocr-plugin)
|
||||
|
||||
See ScriptEngine documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.24")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
let token = ea.getScriptSettings().token?.value??ea.getScriptSettings().token;
|
||||
const BASE_URL = "https://ocr.taskbone.com";
|
||||
|
||||
//convert setting to 1.5.21 format
|
||||
if(token && !ea.getScriptSettings().token.value) {
|
||||
ea.setScriptSettings({token: {value: token, hidden: true}});
|
||||
}
|
||||
|
||||
//get new token if token was not provided
|
||||
if (!token) {
|
||||
const tokenResponse = await fetch(
|
||||
BASE_URL + "/get-new-token", {
|
||||
method: 'post'
|
||||
});
|
||||
if (tokenResponse.status === 200) {
|
||||
jsonResponse = await tokenResponse.json();
|
||||
token = jsonResponse.token;
|
||||
ea.setScriptSettings({token: {value: token, hidden: true}});
|
||||
} else {
|
||||
notice(`Taskbone OCR Error: ${tokenResponse.status}\nPlease try again later.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//get image element
|
||||
//if multiple image elements were selected prompt user to choose
|
||||
const imageElements = ea.getViewSelectedElements().filter((el)=>el.type==="image");
|
||||
|
||||
//need to save the view to ensure recently pasted images are saved as files
|
||||
await ea.targetView.save();
|
||||
|
||||
let selectedImageElement = null;
|
||||
switch (imageElements.length) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
selectedImageElement = imageElements[0];
|
||||
break;
|
||||
default:
|
||||
const files = imageElements.map((el)=>ea.getViewFileForImageElement(el));
|
||||
selectedImageElement = await utils.suggester(files.map((f)=>f.name),imageElements);
|
||||
break;
|
||||
}
|
||||
|
||||
if(!selectedImageElement) {
|
||||
notice("No image element was selected");
|
||||
return;
|
||||
}
|
||||
const imageFile = ea.getViewFileForImageElement(selectedImageElement);
|
||||
if(!imageFile) {
|
||||
notice("Can read image file");
|
||||
return;
|
||||
}
|
||||
|
||||
//Execute the OCR
|
||||
let text = null;
|
||||
const fileBuffer = await app.vault.readBinary(imageFile);
|
||||
const formData = new FormData();
|
||||
formData.append("image", new Blob([fileBuffer]))
|
||||
try {
|
||||
const response = await fetch(
|
||||
BASE_URL + "/get-text", {
|
||||
headers: {
|
||||
Authorization: "Bearer " + token
|
||||
},
|
||||
method: "post",
|
||||
body: formData
|
||||
});
|
||||
if (response.status == 200) {
|
||||
jsonResponse = await response.json();
|
||||
text = jsonResponse?.text;
|
||||
} else {
|
||||
notice(`Could not read Text from ${file.path}:\n Error: ${response.status}`);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
notice(`The OCR service seems unavailable right now. Please try again later.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!text) {
|
||||
notice("No text found");
|
||||
return;
|
||||
}
|
||||
console.log({text});
|
||||
|
||||
//add text element to drawing
|
||||
const id = ea.addText(selectedImageElement.x,selectedImageElement.y+selectedImageElement.height,text);
|
||||
await ea.addElementsToView();
|
||||
ea.selectElementsInView([ea.getElement(id)]);
|
||||
ea.getExcalidrawAPI().zoomToFit(ea.getViewSelectedElements(),1);
|
||||
|
||||
//utility function
|
||||
function notice(message) {
|
||||
new Notice(message,10000);
|
||||
console.log(message);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 120 500 320"><path d="M474.32 295.68H225.68c-8.398 0-15.68-6.719-15.68-15.68 0-8.398 6.719-15.68 15.68-15.68h248.64c8.398 0 15.68 6.719 15.68 15.68 0 8.398-6.719 15.68-15.68 15.68z"/><path d="m454.16 182-53.199-53.199c-2.8-2.8-6.719-4.48-11.199-4.48h-117.6c-17.359 0-31.359 14-31.359 31.358v108.64h31.359v-100.8c0-4.48 3.36-7.84 7.84-7.84h77.84v42c0 15.68 12.32 28 28 28h42v38.642H459.2V193.2c-.559-4.48-1.68-8.399-5.04-11.2zm-65.52 12.32v-33.602l33.602 33.602zM427.84 396.48c0 4.48-3.36 7.84-7.84 7.84H280c-4.48 0-7.84-3.36-7.84-7.84v-54.32c0-8.398-6.718-15.68-15.68-15.68-8.398 0-15.68 6.719-15.68 15.68v62.16c0 17.359 14 31.359 31.36 31.359h155.68c17.358 0 31.358-14 31.358-31.359v-62.16c0-8.398-6.718-15.68-15.68-15.68-8.398 0-15.68 6.719-15.68 15.68zM370.16 326.48h-66.641c-4.48 0-7.84-3.36-7.84-7.84s3.36-7.84 7.84-7.84h66.641c4.48 0 7.84 3.36 7.84 7.84s-3.922 7.84-7.84 7.84z"/><path d="M350 357.84h-46.48c-4.48 0-7.84-3.36-7.84-7.84s3.36-7.84 7.84-7.84H350c4.48 0 7.84 3.36 7.84 7.84s-3.36 7.84-7.84 7.84z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
1080
ea-scripts/Archive/TheBrain-navigation.md
Normal file
1
ea-scripts/Archive/TheBrain-navigation.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M380.6 365.6C401.1 379.9 416 404.3 416 432C416 476.2 380.2 512 336 512C291.8 512 256 476.2 256 432C256 423.6 257.3 415.4 259.7 407.8L114.1 280.4C103.8 285.3 92.21 288 80 288C35.82 288 0 252.2 0 208C0 163.8 35.82 128 80 128C101.9 128 121.7 136.8 136.2 151.1L320 77.52C321.3 34.48 356.6 0 400 0C444.2 0 480 35.82 480 80C480 117.9 453.7 149.6 418.4 157.9L380.6 365.6zM156.3 232.2L301.9 359.6C306.9 357.3 312.1 355.4 317.6 354.1L355.4 146.4C351.2 143.6 347.4 140.4 343.8 136.9L159.1 210.5C159.7 218 158.5 225.3 156.3 232.2V232.2z"/></svg>
|
||||
|
After Width: | Height: | Size: 605 B |
49
ea-scripts/Archive/Toggle Fullscreen on Mobile.md
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||

|
||||
|
||||
Hides Obsidian workspace leaf padding and header (based on option in settings, default is "hide header" = true) which will take Excalidraw to full screen. ⚠ Note that if the header is not visible, it will be very difficult to invoke the command palette to end full screen. Only hide the header if you have a keyboard or you've practiced opening command palette!
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
|
||||
if(!settings["Hide header"]) {
|
||||
settings = {
|
||||
"Hide header": {
|
||||
value: false,
|
||||
},
|
||||
...settings
|
||||
};
|
||||
await ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
if(!settings["Hide header"].description) {
|
||||
settings["Hide header"].description = "⚠ Note that if the header is not visible, it will be very difficult to invoke the command palette to end full screen. Only hide the header if you have a keyboard or you've practiced opening command palette!";
|
||||
await ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const hideHeader = settings["Hide header"].value;
|
||||
|
||||
const newStylesheet = document.createElement("style");
|
||||
newStylesheet.id = "excalidraw-full-screen";
|
||||
newStylesheet.textContent = `
|
||||
.workspace-leaf-content .view-content {
|
||||
padding: 0px !important;
|
||||
}
|
||||
${hideHeader?`
|
||||
.view-header {
|
||||
height: 1px !important;
|
||||
}`:""}
|
||||
.status-bar {
|
||||
display: none !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const oldStylesheet = document.getElementById(newStylesheet.id);
|
||||
if(oldStylesheet) document.head.removeChild(oldStylesheet);
|
||||
else document.head.appendChild(newStylesheet);
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
The script will delete the selected text elements from the canvas and will copy the text from these text elements into the Excalidraw markdown file as metadata. This means, that the text will no longer be visible in the drawing, however you will be able to search for the text in Obsidian and find the drawing containing this image.
|
||||
|
||||
See ScriptEngine documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
//get text elements
|
||||
|
||||
const textElements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
|
||||
if(textElements.length===0) {
|
||||
notice("No text elements were selected")
|
||||
return;
|
||||
}
|
||||
|
||||
metadata = "# Metadata\n" + textElements
|
||||
.map((el)=>el.rawText.replaceAll(/%|\^/g,"_")) //cleaning these characters for safety, might not be needed
|
||||
.join("/n") + "\n";
|
||||
|
||||
ea.deleteViewElements(textElements);
|
||||
await ea.targetView.save();
|
||||
data = await app.vault.read(ea.targetView.file);
|
||||
splitAfterFrontmatter = data.split(/(^---[\w\W]*?---\n)/);
|
||||
if(splitAfterFrontmatter.length !== 3) {
|
||||
notice("Error locating frontmatter in markdown file");
|
||||
console.log({file:ea.targetView.file});
|
||||
return;
|
||||
}
|
||||
newData = splitAfterFrontmatter[1]+metadata+splitAfterFrontmatter[2]
|
||||
await app.vault.modify(ea.targetView.file,newData);
|
||||
|
||||
//utility function
|
||||
function notice(message) {
|
||||
new Notice(message);
|
||||
console.log(message);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 60 500 450"><path d="M563.9 229.44V77.77c0-6.441-5.219-11.668-11.668-11.668h-151.67c-3.098 0-6.063 1.23-8.25 3.418l-252.79 252.79c-4.559 4.559-4.559 11.941 0 16.496l151.67 151.67a11.636 11.636 0 0 0 8.25 3.418c2.984 0 5.969-1.14 8.25-3.418l48.582-48.57c20.082 31.219 55.047 51.988 94.844 51.988 62.184 0 112.78-50.598 112.78-112.78 0-39.797-20.781-74.773-52-94.848l48.582-48.582a11.683 11.683 0 0 0 3.414-8.246zm-23.336 151.68c0 49.32-40.125 89.449-89.449 89.449-49.32 0-89.445-40.125-89.445-89.449 0-49.32 40.125-89.445 89.445-89.445 49.324 0 89.449 40.125 89.449 89.445zm0-156.51-50.723 50.723c-12.098-4.441-25.109-6.996-38.727-6.996-62.184 0-112.78 50.598-112.78 112.78 0 13.625 2.55 26.625 6.996 38.727l-45.887 45.89-135.17-135.17 241.12-241.12h135.17zm-64.176-34.043c20.371 0 36.945-16.578 36.945-36.949s-16.574-36.945-36.945-36.945-36.949 16.578-36.949 36.949c0 20.367 16.578 36.945 36.949 36.945zm0-50.562c7.508 0 13.613 6.106 13.613 13.613 0 7.508-6.106 13.613-13.613 13.613-7.508 0-13.613-6.106-13.613-13.613-.004-7.508 6.102-13.613 13.613-13.613zm-25.285 178.9c6.45 0 11.668 5.219 11.668 11.668v38.887l38.898-.004c6.45 0 11.668 5.219 11.668 11.668 0 6.45-5.219 11.668-11.668 11.668h-38.898v38.883c0 6.45-5.219 11.668-11.668 11.668a11.661 11.661 0 0 1-11.668-11.668v-38.887h-38.887c-6.45 0-11.668-5.219-11.668-11.668s5.219-11.668 11.668-11.668h38.887v-38.887c.004-6.445 5.223-11.66 11.668-11.66z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
348
ea-scripts/Archive/index.md
Normal file
@@ -0,0 +1,348 @@
|
||||
If you are enjoying the Excalidraw plugin then please support my work and enthusiasm by buying me a coffee on [https://ko-fi/zsolt](https://ko-fi.com/zsolt).
|
||||
|
||||
[<img src="https://user-images.githubusercontent.com/14358394/115450238-f39e8100-a21b-11eb-89d0-fa4b82cdbce8.png" class="coffee">](https://ko-fi.com/zsolt)
|
||||
|
||||
---
|
||||
|
||||
Jump ahead to the [[#List of available scripts]]
|
||||
|
||||
# Introducing Excalidraw Automate Script Engine
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/hePJcObHIso" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
|
||||
Script Engine scripts are installed in the `Downloaded` subfolder of the `Excalidraw Automate script folder` specified in plugin settings.
|
||||
|
||||
In the `Command Palette` installed scripts are prefixed with `Downloaded/`, thus you can always know if you are executing a local script of your own, or one that you have downloaded from GitHub.
|
||||
|
||||
## Attention developers and hobby hackers
|
||||
<img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/hobby-programmer.svg' align='left' style='background-color:whitesmoke; width:80px; margin-right:15px; margin-bottom:10px;'/>
|
||||
If you want to modify scripts, I recommend moving them to the `Excalidraw Automate script folder` or a different subfolder under the script folder. Scripts in the `Downloaded` folder will be overwritten when you click the `Update this script` button. Note also, that at this time, I do not check if the script file has been updated on GitHub, thus the `Update this script` button is always visible once you have installed a script, not only when an update is availble (hope to build this feature in the future).
|
||||
|
||||
I would love to include your contribution in the script library. If you have a script of your own that you would like to share with the community, please open a [PR](https://github.com/zsviczian/obsidian-excalidraw-plugin/pulls) on GitHub. Be sure to include the following in your pull request
|
||||
- The [script file](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/ea-scripts) with a self explanetory name. The name of the file will be the name of the script in the Command Palette.
|
||||
- An [image](https://github.com/zsviczian/obsidian-excalidraw-plugin/tree/master/images) explaining the scripts purpose. Remember a picture speaks thousand words!
|
||||
- An update to this file [ea-scripts/index.md](https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/index.md)
|
||||
|
||||
---
|
||||
|
||||
# List of available scripts
|
||||
- [[#Add Connector Point]]
|
||||
- [[#Add Link to Existing File and Open]]
|
||||
- [[#Add Link to New Page and Open]]
|
||||
- [[#Add Next Step in Process]]
|
||||
- [[#Box Each Selected Groups]]
|
||||
- [[#Box Selected Elements]]
|
||||
- [[#Change shape of selected elements]]
|
||||
- [[#Connect elements]]
|
||||
- [[#Convert freedraw to line]]
|
||||
- [[#Convert selected text elements to sticky notes]]
|
||||
- [[#Convert text to link with folder and alias]]
|
||||
- [[#Copy Selected Element Styles to Global]]
|
||||
- [[#Create new markdown file and embed into active drawing]]
|
||||
- [[#Darken background color]]
|
||||
- [[#Elbow connectors]]
|
||||
- [[#Expand rectangles horizontally keep text centered]]
|
||||
- [[#Expand rectangles horizontally]]
|
||||
- [[#Expand rectangles vertically keep text centered]]
|
||||
- [[#Expand rectangles vertically]]
|
||||
- [[#Fixed horizontal distance between centers]]
|
||||
- [[#Fixed inner distance]]
|
||||
- [[#Fixed spacing]]
|
||||
- [[#Fixed vertical distance between centers]]
|
||||
- [[#Fixed vertical distance]]
|
||||
- [[#Lighten background color]]
|
||||
- [[Mindmap connector]]
|
||||
- [[#Modify background color opacity]]
|
||||
- [[#Normalize Selected Arrows]]
|
||||
- [[#OCR - Optical Character Recognition]]
|
||||
- [[#Organic Line]]
|
||||
- [[#Repeat Elements]]
|
||||
- [[#Reverse arrows]]
|
||||
- [[#Scribble Helper]]
|
||||
- [[#Select Elements of Type]]
|
||||
- [[#Set background color of unclosed line object by adding a shadow clone]]
|
||||
- [[#Set Dimensions]]
|
||||
- [[#Set Font Family]]
|
||||
- [[#Set Grid]]
|
||||
- [[#Set Link Alias]]
|
||||
- [[#Set Stroke Width of Selected Elements]]
|
||||
- [[#Set Text Alignment]]
|
||||
- [[#Split text by lines]]
|
||||
- [[#Toggle Fullscreen on Mobile]]
|
||||
- [[#Transfer TextElements to Excalidraw markdown metadata]]
|
||||
- [[#Zoom to Fit Selected Elements]]
|
||||
|
||||
## Add Connector Point
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Connector%20Point.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Add%20Connector%20Point.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will add a small circle to the top left of each text element in the selection and add the text and the "connector point" to a group. You can use the connector points to link text elements with an arrow (in for example a Wardley Map).<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-bullet-point.jpg'></td></tr></table>
|
||||
|
||||
## Add Link to Existing File and Open
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Link%20to%20Existing%20File%20and%20Open.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Add%20Link%20to%20Existing%20File%20and%20Open.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Prompts for a file from the vault. Adds a link to the selected element pointing to the selected file. You can control in settings to open the file in the current active pane or an adjacent pane.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-add-link-and-open.jpg'></td></tr></table>
|
||||
|
||||
## Add Link to New Page and Open
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Link%20to%20New%20Page%20and%20Open.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Add%20Link%20to%20New%20Page%20and%20Open.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Prompts for filename. Offers option to create and open a new Markdown or Excalidraw document. Adds link pointing to the new file, to the selected objects in the drawing. You can control in settings to open the file in the current active pane or an adjacent pane.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-add-link-to-new-page-and-pen.jpg'></td></tr></table>
|
||||
|
||||
## Add Next Step in Process
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Add%20Next%20Step%20in%20Process.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Add%20Next%20Step%20in%20Process.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will prompt you for the title of the process step, then will create a stick note with the text. If an element is selected then the script will connect this new step with an arrow to the previous step (the selected element). If no element is selected, then the script assumes this is the first step in the process and will only output the sticky note with the text that was entered.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-add-process-step.jpg'></td></tr></table>
|
||||
|
||||
## Box Each Selected Groups
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Box%20Each%20Selected%20Groups.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Box%20Each%20Selected%20Groups.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will add encapsulating boxes around each of the currently selected groups in Excalidraw.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-each-selected-groups.png'></td></tr></table>
|
||||
|
||||
## Box Selected Elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Box%20Selected%20Elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Box%20Selected%20Elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will add an encapsulating box around the currently selected elements in Excalidraw.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-elements.jpg'></td></tr></table>
|
||||
|
||||
## Change shape of selected elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Change%20shape%20of%20selected%20elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Change%20shape%20of%20selected%20elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The script allows you to change the shape of selected Rectangles, Diamonds and Ellipses.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-change-shape.jpg'></td></tr></table>
|
||||
|
||||
## Connect elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Connect%20elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Connect%20elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will connect two objects with an arrow. If either of the objects are a set of grouped elements (e.g. a text element grouped with an encapsulating rectangle), the script will identify these groups, and connect the arrow to the largest object in the group (assuming you want to connect the arrow to the box around the text element).<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-connect-elements.jpg'></td></tr></table>
|
||||
|
||||
## Convert freedraw to line
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Convert%20freedraw%20to%20line.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Convert%20freedraw%20to%20line.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Convert selected freedraw objects into editable lines. This will allow you to adjust your drawings by dragging line points and will also allow you to select shape fill in case of enclosed lines. You can adjust conversion point density in settings.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-convert-freedraw-to-line.jpg'></td></tr></table>
|
||||
|
||||
## Convert selected text elements to sticky notes
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Convert%20selected%20text%20elements%20to%20sticky%20notes.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Convert%20selected%20text%20elements%20to%20sticky%20notes.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Converts selected plain text elements to sticky notes with transparent background and transparent stroke color (default setting, can be changed in plugin settings). Essentially converts text element into a wrappable format.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-textelement-to-transparent-stickynote.png'></td></tr></table>
|
||||
|
||||
## Convert text to link with folder and alias
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Convert%20text%20to%20link%20with%20folder%20and%20alias.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Convert%20text%20to%20link%20with%20folder%20and%20alias.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Converts text elements to links pointing to a file in a selected folder and with the alias set as the original text. The script will prompt the user to select an existing folder from the vault.<br><code>original text</code> - <code>[[selected folder/original text|original text]]</code></td></tr></table>
|
||||
|
||||
## Copy Selected Element Styles to Global
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Copy%20Selected%20Element%20Styles%20to%20Global.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Copy%20Selected%20Element%20Styles%20to%20Global.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will copy styles of any selected element into Excalidraw's global styles.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-copy-selected-element-styles-to-global.png'></td></tr></table>
|
||||
|
||||
## Create new markdown file and embed into active drawing
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Create%20new%20markdown%20file%20and%20embed%20into%20active%20drawing.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Create%20new%20markdown%20file%20and%20embed%20into%20active%20drawing.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The script will prompt you for a filename, then create a new markdown document with the file name provided, open the new markdown document in an adjacent pane, and embed the markdown document into the active Excalidraw drawing.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-create-and-embed-new-markdown-file.jpg'></td></tr></table>
|
||||
|
||||
## Darken background color
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Darken%20background%20color.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Darken%20background%20color.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script darkens the background color of the selected element by 2% at a time. You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect. In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/darken-lighten-background-color.png'></td></tr></table>
|
||||
|
||||
## Elbow connectors
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Elbow%20connectors.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Elbow%20connectors.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script converts the selected connectors to elbows.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/elbow-connectors.png'></td></tr></table>
|
||||
|
||||
## Expand rectangles horizontally keep text centered
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Expand%20rectangles%20horizontally%20keep%20text%20centered.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Expand%20rectangles%20horizontally%20keep%20text%20centered.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script expands the width of the selected rectangles until they are all the same width and keep the text centered.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-expand-rectangles.gif'></td></tr></table>
|
||||
|
||||
## Expand rectangles horizontally
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Expand%20rectangles%20horizontally.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Expand%20rectangles%20horizontally.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script expands the width of the selected rectangles until they are all the same width.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-expand-rectangles.gif'></td></tr></table>
|
||||
|
||||
## Expand rectangles vertically keep text centered
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Expand%20rectangles%20vertically%20keep%20text%20centered.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Expand%20rectangles%20vertically%20keep%20text%20centered.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script expands the height of the selected rectangles until they are all the same height and keep the text centered.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-expand-rectangles.gif'></td></tr></table>
|
||||
|
||||
## Expand rectangles vertically
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Expand%20rectangles%20vertically.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Expand%20rectangles%20vertically.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script expands the height of the selected rectangles until they are all the same height.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-expand-rectangles.gif'></td></tr></table>
|
||||
|
||||
## Fixed horizontal distance between centers
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Fixed%20horizontal%20distance%20between%20centers.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Fixed%20horizontal%20distance%20between%20centers.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script arranges the selected elements horizontally with a fixed center spacing.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-fixed-horizontal-distance-between-centers.png'></td></tr></table>
|
||||
|
||||
## Fixed inner distance
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Fixed%20inner%20distance.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Fixed%20inner%20distance.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script arranges selected elements and groups with a fixed inner distance.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-fixed-inner-distance.png'></td></tr></table>
|
||||
|
||||
## Fixed spacing
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Fixed%20spacing.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Fixed%20spacing.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The script arranges the selected elements horizontally with a fixed spacing. When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-fix-space-demo.png'></td></tr></table>
|
||||
|
||||
## Fixed vertical distance between centers
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Fixed%20vertical%20distance%20between%20centers.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Fixed%20vertical%20distance%20between%20centers.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script arranges the selected elements vertically with a fixed center spacing.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-fixed-vertical-distance-between-centers.png'></td></tr></table>
|
||||
|
||||
## Fixed vertical distance
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Fixed%20vertical%20distance.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Fixed%20vertical%20distance.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The script arranges the selected elements vertically with a fixed spacing. When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-fixed-vertical-distance.png'></td></tr></table>
|
||||
|
||||
## Lighten background color
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Lighten%20background%20color.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Lighten%20background%20color.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script lightens the background color of the selected element by 2% at a time. You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect.In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/darken-lighten-background-color.png'></td></tr></table>
|
||||
|
||||
## Mindmap connector
|
||||
```excalidraw-script-install
|
||||
https://github.com/xllowl/obsidian-excalidraw-plugin/blob/master/ea-scripts/Mindmap%20connector.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/xllowl'>@xllowl</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/xllowl/obsidian-excalidraw-plugin/blob/master/ea-scripts/Mindmap%20connector.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script creates mindmap like lines(only right side available). The line will starts according to the creation time of the elements. So you may need to create the header element first.<br><img src='https://github.com/xllowl/obsidian-excalidraw-plugin/blob/master/images/mindmap%20connector.png'></td></tr></table>
|
||||
|
||||
## Modify background color opacity
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Modify%20background%20color%20opacity.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Modify%20background%20color%20opacity.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script changes the opacity of the background color of the selected boxes. The default background color in Excalidraw is so dark that the text is hard to read. You can lighten the color a bit by setting transparency. And you can tweak the transparency over and over again until you're happy with it. Although excalidraw has the opacity option in its native property Settings, it also changes the transparency of the border. Use this script to change only the opacity of the background color without affecting the border.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-modify-background-color-opacity.png'></td></tr></table>
|
||||
|
||||
## Normalize Selected Arrows
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Normalize%20Selected%20Arrows.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Normalize%20Selected%20Arrows.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will reset the start and end positions of the selected arrows. The arrow will point to the center of the connected box and will have a gap of 8px from the box.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-normalize-selected-arrows.png'></td></tr></table>
|
||||
|
||||
## OCR - Optical Character Recognition
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/OCR%20-%20Optical%20Character%20Recognition.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/OCR%20-%20Optical%20Character%20Recognition.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">REQUIRES EXCALIDRAW 1.5.15<br>The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and 2) will add the text to your drawing as a text element.<br><mark>⚠ Note that you will need to manually paste your token into the script after the first run! ⚠</mark><br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-ocr.jpg'><br><iframe width="560" height="315" src="https://www.youtube.com/embed/W2NMzR8s4eE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></td></tr></table>
|
||||
|
||||
## Organic Line
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Organic%20Line.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Organic%20Line.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Converts selected freedraw lines such that pencil pressure will decrease from maximum to minimum from the beginning of the line to its end. The resulting line is placed at the back of the layers, under all other items. Helpful when drawing organic mindmaps.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-organic-line.jpg'></td></tr></table>
|
||||
|
||||
## Repeat Elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Repeat%20Elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/1-2-3'>@1-2-3</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Repeat%20Elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will detect the difference between 2 selected elements, including position, size, angle, stroke and background color, and create several elements that repeat these differences based on the number of repetitions entered by the user.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-repeat-elements.png'></td></tr></table>
|
||||
|
||||
## Reverse arrows
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Reverse%20arrows.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Reverse%20arrows.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Reverse the direction of **arrows** within the scope of selected elements.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-reverse-arrow.jpg'></td></tr></table>
|
||||
|
||||
## Scribble Helper
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Scribble%20Helper.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Scribble%20Helper.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">iOS scribble helper for better handwriting experience with text elements. If no elements are selected then the creates a text element at pointer position and you can use the edit box to modify the text with scribble. If a text element is selected then opens the input prompt where you can modify this text with scribble.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-scribble-helper.jpg'></td></tr></table>
|
||||
|
||||
## Select Elements of Type
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Select%20Elements%20of%20Type.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Select%20Elements%20of%20Type.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Prompts you with a list of the different element types in the active image. Only elements of the selected type will be selected on the canvas. If nothing is selected when running the script, then the script will process all the elements on the canvas. If some elements are selected when the script is executed, then the script will only process the selected elements.<br>The script is useful when, for example, you want to bring to front all the arrows, or want to change the color of all the text elements, etc.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-select-element-of-type.jpg'></td></tr></table>
|
||||
|
||||
## Set background color of unclosed line object by adding a shadow clone
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20background%20color%20of%20unclosed%20line%20object%20by%20adding%20a%20shadow%20clone.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20background%20color%20of%20unclosed%20line%20object%20by%20adding%20a%20shadow%20clone.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Use this script to set the background color of unclosed (i.e. open) line objects by creating a clone of the object. The script will set the stroke color of the clone to transparent and will add a straight line to close the object. Use settings to define the default background color, the fill style, and the strokeWidth of the clone. By default the clone will be grouped with the original object, you can disable this also in settings.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-set-background-color-of-unclosed-line.jpg'></td></tr></table>
|
||||
|
||||
## Set Dimensions
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Dimensions.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Dimensions.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Currently there is no way to specify the exact location and size of objects in Excalidraw. You can bridge this gap with the following simple script.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-dimensions.jpg'></td></tr></table>
|
||||
|
||||
## Set Font Family
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Font%20Family.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Font%20Family.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Sets font family of the text block (Virgil, Helvetica, Cascadia). Useful if you want to set a keyboard shortcut for selecting font family.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-font-family.jpg'></td></tr></table>
|
||||
|
||||
## Set Grid
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Grid.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Grid.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The default grid size in Excalidraw is 20. Currently there is no way to change the grid size via the user interface. This script offers a way to bridge this gap.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-grid.jpg'></td></tr></table>
|
||||
|
||||
## Set Link Alias
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Link%20Alias.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Link%20Alias.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Iterates all of the links in the selected TextElements and prompts the user to set or modify the alias for each link found.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-set-link-alias.jpg'></td></tr></table>
|
||||
|
||||
## Set Stroke Width of Selected Elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Stroke%20Width%20of%20Selected%20Elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Stroke%20Width%20of%20Selected%20Elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">This script will set the stroke width of selected elements. This is helpful, for example, when you scale freedraw sketches and want to reduce or increase their line width.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-stroke-width.jpg'></td></tr></table>
|
||||
|
||||
## Set Text Alignment
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Set%20Text%20Alignment.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Set%20Text%20Alignment.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Sets text alignment of text block (cetner, right, left). Useful if you want to set a keyboard shortcut for selecting text alignment.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-text-align.jpg'></td></tr></table>
|
||||
|
||||
## Split text by lines
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Split%20text%20by%20lines.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Split%20text%20by%20lines.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Split lines of text into separate text elements for easier reorganization<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-split-lines.jpg'></td></tr></table>
|
||||
|
||||
## TheBrain-navigation
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/TheBrain-navigation.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/TheBrain-navigation.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">An Excalidraw based graph user interface for your Vault. Requires the <a href='https://github.com/SkepticMystic/breadcrumbs'>Breadcrumbs plugin</a> to be installed and configured as well. Generates a user interface similar to that of <a href='https://TheBrain.com'>TheBrain</a>. Watch this introduction to this script on <a href='https://youtu.be/J4T5KHERH_o'>YouTube</a>.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/TheBrain.jpg'></td></tr></table>
|
||||
|
||||
## Toggle Fullscreen on Mobile
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Toggle%20Fullscreen%20on%20Mobile.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Toggle%20Fullscreen%20on%20Mobile.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Hides Obsidian workspace leaf padding and header (based on option in settings, default is "hide header" = false) which will take Excalidraw to full screen. ⚠ Note that if the header is not visible, it will be very difficult to invoke the command palette to end full screen. Only hide the header if you have a keyboard or you've practiced opening command palette!<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/ea-toggle-fullscreen.jpg'></td></tr></table>
|
||||
|
||||
## Transfer TextElements to Excalidraw markdown metadata
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Transfer%20TextElements%20to%20Excalidraw%20markdown%20metadata.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Transfer%20TextElements%20to%20Excalidraw%20markdown%20metadata.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">The script will delete the selected text elements from the canvas and will copy the text from these text elements into the Excalidraw markdown file as metadata. This means, that the text will no longer be visible in the drawing, however you will be able to search for the text in Obsidian and find the drawing containing this image.<br><img src='https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-text-to-metadata.jpg'></td></tr></table>
|
||||
|
||||
## Zoom to Fit Selected Elements
|
||||
```excalidraw-script-install
|
||||
https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Zoom%20to%20Fit%20Selected%20Elements.md
|
||||
```
|
||||
<table><tr valign='top'><td class="label">Author</td><td class="data"><a href='https://github.com/zsviczian'>@zsviczian</a></td></tr><tr valign='top'><td class="label">Source</td><td class="data"><a href='https://github.com/zsviczian/obsidian-excalidraw-plugin/blob/master/ea-scripts/Zoom%20to%20Fit%20Selected%20Elements.md'>File on GitHub</a></td></tr><tr valign='top'><td class="label">Description</td><td class="data">Similar to Excalidraw standard <kbd>SHIFT+2</kbd> feature: Zoom to fit selected elements, but with the ability to zoom to 1000%. Inspiration: [#272](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/272)</td></tr></table>
|
||||
399
ea-scripts/Auto Layout.md
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script performs automatic layout for the selected top-level grouping objects. It is powered by [elkjs](https://github.com/kieler/elkjs) and needs to be connected to the Internet.
|
||||
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if (
|
||||
!ea.verifyMinimumPluginVersion ||
|
||||
!ea.verifyMinimumPluginVersion("1.5.21")
|
||||
) {
|
||||
new Notice(
|
||||
"This script requires a newer version of Excalidraw. Please install the latest version."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if (!settings["Layout Options JSON"]) {
|
||||
settings = {
|
||||
"Layout Options JSON": {
|
||||
height: "450px",
|
||||
value: `{\n "org.eclipse.elk.layered.crossingMinimization.semiInteractive": "true",\n "org.eclipse.elk.layered.considerModelOrder.components": "FORCE_MODEL_ORDER"\n}`,
|
||||
description: `You can use layout options to configure the layout algorithm. A list of all options and further details of their exact effects is available in <a href="http://www.eclipse.org/elk/reference.html" rel="nofollow">ELK's documentation</a>.`,
|
||||
},
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
if (typeof ELK === "undefined") {
|
||||
loadELK(doAutoLayout);
|
||||
} else {
|
||||
doAutoLayout();
|
||||
}
|
||||
|
||||
async function doAutoLayout() {
|
||||
const selectedElements = ea.getViewSelectedElements();
|
||||
const groups = ea
|
||||
.getMaximumGroups(selectedElements)
|
||||
.map((g) => g.filter((el) => el.containerId == null)) // ignore text in stickynote
|
||||
.filter((els) => els.length > 0);
|
||||
|
||||
const stickynotesMap = selectedElements
|
||||
.filter((el) => el.containerId != null)
|
||||
.reduce((result, el) => {
|
||||
result.set(el.containerId, el);
|
||||
return result;
|
||||
}, new Map());
|
||||
|
||||
const elk = new ELK();
|
||||
const knownLayoutAlgorithms = await elk.knownLayoutAlgorithms();
|
||||
const layoutAlgorithms = knownLayoutAlgorithms
|
||||
.map((knownLayoutAlgorithm) => ({
|
||||
id: knownLayoutAlgorithm.id,
|
||||
displayText:
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.layered" ||
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.radial" ||
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.mrtree"
|
||||
? "* " +
|
||||
knownLayoutAlgorithm.name +
|
||||
": " +
|
||||
knownLayoutAlgorithm.description
|
||||
: knownLayoutAlgorithm.name + ": " + knownLayoutAlgorithm.description,
|
||||
}))
|
||||
.sort((lha, rha) => lha.displayText.localeCompare(rha.displayText));
|
||||
|
||||
const layoutAlgorithmsSimple = knownLayoutAlgorithms
|
||||
.map((knownLayoutAlgorithm) => ({
|
||||
id: knownLayoutAlgorithm.id,
|
||||
displayText:
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.layered" ||
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.radial" ||
|
||||
knownLayoutAlgorithm.id === "org.eclipse.elk.mrtree"
|
||||
? "* " + knownLayoutAlgorithm.name
|
||||
: knownLayoutAlgorithm.name,
|
||||
}))
|
||||
.sort((lha, rha) => lha.displayText.localeCompare(rha.displayText));
|
||||
|
||||
// const knownOptions = knownLayoutAlgorithms
|
||||
// .reduce(
|
||||
// (result, knownLayoutAlgorithm) => [
|
||||
// ...result,
|
||||
// ...knownLayoutAlgorithm.knownOptions,
|
||||
// ],
|
||||
// []
|
||||
// )
|
||||
// .filter((value, index, self) => self.indexOf(value) === index) // remove duplicates
|
||||
// .sort((lha, rha) => lha.localeCompare(rha));
|
||||
// console.log("knownOptions", knownOptions);
|
||||
|
||||
const selectedAlgorithm = await utils.suggester(
|
||||
layoutAlgorithms.map((algorithmInfo) => algorithmInfo.displayText),
|
||||
layoutAlgorithms.map((algorithmInfo) => algorithmInfo.id),
|
||||
"Layout algorithm"
|
||||
);
|
||||
|
||||
const knownNodePlacementStrategy = [
|
||||
"SIMPLE",
|
||||
"INTERACTIVE",
|
||||
"LINEAR_SEGMENTS",
|
||||
"BRANDES_KOEPF",
|
||||
"NETWORK_SIMPLEX",
|
||||
];
|
||||
|
||||
const knownDirections = [
|
||||
"UNDEFINED",
|
||||
"RIGHT",
|
||||
"LEFT",
|
||||
"DOWN",
|
||||
"UP"
|
||||
];
|
||||
|
||||
let nodePlacementStrategy = "BRANDES_KOEPF";
|
||||
let componentComponentSpacing = "10";
|
||||
let nodeNodeSpacing = "100";
|
||||
let nodeNodeBetweenLayersSpacing = "100";
|
||||
let discoComponentLayoutAlgorithm = "org.eclipse.elk.layered";
|
||||
let direction = "UNDEFINED";
|
||||
|
||||
if (selectedAlgorithm === "org.eclipse.elk.layered") {
|
||||
nodePlacementStrategy = await utils.suggester(
|
||||
knownNodePlacementStrategy,
|
||||
knownNodePlacementStrategy,
|
||||
"Node placement strategy"
|
||||
);
|
||||
|
||||
selectedDirection = await utils.suggester(
|
||||
knownDirections,
|
||||
knownDirections,
|
||||
"Direction"
|
||||
);
|
||||
direction = selectedDirection??"UNDEFINED";
|
||||
} else if (selectedAlgorithm === "org.eclipse.elk.disco") {
|
||||
const componentLayoutAlgorithms = layoutAlgorithmsSimple.filter(al => al.id !== "org.eclipse.elk.disco");
|
||||
const selectedDiscoComponentLayoutAlgorithm = await utils.suggester(
|
||||
componentLayoutAlgorithms.map((algorithmInfo) => algorithmInfo.displayText),
|
||||
componentLayoutAlgorithms.map((algorithmInfo) => algorithmInfo.id),
|
||||
"Disco Connected Components Layout Algorithm"
|
||||
);
|
||||
discoComponentLayoutAlgorithm = selectedDiscoComponentLayoutAlgorithm??"org.eclipse.elk.layered";
|
||||
}
|
||||
|
||||
if (
|
||||
selectedAlgorithm === "org.eclipse.elk.box" ||
|
||||
selectedAlgorithm === "org.eclipse.elk.rectpacking"
|
||||
) {
|
||||
nodeNodeSpacing = await utils.inputPrompt("Node Spacing", "number", "10");
|
||||
} else {
|
||||
let userSpacingStr = await utils.inputPrompt(
|
||||
"Components Spacing, Node Spacing, Node Node Between Layers Spacing",
|
||||
"number, number, number",
|
||||
"10, 100, 100"
|
||||
);
|
||||
let userSpacingArr = (userSpacingStr??"").split(",");
|
||||
componentComponentSpacing = userSpacingArr[0] ?? "10";
|
||||
nodeNodeSpacing = userSpacingArr[1] ?? "100";
|
||||
nodeNodeBetweenLayersSpacing = userSpacingArr[2] ?? "100";
|
||||
}
|
||||
|
||||
let layoutOptionsJson = {};
|
||||
try {
|
||||
layoutOptionsJson = JSON.parse(settings["Layout Options JSON"].value);
|
||||
} catch (e) {
|
||||
new Notice(
|
||||
"Error reading Layout Options JSON, see developer console for more information",
|
||||
4000
|
||||
);
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
layoutOptionsJson["elk.algorithm"] = selectedAlgorithm;
|
||||
layoutOptionsJson["org.eclipse.elk.spacing.componentComponent"] =
|
||||
componentComponentSpacing;
|
||||
layoutOptionsJson["org.eclipse.elk.spacing.nodeNode"] = nodeNodeSpacing;
|
||||
layoutOptionsJson["org.eclipse.elk.layered.spacing.nodeNodeBetweenLayers"] =
|
||||
nodeNodeBetweenLayersSpacing;
|
||||
layoutOptionsJson["org.eclipse.elk.layered.nodePlacement.strategy"] =
|
||||
nodePlacementStrategy;
|
||||
layoutOptionsJson["org.eclipse.elk.disco.componentCompaction.componentLayoutAlgorithm"] =
|
||||
discoComponentLayoutAlgorithm;
|
||||
layoutOptionsJson["org.eclipse.elk.direction"] = direction;
|
||||
|
||||
const graph = {
|
||||
id: "root",
|
||||
layoutOptions: layoutOptionsJson,
|
||||
children: [],
|
||||
edges: [],
|
||||
};
|
||||
|
||||
let groupMap = new Map();
|
||||
let targetElkMap = new Map();
|
||||
let arrowEls = [];
|
||||
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
const elements = groups[i];
|
||||
if (
|
||||
elements.length === 1 &&
|
||||
(elements[0].type === "arrow" || elements[0].type === "line")
|
||||
) {
|
||||
if (
|
||||
elements[0].type === "arrow" &&
|
||||
elements[0].startBinding &&
|
||||
elements[0].endBinding
|
||||
) {
|
||||
arrowEls.push(elements[0]);
|
||||
}
|
||||
} else {
|
||||
let elkId = "g" + i;
|
||||
elements.reduce((result, el) => {
|
||||
result.set(el.id, elkId);
|
||||
return result;
|
||||
}, targetElkMap);
|
||||
|
||||
const box = ea.getBoundingBox(elements);
|
||||
groupMap.set(elkId, {
|
||||
elements: elements,
|
||||
boundingBox: box,
|
||||
});
|
||||
|
||||
graph.children.push({
|
||||
id: elkId,
|
||||
width: box.width,
|
||||
height: box.height,
|
||||
x: box.topX,
|
||||
y: box.topY,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < arrowEls.length; i++) {
|
||||
const arrowEl = arrowEls[i];
|
||||
const startElkId = targetElkMap.get(arrowEl.startBinding.elementId);
|
||||
const endElkId = targetElkMap.get(arrowEl.endBinding.elementId);
|
||||
|
||||
graph.edges.push({
|
||||
id: "e" + i,
|
||||
sources: [startElkId],
|
||||
targets: [endElkId],
|
||||
});
|
||||
}
|
||||
|
||||
const initTopX =
|
||||
Math.min(...Array.from(groupMap.values()).map((v) => v.boundingBox.topX)) -
|
||||
12;
|
||||
const initTopY =
|
||||
Math.min(...Array.from(groupMap.values()).map((v) => v.boundingBox.topY)) -
|
||||
12;
|
||||
|
||||
elk
|
||||
.layout(graph)
|
||||
.then((resultGraph) => {
|
||||
for (const elkEl of resultGraph.children) {
|
||||
const group = groupMap.get(elkEl.id);
|
||||
for (const groupEl of group.elements) {
|
||||
const originalDistancX = groupEl.x - group.boundingBox.topX;
|
||||
const originalDistancY = groupEl.y - group.boundingBox.topY;
|
||||
const groupElDistanceX =
|
||||
elkEl.x + initTopX + originalDistancX - groupEl.x;
|
||||
const groupElDistanceY =
|
||||
elkEl.y + initTopY + originalDistancY - groupEl.y;
|
||||
|
||||
groupEl.x = groupEl.x + groupElDistanceX;
|
||||
groupEl.y = groupEl.y + groupElDistanceY;
|
||||
|
||||
if (stickynotesMap.has(groupEl.id)) {
|
||||
const stickynote = stickynotesMap.get(groupEl.id);
|
||||
stickynote.x = stickynote.x + groupElDistanceX;
|
||||
stickynote.y = stickynote.y + groupElDistanceY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(selectedElements);
|
||||
ea.addElementsToView(false, false);
|
||||
|
||||
normalizeSelectedArrows();
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
function loadELK(doAfterLoaded) {
|
||||
let script = document.createElement("script");
|
||||
script.onload = function () {
|
||||
if (typeof ELK !== "undefined") {
|
||||
doAfterLoaded();
|
||||
}
|
||||
};
|
||||
script.src =
|
||||
"https://cdn.jsdelivr.net/npm/elkjs@0.8.2/lib/elk.bundled.min.js";
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normalize Selected Arrows
|
||||
*/
|
||||
|
||||
function normalizeSelectedArrows() {
|
||||
let gapValue = 2;
|
||||
|
||||
const selectedIndividualArrows = ea.getMaximumGroups(ea.getViewSelectedElements())
|
||||
.reduce((result, g) => [...result, ...g.filter(el => el.type === 'arrow')], []);
|
||||
|
||||
const allElements = ea.getViewElements();
|
||||
for (const arrow of selectedIndividualArrows) {
|
||||
const startBindingEl = allElements.filter(
|
||||
(el) => el.id === (arrow.startBinding || {}).elementId
|
||||
)[0];
|
||||
const endBindingEl = allElements.filter(
|
||||
(el) => el.id === (arrow.endBinding || {}).elementId
|
||||
)[0];
|
||||
|
||||
if (startBindingEl) {
|
||||
recalculateStartPointOfLine(
|
||||
arrow,
|
||||
startBindingEl,
|
||||
endBindingEl,
|
||||
gapValue
|
||||
);
|
||||
}
|
||||
if (endBindingEl) {
|
||||
recalculateEndPointOfLine(arrow, endBindingEl, startBindingEl, gapValue);
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(selectedIndividualArrows);
|
||||
ea.addElementsToView(false, false);
|
||||
}
|
||||
|
||||
function recalculateStartPointOfLine(line, el, elB, gapValue) {
|
||||
const aX = el.x + el.width / 2;
|
||||
const bX =
|
||||
line.points.length <= 2 && elB
|
||||
? elB.x + elB.width / 2
|
||||
: line.x + line.points[1][0];
|
||||
const aY = el.y + el.height / 2;
|
||||
const bY =
|
||||
line.points.length <= 2 && elB
|
||||
? elB.y + elB.height / 2
|
||||
: line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = gapValue;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if (intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for (let i = 1; i < line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el, elB, gapValue) {
|
||||
const aX = el.x + el.width / 2;
|
||||
const bX =
|
||||
line.points.length <= 2 && elB
|
||||
? elB.x + elB.width / 2
|
||||
: line.x + line.points[line.points.length - 2][0];
|
||||
const aY = el.y + el.height / 2;
|
||||
const bY =
|
||||
line.points.length <= 2 && elB
|
||||
? elB.y + elB.height / 2
|
||||
: line.y + line.points[line.points.length - 2][1];
|
||||
|
||||
line.endBinding.gap = gapValue;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if (intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [
|
||||
intersectA[0][0] - line.x,
|
||||
intersectA[0][1] - line.y,
|
||||
];
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Auto Layout.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1670131481615" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3504" width="128" height="128" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M947.2 0H76.8C33.6 0 0 33.6 0 76.8v870.4C0 990.4 33.6 1024 76.8 1024h870.4c38.4 0 72-30.4 76.8-68.8V76.8C1024 33.6 990.4 0 947.2 0zM84.8 84.8h852.8V256H84.8V84.8z m256 256h596.8v256H340.8v-256z m-256 598.4V340.8H256v596.8H84.8z m256 0v-256h596.8v256H340.8z" p-id="3505"></path></svg>
|
||||
|
After Width: | Height: | Size: 616 B |
181
ea-scripts/Box Each Selected Groups.md
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script will add encapsulating boxes around each of the currently selected groups in Excalidraw.
|
||||
|
||||
You can focus on content creation first, and then batch add consistent style boxes to each group of text.
|
||||
|
||||
Tips 1: You can copy the desired style to the global state using script `Copy Selected Element Style to Global`, then add boxes with the same global style using script `Box Each Selected Groups`.
|
||||
|
||||
Tips 2: Next you can use scripts `Expand rectangles horizontally keep text centered` and `Expand rectangles vertically keep text centered` to make the boxes the same size, if you wish.
|
||||
|
||||
Tips 3: If you want the left and right margins to be different from the top and bottom margins, input something like `32,16`, this will create a box with left and right margins of `32` and top and bottom margins of `16`.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default padding"]) {
|
||||
settings = {
|
||||
"Prompt for padding?": true,
|
||||
"Default padding" : {
|
||||
value: 10,
|
||||
description: "Padding between the bounding box of the selected elements, and the box the script creates"
|
||||
},
|
||||
"Remember last padding?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let paddingStr = settings["Default padding"].value.toString();
|
||||
const rememberLastPadding = settings["Remember last padding?"];
|
||||
|
||||
if(settings["Prompt for padding?"]) {
|
||||
paddingStr = await utils.inputPrompt("padding?","string",paddingStr);
|
||||
}
|
||||
if(!paddingStr) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastPadding) {
|
||||
settings["Default padding"].value = paddingStr;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
var paddingLR = 0;
|
||||
var paddingTB = 0;
|
||||
if(paddingStr.indexOf(',') > 0) {
|
||||
const paddingParts = paddingStr.split(',');
|
||||
paddingLR = parseInt(paddingParts[0]);
|
||||
paddingTB = parseInt(paddingParts[1]);
|
||||
}
|
||||
else {
|
||||
paddingLR = paddingTB = parseInt(paddingStr);
|
||||
}
|
||||
|
||||
if(isNaN(paddingLR) || isNaN(paddingTB)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedElements = ea.getViewSelectedElements();
|
||||
const groups = ea.getMaximumGroups(selectedElements);
|
||||
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
||||
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ?
|
||||
[...result, group[0]] : result, []);
|
||||
for(const elements of groups) {
|
||||
if(elements.length === 1 && elements[0].type ==="arrow" || elements[0].type==="line") {
|
||||
// individual arrows or lines are not affected
|
||||
continue;
|
||||
}
|
||||
const box = ea.getBoundingBox(elements);
|
||||
color = ea
|
||||
.getExcalidrawAPI()
|
||||
.getAppState()
|
||||
.currentItemStrokeColor;
|
||||
// use current stroke with and style
|
||||
const appState = ea.getExcalidrawAPI().getAppState();
|
||||
const strokeWidth = appState.currentItemStrokeWidth;
|
||||
const strokeStyle = appState.currentItemStrokeStyle;
|
||||
const strokeSharpness = appState.currentItemStrokeSharpness;
|
||||
const roughness = appState.currentItemRoughness;
|
||||
const fillStyle = appState.currentItemFillStyle;
|
||||
const backgroundColor = appState.currentItemBackgroundColor;
|
||||
ea.style.strokeWidth = strokeWidth;
|
||||
ea.style.strokeStyle = strokeStyle;
|
||||
ea.style.strokeSharpness = strokeSharpness;
|
||||
ea.style.roughness = roughness;
|
||||
ea.style.fillStyle = fillStyle;
|
||||
ea.style.backgroundColor = backgroundColor;
|
||||
ea.style.strokeColor = color;
|
||||
|
||||
const id = ea.addRect(
|
||||
box.topX - paddingLR,
|
||||
box.topY - paddingTB,
|
||||
box.width + 2*paddingLR,
|
||||
box.height + 2*paddingTB
|
||||
);
|
||||
|
||||
// Change the join point in the group to the new box
|
||||
const elementsWithBounded = elements.filter(el => (el.boundElements || []).length > 0);
|
||||
const boundedElementsCollection = elementsWithBounded.reduce((result, el) => [...result, ...el.boundElements], []);
|
||||
for(const el of elementsWithBounded) {
|
||||
el.boundElements = [];
|
||||
}
|
||||
|
||||
const newRect = ea.getElement(id);
|
||||
newRect.boundElements = boundedElementsCollection;
|
||||
|
||||
const elementIds = elements.map(el => el.id);
|
||||
|
||||
const startBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.startBinding||{}).elementId));
|
||||
for(startBindingLine of startBindingLines) {
|
||||
startBindingLine.startBinding.elementId = id;
|
||||
recalculateStartPointOfLine(startBindingLine, newRect);
|
||||
}
|
||||
|
||||
const endBindingLines = allIndividualArrows.filter(el => elementIds.includes((el.endBinding||{}).elementId));
|
||||
for(endBindingLine of endBindingLines) {
|
||||
endBindingLine.endBinding.elementId = id;
|
||||
recalculateEndPointOfLine(endBindingLine, newRect);
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
|
||||
}
|
||||
|
||||
await ea.addElementsToView(false,false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = 8;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = 8;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Box Each Selected Groups.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 250 160" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 30h70m-70 0h70M10 20h70m-70 0h70M60 55c0 .87-.08 1.75-.23 2.6-.15.86-.38 1.71-.67 2.53-.3.82-.68 1.62-1.11 2.37-.43.75-.94 1.48-1.5 2.14-.56.67-1.18 1.29-1.85 1.85-.66.56-1.39 1.07-2.14 1.5-.75.43-1.55.81-2.37 1.11-.82.29-1.67.52-2.53.67-.85.15-1.73.23-2.6.23-.87 0-1.75-.08-2.6-.23-.86-.15-1.71-.38-2.53-.67-.82-.3-1.62-.68-2.37-1.11-.75-.43-1.48-.94-2.14-1.5-.67-.56-1.29-1.18-1.85-1.85-.56-.66-1.07-1.39-1.5-2.14-.43-.75-.81-1.55-1.11-2.37-.29-.82-.52-1.67-.67-2.53-.15-.85-.23-1.73-.23-2.6 0-.87.08-1.75.23-2.6.15-.86.38-1.71.67-2.53.3-.82.68-1.62 1.11-2.37.43-.75.94-1.48 1.5-2.14.56-.67 1.18-1.29 1.85-1.85.66-.56 1.39-1.07 2.14-1.5.75-.43 1.55-.81 2.37-1.11.82-.29 1.67-.52 2.53-.67.85-.15 1.73-.23 2.6-.23.87 0 1.75.08 2.6.23.86.15 1.71.38 2.53.67.82.3 1.62.68 2.37 1.11.75.43 1.48.94 2.14 1.5.67.56 1.29 1.18 1.85 1.85.56.66 1.07 1.39 1.5 2.14.43.75.81 1.55 1.11 2.37.29.82.52 1.67.67 2.53.15.85.19 2.17.23 2.6.04.43.04-.43 0 0M26 110c4.05 4.62 8.09 9.25 14 16m-14-16 14 16m0 0-14 14m14-14-14 14m0 0-16-14m16 14c-3.54-3.1-7.09-6.2-16-14m0 0 16-16m-16 16 16-16M50 110h30m-30 0h30M50 140h30m-30 0h30M160 30h70m-70 0h70M160 20h70m-70 0h70M210 55c0 .87-.08 1.75-.23 2.6-.15.86-.38 1.71-.67 2.53-.3.82-.68 1.62-1.11 2.37-.43.75-.94 1.48-1.5 2.14-.56.67-1.18 1.29-1.85 1.85-.66.56-1.39 1.07-2.14 1.5-.75.43-1.55.81-2.37 1.11-.82.29-1.67.52-2.53.67-.85.15-1.73.23-2.6.23-.87 0-1.75-.08-2.6-.23-.86-.15-1.71-.38-2.53-.67-.82-.3-1.62-.68-2.37-1.11-.75-.43-1.48-.94-2.14-1.5-.67-.56-1.29-1.18-1.85-1.85-.56-.66-1.07-1.39-1.5-2.14-.43-.75-.81-1.55-1.11-2.37-.29-.82-.52-1.67-.67-2.53-.15-.85-.23-1.73-.23-2.6 0-.87.08-1.75.23-2.6.15-.86.38-1.71.67-2.53.3-.82.68-1.62 1.11-2.37.43-.75.94-1.48 1.5-2.14.56-.67 1.18-1.29 1.85-1.85.66-.56 1.39-1.07 2.14-1.5.75-.43 1.55-.81 2.37-1.11.82-.29 1.67-.52 2.53-.67.85-.15 1.73-.23 2.6-.23.87 0 1.75.08 2.6.23.86.15 1.71.38 2.53.67.82.3 1.62.68 2.37 1.11.75.43 1.48.94 2.14 1.5.67.56 1.29 1.18 1.85 1.85.56.66 1.07 1.39 1.5 2.14.43.75.81 1.55 1.11 2.37.29.82.52 1.67.67 2.53.15.85.19 2.17.23 2.6.04.43.04-.43 0 0M176 110c4.53 5.17 9.05 10.34 14 16m-14-16c5.5 6.28 10.99 12.56 14 16m0 0-14 14m14-14-14 14m0 0-16-14m16 14c-5.47-4.79-10.94-9.57-16-14m0 0 16-16m-16 16 16-16M200 110h30m-30 0h30M200 140h30m-30 0h30M150 10h90m-90 0h90m0 0v70m0-70v70m0 0h-90m90 0h-90m0 0V10m0 70V10M150 100h90m-90 0h90m0 0v50m0-50v50m0 0h-90m90 0h-90m0 0v-50m0 50v-50"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m100 20 31.17 59.33-28.84 60L100 20"/><path fill="none" stroke-width="4" d="M100 20c11.09 21.12 22.19 42.24 31.17 59.33M100 20c9.23 17.58 18.47 35.16 31.17 59.33m0 0c-8.1 16.84-16.19 33.68-28.84 60m28.84-60c-10.41 21.65-20.81 43.3-28.84 60m0 0C101.45 94.2 100.57 49.07 100 20m2.33 119.33c-.57-29.27-1.15-58.55-2.33-119.33m0 0s0 0 0 0m0 0s0 0 0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
55
ea-scripts/Box Selected Elements.md
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||

|
||||
|
||||
This script will add an encapsulating box around the currently selected elements in Excalidraw.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default padding"]) {
|
||||
settings = {
|
||||
"Prompt for padding?": true,
|
||||
"Default padding" : {
|
||||
value: 10,
|
||||
description: "Padding between the bounding box of the selected elements, and the box the script creates"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let padding = settings["Default padding"].value;
|
||||
|
||||
if(settings["Prompt for padding?"]) {
|
||||
padding = parseInt (await utils.inputPrompt("padding?","number",padding.toString()));
|
||||
}
|
||||
|
||||
if(isNaN(padding)) {
|
||||
new Notice("The padding value provided is not a number");
|
||||
return;
|
||||
}
|
||||
elements = ea.getViewSelectedElements();
|
||||
const box = ea.getBoundingBox(elements);
|
||||
color = ea
|
||||
.getExcalidrawAPI()
|
||||
.getAppState()
|
||||
.currentItemStrokeColor;
|
||||
//uncomment for random color:
|
||||
//color = '#'+(Math.random()*0xFFFFFF<<0).toString(16).padStart(6,"0");
|
||||
ea.style.strokeColor = color;
|
||||
id = ea.addRect(
|
||||
box.topX - padding,
|
||||
box.topY - padding,
|
||||
box.width + 2*padding,
|
||||
box.height + 2*padding
|
||||
);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
|
||||
ea.addElementsToView(false,false);
|
||||
1
ea-scripts/Box Selected Elements.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="100 80 500 400"><path d="M164.27 110.96h158.32v-28H136.27v170.87h28zM377.42 110.96h158.32v142.87h28V82.96H377.42zM535.73 449.04H377.41v28h186.32V306.17h-28zM164.27 306.16h-28v170.87h186.32v-28H164.27z"/><path d="M197.86 220.36v119.3c0 42.34 34.445 76.789 76.793 76.789h150.68c42.348 0 76.793-34.445 76.793-76.789l.004-119.3c0-42.34-34.445-76.789-76.793-76.789h-150.69c-42.348-.004-76.793 34.445-76.793 76.789zm276.27 0v119.3c0 26.902-21.887 48.789-48.793 48.789l-150.69-.004c-26.906 0-48.793-21.887-48.793-48.789v-119.29c0-26.902 21.887-48.789 48.793-48.789h150.68c26.91-.004 48.797 21.88 48.797 48.79z"/></svg>
|
||||
|
After Width: | Height: | Size: 660 B |
52
ea-scripts/Change shape of selected elements.md
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||

|
||||
|
||||
The script allows you to change the shape and fill style of selected Rectangles, Diamonds, Ellipses, Lines, Arrows and Freedraw.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
const fillStylesDispaly=["Dots (⚠ VERY SLOW performance on large objects!)","Zigzag","Zigzag-line", "Dashed", "Hachure", "Cross-hatch", "Solid"];
|
||||
const fillStyles=["dots","zigzag","zigzag-line", "dashed", "hachure", "cross-hatch", "solid"];
|
||||
const fillShapes=["ellipse","rectangle","diamond", "freedraw", "line"];
|
||||
const boxShapesDispaly=["○ ellipse","□ rectangle","◇ diamond"];
|
||||
const boxShapes=["ellipse","rectangle","diamond"];
|
||||
const lineShapesDispaly=["- line","⭢ arrow"];
|
||||
const lineShapes=["line","arrow"];
|
||||
|
||||
let editedElements = [];
|
||||
|
||||
let elements = ea.getViewSelectedElements().filter(el=>boxShapes.contains(el.type));
|
||||
if (elements.length>0) {
|
||||
newShape = await utils.suggester(boxShapesDispaly, boxShapes, "Change shape of 'box' type elements in selection, press ESC to skip");
|
||||
if(newShape) {
|
||||
editedElements = elements;
|
||||
elements.forEach(el=>el.type = newShape);
|
||||
}
|
||||
}
|
||||
|
||||
elements = ea.getViewSelectedElements().filter(el=>fillShapes.contains(el.type));
|
||||
if (elements.length>0) {
|
||||
newFillStyle = await utils.suggester(fillStylesDispaly, fillStyles, "Change the fill style of elements in selection, press ESC to skip");
|
||||
if(newFillStyle) {
|
||||
editedElements = editedElements.concat(elements.filter(e=>!editedElements.some(el=>el.id===e.id)));
|
||||
elements.forEach(el=>el.fillStyle = newFillStyle);
|
||||
}
|
||||
}
|
||||
|
||||
elements = ea.getViewSelectedElements().filter(el=>lineShapes.contains(el.type));
|
||||
if (elements.length>0) {
|
||||
newShape = await utils.suggester(lineShapesDispaly, lineShapes, "Change shape of 'line' type elements in selection, press ESC to skip");
|
||||
if(newShape) {
|
||||
editedElements = editedElements.concat(elements.filter(e=>!editedElements.some(el=>el.id===e.id)));
|
||||
elements.forEach((el)=>{
|
||||
el.type = newShape;
|
||||
if(newShape === "arrow") {
|
||||
el.endArrowhead = "triangle";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(editedElements);
|
||||
|
||||
ea.addElementsToView(false,false);
|
||||
1
ea-scripts/Change shape of selected elements.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 170 70" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h60m-60 0h60m0 0v60m0-60v60m0 0H10m60 0H10m0 0V10m0 60V10M141 10c6.47 6.91 12.94 13.83 29 31m-29-31c9.29 9.93 18.57 19.86 29 31m0 0-29 29m29-29-29 29m0 0c-10.49-9.82-20.99-19.64-31-29m31 29c-7.35-6.88-14.71-13.76-31-29m0 0 31-31m-31 31 31-31"/><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M80 40h20m-20 0h20"/><path fill-rule="evenodd" stroke-width="0" d="m100 40-9.06 4.23v-8.46L100 40"/><path fill="none" stroke-width="4" d="M100 40c-3.14 1.47-6.29 2.93-9.06 4.23M100 40c-3.13 1.46-6.27 2.92-9.06 4.23m0 0v-8.46m0 8.46v-8.46m0 0c3.38 1.58 6.76 3.16 9.06 4.23m-9.06-4.23c2.17 1.02 4.34 2.03 9.06 4.23m0 0s0 0 0 0m0 0s0 0 0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 802 B |
81
ea-scripts/Connect elements.md
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||

|
||||
|
||||
This script will connect two objects with an arrow. If either of the objects are a set of grouped elements (e.g. a text element grouped with an encapsulating rectangle), the script will identify these groups, and connect the arrow to the largest object in the group (assuming you want to connect the arrow to the box around the text element).
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Starting arrowhead"]) {
|
||||
settings = {
|
||||
"Starting arrowhead" : {
|
||||
value: "none",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Ending arrowhead" : {
|
||||
value: "triangle",
|
||||
valueset: ["none","arrow","triangle","bar","dot"]
|
||||
},
|
||||
"Line points" : {
|
||||
value: 1,
|
||||
description: "Number of line points between start and end"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const arrowStart = settings["Starting arrowhead"].value === "none" ? null : settings["Starting arrowhead"].value;
|
||||
const arrowEnd = settings["Ending arrowhead"].value === "none" ? null : settings["Ending arrowhead"].value;
|
||||
const linePoints = Math.floor(settings["Line points"].value);
|
||||
|
||||
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
groups = ea.getMaximumGroups(elements);
|
||||
if(groups.length !== 2) {
|
||||
//unfortunately getMaxGroups returns duplicated resultset for sticky notes
|
||||
//needs additional filtering
|
||||
cleanGroups=[];
|
||||
idList = [];
|
||||
for (group of groups) {
|
||||
keep = true;
|
||||
for(item of group) if(idList.contains(item.id)) keep = false;
|
||||
if(keep) {
|
||||
cleanGroups.push(group);
|
||||
idList = idList.concat(group.map(el=>el.id))
|
||||
}
|
||||
}
|
||||
if(cleanGroups.length !== 2) return;
|
||||
groups = cleanGroups;
|
||||
}
|
||||
els = [
|
||||
ea.getLargestElement(groups[0]),
|
||||
ea.getLargestElement(groups[1])
|
||||
];
|
||||
|
||||
ea.style.strokeColor = els[0].strokeColor;
|
||||
ea.style.strokeWidth = els[0].strokeWidth;
|
||||
ea.style.strokeStyle = els[0].strokeStyle;
|
||||
ea.style.strokeSharpness = els[0].strokeSharpness;
|
||||
ea.connectObjects(
|
||||
els[0].id,
|
||||
null,
|
||||
els[1].id,
|
||||
null,
|
||||
{
|
||||
endArrowHead: arrowEnd,
|
||||
startArrowHead: arrowStart,
|
||||
numberOfPoints: linePoints
|
||||
}
|
||||
);
|
||||
ea.addElementsToView(false,false,true);
|
||||
1
ea-scripts/Connect elements.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="5 5 170 70" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h60m-60 0h60m0 0v60m0-60v60m0 0H10m60 0H10m0 0V10m0 60V10"/><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M70 40h40m-40 0h40"/><path fill-rule="evenodd" stroke-width="0" d="m110 40-13.59 6.34V33.66L110 40"/><path fill="none" stroke-width="4" d="M110 40c-4.72 2.2-9.43 4.4-13.59 6.34M110 40c-4.7 2.19-9.4 4.38-13.59 6.34m0 0V33.66m0 12.68V33.66m0 0c5.07 2.37 10.14 4.73 13.59 6.34m-13.59-6.34c3.25 1.52 6.51 3.04 13.59 6.34m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M110 10h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0V10m0 60V10"/></svg>
|
||||
|
After Width: | Height: | Size: 753 B |
64
ea-scripts/Convert freedraw to line.md
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||

|
||||
|
||||
Convert selected freedraw objects into editable lines. This will allow you to adjust your drawings by dragging line points and will also allow you to select shape fill in case of enclosed lines. You can adjust conversion point density in settings.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Point density"]) {
|
||||
settings = {
|
||||
"Point density" : {
|
||||
value: "7:1",
|
||||
valueset: ["1:1","2:1","3:1","4:1","5:1","6:1","7:1","8:1","9:1","10:1","11:1"],
|
||||
description: "A freedraw object has many points. Converting freedraw to a line with too many points will result in an impractical object that is hard to edit. This setting sepcifies how many points from freedraw should be averaged to form a point on the line"
|
||||
},
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const scale = settings["Point density"].value;
|
||||
const setSize = parseInt(scale.substring(0,scale.indexOf(":")));
|
||||
|
||||
const elements = ea.getViewSelectedElements().filter(el=>el.type==="freedraw");
|
||||
if(elements.length === 0) {
|
||||
new Notice("No freedraw object is selected");
|
||||
}
|
||||
|
||||
|
||||
ea.style.roughness=0;
|
||||
ea.style.strokeSharpness="round";
|
||||
|
||||
elements.forEach((el)=>{
|
||||
points = [];
|
||||
points.push(el.points[0]);
|
||||
for(i=1;i<el.points.length;i+=setSize) {
|
||||
point = [0,0];
|
||||
count = 0;
|
||||
for(p of el.points.slice(i,i+setSize)) {
|
||||
point = [ point[0]+p[0] , point[1]+p[1] ];
|
||||
count++;
|
||||
}
|
||||
point = [point[0]/count,point[1]/count];
|
||||
points.push(point);
|
||||
}
|
||||
const lineId = ea.addLine(points);
|
||||
const line = ea.getElement(lineId);
|
||||
line.strokeWidth = el.strokeWidth*3;
|
||||
line.strokeColor = el.strokeColor;
|
||||
line.width = el.width;
|
||||
line.height = el.height;
|
||||
line.x = el.x;
|
||||
line.y = el.y;
|
||||
});
|
||||
|
||||
ea.deleteViewElements(elements);
|
||||
await ea.addElementsToView(false,false,true);
|
||||
ea.selectElementsInView(ea.getElements());
|
||||
1
ea-scripts/Convert freedraw to line.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M480 256c-17.67 0-32 14.31-32 32c0 52.94-43.06 96-96 96H192L192 344c0-9.469-5.578-18.06-14.23-21.94C169.1 318.3 159 319.8 151.9 326.2l-80 72C66.89 402.7 64 409.2 64 416s2.891 13.28 7.938 17.84l80 72C156.4 509.9 162.2 512 168 512c3.312 0 6.615-.6875 9.756-2.062C186.4 506.1 192 497.5 192 488L192 448h160c88.22 0 160-71.78 160-160C512 270.3 497.7 256 480 256zM160 128h159.1L320 168c0 9.469 5.578 18.06 14.23 21.94C337.4 191.3 340.7 192 343.1 192c5.812 0 11.57-2.125 16.07-6.156l80-72C445.1 109.3 448 102.8 448 95.1s-2.891-13.28-7.938-17.84l-80-72c-7.047-6.312-17.19-7.875-25.83-4.094C325.6 5.938 319.1 14.53 319.1 24L320 64H160C71.78 64 0 135.8 0 224c0 17.69 14.33 32 32 32s32-14.31 32-32C64 171.1 107.1 128 160 128z"/></svg>
|
||||
|
After Width: | Height: | Size: 794 B |
70
ea-scripts/Convert selected text elements to sticky notes.md
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||

|
||||
|
||||
Converts selected plain text elements to sticky notes with transparent background and transparent stroke color. Essentially converts text element into a wrappable format.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
let settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Border color"]) {
|
||||
settings = {
|
||||
"Border color" : {
|
||||
value: "#000000",
|
||||
description: "Any legal HTML color (#000000, rgb, color-name, etc.). Set to 'transparent' for transparent color."
|
||||
},
|
||||
"Background color" : {
|
||||
value: "transparent",
|
||||
description: "Background color of the sticky note. Set to 'transparent' for transparent color."
|
||||
},
|
||||
"Background fill style" : {
|
||||
value: "solid",
|
||||
description: "Fill style of the sticky note",
|
||||
valueset: ["hachure","cross-hatch","solid"]
|
||||
}
|
||||
};
|
||||
await ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
if(!settings["Max sticky note width"]) {
|
||||
settings["Max sticky note width"] = {
|
||||
value: "600",
|
||||
description: "Maximum width of new sticky note. If text is longer, it will be wrapped",
|
||||
valueset: ["400","600","800","1000","1200","1400","2000"]
|
||||
}
|
||||
await ea.setScriptSettings(settings);
|
||||
}
|
||||
const maxWidth = parseInt(settings["Max sticky note width"].value);
|
||||
const strokeColor = settings["Border color"].value;
|
||||
const backgroundColor = settings["Background color"].value;
|
||||
const fillStyle = settings["Background fill style"].value;
|
||||
|
||||
const elements = ea
|
||||
.getViewSelectedElements()
|
||||
.filter((el)=>(el.type==="text")&&(el.containerId===null));
|
||||
if(elements.length===0) {
|
||||
new Notice("Please select a text element");
|
||||
return;
|
||||
}
|
||||
ea.style.strokeColor = strokeColor;
|
||||
ea.style.backgroundColor = backgroundColor;
|
||||
ea.style.fillStyle = fillStyle;
|
||||
const padding = 6;
|
||||
const boxes = [];
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.getElements().forEach((el)=>{
|
||||
const width = el.width+2*padding;
|
||||
const widthOK = width<=maxWidth;
|
||||
const id = ea.addRect(el.x-padding,el.y-padding,widthOK?width:maxWidth,el.height+2*padding);
|
||||
boxes.push(id);
|
||||
ea.getElement(id).boundElements=[{type:"text",id:el.id}];
|
||||
el.containerId = id;
|
||||
});
|
||||
await ea.addElementsToView(false,true);
|
||||
const containers = ea.getViewElements().filter(el=>boxes.includes(el.id));
|
||||
ea.getExcalidrawAPI().updateContainerSize(containers);
|
||||
ea.selectElementsInView(containers);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170 90" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M100 10h40m-40 0h40m0 0 20 20m-20-20 20 20m0 0v50m0-50v50m0 0h-60m60 0h-60m0 0V10m0 70V10M140 10v20m0-20v20m0 0h20m-20 0h20M110 40c11.87.13 23.73.26 31 .33M110 40c6.44.07 12.89.14 31 .33M110 50c10.03.11 20.05.22 31 .33M110 50l31 .33M110 60c9.93.11 19.86.21 31 .33M110 60c11.38.12 22.75.24 31 .33M10 20c8.88.1 17.77.19 31 .33M10 20c6.49.07 12.98.14 31 .33M10 40c11.73.13 23.47.25 31 .33M10 40c10.52.11 21.04.23 31 .33M10 60c11.67.13 23.34.25 31 .33M10 60c6.23.07 12.46.13 31 .33"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m80 20 9.33 19.67L80 60V50H60V30h20V20"/><path fill="none" stroke-width="4" d="M80 20c2.84 5.99 5.68 11.98 9.33 19.67M80 20c2.52 5.31 5.04 10.63 9.33 19.67m0 0C87.01 44.73 84.69 49.79 80 60m9.33-20.33C87.4 43.88 85.47 48.09 80 60m0 0V50m0 10V50m0 0H60m20 0H60m0 0V30m0 20V30m0 0h20m-20 0h20m0 0V20m0 10V20m0 0s0 0 0 0m0 0s0 0 0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
32
ea-scripts/Convert text to link with folder and alias.md
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||
Converts text elements to links pointing to a file in a selected folder and with the alias set as the original text. The script will prompt the user to select an existing folder from the vault.
|
||||
`original text` => `[[selected folder/original text|original text]]`
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
folders = new Set();
|
||||
app.vault.getFiles().forEach((f)=>
|
||||
folders.add(f.path.substring(0,f.path.lastIndexOf("/")))
|
||||
);
|
||||
|
||||
f = Array.from(folders);
|
||||
folder = await utils.suggester(f,f);
|
||||
folder = folder??""; //if exiting suggester with ESC
|
||||
folder = folder === "" ? folder : folder + "/";
|
||||
|
||||
elements = ea.getViewSelectedElements().filter((el)=>el.type==="text");
|
||||
|
||||
elements.forEach((el)=>{
|
||||
el.rawText = "[["+folder+el.rawText+"|"+el.rawText+"]]";
|
||||
el.text = "[["+folder+el.text+"|"+el.text+"]]";
|
||||
el.originalText = "[["+folder+el.originalText+"|"+el.originalText+"]]";
|
||||
})
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.addElementsToView();
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170.322 103.335" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 30c11.75.1 23.5.19 41 .33M10 30c8.59.07 17.17.14 41 .33M10 50c15.52.13 31.04.25 41 .33M10 50c13.91.11 27.82.23 41 .33M10 70c15.43.13 30.87.25 41 .33M10 70c8.24.07 16.47.13 41 .33"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m90 30 9.33 19.67L90 70V60H70V40h20V30"/><path fill="none" stroke-width="4" d="M90 30c2.84 5.99 5.68 11.98 9.33 19.67M90 30c2.52 5.31 5.04 10.63 9.33 19.67m0 0C97.01 54.73 94.69 59.79 90 70m9.33-20.33C97.4 53.88 95.47 58.09 90 70m0 0V60m0 10V60m0 0H70m20 0H70m0 0V40m0 20V40m0 0h20m-20 0h20m0 0V30m0 10V30m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="m123.787 39.591 13.742-24.59m-13.742 24.59 13.742-24.59m0 0c1.863-3.335 4.462-4.071 7.797-2.208M137.529 15c1.863-3.334 4.462-4.07 7.797-2.207m0 0 9.995 5.586m-9.995-5.586 9.995 5.586m0 0c3.335 1.863 4.07 4.462 2.207 7.797m-2.207-7.797c3.335 1.863 4.07 4.462 2.207 7.797m0 0-13.741 24.591m13.741-24.591-13.741 24.591m0 0c-1.864 3.335-4.463 4.07-7.798 2.207m7.798-2.207c-1.864 3.335-4.463 4.07-7.798 2.207m0 0-9.995-5.585m9.995 5.585-9.995-5.585m0 0c-3.335-1.864-4.07-4.463-2.207-7.798m2.207 7.798c-3.335-1.864-4.07-4.463-2.207-7.798M102.795 77.158l13.742-24.591m-13.742 24.59 13.742-24.59m0 0c1.863-3.335 4.462-4.07 7.797-2.207m-7.797 2.207c1.863-3.335 4.462-4.07 7.797-2.207m0 0 9.995 5.585m-9.995-5.585 9.995 5.585m0 0c3.335 1.864 4.07 4.463 2.207 7.797m-2.207-7.797c3.335 1.864 4.07 4.463 2.207 7.797m0 0-13.742 24.591m13.742-24.59-13.742 24.59m0 0c-1.863 3.335-4.462 4.07-7.797 2.207m7.797-2.207c-1.863 3.335-4.462 4.07-7.797 2.207m0 0-9.995-5.585m9.995 5.585-9.995-5.585m0 0c-3.335-1.864-4.07-4.463-2.207-7.797m2.207 7.797c-3.335-1.864-4.07-4.463-2.207-7.797"/><g stroke-linecap="round"><path fill="#fff" stroke-width="0" d="m119.734 61.096 11.366-20.34 7.865 4.396-11.366 20.34"/><path fill="none" stroke="transparent" stroke-width="4" d="m119.734 61.096 11.366-20.34m-11.366 20.34 11.366-20.34m0 0c1.64.918 3.29 1.84 7.865 4.396m-7.865-4.396 7.865 4.396m0 0-11.366 20.34m11.366-20.34-11.366 20.34m0 0-7.865-4.396m7.865 4.395-7.865-4.395"/></g><g stroke-linecap="round"><path stroke-width="0" d="m118.676 68.759 18.727-33.513 2.95 1.65-18.726 33.512"/><path fill="none" stroke-width="4" d="m118.676 68.759 18.727-33.513M118.676 68.76l18.727-33.513m0 0 2.95 1.65m-2.95-1.65 2.95 1.65m0 0-18.726 33.512m18.726-33.513c-6.907 12.361-13.82 24.73-18.726 33.513m0 0-2.951-1.65m2.95 1.65-2.95-1.65"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
43
ea-scripts/Copy Selected Element Styles to Global.md
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script will copy styles of any selected element into Excalidraw's global styles.
|
||||
|
||||
After copying the styles of element such as box, text, or arrow using this script, You can then use Excalidraw's box, arrow, and other tools to create several elements with the same style. This is sometimes more convenient than `Copy Styles` and `Paste Styles`, especially when used with the script `Box Each Selected Groups`.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
const element = ea.getViewSelectedElement();
|
||||
const appState = ea.getExcalidrawAPI().getAppState();
|
||||
|
||||
if(!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
appState.currentItemStrokeWidth = element.strokeWidth;
|
||||
appState.currentItemStrokeStyle = element.strokeStyle;
|
||||
appState.currentItemStrokeSharpness = element.strokeSharpness;
|
||||
appState.currentItemRoughness = element.roughness;
|
||||
appState.currentItemFillStyle = element.fillStyle;
|
||||
appState.currentItemBackgroundColor = element.backgroundColor;
|
||||
appState.currentItemStrokeColor = element.strokeColor;
|
||||
|
||||
if(element.type === 'text') {
|
||||
appState.currentItemFontFamily = element.fontFamily;
|
||||
appState.currentItemFontSize = element.fontSize;
|
||||
appState.currentItemTextAlign = element.textAlign;
|
||||
}
|
||||
|
||||
if(element.type === 'arrow') {
|
||||
appState.currentItemStartArrowhead = element.startArrowhead;
|
||||
appState.currentItemEndArrowhead = element.endArrowhead;
|
||||
}
|
||||
1
ea-scripts/Copy Selected Element Styles to Global.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><path d="M224 0H336C362.5 0 384 21.49 384 48V256H0V48C0 21.49 21.49 0 48 0H64L96 64L128 0H160L192 64L224 0zM384 288V320C384 355.3 355.3 384 320 384H256V448C256 483.3 227.3 512 192 512C156.7 512 128 483.3 128 448V384H64C28.65 384 0 355.3 0 320V288H384zM192 464C200.8 464 208 456.8 208 448C208 439.2 200.8 432 192 432C183.2 432 176 439.2 176 448C176 456.8 183.2 464 192 464z"/></svg>
|
||||
|
After Width: | Height: | Size: 443 B |
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
The script will prompt you for a filename, then create a new markdown document with the file name provided, open the new markdown document in an adjacent pane, and embed the markdown document into the active Excalidraw drawing.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
let folder = ea.targetView.file.path;
|
||||
folder = folder.lastIndexOf("/")===-1?"":folder.substring(0,folder.lastIndexOf("/"))+"/";
|
||||
const fname = await utils.inputPrompt("Filename for new file","Filename",folder);
|
||||
const file = await app.fileManager.createAndOpenMarkdownFile(fname,true);
|
||||
await ea.addImage(0,0,file);
|
||||
ea.addElementsToView(true,true);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 170 160" stroke="#000"><text y="47.436" font-family="Helvetica, Segoe UI Emoji" font-size="52.832" style="white-space:pre" transform="translate(68.667 52.333)">MD</text><path fill="none" stroke-linecap="round" stroke-width="8" d="M60 150c34.92.23 69.85.47 99.33.67M60 150c25.08.17 50.16.34 99.33.67m0 0c.31-36.8.62-73.6 1-120m-1 120 1-120m0 0c-4.15-4.45-8.3-8.9-18.66-20m18.66 20c-6.97-7.48-13.95-14.95-18.66-20m0 0c-18.65-.08-37.31-.15-82-.34m82 .34c-24.26-.1-48.51-.2-82-.34m0 0c.11 47.28.22 94.55.33 139.67m-.33-139.67c.1 44.54.21 89.07.33 139.67M30 10v40m0-40v40M10 30h40m-40 0h40"/><path fill="none" stroke-linecap="round" stroke-width="4" d="M140 10v20m0-20v20m0 0h20m-20 0h20"/></svg>
|
||||
|
After Width: | Height: | Size: 746 B |
52
ea-scripts/Darken background color.md
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script darkens the background color of the selected element by 2% at a time.
|
||||
|
||||
You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect.
|
||||
|
||||
In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.
|
||||
|
||||
The color conversion method was copied from [color-convert](https://github.com/Qix-/color-convert).
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.7.19")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
let settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Step size"]) {
|
||||
settings = {
|
||||
"Step size" : {
|
||||
value: 2,
|
||||
description: "Step size in percentage for making the color darker"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const step = settings["Step size"].value;
|
||||
|
||||
const elements = ea
|
||||
.getViewSelectedElements()
|
||||
.filter((el) =>
|
||||
["rectangle", "ellipse", "diamond", "image", "line", "freedraw"].includes(el.type)
|
||||
);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
for (const el of ea.getElements()) {
|
||||
const color = ea.colorNameToHex(el.backgroundColor);
|
||||
const cm = ea.getCM(color);
|
||||
if (cm) {
|
||||
const darker = cm.darkerBy(step);
|
||||
if(Math.floor(darker.lightness)>0) el.backgroundColor = darker.stringHSL();
|
||||
}
|
||||
}
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Darken background color.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="120 30 500 500" stroke="#000"><path d="M365.4 56a224.009 224.009 0 0 0-158.39 65.609 223.994 223.994 0 0 0 0 316.78 224.001 224.001 0 0 0 158.39 65.609c59.41 0 116.39-23.602 158.39-65.609a223.99 223.99 0 0 0 65.605-158.39c0-39.32-10.348-77.949-30.008-112s-47.938-62.328-81.992-81.988a224 224 0 0 0-112-30.012zm92.398 243.6h-72.801v72.801l.004-.004a19.602 19.602 0 0 1-39.2 0v-72.8h-72.8v.003a19.6 19.6 0 0 1-16.974-9.8 19.59 19.59 0 0 1 0-19.603c3.5-6.062 9.97-9.8 16.973-9.8h72.801v-72.802.004a19.602 19.602 0 0 1 39.2 0V260.4h72.8v-.004a19.604 19.604 0 0 1 16.974 29.403 19.604 19.604 0 0 1-16.973 9.801z"/></svg>
|
||||
|
After Width: | Height: | Size: 664 B |
71
ea-scripts/Deconstruct selected elements into new drawing.md
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||

|
||||
|
||||
Select some elements in the scene. The script will take these elements and move them into a new Excalidraw file, and open that file. The selected elements will also be replaced in your original drawing with the embedded Excalidraw file (the one that was just created). You will be prompted for the file name of the new deconstructed image. The script is useful if you want to break a larger drawing into smaller reusable parts that you want to reference in multiple drawings.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.7.29")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
const els = ea.getViewSelectedElements();
|
||||
if (els.length === 0) {
|
||||
new Notice("You must select elements first")
|
||||
return;
|
||||
}
|
||||
|
||||
const bb = ea.getBoundingBox(els);
|
||||
ea.copyViewElementsToEAforEditing(els);
|
||||
|
||||
ea.getElements().filter(el=>el.type==="image").forEach(el=>{
|
||||
const img = ea.targetView.excalidrawData.getFile(el.fileId);
|
||||
const path = (img?.linkParts?.original)??(img?.file?.path);
|
||||
if(img && path) {
|
||||
ea.imagesDict[el.fileId] = {
|
||||
mimeType: img.mimeType,
|
||||
id: el.fileId,
|
||||
dataURL: img.img,
|
||||
created: img.mtime,
|
||||
file: path,
|
||||
hasSVGwithBitmap: img.isSVGwithBitmap,
|
||||
latex: null,
|
||||
};
|
||||
return;
|
||||
}
|
||||
const equation = ea.targetView.excalidrawData.getEquation(el.fileId);
|
||||
eqImg = ea.targetView.getScene()?.files[el.fileId]
|
||||
if(equation && eqImg) {
|
||||
ea.imagesDict[el.fileId] = {
|
||||
mimeType: eqImg.mimeType,
|
||||
id: el.fileId,
|
||||
dataURL: eqImg.dataURL,
|
||||
created: eqImg.created,
|
||||
file: null,
|
||||
hasSVGwithBitmap: null,
|
||||
latex: equation.latex,
|
||||
};
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
let folder = ea.targetView.file.path;
|
||||
folder = folder.lastIndexOf("/")===-1?"":folder.substring(0,folder.lastIndexOf("/"))+"/";
|
||||
const fname = await utils.inputPrompt("Filename for new file","Filename","");
|
||||
const template = app.metadataCache.getFirstLinkpathDest(ea.plugin.settings.templateFilePath,"");
|
||||
|
||||
const newPath = await ea.create ({
|
||||
filename: fname + ".md",
|
||||
foldername: folder,
|
||||
templatePath: template?.path,
|
||||
onNewPane: true
|
||||
});
|
||||
|
||||
setTimeout(async ()=>{
|
||||
const file = app.metadataCache.getFirstLinkpathDest(newPath,"")
|
||||
ea.deleteViewElements(els);
|
||||
ea.clear();
|
||||
await ea.addImage(bb.topX,bb.topY,file,false);
|
||||
ea.addElementsToView(false, true, true);
|
||||
},1000);
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M169.7 .9c-22.8-1.6-41.9 14-47.5 34.7L110.4 80c.5 0 1.1 0 1.6 0c176.7 0 320 143.3 320 320c0 .5 0 1.1 0 1.6l44.4-11.8c20.8-5.5 36.3-24.7 34.7-47.5C498.5 159.5 352.5 13.5 169.7 .9zM399.8 410.2c.1-3.4 .2-6.8 .2-10.2c0-159.1-128.9-288-288-288c-3.4 0-6.8 .1-10.2 .2L.5 491.9c-1.5 5.5 .1 11.4 4.1 15.4s9.9 5.6 15.4 4.1L399.8 410.2zM176 272c-17.7 0-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32s-14.3 32-32 32zm128 64c0 17.7-14.3 32-32 32s-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32zM160 384c0 17.7-14.3 32-32 32s-32-14.3-32-32s14.3-32 32-32s32 14.3 32 32z"/></svg>
|
||||
|
After Width: | Height: | Size: 624 B |
93
ea-scripts/Elbow connectors.md
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script converts the selected connectors to elbows.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
const selectedCenterConnectPoints = await utils.suggester(
|
||||
['Yes', 'No'],
|
||||
[true, false],
|
||||
"Center connect points?"
|
||||
);
|
||||
const centerConnectPoints = selectedCenterConnectPoints??false;
|
||||
|
||||
const allElements = ea.getViewElements();
|
||||
const elements = ea.getViewSelectedElements();
|
||||
|
||||
const lines = elements.filter((el)=>el.type==="arrow" || el.type==="line");
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.points.length >= 3) {
|
||||
if(centerConnectPoints) {
|
||||
const startBindingEl = allElements.filter(el => el.id === (line.startBinding||{}).elementId)[0];
|
||||
const endBindingEl = allElements.filter(el => el.id === (line.endBinding||{}).elementId)[0];
|
||||
|
||||
if(startBindingEl) {
|
||||
const startPointX = line.x +line.points[0][0];
|
||||
if(startPointX >= startBindingEl.x && startPointX <= startBindingEl.x + startBindingEl.width) {
|
||||
line.points[0][0] = startBindingEl.x + startBindingEl.width / 2 - line.x;
|
||||
}
|
||||
|
||||
const startPointY = line.y +line.points[0][1];
|
||||
if(startPointY >= startBindingEl.y && startPointY <= startBindingEl.y + startBindingEl.height) {
|
||||
line.points[0][1] = startBindingEl.y + startBindingEl.height / 2 - line.y;
|
||||
}
|
||||
}
|
||||
|
||||
if(endBindingEl) {
|
||||
const startPointX = line.x +line.points[line.points.length-1][0];
|
||||
if(startPointX >= endBindingEl.x && startPointX <= endBindingEl.x + endBindingEl.width) {
|
||||
line.points[line.points.length-1][0] = endBindingEl.x + endBindingEl.width / 2 - line.x;
|
||||
}
|
||||
|
||||
const startPointY = line.y +line.points[line.points.length-1][1];
|
||||
if(startPointY >= endBindingEl.y && startPointY <= endBindingEl.y + endBindingEl.height) {
|
||||
line.points[line.points.length-1][1] = endBindingEl.y + endBindingEl.height / 2 - line.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < line.points.length - 2; i++) {
|
||||
var p1;
|
||||
var p3;
|
||||
if (line.points[i][0] < line.points[i + 2][0]) {
|
||||
p1 = line.points[i];
|
||||
p3 = line.points[i+2];
|
||||
} else {
|
||||
p1 = line.points[i + 2];
|
||||
p3 = line.points[i];
|
||||
}
|
||||
const p2 = line.points[i + 1];
|
||||
|
||||
if (p1[0] === p3[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const k = (p3[1] - p1[1]) / (p3[0] - p1[0]);
|
||||
const b = p1[1] - k * p1[0];
|
||||
|
||||
y0 = k * p2[0] + b;
|
||||
const up = p2[1] < y0;
|
||||
|
||||
if ((k > 0 && !up) || (k < 0 && up)) {
|
||||
p2[0] = p1[0];
|
||||
p2[1] = p3[1];
|
||||
} else {
|
||||
p2[0] = p3[0];
|
||||
p2[1] = p1[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(lines);
|
||||
await ea.addElementsToView(false,false);
|
||||
1
ea-scripts/Elbow connectors.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 120" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="8" d="M10 10v80m0-80v80m0 0h80m-80 0h80M70 70l20 20M70 70l20 20m0 0-20 20m20-20-20 20"/></svg>
|
||||
|
After Width: | Height: | Size: 226 B |
156
ea-scripts/Expand rectangles horizontally keep text centered.md
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script expands the width of the selected rectangles until they are all the same width and keep the text centered.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements);
|
||||
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
||||
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow')) ?
|
||||
[...result, group[0]] : result, []);
|
||||
|
||||
const groupWidths = topGroups
|
||||
.map((g) => {
|
||||
if(g.length === 1 && (g[0].type === 'arrow' || g[0].type === 'line')) {
|
||||
// ignore individual lines
|
||||
return { minLeft: 0, maxRight: 0 };
|
||||
}
|
||||
return g.reduce(
|
||||
(pre, cur, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
minLeft: cur.x,
|
||||
maxRight: cur.x + cur.width,
|
||||
index: i,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
minLeft: cur.x < pre.minLeft ? cur.x : pre.minLeft,
|
||||
maxRight:
|
||||
cur.x + cur.width > pre.maxRight
|
||||
? cur.x + cur.width
|
||||
: pre.maxRight,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
},
|
||||
{ minLeft: 0, maxRight: 0 }
|
||||
);
|
||||
})
|
||||
.map((r) => {
|
||||
r.width = r.maxRight - r.minLeft;
|
||||
return r;
|
||||
});
|
||||
|
||||
const maxGroupWidth = Math.max(...groupWidths.map((g) => g.width));
|
||||
|
||||
for (var i = 0; i < topGroups.length; i++) {
|
||||
const rects = topGroups[i]
|
||||
.filter((el) => el.type === "rectangle")
|
||||
.sort((lha, rha) => lha.x - rha.x);
|
||||
const texts = topGroups[i]
|
||||
.filter((el) => el.type === "text")
|
||||
.sort((lha, rha) => lha.x - rha.x);
|
||||
const groupWith = groupWidths[i].width;
|
||||
if (groupWith < maxGroupWidth) {
|
||||
const distance = maxGroupWidth - groupWith;
|
||||
const perRectDistance = distance / rects.length;
|
||||
const textsWithRectIndex = [];
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
const rectLeft = rect.x;
|
||||
const rectTop = rect.y;
|
||||
const rectRight = rect.x + rect.width;
|
||||
const rectBottom = rect.y + rect.height;
|
||||
|
||||
const textsWithRect = texts.filter(text => text.x >= rectLeft && text.x <= rectRight
|
||||
&& text.y >= rectTop && text.y <= rectBottom);
|
||||
|
||||
textsWithRectIndex[j] = textsWithRect;
|
||||
}
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
rect.x = rect.x + perRectDistance * j - perRectDistance / 2;
|
||||
rect.width += perRectDistance;
|
||||
|
||||
const textsWithRect = textsWithRectIndex[j];
|
||||
|
||||
if(textsWithRect) {
|
||||
for(const text of textsWithRect) {
|
||||
text.x = text.x + perRectDistance * j;
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate the position of the points
|
||||
const startBindingLines = allIndividualArrows.filter(el => (el.startBinding||{}).elementId === rect.id);
|
||||
for(startBindingLine of startBindingLines) {
|
||||
recalculateStartPointOfLine(startBindingLine, rect);
|
||||
}
|
||||
|
||||
const endBindingLines = allIndividualArrows.filter(el => (el.endBinding||{}).elementId === rect.id);
|
||||
for(endBindingLine of endBindingLines) {
|
||||
recalculateEndPointOfLine(endBindingLine, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = 8;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = 8;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 410 190" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M45 10h70m-70 0h70m0 0v60m0-60v60m0 0H45m70 0H45m0 0V10m0 60V10M60 90h40m-40 0h40m0 0v40m0-40v40m0 0H60m40 0H60m0 0V90m0 40V90"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(50 31)">test</text><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(65 101)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 150h140m-140 0h140m0 0v28m0-28v28m0 0H10m140 0H10m0 0v-28m0 28v-28"/><text x="65" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(15 155)">test</text><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="M180 10v170l60-90-60-80"/><path fill="none" stroke-width="4" d="M180 10v170m0-170v170m0 0c21.15-31.72 42.3-63.45 60-90m-60 90c19.35-29.03 38.7-58.05 60-90m0 0c-19.42-25.89-38.84-51.78-60-80m60 80c-20.43-27.24-40.86-54.47-60-80m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M260 10h140m-140 0h140m0 0v60m0-60v60m0 0H260m140 0H260m0 0V10m0 60V10M260 90h140m-140 0h140m0 0v40m0-40v40m0 0H260m140 0H260m0 0V90m0 40V90"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(300 31)">test</text><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(315 101)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M260 150h140m-140 0h140m0 0v28m0-28v28m0 0H260m140 0H260m0 0v-28m0 28v-28"/><text x="65" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(265 155)">test</text></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
133
ea-scripts/Expand rectangles horizontally.md
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script expands the width of the selected rectangles until they are all the same width.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements);
|
||||
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
||||
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ?
|
||||
[...result, group[0]] : result, []);
|
||||
|
||||
const groupWidths = topGroups
|
||||
.map((g) => {
|
||||
if(g.length === 1 && (g[0].type === 'arrow' || g[0].type === 'line')) {
|
||||
// ignore individual lines
|
||||
return { minLeft: 0, maxRight: 0 };
|
||||
}
|
||||
return g.reduce(
|
||||
(pre, cur, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
minLeft: cur.x,
|
||||
maxRight: cur.x + cur.width,
|
||||
index: i,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
minLeft: cur.x < pre.minLeft ? cur.x : pre.minLeft,
|
||||
maxRight:
|
||||
cur.x + cur.width > pre.maxRight
|
||||
? cur.x + cur.width
|
||||
: pre.maxRight,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
},
|
||||
{ minLeft: 0, maxRight: 0 }
|
||||
);
|
||||
})
|
||||
.map((r) => {
|
||||
r.width = r.maxRight - r.minLeft;
|
||||
return r;
|
||||
});
|
||||
|
||||
const maxGroupWidth = Math.max(...groupWidths.map((g) => g.width));
|
||||
|
||||
for (var i = 0; i < topGroups.length; i++) {
|
||||
const rects = topGroups[i]
|
||||
.filter((el) => el.type === "rectangle")
|
||||
.sort((lha, rha) => lha.x - rha.x);
|
||||
|
||||
const groupWith = groupWidths[i].width;
|
||||
if (groupWith < maxGroupWidth) {
|
||||
const distance = maxGroupWidth - groupWith;
|
||||
const perRectDistance = distance / rects.length;
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
rect.x = rect.x + perRectDistance * j;
|
||||
rect.width += perRectDistance;
|
||||
|
||||
// recalculate the position of the points
|
||||
const startBindingLines = allIndividualArrows.filter(el => (el.startBinding||{}).elementId === rect.id);
|
||||
for(startBindingLine of startBindingLines) {
|
||||
recalculateStartPointOfLine(startBindingLine, rect);
|
||||
}
|
||||
|
||||
const endBindingLines = allIndividualArrows.filter(el => (el.endBinding||{}).elementId === rect.id);
|
||||
for(endBindingLine of endBindingLines) {
|
||||
recalculateEndPointOfLine(endBindingLine, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = 8;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = 8;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Expand rectangles horizontally.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 260 160" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h80m-80 0h80m0 0v40m0-40v40m0 0H10m80 0H10m0 0V10m0 40V10M10 110h20m-20 0h20m0 0v40m0-40v40m0 0H10m20 0H10m0 0v-40m0 40v-40M10 60h40m-40 0h40m0 0v40m0-40v40m0 0H10m40 0H10m0 0V60m0 40V60"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m110.167 10-.17 140 40-70-39.83-70"/><path fill="none" stroke-width="4" d="M110.167 10c-.04 37.8-.09 75.6-.17 140m.17-140c-.03 28.29-.07 56.58-.17 140m0 0c13.69-23.95 27.38-47.9 40-70m-40 70c15.92-27.85 31.83-55.69 40-70m0 0c-14.45-25.41-28.91-50.81-39.83-70m39.83 70c-10.22-17.96-20.44-35.92-39.83-70m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M170 10h80m-80 0h80m0 0v40m0-40v40m0 0h-80m80 0h-80m0 0V10m0 40V10M170 110h80m-80 0h80m0 0v40m0-40v40m0 0h-80m80 0h-80m0 0v-40m0 40v-40M170 60h80m-80 0h80m0 0v40m0-40v40m0 0h-80m80 0h-80m0 0V60m0 40V60"/></svg>
|
||||
|
After Width: | Height: | Size: 1010 B |
156
ea-scripts/Expand rectangles vertically keep text centered.md
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script expands the height of the selected rectangles until they are all the same height and keep the text centered.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements);
|
||||
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
||||
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ?
|
||||
[...result, group[0]] : result, []);
|
||||
|
||||
const groupHeights = topGroups
|
||||
.map((g) => {
|
||||
if(g.length === 1 && (g[0].type === 'arrow' || g[0].type === 'line')) {
|
||||
// ignore individual lines
|
||||
return { minTop: 0, maxBottom: 0 };
|
||||
}
|
||||
return g.reduce(
|
||||
(pre, cur, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
minTop: cur.y,
|
||||
maxBottom: cur.y + cur.height,
|
||||
index: i,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
minTop: cur.y < pre.minTop ? cur.y : pre.minTop,
|
||||
maxBottom:
|
||||
cur.y + cur.height > pre.maxBottom
|
||||
? cur.y + cur.height
|
||||
: pre.maxBottom,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
},
|
||||
{ minTop: 0, maxBottom: 0 }
|
||||
);
|
||||
})
|
||||
.map((r) => {
|
||||
r.height = r.maxBottom - r.minTop;
|
||||
return r;
|
||||
});
|
||||
|
||||
const maxGroupHeight = Math.max(...groupHeights.map((g) => g.height));
|
||||
|
||||
for (var i = 0; i < topGroups.length; i++) {
|
||||
const rects = topGroups[i]
|
||||
.filter((el) => el.type === "rectangle")
|
||||
.sort((lha, rha) => lha.y - rha.y);
|
||||
const texts = topGroups[i]
|
||||
.filter((el) => el.type === "text")
|
||||
.sort((lha, rha) => lha.y - rha.y);
|
||||
const groupWith = groupHeights[i].height;
|
||||
if (groupWith < maxGroupHeight) {
|
||||
const distance = maxGroupHeight - groupWith;
|
||||
const perRectDistance = distance / rects.length;
|
||||
const textsWithRectIndex = [];
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
const rectLeft = rect.x;
|
||||
const rectTop = rect.y;
|
||||
const rectRight = rect.x + rect.width;
|
||||
const rectBottom = rect.y + rect.height;
|
||||
|
||||
const textsWithRect = texts.filter(text => text.x >= rectLeft && text.x <= rectRight
|
||||
&& text.y >= rectTop && text.y <= rectBottom);
|
||||
|
||||
textsWithRectIndex[j] = textsWithRect;
|
||||
}
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
rect.y = rect.y + perRectDistance * j - perRectDistance / 2;
|
||||
rect.height += perRectDistance;
|
||||
|
||||
const textsWithRect = textsWithRectIndex[j];
|
||||
|
||||
if(textsWithRect) {
|
||||
for(const text of textsWithRect) {
|
||||
text.y = text.y + perRectDistance * j;
|
||||
}
|
||||
}
|
||||
|
||||
// recalculate the position of the points
|
||||
const startBindingLines = allIndividualArrows.filter(el => (el.startBinding||{}).elementId === rect.id);
|
||||
for(startBindingLine of startBindingLines) {
|
||||
recalculateStartPointOfLine(startBindingLine, rect);
|
||||
}
|
||||
|
||||
const endBindingLines = allIndividualArrows.filter(el => (el.endBinding||{}).elementId === rect.id);
|
||||
for(endBindingLine of endBindingLines) {
|
||||
recalculateEndPointOfLine(endBindingLine, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = 8;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = 8;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 190" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 55h40m-40 0h40m0 0v80m0-80v80m0 0H10m40 0H10m0 0V55m0 80V55M70 80h50m-50 0h50m0 0v30m0-30v30m0 0H70m50 0H70m0 0V80m0 30V80"/><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(15 86)">test</text><text x="20" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(75 86)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M140 10h70m-70 0h70m0 0v170m0-170v170m0 0h-70m70 0h-70m0 0V10m0 170V10"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(145 86)">test</text><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="M230 10v170l60-90-60-80"/><path fill="none" stroke-width="4" d="M230 10v170m0-170v170m0 0c21.15-31.72 42.3-63.45 60-90m-60 90c19.35-29.03 38.7-58.05 60-90m0 0c-19.42-25.89-38.84-51.78-60-80m60 80c-20.43-27.24-40.86-54.47-60-80m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M310 10h40m-40 0h40m0 0v170m0-170v170m0 0h-40m40 0h-40m0 0V10m0 170V10M370 10h50m-50 0h50m0 0v170m0-170v170m0 0h-50m50 0h-50m0 0V10m0 170V10"/><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(315 86)">test</text><text x="20" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(375 86)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M440 10h70m-70 0h70m0 0v170m0-170v170m0 0h-70m70 0h-70m0 0V10m0 170V10"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(445 86)">test</text></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
131
ea-scripts/Expand rectangles vertically.md
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script expands the height of the selected rectangles until they are all the same height.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
const elements = ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements);
|
||||
const allLines = ea.getViewElements().filter(el => el.type === 'arrow' || el.type === 'line');
|
||||
const allIndividualArrows = ea.getMaximumGroups(ea.getViewElements())
|
||||
.reduce((result, group) => (group.length === 1 && (group[0].type === 'arrow' || group[0].type === 'line')) ?
|
||||
[...result, group[0]] : result, []);
|
||||
|
||||
const groupHeights = topGroups
|
||||
.map((g) => {
|
||||
if(g.length === 1 && (g[0].type === 'arrow' || g[0].type === 'line')) {
|
||||
// ignore individual lines
|
||||
return { minTop: 0, maxBottom: 0 };
|
||||
}
|
||||
return g.reduce(
|
||||
(pre, cur, i) => {
|
||||
if (i === 0) {
|
||||
return {
|
||||
minTop: cur.y,
|
||||
maxBottom: cur.y + cur.height,
|
||||
index: i,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
minTop: cur.y < pre.minTop ? cur.y : pre.minTop,
|
||||
maxBottom:
|
||||
cur.y + cur.height > pre.maxBottom
|
||||
? cur.y + cur.height
|
||||
: pre.maxBottom,
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
},
|
||||
{ minTop: 0, maxBottom: 0 }
|
||||
);
|
||||
})
|
||||
.map((r) => {
|
||||
r.height = r.maxBottom - r.minTop;
|
||||
return r;
|
||||
});
|
||||
|
||||
const maxGroupHeight = Math.max(...groupHeights.map((g) => g.height));
|
||||
|
||||
for (var i = 0; i < topGroups.length; i++) {
|
||||
const rects = topGroups[i]
|
||||
.filter((el) => el.type === "rectangle")
|
||||
.sort((lha, rha) => lha.y - rha.y);
|
||||
|
||||
const groupWidth = groupHeights[i].height;
|
||||
if (groupWidth < maxGroupHeight) {
|
||||
const distance = maxGroupHeight - groupWidth;
|
||||
const perRectDistance = distance / rects.length;
|
||||
for (var j = 0; j < rects.length; j++) {
|
||||
const rect = rects[j];
|
||||
rect.y = rect.y + perRectDistance * j;
|
||||
rect.height += perRectDistance;
|
||||
|
||||
// recalculate the position of the points
|
||||
const startBindingLines = allIndividualArrows.filter(el => (el.startBinding||{}).elementId === rect.id);
|
||||
for(startBindingLine of startBindingLines) {
|
||||
recalculateStartPointOfLine(startBindingLine, rect);
|
||||
}
|
||||
|
||||
const endBindingLines = allIndividualArrows.filter(el => (el.endBinding||{}).elementId === rect.id);
|
||||
for(endBindingLine of endBindingLines) {
|
||||
recalculateEndPointOfLine(endBindingLine, rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = 8;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = 8;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Expand rectangles vertically.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 190" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M100 10h40m-40 0h40m0 0v80m0-80v80m0 0h-40m40 0h-40m0 0V10m0 80V10M160 10h50m-50 0h50m0 0v30m0-30v30m0 0h-50m50 0h-50m0 0V10m0 30V10"/><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(105 41)">test</text><text x="20" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(165 16)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h70m-70 0h70m0 0v170m0-170v170m0 0H10m70 0H10m0 0V10m0 170V10"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(15 86)">test</text><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="M230 10v170l60-90-60-80"/><path fill="none" stroke-width="4" d="M230 10v170m0-170v170m0 0c21.15-31.72 42.3-63.45 60-90m-60 90c19.35-29.03 38.7-58.05 60-90m0 0c-19.42-25.89-38.84-51.78-60-80m60 80c-20.43-27.24-40.86-54.47-60-80m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M400 10h40m-40 0h40m0 0v170m0-170v170m0 0h-40m40 0h-40m0 0V10m0 170V10M460 10h50m-50 0h50m0 0v170m0-170v170m0 0h-50m50 0h-50m0 0V10m0 170V10"/><text x="15" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(405 41)">test</text><text x="20" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(465 16)">test</text><path fill="none" stroke-linecap="round" stroke-width="4" d="M310 10h70m-70 0h70m0 0v170m0-170v170m0 0h-70m70 0h-70m0 0V10m0 170V10"/><text x="30" y="14" font-family="Helvetica, Segoe UI Emoji" font-size="16" style="white-space:pre" text-anchor="middle" transform="translate(315 86)">test</text></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
74
ea-scripts/Fixed horizontal distance between centers.md
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script arranges the selected elements horizontally with a fixed center spacing.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default distance"]) {
|
||||
settings = {
|
||||
"Prompt for distance?": true,
|
||||
"Default distance" : {
|
||||
value: 10,
|
||||
description: "Fixed horizontal distance between centers"
|
||||
},
|
||||
"Remember last distance?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let distanceStr = settings["Default distance"].value.toString();
|
||||
const rememberLastDistance = settings["Remember last distance?"];
|
||||
|
||||
if(settings["Prompt for distance?"]) {
|
||||
distanceStr = await utils.inputPrompt("distance?","number",distanceStr);
|
||||
}
|
||||
|
||||
const distance = parseInt(distanceStr);
|
||||
if(isNaN(distance)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastDistance) {
|
||||
settings["Default distance"].value = distance;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements)
|
||||
.filter(els => !(els.length === 1 && els[0].type ==="arrow")) // ignore individual arrows
|
||||
.filter(els => !(els.length === 1 && (els[0].containerId))); // ignore text in stickynote
|
||||
|
||||
const groups = topGroups.sort((lha,rha) => lha[0].x - rha[0].x);
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const preGroup = groups[i-1];
|
||||
const curGroup = groups[i];
|
||||
|
||||
const preLeft = Math.min(...preGroup.map(el => el.x));
|
||||
const preRight = Math.max(...preGroup.map(el => el.x + el.width));
|
||||
const preCenter = preLeft + (preRight - preLeft) / 2;
|
||||
const curLeft = Math.min(...curGroup.map(el => el.x));
|
||||
const curRight = Math.max(...curGroup.map(el => el.x + el.width));
|
||||
const curCenter = curLeft + (curRight - curLeft) / 2;
|
||||
const distanceBetweenCenters = curCenter - preCenter - distance;
|
||||
|
||||
for(const curEl of curGroup) {
|
||||
curEl.x = curEl.x - distanceBetweenCenters;
|
||||
}
|
||||
}
|
||||
}
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Fixed horizontal distance between centers.svg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
127
ea-scripts/Fixed inner distance.md
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script arranges selected elements and groups with a fixed inner distance.
|
||||
|
||||
Tips: You can use the `Box Selected Elements` and `Dimensions` scripts to create rectangles of the desired size, then use the `Change shape of selected elements` script to convert the rectangles to ellipses, and then use the `Fixed inner distance` script regains a desired inner distance.
|
||||
|
||||
Inspiration: #394
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default distance"]) {
|
||||
settings = {
|
||||
"Prompt for distance?": true,
|
||||
"Default distance" : {
|
||||
value: 10,
|
||||
description: "Fixed horizontal distance between centers"
|
||||
},
|
||||
"Remember last distance?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let distanceStr = settings["Default distance"].value.toString();
|
||||
const rememberLastDistance = settings["Remember last distance?"];
|
||||
|
||||
if(settings["Prompt for distance?"]) {
|
||||
distanceStr = await utils.inputPrompt("distance?","number",distanceStr);
|
||||
}
|
||||
|
||||
const borders = ["top", "bottom", "left", "right"];
|
||||
const fromBorder = await utils.suggester(borders, borders, "from border?");
|
||||
|
||||
if(!fromBorder) {
|
||||
return;
|
||||
}
|
||||
|
||||
const distance = parseInt(distanceStr);
|
||||
if(isNaN(distance)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastDistance) {
|
||||
settings["Default distance"].value = distance;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements)
|
||||
.filter(els => !(els.length === 1 && els[0].type ==="arrow")) // ignore individual arrows
|
||||
.filter(els => !(els.length === 1 && (els[0].containerId))); // ignore text in stickynote
|
||||
|
||||
if(topGroups.length <= 1) {
|
||||
new Notice("At least 2 or more elements or groups should be selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(fromBorder === 'top') {
|
||||
const groups = topGroups.sort((lha,rha) => Math.min(...lha.map(t => t.y)) - Math.min(...rha.map(t => t.y)));
|
||||
const firstGroupTop = Math.min(...groups[0].map(el => el.y));
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const curGroup = groups[i];
|
||||
const moveDistance = distance * i;
|
||||
for(const curEl of curGroup) {
|
||||
curEl.y = firstGroupTop + moveDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(fromBorder === 'bottom') {
|
||||
const groups = topGroups.sort((lha,rha) => Math.min(...lha.map(t => t.y + t.height)) - Math.min(...rha.map(t => t.y + t.height))).reverse();
|
||||
const firstGroupBottom = Math.max(...groups[0].map(el => el.y + el.height));
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const curGroup = groups[i];
|
||||
const moveDistance = distance * i;
|
||||
for(const curEl of curGroup) {
|
||||
curEl.y = firstGroupBottom - moveDistance - curEl.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(fromBorder === 'left') {
|
||||
const groups = topGroups.sort((lha,rha) => Math.min(...lha.map(t => t.x)) - Math.min(...rha.map(t => t.x)));
|
||||
const firstGroupLeft = Math.min(...groups[0].map(el => el.x));
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const curGroup = groups[i];
|
||||
const moveDistance = distance * i;
|
||||
for(const curEl of curGroup) {
|
||||
curEl.x = firstGroupLeft + moveDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(fromBorder === 'right') {
|
||||
const groups = topGroups.sort((lha,rha) => Math.min(...lha.map(t => t.x + t.width)) - Math.min(...rha.map(t => t.x + t.width))).reverse();
|
||||
const firstGroupRight = Math.max(...groups[0].map(el => el.x + el.width));
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const curGroup = groups[i];
|
||||
const moveDistance = distance * i;
|
||||
for(const curEl of curGroup) {
|
||||
curEl.x = firstGroupRight - moveDistance - curEl.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Fixed inner distance.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130 130" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M120 65a55.086 55.086 0 0 1-1.87 14.24c-.62 2.31-1.4 4.6-2.32 6.81-.91 2.21-1.98 4.38-3.18 6.45-1.2 2.07-2.54 4.08-4 5.98-1.45 1.9-3.05 3.72-4.74 5.41a54.136 54.136 0 0 1-5.41 4.74c-1.9 1.46-3.91 2.8-5.98 4-2.07 1.2-4.24 2.27-6.45 3.18-2.21.92-4.5 1.7-6.81 2.32A55.086 55.086 0 0 1 65 120a55.086 55.086 0 0 1-14.24-1.87c-2.31-.62-4.6-1.4-6.81-2.32-2.21-.91-4.38-1.98-6.45-3.18-2.07-1.2-4.08-2.54-5.98-4-1.9-1.45-3.72-3.05-5.41-4.74a54.136 54.136 0 0 1-4.74-5.41c-1.46-1.9-2.8-3.91-4-5.98-1.2-2.07-2.27-4.24-3.18-6.45-.92-2.21-1.7-4.5-2.32-6.81A55.086 55.086 0 0 1 10 65a55.086 55.086 0 0 1 1.87-14.24c.62-2.31 1.4-4.6 2.32-6.81.91-2.21 1.98-4.38 3.18-6.45 1.2-2.07 2.54-4.08 4-5.98 1.45-1.9 3.05-3.72 4.74-5.41 1.69-1.69 3.51-3.29 5.41-4.74 1.9-1.46 3.91-2.8 5.98-4 2.07-1.2 4.24-2.27 6.45-3.18 2.21-.92 4.5-1.7 6.81-2.32A55.086 55.086 0 0 1 65 10a55.086 55.086 0 0 1 14.24 1.87c2.31.62 4.6 1.4 6.81 2.32 2.21.91 4.38 1.98 6.45 3.18 2.07 1.2 4.08 2.54 5.98 4 1.9 1.45 3.72 3.05 5.41 4.74 1.69 1.69 3.29 3.51 4.74 5.41 1.46 1.9 2.8 3.91 4 5.98 1.2 2.07 2.27 4.24 3.18 6.45.92 2.21 1.7 4.5 2.32 6.81.62 2.32 1.09 4.69 1.4 7.06.31 2.37.39 5.98.47 7.18.08 1.2.08-1.2 0 0"/><path fill="none" stroke-linecap="round" stroke-width="4" d="M110 70c0 1.9-.14 3.81-.41 5.69-.27 1.88-.68 3.76-1.21 5.58-.53 1.82-1.21 3.62-1.99 5.35-.79 1.72-1.71 3.41-2.74 5.01a41.072 41.072 0 0 1-3.42 4.56c-1.24 1.44-2.6 2.8-4.04 4.04a41.072 41.072 0 0 1-4.56 3.42c-1.6 1.03-3.29 1.95-5.01 2.74-1.73.78-3.53 1.46-5.35 1.99-1.82.53-3.7.94-5.58 1.21S71.9 110 70 110c-1.9 0-3.81-.14-5.69-.41-1.88-.27-3.76-.68-5.58-1.21-1.82-.53-3.62-1.21-5.35-1.99-1.72-.79-3.41-1.71-5.01-2.74a41.072 41.072 0 0 1-4.56-3.42c-1.44-1.24-2.8-2.6-4.04-4.04a41.072 41.072 0 0 1-3.42-4.56c-1.03-1.6-1.95-3.29-2.74-5.01-.78-1.73-1.46-3.53-1.99-5.35-.53-1.82-.94-3.7-1.21-5.58A40.12 40.12 0 0 1 30 70c0-1.9.14-3.81.41-5.69.27-1.88.68-3.76 1.21-5.58.53-1.82 1.21-3.62 1.99-5.35.79-1.72 1.71-3.41 2.74-5.01 1.03-1.59 2.18-3.13 3.42-4.56 1.24-1.44 2.6-2.8 4.04-4.04 1.43-1.24 2.97-2.39 4.56-3.42 1.6-1.03 3.29-1.95 5.01-2.74 1.73-.78 3.53-1.46 5.35-1.99 1.82-.53 3.7-.94 5.58-1.21S68.1 30 70 30c1.9 0 3.81.14 5.69.41 1.88.27 3.76.68 5.58 1.21 1.82.53 3.62 1.21 5.35 1.99 1.72.79 3.41 1.71 5.01 2.74 1.59 1.03 3.13 2.18 4.56 3.42 1.44 1.24 2.8 2.6 4.04 4.04 1.24 1.43 2.39 2.97 3.42 4.56 1.03 1.6 1.95 3.29 2.74 5.01.78 1.73 1.46 3.53 1.99 5.35.53 1.82.94 3.7 1.21 5.58s.34 4.74.41 5.69c.07.95.07-.95 0 0"/><path fill="none" stroke-linecap="round" stroke-width="4" d="M100 75c0 1.45-.13 2.92-.38 4.34-.25 1.43-.63 2.85-1.13 4.21a24.875 24.875 0 0 1-4.34 7.52c-.93 1.11-1.97 2.15-3.08 3.08a24.875 24.875 0 0 1-7.52 4.34c-1.36.5-2.78.88-4.21 1.13-1.42.25-2.89.38-4.34.38-1.45 0-2.92-.13-4.34-.38-1.43-.25-2.85-.63-4.21-1.13a24.875 24.875 0 0 1-7.52-4.34c-1.11-.93-2.15-1.97-3.08-3.08a24.875 24.875 0 0 1-4.34-7.52c-.5-1.36-.88-2.78-1.13-4.21-.25-1.42-.38-2.89-.38-4.34 0-1.45.13-2.92.38-4.34.25-1.43.63-2.85 1.13-4.21a24.875 24.875 0 0 1 4.34-7.52c.93-1.11 1.97-2.15 3.08-3.08a24.875 24.875 0 0 1 7.52-4.34c1.36-.5 2.78-.88 4.21-1.13 1.42-.25 2.89-.38 4.34-.38 1.45 0 2.92.13 4.34.38 1.43.25 2.85.63 4.21 1.13a24.875 24.875 0 0 1 7.52 4.34c1.11.93 2.15 1.97 3.08 3.08a24.875 24.875 0 0 1 4.34 7.52c.5 1.36.88 2.78 1.13 4.21.25 1.42.32 3.62.38 4.34.06.72.06-.72 0 0"/></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
69
ea-scripts/Fixed spacing.md
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
The script arranges the selected elements horizontally with a fixed spacing.
|
||||
|
||||
When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default spacing"]) {
|
||||
settings = {
|
||||
"Prompt for spacing?": true,
|
||||
"Default spacing" : {
|
||||
value: 10,
|
||||
description: "Fixed horizontal spacing between elements"
|
||||
},
|
||||
"Remember last spacing?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let spacingStr = settings["Default spacing"].value.toString();
|
||||
const rememberLastSpacing = settings["Remember last spacing?"];
|
||||
|
||||
if(settings["Prompt for spacing?"]) {
|
||||
spacingStr = await utils.inputPrompt("spacing?","number",spacingStr);
|
||||
}
|
||||
|
||||
const spacing = parseInt(spacingStr);
|
||||
if(isNaN(spacing)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastSpacing) {
|
||||
settings["Default spacing"].value = spacing;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements)
|
||||
.filter(els => !(els.length === 1 && els[0].type ==="arrow")) // ignore individual arrows
|
||||
.filter(els => !(els.length === 1 && (els[0].containerId))); // ignore text in stickynote
|
||||
|
||||
const groups = topGroups.sort((lha,rha) => lha[0].x - rha[0].x);
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const preGroup = groups[i-1];
|
||||
const curGroup = groups[i];
|
||||
|
||||
const preRight = Math.max(...preGroup.map(el => el.x + el.width));
|
||||
const curLeft = Math.min(...curGroup.map(el => el.x));
|
||||
const distance = curLeft - preRight - spacing;
|
||||
|
||||
for(const curEl of curGroup) {
|
||||
curEl.x = curEl.x - distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Fixed spacing.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 465 290" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h60m-60 0h60m0 0v60m0-60v60m0 0H10m60 0H10m0 0V10m0 60V10M50 150h60m-60 0h60m0 0v60m0-60v60m0 0H50m60 0H50m0 0v-60m0 60v-60M40 80h50m-50 0h50m0 0v60m0-60v60m0 0H40m50 0H40m0 0V80m0 60V80M70 220h30m-30 0h30m0 0v60m0-60v60m0 0H70m30 0H70m0 0v-60m0 60v-60M240 10h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0V10m0 60V10M360 150h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0v-60m0 60v-60M305 80h50m-50 0h50m0 0v60m0-60v60m0 0h-50m50 0h-50m0 0V80m0 60V80M425 220h30m-30 0h30m0 0v60m0-60v60m0 0h-30m30 0h-30m0 0v-60m0 60v-60"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m130 10-.58 269.33 81.66-130L130 10"/><path fill="none" stroke-width="4" d="M130 10c-.2 94.2-.41 188.39-.58 269.33M130 10c-.18 81.45-.35 162.91-.58 269.33m0 0c28.12-44.76 56.24-89.53 81.66-130m-81.66 130c19.55-31.13 39.11-62.26 81.66-130m0 0C189.8 112.77 168.53 76.2 130 10m81.08 139.33C180.58 96.91 150.07 44.49 130 10m0 0s0 0 0 0m0 0s0 0 0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
76
ea-scripts/Fixed vertical distance between centers.md
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script arranges the selected elements vertically with a fixed center spacing.
|
||||
|
||||
See documentation for more details:
|
||||
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default distance"]) {
|
||||
settings = {
|
||||
"Prompt for distance?": true,
|
||||
"Default distance" : {
|
||||
value: 10,
|
||||
description: "Fixed vertical distance between centers"
|
||||
},
|
||||
"Remember last distance?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let distanceStr = settings["Default distance"].value.toString();
|
||||
const rememberLastDistance = settings["Remember last distance?"];
|
||||
|
||||
if(settings["Prompt for distance?"]) {
|
||||
distanceStr = await utils.inputPrompt("distance?","number",distanceStr);
|
||||
}
|
||||
|
||||
const distance = parseInt(distanceStr);
|
||||
if(isNaN(distance)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastDistance) {
|
||||
settings["Default distance"].value = distance;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements)
|
||||
.filter(els => !(els.length === 1 && els[0].type ==="arrow")) // ignore individual arrows
|
||||
.filter(els => !(els.length === 1 && (els[0].containerId))); // ignore text in stickynote
|
||||
|
||||
const groups = topGroups.sort((lha,rha) => lha[0].y - rha[0].y);
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const preGroup = groups[i-1];
|
||||
const curGroup = groups[i];
|
||||
|
||||
const preTop = Math.min(...preGroup.map(el => el.y));
|
||||
const preBottom = Math.max(...preGroup.map(el => el.y + el.height));
|
||||
const preCenter = preTop + (preBottom - preTop) / 2;
|
||||
const curTop = Math.min(...curGroup.map(el => el.y));
|
||||
const curBottom = Math.max(...curGroup.map(el => el.y + el.height));
|
||||
const curCenter = curTop + (curBottom - curTop) / 2;
|
||||
const distanceBetweenCenters = curCenter - preCenter - distance;
|
||||
|
||||
for(const curEl of curGroup) {
|
||||
curEl.y = curEl.y - distanceBetweenCenters;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Fixed vertical distance between centers.svg
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
69
ea-scripts/Fixed vertical distance.md
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
The script arranges the selected elements vertically with a fixed spacing.
|
||||
|
||||
When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default spacing"]) {
|
||||
settings = {
|
||||
"Prompt for spacing?": true,
|
||||
"Default spacing" : {
|
||||
value: 10,
|
||||
description: "Fixed vertical spacing between elements"
|
||||
},
|
||||
"Remember last spacing?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let spacingStr = settings["Default spacing"].value.toString();
|
||||
const rememberLastSpacing = settings["Remember last spacing?"];
|
||||
|
||||
if(settings["Prompt for spacing?"]) {
|
||||
spacingStr = await utils.inputPrompt("spacing?","number",spacingStr);
|
||||
}
|
||||
|
||||
const spacing = parseInt(spacingStr);
|
||||
if(isNaN(spacing)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastSpacing) {
|
||||
settings["Default spacing"].value = spacing;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements();
|
||||
const topGroups = ea.getMaximumGroups(elements)
|
||||
.filter(els => !(els.length === 1 && els[0].type ==="arrow")) // ignore individual arrows
|
||||
.filter(els => !(els.length === 1 && (els[0].containerId))); // ignore text in stickynote
|
||||
|
||||
const groups = topGroups.sort((lha,rha) => lha[0].y - rha[0].y);
|
||||
|
||||
for(var i=0; i<groups.length; i++) {
|
||||
if(i > 0) {
|
||||
const preGroup = groups[i-1];
|
||||
const curGroup = groups[i];
|
||||
|
||||
const preBottom = Math.max(...preGroup.map(el => el.y + el.height));
|
||||
const curTop = Math.min(...curGroup.map(el => el.y));
|
||||
const distance = curTop - preBottom - spacing;
|
||||
|
||||
for(const curEl of curGroup) {
|
||||
curEl.y = curEl.y - distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Fixed vertical distance.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 460 290" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h60m-60 0h60m0 0v60m0-60v60m0 0H10m60 0H10m0 0V10m0 60V10M90 80h60m-60 0h60m0 0v60m0-60v60m0 0H90m60 0H90m0 0V80m0 60V80M50 50h50m-50 0h50m0 0v60m0-60v60m0 0H50m50 0H50m0 0V50m0 60V50M130 150h30m-30 0h30m0 0v60m0-60v60m0 0h-30m30 0h-30m0 0v-60m0 60v-60"/><g fill-rule="evenodd" stroke-linecap="round"><path stroke-width="0" d="m190.583 10-.58 269.33 81.66-130L190.583 10"/><path fill="none" stroke-width="4" d="M190.583 10c-.2 94.2-.41 188.39-.58 269.33m.58-269.33c-.18 81.45-.35 162.91-.58 269.33m0 0c28.12-44.76 56.24-89.53 81.66-130m-81.66 130c19.55-31.13 39.11-62.26 81.66-130m0 0c-21.28-36.56-42.55-73.13-81.08-139.33m81.08 139.33c-30.5-52.42-61.01-104.84-81.08-139.33m0 0s0 0 0 0m0 0s0 0 0 0"/></g><path fill="none" stroke-linecap="round" stroke-width="4" d="M300 10h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0V10m0 60V10M380 150h60m-60 0h60m0 0v60m0-60v60m0 0h-60m60 0h-60m0 0v-60m0 60v-60M340 80h50m-50 0h50m0 0v60m0-60v60m0 0h-50m50 0h-50m0 0V80m0 60V80M420 220h30m-30 0h30m0 0v60m0-60v60m0 0h-30m30 0h-30m0 0v-60m0 60v-60"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
67
ea-scripts/Grid Selected Images.md
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||

|
||||
|
||||
This script arranges selected images into compact grid view, removing gaps in-between, resizing when necessary and breaking into multiple rows/columns.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
try {
|
||||
let els = ea.getViewSelectedElements().filter(el => el.type == 'image');
|
||||
|
||||
new Notice(els.length);
|
||||
|
||||
if (els.length == 0) throw new Error('No image elements selected');
|
||||
|
||||
const bounds = ea.getBoundingBox(els);
|
||||
const { topX, topY, width, height } = bounds;
|
||||
|
||||
els.sort((a, b) => a.x + a.y < b.x + b.y);
|
||||
|
||||
const areaAvailable = width * height;
|
||||
|
||||
let elWidth = els[0].width;
|
||||
let elHeight = els[0].height;
|
||||
|
||||
if (elWidth * elHeight > areaAvailable) {
|
||||
while (elWidth * elHeight > areaAvailable) {
|
||||
elWidth /= 1.1;
|
||||
elHeight /= 1.1;
|
||||
}
|
||||
} else if (elWidth * elHeight < areaAvailable) {
|
||||
while (elWidth * elHeight > areaAvailable) {
|
||||
elWidth *= 1.1;
|
||||
elHeight *= 1.1;
|
||||
}
|
||||
}
|
||||
|
||||
const rows = (width - elWidth) / elWidth;
|
||||
|
||||
let row = 0, column = 0;
|
||||
for (const element of els) {
|
||||
element.x = topX + (elWidth * row);
|
||||
element.y = topY + (elHeight * column);
|
||||
|
||||
if (element.width > elWidth) {
|
||||
while (element.width >= elWidth) {
|
||||
element.width /= 1.1;
|
||||
element.height /= 1.1;
|
||||
}
|
||||
} else if (element.width < elWidth) {
|
||||
while (element.width <= elWidth) {
|
||||
element.width *= 1.1;
|
||||
element.height *= 1.1;
|
||||
}
|
||||
}
|
||||
|
||||
row++;
|
||||
if (row > rows) {
|
||||
row = 0;
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
ea.addElementsToView(false, true, true);
|
||||
} catch (err) {
|
||||
_ = new Notice(err.toString())
|
||||
}
|
||||
2
ea-scripts/Grid Selected Images.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 376.3492303436433 256.64929991179815" stroke="#000">
|
||||
<g stroke-linecap="round" transform="translate(10 10) rotate(0 58.5858154296875 58.5858154296875)"><path d="M-1.64 1.57 C38.67 2.87, 77.63 0.2, 117.31 1.14 M-0.05 -0.5 C40.75 0.3, 82.48 0.12, 118.09 0.99 M116.67 0.11 C118.02 47.69, 116.43 92.18, 118.63 118.15 M117.41 0.39 C116.57 38.93, 117.51 79.53, 116.57 116.49 M118.65 117.22 C92.96 119.01, 66.56 117.46, -0.42 117.17 M117.21 116.56 C91.43 117.53, 63.4 117.03, -0.23 117.71 M1.5 116.9 C-2.3 91.83, 1.37 68.12, -0.05 -0.85 M-0.84 116.86 C-1.03 87.92, -0.86 61.1, 0.54 0.72" stroke-width="2" fill="none"></path></g><g stroke-linecap="round" transform="translate(128.96603337932902 10.2586194164669) rotate(0 58.5858154296875 58.5858154296875)"><path d="M0.05 1.78 C24.68 -1.8, 48.73 0.22, 118.17 0.33 M-0.27 0.22 C34.72 0.61, 69.52 1.58, 118.12 0.36 M117.6 1.43 C115.71 34.53, 118.33 70.74, 117.89 116.98 M116.68 -0.46 C117.9 41.7, 116.85 81.21, 116.34 117.29 M118.4 119.11 C83.22 117.59, 48.31 117.2, -1.44 117.99 M118.15 116.77 C74.14 115.56, 31.55 116.99, -0.96 117.69 M-1.69 115.77 C1.1 78.33, -0.93 41, -1.14 1.03 M-0.43 116.37 C0.72 90.14, 1.52 62.17, 0.55 -0.66" stroke-width="2" fill="none"></path></g><g stroke-linecap="round" transform="translate(248.3020093440573 10.465294492851172) rotate(0 58.5858154296875 58.5858154296875)"><path d="M0.39 -0.88 C44.51 0.1, 89.74 -0.71, 117.03 -0.11 M0.42 0.03 C30.22 0.74, 59.56 0.11, 117.15 -0.25 M116 -0.35 C118.88 36.78, 118.14 71.41, 118.16 117.65 M117.62 0.75 C115.99 39.07, 115.76 79.63, 117.09 117.91 M117.44 117.56 C81.29 118.3, 44.81 119.12, 1.29 117.25 M116.84 116.27 C88.98 117.24, 60.29 117.22, 0.21 117.92 M1.97 115.99 C0.94 82.75, -0.15 51.05, -1.24 -1.67 M-0.26 118 C1.05 86.36, 1.06 53.45, 0.95 0.65" stroke-width="2" fill="none"></path></g><g stroke-linecap="round" transform="translate(10.875590140210988 129.01237455957016) rotate(0 58.5858154296875 58.5858154296875)"><path d="M0.24 -0.16 C29.59 1.02, 57.45 2.91, 117.44 0.38 M0.41 0.64 C32.74 0.23, 66.39 0.45, 116.84 -0.9 M118.21 0.43 C119.3 32.21, 116.11 63.55, 119.15 115.99 M117.68 -0.62 C115.84 34.54, 116.24 68.9, 116.91 118 M115.86 119.08 C76.96 118.61, 32.48 117.59, -1.75 116.45 M117.39 116.77 C85.7 116.42, 54.91 116.16, 0.1 118.13 M-0.18 118.45 C-0.52 71.18, -0.96 24.41, 1.23 0.16 M0.3 117.66 C0.57 92.18, 0.07 65.33, -0.4 0.17" stroke-width="2" fill="none"></path></g><g stroke-linecap="round" transform="translate(129.84162351954 129.27099397603888) rotate(0 58.5858154296875 58.5858154296875)"><path d="M-0.16 1.48 C27.24 1.09, 56.31 0.13, 117.56 -0.42 M0.64 0.04 C34.52 0.5, 69.88 -0.81, 116.27 -0.23 M117.6 1.5 C115.78 39.75, 114.64 84.85, 115.99 117.12 M116.55 -0.84 C116.19 29.74, 115.7 60.09, 118 117.71 M119.08 118.46 C74.37 114.72, 29.76 114.66, -0.72 116.45 M116.77 116.64 C81.73 117.03, 46.47 117.52, 0.96 118.05 M1.28 117.07 C0.37 77.34, -0.95 39.83, 0.16 -1.64 M0.49 117.63 C0.17 83.07, -1.11 48.64, 0.17 0.23" stroke-width="2" fill="none"></path></g><g stroke-linecap="round" transform="translate(249.17759948426828 129.47766905242315) rotate(0 58.5858154296875 58.5858154296875)"><path d="M1.48 0.05 C26.67 2.03, 51.16 0.48, 116.75 0 M0.04 -0.61 C27.7 -1.15, 53.12 -1.65, 116.94 0.54 M118.67 -0.27 C116.09 22.53, 119.75 46.69, 117.12 116.32 M116.34 -0.31 C117.34 27.65, 117.51 57.73, 117.71 117.89 M118.46 117.96 C73.87 118.06, 32.19 117.57, -0.72 117.14 M116.64 116.71 C84.55 115.98, 52.82 117.66, 0.88 117.52 M-0.11 116.63 C-0.44 89.26, 1.33 65.24, -1.64 -0.19 M0.46 117.75 C-0.38 77.25, -0.75 38.91, 0.23 0.69" stroke-width="2" fill="none"></path></g></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
52
ea-scripts/Lighten background color.md
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script lightens the background color of the selected element by 2% at a time.
|
||||
|
||||
You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect.
|
||||
|
||||
In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.
|
||||
|
||||
The color conversion method was copied from [color-convert](https://github.com/Qix-/color-convert).
|
||||
|
||||
```javascript
|
||||
*/
|
||||
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.7.19")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
let settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Step size"]) {
|
||||
settings = {
|
||||
"Step size" : {
|
||||
value: 2,
|
||||
description: "Step size in percentage for making the color lighter"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const step = settings["Step size"].value;
|
||||
|
||||
const elements = ea
|
||||
.getViewSelectedElements()
|
||||
.filter((el) =>
|
||||
["rectangle", "ellipse", "diamond", "image", "line", "freedraw"].includes(el.type)
|
||||
);
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
for (const el of ea.getElements()) {
|
||||
const color = ea.colorNameToHex(el.backgroundColor);
|
||||
const cm = ea.getCM(color);
|
||||
if (cm) {
|
||||
const lighter = cm.lighterBy(step);
|
||||
if(Math.ceil(lighter.lightness)<100) el.backgroundColor = lighter.stringHSL();
|
||||
}
|
||||
}
|
||||
await ea.addElementsToView(false, false);
|
||||
1
ea-scripts/Lighten background color.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="50 -20 600 600"><path d="M350 0c-74.262 0-145.48 29.5-197.99 82.012a279.995 279.995 0 0 0 0 395.98 279.995 279.995 0 0 0 395.98 0 279.995 279.995 0 0 0 0-395.98A279.992 279.992 0 0 0 350 0zm140 324.8H210v-89.602h280z"/></svg>
|
||||
|
After Width: | Height: | Size: 274 B |
113
ea-scripts/Mindmap connector.md
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||

|
||||
This script creates mindmap like lines(only right and down side are available). The line will starts according to the creation time of the elements. So you may need to create the header element first.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
const elements = ea.getViewSelectedElements();
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
groups = ea.getMaximumGroups(elements);
|
||||
|
||||
els=[];
|
||||
elsx=[];
|
||||
elsy=[];
|
||||
for (i = 0, len =groups.length; i < len; i++) {
|
||||
els.push(ea.getLargestElement(groups[i]));
|
||||
elsx.push(ea.getLargestElement(groups[i]).x);
|
||||
elsy.push(ea.getLargestElement(groups[i]).y);
|
||||
}
|
||||
//line style setting
|
||||
ea.style.strokeColor = els[0].strokeColor;
|
||||
ea.style.strokeWidth = els[0].strokeWidth;
|
||||
ea.style.strokeStyle = els[0].strokeStyle;
|
||||
ea.style.strokeSharpness = els[0].strokeSharpness;
|
||||
//all min max x y
|
||||
let maxy = Math.max.apply(null, elsy);
|
||||
let indexmaxy=elsy.indexOf(maxy);
|
||||
let miny = Math.min.apply(null, elsy);
|
||||
let indexminy = elsy.indexOf(miny);
|
||||
let maxx = Math.max.apply(null, elsx);
|
||||
let indexmaxx = elsx.indexOf(maxx);
|
||||
let minx = Math.min.apply(null, elsx);
|
||||
let indexminx = elsx.indexOf(minx);
|
||||
//child max min x y
|
||||
let gmaxy = Math.max.apply(null, elsy.slice(1));
|
||||
let gindexmaxy=elsy.indexOf(gmaxy);
|
||||
let gminy = Math.min.apply(null, elsy.slice(1));
|
||||
let gindexminy = elsy.indexOf(gminy);
|
||||
let gmaxx = Math.max.apply(null, elsx.slice(1));
|
||||
let gindexmaxx = elsx.indexOf(gmaxx);
|
||||
let gminx = Math.min.apply(null, elsx.slice(1));
|
||||
let gindexminx = elsx.indexOf(gminx);
|
||||
let s=0;//Set line direction down as default
|
||||
if (indexminx==0 && els[0].x + els[0].width<=gminx) {
|
||||
s=1;
|
||||
}
|
||||
else if (indexminy == 0) {
|
||||
s=0;
|
||||
}
|
||||
var length_left;
|
||||
if(els[0].x + els[0].width * 2<=gminx){length_left=els[0].x + els[0].width * 1.5;}
|
||||
else {length_left=(els[0].x + els[0].width+gminx)/2;}
|
||||
|
||||
var length_down;
|
||||
if(els[0].y + els[0].height* 2.5<=gminy){length_down=els[0].y + els[0].height * 2;}
|
||||
else {length_down=(els[0].y + els[0].height+gminy)/2;}
|
||||
if(s) {
|
||||
ea.addLine(
|
||||
[[length_left,
|
||||
maxy + els[indexmaxy].height / 2],
|
||||
[length_left,
|
||||
miny + els[indexminy].height / 2]]
|
||||
);
|
||||
for (i = 1, len = groups.length; i < len; i++) {
|
||||
ea.addLine(
|
||||
[[els[i].x,
|
||||
els[i].y + els[i].height/2],
|
||||
[length_left,
|
||||
els[i].y + els[i].height/2]]
|
||||
);
|
||||
}
|
||||
ea.addArrow(
|
||||
[[els[0].x+els[0].width,
|
||||
els[0].y + els[0].height / 2],
|
||||
[length_left,
|
||||
els[0].y + els[0].height / 2]],
|
||||
{
|
||||
startArrowHead: "none",
|
||||
endArrowHead: "dot"
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
else {
|
||||
ea.addLine(
|
||||
[[maxx + els[indexmaxx].width / 2,
|
||||
length_down],
|
||||
[minx + els[indexminx].width / 2,
|
||||
length_down]]
|
||||
);
|
||||
for (i = 1, len = groups.length; i < len; i++) {
|
||||
ea.addLine(
|
||||
[[els[i].x + els[i].width / 2,
|
||||
els[i].y],
|
||||
[els[i].x + els[i].width / 2,
|
||||
length_down]]
|
||||
);
|
||||
}
|
||||
ea.addArrow(
|
||||
[[els[0].x + els[0].width / 2,
|
||||
els[0].y + els[0].height],
|
||||
[els[0].x + els[0].width / 2,
|
||||
length_down]],
|
||||
{
|
||||
startArrowHead: "none",
|
||||
endArrowHead: "dot"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
await ea.addElementsToView(false,false,true);
|
||||
12
ea-scripts/Mindmap connector.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg width="607" height="541" viewBox="0 0 607 541" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M280 43.355V253.355H140V206.687L0 206.691V346.691H140V300.023H280V510.023C280 522.925 290.453 533.355 303.332 533.355H490.002C502.904 533.355 513.334 522.925 513.334 510.023C513.334 497.144 502.904 486.691 490.002 486.691H326.672V300.021H490.002C502.904 300.021 513.334 289.568 513.334 276.689C513.334 263.81 502.904 253.357 490.002 253.357H326.672V66.6869H490.002C502.904 66.6869 513.334 56.2569 513.334 43.3549C513.334 30.4529 502.904 20.0229 490.002 20.0229H303.332C290.453 20.019 280 30.4489 280 43.3509V43.355ZM46.67 300.025V253.357H93.338V300.025H46.67Z" fill="black"/>
|
||||
<rect x="540" y="23" width="39" height="39" fill="#D9D9D9"/>
|
||||
<rect x="503" width="104" height="95" fill="#D9D9D9"/>
|
||||
<rect x="503.5" y="0.5" width="103" height="94" fill="black" stroke="black"/>
|
||||
<rect x="503" y="223" width="104" height="95" fill="black"/>
|
||||
<rect x="503.5" y="446.5" width="103" height="94" fill="black" stroke="black"/>
|
||||
<path d="M532 243H580V291H532V243Z" fill="white"/>
|
||||
<path d="M532 475H580V523H532V475Z" fill="white"/>
|
||||
<path d="M532 243H580V291H532V243Z" fill="white"/>
|
||||
<path d="M532 23H580V71H532V23Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
216
ea-scripts/Modify background color opacity.md
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||

|
||||
|
||||
Download this file and save to your Obsidian Vault including the first line, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
This script changes the opacity of the background color of the selected boxes.
|
||||
|
||||
The default background color in Excalidraw is so dark that the text is hard to read. You can lighten the color a bit by setting transparency. And you can tweak the transparency over and over again until you're happy with it.
|
||||
|
||||
Although excalidraw has the opacity option in its native property Settings, it also changes the transparency of the border. Use this script to change only the opacity of the background color without affecting the border.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Default opacity"]) {
|
||||
settings = {
|
||||
"Prompt for opacity?": true,
|
||||
"Default opacity" : {
|
||||
value: 0.6,
|
||||
description: "Element's background color transparency"
|
||||
},
|
||||
"Remember last opacity?": false
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let opacityStr = settings["Default opacity"].value.toString();
|
||||
const rememberLastOpacity = settings["Remember last opacity?"];
|
||||
|
||||
if(settings["Prompt for opacity?"]) {
|
||||
opacityStr = await utils.inputPrompt("Background color opacity?","number",opacityStr);
|
||||
}
|
||||
|
||||
const alpha = parseFloat(opacityStr);
|
||||
if(isNaN(alpha)) {
|
||||
return;
|
||||
}
|
||||
if(rememberLastOpacity) {
|
||||
settings["Default opacity"].value = alpha;
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
const elements=ea.getViewSelectedElements().filter((el)=>["rectangle","ellipse","diamond","line","image"].includes(el.type));
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
ea.getElements().forEach((el)=>{
|
||||
const color = colorNameToHex(el.backgroundColor);
|
||||
const rgbColor = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
|
||||
if(rgbColor) {
|
||||
const r = parseInt(rgbColor[1], 16);
|
||||
const g = parseInt(rgbColor[2], 16);
|
||||
const b = parseInt(rgbColor[3], 16);
|
||||
el.backgroundColor=`rgba(${r},${g},${b},${alpha})`;
|
||||
}
|
||||
else {
|
||||
const rgbaColor = /^rgba\((\d+,\d+,\d+,)(\d*\.?\d*)\)$/i.exec(color);
|
||||
if(rgbaColor) {
|
||||
el.backgroundColor=`rgba(${rgbaColor[1]}${alpha})`;
|
||||
}
|
||||
}
|
||||
});
|
||||
await ea.addElementsToView(false, false);
|
||||
|
||||
function colorNameToHex(color) {
|
||||
const colors = {
|
||||
"aliceblue":"#f0f8ff",
|
||||
"antiquewhite":"#faebd7",
|
||||
"aqua":"#00ffff",
|
||||
"aquamarine":"#7fffd4",
|
||||
"azure":"#f0ffff",
|
||||
"beige":"#f5f5dc",
|
||||
"bisque":"#ffe4c4",
|
||||
"black":"#000000",
|
||||
"blanchedalmond":"#ffebcd",
|
||||
"blue":"#0000ff",
|
||||
"blueviolet":"#8a2be2",
|
||||
"brown":"#a52a2a",
|
||||
"burlywood":"#deb887",
|
||||
"cadetblue":"#5f9ea0",
|
||||
"chartreuse":"#7fff00",
|
||||
"chocolate":"#d2691e",
|
||||
"coral":"#ff7f50",
|
||||
"cornflowerblue":"#6495ed",
|
||||
"cornsilk":"#fff8dc",
|
||||
"crimson":"#dc143c",
|
||||
"cyan":"#00ffff",
|
||||
"darkblue":"#00008b",
|
||||
"darkcyan":"#008b8b",
|
||||
"darkgoldenrod":"#b8860b",
|
||||
"darkgray":"#a9a9a9",
|
||||
"darkgreen":"#006400",
|
||||
"darkkhaki":"#bdb76b",
|
||||
"darkmagenta":"#8b008b",
|
||||
"darkolivegreen":"#556b2f",
|
||||
"darkorange":"#ff8c00",
|
||||
"darkorchid":"#9932cc",
|
||||
"darkred":"#8b0000",
|
||||
"darksalmon":"#e9967a",
|
||||
"darkseagreen":"#8fbc8f",
|
||||
"darkslateblue":"#483d8b",
|
||||
"darkslategray":"#2f4f4f",
|
||||
"darkturquoise":"#00ced1",
|
||||
"darkviolet":"#9400d3",
|
||||
"deeppink":"#ff1493",
|
||||
"deepskyblue":"#00bfff",
|
||||
"dimgray":"#696969",
|
||||
"dodgerblue":"#1e90ff",
|
||||
"firebrick":"#b22222",
|
||||
"floralwhite":"#fffaf0",
|
||||
"forestgreen":"#228b22",
|
||||
"fuchsia":"#ff00ff",
|
||||
"gainsboro":"#dcdcdc",
|
||||
"ghostwhite":"#f8f8ff",
|
||||
"gold":"#ffd700",
|
||||
"goldenrod":"#daa520",
|
||||
"gray":"#808080",
|
||||
"green":"#008000",
|
||||
"greenyellow":"#adff2f",
|
||||
"honeydew":"#f0fff0",
|
||||
"hotpink":"#ff69b4",
|
||||
"indianred ":"#cd5c5c",
|
||||
"indigo":"#4b0082",
|
||||
"ivory":"#fffff0",
|
||||
"khaki":"#f0e68c",
|
||||
"lavender":"#e6e6fa",
|
||||
"lavenderblush":"#fff0f5",
|
||||
"lawngreen":"#7cfc00",
|
||||
"lemonchiffon":"#fffacd",
|
||||
"lightblue":"#add8e6",
|
||||
"lightcoral":"#f08080",
|
||||
"lightcyan":"#e0ffff",
|
||||
"lightgoldenrodyellow":"#fafad2",
|
||||
"lightgrey":"#d3d3d3",
|
||||
"lightgreen":"#90ee90",
|
||||
"lightpink":"#ffb6c1",
|
||||
"lightsalmon":"#ffa07a",
|
||||
"lightseagreen":"#20b2aa",
|
||||
"lightskyblue":"#87cefa",
|
||||
"lightslategray":"#778899",
|
||||
"lightsteelblue":"#b0c4de",
|
||||
"lightyellow":"#ffffe0",
|
||||
"lime":"#00ff00",
|
||||
"limegreen":"#32cd32",
|
||||
"linen":"#faf0e6",
|
||||
"magenta":"#ff00ff",
|
||||
"maroon":"#800000",
|
||||
"mediumaquamarine":"#66cdaa",
|
||||
"mediumblue":"#0000cd",
|
||||
"mediumorchid":"#ba55d3",
|
||||
"mediumpurple":"#9370d8",
|
||||
"mediumseagreen":"#3cb371",
|
||||
"mediumslateblue":"#7b68ee",
|
||||
"mediumspringgreen":"#00fa9a",
|
||||
"mediumturquoise":"#48d1cc",
|
||||
"mediumvioletred":"#c71585",
|
||||
"midnightblue":"#191970",
|
||||
"mintcream":"#f5fffa",
|
||||
"mistyrose":"#ffe4e1",
|
||||
"moccasin":"#ffe4b5",
|
||||
"navajowhite":"#ffdead",
|
||||
"navy":"#000080",
|
||||
"oldlace":"#fdf5e6",
|
||||
"olive":"#808000",
|
||||
"olivedrab":"#6b8e23",
|
||||
"orange":"#ffa500",
|
||||
"orangered":"#ff4500",
|
||||
"orchid":"#da70d6",
|
||||
"palegoldenrod":"#eee8aa",
|
||||
"palegreen":"#98fb98",
|
||||
"paleturquoise":"#afeeee",
|
||||
"palevioletred":"#d87093",
|
||||
"papayawhip":"#ffefd5",
|
||||
"peachpuff":"#ffdab9",
|
||||
"peru":"#cd853f",
|
||||
"pink":"#ffc0cb",
|
||||
"plum":"#dda0dd",
|
||||
"powderblue":"#b0e0e6",
|
||||
"purple":"#800080",
|
||||
"rebeccapurple":"#663399",
|
||||
"red":"#ff0000",
|
||||
"rosybrown":"#bc8f8f",
|
||||
"royalblue":"#4169e1",
|
||||
"saddlebrown":"#8b4513",
|
||||
"salmon":"#fa8072",
|
||||
"sandybrown":"#f4a460",
|
||||
"seagreen":"#2e8b57",
|
||||
"seashell":"#fff5ee",
|
||||
"sienna":"#a0522d",
|
||||
"silver":"#c0c0c0",
|
||||
"skyblue":"#87ceeb",
|
||||
"slateblue":"#6a5acd",
|
||||
"slategray":"#708090",
|
||||
"snow":"#fffafa",
|
||||
"springgreen":"#00ff7f",
|
||||
"steelblue":"#4682b4",
|
||||
"tan":"#d2b48c",
|
||||
"teal":"#008080",
|
||||
"thistle":"#d8bfd8",
|
||||
"tomato":"#ff6347",
|
||||
"turquoise":"#40e0d0",
|
||||
"violet":"#ee82ee",
|
||||
"wheat":"#f5deb3",
|
||||
"white":"#ffffff",
|
||||
"whitesmoke":"#f5f5f5",
|
||||
"yellow":"#ffff00",
|
||||
"yellowgreen":"#9acd32"
|
||||
};
|
||||
if (typeof colors[color.toLowerCase()] != 'undefined')
|
||||
return colors[color.toLowerCase()];
|
||||
return color;
|
||||
}
|
||||
1
ea-scripts/Modify background color opacity.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 550"><path d="M478.98 137.02A205.802 205.802 0 0 0 255.062 22.364a205.785 205.785 0 0 0-115.79 65.234 205.78 205.78 0 0 0-51.773 122.4 205.1 205.1 0 0 0 120.399 201.249 210.043 210.043 0 0 0 88.988 102.84 210 210 0 0 0 255.1-33.793 209.995 209.995 0 0 0 59.137-122.46 209.99 209.99 0 0 0-28.293-133.02 209.985 209.985 0 0 0-103.86-87.793zm-186.9-84.523h10.5a170.974 170.974 0 0 1 102.6 42.441 170.932 170.932 0 0 1 54.898 96.508l-194.95-136.68a171.623 171.623 0 0 1 26.949-2.273zm-70 15.051 230.12 161.88 9.45 6.648a171.28 171.28 0 0 1-22.048 71.75l-275.62-197.4a170.925 170.925 0 0 1 58.45-42.875zm-78.398 71.398 276.32 197.4a171.807 171.807 0 0 1-58.102 43.047l-239.4-175.7a169.266 169.266 0 0 1 21.176-64.75zm-21.176 108.32 197.57 144.73a165.295 165.295 0 0 1-38.5 2.102 171.169 171.169 0 0 1-105.7-45.07 171.164 171.164 0 0 1-53.375-101.76zm280 260.23a176.25 176.25 0 0 1-84.371-21.984 176.27 176.27 0 0 1-63.504-59.742 197.049 197.049 0 0 0 24.852 3.328h12.773a206.319 206.319 0 0 0 140.66-55.766 206.312 206.312 0 0 0 64.789-136.73 202.42 202.42 0 0 0-3.848-52.5 175.017 175.017 0 0 1 70.512 85.367 175.016 175.016 0 0 1 5.157 110.61 174.986 174.986 0 0 1-62.262 91.562 175.008 175.008 0 0 1-104.76 35.863z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
91
ea-scripts/Normalize Selected Arrows.md
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||

|
||||
|
||||
This script will reset the start and end positions of the selected arrows. The arrow will point to the center of the connected box and will have a gap of 8px from the box.
|
||||
|
||||
Tips: If you are drawing a flowchart, you can use `Normalize Selected Arrows` script to correct the position of the start and end points of the arrows, then use `Elbow connectors` script, and you will get the perfect connecting line!
|
||||
|
||||
```javascript
|
||||
*/
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.5.21")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Gap"]) {
|
||||
settings = {
|
||||
"Gap" : {
|
||||
value: 8,
|
||||
description: "The value of the gap between the connection line and the element, which must be greater than 0. If you want the connector to be next to the element, set it to 1."
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
let gapValue = settings["Gap"].value;
|
||||
|
||||
const selectedIndividualArrows = ea.getMaximumGroups(ea.getViewSelectedElements())
|
||||
.reduce((result, g) => [...result, ...g.filter(el => el.type === 'arrow')], []);
|
||||
|
||||
const allElements = ea.getViewElements();
|
||||
for(const arrow of selectedIndividualArrows) {
|
||||
const startBindingEl = allElements.filter(el => el.id === (arrow.startBinding||{}).elementId)[0];
|
||||
const endBindingEl = allElements.filter(el => el.id === (arrow.endBinding||{}).elementId)[0];
|
||||
|
||||
if(startBindingEl) {
|
||||
recalculateStartPointOfLine(arrow, startBindingEl, endBindingEl, gapValue);
|
||||
}
|
||||
if(endBindingEl) {
|
||||
recalculateEndPointOfLine(arrow, endBindingEl, startBindingEl, gapValue);
|
||||
}
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(selectedIndividualArrows);
|
||||
await ea.addElementsToView(false,false);
|
||||
|
||||
function recalculateStartPointOfLine(line, el, elB, gapValue) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = (line.points.length <=2 && elB) ? elB.x + elB.width/2 : line.x + line.points[1][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = (line.points.length <=2 && elB) ? elB.y + elB.height/2 : line.y + line.points[1][1];
|
||||
|
||||
line.startBinding.gap = gapValue;
|
||||
line.startBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.startBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[0] = [0, 0];
|
||||
for(var i = 1; i<line.points.length; i++) {
|
||||
line.points[i][0] -= intersectA[0][0] - line.x;
|
||||
line.points[i][1] -= intersectA[0][1] - line.y;
|
||||
}
|
||||
line.x = intersectA[0][0];
|
||||
line.y = intersectA[0][1];
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateEndPointOfLine(line, el, elB, gapValue) {
|
||||
const aX = el.x + el.width/2;
|
||||
const bX = (line.points.length <=2 && elB) ? elB.x + elB.width/2 : line.x + line.points[line.points.length-2][0];
|
||||
const aY = el.y + el.height/2;
|
||||
const bY = (line.points.length <=2 && elB) ? elB.y + elB.height/2 : line.y + line.points[line.points.length-2][1];
|
||||
|
||||
line.endBinding.gap = gapValue;
|
||||
line.endBinding.focus = 0;
|
||||
const intersectA = ea.intersectElementWithLine(
|
||||
el,
|
||||
[bX, bY],
|
||||
[aX, aY],
|
||||
line.endBinding.gap
|
||||
);
|
||||
|
||||
if(intersectA.length > 0) {
|
||||
line.points[line.points.length - 1] = [intersectA[0][0] - line.x, intersectA[0][1] - line.y];
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Normalize Selected Arrows.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" stroke="#000"><path fill="none" stroke-linecap="round" stroke-width="4" d="M10 10h80m-80 0h80m0 0v40m0-40v40m0 0H10m80 0H10m0 0V10m0 40V10"/><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M10 90c4.5-6.67 22.5-33.33 27-40M10 90c4.5-6.67 22.5-33.33 27-40"/><path fill-rule="evenodd" stroke-width="0" d="m37 50-2.35 14.81-10.51-7.09L37 50"/><path fill="none" stroke-width="4" d="M37 50c-.55 3.44-1.09 6.89-2.35 14.81M37 50c-.9 5.69-1.81 11.39-2.35 14.81m0 0c-4.05-2.73-8.1-5.46-10.51-7.09m10.51 7.09c-2.73-1.83-5.45-3.67-10.51-7.09m0 0C26.78 56.13 29.43 54.55 37 50m-12.86 7.72C29.26 54.65 34.39 51.57 37 50m0 0s0 0 0 0m0 0s0 0 0 0"/></g><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M90 90 63 51.67M90 90 63 51.67"/><path fill-rule="evenodd" stroke-width="0" d="m63 51.67 13.01 7.46-10.36 7.3L63 51.67"/><path fill="none" stroke-width="4" d="M63 51.67c3.02 1.73 6.03 3.46 13.01 7.46M63 51.67c3.43 1.97 6.87 3.94 13.01 7.46m0 0c-3.33 2.34-6.65 4.69-10.36 7.3m10.36-7.3c-3.43 2.42-6.86 4.84-10.36 7.3m0 0c-.96-5.35-1.92-10.7-2.65-14.76m2.65 14.76c-.9-4.99-1.79-9.98-2.65-14.76m0 0s0 0 0 0m0 0s0 0 0 0"/></g><g stroke-linecap="round"><path fill="none" stroke-width="4" d="M50 90V50m0 40V50"/><path fill-rule="evenodd" stroke-width="0" d="m50 50 6.34 13.59H43.66L50 50"/><path fill="none" stroke-width="4" d="M50 50c2.27 4.86 4.53 9.72 6.34 13.59M50 50c1.62 3.47 3.24 6.95 6.34 13.59m0 0H43.66m12.68 0H43.66m0 0C46.18 58.2 48.69 52.81 50 50m-6.34 13.59C45.75 59.12 47.84 54.64 50 50m0 0s0 0 0 0m0 0s0 0 0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
32
ea-scripts/Organic Line.md
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||

|
||||
|
||||
Converts selected freedraw lines such that pencil pressure will decrease from maximum to minimum from the beginning of the line to its end. The resulting line is placed at the back of the layers, under all other items. Helpful when drawing organic mindmaps.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
let elements = ea.getViewSelectedElements().filter((el)=>["freedraw","line","arrow"].includes(el.type));
|
||||
if(elements.length === 0) {
|
||||
elements = ea.getViewSelectedElements();
|
||||
const len = elements.length;
|
||||
if(len === 0 || ["freedraw","line","arrow"].includes(elements[len].type)) {
|
||||
return;
|
||||
}
|
||||
elements = [elements[len]];
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(elements);
|
||||
|
||||
ea.getElements().forEach((el)=>{
|
||||
el.simulatePressure = false;
|
||||
el.type = "freedraw";
|
||||
el.pressures = [];
|
||||
const len = el.points.length;
|
||||
for(i=0;i<len;i++)
|
||||
el.pressures.push((len-i)/len);
|
||||
});
|
||||
|
||||
await ea.addElementsToView(false,true);
|
||||
elements.forEach((el)=>ea.moveViewElementToZIndex(el.id,0));
|
||||
const ids=ea.getElements().map(el=>el.id);
|
||||
ea.selectElementsInView(ea.getViewElements().filter(el=>ids.contains(el.id)));
|
||||
1
ea-scripts/Organic Line.svg
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
188
ea-scripts/Palette loader.md
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
Design your palette at http://paletton.com/
|
||||
Once you are happy with your colors, click Tables/Export in the bottom right of the screen:
|
||||

|
||||
Then click "Color swatches/as Sketch Palette"
|
||||

|
||||
Copy the contents of the page to a markdown file in your vault. Place the file in the Excalidraw/Palettes folder (you can change this folder in settings).
|
||||

|
||||

|
||||
|
||||
```javascript
|
||||
*/
|
||||
//--------------------------
|
||||
// Load settings
|
||||
//--------------------------
|
||||
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.7.19")) {
|
||||
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
|
||||
return;
|
||||
}
|
||||
|
||||
const api = ea.getExcalidrawAPI();
|
||||
let settings = ea.getScriptSettings();
|
||||
//set default values on first run
|
||||
if(!settings["Palette folder"]) {
|
||||
settings = {
|
||||
"Palette folder" : {
|
||||
value: "Excalidraw/Palettes",
|
||||
description: "The path to the folder where you store the Excalidraw Palettes"
|
||||
},
|
||||
"Light-gray" : {
|
||||
value: "#505050",
|
||||
description: "Base light-gray used for mixing with the accent color to generate the palette light-gray"
|
||||
},
|
||||
"Dark-gray" : {
|
||||
value: "#e0e0e0",
|
||||
description: "Base dark-gray used for mixing with the accent color to generate the palette dark-gray"
|
||||
}
|
||||
};
|
||||
ea.setScriptSettings(settings);
|
||||
}
|
||||
|
||||
const lightGray = settings["Light-gray"].value;
|
||||
const darkGray = settings["Dark-gray"].value;
|
||||
|
||||
let paletteFolder = settings["Palette folder"].value.toLowerCase();
|
||||
if(paletteFolder === "" || paletteFolder === "/") {
|
||||
new Notice("The palette folder cannot be the root folder of your vault");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!paletteFolder.endsWith("/")) paletteFolder += "/";
|
||||
|
||||
|
||||
//--------------------------
|
||||
// Select palette
|
||||
//--------------------------
|
||||
const palettes = app.vault.getFiles()
|
||||
.filter(f=>f.extension === "md" && f.path.toLowerCase() === paletteFolder + f.name.toLowerCase())
|
||||
.sort((a,b)=>a.basename.toLowerCase()<b.basename.toLowerCase()?-1:1);
|
||||
const file = await utils.suggester(["Excalidraw Default"].concat(palettes.map(f=>f.name)),["Default"].concat(palettes), "Choose a palette, press ESC to abort");
|
||||
if(!file) return;
|
||||
|
||||
if(file === "Default") {
|
||||
api.updateScene({
|
||||
appState: {
|
||||
colorPalette: {}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
//--------------------------
|
||||
// Load palette
|
||||
//--------------------------
|
||||
const sketchPalette = await app.vault.read(file);
|
||||
|
||||
const parseJSON = (data) => {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const loadPaletteFromPlainText = (data) => {
|
||||
const colors = [];
|
||||
data.replaceAll("\r","").split("\n").forEach(c=>{
|
||||
c = c.trim();
|
||||
if(c==="") return;
|
||||
if(c.match(/[^hslrga-fA-F\(\d\.\,\%\s)#]/)) return;
|
||||
const cm = ea.getCM(c);
|
||||
if(cm) colors.push(cm.stringHEX({alpha: false}));
|
||||
})
|
||||
return colors;
|
||||
}
|
||||
|
||||
const paletteJSON = parseJSON(sketchPalette);
|
||||
|
||||
const colors = paletteJSON
|
||||
? paletteJSON.colors.map(c=>ea.getCM({r:c.red*255,g:c.green*255,b:c.blue*255,a:c.alpha}).stringHEX({alpha: false}))
|
||||
: loadPaletteFromPlainText(sketchPalette);
|
||||
const baseColor = ea.getCM(colors[0]);
|
||||
|
||||
// Add black, white, transparent, gary
|
||||
const palette = [[
|
||||
"transparent",
|
||||
"black",
|
||||
baseColor.mix({color: lightGray, ratio:0.95}).stringHEX({alpha: false}),
|
||||
baseColor.mix({color: darkGray, ratio:0.95}).stringHEX({alpha: false}),
|
||||
"white"
|
||||
]];
|
||||
|
||||
// Create Excalidraw palette
|
||||
for(i=0;i<Math.floor(colors.length/5);i++) {
|
||||
palette.push([
|
||||
colors[i*5+1],
|
||||
colors[i*5+2],
|
||||
colors[i*5],
|
||||
colors[i*5+3],
|
||||
colors[i*5+4]
|
||||
]);
|
||||
}
|
||||
|
||||
const paletteSize = palette.flat().length;
|
||||
const newPalette = {
|
||||
canvasBackground: palette.flat(),
|
||||
elementStroke: palette.flat(),
|
||||
elementBackground: palette.flat()
|
||||
};
|
||||
|
||||
|
||||
//--------------------------
|
||||
// Check if palette has the same size as the current. Is re-paint possible?
|
||||
//--------------------------
|
||||
const oldPalette = api.getAppState().colorPalette;
|
||||
|
||||
//You can only switch and repaint equal size palettes
|
||||
let canRepaint = Object.keys(oldPalette).length === 3 &&
|
||||
oldPalette.canvasBackground.length === paletteSize &&
|
||||
oldPalette.elementBackground.length === paletteSize &&
|
||||
oldPalette.elementStroke.length === paletteSize;
|
||||
|
||||
//Check that the palette for canvas background, element stroke and element background are the same
|
||||
for(i=0;canRepaint && i<paletteSize;i++) {
|
||||
if(
|
||||
oldPalette.canvasBackground[i] !== oldPalette.elementBackground[i] ||
|
||||
oldPalette.canvasBackground[i] !== oldPalette.elementStroke[i]
|
||||
) {
|
||||
canRepaint = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const shouldRepaint = canRepaint && await utils.suggester(["Try repainting the drawing with the new palette","Just load the new palette"], [true, false],"ESC will load the palette without repainting");
|
||||
|
||||
|
||||
//--------------------------
|
||||
// Apply palette
|
||||
//--------------------------
|
||||
if(shouldRepaint) {
|
||||
const map = new Map();
|
||||
for(i=0;i<paletteSize;i++) {
|
||||
map.set(oldPalette.canvasBackground[i],newPalette.canvasBackground[i])
|
||||
}
|
||||
|
||||
ea.copyViewElementsToEAforEditing(ea.getViewElements());
|
||||
ea.getElements().forEach(el=>{
|
||||
el.strokeColor = map.get(el.strokeColor)??el.strokeColor;
|
||||
el.backgroundColor = map.get(el.backgroundColor)??el.backgroundColor;
|
||||
})
|
||||
|
||||
const canvasColor = api.getAppState().viewBackgroundColor;
|
||||
|
||||
await api.updateScene({
|
||||
appState: {
|
||||
colorPalette: newPalette,
|
||||
viewBackgroundColor: map.get(canvasColor)??canvasColor
|
||||
}
|
||||
});
|
||||
|
||||
ea.addElementsToView();
|
||||
} else {
|
||||
api.updateScene({
|
||||
appState: {
|
||||
colorPalette: newPalette
|
||||
}
|
||||
});
|
||||
}
|
||||
1
ea-scripts/Palette loader.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.1.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M512 255.1C512 256.9 511.1 257.8 511.1 258.7C511.6 295.2 478.4 319.1 441.9 319.1H344C317.5 319.1 296 341.5 296 368C296 371.4 296.4 374.7 297 377.9C299.2 388.1 303.5 397.1 307.9 407.8C313.9 421.6 320 435.3 320 449.8C320 481.7 298.4 510.5 266.6 511.8C263.1 511.9 259.5 512 256 512C114.6 512 0 397.4 0 256C0 114.6 114.6 0 256 0C397.4 0 512 114.6 512 256V255.1zM96 255.1C78.33 255.1 64 270.3 64 287.1C64 305.7 78.33 319.1 96 319.1C113.7 319.1 128 305.7 128 287.1C128 270.3 113.7 255.1 96 255.1zM128 191.1C145.7 191.1 160 177.7 160 159.1C160 142.3 145.7 127.1 128 127.1C110.3 127.1 96 142.3 96 159.1C96 177.7 110.3 191.1 128 191.1zM256 63.1C238.3 63.1 224 78.33 224 95.1C224 113.7 238.3 127.1 256 127.1C273.7 127.1 288 113.7 288 95.1C288 78.33 273.7 63.1 256 63.1zM384 191.1C401.7 191.1 416 177.7 416 159.1C416 142.3 401.7 127.1 384 127.1C366.3 127.1 352 142.3 352 159.1C352 177.7 366.3 191.1 384 191.1z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
77
ea-scripts/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Excalidraw Script Engine scripts library
|
||||
Click to watch the intro video:
|
||||
|
||||
[](https://youtu.be/hePJcObHIso)
|
||||
|
||||
> **Warning**
|
||||
> There is an easier way to install/manage scripts than what is shown in this video
|
||||
|
||||
See the [Excalidraw Script Engine](https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html) documentation for more details.
|
||||
|
||||
## How to install scripts into your Obsidian Vault
|
||||
To install one of the built-in scripts:
|
||||
- Open up an excalidraw drawing in Obsidian
|
||||
- In the pane dropdown menu select "Install or update Excalidraw Scripts"
|
||||
- Click on one of the available scripts
|
||||
- Click on "Install this script" (note if the script is already installed you will instead see an option to update it)
|
||||
- Restart Obsidian so the script will be picked up
|
||||
|
||||
Note: By default this will install the script into your vault in the `Excalidraw/Scripts/Downloaded` folder
|
||||
|
||||
<details><summary>Manual installation of scripts</summary>
|
||||
|
||||
Open the script you are interested in and save it to your Obsidian Vault including the first line `/*`, or open it in "Raw" and copy the entire contents to Obsidian.
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
|
||||
## List of available scripts
|
||||
|Title|Description|Icon|Contributor|
|
||||
|----|----|----|----|
|
||||
|[Add Connector Point](Add%20Connector%20Point.md)|This script will add a small circle to the top left of each text element in the selection and add the text and the "bullet point" into a group.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Add Link to Existing File and Open](Add%20Link%20to%20Existing%20File%20and%20Open.md)|Prompts for a file from the vault. Adds a link to the selected element pointing to the selected file. You can control in settings to open the file in the current active pane or an adjacent pane.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Add Link to New Page and Open](Add%20Link%20and%20Open%20Page.md)|Prompts for filename. Offers option to create and open a new Markdown or Excalidraw document. Adds link pointing to the new file, to the selected objects in the drawing. You can control in settings to open the file in the current active pane or an adjacent pane.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Add Next Step in Process](Add%20Link%20to%20New%20Page%20and%20Open.md)|This script will prompt you for the title of the process step, then will create a stick note with the text. If an element is selected then the script will connect this new step with an arrow to the previous step (the selected element). If no element is selected, then the script assumes this is the first step in the process and will only output the sticky note with the text that was entered.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Box Each Selected Groups](Box%20Each%20Selected%20Groups.md)|This script will add encapsulating boxes around each of the currently selected groups in Excalidraw.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Box Selected Elements](Box%20Selected%20Elements.md)|This script will add an encapsulating box around the currently selected elements in Excalidraw.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Change shape of selected elements](Change%20shape%20of%20selected%20elements.md)|The script allows you to change the shape of selected Rectangles, Diamonds and Ellipses||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Connect elements](Connect%20elements.md)|This script will connect two objects with an arrow. If either of the objects are a set of grouped elements (e.g. a text element grouped with an encapsulating rectangle), the script will identify these groups, and connect the arrow to the largest object in the group (assuming you want to connect the arrow to the box around the text element).||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Convert freedraw to line](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/ea-scripts/Convert%20freedraw%20to%20line.md)|Convert selected freedraw objects into editable lines. This will allow you to adjust your drawings by dragging line points and will also allow you to select shape fill in case of enclosed lines. You can adjust conversion point density in settings||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Convert selected text elements to sticky notes](Convert%20selected%20text%20elements%20to%20sticky%20notes.md)|Converts selected plain text elements to sticky notes with transparent background and transparent stroke color. Essentially converts text element into a wrappable format.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Convert text to link with folder and alias](Convert%20text%20to%20link%20with%20folder%20and%20alias.md)|Converts text elements to links pointing to a file in a selected folder and with the alias set as the original text. The script will prompt the user to select an existing folder from the vault.|`original text` => `[[selected folder/original text\|original text]]`|[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Copy Selected Element Styles to Global](Copy%20Selected%20Element%20Styles%20to%20Global)|This script will copy styles of any selected element into Excalidraw's global styles.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Create new markdown file and embed into active drawing](Create%20new%20markdown%20file%20and%20embed%20into%20active%20drawing.md)|The script will prompt you for a filename, then create a new markdown document with the file name provided, open the new markdown document in an adjacent pane, and embed the markdown document into the active Excalidraw drawing.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Darken background color](Darken%20background%20color.md)|This script darkens the background color of the selected element by 2% at a time. You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect. In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Elbow connectors](Elbow%20connectors.md)|This script converts the selected connectors to elbows.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Expand rectangles horizontally keep text centered](Expand%20rectangles%20horizontally%20keep%20text20%centered.md)|This script expands the width of the selected rectangles until they are all the same width and keep the text centered.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Expand rectangles horizontally](Expand%20rectangles%20horizontally.md)|This script expands the width of the selected rectangles until they are all the same width.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Expand rectangles vertically keep text centered](Expand%20rectangles%20vertically%20keep%20text%20centered.md)|This script expands the height of the selected rectangles until they are all the same height and keep the text centered.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Expand rectangles vertically](Expand%20rectangles%20vertically.md)|This script expands the height of the selected rectangles until they are all the same height.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Fixed horizontal distance between centers](Fixed%20horizontal%20distance%20between%20centers.md)|This script arranges the selected elements horizontally with a fixed center spacing.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Fixed inner distance](Fixed%20inner%20distance.md)|This script arranges selected elements and groups with a fixed inner distance.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Fixed spacing](Fixed%20spacing.md)|The script arranges the selected elements horizontally with a fixed spacing. When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Fixed vertical distance between centers](Fixed%20vertical%20distance%20between%20centers.md)|This script arranges the selected elements vertically with a fixed center spacing.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Fixed vertical distance](Fixed%20vertical%20distance.md)|The script arranges the selected elements vertically with a fixed spacing. When we create an architecture diagram or mind map, we often need to arrange a large number of elements in a fixed spacing. `Fixed spacing` and `Fixed vertical Distance` scripts can save us a lot of time.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Lighten background color](Lighten%20background%20color.md)|This script lightens the background color of the selected element by 2% at a time. You can use this script several times until you are satisfied. It is recommended to set a shortcut key for this script so that you can quickly try to DARKEN and LIGHTEN the color effect.In contrast to the `Modify background color opacity` script, the advantage is that the background color of the element is not affected by the canvas color, and the color value does not appear in a strange rgba() form.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Mindmap connector](Mindmap%20connector.md)|This script creates mindmap like lines (only right side and down available currently) for selected elements. The line will start according to the creation time of the elements. So you should create the header element first.||[@xllowl](https://github.com/xllowl)|
|
||||
|[Modify background color opacity](Modify%20background%20color%20opacity.md)|This script changes the opacity of the background color of the selected boxes. The default background color in Excalidraw is so dark that the text is hard to read. You can lighten the color a bit by setting transparency. And you can tweak the transparency over and over again until you're happy with it. Although excalidraw has the opacity option in its native property Settings, it also changes the transparency of the border. Use this script to change only the opacity of the background color without affecting the border.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Normalize Selected Arrows](Normalize%20Selected%20Arrows.md)|This script will reset the start and end positions of the selected arrows. The arrow will point to the center of the connected box and will have a gap of 8px from the box.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[OCR - Optical Character Recognition](OCR%20-%20Optical%20Character%20Recognition.md)|The script will 1) send the selected image file to [taskbone.com](https://taskbone.com) to exctract the text from the image, and 2) will add the text to your drawing as a text element.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Organic Line](Organic%20Line.md)|Converts selected freedraw lines such that pencil pressure will decrease from maximum to minimum from the beginning of the line to its end. The resulting line is placed at the back of the layers, under all other items. Helpful when drawing organic mindmaps.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Repeat Elements](Repeat%20Elements.md)|This script will detect the difference between 2 selected elements, including position, size, angle, stroke and background color, and create several elements that repeat these differences based on the number of repetitions entered by the user.||[@1-2-3](https://github.com/1-2-3)|
|
||||
|[Reverse arrows](Reverse%20arrows.md)|Reverse the direction of **arrows** within the scope of selected elements.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Scribble Helper](Scribble%20Helper.md)|iOS scribble helper for better handwriting experience with text elements. If no elements are selected then the creates a text element at pointer position and you can use the edit box to modify the text with scribble. If a text element is selected then opens the input prompt where you can modify this text with scribble.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Select Elements of Type](Select%20Elements%20of%20Type.md)|Prompts you with a list of the different element types in the active image. Only elements of the selected type will be selected on the canvas. If nothing is selected when running the script, then the script will process all the elements on the canvas. If some elements are selected when the script is executed, then the script will only process the selected elements.<br>The script is useful when, for example, you want to bring to front all the arrows, or want to change the color of all the text elements, etc.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set background color of unclosed line object by adding a shadow clone](Set%20background%20color%20of%20unclosed%20line%20object%20by%20adding%20a%20shadow%20clone.md)|Use this script to set the background color of unclosed (i.e. open) line objects by creating a clone of the object. The script will set the stroke color of the clone to transparent and will add a straight line to close the object. Use settings to define the default background color, the fill style, and the strokeWidth of the clone. By default the clone will be grouped with the original object, you can disable this also in settings.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set Dimensions](Set%20Dimensions.md)|Currently there is no way to specify the exact location and size of objects in Excalidraw. You can bridge this gap with the following simple script.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set Font Family](Set%20Font%20Family.md)|Sets font family of the text block (Virgil, Helvetica, Cascadia). Useful if you want to set a keyboard shortcut for selecting font family.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set Grid](Set%20Grid.md)|The default grid size in Excalidraw is 20. Currently there is no way to change the grid size via the user interface. This script offers a way to bridge this gap.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set Link Alias](Set20%Link20%Alias.md)|Iterates all of the links in the selected TextElements and prompts the user to set or modify the alias for each link found.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set stroke width of selected elements](Set%20Stroke%20Width%20of%20Selected%20Elements.md)|This script will set the stroke width of selected elements. This is helpful, for example, when you scale freedraw sketches and want to reduce or increase their line width.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Split text by lines](Split%20text%20by%20lines.md)|Split lines of text into separate text elements for easier reorganization||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Set Text Alignment](Set%20Text%20Alignment.md)|Sets text alignment of text block (cetner, right, left). Useful if you want to set a keyboard shortcut for selecting text alignment.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[TheBrain-navigation](TheBrain-navigation.md)|An Excalidraw based graph user interface for your Vault. Requires the [Dataview plugin](https://github.com/blacksmithgu/obsidian-dataview). Generates a graph view similar to that of [TheBrain](https://TheBrain.com) plex. Watch introduction to this script on [YouTube](https://youtu.be/plYobK-VufM).||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Toggle Fullscreen on Mobile](Toggle%20Fullscreen%20on%20Mobile.md)|Hides Obsidian workspace leaf padding and header (based on option in settings, default is "hide header" = false) which will take Excalidraw to full screen. ⚠ Note that if the header is not visible, it will be very difficult to invoke the command palette to end full screen. Only hide the header if you have a keyboard or you've practiced opening command palette!||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Transfer TextElements to Excalidraw markdown metadata](Transfer%20TextElements%20to%20Excalidraw%20markdown%20metadata.md)|The script will delete the selected text elements from the canvas and will copy the text from these text elements into the Excalidraw markdown file as metadata. This means, that the text will no longer be visible in the drawing, however you will be able to search for the text in Obsidian and find the drawing containing this image.||[@zsviczian](https://github.com/zsviczian)|
|
||||
|[Zoom to Fit Selected Elements](Zoom%20to%20Fit%20Selected%20Elements.md)|Similar to Excalidraw standard <kbd>SHIFT+2</kbd> feature: Zoom to fit selected elements, but with the ability to zoom to 1000%. Inspiration: [#272](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues/272)||[@zsviczian](https://github.com/zsviczian)|
|
||||
29
ea-scripts/Rename Image.md
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
|
||||

|
||||
|
||||
Select an image on the canvas and run the script. You will be prompted to provide a new filename / filepath. This cuts down the time to name images you paste from the web or drag and drop from your file system.
|
||||
|
||||
```javascript
|
||||
*/
|
||||
await ea.addElementsToView(); //to ensure all images are saved into the file
|
||||
|
||||
const img = ea.getViewSelectedElements().filter(el=>el.type === "image");
|
||||
if(img.length === 0) {
|
||||
new Notice("No image is selected");
|
||||
return;
|
||||
}
|
||||
|
||||
for(i of img) {
|
||||
const currentPath = ea.plugin.filesMaster.get(i.fileId).path;
|
||||
const file = app.vault.getAbstractFileByPath(currentPath);
|
||||
if(!file) {
|
||||
new Notice("Can't find file: " + currentPath);
|
||||
continue;
|
||||
}
|
||||
const pathNoExtension = file.path.substring(0,file.path.length-file.extension.length-1);
|
||||
const newPath = await utils.inputPrompt("Please provide the filename","file path",pathNoExtension);
|
||||
if(newPath && newPath !== pathNoExtension) {
|
||||
await app.fileManager.renameFile(file,`${newPath}.${file.extension}`);
|
||||
}
|
||||
}
|
||||
1
ea-scripts/Rename Image.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" stroke="#000" viewBox="0 0 122.88 102.06"><path stroke-linecap="round" stroke-width="4" d="M8.18,23.12h67.09v5.39H8.18c-0.77,0-1.47,0.31-1.98,0.82c-0.5,0.51-0.82,1.21-0.82,1.98v39.46c0,0.77,0.31,1.47,0.82,1.98 c0.51,0.5,1.21,0.82,1.98,0.82h67.09v5.39H8.18c-2.24,0-4.29-0.92-5.77-2.4L2.4,76.53C0.92,75.05,0,73.01,0,70.76V31.3 c0-2.24,0.92-4.29,2.4-5.77l0.01-0.01C3.89,24.04,5.94,23.12,8.18,23.12L8.18,23.12z M71.77,53.85c-1.52,0-2.75-1.23-2.75-2.75 c0-1.52,1.23-2.75,2.75-2.75h12.78V18.04c-0.39-3.8-1.56-6.62-3.34-8.6c-1.93-2.16-4.67-3.43-7.99-3.98 c-1.49-0.24-2.51-1.65-2.26-3.15c0.24-1.49,1.65-2.51,3.15-2.26c4.54,0.75,8.37,2.57,11.19,5.74c0.72,0.8,1.37,1.69,1.94,2.66 c0.72-1.25,1.58-2.35,2.56-3.32c2.94-2.92,6.88-4.51,11.59-5.1c1.51-0.18,2.88,0.89,3.06,2.4c0.18,1.51-0.89,2.88-2.4,3.06 c-3.52,0.44-6.38,1.54-8.39,3.53c-1.99,1.97-3.25,4.91-3.61,9.04v5.07h24.65c2.24,0,4.29,0.92,5.77,2.4l0.01,0.01 c1.48,1.48,2.4,3.53,2.4,5.77v39.46c0,2.24-0.92,4.29-2.4,5.77l-0.01,0.01c-1.48,1.48-3.53,2.4-5.77,2.4H90.05v5.07 c0.36,4.13,1.62,7.08,3.61,9.04c2,1.98,4.86,3.09,8.39,3.53c1.51,0.18,2.58,1.56,2.4,3.06c-0.18,1.51-1.55,2.58-3.06,2.4 c-4.7-0.59-8.65-2.18-11.59-5.1c-0.98-0.97-1.84-2.07-2.56-3.32c-0.57,0.97-1.22,1.85-1.94,2.66c-2.83,3.16-6.66,4.99-11.19,5.74 c-1.49,0.24-2.9-0.77-3.15-2.26c-0.24-1.49,0.77-2.9,2.26-3.15c3.32-0.55,6.06-1.81,7.99-3.98c1.78-1.99,2.94-4.81,3.34-8.6 l0-30.17H71.77L71.77,53.85L71.77,53.85z M90.05,28.5v19.84h12.98c1.52,0,2.75,1.23,2.75,2.75c0,1.52-1.23,2.75-2.75,2.75H90.05 v19.71h24.65c0.77,0,1.47-0.31,1.98-0.82c0.5-0.51,0.82-1.21,0.82-1.98V31.3c0-0.77-0.31-1.47-0.82-1.98 c-0.51-0.5-1.21-0.82-1.98-0.82H90.05L90.05,28.5z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |