vault backup: 2023-11-14 15:21:35

This commit is contained in:
2023-11-14 15:21:35 +01:00
parent 0a356f1071
commit 3193cc7b34
40 changed files with 3056 additions and 93 deletions

View File

@@ -3905,26 +3905,44 @@ tJRn/6DCtRq1EQpEsjSxkatmn1QVpAUyBSh0NxeQYcAjJHD7IogS+jg322oiD6j+
uo6iTGtGMoRifrY8pqhw5hHMa+8ZzHe3uZex7xOuu6hqWbMNEeRlk7nkYuocTHNG
M8xj1HrrrvycAAtIDNmOAA4AAhADaBuAFJgaABcwGyASuKG4Do3BgBCAAUyF4Bm9
M8xj1Hrro5y4p8UgAwEr6QH61U8KFVjQAJNawAhss96xnB4RnvwSMhFglfsan4Fu
qdAaoBCsaKxxEAIAGwAEQBG4B7ATYB9AAhAbFHYFlKx8rHr4EqxrIA8sY8+49d6s
WJdWkhDQGBcw7a9y3hnTP05kcfhq6bNiqUx4tHXX1Uxs7s0Nw0s80yIkYR605B7S
aM8xrGqscvgotHigHaxirGqsZqxlPrIADKxjrHcgCax6rHXX11yPrHOsayAdQ0XW
CQILOrvpqgIJBIXfJRAPmkmUY+yvPL/fh4PGGHtHsOujxh+0ZD+hqDSYYogGm0Zo
OmxsbGqse0oj9UFsagAcbGr5lyARexpoHwAdLQmgFWx9bHOAD2ZQgB5MmJBvbGRs
fAcwx6UPon8sIbgkzXuxdzDvt9hl9aD+KG8YjGP2uDhteztsYwdZLrmhoAx0gj2Z
f6xrIAzMCwACjGiAGUADjBMWGTW0Mp9sYGxqIBSAAoxozzkP1zAEfoNuGexrIBNw
rAQsvhf0KQIYshBLCCqffa3CB18tLix+tdB0Kz98zDw0e7liqbq4LLPYJ0sL3Bpl
ADACApUQAoAL7HltI+xiCwnYFdSO0B8AHsFT8glwouKN/BY2D2xvr9UQFBAEi04s
SzR3sqZqsK4U0DdQI4BhXTg/067GTiCocEu3W8S7uiY/LVQ4JRI8F6vSpKxhHGVo
HNoUUyb1kxQDXA9sa7RAwBksaZgAgA+aRGAKUAMXF+x/QA5sZQuDtISsb9AEgAwQ
va48IafulRxhiJEcfRhzHHdUflZatqsyqQiqNBRCLLYcn8DwSIyuiCGFqwzWXKwq
GOxqoA1VGO1EgAsRC6EM2r2zWdAI4BuyW5xuTFPQElgBABhhzGgTzJNwAGE0XHec
0ARWDgGrjKdUnGp0GwzenGPcCNeC4s9BFVwiVZVnLv3GMi91kE+mq60pCO2DV4dC
bJx87Hr4EGxjEBtKMwvTgAt0xsCMwBhAGYAbYRSADpxhnGfsdWwfnGAwCYAUCBlA
DsoFpzz2IRwTIJCUAzaILHd5JCx+8dS7qO2+bhfELxx7BA78nAALSAzZjgAOAAIQ
AJxoUAcgFwAHod+YBRAPmklgGwAIgB/gDQAM3GBzDExdLGbcdIAc3HvYCM8Z8Aqg
A2gbgBSYGgAXMBsgErihuA6NwYAQgAFMheAZvanQGqAe3GHccRACABsABEARuAew
FtxomBwAA6EBp91Y2AAQmAQAEJgIAA==
E2AfQAIQGxR2BZncddx6+B3cayAG3GPPuPXX3GjPP9xj3HL4KLR4oBQ8bdxj3Gvc
ZT6yAAXcbDx3IAA8c9xurGw0hjx8PGsgHUNF1jM8ZTxj3HtKI/VPPGoAFTxq+Zcg
EXsaaB8AHS0JoBi8dLxzgA9mUIAeTJiQZrxpPHY8ayAMzAsAAoxogBlAA4wTFhk1
tDKWvG48aiAUgAKMaM85D9cwBH6DbhB8ayATcAAwAgKVEAKAAnx5bSx8YgsJ2BXU
jtAfAB7BU/INrBTEA44DMB9qmukNfHUQFBAEi1hZFAncZ0cki8JaPGu0QMAQ3GmY
AIAPmkRgClADFxp8f0AHPGULg7SJ3G/QBIAMEBG8aqANVRjtRIALEQuhDNq9s1nQ
COAbslICbkxT0BJYAQAYYcxoE8yTcABhOQJ6AmX8dbx6+B48YxAbSjML04ALdMbA
jMAYQBmAG2EUgAf8b/xqfHVsFgJgMAmAFAgZQA78aFAHIBcAB6HfmA+sYHMbAAiA
H+ANAAWCaWAMTFTcc4J0gB+se9gIzxnwCqAFgmiYHAADoQGn3VjYABCYBAAQmAgA
A===
```
%%

View File

@@ -0,0 +1,848 @@
---
excalidraw-plugin: parsed
tags: [excalidraw]
---
==⚠ Switch to EXCALIDRAW VIEW in the MORE OPTIONS menu of this document. ⚠==
# Text Elements
%%
# Drawing
```compressed-json
N4KAkARALgngDgUwgLgAQQQDwMYEMA2AlgCYBOuA7hADTgQBuCpAzoQPYB2KqATL
ZMzYBXUtiRoIACyhQ4zZAHoFAc0JRJQgEYA6bGwC2CgF7N6hbEcK4OCtptbErHAL
RY8RMpWdx8Q1TdIEfARcZgRmBShcZQUARm0ATm0eAAYaOiCEfQQOKGZuAG1wMFAw
MogSbghmIXoEzAB5AHYAFXwAVQAxAAUoACV6ADNB9gBlTHSyyFhEKsHAhE8qfnKJ
tGcAVhSU5ISADhSNgBYAZhOmrdiNlcgYbmcjgDZ4072ThMO9niaE35uICgkdTcHb
bFKxf6SBCEZTSEHaMEQ4qQazKYIg/7MKCkNgAawQAGE2Pg2KQqgBiWIIKlUyblTS
4bC45Q4oQcYhEklkiTY6zMOC4QK5OmQEb4fCjWDoiSSRkaQIi6rYvEIADqQMk3CR
UyVOPxkpg0vQgg8itZsI44XyaG15TYAuwajuNu2/xZwjgAEliNbUAUALr/ea4bLe
7gcITi/6s9mW5i+iNR5HVBCLbipFIncEJU5Nf6MFjsLhoE75pisTgAOU4Yi1xw2P
CzCSu/0IzAAIpkoGm0IMCGF/pphOyAKLBbK5BOR/D/IRwYi4bvELWPX6nE6xFI8I
4pPb/IgcXHh6f7thMnuoPv4AfJuBsQiTwrIsBFKZlFI3d/PwPP19v0HbLaUwAeC3
7Ij+OpwIE8YiOEhQQeUrD6JGi4IN00E1AqaDYkICD7qEUBEvo+hqEu3T3sKaB/u+
CKAZ+IGxOBxQAL4rKU5SVBI9AABoNAAQrEmgpMQACyACCrQNBwnQAFr0DAewAIp8
YqMziOg8ypksiprKgzjPKCzyPCcTwbAkTSPE0fDJs6elHDwezaBsFwpDujyPF8Rz
NqWyaAsQwI2okTSxAcsQXE0eyxDw1zJlCMJwmgjnHEcRzBU0O5WTwjwbI8/yokaH
7JlieqEsSpIUjS1JIIOjLMjGHJldy6C8hw/KCjkUCKmKEpSupUhyrBirFSq6r+Zq
NqYsq+q9VUJqVNGwgWlaWr/PajJOlqrrJu6c7er6AZBuQobLmgiYzsm9VxlOSY6m
EF6bpmXw5bEPk6gWFbFqgsRAQw5ZFtWHC1jaCQ5Tw3zPAkrYdl2F5XjeOpDmyxBj
lkHXXedOpzguS4rmuZybmcqX7g+R6nSeyYkueJ2Xv2eG3hReRPm+1Hvp+YApN+n4
s2AzjxOZIXguFkXRWzJyJKczzfUclwgxuPCc7+z483zwWhULUUxW+YBHNojzbHsH
lg1s5nZY8CvM0rvNBQLYXOcLmtvhsyQbJFO45e8jxHHsKXm1M3NW/zat2xrbNO82
GzvBZKWuTwCSrr7ZT+yrNvqyLSuPE5Vnub8XzNuCOUJy+lvJ0HEUh0rTTJLHOaNj
wYVNE0JlHIXSfW6X9ts5Xex7MFa7gnsGzHPHb4IYnxdt4Lwdp1rSUpalYUZWDpst
+PgeT2X09vrPKVpYvWUFyP4H/FBVqwfto/VIQyH4Kh6Gn1hqA4XTOo31iREkTIiz
kQ+nVUc+Aeq3Xh3Z82957pRSJlZeUx/QsTYsmTi6BOiDAAI7cQoIJE4pBlApCgLi
ToTQjAjiEDAIwzhVLwD6ppRY5BljJl0vpF2CJ7IvXeN8EyEd/i2V5mZBEINB6S3B
BLXKvkNTcAzs5LKjxGwRw2FcKRDtIBxVhL/VAOxspWWcrubYG8FEQHyupQqt0pql
S5BVKqtIapMh2uyTk5UeTkFagKIUnUgyEHFAaI0/VsDymqkVYxo0ApfUmiVDxfU5
rLgWn4SQV0VrJjWo6WAm1DHlB2l6H08FDohgQGGMmN1yiXWWrkjGiEtLcDMqlCBu
YyyFk4NwPMyZ3r/RrOpWI7lYhPAHkTeB0Ngg417LTQcw5kbjjRsePJkAsaoWpq0v
GG5XIR3qS/EmYzimQEpviamcNn7lDvD/faistbJOAivLW8QNzSxSpZBuJlzgKK/C
PLmSsxYOWMk8U4g8OkXDZmoiRmiDgQPtict8Os9a7j1mZTRcs7ns11r8poWiAUay
BVMcRWcpEnBkXIzexyHkHLfKiyR0iMVYuhRzQ+0Dj4YTPhkoqV8ULdjvjBB+T98J
vwMB/MiDMmYoszoSjFxLQZ3LJWUGBZRWLFHYpABBEBiCLGQRwLYmg4CVkBqMQ0XR
sCaFiAAaXIbMCQVDtL/HoakJ23tGxx3OAPMKLYbL3BejsW2kVG5uSikcf4flAkly
AeXHUSiEpfUcjuEyVkPiZg+PIvKHA0QGOCSqWxTUICUnMb4hGtVrENVMfYvkTiOp
dTcT1Q0fVZTeMGnG/EATxpBL8SEmaEhwlmkWtEwp1adTxI2i6I5EBUl7RpTqYMx0
VmRNjC2s6mJSloAuAbVIWYfqNNqTaRZ5R50cABkDL6JxIqyy+EuqVPSEB9JptebZ
kBEajhGY+Ips55xTNxjmfGKRjIJGsksw8Q6KZng2dwLZx8Gb7Itoc75yLWbj3ObI
o4rT87yOAzzH5Vke5mQsoKtmzhnkGw3GZMKccEMwecHBhyFwTbIctiC/W4KQbwqh
bhs57TnKyNlr6t8+leXuSJbIwV1HtBgYuLEBj2KyjOErmDX4vH1xmVuZx7j9GI6M
amM4UBntvovQcki3FAGmPettjolDSRUhhTrrx9pj7oqSdozxvj0LeZiwONFZ1PdN
wJAk2pv2lt8MIaI5G4uGdTitOCu06KOjcNucI0hzzWteaV3Ss8AeWY2G5g2EF2F8
GQum348rINmZUqx22O8YzCXnNj0A8XSuu49jPq+EvDjBWi5FfC1cbQ31gpZTed7J
zFK8XARQy9Br0sTjbnhZR1T7X1OdeLmLWjfWKmDZM+SkVlL75wSohfJC9K0JUuZa
QXCrLCLstIl/Llf9/yfisz1iO/WIGZiG2AUVYBxVlElRUam1RNAAAlcAyWQaEMKq
pRgiQAJrOFVE0bVno+g8D1ZQhYRq6H3Drk7eFRnZGWWcnHXRXCIOOU+BZYKq5gru
pEWNdMutstlYxUPBDkJoTKK1NZrcesngXFjrHVcUaY0YhrfGxqZjKqKgZFY+qCaq
gtTas4/N7i63oBLT4oa/jRETQ59NIts1iTzQuk2mJ8u20Og7V9LaOoe3pKW5kwdV
61dIw16gMdRUJ2oAjYRt21SPpahfcuv6VZmncCzD8X4Hxd0VH3Yen9yYz3DNRpey
35NMY3sPTM+9cyfgpWJm+03L9P2wwGfTPZ3LCtHaVsKubHWyg0elu0yDJKUOkd3F
O5Kz6QoXBg5p1OlmhPVxMquRsXxAXVe5o3qelndOCxOJ7GWMn5bd6Vr37Txd4hvC
0bHBeBwngJAbxPLTwC6vjd6+8VHXxLtj+Gy505q+m9ddp1lVyyOmdx2X+Po/YHS9
63L2N7QNn6eX+fdfmDRyBNJAHmGnuZWeWiW6iBGiGqWzeVcvwbez6m6KmM2B+Oec
mwWYBxG4WLeUBS+HecB+W0CR8t462i2foy2dKN8DKBB3ALKFMBE78e2xA38lEfo/
8yBHm/GgmkBjmmBsBXeIqsCEqyYakcwUONCioK63ATwjuTSgM6kqQZWvG7kHC3Sn
YvSF4lBOo0qFAIk3EqomAmAfEuICQf2Vggw2qDQnoMAGwRgPAikYuhaniUuZaCua
ocuraiExioSyupokSS08YsSWu60iSaAqQrOBUxq9wtyiQOUGiOOZkKQkMdq6wIUf
MkcemEcBwBs5aJidi6AyaPOlidUQygu2aji7UwoHqzhm6DWcOqQvwesjmXysUVOA
aOUTk24lqVqEa2KKY90UczwqRXaBu58xu2S1MVuOoBSPhKe9IQyKME4jMRuyYkyM
eq4cesRPGwir6pMEe4yEA6y6ex6v6Weh2h+uehypm0s5mo+0Kxe4GZeVWCBNWTGP
AxOHwpOHyHk9Rd+tGD+UG8BBeI2AmBK7e9msRtyQGt+Gmm+qRzkzCFOlsTxUiHwL
sbwEUHROBfxxxcmYUCI3c+wz6feKGTstm7SW6Zw4m9e4JmJGWGKmWWG7xlmgJ6Km
Kdx6JiBAmjYusRkdcIJHxGmOwSO+8BszYbkvx12jy4W24QUEMUigBYWEJp2ZOYMT
w3JaJophePM3wushwiptRoJxW2JZWLs4CjY8WuGWYyQNyL0ccXs8WKGYMXGU2imj
+zJqp/xPMfWL+rymYfWe+lmDkiQvGFk5WwUypppOs9czY6Ui+dJKGGK2gXk24G4n
sQBFJAm7p6Gwa3pUKFeOwLkxwjmrSwpKpo8DxcmaZnpZwM6smAm9kCI2UIJa4Rm0
GKZbp8Qxw3c2BFeIKOYVwDkmZV2LpGJqZOwxpG4Hs1pup4WTwtEgpLkLBRZYpjxj
kzY5kOcF+sJk5jkxkDc7sqU4BuGGp4K2pypFeSQIMjY4IW4EcqJ+5lch524OpPJc
msiyQ7k3skK/ZxZ/sWUuwECm4KUte65TGz5kib50285apzg352WwZ/5dcgFT5TxL
sL0Zk6G2B+5Gc0Ff58ZdelmwFr55xPpN5mpDY95x5lseFHkBFVGzZqGw5FpY5rWj
51Zp5DYs6l5uWTZ9x/sG4TkXsneVZPMXkER55m40UHFIpn5lssZ8ZPmSZspcmXsu
s5wFwryoWElC5pZGcBw8Kj6bwZJlmqUXGtcMJ5JXFUljkUUPZsRccZFk5lcfWk2c
FplLJJZqZWlF2ulGKdRBlm5ylO5al4FrpqGTsMliZhZJ5wlbFYl15NFZZJkXplZa
WmwiFkUXlqF3BLl3FdFPmDFNp5F1mIMHwFym4JK+5S5AZq5nyuFBVMRxVPxgVg56
p5VK5+wa5TFPMg8yQWFAFzlA5rJ6pt5WppF3lBJhJ3VTlDV/VkFGFvu41OFo1XVr
k2FOGNFUFs1S1PV1VL+hV8yEG9V+5OsJschDkqJBJKVyF+wxkaFq1YsbSUiDmE5Q
F8QIFVFH5GlbJTxIam4q4pJI1JGvl25qle5q18QmY0Uz61yeVdlRljlOF+5oNfWZ
k3wLqj1Cl9lxlE1YECBOx1Bu2n8dBB2Wxqyl818t85B/S+x+BC2/6wEDW5kb50sZ
WjFQqXGxKyF0VeW9EXGryXksR7kPw0Zz4Owm6q4/cbx8FMKbkKUbwnsAW6+tNEGr
F6UWUJ+QtcZhmEs2O+JatOVWw8K/yU+/4cZDl3w3whwiK/GOwuYwUQ+55VVXNpwE
Z3s/N2GTFVtHs/NXsbVLNKUWY3sOOAtEtVt0smYEUEGgdbtcZ0sDYzwdtgtRtlyW
wWUA85OkdiddOKd9tOtS+HwcclkrtPtpkGd4tad1pg8kUhwWdCdXsOYO4EZBdDtx
kSNDYH+8dCt2GDmDqf+qNMKlw+t+wUNtNWwz0rFg9NEw9vRI5kdw9UUq4lxXNetC
KhtQ9ECOUelf1RtSdHkJdLNSdAZ+88lvdW4+94BC92isNQdTk4IYMF2WZatfdu4A
9PdfJ5924E1Dtvw0UjYvGv1z9cZvw4CoKLs+lZ9ECF9adg88+kZ3tXNFZlkBmQpn
NQt9ETEYqcCOoAhBqQhlAIhbun0pwEh7uUhWojmTNPc7wUMShB6Khm2J6j2Qu3QC
AAAagAPr+RYDEAbAAAyfQIkAA4mwMoMwBwPgIMDYe4TKANAqBkZWr4a4bWkrvWir
hEmbt4b6D9O2gEbwF2vouzjqPQspckDbdsM2Lxplpwvat7E5O8Sic2MsWDBkYUdk
ZVBYsHumgLlzkUSLnmmUYTsDNoIAmvrJlII0SokPi/o+ibBuOvajV0dMp3h5P5nu
NtKyGkoMcmAOsMe+mMUMhbqMVMUjDMaMvMVHtjPdMseuI/d/Unpsfk2smnpshnpB
H+tnq5ezGCWZZ8ecdJnfacc2fCSTo5jvR05lU8uLEPpmOxofezDBoSUhRFMGRvRp
lxrRpcg3Cjb1ZJVrICUGQ9e1VbGBms5DW1qM9syxrs7ZY8c8Y/WTlVTBl3D3KkGB
TGeM3rAKpxac2+APmFBVgfUlXM67CSV5Sc31W098xFGDH8/SecwRns5NW05uE5K0
sziLarPsw81ZLfW9WqYi/yZagbGi5Zri8i/i5ZHDc2cSwicZAS/NcXDrNLLib8Fu
Dcps+9WAJSyizSxLcrCVjiYaTuFPfCz3jPn7ZuKnUS1SVsCZLSStZ02+N9C/qK5X
W3XJnXAiIjVItFMA95Q3iK7uGK1XY8bdZyXCw3nySS9S2S9y9NT+TBctayzi+a1S
6i7S+Kc1YGbCyGRS065y1a/s2acab2TvFCzBuC786fVJdlUG1lsDXK1MBi08z6TG
VG28MG7G58zyhIkCYsz3QNcRUeTq82QCz8zm/sxKUdeonjszTBgMy8UM+K7aQjdF
Jq+XfpSvlJrxvPcXEkIE03u22Zj0wJZBZ9fPJE7/Q666bWzc8M3CYdRZK0s5FWya
c2WLPem81M0lQGyZNG1nM6Vs47M7HZqW5ZnFecA5FuBs0K+nDC8CUs6WSFc+rJYW
fcy/o81i5uw+wmQWcmXG2UAm++ye+5bjsZCFMCxO41WG5CxG+FuEwcMB9E2B1e6c
j66S4SzGZ+0+z+xm0XvSyhT7sy2PamU8ehmezZpew3vDulBBuFVJa2Xxddb++y7y
0zXicvaq+69m6axSz2ynNreKTNb+RtZjdxwE7x2x2yQJ3a5tVjSyTjWysRLQfQSo
nUyTatoyphOpEHpBAQTTTRFcO8j8CVagbTa0Q6q0QR3/WcMy7+SdUg0bdu8+nrBz
YfcLTEfWNlPZA3WrUPu2dmDHF5/ZxZJ7AnptbAwcB8rxqF9550ucOCDapfSLRBhi
sra67TZuhwX1s8Gh95yDKLfXSq5LZmPnC9H6z7YcLXZ5O/TrQTEPP5nxwrVcFEUv
fLTROHZZN3FZxbT7XpqkBanLVWVbXDgPLuFmF1w7acLuPPPnQV8HelD8NuFGZfU8
HXODJnTN3GVIr0XnRHT7ZLLIlFFmIa610ZO8DuJ5+t8t1FBZGt0tyBzHF7Ud5LU3
XiVfhd891/a3bd8PY3I3DAzrUmWkQa299LHlzK2ncPqDzt43dlJC75gFwre9y3cz
l9+58cMj+D28+8LcxdznXzdN5fS9J5MtzKZbag7dug+UJgxpNg7Qm9Hg2InOng2u
i0g3GeR5G8JQzDNTKoRxE9icEYCJIQI8PQDJFww0O0LiHxJoJWHAN0O2J6N7H0OI
xLl4tLjI84T9MNIrp4g2l4c2hMS4ZAJo7ZEEcmLo2gF2gY6uFxt7CCd3I+hHPjjq
FwvXIkHHN9O5JuqB+sfI5zlms4ymrzu4wUZ481A4t46UQToEp1VybBal4oqE57hh
2FXZyUt0QZhcg5G6Kk72iU+UJkzkkTcOsQHk5HgU+emHnMUQdemU9MhU1Z+ZEjjU
9k+ULsY05Tc04cYwa6d/jM82b3wc6swzsc+B/1QP1O68eK2cTcU6dM4PxcsP+RzR
dcd8U/uKdc5P3c6tdc72Ylb6Rv/W1v4x6hq85M2v1cwidO1P7Faf+85u7fxu0h0B
Ye41sjuJ26Q/6VTRYCQhyA3CQf9j1lbYceY4LBBo2SSoT9D+dJajD635SP8usKzB
flciX7H8FWs+Cug21AxD9kBLLJ/piT1YYDHuffVAQQKB7csp2SJdolh1BZJxYBTJ
aZsWzChv8MqNAy2KAO+iINpm7AjWtQP3ZyYf+oHP/qclIHKsgBrA9fpf135JsJ8l
HFKOALwFF5EBdGTtr03lZUkssYacSgoLACrsJYZ/YzlMF4yid242LV0v+2eZKw1W
YNGTI3H4rqVHWSLZ1ly3ap2kQ0ECR0vtQpa4dGWHwQVmzFcEOkIMs/ewa6RChxlJ
mNJKHpYJHYDYPBX/RjlYMRobhbBHZSwU2xsFcFTBjVdkndS5J3si8PHEwSEOyGSc
5q3LMIcGg0E5YYqCQwaiRSVL5CmO+pcrFBz3Zss/Sy5WwYGS7anJvBgpTdLuTaFq
kt2OVK0szTZjdYJs52MCjBh4ptk7BVxH1tlEFLyDZhdHdsi1z/avtMWMwldsR2Mj
bsHI8Aywdc0oEoleBbLU9vZCOHn9MSSgo5igOAFXCwY1qAwamU/5DDXSzwm4W8I6
ov8vYP9RDmsN4obCh2xbAEY5iBErtsqo5MYYRw/5rt9BHzcQW+A6EBlN03Q1QXcM
OaL9cBNbOoQW1zYUCOu5w5EXwLKBrVBOcfblroImZ39tB5bedhimc5pZaR67eIcA
MZHPBmRV5VPlMGJHIkSeDI0oUJ3j4CZriDwvEf0wJHDVc2mwf4UCzbb9N3WGIuel
iIEzmDCK0I80qMM9jjDp8irfVqINH5tM5h9HTYcrEhIKlZRJo7mN8NeFz9JhvWSB
jaO0H2jjhdWEQdf0Y4mQGsrPBfH9zqxLCXYq4VYSu2T7fs5+mo6ij6IspVFrKD5X
CgqMBFKjGOO4AJsPS8gp9pm+eFEVMBrIO83U+3bLlrAFFUCyRbLU4FxgFousaRHw
isWqSrHnBUOYonQfWIkp4EX4uNBTvjSU4t8BAJBMmgtm/RNMdkOnVpo6iCHyI5yX
NEKIrTeDRQVBA3KuDlAhq80/BatRsLYwigXtcBXNFWjpSXGW0jGTLSBG8OHIrlu4
shYISzTmSdtn0PwlzqzRmSDwcoclY8cyPhSQ94eNEHzvjFzpg9bxMXBHPF0jrvBU
qGNMUVbS3CPRoSVXBOpXRyho8fxktK7jZVNRjcdaQ3LYLPkwkJ1ms7XPhHhIVqxx
u4IY+yPV1a7KUSucdJbjuCuBJ1PupdC5Ll2NGF1P6Dvc7kt0iJIT8ut3LKFcG24o
Srad3eyA92B5aJCBEkwHmxMbog8AJUQhOnWWcjnBDub3D5EhK4kY8SKdcfHhjy9J
QDbuCOVyK1Ue4iSfgPcR9LJP+5lYIo3cQQfkJEm/APkvtRDg7Ssgexhu2rP+l7Hh
TSwHIaRIQQrUsn+T7e3dNOgbF0oaJvJEUvyQ2DClBTWuBsQeDpQ8huSdaPwKyN9U
hGJTJaNmEEsPXCk+18pQzT4LlKtolTqSMU4qTBNKnVT3JMBb4AlMclxl5ufWOybu
HKlxlKphUrqQCJCiYY/afUyKANO8idSWp/Uv/F3T6m2CjIceLqRiieCgppWik0bP
+DJ53YSg/BChIIS0jCFCG+DXRCumZ4kMpE8ZRzJz2ULc9aGrYJ7JIHbDMANg7Qbo
CwwEbEAUgFAZwHwz4h8Q7AXDPYJoGV6KNJcUjVNL7wrQa8MiEjY0Mo0bRRILcGjb
XFo1N46hzeqiUIusFUlGVAyjcOOE1Kd7lAXebwZ2PZD1EYZPOfuLXpkUTQ5EqoQf
fnCH397QBw+uaSPjqE9RVoAhcUpmmPRCbxQVEU5MjI31WLQc0+1MJ6A6jkLZ8PQu
favhkyOhZNJikAcYujEGSFML0VfA6AsWjzlNZkqxJvhTGWRKydiDTEcR3x2QtMji
Y/EZnmLZI78Fx0grpslBwHLtj+bIpEWljLGkjihU1RgVrXf7uz6RuGAQTE3argjF
RhbEgYaKknlDChPqH2W0xOxTCpsjs1EXOyMiLtiSrs4AbzC9FECzRoIhObQMcFsZ
bhZQd0RyNtkgDkggsMATRy1jSVH22YouWwJrn6YOB8g0WEBxzAuxtELA8kTzBDnp
SG5cY9pEVQiiP9cMfs5gQJXeDG12Rnwxqif0RH0i2Y6Y3MlmMjEtyJB2WKQeqO1h
PEHe9Zbss+236SCHZ+8psTWOcHaD5+M/eqmvLFjNjLWhLafqv1+EpRdY3ZeKX2W3
knFgUXZRWnvKyHWylYgssFMLLnJvyghD8sBRnCFmzkAq+5e2b/OhTgKZyxsJBTRW
nmq0tYn81cEAovkgLE50YgSlfJbFiCB5vMOgavLAWHy6yjmBsqfNQFWjphqc/MTm
UzH5l3xt89pHGRQqbob5a8zhZXW4XMKc5Tos7CnMvkiK8yzc3hTQo9HAp6FxsbfN
RwuEQVSFaWAsQwrUVhjj+OCyiWUB0WqKmFGioKivxgVlztYT86+aVy/yPzqxFC20
RPiUEXFL5ti5xQyIAEzs8Fnil+eSx9Hti0F/i2sS4q1jFsFmcLRxc/LCXaCdmnrR
oevK4XyKX23cHYewvLmjzeaqUB0X/PjbbDE2+8iuYvP6paLoUIwndiG2bLlLRYKb
JuLuzJGdjW+3YjlPth/j9jVOpBNbMOIprwwxx1NCcQ1kQwpQsoWUCzLAw6SpRHeg
E2Bm+JeiCTZl3nXHHHEZxMTbxjcOuFljh7rdN0JkN4N3FK5hcvIvktSQlwNhJc4J
UEm3s3Ve7nLRaA0zAfZ3IYfASuJYtLh13cj2NrluWGSU8rS5nk6cQ+d5b+P2DKZw
Gt4kTKViEU61LyydXxQrUqStEVaRi6Cbb2JKsdNhVtZTK1njmF05uj7RbqXTfJIV
rJ1dElTHNLr3otxZy4ldHUpXsTTgNKwMQrS8jPpOJ6PQussTx6rTWuRdeFf8r5Xc
qhJOPYVS7Rx6QNY6tK/FalEJUsq+VBKhbvKslqyr38nK8bgLTWXqrs6dZAVWZKjp
iq9JjKhyr931Vt4vKH3bVf/PuQ8E0GfBDBjtKwZ7ScGB07gM+gOknS0AZkPEpuEf
L+4qGh6HnlKiewUBcA7YJoCJBgAsMXshASsBsFVBCACQjwPhoMBOCDBVQ7YIGXYV
Bky4SosjTXODIQDQzqgsMvXgjNWhIyTeOjaNCERhyYz4UX8yKYvi0SWoLGCRBuG7
0lie9IoMtRxqHyTQuMwZp6YPkjCcbMyc0JRFxFHyrTNEGwXkA4d7N0T+oVEDageg
uIsjAqQoyTW6DbgdSYtWEBMyAAMT7T58FZhfFTirM6Uh4im4eLWaU1vQ2h6+TYNY
s32Nlt8zZ/SyALslvVqle+uYgeZYtuKOj7huI7OVXMA03jbSPi70cAPH7Qaj+Eip
Qe/Ln6BzJ5Z8wZoAP9bBLTSwSl5ivLQ3H8Elt7OUahsrlULuBnA/5smJymRyJFrC
6RWCOo3jteFfQ/DhuPCzhyUxtGqudwgCZUdO55FJjVCNQHMcWhlWOfpxpo0gsqFF
QiIStJQl/CiSEI5jdRjjlBMqNSmiOdJrZaQV0hyQzIRpqQrKbhNOcrmdlOY0EkhN
qY0zenPZq8iUN2G1ajKIaFyjIBmG2+WiPMiqiJlWApAesylFuyYRlpPUfCP/U6aC
5Cw/wacJJFCjTS6wyLWM3w1kbwtYZf0dAyIEMlS5pSxOY3K/Y8K2YFG/RTnNg6RN
GafcgSmgKVYwaeNFRSyg2ATGXNDB9GgbFqLdmjz6tNRRrTh34WXVSGgwhsUFVq3x
jOtjQ+rA3DkHiKat7W6ojZVG3qDQ01Q8xUvKG1WURtubIwb2z7ymlptDWxoVzPcF
WLst3FHbWtpcHGtkWXHNrZUVW2zaiRtmnkVoO23XaOtt2lwXUNEyxFAJppbuWVuI
n8j3tOYT7Tt2+0RMCFvcv7eXPqVpsjtUlCMflqeRQ6Y2MOmDqlsM7paCuOg9YZlL
1gpdKF4W/YYTBeFKKpgvo+uIcrxmxbYqBOw4XkoqUYc4utE8JUxgi2pCG5P28HYF
lWoqie4ao2eUkD0EX44lZVf0l5p50+a8FsizeTwvQq2syh7VExcfPUUDal5XIuzV
oJiUC19WyE6ATdQ5IXaut2seBRAsQXpseNZmsdsPOBRG6MFIs5HY8T01hQDNaC9G
n1g97fK8dEFDbWJwtGGUTabuz+oEokWStIhCmxSluRUohpTdMm2QUru0UsURK7FG
oRItY1Mt2NwKePVFXs35LxRzWgDqHGeqvkrgjyhDTxsq1GjBVZQCipFFkQ3cmdcm
QrfXMdjnU0qV1fuTptqVKwI421WqscCM7K6pqRG49qHBqpFVe9nggxS/yYG4LHYI
+3an3uz0Ii9BtCiJbPrqrJaIKbmhFVMC70GlR9e1dfRYqQ2HaGBY1VyHXji6vz++
ocU/RjhAmX7GOEG2BREpv3n7GsgequZvor1gAY+f5V/aBLdG4bO9L+yyW/o91mDC
leeoA4tVv0X739AGlDgEu5Y76dqa+u3VMAb18jjFGei8iyO0Ed68F2B0SlnviU3s
h9YCgGhHv60L7SNH8l3QZmzjSci2k+/2T7roP+7GDjHQfdErAVsHWk7uuvVsPSVF
KyFvBhg8Jwf0IG4la8ig/5Sj1stJFk2FrZfJkNA00DReGPQJoIORUcDxBhvKJoci
tCGBBexJjXp3oN51B9kJ3fnpfImHi9Ouh/RYawIWiGwTkVKihVb3EKe8jhqw53tX
1j6D9jVMbfxsb3b7gDd+uA/IbzkY7Z1rRBdZTsY74HHYSQfTluDBg7KwDjVGg9M2
eABN0BZAgQ+yyP1Aa0snsdWnXD8nz7tBvfbKAExervkF91R+HHUd2G4Fsar8HbD2
M5QdLjZK2bpep0Gh9K6GJ8JlIQRZiOo5pXQ3nceICwcF6jLNJnFl0ym07YGscZWp
hyfG20ssMy3lTCitSP4kVPyuospXWUO1w0djAPUtx7LnBSZ0+1ruDQFp1dxO7tKz
nstG5PGo6+cRiVatZUcSPO3x1rqkXGX+cLuKU/5HcogbXJyZ/xyWphhapErdu30f
bozt24WqkewkjbhpL+PomlpBk9zdDx0npHwe6UfYKz2hMiT/a2x7EwQrJbGRxpPk
6kzjiGkTS/JuYLVkVMbrOTkoYmZk2YwHg/VLdrXXuJ1P5MzSlqZ7VtsybFPRT2TG
UkEhmDSminfa0pxU6yYlM+ShTfJqTWnRZPin6pspxzPKdDk+0NTq4izRlItTb0yp
PJl4qaYFOS0TTIp5kxaa8kymE6Hk7DL1KdOeTPT6p50z6e1N+mrTvp700GYDMhm9
TbpgKbIl/5emPToZ401GYWVGn3JiZmM76bIlJm7TVteDNajTPamzgLqaaU6YzN5m
EzJZhyeqYLPSsmTlZg2DMm5PqnTgbKi4BGYVoXBMufRV022aM1abtTZ2bKJujpPa
naTcyeMw7R6ljmdaXwZFtMtbNJSIMcibYHObyntmMUjpnyWVi9jZwGzadXOuxkHN
dnWue5q4AeeGlKlBFFZiKdlE0SeVhp151KcmanP3ntgCpiaQhlJLrnYpEcNc1qeK
k2YBpk5hOhmfBClmP62WJaTWd3OhplyO5n2p/VYpcafJJJpMqeYmnwXv6v5j+ok0
+2QWWaIUEGJKMI7f588N2TaQ9ip4QBDU+0hpPTzQAXSaLNSVdB7mBjeQLlL0S6dQ
2ulbZ4ET2ESJ0DqBGBsAAAKXbBcMEAD07VNxE0CEA/sfQR4A0C4ZZri0Oa9Xn40N
66gVQxa3Xqo317qMK1/hKtcEVjR1q9IsXRtXrGbUHBW18RPSKBxJnNY3g+nVY32q
Zm0zXGaaBmaOv7XC5WZU69mc4Q7UpSvIxY+PnzOpwlhUd5O6UqdWtzlM+TD6bdSk
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
AA==
```
%%

View File

@@ -0,0 +1,25 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-bullet-point.jpg)
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);

View 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

View File

@@ -0,0 +1,65 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-add-link-and-open.jpg)
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);

View 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

View File

@@ -0,0 +1,141 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-add-process-step.jpg)
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");
const previousRectElements = elements.filter((el)=> ['ellipse', 'rectangle', 'diamond'].includes(el.type));
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",
textVerticalAlign: "middle",
box: previousRectElements.length > 0 ? previousRectElements[0].type : false,
...fixWidth
? {width: width, boxPadding:0}
: {boxPadding: textPadding}
}
);
ea.connectObjects(
fromElement.id,
null,
id,
null,
{
endArrowHead: arrowEnd,
startArrowHead: arrowStart,
numberOfPoints: linePoints
}
);
if (previousRectElements.length>0) {
const rect = ea.getElement(id);
rect.strokeColor = fromElement.strokeColor;
rect.strokeWidth = fromElement.strokeWidth;
rect.strokeStyle = fromElement.strokeStyle;
rect.roughness = fromElement.roughness;
rect.roundness = fromElement.roundness;
rect.strokeSharpness = fromElement.strokeSharpness;
rect.backgroundColor = fromElement.backgroundColor;
rect.fillStyle = fromElement.fillStyle;
rect.width = fromElement.width;
rect.height = fromElement.height;
}
await ea.addElementsToView(false,false);
} else {
id = ea.addText(
0,
0,
text,
{
wrapAt: wrapLineLen,
textAlign: "center",
textVerticalAlign: "middle",
box: "rectangle",
boxPadding: textPadding,
...fixWidth?{width: width}:null
}
);
await ea.addElementsToView(true,false);
}
ea.selectElementsInView([ea.getElement(id)]);

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,67 @@
/*
Automatically switches between the select and draw tools, based on whether a pen is being used.
1. Choose the select tool
2. Hover/use the pen to draw, move it away to return to select mode
*This is based on pen hover status, so will only work if your pen supports hover!*
If you click draw with the mouse or press select with the pen, switching will be disabled until the opposite input method is used.
**Note:** This script will stay active until the *Obsidian* window is closed.
Compatible with my *Hardware Eraser Support* script
```javascript
*/
(function() {
'use strict';
let promise
let timeout
let disable
function handlePointer(e) {
ea.setView("active");
var activeTool = ea.getExcalidrawAPI().getAppState().activeTool;
function setActiveTool(t) {
ea.getExcalidrawAPI().setActiveTool(t)
}
if (e.pointerType === 'pen') {
if (disable) return
if (!promise && activeTool.type==='selection') {
setActiveTool({type:"freedraw"})
}
if (timeout) clearTimeout(timeout)
function setTimeoutX(a,b) {
timeout = setTimeout(a,b)
return timeout
}
function revert() {
activeTool = ea.getExcalidrawAPI().getAppState().activeTool;
disable = false
if (activeTool.type==='freedraw') {
setActiveTool({type:"selection"})
} else if (activeTool.type==='selection') {
disable = true
}
promise = false
}
promise = new Promise(resolve => setTimeoutX(resolve, 500))
promise.then(() => revert())
}
}
function handleClick(e) {
ea.setView("active");
if (e.pointerType !== 'pen') {
disable = false
}
}
window.addEventListener('pointermove', handlePointer, { capture: true })
window.addEventListener('pointerdown', handleClick, { capture: true })
})();

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 448 512" style="enable-background:new 0 0 448 512;" xml:space="preserve">
<style type="text/css">
.st0{stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
</style>
<g>
<g>
<path class="st0" d="M355.8,234.1"/>
</g>
<g>
<path d="M32.3,139.7l28.8,24.2l63.5-71.7L95.7,67c-7.2-6.3-18.2-5.6-24.5,1.6l-40.6,46.6C24.3,122.4,25,133.3,32.3,139.7z"/>
<path d="M61.2,165.3l-29.6-24.9c-3.7-3.3-5.9-7.8-6.3-12.7c-0.3-4.9,1.3-9.6,4.5-13.2L70.5,68c6.7-7.6,18.3-8.4,25.9-1.7L126,92.1
L61.2,165.3z M32.9,138.9l28,23.6l62.2-70.2l-28-24.6c-6.8-5.9-17.1-5.2-23.1,1.5l-40.6,46.6c-2.9,3.3-4.3,7.5-4,11.8
C27.6,132,29.6,136,32.9,138.9z"/>
</g>
<g>
<polygon points="218.7,240.1 212.3,168.6 197.2,155.4 133.7,228.1 148.9,241.3 "/>
<path d="M148.5,242.3l-16.2-14.1l64.8-74.2l16.2,14.1l6.5,73L148.5,242.3z M135.1,228l14.1,12.3l68.4-1.2l-6.2-70.1l-14.1-12.3
L135.1,228z"/>
</g>
<g>
<polygon points="192.6,151.6 129.1,224.3 66.2,168.4 129.6,96.7 "/>
<path d="M129.2,225.7l-64.5-57.2l64.8-73.2l64.5,56.2L129.2,225.7z M67.6,168.3l61.5,54.6l62.2-71.2l-61.5-53.6L67.6,168.3z"/>
</g>
<g>
<path d="M109.7,381.6c-23.7-22.2-40-49.3-48.9-78.2c8.2-0.9,22.4-3.6,30.1-12.3c-12.6-12.5-25.3-25-37.9-37.5c0-0.1,0-0.3,0-0.4
l-23.6-22c-6,60.7,15.5,123.7,63.7,168.8s112.5,62.4,172.7,52.4l-24.1-22.6C194.8,432.3,146.9,416.4,109.7,381.6z"/>
<path d="M232.6,456.1c-19.6,0-39.2-2.8-57.9-8.3c-30.9-9.1-58.6-24.9-82.3-47.1C68.7,378.6,51.1,352,40,321.8
c-10.6-28.8-14.6-60.2-11.6-90.7l0.2-2L54,252.8v0.4c6.2,6.1,12.4,12.3,18.6,18.4c6.3,6.3,12.7,12.5,19,18.8l0.7,0.7l-0.6,0.7
c-7.2,8.1-19.8,11.3-29.5,12.5c9.2,29.2,25.9,55.6,48.3,76.6l0,0c35.8,33.5,82.4,50.5,131.3,47.9l0.4,0l25.9,24.3l-2,0.3
C255,455.2,243.8,456.1,232.6,456.1z M30.2,233.3c-5.6,62.5,17.5,122.9,63.6,166c46,43.1,107.8,62.1,169.8,52.5l-22.3-20.9
c-49.2,2.5-96.2-14.7-132.3-48.5l0,0c-22.9-21.5-39.9-48.7-49.2-78.6l-0.4-1.2l1.2-0.1c9.3-1,21.6-3.8,28.8-11.3
c-6.1-6-12.2-12.1-18.3-18.1c-6.3-6.2-12.6-12.5-18.9-18.7L52,254v-0.4L30.2,233.3z"/>
</g>
<g>
<path d="M368.8,105.4c-56-52.4-133.5-67.2-201.3-45.5l21,19.6c56.1-13.2,117.7,1.1,163.1,43.7c33,30.9,51.7,71.2,55.9,112.7
c-0.2-0.4-0.3-0.6-0.3-0.6s-25.1-0.1-36.5,12.7c11.8,11.6,23.5,23.3,35.3,34.9v0.1l2.4,2.3c0.4,0.4,0.9,0.9,1.3,1.3l0,0l17.7,16.6
C444.7,234.1,424.8,157.7,368.8,105.4z"/>
<path d="M428,305.1L409,287.3l-1.3-1.3l-2.7-2.6v-0.1c-5.8-5.7-11.5-11.4-17.3-17.1c-5.9-5.8-11.8-11.7-17.7-17.5l-0.7-0.7
l0.6-0.7c10.5-11.8,31.7-12.9,36.4-13c-4.7-42.1-24.3-81.3-55.4-110.4c-43.5-40.9-104.2-57.1-162.2-43.5l-0.5,0.1l-22.6-21.1
l1.6-0.5c70.5-22.6,148-5,202.3,45.7c54.3,50.7,76.9,126.9,58.9,198.8L428,305.1z M407,282.6l3.4,3.3l16.4,15.4
c17.1-70.7-5.3-145.3-58.7-195.2l0,0c-53.3-49.9-129.3-67.4-198.7-45.8l19.4,18.1c58.5-13.6,119.6,2.9,163.5,44.1
c31.9,29.8,51.8,70.1,56.2,113.3l0.5,5.4l-2.5-4.9c-3.8,0.1-24.3,1.1-34.5,11.7c5.7,5.6,11.3,11.2,17,16.8
c5.9,5.8,11.7,11.6,17.6,17.4L407,282.6L407,282.6z"/>
</g>
<polygon points="425.2,382.2 302.7,283.9 299.4,437.6 340.9,383.8 382.3,456.5 398,447.5 359.4,379.8 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,369 @@
/*
With This Script it is possible to make boolean Operations on Shapes.
The style of the resulting shape will be the style of the highest ranking Element that was used.
The ranking of the elemtns is based on their background. The "denser" the background, the higher the ranking (the order of backgroundstyles is shown below). If they have the same background the opacity will decide. If thats also the same its decided by the order they were created.
The ranking is also important for the diffrence operation, so a tranparent object for example will cut a hole into a solid object.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-showcase.png)
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-boolean-operations-element-ranking.png)
See documentation for more details:
https://zsviczian.github.io/obsidian-excalidraw-plugin/ExcalidrawScriptsEngine.html
```javascript
*/
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.9.20")) {
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
return;
}
const ShadowGroupMarker = "ShadowCloneOf-";
const elements = ea.getViewSelectedElements().filter(
el=>["ellipse", "rectangle", "diamond"].includes(el.type) ||
el.groupIds.some(id => id.startsWith(ShadowGroupMarker)) ||
(["line", "arrow"].includes(el.type) && el.roundness === null)
);
if(elements.length === 0) {
new Notice ("Select ellipses, rectangles or diamonds");
return;
}
const PolyBool = ea.getPolyBool();
const polyboolAction = await utils.suggester(["union (a + b)", "intersect (a && b)", "diffrence (a - b)", "reversed diffrence (b - a)", "xor"], [
PolyBool.union, PolyBool.intersect, PolyBool.difference, PolyBool.differenceRev, PolyBool.xor
], "What would you like todo with the object");
const shadowClones = elements.filter(element => element.groupIds.some(id => id.startsWith(ShadowGroupMarker)));
shadowClones.forEach(shadowClone => {
let parentId = shadowClone.groupIds
.filter(id => id.startsWith(ShadowGroupMarker))[0]
.slice(ShadowGroupMarker.length);
const shadowCloneIndex = elements.findIndex(element => element.id == parentId);
if (shadowCloneIndex == -1) return;
elements[shadowCloneIndex].backgroundColor = shadowClone.backgroundColor;
elements[shadowCloneIndex].fillStyle = shadowClone.fillStyle;
})
const borderElements = elements.filter(element => !element.groupIds.some(id => id.startsWith(ShadowGroupMarker)));
groups = ea.getMaximumGroups(borderElements);
groups = groups.map((group) => group.sort((a, b) => RankElement(b) - RankElement(a)));
groups.sort((a, b) => RankElement(b[0]) - RankElement(a[0]));
ea.style.strokeColor = groups[0][0].strokeColor;
ea.style.backgroundColor = groups[0][0].backgroundColor;
ea.style.fillStyle = groups[0][0].fillStyle;
ea.style.strokeWidth = groups[0][0].strokeWidth;
ea.style.strokeStyle = groups[0][0].strokeStyle;
ea.style.roughness = groups[0][0].roughness;
ea.style.opacity = groups[0][0].opacity;
const basePolygons = groups.shift().map(element => traceElement(element));
const toolPolygons = groups.flatMap(group => group.map(element => traceElement(element)));
const result = polyboolAction({
regions: basePolygons,
inverted: false
}, {
regions: toolPolygons,
inverted: false
});
const polygonHierachy = subordinateInnerPolygons(result.regions);
drawPolygonHierachy(polygonHierachy);
ea.deleteViewElements(elements);
ea.addElementsToView(false,false,true);
return;
function traceElement(element) {
const diamondPath = (diamond) => [
SxVEC(1/2, [0, diamond.height]),
SxVEC(1/2, [diamond.width, 0]),
addVec([SxVEC(1/2, [0, diamond.height]), ([diamond.width, 0])]),
addVec([SxVEC(1/2, [diamond.width, 0]), ([0, diamond.height])]),
SxVEC(1/2, [0, diamond.height])
];
const rectanglePath = (rectangle) => [
[0,0],
[0, rectangle.height],
[rectangle.width, rectangle.height],
[rectangle.width, 0],
[0, 0]
]
const ellipsePath = (ellipse) => {
const angle = ellipse.angle;
const width = ellipse.width;
const height = ellipse.height;
const ellipseAtPoint = (t) => {
const spanningVector = [width/2*Math.cos(t), height/2*Math.sin(t)];
const baseVector = [width/2, height/2];
return addVec([spanningVector, baseVector]);
}
let points = [];
step = (2*Math.PI)/64
for (let t = 0; t < 2*Math.PI; t = t + step) {
points.push(ellipseAtPoint(t));
}
return points;
}
let polygon;
let correctForPolygon = [0, 0];
switch (element.type) {
case "diamond":
polygon = diamondPath(element);
break;
case "rectangle":
polygon = rectanglePath(element);
break;
case "ellipse":
polygon = ellipsePath(element);
break;
case "line":
case "arrow":
if (element.angle != 0) {
let smallestX = 0;
let smallestY = 0;
element.points.forEach(point => {
if (point[0] < smallestX) smallestX = point[0];
if (point[1] < smallestY) smallestY = point[1];
});
polygon = element.points.map(point => {
return [
point[0] -= smallestX,
point[1] -= smallestY
];
});
correctForPolygon = [smallestX, smallestY];
break;
}
if (element.roundness) {
new Notice("This script does not work with curved lines or arrows yet!");
return [];
}
polygon = element.points;
default:
break;
}
if (element.angle == 0) return polygon.map(v => addVec([v, [element.x, element.y]]));
polygon = polygon.map(v => addVec([v, SxVEC(-1/2, [element.width, element.height])]));
polygon = rotateVectorsByAngle(polygon, element.angle);
return polygon.map(v => addVec([v, [element.x, element.y], SxVEC(1/2, [element.width, element.height]), correctForPolygon]));
}
function RankElement(element) {
let score = 0;
const backgroundRank = [
"dashed",
"none",
"hachure",
"zigzag",
"zigzag-line",
"cross-hatch",
"solid"
]
score += (backgroundRank.findIndex((fillStyle) => fillStyle == element.fillStyle) + 1) * 10;
if (element.backgroundColor == "transparent") score -= 100;
if (element.points && getVectorLength(element.points[element.points.length - 1]) > 8) score -= 100;
if (score < 0) score = 0;
score += element.opacity / 100;
return score;
}
function drawPolygonHierachy(polygonHierachy) {
const backgroundColor = ea.style.backgroundColor;
const strokeColor = ea.style.strokeColor;
const setInnerStyle = () => {
ea.style.backgroundColor = backgroundColor;
ea.style.strokeColor = "transparent";
}
const setBorderStyle = () => {
ea.style.backgroundColor = "transparent";
ea.style.strokeColor = strokeColor;
}
const setFilledStyle = () => {
ea.style.backgroundColor = backgroundColor;
ea.style.strokeColor = strokeColor;
}
polygonHierachy.forEach(polygon => {
setFilledStyle();
let path = polygon.path;
path.push(polygon.path[0]);
if (polygon.innerPolygons.length === 0) {
ea.addLine(path);
return;
}
const outerBorder = path;
const innerPolygons = addInnerPolygons(polygon.innerPolygons);
path = path.concat(innerPolygons.backgroundPath);
path.push(polygon.path[0]);
setInnerStyle();
const backgroundId = ea.addLine(path);
setBorderStyle();
const outerBorderId = ea.addLine(outerBorder)
const innerBorderIds = innerPolygons.borderPaths.map(path => ea.addLine(path));
const allIds = [innerBorderIds, outerBorderId, backgroundId].flat();
ea.addToGroup(allIds);
const background = ea.getElement(backgroundId);
background.groupIds.push(ShadowGroupMarker + outerBorderId);
});
}
function addInnerPolygons(polygonHierachy) {
let firstPath = [];
let secondPath = [];
let borderPaths = [];
polygonHierachy.forEach(polygon => {
let path = polygon.path;
path.push(polygon.path[0]);
borderPaths.push(path);
firstPath = firstPath.concat(path);
secondPath.push(polygon.path[0]);
drawPolygonHierachy(polygon.innerPolygons);
});
return {
backgroundPath: firstPath.concat(secondPath.reverse()),
borderPaths: borderPaths
};
}
function subordinateInnerPolygons(polygons) {
const polygonObjectPrototype = (polygon) => {
return {
path: polygon,
innerPolygons: []
};
}
const insertPolygonIntoHierachy = (polygon, hierarchy) => {
for (let i = 0; i < hierarchy.length; i++) {
const polygonObject = hierarchy[i];
let inside = null;
let pointIndex = 0;
do {
inside = pointInPolygon(polygon[pointIndex], polygonObject.path);
pointIndex++
} while (inside === null);
if (inside) {
hierarchy[i].innerPolygons = insertPolygonIntoHierachy(polygon, hierarchy[i].innerPolygons);
return hierarchy;
}
}
polygon = polygonObjectPrototype(polygon);
for (let i = 0; i < hierarchy.length; i++) {
const polygonObject = hierarchy[i];
let inside = null;
let pointIndex = 0;
do {
inside = pointInPolygon(polygonObject.path[pointIndex], polygon.path);
pointIndex++
} while (inside === null);
if (inside) {
polygon.innerPolygons.push(hierarchy.splice(i, 1)[0]);
i--;
}
}
hierarchy.push(polygon);
return hierarchy;
}
let polygonHierachy = [];
polygons.forEach(polygon => {
polygonHierachy = insertPolygonIntoHierachy(polygon, polygonHierachy);
})
return polygonHierachy;
}
/**
* Checks if the given point lays in the polygon
* @param point array [x, y]
* @param polygon array [[x, y], ...]
* @returns true if inside, false if not, null if the point is on one of the polygons vertecies
*/
function pointInPolygon(point, polygon) {
const x = point[0];
const y = point[1];
let inside = false;
// odd even test if point is in polygon
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i][0];
const yi = polygon[i][1];
const xj = polygon[j][0];
const yj = polygon[j][1];
const intersect =
yi > y !== yj > y &&
x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
if (intersect) {
inside = !inside;
}
if ((x === xi && y === yi) || (x === xj && y === yj)) {
return null;
}
}
return inside;
}
function getVectorLength(vector) {
return Math.sqrt(vector[0]**2+vector[1]**2);
}
/**
* Adds two Vectors together
*/
function addVec(vectors) {
return vectors.reduce((acc, vec) => [acc[0] + vec[0], acc[1] + vec[1]], [0, 0]);
}
/**
* Returns the negative of the vector
*/
function negVec(vector) {
return [-vector[0], -vector[1]];
}
/**
* Multiplies Vector with a scalar
*/
function SxVEC(scalar, vector) {
return [vector[0] * scalar, vector[1] * scalar];
}
function rotateVector (vec, ang) {
var cos = Math.cos(ang);
var sin = Math.sin(ang);
return [vec[0] * cos - vec[1] * sin, vec[0] * sin + vec[1] * cos];
}
function rotateVectorsByAngle(vectors, angle) {
const cosAngle = Math.cos(angle);
const sinAngle = Math.sin(angle);
const rotationMatrix = [
[cosAngle, -sinAngle],
[sinAngle, cosAngle]
];
return applyTranformationMatrix(vectors, rotationMatrix);
}
function applyTranformationMatrix(vectors, transformationMatrix) {
const result = [];
for (const vector of vectors) {
const x = vector[0];
const y = vector[1];
const newX = transformationMatrix[0][0] * x + transformationMatrix[0][1] * y;
const newY = transformationMatrix[1][0] * x + transformationMatrix[1][1] * y;
result.push([newX, newY]);
}
return result;
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -0,0 +1,181 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-box-each-selected-groups.png)
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];
}
}

