From 9229f13172b52135b6cfeaa96faf7568aa18bfab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Wed, 28 Aug 2024 16:20:49 +0800 Subject: [PATCH 01/26] =?UTF-8?q?Fix=EF=BC=9A=E8=B0=83=E6=95=B4hide=5Ftext?= =?UTF-8?q?=5Fedit=E4=BA=8B=E4=BB=B6=E8=A7=A6=E5=8F=91=E6=97=B6=E6=9C=BA?= =?UTF-8?q?=EF=BC=8C=E9=98=B2=E6=AD=A2=E4=B8=80=E4=BA=9B=E6=83=85=E5=86=B5?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E6=AD=BB=E5=BE=AA=E7=8E=AF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/TextEdit.js | 13 +++++++------ simple-mind-map/src/plugins/RichText.js | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/simple-mind-map/src/core/render/TextEdit.js b/simple-mind-map/src/core/render/TextEdit.js index 0663ed68..ed70863b 100644 --- a/simple-mind-map/src/core/render/TextEdit.js +++ b/simple-mind-map/src/core/render/TextEdit.js @@ -313,12 +313,7 @@ export default class TextEdit { } this.mindMap.render() }) - this.mindMap.emit( - 'hide_text_edit', - this.textEditNode, - this.renderer.activeNodeList, - this.currentNode - ) + const currentNode = this.currentNode this.currentNode = null this.textEditNode.style.display = 'none' this.textEditNode.innerHTML = '' @@ -327,6 +322,12 @@ export default class TextEdit { this.textEditNode.style.fontWeight = 'normal' this.textEditNode.style.transform = 'translateY(0)' this.showTextEdit = false + this.mindMap.emit( + 'hide_text_edit', + this.textEditNode, + this.renderer.activeNodeList, + currentNode + ) } // 获取当前正在编辑中的节点实例 diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index 2388c33f..b8cfb584 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -360,12 +360,13 @@ class RichText { // } this.mindMap.render() }) - this.mindMap.emit('hide_text_edit', this.textEditNode, list, this.node) + const node = this.node this.textEditNode.style.display = 'none' this.showTextEdit = false this.mindMap.emit('rich_text_selection_change', false) this.node = null this.isInserting = false + this.mindMap.emit('hide_text_edit', this.textEditNode, list, node) } // 初始化Quill富文本编辑器 From 2bcc4a7c18b9c3c8b013c327905ac498ed4c8263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Wed, 28 Aug 2024 16:39:35 +0800 Subject: [PATCH 02/26] =?UTF-8?q?Demo=EF=BC=9A=E6=94=AF=E6=8C=81=E7=82=B9?= =?UTF-8?q?=E5=87=BB=E7=94=BB=E5=B8=83=E5=8F=96=E6=B6=88=E7=BC=A9=E6=94=BE?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=A1=86=E7=9A=84=E8=81=9A=E7=84=A6=E7=8A=B6?= =?UTF-8?q?=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/Edit/components/Scale.vue | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/web/src/pages/Edit/components/Scale.vue b/web/src/pages/Edit/components/Scale.vue index 70002582..0bb0f03d 100644 --- a/web/src/pages/Edit/components/Scale.vue +++ b/web/src/pages/Edit/components/Scale.vue @@ -10,6 +10,7 @@
{ - this.scaleNum = this.toPer(scale) - }) + this.mindMap.on('scale', this.onScale) + this.mindMap.on('draw_click', this.onDrawClick) this.scaleNum = this.toPer(this.mindMap.view.scale) } } }, + beforeDestroy() { + this.mindMap.off('scale', this.onScale) + this.mindMap.off('draw_click', this.onDrawClick) + }, methods: { // 转换成百分数 toPer(scale) { @@ -98,6 +102,14 @@ export default { const cy = this.mindMap.height / 2 this.mindMap.view.setScale(this.scaleNum / 100, cx, cy) } + }, + + onScale(scale) { + this.scaleNum = this.toPer(scale) + }, + + onDrawClick() { + if (this.$refs.inputRef) this.$refs.inputRef.blur() } } } From 428c4fd93b0d8157ded695fa14e03b71fda7d0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Wed, 28 Aug 2024 16:41:59 +0800 Subject: [PATCH 03/26] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E9=BB=98?= =?UTF-8?q?=E8=AE=A4=E4=B8=BB=E9=A2=98=E9=85=8D=E7=BD=AE=E4=B8=AD=E7=9A=84?= =?UTF-8?q?normal=E5=8D=95=E8=AF=8D=E6=8B=BC=E5=86=99=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/themes/default.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simple-mind-map/src/themes/default.js b/simple-mind-map/src/themes/default.js index d0baa737..4960f04a 100644 --- a/simple-mind-map/src/themes/default.js +++ b/simple-mind-map/src/themes/default.js @@ -94,7 +94,7 @@ export default { fontFamily: '微软雅黑, Microsoft YaHei', color: '#565656', fontSize: 16, - fontWeight: 'noraml', + fontWeight: 'normal', fontStyle: 'normal', lineHeight: 1.5, borderColor: '#549688', @@ -116,7 +116,7 @@ export default { fontFamily: '微软雅黑, Microsoft YaHei', color: '#6a6d6c', fontSize: 14, - fontWeight: 'noraml', + fontWeight: 'normal', fontStyle: 'normal', lineHeight: 1.5, borderColor: 'transparent', @@ -138,7 +138,7 @@ export default { fontFamily: '微软雅黑, Microsoft YaHei', color: '#565656', fontSize: 16, - fontWeight: 'noraml', + fontWeight: 'normal', fontStyle: 'normal', lineHeight: 1.5, borderColor: '#549688', From 89d89f4dd8429d8ac0a5362a0520253f591e8f80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Wed, 28 Aug 2024 17:41:52 +0800 Subject: [PATCH 04/26] update --- README.md | 4 ++++ web/src/assets/avatar/封弊者.jpg | Bin 0 -> 50868 bytes 2 files changed, 4 insertions(+) create mode 100644 web/src/assets/avatar/封弊者.jpg diff --git a/README.md b/README.md index 8f40f711..1a45ddf6 100644 --- a/README.md +++ b/README.md @@ -457,4 +457,8 @@ const mindMap = new MindMap({ + + + 封弊者 +

diff --git a/web/src/assets/avatar/封弊者.jpg b/web/src/assets/avatar/封弊者.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5cc641cd3962ccd28d2b68e6c0b6867720f06fb6 GIT binary patch literal 50868 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�aC3OaF zXSt)<=oWacra?^N-W@W^7m0Ng%r}5zm5T&-hbcd5fbkyR)Z+fRY}7Dl(^V*)1>0G- z6HDL6;*vnI+#BhcX(Xvw!*l`5d z4MS1u41lc=-{BQSL4vPD8v%?L5DqITR7&J?>^3-l{FhFU*G7Q-2wPbuA=?U7 zilC;5`8oe}<iN?W_2-j@ma1YH+9U+3YyS1KU89wrGc6nSty`NU zvg(R-w~gbZnZXW<%5T$uFoGS(Us`R4HsqjO;%>~PuK0rcC3$Je-*IhaZsquXa1`_1 zrDOY%dOzqhn&`*8>u^VZ(k{fYA3O-gZyNcNXk~-?_hQ`DXyb(?m&~>ke!SX<{wI0m z(00U&OuLHW5fY9FVXKJ+t!hj#$ukr)4q_a3q{VnXK=&3TJfBZ+UZS*pL*lcl*mm@w zw=TiS7ffPHM3)O1U1+J$(s6RhZ#lxLgqt|l3IQ+9ifE6m4yZa%4B6DK-Q}(TlRIcm`hxUYV;=u8TcD} zO`=qX43E%?E-t1G$Bb7uK6h2F74%66vw(g=2>lsLl{j)JvG8Z1Nr}Spld4V0*YJn| z!ti~3ByFPzx(RMSmzUY|E3KUIF+?1tD$MbFw|eRdH)A|H44u^F*;*?K4<_ctZXWBb z%8$K!mj^+HtnI8qvbN=IX5eA@Rwf@P$n8o$#iay38Ag|+2A0xVJr=XC{_*k>M3~Z%>WQ!#3q7L#dWc1gLqY(m z`P=`uf(eCINTt*NU(-_C7EE%B973Zu6mKNXF%7Lq?-4dy?Y}?-xnDkd_31F+7tBHS zr#ZpCmcDcieynw`Nb1{)a}c{cX+!?a?yk&8svq5ux->Wh$fZjR9^5uQB1(&z2^F5{k85zM3_ycDGH8 zh>5jGdxwP%xyQYj+K&`u@MNWkGgJ_p0KR~>*eE;;_yX`VV3-BUMo8w$00o6ZW#qvh z=9}WRk`uc&Xy%7#pxYm#Shgpk_2Lbg`eej8whJX4tSpy_LhFryVdMTfEnm;W<|I`w zdhh=&Y3>sOq2H~I^9AAwR8RZu-n*7as4CnOwQORa#k{2oo8# z2JFM2-mi>Aa8F_=7pKDA0RaeDjkNVVH8ak5*4uCxV8bxLn(B~3D4-Lqtv%(oNV+mr z;f)Y=qPdH4e%&6r`(+V*TP#`jGT9!OUI0SL6gL_9z;2VeSF!*khC`c90dORg?Sa*| zO1bd1sGNv@ncBvg+3s4x?9ET^p>bA7g*Zbh;lGw)jfo_pw*2-#^`O@$9xF zOWe>x=cqMv>eg?*SuxpCXAjXvn!|GPKriK@Nz4UT+aJ%}whivuI|N$HIHW`J*H-P0 zf?xF7^Ce{B9df)Li0x$rw7OeQN6bh6SYcgheRe3cyMOww5RoP@RKXcFGB)%!z3@?$ z0ayxAo2^`3$)nYm>Yth_ajoPW}=Qv^R>By zO#+1(eQ3#csaKNG7v? z2e%#V+l@!!&5anA&Cj`kbcCnS2=DT&PWxR}9C?<^cDOWp5)0i$B1P-+MvFhj_QB>E zy#15}gm8%`5ZR#zPjKrWfI`;P=|qG_o``~~V6G&Paa#^WbZRTMpDwVesnFsg&^Yfq zSL#PnS@zR491)Z!Qqp=!f24lAaBudL?F zNsd~JEO!L^cQI#wooW$Lk_=+MP3%TQsU31=F!n>r|BJ}UlkdlPB|xmMf#ns}*iy)V zi8Iu~L7oQQE*rNl9s*^$6J5wsSL1J%1bMaWk5WDFZW1T{YOHIUIA+<UIrg&*})&DwW+@X4v7?&m-9! zQ*n#;^z5h%DYHBIT8>muT_a~9tA#X2tzs9w1sGdsHOPjJw@c4yM;U?DeQ?^v7jx9C znHY|3I14)x|pDG*_>Mrf3Y?N6ZF0x&Lwl7?c& z(FyfK*(Z=Jmg5d4^w@(2=V^alHg2KSAk_GigIuh?Q67r0- zqK!D&g!5q5xWtRRiu6jkl_Ug3Z&SJjmM;$xvcjT6xY2W2VVXIAEGA6PPy!oiX=k!~ zhS52%+~TiATC_q{SkP1l>0er%&TO=q_#b(=az+As@!i&+jHy?!YzeR&71*2My?&M? zH(cIf;+C}8koHisks+;c30C(XYJKz&>mmfEKoeUH`;JTlJ{AG^R`_sh#IOI#Zt;Lf z467rM>zseW1WjCqVq91G+YFZ8QVBa0E$h6u(_#CdkQQOS(n|D8&BB(%)Cxn>Z%sm< z5NXh(S)$fQN?A3|*9^~+k5$$)@Bo0p*6X2{NJHm?U9o3J&XH+}jat)y!Dj58u8(n} z`_wv-C!%*fU`{@{ogHi6+*cA}=$3z3i$vRU0Zo9`2vQf!HRk(x8$C%hEfKWaa}o0F z*tYp01lsNm;qd7`EV3mddrYjNbMw6FR9?(!`c7Jn+RM#vW6ttc=Zkl@hxnE~l5U@{ zUwl2AyVm*s&gEKm^cQL0>au8;FWkAjC#G!5{rv!*Rn)(+xr->vX}Me0)b8e@m2+1J zwM$kp#|RJfHw%DX0R?YuB}D*9kxYTk+lDi7DLZ1+D%|nNPLtI7bJDH3!um@UjD)ma zzwI`!YFkcmJAcWN>gzU05|{64`>r^g=w!z-iZf9OPkZLo8hKwyS>|UGn+f9n3d&L< z?52$v_-_#EVAm=jKqdo`*0#m0+EmGi!}nt#eP1z-cUL5HH!6_kGsSjv!#*x0ugRx3SN9E1tGFo180% zWO%kWyajFXR9jyghttn7QM~G8U&XR;A5$@X**iG91R8d%e#^tKs-X-FaJ)pMP^GwjHWI{eIM=7 zuNZOCw$JQZg~Q&N;$dt~MZo^^wlx-3J|%SelVasv$(a`ptN$y%`5zH+D2p$IJ=M?D zG*Fq_A{pM%kS2tI!%8wXjU#6u%>{yh2m(@%4;&yZgb`PNeDcgkip8z`;BDc0Ln>5^ zXwf(H27`g^?liT?TC=VPPgd4ioXwvmdD>i96}&<(cFBg|uAp#LIcbBH#8a+h<(;Is zk(3!K^kl^Xbq=!AP21DXX$l`ERo7?-8&$LV2(xwz?IzpURXGe{#p34@Lf3j3i^&3I z6GIG03WQzQgGCc{Py(C*L7%5-+QyGDKJE)!a5ud+k2G+wRJ8%P>AYs7DV_t+yGKkK zALLnKFMe*QVEdzFw*a}rmKS9)SwKcBGuwmiEMwS1@YIn(wy;i+AsC^Xl-oNPDdtdx zih!Cx1hA6E87-4sz|(}MAc$(I5dQ2DmUY?e<3abHGCRM=%{jKngLW zVgdzL7+aLXTrk}avVB-;P$cFdrW^JZ(A4L`&6GV!jUUjZj_!46Ebz7oGQihh12|N{ zEmKm1@zB`?_B_NH(#ky5;JlbaU9P)ZTamn_w6RYIPPzr+o;(uq&QNhyq-{yAF!<$fM9q+g7OD>?436L#-8|%zoH8Y?*AS60Bp@81T{e_Wh4}_2Y0% zbhBlKByg*#wnfueOk3yMEbjg_g1}t9s$)2`Bp>Sx2xSxP!lG1nQ$GO|G7fmnqIiK1 z_NeT%vR$FbK|O5>S943POFEcRWD;w5K34^cq_8P~Zn=hXVb7Bdq5{DGKZRr85k2>` ztaiflhDCEJt*F%qUhMR7LulW9PD<1!v`&QU_%j(i&0}lSItC|>dzhqEVG~q<)QyIv zbC0#NZp@IEbUl05HUjJN(%BSR1RT}>uq zhbbv`FvF1CTmzvFK7@|~AX@D~nkx_|Wk*GR9pr5xM2E6ft+72#bxPO~!BG-C0p(Nkjj7gc<4_Q@u@AE2 zE=b}t#2ULkyM%3(c>8PnM-zws5}+E!mEQz%Rk*)Dtx`~UK!Lb)@FnFJ%a7=G!|Oi? zUIvyd?*q5vaYu8`Y+|z_&HWgaUKOupC|_AI-?Fk!hcJ$3uwXC*urnoypqtH>Ezm5I zWf+9d3MDQ+R@~tmOM2NJ4#L5)J8^c-`0Oi9rpy!|h|*GUK6pvImvY8=v$Uv865o%G zgy0GCb;drXEf(pS-oa+7+-<#_O>M!@QC9aTdQ#6l{EtMn{m~Hy4++Q16vIF*uFs>c z7eKKF=1XLf_(8p*MrHZ=S>Y-b_)@D@PtxWqww@$rRUMt5c463{`n7yylI-lTj zeDY!sBvX-SzuHo{-LPR93(wxOGHiqhYOgMHEFzzg1#5WxHFINjApS3cpah$^Wj}-Q z^6qT76&Jza3w%KjgA5@#xe^Qc0+9DX>FX0@d@XGV876a6T~vP$!je}pDxqG^kG0uE zBNDxuPW8VH4Fh^0I7X;BUn}4=}4|85em(8;>XX1Vr zGApDZbE&MA2Af&7^aL$M_bJ7^lpZYkT@{14<=NVP|H6*cgUlti2yzf`ACjZ9^hTg( zh~qNT;)2U3BIiyP<1uV^B&ok|`{y(5yXt%0(pJ90Egi_NhjyLuf)1An*T(8?@3qS~ z+33_-2bF21r~<`hQWh09^18Tuu4`nSk=>#c_FE$<+FBB zRBO|uf!!V)+I9z3Z;Ku~|9rR&@nbMF0nTJn2c<#YKbXTutO&(15@Y5c#kF^vUPMm> zjbBM=9u#Eai`pz-9*?k^u1|SLNW?_Wx!K5RW<&{|g_JH+@xaEuLdg%5lT%U~EILl7 zZ60shXSkoLm&BpW-obMEf5rB+Dsn^`RunHVBoT7EyzNfcw8O#?08cXj`hcsjb4bfn z0O2xRi4vQO8Q2S+lGp;{d^d6B@t!0+@~G46bm1Ad<{aJ6-ebF7>=CMDMQVl&>}x|K zf;%KZ{}^%1>}+1kkagMtxD5NCtxuyaR`1Xw4XiC4=@yJLhB%2DhqEbW`kjT?u@XHZ zd#woHQa#RG?Zs2)N3MKoc;-x{e?sichO5^(Ge=7c425cO+3T_VbYD3g$$%ba6Jcs! zT5Km9x;c*KriQl68x=Z{ZZWTAo4d@-KCATO%w&uSMkXWQlzgs8LO_Og7pp8L)V1Xd z>sRQd@?+cFDf#TR=dW)_k)T|kby}r1GPF9Ev?yh{zGZ;m=hHw<=MbMI?Q$#I_)tj4i)3-YC@PuvV!)Om6o0&_au>PAl* z>q2}c?fm6mmLX!)mf$;#UDJi=;w#TwN@G*|<*$pXM5JyOmh!4zR&5wgsE0I)0raJNh>C%{rzB z*99gTsvTdnHm9|8=56Q~&O9Me%{QU_l2BjdHrPHFdW~77cM_N+>axBd=! zvja|jycu6UDV(Otnzz<8^w(|sKDrd2v7m2_WewS#HK)_gxb)1%t-VJncV1|EvF&AT zeata0TK9-g%&%K_lAX}mP9K`M?FsW8GxURY0V?On@u-V8?hyV(;F$v}J_e6mXnL{E zvV5#zYW+<3=cL-ZmB;e`9hO9BZ(#h{j0-b@ZjSdZ8D-$bX%$O!yjpe&G5fHHPcuP5 zxqL%GKcV%-(qoi^$BXRq z*HPP_Kdy^%l-hFwVS~|j=)U6mT1t;@TD@1>p$G6cCf>B9Pd=zhE$TDM?cPD{>D=a< zY?SsS?#Sc1xhSy~eh$rkMffmkUi1ThK#0x8NT53-uH(?!=+|yO`Rha$gR?Z$6Ylo$ zZqJr1!*7D}>74?<$=&bp9p*`j5BhFnKpV7U-#eAN<9zdMxU6}#KF`4|Th1nbs(`GEx!U~(+ZdoGe1*^5-Io<#xUuaSSdKrOATJvi`#E^&8?Nv3jbGd}WtAV5)^EtSAh}m~u(d6x< z7F{A=w=SFg$OWTid937)i@wlcu^>YOy{f{`w#UFm{|?!=#!9f;EO7GlYoRx_rz|t@ zR+q)m4n8;@m0Q3uCc{Us*^%=8}!{0*5mYc{<>i*_c zvPScY9MMPoLA>vUx1@p1oeobKlh3+xkmKbJl%B-BYRb%eCukwCziWG*=2d zS2R}hEnDoO>`x{oHgZ0hT(54`W8|<=)0u4Y-YRQ)a&*M4-qROJf?K1Ly}})WtLDk)TLQ+)F9tEcHUG)enm%93ZvQ)Z z&0e?5>)#Sh<`|_uMx~60jn%T{B9Hut7n?~fy1Q<6SrtWRvFqGCQ>*)r-81791^;1} zN0lO?8K!xdZKo_=;eKT{D&$7cnkzO(u)n%An`)5%N)TIf|L!xEy>wqCO5Lqa@7@%N zE;_olN}8C!TAovfZKjrye$iXv9rMEcoeNdF<%0}$raO|1zL*y)1uZJ(@MAyxv%tS& z>nVCfU5$8I!_+E4NCZ#gs-Ss@R$0Tc_#9VzmsSIPRS`$wNLn8CQz)?Q@$@?v(PV$?^$vYvJN+k&Di!anzVj`YPCiMXvV@+hRjAnE^QaqLRW5Ex9=F zvz{%pf=s(yf>19mD`@;ce~cb7!evxcPeC`=VH#rz_$20+kudY<`)K#LDmJ}aGv1v| z;f>taxBV6)-^smxL4~{4Z2Z8@3w7xa7&Dry0^)8J?J&Atz6hHb=VF96{-EgovPF_Ie(Mpc?8b(Wdm%iqS+~gd=BkcqX z{c)HE4ndf0;(z|*F_Haor%AzynA2f_yPCRg4wIZ+)?B{Q{6ZOB;)5PUP1i5$3bwUuU}d<3LI#_#HWJ_!EaD{L z)NxOYixjc`YE>k5GpH17Yz3C=WE;k!7U*rwSJ}HwWb=`nGrm#Wsj}86XP?vuRjQSm zUtu_!H)8T`{`bpqUQ&ll)ux*(!3Aw3Ooa{2GYSDT!+Rhl<{9&dj{+0<+UTC>WK)vs z{Y^CA+fDu6HO+HY3;fjsK0rzAQXjWk5X?b44r@XC^h@=;o#RnooBB62<2KFWXTm%} z8pR2k`|j5VC;O^-!m`?0jP3nbvXrj3YSuAWvS<`UYB3 za}FH!UK+OqrRGX8RCK#W&Z&#^H7iO=2!FN+LO@jzzT})pAE6n_j)XhV@na;Y&tm&X z#LviQO>>`~9Ybbg>)L-~d=(yq#@6T0CR)}};3ZsR9Fo7IpHCF)QgRP0wExQZD)=7Z z1BCs3>pw(U+b^PdX)4FV3{6u-8ZgkoEPqg-1 zrrS|I<*=DO^yKl2k(9*e53kwY5oJ#={Gcy8HxqFqn+MG%Uyb$35ByKu^z8>c-U6$! zQg*+`xf$|h=?u~M+gHA7-k9;GCEjv)1@Pv6+?xsM$@_iHmjPaqk%M|bPoAu16YY)k z?Sk;sz=9yz+wxvWb*IHX;!L>5jy$6rm0#_HraG;!WK7q8J?PbR%l+$On#U?p>cNh( zF3pYg3r#n@O=o6;78cI#+vxl;+#^!?O23{H8P|^Wj^y0Bwrc!w-$=3teBuPh9N0Kn zeRd9x@Hi(z{yx_Gu**Yadu1ohL4Dl{826I1`)AW-&`Rd~;?i*t|7BrM+{G``}X zPMXGlT+eNAO?=en*XA#K3|D!3RWie6R3F^l@coy~BJ-bT3ATo_C>GA{oOPTD`BJ+8 zgQ+p~@8PY9FeaaR!R@VrnW9tvkQV8eo%l!ZPTJ0KV?X+N)8&oVVO*^uzc~bL-a_7Z zB*M#*AN?J>Nbx(tseZ5EdrUz+d^Fs3vyGRCKb!d^`03m02jE;zyPwlH(da#Jft?S3 zr3LuB5$UV6xSkVPG#uQ1YVP$)kyZFg_=xYJITP%(toQ6rY1LSP)mH+1Q?#oNKBJEH zUVA-kFp});x~oxqYji0xeqt0s!=t>~64w7w?yc?MR#e?ub1vn3@_ z=8-G>(aC-&!6rB*dZdSWgfY9|&&V&u*wc)>;#1Jquwd6fMWR~($p`7x!`#;RZ2new zQ-6e$QMuSJAe6*9J*xvT3b-GH=wy?PKNu%>(r9D{gzHRb)eOm6A1CozXo4nIN}n=X zvW1fE`hFS4h2&_DzJ=|TtRzQ>6VQAKHab}gm}aEIFWG==p2uV=`FuZUI@(k2^8YHny6_uGFx^?*g)vOnFss?TMI$S{R|P zO~^)UR8TO9;4#Ms1u62U=|>od^ieV;6dS~V1NK-05lmV70HVLMDS*RDas(joz-R_u zv0PW&3qrFB32-;5!1o4mOeJeM7Z2cCn=Kzi0MKx(CD|<8+5*~-DOv8&@JZ>)0dypU z@MnDjPWF>GDJ}+d@n>a)p(KVYSz5}giYd`yO7{Rd@)4~0@}oQlm!9Tl1$TLWQ#3KQ ze)#@OyRFAEd6@aSkC7)bv%+`|76PmhXeApf31hNTY^lno#syrgqv$cU@4l~f-~2Xd}KLIFH=C8ATTkb_h`_0=bNoWh?N9t z?HkXQ9d7`xdV90evHrgQN9>mi)j>o^fv7CO)-5mFT!~2GbeZjV-Y|-bq;bv>t^upQ`9E1?s1_EAmrnb1Qg|d{?kG3{!I>s_W ztIE=<`!fkf0ptJ>ZgQxHxob}l6Ve?`D4C2W4&Jrc_QFy}RbBrK*aldmP7S`Lbm&Q! zX)Y4W?Vi`?=eBo-F4+$dlzY7`$syBjr|o>x%Tz6j5ydpbpk<)+4)%k-6*jiGtEv^Z zlw|p3@>o$ZhMXfGWwclxD=KQL;l`BFdo)QF&AgT@&0vN)fe!$&Z1c5M1auMaQ&3g_ zfknovF&=%4cwue5YOFrKbR-k1LNn}0X1t~*$=VYoPIPdu;e3inc-$*lhUCN)yMM6r zFRs3m3^bG6jz#*p8Jx40*Q^=F2~S-O@8Y8RU%X&D`RGQ+sjAAg!gMs6UXVf~KR@!o z`NmC6ILeNdNsg(GCf<27S(D)Y>fZFRB6j1Zyj_wj z!WigZajbe45Rj7;;klb@_WniPG(AgcP7j0kylrzf_h_*^?y-l7BJD|+4_gv_x9#?U zw8r#DyRoh38c9AyB^WNsjlN@&YxVO^0*!KR#dl+fXh2!~H}F48lk7tP$pQWMkllWH zgt{qnkO_LYa zrwC07SoZ5!YWRYoO;^3(F`qBh`?$WE(r$YD9Qo8erjtFkG_4{iJn0dmPWjB)^@_%* zwlAflzg=uN)!I|~(EgfP_=YU;WIb%iZCqvL`1Xmcan>XZ%alce&*6zW_(jrXrtHIZ z`wE_QwjX9l^WjCEdwfSkcI1?ae+c@b=T?!O^mTthhJN{#d1C9tnBaTh-%619v-@1B zV)bm&C@&-4gnjQyh0A2a&D)!|n^mvjTut87KDbC^FqwmZ0cp_v`F{tdo6@uFEXJzckW^&It2dNp@VkF%Xl$#RKcDA$Ih@(=v33V zyH4V1m~c=|TXMrBaWX%X-E*TQ>(K+JSeNb+(N&4#6=6;6uN*DviyzOQO&??5&KmcB zzkq!_AV1#KfxF}Rp5BviYTAl$*2-~nV6SiV6sG!14t6058Z~7l6s{BJZl}JNScHva zB^*md$_Z1SOWvRwsTgMWZC^do&D-T#>nm>7rAGNNZ%$Yw=0|)!TuOmy^(bTjf1svA z)a`x1$z;B{F2_!EAvwZ3<`k9_R#9P#=2eJmj-*? z;`I)6?&y`cI4)URFSpuYnnew=F8sW&wdZ}9qpntJd+3gDH|Is9lNxtt!nk`hPee@G z-B@0I&u#U)-6odPXXf@+U8y6Q!r_6|6+aYio^NYR6esS9Q@L?LJE|l;Ma3CWkKOEs zPVbIcox8T!u!XPj+&hb?UH#Z^F2?ZWDf2W@sD*Y{ubJX{s@*@$YIV4=WmZ`}%&kR_ zmgr;!PshLVjlFkpq;#8T8H&5!X`dQDZv0W+YMg0S82z9QWA*;%9tisyoz&7a{@gC_)G9D0 zhovJZ;WBo(#|!5_jv7`u@cV$BCBMFkdp>^bcn={F^UoWB&x!Gt$5j%iThES_vhedf zoxIozPu_Z|eLfN~k3~<4aufKU{}N={=N^b!c8&H};*e5Vlu3@_i@8FH?0%69kG|}+pKVUT6b(%Hl^niQ|mA2 zd$nI2ib=*CPs&;DL|0iq6!y=3((2&mheO#hua++Rb}8P6f*{#PhhFPJ)f-GVTw&Q+ z_ib~_wAa$2pcre7ob>hAy|Qe{U%K2cezg{5=c@u@f_(R}lulvMhD+R2Sre7aHLHF1 z0PMIKv+Ek;`!6D!`GIUo^7%oY!}>WLMV5f4A0Qo=k zLu(24Pd->Zyzy#!;i=u?Mh~0FifYfg+wxulOXTAXr&dtAEw!qsIN`Tn;ORS9`cksE z+bs(ue(ATjnJfC#$5`3r%mMk7E(4i(L=wL}XLCJw_=W(_P2PGe zbuooGzwMqu+q$5JsbRFC)w78s%gNcOd);Sq6NI_@2#2TlJ}wHuCT-~Gtm8k*BI>Dm z_G9HeqpZWF$@4r7mw>m@@a~FpOtl#M2gDYW^8$w>CeV5mQ_%Du>Y_*7Hwa+?!&5^j$7c| z$1}!>u4SCvLcN{^Nu}}XjHd~mhEVvF#H0yUaHA*7QsdQZm8*+CASV6fG`{f#Kfbpy0_!E*)_C_%> z<{SanVeHkigNHd2?uqZPVB`#|1~38@b&%^b5@kDDfUJU+_+ZoOwGlSAD0ZnFw>6o3 z)MQmUNbkXLEl~WAY=N)pDZyFL;QrTh!(w`X1Li(*UU91R2|izs7T#r%67&)n9lsx) zto~?K+$8J{`?qrDMsZgd^$x1(R>7FasOWJN@EZymyRf3E(#h(rL4M2~ zR+!DMhZOujb(r^^WIA~{eQxDJe^Hj%us3Tr?g^l<#bw;Wi=(oyinztr9u?rUT?lhprc(9S zro&J~SzH|fy3q#<6|A(W5o9-{%QlDW+VHk0=U##UKfg3sqkH6HLvXmWVLlO-2R0&O zBmy)QFMt@~U19CB$Gfh$(DZF49=P-5M6kq(u+_cBC{*Kh*}OZEPfpZIt=ePUYA}F^ zSywtK$YA;+@A6bFD=1)AWDr0o%!>FJzPIAwNSNA*{4hz7mY^5shp^yhfS^;VV%#@& z7z7QdGBH9JP)aG7iQX|?pO9Y~WwD|mo~=(xi5XWcD+&M9CsVsks4Sj_ z`-zaL!@EW|W9#^;Da5y-56Kmn92ge1evAoqW^KCDIO15kft$PS1Q$`vuG;D}geb1z z+k<@>q6xhA5adikT}x^O5V+nU0!TkqMu{MZ4CYHhK>w%u3;sq{B;SUm1zkH*E5OQ? z9mNoHz@v2f%u@gWPVF&%XR44+9z!MrW01IMC3~Y{Ae5Uzcmi^>90riKZbN^!EBdwO z)U_0&X*ZOjfpLqwk<(v_u?xh5)f0km9+edg(^5PV3Wma;0w7%`%))O;W$z`Y<-+zG zP6U3wVCI)>jgVgebF;*eD^*w?MOW~U8P+SfBUl4o)@JyAS@Ik1A+!pH1_pUxHkt)w zQihnao96%)9j$NanwapQaBpx5J1M-_p~J`u`AF2#vzue@`ilyvdq56$g7nx%gldIH@i&;sE9uPSLr8rCC8?#M~gF#g7@r~Kf z=pX*6UgRJqnfj-;MN_Fpgq>IMMeN_04q5Dry(!$CRl0t5VY3EcegK+3$8aea61au{ z-D{F$Xu$6$oT4K=<|5Mun}*7H8{ z3YXR_HI%~c1+1Z?LChot-ceeW)ivw@0w`}o&0Xf{io+}B+Yr&iQO*GV_bYWUGNVJD z!U`9Ov+m@nAQ>ZPvO?=EcUQH<2Uw1e#Qn)xjn%e~?g%_m^C+__;0AU_u=1r+X#hrp z{8w0|8zc@0psv{Wl#yUn0dT&7?zEDOa0wyPILX5*-ovC-c{D^hHnjoBUp4uW5;*o9 zlnRET$s`Mq$ma(ElMd{8Q^ECay0Vl?M}^53DJ@kNNB6lIqlB!9+*X?_69d|aP;MYo zyz8V-%#*J|7fq9xls|LZF1m!dbWo7Obqf+tZ?grx%Mp|1<~c&ui6W=>qnSnFWTeD- zMH3)n>;E0O#LaB|3K2S+Tg3+B6K2jkRnK~PFkfm4o!&#LBCM`iBg~~v(@Bb6iOsG& z3i4*!Jnxd5x*0HdbyY|RE-*q7EdV?%mSEwZ7K9g!9)VI<4OXCSoTX7lC$`+dYUCzj zj@(DgQ7&zX^+Kk)5cO}N@Oxu-58|xNR}3)tliUQE3Q^~2IBx_zN29})ZhF2HYMyMK zml6)J^=VGCvPN)~GDx8&ivtUQ?IAT$R)MF3Aczs@J!T9MAqOKvZc50%YG6Q)F{Lf=` z7y~0)4B8RlUJpIJ^2_)S@N|j!Qjq}=V=+)bLSPG{BT+1Kd&(+uF7^~%_g160sgYy@ zy5n~)5fa4eQtqMgoN?U}FEHXC$M=z(E$#~1FfyaH#zAyw4Fn=_F7h_5)N6p(_2}a^~(z^|#R+sj&-jQG{A)Dg>7WA;{QU@1@l(o_JO|d9rvW zq<#-?5wz26equWaQmY)deeMgy@m zoG`^#`67EEW781CF7pU{lhD)_rF~VV$KE#+&QyBA!Y@A^)&f*7V8)tHSDqek1|@xw zwGvQFZ3y5YQjbrb3javdSxMj=iy$DLKzDLbh%<8JMIb4ou(eTjn&2l&MljSx22xMi zsytOkgC;QO08@_$0Z$Fxk_y+RWB;L&{PQ&!E@TEBrVs;)bw5a7c7sl23w5gplz{5b&q1U~mh?sK%v^Pxza`SAo)@ zqs38hcLU?b$)D_I%ad%5VmB*{N>*?<2$@T`)UVwx+4DsBn=Z9#214El!^%xFOa;Y> zCi2i$gmlQ5Tp)XT7Z9vE5rm)TAQ~81N^HjvEM{QLO-0HZ6`3;+NC literal 0 HcmV?d00001 From 4e327c3a484375b3c16cb056ea510e30492faf0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Thu, 29 Aug 2024 10:30:52 +0800 Subject: [PATCH 05/26] =?UTF-8?q?Feat=EF=BC=9A=E6=A0=BC=E5=BC=8F=E5=88=B7?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=B7=E8=8A=82=E7=82=B9=E6=89=80=E6=9C=89?= =?UTF-8?q?=E7=94=9F=E6=95=88=E7=9A=84=E6=A0=B7=E5=BC=8F=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=E6=9D=A5=E8=87=AA=E4=B8=BB=E9=A2=98=E7=9A=84=E5=92=8C?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/constants/defaultOptions.js | 6 +- .../src/core/render/node/MindMapNode.js | 2 + simple-mind-map/src/core/render/node/Style.js | 132 ++++++++++++++---- simple-mind-map/src/plugins/Painter.js | 13 +- 4 files changed, 117 insertions(+), 36 deletions(-) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 5da7c1c6..1e9ec431 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -409,5 +409,9 @@ export const defaultOpt = { // 【OuterFrame】插件 outerFramePaddingX: 10, - outerFramePaddingY: 10 + outerFramePaddingY: 10, + + // 【Painter】插件 + // 是否只格式刷节点手动设置的样式,不考虑节点通过主题的应用的样式 + onlyPainterNodeCustomStyles: false } diff --git a/simple-mind-map/src/core/render/node/MindMapNode.js b/simple-mind-map/src/core/render/node/MindMapNode.js index 5b3c7174..b1654cd3 100644 --- a/simple-mind-map/src/core/render/node/MindMapNode.js +++ b/simple-mind-map/src/core/render/node/MindMapNode.js @@ -34,6 +34,8 @@ class MindMapNode { this.lineDraw = this.mindMap.lineDraw // 样式实例 this.style = new Style(this) + // 节点当前生效的全部样式 + this.effectiveStyles = {} // 形状实例 this.shapeInstance = new Shape(this) this.shapePadding = { diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index 1248fbb7..f466a503 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -85,7 +85,14 @@ class Style { // 获取某个样式值 getStyle(prop, root) { - return this.merge(prop, root) + const value = this.merge(prop, root) + if (!root) { + const styles = { + [prop]: value + } + this.addToEffectiveStyles(styles) + } + return value } // 获取自身自定义样式 @@ -93,26 +100,47 @@ class Style { return this.ctx.getData(prop) } + // 更新当前节点生效的样式数据 + addToEffectiveStyles(styles) { + this.ctx.effectiveStyles = { + ...this.ctx.effectiveStyles, + ...styles + } + } + // 矩形 rect(node) { this.shape(node) - node.radius(this.merge('borderRadius')) + const styles = { + borderRadius: this.merge('borderRadius') + } + this.addToEffectiveStyles(styles) + node.radius(styles.borderRadius) } // 形状 shape(node) { - if (this.merge('gradientStyle')) { + const styles = { + gradientStyle: this.merge('gradientStyle'), + startColor: this.merge('startColor'), + endColor: this.merge('endColor'), + fillColor: this.merge('fillColor'), + borderColor: this.merge('borderColor'), + borderWidth: this.merge('borderWidth'), + borderDasharray: this.merge('borderDasharray') + } + if (styles.gradientStyle) { if (!this._gradient) { this._gradient = this.ctx.nodeDraw.gradient('linear') } this._gradient.update(add => { - add.stop(0, this.merge('startColor')) - add.stop(1, this.merge('endColor')) + add.stop(0, styles.startColor) + add.stop(1, styles.endColor) }) node.fill(this._gradient) } else { node.fill({ - color: this.merge('fillColor') + color: styles.fillColor }) } // 节点使用横线样式,不需要渲染非激活状态的边框样式 @@ -125,56 +153,94 @@ class Style { // return // } node.stroke({ - color: this.merge('borderColor'), - width: this.merge('borderWidth'), - dasharray: this.merge('borderDasharray') + color: styles.borderColor, + width: styles.borderWidth, + dasharray: styles.borderDasharray }) + this.addToEffectiveStyles(styles) } // 文字 text(node) { + const styles = { + color: this.merge('color'), + fontFamily: this.merge('fontFamily'), + fontSize: this.merge('fontSize'), + fontWeight: this.merge('fontWeight'), + fontStyle: this.merge('fontStyle'), + textDecoration: this.merge('textDecoration') + } node .fill({ - color: this.merge('color') + color: styles.color }) .css({ - 'font-family': this.merge('fontFamily'), - 'font-size': this.merge('fontSize'), - 'font-weight': this.merge('fontWeight'), - 'font-style': this.merge('fontStyle'), - 'text-decoration': this.merge('textDecoration') + 'font-family': styles.fontFamily, + 'font-size': styles.fontSize, + 'font-weight': styles.fontWeight, + 'font-style': styles.fontStyle, + 'text-decoration': styles.textDecoration }) + this.addToEffectiveStyles(styles) } // 生成内联样式 createStyleText() { + const styles = { + color: this.merge('color'), + fontFamily: this.merge('fontFamily'), + fontSize: this.merge('fontSize'), + fontWeight: this.merge('fontWeight'), + fontStyle: this.merge('fontStyle'), + textDecoration: this.merge('textDecoration') + } + this.addToEffectiveStyles(styles) return ` - color: ${this.merge('color')}; - font-family: ${this.merge('fontFamily')}; - font-size: ${this.merge('fontSize') + 'px'}; - font-weight: ${this.merge('fontWeight')}; - font-style: ${this.merge('fontStyle')}; - text-decoration: ${this.merge('textDecoration')} + color: ${styles.color}; + font-family: ${styles.fontFamily}; + font-size: ${styles.fontSize + 'px'}; + font-weight: ${styles.fontWeight}; + font-style: ${styles.fontStyle}; + text-decoration: ${styles.textDecoration} ` } // 获取文本样式 getTextFontStyle() { - return { - italic: this.merge('fontStyle') === 'italic', - bold: this.merge('fontWeight'), + const styles = { + color: this.merge('color'), + fontFamily: this.merge('fontFamily'), fontSize: this.merge('fontSize'), - fontFamily: this.merge('fontFamily') + fontWeight: this.merge('fontWeight'), + fontStyle: this.merge('fontStyle'), + textDecoration: this.merge('textDecoration') + } + this.addToEffectiveStyles(styles) + return { + italic: styles.fontStyle === 'italic', + bold: styles.fontWeight, + fontSize: styles.fontSize, + fontFamily: styles.fontFamily } } // html文字节点 domText(node, fontSizeScale = 1, isMultiLine) { - node.style.fontFamily = this.merge('fontFamily') - node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px' - node.style.fontWeight = this.merge('fontWeight') || 'normal' - node.style.lineHeight = !isMultiLine ? 'normal' : this.merge('lineHeight') - node.style.fontStyle = this.merge('fontStyle') + const styles = { + color: this.merge('color'), + fontFamily: this.merge('fontFamily'), + fontSize: this.merge('fontSize'), + fontWeight: this.merge('fontWeight'), + fontStyle: this.merge('fontStyle'), + textDecoration: this.merge('textDecoration'), + lineHeight: this.merge('lineHeight') + } + this.addToEffectiveStyles(styles) + node.style.fontFamily = styles.fontFamily + node.style.fontSize = styles.fontSize * fontSizeScale + 'px' + node.style.fontWeight = styles.fontWeight || 'normal' + node.style.lineHeight = !isMultiLine ? 'normal' : styles.lineHeight + node.style.fontStyle = styles.fontStyle } // 标签文字 @@ -200,8 +266,12 @@ class Style { // 内置图标 iconNode(node) { + const styles = { + color: this.merge('color') + } + this.addToEffectiveStyles(styles) node.attr({ - fill: this.merge('color') + fill: styles.color }) } diff --git a/simple-mind-map/src/plugins/Painter.js b/simple-mind-map/src/plugins/Painter.js index 8dcf90e8..3b7be755 100644 --- a/simple-mind-map/src/plugins/Painter.js +++ b/simple-mind-map/src/plugins/Painter.js @@ -53,17 +53,22 @@ class Painter { node.uid === this.painterNode.uid ) return - const style = {} + let style = {} + // 格式刷节点所有生效的样式 + if (!this.mindMap.opt.onlyPainterNodeCustomStyles) { + style = { + ...this.painterNode.effectiveStyles + } + } const painterNodeData = this.painterNode.getData() Object.keys(painterNodeData).forEach(key => { if (checkIsNodeStyleDataKey(key)) { style[key] = painterNodeData[key] } }) + // 先去除目标节点的样式 + this.mindMap.renderer._handleRemoveCustomStyles(node.getData()) node.setStyles(style) - if (painterNodeData.activeStyle) { - node.setStyles(painterNodeData.activeStyle, true) - } } // 插件被移除前做的事情 From 570bbb1b162ede607989b9e8b0d1bfc66a80ec7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Thu, 29 Aug 2024 15:33:38 +0800 Subject: [PATCH 06/26] =?UTF-8?q?Feat=EF=BC=9A=E6=96=B0=E5=A2=9E=E5=BC=80?= =?UTF-8?q?=E5=90=AF=E8=8A=82=E7=82=B9=E6=96=87=E6=9C=AC=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=9B=B4=E6=96=B0=E8=8A=82=E7=82=B9=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=92=8C=E4=BD=8D=E7=BD=AE=E7=9A=84=E5=AE=9E=E4=BE=8B?= =?UTF-8?q?=E5=8C=96=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/constants/defaultOptions.js | 4 ++ simple-mind-map/src/core/render/Render.js | 13 +++++++ simple-mind-map/src/core/render/TextEdit.js | 35 +++++++++++++++-- .../core/render/node/nodeCreateContents.js | 31 ++++++++++----- simple-mind-map/src/plugins/RichText.js | 38 ++++++++++++++++++- 5 files changed, 106 insertions(+), 15 deletions(-) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 1e9ec431..886b914d 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -238,6 +238,10 @@ export const defaultOpt = { padding: 100, // 超出画布四周指定范围内依旧渲染节点 removeNodeWhenOutCanvas: true // 节点移除画布可视区域后从画布删除 }, + // 如果节点文本为空,那么为了避免空白节点高度塌陷,会用该字段指定的文本测量一个高度 + emptyTextMeasureHeightText: 'abc123我和你', + // 是否在进行节点文本编辑时实时更新节点大小和节点位置,开启后当节点数量比较多时可能会造成卡顿 + openRealtimeRenderOnNodeTextEdit: false, // 【Select插件】 // 多选节点时鼠标移动到边缘时的画布移动偏移量 diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js index ec2bf3b8..605313a5 100644 --- a/simple-mind-map/src/core/render/Render.js +++ b/simple-mind-map/src/core/render/Render.js @@ -147,6 +147,19 @@ class Render { }) // 性能模式 this.performanceMode() + // 实时渲染当节点文本编辑时 + if (this.mindMap.opt.openRealtimeRenderOnNodeTextEdit) { + this.mindMap.on('node_text_edit_change', ({ node, text }) => { + node._textData = node.createTextNode(text) + const { width, height } = node.getNodeRect() + node.width = width + node.height = height + node.layout() + this.mindMap.render(() => { + this.textEdit.updateTextEditNode() + }) + }) + } } // 性能模式,懒加载节点 diff --git a/simple-mind-map/src/core/render/TextEdit.js b/simple-mind-map/src/core/render/TextEdit.js index ed70863b..6aa334bd 100644 --- a/simple-mind-map/src/core/render/TextEdit.js +++ b/simple-mind-map/src/core/render/TextEdit.js @@ -25,6 +25,8 @@ export default class TextEdit { // 如果编辑过程中缩放画布了,那么缓存当前编辑的内容 this.cacheEditingText = '' this.hasBodyMousedown = false + this.textNodePaddingX = 5 + this.textNodePaddingY = 3 this.bindEvent() } @@ -214,7 +216,7 @@ export default class TextEdit { this.registerTmpShortcut() if (!this.textEditNode) { this.textEditNode = document.createElement('div') - this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;` + this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: ${this.textNodePaddingY}px ${this.textNodePaddingX}px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;` this.textEditNode.setAttribute('contenteditable', true) this.textEditNode.addEventListener('keyup', e => { e.stopPropagation() @@ -240,6 +242,13 @@ export default class TextEdit { handleInputPasteText(e) } }) + this.textEditNode.addEventListener('input', () => { + this.mindMap.emit('node_text_edit_change', { + node: this.currentNode, + text: this.getEditText(), + richText: false + }) + }) const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body targetNode.appendChild(this.textEditNode) @@ -256,8 +265,10 @@ export default class TextEdit { node.style.domText(this.textEditNode, scale, isMultiLine) this.textEditNode.style.zIndex = nodeTextEditZIndex this.textEditNode.innerHTML = textLines.join('
') - this.textEditNode.style.minWidth = rect.width + 10 + 'px' - this.textEditNode.style.minHeight = rect.height + 6 + 'px' + this.textEditNode.style.minWidth = + rect.width + this.textNodePaddingX * 2 + 'px' + this.textEditNode.style.minHeight = + rect.height + this.textNodePaddingY * 2 + 'px' this.textEditNode.style.left = rect.left + 'px' this.textEditNode.style.top = rect.top + 'px' this.textEditNode.style.display = 'block' @@ -280,6 +291,24 @@ export default class TextEdit { this.cacheEditingText = '' } + // 更新文本编辑框的大小和位置 + updateTextEditNode() { + if (this.mindMap.richText) { + this.mindMap.richText.updateTextEditNode() + return + } + if (!this.showTextEdit || !this.currentNode) { + return + } + const rect = this.currentNode._textData.node.node.getBoundingClientRect() + this.textEditNode.style.minWidth = + rect.width + this.textNodePaddingX * 2 + 'px' + this.textEditNode.style.minHeight = + rect.height + this.textNodePaddingY * 2 + 'px' + this.textEditNode.style.left = rect.left + 'px' + this.textEditNode.style.top = rect.top + 'px' + } + // 删除文本编辑元素 removeTextEditEl() { if (this.mindMap.richText) { diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index a2c0ec6e..5bc5b2a9 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -114,8 +114,10 @@ function createIconNode() { } // 创建富文本节点 -function createRichTextNode() { - const { textAutoWrapWidth } = this.mindMap.opt +function createRichTextNode(specifyText) { + let text = + typeof specifyText === 'string' ? specifyText : this.getData('text') + const { textAutoWrapWidth, emptyTextMeasureHeightText } = this.mindMap.opt let g = new G() // 重新设置富文本节点内容 let recoverText = false @@ -129,7 +131,6 @@ function createRichTextNode() { recoverText = true } } - let text = this.getData('text') if (recoverText && !isUndef(text)) { // 判断节点内容是否是富文本 let isRichText = checkIsRichText(text) @@ -153,7 +154,7 @@ function createRichTextNode() { text: text }) } - let html = `
${this.getData('text')}
` + let html = `
${text}
` if (!this.mindMap.commonCaches.measureRichtextNodeTextSizeEl) { this.mindMap.commonCaches.measureRichtextNodeTextSizeEl = document.createElement('div') @@ -174,7 +175,7 @@ function createRichTextNode() { let { width, height } = el.getBoundingClientRect() // 如果文本为空,那么需要计算一个默认高度 if (height <= 0) { - div.innerHTML = '

abc123我和你

' + div.innerHTML = `