View 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

View File

@@ -0,0 +1,52 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-change-shape.jpg)
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);

View 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

View File

@@ -0,0 +1,102 @@
/*
Connects two lines. Lines may be type of arrow or line. The resulting line will carry the style of the line higher in the drawing layers (bring to front the one you want to control the look and feel). Arrows are connected intelligently.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-concatenate-lines.png)
```js*/
const lines = ea.getViewSelectedElements().filter(el=>el.type==="line" || el.type==="arrow");
if(lines.length !== 2) {
new Notice ("Select two lines or arrows");
return;
}
// https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
const rotate = (point, element) => {
const [x1, y1] = point;
const x2 = element.x + element.width/2;
const y2 = element.y - element.height/2;
const angle = element.angle;
return [
(x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2,
(x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2,
];
}
const points = lines.map(
el=>el.points.map(p=>rotate([p[0]+el.x, p[1]+el.y],el))
);
const last = (p) => p[p.length-1];
const first = (p) => p[0];
const distance = (p1,p2) => Math.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2);
const distances = [
distance(first(points[0]),first(points[1])),
distance(first(points[0]),last (points[1])),
distance(last (points[0]),first(points[1])),
distance(last (points[0]),last (points[1]))
];
const connectDirection = distances.indexOf(Math.min(...distances));
let newPoints = [];
switch(connectDirection) {
case 0: //first-first
newPoints = [...points[0].reverse(),...points[1].slice(1)];
break;
case 1: //first-last
newPoints = [...points[0].reverse(),...points[1].reverse().slice(1)];
break;
case 2: //last-first
newPoints = [...points[0],...points[1].slice(1)];
break;
case 3: //last-last
newPoints = [...points[0],...points[1].reverse().slice(1)];
break;
}
["strokeColor", "backgrounColor", "fillStyle", "roundness", "roughness", "strokeWidth", "strokeStyle", "opacity"].forEach(prop=>{
ea.style[prop] = lines[1][prop];
})
ea.style.startArrowHead = null;
ea.style.endArrowHead = null;
ea.copyViewElementsToEAforEditing(lines);
ea.getElements().forEach(el=>{el.isDeleted = true});
const lineTypes = parseInt(lines.map(line => line.type === "line" ? '1' : '0').join(''),2);
switch (lineTypes) {
case 0: //arrow - arrow
ea.addArrow(
newPoints,
connectDirection === 0 //first-first
? { startArrowHead: lines[0].endArrowhead, endArrowHead: lines[1].endArrowhead }
: connectDirection === 1 //first-last
? { startArrowHead: lines[0].endArrowhead, endArrowHead: lines[1].startArrowhead }
: connectDirection === 2 //last-first
? { startArrowHead: lines[0].startArrowhead, endArrowHead: lines[1].endArrowhead }
//3: last-last
: { startArrowHead: lines[0].startArrowhead, endArrowHead: lines[1].startArrowhead }
);
break;
case 1: //arrow - line
reverse = connectDirection === 0 || connectDirection === 1;
ea.addArrow(newPoints,{
startArrowHead: reverse ? lines[0].endArrowhead : lines[0].startArrowhead,
endArrowHead: reverse ? lines[0].startArrowhead : lines[0].endArrowhead
});
break;
case 2: //line - arrow
reverse = connectDirection === 1 || connectDirection === 3;
ea.addArrow(newPoints,{
startArrowHead: reverse ? lines[1].endArrowhead : lines[1].startArrowhead,
endArrowHead: reverse ? lines[1].startArrowhead : lines[1].endArrowhead
});
break;
case 3: //line - line
ea.addLine(newPoints);
break;
}
ea.addElementsToView();

View File

@@ -0,0 +1,17 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 72.75819749055177 80.03703336574608" width="72.75819749055177" height="80.03703336574608">
<!-- svg-source:excalidraw -->
<defs>
<style class="style-fonts">
@font-face {
font-family: "Virgil";
src: url("https://excalidraw.com/Virgil.woff2");
}
@font-face {
font-family: "Cascadia";
src: url("https://excalidraw.com/Cascadia.woff2");
}
</style>
</defs>
<g stroke-linecap="round"><g transform="translate(4 4) rotate(0 12.71901889991409 17.183109917454658)"><path d="M0 0 C0 7.02, 0 14.05, 0 34.37 M0 34.37 C7.62 34.37, 15.24 34.37, 25.44 34.37" stroke="black" stroke-width="4.5" fill="none" stroke-dasharray="1.5 10"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(51.379765518092086 61.93633577499986) rotate(0 5.684341886080802e-14 7.050348795373111)"><path d="M0 0 C0 4.06, 0 8.11, 0 14.1" stroke="black" stroke-width="4.5" fill="none" stroke-dasharray="1.5 10"></path></g></g><mask></mask><g stroke-linecap="round" transform="translate(34.0013341989918 20.987787610339183) rotate(0 17.378431645779926 17.378431645779983)"><path d="M34.76 17.38 C34.76 18.38, 34.67 19.41, 34.49 20.4 C34.32 21.39, 34.05 22.38, 33.71 23.32 C33.36 24.27, 32.93 25.2, 32.43 26.07 C31.93 26.94, 31.34 27.78, 30.69 28.55 C30.04 29.32, 29.32 30.04, 28.55 30.69 C27.78 31.34, 26.94 31.93, 26.07 32.43 C25.2 32.93, 24.27 33.36, 23.32 33.71 C22.38 34.05, 21.39 34.32, 20.4 34.49 C19.41 34.67, 18.38 34.76, 17.38 34.76 C16.37 34.76, 15.35 34.67, 14.36 34.49 C13.37 34.32, 12.38 34.05, 11.43 33.71 C10.49 33.36, 9.56 32.93, 8.69 32.43 C7.82 31.93, 6.98 31.34, 6.21 30.69 C5.44 30.04, 4.71 29.32, 4.07 28.55 C3.42 27.78, 2.83 26.94, 2.33 26.07 C1.83 25.2, 1.39 24.27, 1.05 23.32 C0.7 22.38, 0.44 21.39, 0.26 20.4 C0.09 19.41, 0 18.38, 0 17.38 C0 16.37, 0.09 15.35, 0.26 14.36 C0.44 13.37, 0.7 12.38, 1.05 11.43 C1.39 10.49, 1.83 9.56, 2.33 8.69 C2.83 7.82, 3.42 6.98, 4.07 6.21 C4.71 5.44, 5.44 4.71, 6.21 4.07 C6.98 3.42, 7.82 2.83, 8.69 2.33 C9.56 1.83, 10.49 1.39, 11.43 1.05 C12.38 0.7, 13.37 0.44, 14.36 0.26 C15.35 0.09, 16.37 0, 17.38 0 C18.38 0, 19.41 0.09, 20.4 0.26 C21.39 0.44, 22.38 0.7, 23.32 1.05 C24.27 1.39, 25.2 1.83, 26.07 2.33 C26.94 2.83, 27.78 3.42, 28.55 4.07 C29.32 4.71, 30.04 5.44, 30.69 6.21 C31.34 6.98, 31.93 7.82, 32.43 8.69 C32.93 9.56, 33.36 10.49, 33.71 11.43 C34.05 12.38, 34.32 13.37, 34.49 14.36 C34.67 15.35, 34.71 16.88, 34.76 17.38 C34.8 17.88, 34.8 16.88, 34.76 17.38" stroke="black" stroke-width="4" fill="none"></path></g><g stroke-linecap="round"><g transform="translate(41.72257566145686 38.36621939788711) rotate(0 9.65718949485347 0)"><path d="M0 0 C4.11 0, 8.22 0, 19.31 0 M0 0 C6.95 0, 13.9 0, 19.31 0" stroke="black" stroke-width="4" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(41.72257587602678 38.36622004108449) rotate(89.99999999999994 9.65718949485347 0)"><path d="M0 0 C5.31 0, 10.62 0, 19.31 0 M0 0 C4.56 0, 9.13 0, 19.31 0" stroke="black" stroke-width="4" fill="none"></path></g></g><mask></mask></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,43 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-copy-selected-element-styles-to-global.png)
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;
}