${emptyTextMeasureHeightText}

` let elTmp = div.children[0] elTmp.classList.add('smm-richtext-node-wrap') height = elTmp.getBoundingClientRect().height @@ -199,10 +200,12 @@ function createRichTextNode() { } // 创建文本节点 -function createTextNode() { +function createTextNode(specifyText) { if (this.getData('richText')) { - return this.createRichTextNode() + return this.createRichTextNode(specifyText) } + const text = + typeof specifyText === 'string' ? specifyText : this.getData('text') if (this.getData('resetRichText')) { delete this.nodeData.data.resetRichText } @@ -212,10 +215,11 @@ function createTextNode() { // 文本超长自动换行 let textStyle = this.style.getTextFontStyle() let textArr = [] - if (!isUndef(this.getData('text'))) { - textArr = String(this.getData('text')).split(/\n/gim) + if (!isUndef(text)) { + textArr = String(text).split(/\n/gim) } - let maxWidth = this.mindMap.opt.textAutoWrapWidth + const { textAutoWrapWidth: maxWidth, emptyTextMeasureHeightText } = + this.mindMap.opt let isMultiLine = false textArr.forEach((item, index) => { let arr = item.split('') @@ -247,6 +251,13 @@ function createTextNode() { g.add(node) }) let { width, height } = g.bbox() + // 如果文本为空,那么需要计算一个默认高度 + if (height <= 0) { + const tmpNode = new Text().text(emptyTextMeasureHeightText) + this.style.text(tmpNode) + const tmpBbox = tmpNode.bbox() + height = tmpBbox.height + } width = Math.min(Math.ceil(width), maxWidth) height = Math.ceil(height) g.attr('data-width', width) diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index b8cfb584..765d76cd 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -57,6 +57,8 @@ class RichText { this.cacheEditingText = '' this.lostStyle = false this.isCompositing = false + this.textNodePaddingX = 6 + this.textNodePaddingY = 4 this.initOpt() this.extendQuill() this.appendCss() @@ -71,14 +73,17 @@ class RichText { // 绑定事件 bindEvent() { this.onCompositionStart = this.onCompositionStart.bind(this) + this.onCompositionUpdate = this.onCompositionUpdate.bind(this) this.onCompositionEnd = this.onCompositionEnd.bind(this) window.addEventListener('compositionstart', this.onCompositionStart) + window.addEventListener('compositionupdate', this.onCompositionUpdate) window.addEventListener('compositionend', this.onCompositionEnd) } // 解绑事件 unbindEvent() { window.removeEventListener('compositionstart', this.onCompositionStart) + window.removeEventListener('compositionupdate', this.onCompositionUpdate) window.removeEventListener('compositionend', this.onCompositionEnd) } @@ -198,8 +203,8 @@ class RichText { let scaleX = rect.width / originWidth let scaleY = rect.height / originHeight // 内边距 - let paddingX = 6 - let paddingY = 4 + let paddingX = this.textNodePaddingX + let paddingY = this.textNodePaddingY if (richTextEditFakeInPlace) { let paddingValue = node.getPaddingVale() paddingX = paddingValue.paddingX @@ -287,6 +292,20 @@ class RichText { this.cacheEditingText = '' } + // 更新文本编辑框的大小和位置 + updateTextEditNode() { + if (!this.node) return + const rect = this.node._textData.node.node.getBoundingClientRect() + const g = this.node._textData.node + const originWidth = g.attr('data-width') + const originHeight = g.attr('data-height') + this.textEditNode.style.minWidth = + originWidth + this.textNodePaddingX * 2 + 'px' + this.textEditNode.style.minHeight = originHeight + 'px' + this.textEditNode.style.left = rect.left + 'px' + this.textEditNode.style.top = rect.top + 'px' + } + // 删除文本编辑框元素 removeTextEditEl() { if (!this.textEditNode) return @@ -491,6 +510,11 @@ class RichText { this.setTextStyleIfNotRichText(this.node) this.lostStyle = false } + this.mindMap.emit('node_text_edit_change', { + node: this.node, + text: this.getEditText(), + richText: true + }) }) // 拦截粘贴,只允许粘贴纯文本 // this.quill.clipboard.addMatcher(Node.TEXT_NODE, node => { @@ -545,6 +569,16 @@ class RichText { this.isCompositing = true } + // 中文输入中 + onCompositionUpdate() { + if (!this.showTextEdit || !this.node) return + this.mindMap.emit('node_text_edit_change', { + node: this.node, + text: this.getEditText(), + richText: true + }) + } + // 中文输入结束 onCompositionEnd() { if (!this.showTextEdit) { From fa8a80792d522a4fa15d86f641e01f278df56fdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Thu, 29 Aug 2024 17:48:03 +0800 Subject: [PATCH 07/26] =?UTF-8?q?Feat=EF=BC=9A=E4=B8=BB=E9=A2=98=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E9=85=8D=E7=BD=AE=E8=83=8C=E6=99=AF=E6=B8=90=E5=8F=98?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/node/Style.js | 3 +++ simple-mind-map/src/themes/default.js | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index f466a503..a4663764 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -124,6 +124,8 @@ class Style { gradientStyle: this.merge('gradientStyle'), startColor: this.merge('startColor'), endColor: this.merge('endColor'), + startDir: this.merge('startDir'), + endDir: this.merge('endDir'), fillColor: this.merge('fillColor'), borderColor: this.merge('borderColor'), borderWidth: this.merge('borderWidth'), @@ -137,6 +139,7 @@ class Style { add.stop(0, styles.startColor) add.stop(1, styles.endColor) }) + this._gradient.from(...styles.startDir).to(...styles.endDir) node.fill(this._gradient) } else { node.fill({ diff --git a/simple-mind-map/src/themes/default.js b/simple-mind-map/src/themes/default.js index 4960f04a..d32049e4 100644 --- a/simple-mind-map/src/themes/default.js +++ b/simple-mind-map/src/themes/default.js @@ -82,6 +82,8 @@ export default { gradientStyle: false, startColor: '#549688', endColor: '#fff', + startDir: [0, 0], + endDir: [1, 0], // 连线标记的位置,start(头部)、end(尾部),该配置在showLineMarker配置为true时生效 lineMarkerDir: 'end' }, @@ -105,6 +107,8 @@ export default { gradientStyle: false, startColor: '#549688', endColor: '#fff', + startDir: [0, 0], + endDir: [1, 0], lineMarkerDir: 'end' }, // 三级及以下节点样式 @@ -127,6 +131,8 @@ export default { gradientStyle: false, startColor: '#549688', endColor: '#fff', + startDir: [0, 0], + endDir: [1, 0], lineMarkerDir: 'end' }, // 概要节点样式 @@ -148,7 +154,9 @@ export default { textDecoration: 'none', gradientStyle: false, startColor: '#549688', - endColor: '#fff' + endColor: '#fff', + startDir: [0, 0], + endDir: [1, 0] } } @@ -179,7 +187,9 @@ const nodeSizeIndependenceList = [ 'gradientStyle', 'lineRadius', 'startColor', - 'endColor' + 'endColor', + 'startDir', + 'endDir' ] export const checkIsNodeSizeIndependenceConfig = config => { let keys = Object.keys(config) From 06fb6245b772128772380f84d67621e4ec2f9c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Thu, 29 Aug 2024 18:29:04 +0800 Subject: [PATCH 08/26] =?UTF-8?q?Demo=EF=BC=9A=E6=94=AF=E6=8C=81=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E8=8A=82=E7=82=B9=E8=83=8C=E6=99=AF=E6=B8=90=E5=8F=98?= =?UTF-8?q?=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/config/en.js | 52 +++++++++++++++++ web/src/config/index.js | 14 ++++- web/src/config/zh.js | 52 +++++++++++++++++ web/src/lang/en_us.js | 3 +- web/src/lang/zh_cn.js | 3 +- web/src/pages/Edit/components/Style.vue | 75 +++++++++++++++++++++---- 6 files changed, 184 insertions(+), 15 deletions(-) diff --git a/web/src/config/en.js b/web/src/config/en.js index 5a5f0968..8ab141a5 100644 --- a/web/src/config/en.js +++ b/web/src/config/en.js @@ -557,3 +557,55 @@ export const numberLevelList = [ value: 0 } ] + +// 背景渐变方向 +export const linearGradientDirList = [ + { + name: 'Left to right', + value: '1', + start: [0, 0], + end: [1, 0] + }, + { + name: 'Right to left', + value: '2', + start: [1, 0], + end: [0, 0] + }, + { + name: 'Top to bottom', + value: '3', + start: [0, 0], + end: [0, 1] + }, + { + name: 'Bottom to top', + value: '4', + start: [0, 1], + end: [0, 0] + }, + { + name: 'Left top to right bottom', + value: '5', + start: [0, 0], + end: [1, 1] + }, + { + name: 'Left bottom to right top', + value: '6', + start: [0, 1], + end: [1, 0] + }, + { + name: 'Right top to left bottom', + value: '7', + start: [1, 0], + end: [0, 1] + }, + { + name: 'Right bottom to left top', + value: '8', + start: [1, 1], + end: [0, 0] + } +] diff --git a/web/src/config/index.js b/web/src/config/index.js index 32affc86..b8ceff17 100644 --- a/web/src/config/index.js +++ b/web/src/config/index.js @@ -21,7 +21,8 @@ import { shapeListMap as shapeListMapZh, lineStyleMap as lineStyleMapZh, numberTypeList as numberTypeListZh, - numberLevelList as numberLevelListZh + numberLevelList as numberLevelListZh, + linearGradientDirList as linearGradientDirListZh } from './zh' import { fontFamilyList as fontFamilyListEn, @@ -36,7 +37,8 @@ import { backgroundSizeList as backgroundSizeListEn, downTypeList as downTypeListEn, numberTypeList as numberTypeListEn, - numberLevelList as numberLevelListEn + numberLevelList as numberLevelListEn, + linearGradientDirList as linearGradientDirListEn } from './en' const fontFamilyList = { @@ -114,6 +116,11 @@ const numberLevelList = { en: numberLevelListEn } +const linearGradientDirList = { + zh: linearGradientDirListZh, + en: linearGradientDirListEn +} + export { fontSizeList, lineHeightList, @@ -137,5 +144,6 @@ export { sidebarTriggerList, downTypeList, numberTypeList, - numberLevelList + numberLevelList, + linearGradientDirList } diff --git a/web/src/config/zh.js b/web/src/config/zh.js index 3985d124..9b24c5c1 100644 --- a/web/src/config/zh.js +++ b/web/src/config/zh.js @@ -651,3 +651,55 @@ export const numberLevelList = [ value: 0 } ] + +// 背景渐变方向 +export const linearGradientDirList = [ + { + name: '从左到右', + value: '1', + start: [0, 0], + end: [1, 0] + }, + { + name: '从右到左', + value: '2', + start: [1, 0], + end: [0, 0] + }, + { + name: '从上到下', + value: '3', + start: [0, 0], + end: [0, 1] + }, + { + name: '从下到上', + value: '4', + start: [0, 1], + end: [0, 0] + }, + { + name: '从左上到右下', + value: '5', + start: [0, 0], + end: [1, 1] + }, + { + name: '从左下到右上', + value: '6', + start: [0, 1], + end: [1, 0] + }, + { + name: '从右上到左下', + value: '7', + start: [1, 0], + end: [0, 1] + }, + { + name: '从右下到左上', + value: '8', + start: [1, 1], + end: [0, 0] + } +] diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index d313a98e..f4f4917e 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -238,7 +238,8 @@ export default { endColor: 'End', arrowDir: 'Arrow dir', arrowDirStart: 'Start', - arrowDirEnd: 'End' + arrowDirEnd: 'End', + direction: 'Direction' }, theme: { title: 'Theme', diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index cb351c11..e7b71a59 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -236,7 +236,8 @@ export default { endColor: '结束', arrowDir: '箭头位置', arrowDirStart: '头部', - arrowDirEnd: '尾部' + arrowDirEnd: '尾部', + direction: '方向' }, theme: { title: '主题', diff --git a/web/src/pages/Edit/components/Style.vue b/web/src/pages/Edit/components/Style.vue index dcbe7cfd..24950309 100644 --- a/web/src/pages/Edit/components/Style.vue +++ b/web/src/pages/Edit/components/Style.vue @@ -247,16 +247,16 @@ -
- -
-
- {{ $t('style.gradientStyle') }} + {{ + $t('style.gradientStyle') + }}
+
+
{{ $t('style.startColor') }}
+
+ {{ $t('style.direction') }} + + + + +
{{ $t('style.shape') }}
@@ -458,7 +476,8 @@ import { borderRadiusList, lineHeightList, shapeList, - shapeListMap + shapeListMap, + linearGradientDirList } from '@/config' import { mapState } from 'vuex' @@ -502,7 +521,8 @@ export default { lineMarkerDir: '', gradientStyle: false, startColor: '', - endColor: '' + endColor: '', + linearGradientDir: '' } } }, @@ -522,6 +542,11 @@ export default { }, shapeListMap() { return shapeListMap[this.$i18n.locale] || shapeListMap.zh + }, + linearGradientDirList() { + return ( + linearGradientDirList[this.$i18n.locale] || linearGradientDirList.zh + ) } }, watch: { @@ -587,6 +612,24 @@ export default { ].forEach(item => { this.style[item] = this.activeNodes[0].getStyle(item, false) }) + this.initLinearGradientDir() + }, + + // 初始化渐变方向样式 + initLinearGradientDir() { + const startDir = this.activeNodes[0].getStyle('startDir', false) + const endDir = this.activeNodes[0].getStyle('endDir', false) + const target = this.linearGradientDirList.find(item => { + return ( + item.start[0] === startDir[0] && + item.start[1] === startDir[1] && + item.end[0] === endDir[0] && + item.end[1] === endDir[1] + ) + }) + if (target) { + this.style.linearGradientDir = target.value + } }, /** @@ -595,9 +638,21 @@ export default { * @Desc: 修改样式 */ update(prop) { - this.activeNodes.forEach(node => { - node.setStyle(prop, this.style[prop]) - }) + if (prop === 'linearGradientDir') { + const target = this.linearGradientDirList.find(item => { + return item.value === this.style.linearGradientDir + }) + this.activeNodes.forEach(node => { + node.setStyles({ + startDir: [...target.start], + endDir: [...target.end] + }) + }) + } else { + this.activeNodes.forEach(node => { + node.setStyle(prop, this.style[prop]) + }) + } }, /** From ce49fcb5113d24f466d6ab091f534c66c5cd52e0 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Thu, 29 Aug 2024 22:01:05 +0800 Subject: [PATCH 09/26] =?UTF-8?q?Feat:=E4=BF=AE=E6=94=B9=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=BD=93=E5=89=8D=E5=BA=94=E7=94=A8=E6=A0=B7?= =?UTF-8?q?=E5=BC=8F=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/node/Style.js | 41 +++++++------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index a4663764..7a6e9d4a 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -64,8 +64,10 @@ class Style { let themeConfig = this.ctx.mindMap.themeConfig // 三级及以下节点 let defaultConfig = themeConfig.node + let useRoot = false if (root || rootProp.includes(prop)) { // 直接使用最外层样式 + useRoot = true defaultConfig = themeConfig } else if (this.ctx.isGeneralization) { // 概要节点 @@ -78,21 +80,21 @@ class Style { defaultConfig = themeConfig.second } // 优先使用节点本身的样式 - return this.getSelfStyle(prop) !== undefined - ? this.getSelfStyle(prop) - : defaultConfig[prop] + const value = + this.getSelfStyle(prop) !== undefined + ? this.getSelfStyle(prop) + : defaultConfig[prop] + if (!useRoot) { + this.addToEffectiveStyles({ + [prop]: value + }) + } + return value } // 获取某个样式值 getStyle(prop, root) { - const value = this.merge(prop, root) - if (!root) { - const styles = { - [prop]: value - } - this.addToEffectiveStyles(styles) - } - return value + return this.merge(prop, root) } // 获取自身自定义样式 @@ -111,11 +113,7 @@ class Style { // 矩形 rect(node) { this.shape(node) - const styles = { - borderRadius: this.merge('borderRadius') - } - this.addToEffectiveStyles(styles) - node.radius(styles.borderRadius) + node.radius(this.merge('borderRadius')) } // 形状 @@ -160,7 +158,6 @@ class Style { width: styles.borderWidth, dasharray: styles.borderDasharray }) - this.addToEffectiveStyles(styles) } // 文字 @@ -184,7 +181,6 @@ class Style { 'font-style': styles.fontStyle, 'text-decoration': styles.textDecoration }) - this.addToEffectiveStyles(styles) } // 生成内联样式 @@ -197,7 +193,6 @@ class Style { fontStyle: this.merge('fontStyle'), textDecoration: this.merge('textDecoration') } - this.addToEffectiveStyles(styles) return ` color: ${styles.color}; font-family: ${styles.fontFamily}; @@ -218,7 +213,6 @@ class Style { fontStyle: this.merge('fontStyle'), textDecoration: this.merge('textDecoration') } - this.addToEffectiveStyles(styles) return { italic: styles.fontStyle === 'italic', bold: styles.fontWeight, @@ -238,7 +232,6 @@ class Style { textDecoration: this.merge('textDecoration'), lineHeight: this.merge('lineHeight') } - this.addToEffectiveStyles(styles) node.style.fontFamily = styles.fontFamily node.style.fontSize = styles.fontSize * fontSizeScale + 'px' node.style.fontWeight = styles.fontWeight || 'normal' @@ -269,12 +262,8 @@ class Style { // 内置图标 iconNode(node) { - const styles = { - color: this.merge('color') - } - this.addToEffectiveStyles(styles) node.attr({ - fill: styles.color + fill: this.merge('color') }) } From 7ba11be42b0b0fc1eaedf79753311684d3a6ef9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Fri, 30 Aug 2024 14:01:59 +0800 Subject: [PATCH 10/26] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E4=B8=AD=E5=AD=98=E5=9C=A8<>=E7=AC=A6=E5=8F=B7?= =?UTF-8?q?=E6=97=B6=E5=AF=BC=E5=87=BAsvg=E6=8A=A5=E9=94=99=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Formula.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/simple-mind-map/src/plugins/Formula.js b/simple-mind-map/src/plugins/Formula.js index b28926a8..8ac2da8c 100644 --- a/simple-mind-map/src/plugins/Formula.js +++ b/simple-mind-map/src/plugins/Formula.js @@ -1,6 +1,6 @@ import katex from 'katex' import Quill from 'quill' -import { getChromeVersion } from '../utils/index' +import { getChromeVersion, htmlEscape } from '../utils/index' import { getBaseStyleText, getFontStyleText } from './FormulaStyle' // 数学公式支持插件 @@ -58,7 +58,7 @@ class Formula { let node = super.create(value) if (typeof value === 'string') { katex.render(value, node, self.config) - node.setAttribute('data-value', value) + node.setAttribute('data-value', htmlEscape(value)) } return node } @@ -110,11 +110,7 @@ class Formula { for (const el of els) nodeText = nodeText.replace( el.outerHTML, - `\$${el - .getAttribute('data-value') - .replaceAll('&', '&') - .replaceAll('<', '<') - .replaceAll('>', '>')}\$` + `\$${htmlEscape(el.getAttribute('data-value'))}\$` ) } return nodeText From c12b7f6dae9e55d68a6bdf4051a2b3a8c6ed4459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Fri, 30 Aug 2024 17:02:48 +0800 Subject: [PATCH 11/26] =?UTF-8?q?Feat=EF=BC=9A=E6=9B=B4=E6=96=B0=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E9=9D=9E=E6=A0=B7=E5=BC=8F=E5=AD=97=E6=AE=B5=E5=88=97?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/constants/constant.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simple-mind-map/src/constants/constant.js b/simple-mind-map/src/constants/constant.js index 7acd677d..818b2ffe 100644 --- a/simple-mind-map/src/constants/constant.js +++ b/simple-mind-map/src/constants/constant.js @@ -328,7 +328,9 @@ export const nodeDataNoStylePropList = [ 'notation', 'outerFrame', 'number', - 'range' + 'range', + 'customLeft', + 'customTop' ] // 错误类型 From 453e7311b81e4f42b79fcec5cba96a44b2d1656d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Fri, 30 Aug 2024 17:38:39 +0800 Subject: [PATCH 12/26] =?UTF-8?q?Feat=EF=BC=9A=E5=85=AC=E5=BC=8F=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=9A=E5=8E=BB=E9=99=A4=E5=B0=86=E5=85=AC=E5=BC=8F?= =?UTF-8?q?=E5=AF=8C=E6=96=87=E6=9C=AC=E8=BD=AC=E6=8D=A2=E4=B8=BA=E5=85=AC?= =?UTF-8?q?=E5=BC=8F=E6=BA=90=E7=A0=81=E6=97=B6=E7=9A=84=E7=89=B9=E6=AE=8A?= =?UTF-8?q?=E5=AD=97=E7=AC=A6=E8=BD=AC=E4=B9=89=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=8F=8C=E9=87=8D=E8=BD=AC=E6=8D=A2=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Formula.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/plugins/Formula.js b/simple-mind-map/src/plugins/Formula.js index 8ac2da8c..af7e49fb 100644 --- a/simple-mind-map/src/plugins/Formula.js +++ b/simple-mind-map/src/plugins/Formula.js @@ -110,7 +110,7 @@ class Formula { for (const el of els) nodeText = nodeText.replace( el.outerHTML, - `\$${htmlEscape(el.getAttribute('data-value'))}\$` + `\$${el.getAttribute('data-value')}\$` ) } return nodeText From 1f303145c632427944f6cc24963c0c9a62eb0175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Tue, 3 Sep 2024 17:20:49 +0800 Subject: [PATCH 13/26] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E5=AF=8C?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E6=A8=A1=E5=BC=8F=E4=B8=8B=E5=8D=B3=E4=BD=BF?= =?UTF-8?q?=E6=9C=AA=E4=BF=AE=E6=94=B9=E6=96=87=E6=9C=AC=E4=B9=9F=E4=BC=9A?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/RichText.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index 765d76cd..e32c96cc 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -359,6 +359,18 @@ class RichText { return html.replace(/


<\/p>$/, '') } + // 给html字符串中的节点样式按样式名首字母排序 + sortHtmlNodeStyles(html) { + return html.replace(/(<[^<>]+\s+style=")([^"]+)("\s*>)/g, (_, a, b, c) => { + let arr = b.match(/[^:]+:[^:]+;/g) || [] + arr = arr.map(item => { + return item.trim() + }) + arr.sort() + return a + arr.join('') + c + }) + } + // 隐藏文本编辑控件,即完成编辑 hideEditText(nodes) { if (!this.showTextEdit) { @@ -369,6 +381,7 @@ class RichText { beforeHideRichTextEdit(this) } let html = this.getEditText() + html = this.sortHtmlNodeStyles(html) let list = nodes && nodes.length > 0 ? nodes : this.mindMap.renderer.activeNodeList list.forEach(node => { From bd0fc37f03b3f5ed2d033416e7e29fb356dd2344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Wed, 4 Sep 2024 09:07:21 +0800 Subject: [PATCH 14/26] =?UTF-8?q?Demo=EF=BC=9A=E5=88=A0=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/scripts/transformMdToVue.js | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 web/scripts/transformMdToVue.js diff --git a/web/scripts/transformMdToVue.js b/web/scripts/transformMdToVue.js deleted file mode 100644 index cb36f3ee..00000000 --- a/web/scripts/transformMdToVue.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path') -const fs = require('fs') -const hljs = require('highlight.js') -const md = require('markdown-it')({ - html: true, - xhtmlOut: true, - highlight: function(str, lang) { - if (lang && hljs.getLanguage(lang)) { - try { - return ( - '