View 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

View File

@@ -0,0 +1,61 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-ellipse-elements.png)
This script will add an encapsulating ellipse 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 ellipse 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;
const ellipseWidth = box.width/Math.sqrt(2);
const ellipseHeight = box.height/Math.sqrt(2);
const topX = box.topX - (ellipseWidth - box.width/2);
const topY = box.topY - (ellipseHeight - box.height/2);
id = ea.addEllipse(
topX - padding,
topY - padding,
2*ellipseWidth + 2*padding,
2*ellipseHeight + 2*padding
);
ea.copyViewElementsToEAforEditing(elements);
ea.addToGroup([id].concat(elements.map((el)=>el.id)));
ea.addElementsToView(false,false);

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1,12 @@
/*
Creates a new Excalidraw.com collaboration room and places the link to the room on the clipboard.
```js*/
const room = Array.from(window.crypto.getRandomValues(new Uint8Array(10))).map((byte) => `0${byte.toString(16)}`.slice(-2)).join("");
const key = (await window.crypto.subtle.exportKey("jwk",await window.crypto.subtle.generateKey({name:"AES-GCM",length:128},true,["encrypt", "decrypt"]))).k;
const link = `https://excalidraw.com/#room=${room},${key}`;
ea.addIFrame(0,0,800,600,link);
ea.addElementsToView(true,true);
window.navigator.clipboard.writeText(link);
new Notice("The collaboration room link is available on the clipboard.",4000);

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"><g stroke-width="1.5"></path><circle cx="9" cy="7" r="4"></circle><path d="M3 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path><path d="M21 21v-2a4 4 0 0 0 -3 -3.85"></path></g></svg>