' +
-          hljs.highlight(str, {
-            language: lang, 
-            ignoreIllegals: true
-          }).value +
-          '
' - ) - } catch (__) {} - } - - return ( - '
' + md.utils.escapeHtml(str) + '
' - ) - } -}).use(require('markdown-it-checkbox')) - -const templatePath = path.join(__dirname, '../src/pages/Doc/Template.vue') - -exports.transformMdToVue = (content) => { - let result = md.render(content) - let template = fs.readFileSync(templatePath, 'utf-8') - return template.replace('$$$$', result) -} \ No newline at end of file From c8d5a34640f4f7a5f5c8484a4d77d6a5b3716ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Thu, 5 Sep 2024 09:40:41 +0800 Subject: [PATCH 15/26] =?UTF-8?q?Demo=EF=BC=9A=E6=94=AF=E6=8C=81=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=92=8C=E5=AF=BC=E5=87=BAFreeMind=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/config/en.js | 6 +++ web/src/config/zh.js | 6 +++ web/src/lang/en_us.js | 4 +- web/src/lang/zh_cn.js | 4 +- web/src/pages/Edit/components/Edit.vue | 3 ++ web/src/pages/Edit/components/Export.vue | 20 +++++++++- web/src/pages/Edit/components/Import.vue | 49 ++++++++++++++++++++---- 7 files changed, 80 insertions(+), 12 deletions(-) diff --git a/web/src/config/en.js b/web/src/config/en.js index 8ab141a5..a98fdd32 100644 --- a/web/src/config/en.js +++ b/web/src/config/en.js @@ -495,6 +495,12 @@ export const downTypeList = [ type: 'txt', icon: 'iconTXT', desc: 'Plain text file' + }, + { + name: 'FreeMind', + type: 'mm', + icon: 'iconTXT', + desc: 'FreeMind software format' } ] diff --git a/web/src/config/zh.js b/web/src/config/zh.js index 9b24c5c1..bf91eda4 100644 --- a/web/src/config/zh.js +++ b/web/src/config/zh.js @@ -589,6 +589,12 @@ export const downTypeList = [ type: 'txt', icon: 'iconTXT', desc: '纯文本文件' + }, + { + name: 'FreeMind', + type: 'mm', + icon: 'iconTXT', + desc: 'FreeMind软件格式' } ] diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index f4f4917e..dbb9aef1 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -157,8 +157,8 @@ export default { import: { title: 'Import', selectFile: 'Select file', - supportFile: 'Support .smm、.json、.xmind、.xlsx、.md file', - enableFileTip: 'Please select .smm、.json、.xmind、.xlsx、.md file', + supportFile: 'Support .smm、.json、.xmind、.xlsx、.md、 .mm file', + enableFileTip: 'Please select .smm、.json、.xmind、.xlsx、.md、 .mm file', maxFileNum: 'At most one file can be selected', notSelectTip: 'Please select the file to import', fileContentError: 'The file content is incorrect', diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index e7b71a59..bfb4be35 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -155,8 +155,8 @@ export default { import: { title: '导入', selectFile: '选取文件', - supportFile: '支持.smm、.json、.xmind、.xlsx、.md文件', - enableFileTip: '请选择.smm、.json、.xmind、.xlsx、.md文件', + supportFile: '支持.smm、.json、.xmind、.xlsx、.md、 .mm文件', + enableFileTip: '请选择.smm、.json、.xmind、.xlsx、.md、 .mm文件', maxFileNum: '最多只能选择一个文件', notSelectTip: '请选择要导入的文件', fileContentError: '文件内容有误', diff --git a/web/src/pages/Edit/components/Edit.vue b/web/src/pages/Edit/components/Edit.vue index ef9d9ec0..7d61efd9 100644 --- a/web/src/pages/Edit/components/Edit.vue +++ b/web/src/pages/Edit/components/Edit.vue @@ -79,6 +79,8 @@ import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js' // import Notation from 'simple-mind-map-plugin-notation' // 编号插件,该插件为付费插件,详情请查看开发文档 // import Numbers from 'simple-mind-map-plugin-numbers' +// Freemind软件格式导入导出插件,该插件为付费插件,详情请查看开发文档 +import Freemind from 'simple-mind-map-plugin-freemind' import OutlineSidebar from './OutlineSidebar' import Style from './Style' import BaseStyle from './BaseStyle' @@ -135,6 +137,7 @@ MindMap.usePlugin(MiniMap) .usePlugin(RainbowLines) .usePlugin(Demonstrate) .usePlugin(OuterFrame) + .usePlugin(Freemind) // .usePlugin(Cooperate) // 协同插件 // 注册自定义主题 diff --git a/web/src/pages/Edit/components/Export.vue b/web/src/pages/Edit/components/Export.vue index aa96e22c..db769a7c 100644 --- a/web/src/pages/Edit/components/Export.vue +++ b/web/src/pages/Edit/components/Export.vue @@ -8,7 +8,7 @@ element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)" :width="isMobile ? '90%' : '50%'" - :top="isMobile? '20px' : '15vh'" + :top="isMobile ? '20px' : '15vh'" >
@@ -98,12 +98,14 @@ import { mapState, mapMutations } from 'vuex' import { downTypeList } from '@/config' import { isMobile } from 'simple-mind-map/src/utils/index' +import MarkdownIt from 'markdown-it' /** * @Author: 王林 * @Date: 2021-06-24 22:53:54 * @Desc: 导出 */ +let md = null export default { name: 'Export', data() { @@ -203,6 +205,22 @@ export default { this.fileName, this.isTransparent ) + } else if (this.exportType === 'mm') { + this.$bus.$emit('export', this.exportType, true, this.fileName, { + transformNote: note => { + if (!md) { + md = new MarkdownIt() + } + return md.render(note) + }, + transformImage: img => { + if (/^https?:\/\//.test(img)) { + return img + } else { + return '' + } + } + }) } else { this.$bus.$emit('export', this.exportType, true, this.fileName) } diff --git a/web/src/pages/Edit/components/Import.vue b/web/src/pages/Edit/components/Import.vue index a19f76ab..fc8dc05e 100644 --- a/web/src/pages/Edit/components/Import.vue +++ b/web/src/pages/Edit/components/Import.vue @@ -9,7 +9,7 @@ - {{ - item.title - }} + {{ item.title }} {{ @@ -56,6 +59,7 @@