After

Width:  |  Height:  |  Size: 382 B

View File

@@ -0,0 +1,67 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-grid-selected-images.png)
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())
}

View 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

View File

@@ -0,0 +1,75 @@
/*
Adds support for pen inversion, a.k.a. the hardware eraser on the back of your pen.
Simply use the eraser on a supported pen, and it will erase. Your previous tool will be restored when the eraser leaves the screen.
(Tested with a surface pen, but should work with all windows ink devices, and probably others)
**Note:** This script will stay active until the *Obsidian* window is closed.
Compatible with my *Auto Draw for Pen* script
```javascript
*/
(function() {
'use strict';
let activated
let revert
function handlePointer(e) {
const activeTool = ea.getExcalidrawAPI().getAppState().activeTool;
const isEraser = e.pointerType === 'pen' && e.buttons & 32
function setActiveTool(t) {
ea.getExcalidrawAPI().setActiveTool(t)
}
if (!activated && isEraser) {
//Store previous tool
const btns = document.querySelectorAll('.App-toolbar input.ToolIcon_type_radio')
for (const i in btns) {
if (btns[i]?.checked) {
revert = btns[i]
}
}
revert = activeTool
// Activate eraser tool
setActiveTool({type: "eraser"})
activated = true
// Force Excalidraw to recognize this the same as pen tip
// https://github.com/excalidraw/excalidraw/blob/4a9fac2d1e5c4fac334201ef53c6f5d2b5f6f9f5/src/components/App.tsx#L2945-L2951
Object.defineProperty(e, 'button', {
value: 0,
writable: false
});
}
// Keep on eraser!
if (isEraser && activated) {
setActiveTool({type: "eraser"})
}
if (activated && !isEraser) {
// Revert tool on release
// revert.click()
setActiveTool(revert)
activated = false
// Force delete "limbo" elements
// This doesn't happen on the web app
// It's a bug caused by switching to eraser during a stroke
ea.setView("active");
var del = []
for (const i in ea.getViewElements()) {
const element = ea.getViewElements()[i];
if (element.opacity === 20) {
del.push(element)
}
}
ea.deleteViewElements(del)
setActiveTool(revert)
}
}
window.addEventListener('pointerdown', handlePointer, { capture: true })
window.addEventListener('pointermove', handlePointer, { capture: true })
})();

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 448 512" style="enable-background:new 0 0 448 512;" xml:space="preserve">
<style type="text/css">
.st0{stroke:#000000;stroke-width:2;stroke-miterlimit:10;}
</style>
<path class="st0" d="M355.8,234.1"/>
<g>
<path class="st0" d="M404.8,293.5L306.9,208l-120,137.4l97.9,85.5c13.6,11.9,34.4,10.5,46.3-3.1l76.8-88
C419.9,326.2,418.5,305.5,404.8,293.5z M389.4,322.2l-78.2,89.6c-3.8,4.3-10.4,4.8-14.8,1l-77.8-68l92-105.3l77.8,68
C392.8,311.2,393.2,317.8,389.4,322.2z"/>
<polygon class="st0" points="52.4,103.7 64.4,238.9 93,263.8 213,126.4 184.4,101.4 "/>
<rect x="108.3" y="185.1" transform="matrix(0.6578 -0.7532 0.7532 0.6578 -108.9276 230.7956)" class="st0" width="182.4" height="100.3"/>
<path class="st0" d="M109.7,381.6c-23.7-22.2-40-49.3-48.9-78.2c8.2-0.9,22.4-3.6,30.1-12.3c-12.6-12.5-25.3-25-37.9-37.5
c0-0.1,0-0.3,0-0.4l-23.6-22c-6,60.7,15.5,123.7,63.7,168.8s112.5,62.4,172.7,52.4l-24.1-22.6C194.8,432.3,146.9,416.4,109.7,381.6
z"/>
<path class="st0" d="M368.8,105.4c-56-52.4-133.5-67.2-201.3-45.5l21,19.6c56.1-13.2,117.7,1.1,163.1,43.7
c33,30.9,51.7,71.2,55.9,112.7c-0.2-0.4-0.3-0.6-0.3-0.6s-25.1-0.1-36.5,12.7c11.8,11.6,23.5,23.3,35.3,34.9c0,0,0,0.1,0,0.1
l2.4,2.3c0.4,0.4,0.9,0.9,1.3,1.3c0,0,0,0,0,0l17.7,16.6C444.7,234.1,424.8,157.7,368.8,105.4z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,370 @@
/*
format **the left to right** mind map
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-mindmap-format-1.png)
# tree
Mind map is actually a tree, so you must have a **root node**. The script will determine **the leftmost element** of the selected element as the root element (node is excalidraw element, e.g. rectangle, diamond, ellipse, text, image, but it can't be arrow, line, freedraw, **group**)
The element connecting node and node must be an **arrow** and have the correct direction, e.g. **parent node -> children node**
# sort
The order of nodes in the Y axis or vertical direction is determined by **the creation time** of the arrow connecting it
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-mindmap-format-2.png)
So if you want to readjust the order, you can **delete arrows and reconnect them**
# setting
Script provides options to adjust the style of mind map, The option is at the bottom of the option of the exalidraw plugin(e.g. Settings -> Community plugins -> Excalidraw -> drag to bottom)
# problem
1. since the start bingding and end bingding of the arrow are easily disconnected from the node, so if there are unformatted parts, please **check the connection** and use the script to **reformat**
```javascript
*/
let settings = ea.getScriptSettings();
//set default values on first run
if (!settings["MindMap Format"]) {
settings = {
"MindMap Format": {
value: "Excalidraw/MindMap Format",
description:
"This is prepared for the namespace of MindMap Format and does not need to be modified",
},
"default gap": {
value: 10,
description: "Interval size of element",
},
"curve length": {
value: 40,
description: "The length of the curve part in the mind map line",
},
"length between element and line": {
value: 50,
description:
"The distance between the tail of the connection and the connecting elements of the mind map",
},
};
ea.setScriptSettings(settings);
}
const sceneElements = ea.getExcalidrawAPI().getSceneElements();
// default X coordinate of the middle point of the arc
const defaultDotX = Number(settings["curve length"].value);
// The default length from the middle point of the arc on the X axis
const defaultLengthWithCenterDot = Number(
settings["length between element and line"].value
);
// Initial trimming distance of the end point on the Y axis
const initAdjLength = 4;
// default gap
const defaultGap = Number(settings["default gap"].value);
const setCenter = (parent, line) => {
// Focus and gap need the api calculation of excalidraw
// e.g. determineFocusDistance, but they are not available now
// so they are uniformly set to 0/1
line.startBinding.focus = 0;
line.startBinding.gap = 1;
line.endBinding.focus = 0;
line.endBinding.gap = 1;
line.x = parent.x + parent.width;
line.y = parent.y + parent.height / 2;
};
/**
* set the middle point of curve
* @param {any} lineEl the line element of excalidraw
* @param {number} height height of dot on Y axis
* @param {number} [ratio=1] coefficient of the initial trimming distance of the end point on the Y axis, default is 1
*/
const setTopCurveDotOnLine = (lineEl, height, ratio = 1) => {
if (lineEl.points.length < 3) {
lineEl.points.splice(1, 0, [defaultDotX, lineEl.points[0][1] - height]);
} else if (lineEl.points.length === 3) {
lineEl.points[1] = [defaultDotX, lineEl.points[0][1] - height];
} else {
lineEl.points.splice(2, lineEl.points.length - 3);
lineEl.points[1] = [defaultDotX, lineEl.points[0][1] - height];
}
lineEl.points[2][0] = lineEl.points[1][0] + defaultLengthWithCenterDot;
// adjust the curvature of the second line segment
lineEl.points[2][1] = lineEl.points[1][1] - initAdjLength * ratio * 0.8;
};
const setMidCurveDotOnLine = (lineEl) => {
if (lineEl.points.length < 3) {
lineEl.points.splice(1, 0, [defaultDotX, lineEl.points[0][1]]);
} else if (lineEl.points.length === 3) {
lineEl.points[1] = [defaultDotX, lineEl.points[0][1]];
} else {
lineEl.points.splice(2, lineEl.points.length - 3);
lineEl.points[1] = [defaultDotX, lineEl.points[0][1]];
}
lineEl.points[2][0] = lineEl.points[1][0] + defaultLengthWithCenterDot;
lineEl.points[2][1] = lineEl.points[1][1];
};
/**
* set the middle point of curve
* @param {any} lineEl the line element of excalidraw
* @param {number} height height of dot on Y axis
* @param {number} [ratio=1] coefficient of the initial trimming distance of the end point on the Y axis, default is 1
*/
const setBottomCurveDotOnLine = (lineEl, height, ratio = 1) => {
if (lineEl.points.length < 3) {
lineEl.points.splice(1, 0, [defaultDotX, lineEl.points[0][1] + height]);
} else if (lineEl.points.length === 3) {
lineEl.points[1] = [defaultDotX, lineEl.points[0][1] + height];
} else {
lineEl.points.splice(2, lineEl.points.length - 3);
lineEl.points[1] = [defaultDotX, lineEl.points[0][1] + height];
}
lineEl.points[2][0] = lineEl.points[1][0] + defaultLengthWithCenterDot;
// adjust the curvature of the second line segment
lineEl.points[2][1] = lineEl.points[1][1] + initAdjLength * ratio * 0.8;
};
const setTextXY = (rect, text) => {
text.x = rect.x + (rect.width - text.width) / 2;
text.y = rect.y + (rect.height - text.height) / 2;
};
const setChildrenXY = (parent, children, line, elementsMap) => {
x = parent.x + parent.width + line.points[2][0];
y = parent.y + parent.height / 2 + line.points[2][1] - children.height / 2;
distX = children.x - x;
distY = children.y - y;
ea.getElementsInTheSameGroupWithElement(children, sceneElements).forEach((el) => {
el.x = el.x - distX;
el.y = el.y - distY;
});
if (
["rectangle", "diamond", "ellipse"].includes(children.type) &&
![null, undefined].includes(children.boundElements)
) {
const textDesc = children.boundElements.filter(
(el) => el.type === "text"
)[0];
if (textDesc !== undefined) {
const textEl = elementsMap.get(textDesc.id);
setTextXY(children, textEl);
}
}
};
/**
* returns the height of the upper part of all child nodes
* and the height of the lower part of all child nodes
* @param {Number[]} childrenTotalHeightArr
* @returns {Number[]} [topHeight, bottomHeight]
*/
const getNodeCurrentHeight = (childrenTotalHeightArr) => {
if (childrenTotalHeightArr.length <= 0) return [0, 0];
else if (childrenTotalHeightArr.length === 1)
return [childrenTotalHeightArr[0] / 2, childrenTotalHeightArr[0] / 2];
const heightArr = childrenTotalHeightArr;
let topHeight = 0,
bottomHeight = 0;
const isEven = heightArr.length % 2 === 0;
const mid = Math.floor(heightArr.length / 2);
const topI = mid - 1;
const bottomI = isEven ? mid : mid + 1;
topHeight = isEven ? 0 : heightArr[mid] / 2;
for (let i = topI; i >= 0; i--) {
topHeight += heightArr[i];
}
bottomHeight = isEven ? 0 : heightArr[mid] / 2;
for (let i = bottomI; i < heightArr.length; i++) {
bottomHeight += heightArr[i];
}
return [topHeight, bottomHeight];
};
/**
* handle the height of each point in the single-level tree
* @param {Array} lines
* @param {Map} elementsMap
* @param {Boolean} isEven
* @param {Number} mid 'lines' array midpoint index
* @returns {Array} height array corresponding to 'lines'
*/
const handleDotYValue = (lines, elementsMap, isEven, mid) => {
const getTotalHeight = (line, elementsMap) => {
return elementsMap.get(line.endBinding.elementId).totalHeight;
};
const getTopHeight = (line, elementsMap) => {
return elementsMap.get(line.endBinding.elementId).topHeight;
};
const getBottomHeight = (line, elementsMap) => {
return elementsMap.get(line.endBinding.elementId).bottomHeight;
};
const heightArr = new Array(lines.length).fill(0);
const upI = mid === 0 ? 0 : mid - 1;
const bottomI = isEven ? mid : mid + 1;
let initHeight = isEven ? 0 : getTopHeight(lines[mid], elementsMap);
for (let i = upI; i >= 0; i--) {
heightArr[i] = initHeight + getBottomHeight(lines[i], elementsMap);
initHeight += getTotalHeight(lines[i], elementsMap);
}
initHeight = isEven ? 0 : getBottomHeight(lines[mid], elementsMap);
for (let i = bottomI; i < lines.length; i++) {
heightArr[i] = initHeight + getTopHeight(lines[i], elementsMap);
initHeight += getTotalHeight(lines[i], elementsMap);
}
return heightArr;
};
/**
* format single-level tree
* @param {any} parent
* @param {Array} lines
* @param {Map} childrenDescMap
* @param {Map} elementsMap
*/
const formatTree = (parent, lines, childrenDescMap, elementsMap) => {
lines.forEach((item) => setCenter(parent, item));
const isEven = lines.length % 2 === 0;
const mid = Math.floor(lines.length / 2);
const heightArr = handleDotYValue(lines, childrenDescMap, isEven, mid);
lines.forEach((item, index) => {
if (isEven) {
if (index < mid) setTopCurveDotOnLine(item, heightArr[index], index + 1);
else setBottomCurveDotOnLine(item, heightArr[index], index - mid + 1);
} else {
if (index < mid) setTopCurveDotOnLine(item, heightArr[index], index + 1);
else if (index === mid) setMidCurveDotOnLine(item);
else setBottomCurveDotOnLine(item, heightArr[index], index - mid);
}
});
lines.forEach((item) => {
if (item.endBinding !== null) {
setChildrenXY(
parent,
elementsMap.get(item.endBinding.elementId),
item,
elementsMap
);
}
});
};
const generateTree = (elements) => {
const elIdMap = new Map([[elements[0].id, elements[0]]]);
let minXEl = elements[0];
for (let i = 1; i < elements.length; i++) {
elIdMap.set(elements[i].id, elements[i]);
if (
!(elements[i].type === "arrow" || elements[i].type === "line") &&
elements[i].x < minXEl.x
) {
minXEl = elements[i];
}
}
const root = {
el: minXEl,
totalHeight: minXEl.height,
topHeight: 0,
bottomHeight: 0,
linkChildrensLines: [],
isLeafNode: false,
children: [],
};
const preIdSet = new Set(); // The id_set of Elements that is already in the tree, avoid a dead cycle
const dfsForTreeData = (root) => {
if (preIdSet.has(root.el.id)) {
return 0;
}
preIdSet.add(root.el.id);
let lines = root.el.boundElements.filter(
(el) =>
el.type === "arrow" &&
!preIdSet.has(el.id) &&
elIdMap.get(el.id)?.startBinding?.elementId === root.el.id
);
if (lines.length === 0) {
root.isLeafNode = true;
root.totalHeight = root.el.height + 2 * defaultGap;
[root.topHeight, root.bottomHeight] = [
root.totalHeight / 2,
root.totalHeight / 2,
];
return root.totalHeight;
} else {
lines = lines.map((elementDesc) => {
preIdSet.add(elementDesc.id);
return elIdMap.get(elementDesc.id);
});
}
const linkChildrensLines = [];
lines.forEach((el) => {
const line = el;
if (
line &&
line.endBinding !== null &&
line.endBinding !== undefined &&
!preIdSet.has(elIdMap.get(line.endBinding.elementId).id)
) {
const children = elIdMap.get(line.endBinding.elementId);
linkChildrensLines.push(line);
root.children.push({
el: children,
totalHeight: 0,
topHeight: 0,
bottomHeight: 0,
linkChildrensLines: [],
isLeafNode: false,
children: [],
});
}
});
let totalHeight = 0;
root.children.forEach((el) => (totalHeight += dfsForTreeData(el)));
root.linkChildrensLines = linkChildrensLines;
if (root.children.length === 0) {
root.isLeafNode = true;
root.totalHeight = root.el.height + 2 * defaultGap;
[root.topHeight, root.bottomHeight] = [
root.totalHeight / 2,
root.totalHeight / 2,
];
} else if (root.children.length > 0) {
root.totalHeight = Math.max(root.el.height + 2 * defaultGap, totalHeight);
[root.topHeight, root.bottomHeight] = getNodeCurrentHeight(
root.children.map((item) => item.totalHeight)
);
}
return totalHeight;
};
dfsForTreeData(root);
const dfsForFormat = (root) => {
if (root.isLeafNode) return;
const childrenDescMap = new Map(
root.children.map((item) => [item.el.id, item])
);
formatTree(root.el, root.linkChildrensLines, childrenDescMap, elIdMap);
root.children.forEach((el) => dfsForFormat(el));
};
dfsForFormat(root);
};
const elements = ea.getViewSelectedElements();
generateTree(elements);
ea.copyViewElementsToEAforEditing(elements);
await ea.addElementsToView(false, false);

View 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="1673428425027" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1642" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M388.7 542.88c-16.57 0-30-13.43-30-30s13.43-30 30-30c52.3 0 94.85-42.55 94.85-94.85v-67.81c0-40.96 15.84-79.58 44.6-108.74 28.76-29.16 67.16-45.53 108.12-46.1l3.43-0.05c16.57-0.22 30.18 13.02 30.41 29.58 0.23 16.57-13.02 30.18-29.58 30.41l-3.43 0.05c-51.58 0.71-93.55 43.25-93.55 94.84v67.81c0 85.4-69.47 154.86-154.85 154.86z" fill="#000000" p-id="1643"></path><path d="M640.12 860.42h-0.42l-3.43-0.05c-40.96-0.56-79.36-16.93-108.12-46.09s-44.6-67.78-44.6-108.74v-67.8c0-52.3-42.55-94.85-94.85-94.85-16.57 0-30-13.43-30-30s13.43-30 30-30c85.38 0 154.85 69.47 154.85 154.85v67.8c0 51.59 41.96 94.13 93.55 94.84l3.43 0.05c16.57 0.23 29.81 13.84 29.59 30.41-0.24 16.42-13.62 29.58-30 29.58z" fill="#000000" p-id="1644"></path><path d="M640.11 542.88H388.7c-16.57 0-30-13.43-30-30s13.43-30 30-30h251.42c16.57 0 30 13.43 30 30-0.01 16.57-13.44 30-30.01 30z" fill="#000000" p-id="1645"></path><path d="M343.89 638.95H137.78c-38.6 0-70-31.4-70-70V456.81c0-38.6 31.4-70 70-70h206.11c38.6 0 70 31.4 70 70v112.13c0 38.6-31.4 70.01-70 70.01zM137.78 446.81c-5.51 0-10 4.49-10 10v112.13c0 5.51 4.49 10 10 10h206.11c5.51 0 10-4.49 10-10V456.81c0-5.51-4.49-10-10-10H137.78zM830.16 316.96h-93.98c-69.51 0-126.07-56.55-126.07-126.07S666.66 64.83 736.18 64.83h93.98c69.51 0 126.07 56.55 126.07 126.07-0.01 69.5-56.56 126.06-126.07 126.06z m-93.98-192.13c-36.43 0-66.07 29.64-66.07 66.07s29.64 66.07 66.07 66.07h93.98c36.43 0 66.07-29.64 66.07-66.07s-29.64-66.07-66.07-66.07h-93.98zM830.16 638.95h-93.98c-69.51 0-126.07-56.55-126.07-126.07 0-69.51 56.55-126.07 126.07-126.07h93.98c69.51 0 126.07 56.55 126.07 126.07-0.01 69.51-56.56 126.07-126.07 126.07z m-93.98-192.14c-36.43 0-66.07 29.64-66.07 66.07 0 36.43 29.64 66.07 66.07 66.07h93.98c36.43 0 66.07-29.64 66.07-66.07 0-36.43-29.64-66.07-66.07-66.07h-93.98z" fill="#000000" p-id="1646"></path><path d="M830.16 959.17h-93.98c-69.51 0-126.07-56.55-126.07-126.07s56.55-126.07 126.07-126.07h93.98c69.51 0 126.07 56.55 126.07 126.07s-56.56 126.07-126.07 126.07z m-93.98-192.13c-36.43 0-66.07 29.64-66.07 66.07s29.64 66.07 66.07 66.07h93.98c36.43 0 66.07-29.64 66.07-66.07s-29.64-66.07-66.07-66.07h-93.98z" fill="#000000" p-id="1647"></path></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,216 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-download-raw.jpg)
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.
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-modify-background-color-opacity.png)
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;
}

View 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

View File

@@ -0,0 +1,80 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-organic-line.jpg)
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
*/
if(!ea.verifyMinimumPluginVersion || !ea.verifyMinimumPluginVersion("1.8.8")) {
new Notice("This script requires a newer version of Excalidraw. Please install the latest version.");
return;
}
let elements = ea.getViewSelectedElements().filter((el)=>["freedraw","line","arrow"].includes(el.type));
//if nothing is selected find the last element that was drawn and use it if it is the right element 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]];
}
const lineType = await utils.suggester(["Thick to thin", "Thin to thick to thin"],["l1","l2"],"Select the type of line");
if(!lineType) return;
ea.copyViewElementsToEAforEditing(elements);
ea.getElements().forEach((el)=>{
el.simulatePressure = false;
el.type = "freedraw";
el.pressures = Array(el.points.length).fill(1);
el.customData = {
strokeOptions: {
... lineType === "l1"
? {
options: {
thinning: 1,
smoothing: 0.5,
streamline: 0.5,
easing: "linear",
start: {
taper: 0,
cap: true
},
end: {
taper: true,
easing: "linear",
cap: false
}
}
}
: {
options: {
thinning: 4,
smoothing: 0.5,
streamline: 0.5,
easing: "linear",
start: {
taper: true,
easing: "linear",
cap: true
},
end: {
taper: true,
easing: "linear",
cap: false
}
}
}
}
};
});
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)));

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,70 @@
/*
![](https://raw.githubusercontent.com/zsviczian/obsidian-excalidraw-plugin/master/images/scripts-text-aura.jpg)
Select a single text element, or a text element in a container. The container must have a transparent background.
The script will add an aura to the text by adding 4 copies of the text each with the inverted stroke color of the original text element and with a very small X and Y offset. The resulting 4 + 1 (original) text elements or containers will be grouped.
If you copy a color string on the clipboard before running the script, the script will use that color instead of the inverted color.
```js*/
els = ea.getViewSelectedElements();
const isText = (els.length === 1) && els[0].type === "text";
const isContainer = (els.length === 2) &&
((els[0].type === "text" && els[1].id === els[0].containerId && els[1].backgroundColor.toLowerCase() === "transparent") ||
(els[1].type === "text" && els[0].id === els[1].containerId && els[0].backgroundColor.toLowerCase() === "transparent"));
if (!(isText || isContainer)) {
new Notice ("Select a single text element, or a container with a text element and with transparent background color",10000);
return;
}
let strokeColor = ea
.getCM(els.filter(el=>el.type === "text")[0].strokeColor)
.invert({alpha: false})
.stringHEX({alpha: false});
clipboardText = await navigator.clipboard.readText();
if(clipboardText) {
const cm1 = ea.getCM(clipboardText);
if(cm1.format !== "invalid") {
strokeColor = cm1.stringHEX();
} else {
const cm2 = ea.getCM("#"+clipboardText);
if(cm2.format !== "invalid") {
strokeColor = cm2.stringHEX();
}
}
}
const offset = els.filter(el=>el.type === "text")[0].fontSize/24;
let ids = [];
const addClone = (offsetX, offsetY) => {
els.forEach(el=>{
const clone = ea.cloneElement(el);
ids.push(clone.id);
clone.x += offsetX;
clone.y += offsetY;
if(offsetX!==0 || offsetY!==0) {
switch (clone.type) {
case "text":
clone.strokeColor = strokeColor;
break;
default:
clone.strokeColor = "transparent";
break;
}
}
ea.elementsDict[clone.id] = clone;
})
}
addClone(-offset,0);
addClone(offset,0);
addClone(0,offset);
addClone(0,-offset);
addClone(0,0);
ea.copyViewElementsToEAforEditing(els);
els.forEach(el=>ea.elementsDict[el.id].isDeleted = true);
ea.addToGroup(ids);
ea.addElementsToView(false, true, true);

View File

@@ -0,0 +1,17 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120">
<!-- svg-source:excalidraw -->
<defs>
<style class="style-fonts">
@font-face {
font-family: "Virgil";
src: url("https://excalidraw.com/Virgil.woff2");
}
@font-face {
font-family: "Cascadia";
src: url("https://excalidraw.com/Cascadia.woff2");
}
</style>
</defs>
<g stroke-linecap="round"><g transform="translate(0 0) rotate(0 60 60)" fill-rule="evenodd"><path d="M0 0 L120 0 L120 40 L80 40 L80 120 L40 120 L40 40 L0 40 L0 0" stroke="none" stroke-width="0" fill="red" fill-rule="evenodd"></path><path d="M0 0 C41.51 0, 83.02 0, 120 0 M0 0 C30.58 0, 61.16 0, 120 0 M120 0 C120 12.11, 120 24.22, 120 40 M120 0 C120 13.92, 120 27.84, 120 40 M120 40 C108.75 40, 97.49 40, 80 40 M120 40 C107.65 40, 95.29 40, 80 40 M80 40 C80 66.51, 80 93.01, 80 120 M80 40 C80 70.33, 80 100.66, 80 120 M80 120 C66.08 120, 52.16 120, 40 120 M80 120 C70.07 120, 60.13 120, 40 120 M40 120 C40 89.21, 40 58.42, 40 40 M40 120 C40 92.66, 40 65.33, 40 40 M40 40 C25.35 40, 10.71 40, 0 40 M40 40 C27.7 40, 15.4 40, 0 40 M0 40 C0 24.03, 0 8.05, 0 0 M0 40 C0 27.82, 0 15.65, 0 0 M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0" stroke="transparent" stroke-width="0.5" fill="none"></path></g></g><mask></mask><g stroke-linecap="round"><g transform="translate(110 10) rotate(0 -50 50)" fill-rule="evenodd"><path d="M0 0 L-100 0 L-100 20 L-60 20 L-60 100 L-40 100 L-40 20 L0 20 L0 0" stroke="none" stroke-width="0" fill="currentColor" fill-rule="evenodd"></path><path d="M0 0 C-23.27 0, -46.54 0, -100 0 M0 0 C-23.31 0, -46.62 0, -100 0 M-100 0 C-100 6.13, -100 12.26, -100 20 M-100 0 C-100 5.84, -100 11.69, -100 20 M-100 20 C-87.37 20, -74.74 20, -60 20 M-100 20 C-88.34 20, -76.68 20, -60 20 M-60 20 C-60 37.78, -60 55.56, -60 100 M-60 20 C-60 39.34, -60 58.68, -60 100 M-60 100 C-52.58 100, -45.17 100, -40 100 M-60 100 C-54.72 100, -49.43 100, -40 100 M-40 100 C-40 83.83, -40 67.67, -40 20 M-40 100 C-40 77.76, -40 55.51, -40 20 M-40 20 C-25.4 20, -10.8 20, 0 20 M-40 20 C-28.47 20, -16.93 20, 0 20 M0 20 C0 15.42, 0 10.84, 0 0 M0 20 C0 14.54, 0 9.08, 0 0 M0 0 C0 0, 0 0, 0 0 M0 0 C0 0, 0 0, 0 0" stroke="currentColor" stroke-width="0.5" fill="none"></path></g></g><mask></mask></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -5,5 +5,5 @@
"textFontFamily": "Lexend Deca",
"monospaceFontFamily": "SauceCodePro Nerd Font Mono",
"accentColor": "#ef6b6b",
"baseFontSize": 18
"baseFontSize": 20
}

View File

@@ -224397,7 +224397,10 @@
"latexBoilerplate": "\\color{blue}",
"taskboneEnabled": false,
"taskboneAPIkey": "",
"pinnedScripts": [],
"pinnedScripts": [
"!Załączniki/Excalidraw/Scripts/Downloaded/Hardware Eraser Support.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Repeat Elements.md"
],
"customPens": [
{
"type": "default",

View File

@@ -4,19 +4,15 @@
"type": "split",
"children": [
{
"id": "003a0fb52376c630",
"id": "c5519d39154c583a",
"type": "tabs",
"children": [
{
"id": "de054390e12f6929",
"id": "92c1866c2ef5d3f5",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "PE/Ćwiczenia/1 SEM/02. Pot. węzłowe.md",
"mode": "source",
"source": false
}
"type": "empty",
"state": {}
}
}
]
@@ -93,7 +89,6 @@
"state": {
"type": "backlink",
"state": {
"file": "!Załączniki/02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw.md",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
@@ -110,7 +105,6 @@
"state": {
"type": "outgoing-link",
"state": {
"file": "!Załączniki/02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw.md",
"linksCollapsed": false,
"unlinkedCollapsed": true
}
@@ -132,9 +126,7 @@
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "!Załączniki/02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw.md"
}
"state": {}
}
},
{
@@ -225,73 +217,47 @@
"3d-graph:3D Graph": false,
"juggl:Juggl global graph": false,
"random-note:Open random note": false,
"obsidian-excalidraw-plugin:Create new drawing": false,
"breadcrumbs:Breadcrumbs Visualisation": false
"obsidian-excalidraw-plugin:Create new drawing": false
}
},
"floating": {
"id": "eaa77caefe548457",
"type": "floating",
"children": [
{
"id": "723d659981dc264a",
"type": "window",
"children": [
{
"id": "6f17276c7747d862",
"type": "tabs",
"children": [
{
"id": "53fb200ec73fec3d",
"type": "leaf",
"state": {
"type": "excalidraw",
"state": {
"file": "!Załączniki/02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw.md"
}
}
}
]
}
],
"direction": "vertical",
"x": 0,
"y": 35,
"width": 1600,
"height": 865,
"maximize": false,
"zoom": -1.5
}
]
},
"active": "53fb200ec73fec3d",
"active": "92c1866c2ef5d3f5",
"lastOpenFiles": [
"!Załączniki/02. Pot. węzłowe 2023-11-08 09.17.19.excalidraw.md",
"PE/Ćwiczenia/1 SEM/02. Pot. węzłowe.md",
"!Załączniki/02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Text Aura.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Text Aura.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Organic Line.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Organic Line.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Modify background color opacity.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Modify background color opacity.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Mindmap format.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Mindmap format.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Hardware Eraser Support.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Hardware Eraser Support.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Grid Selected Images.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Grid Selected Images.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Excalidraw Collaboration Frame.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Excalidraw Collaboration Frame.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Ellipse Selected Elements.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Ellipse Selected Elements.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Copy Selected Element Styles to Global.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Copy Selected Element Styles to Global.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Concatenate lines.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Concatenate lines.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Change shape of selected elements.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Box Each Selected Groups.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Boolean Operations.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Auto Draw for Pen.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Add Next Step in Process.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Add Link to Existing File and Open.md",
"!Załączniki/Excalidraw/Scripts/Downloaded/Add Connector Point.md",
"TUC/Bezhazardówki.md",
"ASC/1 SEM/Ćwiczenia/3. BCD i EXCESS-3.md",
"ASC/1 SEM/Ćwiczenia/2. Reprezentacja liczb ujemnych.md",
"ASC/1 SEM/Ćwiczenia/Ćwiczenia.md",
"ASC/ASC.md",
"PI/Ćwiczenia/3. Projektowanie rozkazów.md",
"PI/Ćwiczenia/20221121122351.md",
"PI/Ćwiczenia/20221010123607.md",
"PI/Ćwiczenia/1.Rekurencja.md",
"PI/Wykłady/1 SEM/20221014134528.md",
"PI/Ćwiczenia/2.Gramatyki.md",
"PI/PI.md",
"PE/Wykład/Wykład.md",
"!Załączniki/20221123102116 2022-11-23 10.21.43.excalidraw.md",
"Elektrotechnika/Ćwiczenia/20221123102116.md",
"Elektrotechnika/Ćwiczenia/20221028102800.md",
"!Załączniki/02. Pot. węzłowe 2023-10-25 08.42.46.excalidraw.md",
"!Załączniki/02. Pot. węzłowe 2023-10-25 08.38.29.excalidraw.md",
"PE/Ćwiczenia/1 SEM/01. Wstęp.md",
"Elektrotechnika/Ćwiczenia/20221014103322.md",
"TC/TC.md",
"TC/Ściągi/ALGEBRA BOOLOWSKA.md",
"TC/Ćwiczenia/Minimalizacja.md",
"!Załączniki/Minimalizacja 2023-10-24 15.05.07.excalidraw.md",
"ASC/1 SEM/Wykłady",
"PE/Wykład",
"PE/Ćwiczenia/1 SEM",
@@ -302,16 +268,6 @@
"AMiAL/CS/Ćwiczenia/1 SEM",
"AMiAL/CS/Ćwiczenia",
"AMiAL/CS",
"!Załączniki/Pasted image 20230620141025.png",
"!Załączniki/Excalidraw/Scripts/Downloaded/Normalize Selected Arrows.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Fixed inner distance.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Alternative Pens.svg",
"!Załączniki/Pasted image 20230314104143.png",
"!Załączniki/Excalidraw/Scripts/Downloaded/Box Selected Elements.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Text Arch.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Repeat Elements.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Elbow connectors.svg",
"!Załączniki/Excalidraw/Scripts/Downloaded/Convert freedraw to line.svg",
"TC/Untitled.canvas"
]
}

View File

@@ -1,3 +1,4 @@
![[02. Pot. węzłowe 2023-10-25 08.38.29.excalidraw]]
![[02. Pot. węzłowe 2023-10-25 08.42.46.excalidraw]]
![[02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw]]
![[02. Pot. węzłowe 2023-11-08 08.38.58.excalidraw]]
![[02. Pot. węzłowe 2023-11-08 09.17.19.excalidraw]]