From d36d02c2ff10ff828bde5bc77375984524090c5d Mon Sep 17 00:00:00 2001 From: xiaoiver Date: Fri, 22 Nov 2024 23:40:05 +0800 Subject: [PATCH] fix: rough rect with drop shadow --- __tests__/ssr/rough-rect.spec.ts | 76 ++++++++++++++++++ .../ssr/snapshots/rough-rect-dropshadow.png | Bin 0 -> 18719 bytes .../ssr/snapshots/rough-rect-dropshadow.svg | 47 +++++++++++ .../ssr/snapshots/rough-rect-rerender.png | Bin 0 -> 4383 bytes .../ssr/snapshots/rough-rect-rerender.svg | 37 +++++++++ __tests__/ssr/snapshots/rough-rect-stroke.png | Bin 0 -> 21191 bytes __tests__/ssr/snapshots/rough-rect-stroke.svg | 42 ++++++++++ packages/core/examples/main.ts | 22 +++-- packages/core/src/drawcalls/BatchManager.ts | 30 +++++++ packages/core/src/drawcalls/Drawcall.ts | 16 +--- packages/core/src/drawcalls/ShadowRect.ts | 7 +- packages/core/src/drawcalls/SmoothPolyline.ts | 2 +- packages/core/src/plugins/Renderer.ts | 2 +- packages/core/src/shapes/Path.ts | 3 + packages/core/src/shapes/RoughCircle.ts | 1 - packages/core/src/shapes/RoughEllipse.ts | 1 - packages/core/src/shapes/RoughPath.ts | 7 +- packages/core/src/shapes/RoughPolyline.ts | 1 - packages/core/src/shapes/RoughRect.ts | 1 - packages/core/src/shapes/Shape.ts | 11 ++- packages/core/src/shapes/mixins/Rough.ts | 26 +----- packages/core/src/utils/serialize.ts | 3 +- .../lesson_013/src/drawcalls/BatchManager.ts | 35 ++++++-- packages/lesson_013/src/drawcalls/Drawcall.ts | 16 +--- .../lesson_013/src/drawcalls/ShadowRect.ts | 7 +- .../src/drawcalls/SmoothPolyline.ts | 2 +- packages/lesson_013/src/shapes/Path.ts | 22 ++--- packages/lesson_013/src/shapes/RoughCircle.ts | 1 - .../lesson_013/src/shapes/RoughEllipse.ts | 1 - packages/lesson_013/src/shapes/RoughPath.ts | 7 +- .../lesson_013/src/shapes/RoughPolyline.ts | 1 - packages/lesson_013/src/shapes/RoughRect.ts | 1 - packages/lesson_013/src/shapes/Shape.ts | 6 ++ .../lesson_013/src/shapes/mixins/Rough.ts | 26 +----- packages/lesson_013/src/utils/serialize.ts | 2 +- 35 files changed, 338 insertions(+), 124 deletions(-) create mode 100644 __tests__/ssr/snapshots/rough-rect-dropshadow.png create mode 100644 __tests__/ssr/snapshots/rough-rect-dropshadow.svg create mode 100644 __tests__/ssr/snapshots/rough-rect-rerender.png create mode 100644 __tests__/ssr/snapshots/rough-rect-rerender.svg create mode 100644 __tests__/ssr/snapshots/rough-rect-stroke.png create mode 100644 __tests__/ssr/snapshots/rough-rect-stroke.svg diff --git a/__tests__/ssr/rough-rect.spec.ts b/__tests__/ssr/rough-rect.spec.ts index 227c8c9..90b80b9 100644 --- a/__tests__/ssr/rough-rect.spec.ts +++ b/__tests__/ssr/rough-rect.spec.ts @@ -47,4 +47,80 @@ describe('RoughRect', () => { 'rough-rect', ); }); + + it('should render a rough rect correctly.', async () => { + const rect = new RoughRect({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'black', + stroke: 'red', + strokeWidth: 2, + }); + canvas.appendChild(rect); + canvas.render(); + + expect($canvas.getContext('webgl1')).toMatchWebGLSnapshot( + dir, + 'rough-rect-stroke', + ); + expect(exporter.toSVG({ grid: true })).toMatchSVGSnapshot( + dir, + 'rough-rect-stroke', + ); + }); + + it('should render a rough rect correctly.', async () => { + const rect = new RoughRect({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'black', + stroke: 'red', + strokeWidth: 2, + dropShadowBlurRadius: 4, + dropShadowColor: 'blue', + dropShadowOffsetX: 5, + dropShadowOffsetY: 5, + }); + canvas.appendChild(rect); + canvas.render(); + + expect($canvas.getContext('webgl1')).toMatchWebGLSnapshot( + dir, + 'rough-rect-dropshadow', + ); + expect(exporter.toSVG({ grid: true })).toMatchSVGSnapshot( + dir, + 'rough-rect-dropshadow', + ); + }); + + it('should render a simple rough rect correctly.', async () => { + const rect = new RoughRect({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'black', + }); + canvas.appendChild(rect); + canvas.render(); + + rect.height = 20; + rect.width = 20; + rect.fillStyle = 'dots'; + canvas.render(); + + expect($canvas.getContext('webgl1')).toMatchWebGLSnapshot( + dir, + 'rough-rect-rerender', + ); + expect(exporter.toSVG({ grid: true })).toMatchSVGSnapshot( + dir, + 'rough-rect-rerender', + ); + }); }); diff --git a/__tests__/ssr/snapshots/rough-rect-dropshadow.png b/__tests__/ssr/snapshots/rough-rect-dropshadow.png new file mode 100644 index 0000000000000000000000000000000000000000..26d6e85c2d6d1a39323afc0ac1ed505c08dff888 GIT binary patch literal 18719 zcmdtKcU+Un+CJ{CF1kt)QBV+2P!SQ3-eFaWAVqpJRO!70kWf^RURDXcD7}Z?0tD$w zm6}ikL~4MD5D5J{ad*$zv!}i9`}^L4)MWxL=$?8o`9w=r_Tp2MtJWq7 z*)@Aji+eiingZ_H13P{@p6tH+&+qD&Kdar^#~!2f%AbAuh1EIz%x`LJs8)}nnv$mfq@OgGsCUHjxi&qStFsIxs_U$lq+r{bI`#|f>z zv3vhj7yqm|<@%}7JhBb)y58P=98~ZhZsR6o|DzQ2ci1N1{7vFNWc!;coE7doj=OuM zU|v|vs`YG=c)#umx54XSu|51w4C$zIs z|0LTVW(Eq<`0gRxHJ`+oZvC%}_E%v2Mcu7e60ztP%Q6#lT(PrvIngdEx&o z#p|#$o;UvD!haHa^38W=v8_}2KRaD@eoBSufA{P^8S%Gykl;~Y{M&rwK9Jgxrgdk7P8?W+!mm^t{6zuFSc>DW||GuEeMD zj~6XYct++$B|fcxEdE=qfj4g>mB2;fb(~zrMWr%zP_IlKf`9bs5ww{7Ci_TL6g)x; zEv~_@1<^!{uOuObwf@yp4G2E(4s-UeZ=>Mu@CTe(U(^h`*`9<&Dy0K4o}A5I3c07o zxe)qUJ?sseJKQYm43PQGtB@?(`}GcajMb}f&brO2)2@W7LhPi$8n zuExG}s4<^d!+0}Qk0){0JnQDxFME55t8PK}06!syySiR~+R&kw-muj5oJfrUoBMDT zkZZUqU4!k_8qFaLouQYCxb}Ae^+tr{AtEVij5|b?)Z|fgtV5FRA1|tY+G}fU^E}&@8HlA?!$D^aPXEMKX@F14BJ+-B@UgDs#uL<*4O7*kb$^*(>T##vrXBb&9k$Ny-RkMN zAr|8{V5_bzUeF~^_J!S;LD%GeJM|{W9)fZ5M;rzovvbv$y;InTd0cB#6^RnS?Q2)( zfBK}&a!i736+Nwsb@IjE3OFDd*SHU-Z;b066b4Xx$4w-srdByliASPQ+xM`$eQ3dT zm*}Y!*m}Rvc7DK_1jAyD(q&wQJ#5tv3^aEQ(EU^HPb_b z(PGmz?n!StJIA>=rrkB(!*@*RnwB1A3;PHS;1lk{(7Zba#dm>^CvyB1X2}>a;L4#D z7Nv3fCp+{q#)YHMe-Bns(bLB-5R>9Hr!KvjxRacqH(Tsjeq)0 zuB2(^oVTj=T*j@FS3CzHUs`xf2>Kpl^8-31)rpx=$ilk1D^k&3ZQyU= z{^yI0Q&2R7J6lP1VrsoQmjU(lX`wDt-ju2|sX2c6`BtX!ObGi?@5;zR-AVyL6kjB= zB!-Kq9w~HiU#}|}a>GT|keX>w1qJ2NzV;oUTE1P{;p)%X!`{?lU$8|+4gxVTO*>PB zwA{sBr=zlwLTHvO@O$AKOe(x?_+n+{^KamD(P8k9i3J&m{5u-oICAGzbHL15B3pL_ zvv~xjdD7hAV_s+*EzKy#wvc(PqTg-G`5~W(0)&GWAf7$Oxq?pZz)p%w$A0m{Ng3;r zf@hl8!}Z`|2rM(LxMsS2auT6atRyTXQQw>^bEp)lVas`w7dEC=Y!FN7Ht9mgXl~9W zxe-d(`W!6XU!c8Ex3}WteY{Wec{4|(xXM<0aI;G{st{kgm=;}wHd6cgnzump1c=DirMf@8w^FwoG^ zbY5x2Kmq6=`-wI=0BK}g1X8EZs}@~UY95A1Nv%6s-U1?ru(K4E&BsZI&cn4GYhUK) zn_1opz4i*3bCIXvYcV6IMR%OT+HSwG!^jiY2~$6C{tYq_b_*&eWfw3F1LL*T_lV9_UNH%5td5Dh=e66lFo&1|ToS?WsYIC?>WBol>4665V{A zl5+iJoqqi)B4v)ucr?e*Q00W|4cZi_PIfN*Yi;M@#{z9d_UtTLzWEe47E8^2!Z9l_ zCL`xfsdsx?7MiD-x3~&*Zbri2PVA4Pw>?{_7_Kl)bfNbB^dU0jcl$o&SXw!KtLtCO z0^U(_PoN@KyU_iq=alYK=jN9koi!W32K)2?$ERV8_S+JfZ+NF&*yA?)T5ZtL>9ciJ z_1BLIX;!U4u!+)UOCA)-KOZj^d0J{|ZF?L)uTwk-;xD{*At}0krGOXHQ;c)GqITQW z(mrCtrK2x$I)E>)&S3CKbpO%8H5r5Fsge9bns-r7-YG;0C ztY7me=;o2oH}B?V&4M2m8#$zLA-tmSi2YY-jXTnhIrj}3$1VMK>UT)JPJN>lYt_g0 zL|dk8a_@_%oksJX3J)M^rNJkX7aw19+o?5=L0k2+P!;Xv+ppmVpR7SP@{@o7WBi(z zT5jt0oybMW#fLy&W4Ac!h&rQ1ilYdNR*Hp%TGCus4wyJG)l=I~Vq)NL1vTarWD2&F zl@Ah^m%G;*cS@91HIxP)DRxHtAH;imOsxHg!|f-gWWlpQa)xO5_A)2OufXNqzR%d? zWPplVuza7QlJMR}bj_d}cHeKR+#;G^Oi@Xkr{4Z?HZr{`ZK(tdm z;1P|>*@PCc);M12jw>?*qW1I-IBKFn?nR3Er}d&YNc2{c&ai=e$kk&dzhtnYUs|Dd zHfVg0_z4Luf^?5p*<*fHR`qLN(;i75EgDb{i&|cGT1rgt$^yT~ER*RRFwVS8!k8W> zzlvg{QDN@XbU$~^WoyfY3!0iTBN&%XwLE;Menk)xAy{x{xo&%WUMX=vuWarbZFIS1 zWF(@|BT-{PSy}Q&nq~#Tjt(QUUdGKL$o}=1n9j#G%A9UG2+84Z^G=nPkt=&mx9scYo9#Ee9L0@sU!m>W-Fjsi2}x#_ISHv2j)*)vB}KLeO7I8T zAiDwa`nR>Qvx338tP-CZ=f}h|tjDDM?Xg9^D5-6kBBS0OWqzsNVXbo0lT5-lWDaIW zSGQUKpr^m zO4HFP7&J})A~Ic@s^Lf$H&%3Vk0`z(Zle_&mF#q6m)&D+Up0~#$1TybM-(=w-~LG{ zF=kL{Xow*p4fP?;(66PfZFaOoq*-HJ+YQ%+@oM$&Fn7??bgj9+|3_~y6ukW3F$}iHHBov>IuVU2HT(th;)3Cg(1cHBd zQH|piEu(f-eOVb!PI3Z+QP0VZQ5hjxjF!k~V9zP5G2NbH%bv{O6W*p2YZ}|CoVb{M zBNC1&oo#0Gd;ez8LrH9Mt1{Bk3TtnOG34_og1A15ba#H`A}?THcrsYo%V-rk#JQK1@21CK&A9&mn1nOE-9 zy2QEsNKxUh91U2|8)nX{A}+!+tR@@?>p@H**T9-)YJtX|RAhYg?R0wc-Q)16< z{NfW-C&m=}_KD!a!jU?}-`L#eps--&1bC$YzuDWD_Ff&`#4iMWuY-S9JX+Y(o0tnX zPD*^9pu%mq&E@8{5K0QHt3#Xjlv`jKT#RWKLPaMgC)K@m5KpZfRdpRQJ(5FiWQ4p& zG+xuPD_JG{t380R5mGIJ3$Ptd}5 z<~i8XvfpgBv#}uXqHEPZ+>&e1Vb2b}Gk-zMIAhAl5p`v4TR_P5=+}_bjP}JI`%k2b zN70oN;ss}+1Da@A^0M!@RqX~xF*&1vxK-RWG|f%*a2Zk|KWZ5szQgdew4%U(C)+{x zsgv0pRly2t)dWDUrQ7qVO1s(e+J{dd#yM{WU#@r?CKuqdII`7l&mWPevYKv}zPH9+ z9a8uS=WzjiNJwK34yV>e3%i6P{oaEY>qCMcFNbREy+`&faIJWsmdbvbQNW|wbu!j0 z4LPmKp4}SzO*#8=9%5%OW|LvV8ma;o&UxW!Ag2Ks38qF^FMLi-qucDBNM~1^O6&tj zO)6}CO2~D3baE1^Q{?qp2XEZd3sMP?LiosWb}n&R@Md3)+Mj)_R2FKy1mjLaTs(R3 zh|_9W(I!@dazin@K^dE_RFU2StdjrAObKo*-Q~1~z-oC88qDXIperO18M(6*e z3u}|LMJs8@36hj|n8`|w?cu6ixRFz-C)d2S6z3s@Cm%*mN$e?mwtxHMNh5MKr#tf- zjGVr-H1{5He#+6(!o4!xgIHNl$rQgE?C_REExaL1mz%HQzBdUSYt~Y36uQO)< zdV!pSXY1WHSpQNzRhp)8nF;MSs2D9M1g$7w6p-=_fOtGlXZG-l7P9N1dn2gf9j75( zfOnq!Nq2m5b`K$p@yDg_@wA~R_D`;t;H^_^QCav_QKsY2#kuDckCFU8I<=Nj>{F-? zKvQS^UM((rQ%&bx)EFe=qh7sm**Dp6xo!ux7Us~uldjg}gc-zA<>@?gdu2$ld9-gO zS4qPoZ40QBRY_x%%T9gM$d?=07-dev&<+cv|3kJHYxU@k6DbSv?piW|LUMRvTL^PE zYIKKw6Ou>p$H})b=*IkSNagdurW zka>11$feLT+HxS;DT!;8C;mZ*GTYQu)Z1t%*!AS+vfy)N8XsjMTG?55c|05OkHI1+ zZEQ@T0DsPzhST>PS1GmCiuX&DG43YPFJeELKvP?Y5^$-Vja&8>lz#1!4C9LGBL zVVBlB?~Z0|ys4$OC_U>ZWEW-Jjq^lXPvVVscD8bx zI&}=!@OyZwO2;V#qc%}~H5dP^fswUkh5z?=B9$Uo z&0Bmlz1}0Z%FgD_+zaqk#@18r81GTH1ygEvjasuOCRpPOxaomZxhT2LzWTj|#Q3Dd zvGJ7=ioGeqI>3KOL}Y6Alt*&SvbR`=yF)0{>&K&3ljskT$fF+!3KpeV1g)#~C|_vm zi^Ziqv28(2A9A~04#V2Xbaz>Tss8fnrq^2(@0E2{mqPhMZG0g&eXK;iFG~^5&)+ee zyIQy>R`)2|V_!sLe3ag>Xwb7!BdQhU6^uAnrixyq+&<%Dh*iXVGC3|LoVx0O@^#@$ z3;h{F)0{>zK`nwSt39(n`(pqkgD@i6W`h5E!gyQ^mquLlcNg03yxi9sxEs|`Lre{Br1B6q%ER-Ce)4f@ zX|EOO`%Jtf*=KTk&T=*Qc$nxA;CsFwUBx{8thRCMkiMJBvsPZosU^l9p?CL=r-!al zdgciK$4j~my#&7<>B#!2HMZnC^QZULGwnoxGyJdsJ2zcSU?)igK%yB|#%YdiPy%0h zYelBt6I>`Ht}f2b*6N|f1ByE~p$-9xty3qP&_u~qv)a?ku&P~K05qwPz^KuLiTb&) zii0JEPP^;InghG+5f6&|1um3365PzZiZ|@ENacaNuLvkxF$& zkmD!p*|`PyT$3tG;@33-v#g z3=r=$=%Y~-FiKQ5;g^7^ka)brxU=r88HDwrMM8f5Lx(%rH*RWV6ud3CQxI10O#$pb z#tDdNYG-8u#{I85aIKXS4v}%~8C`w{xW`vLC$THf$A?fni}S+JZtm!NBA)4GWdb9_ zUL`RQ^o?&@C~P{Iy6G~lKRS4d?k~&TeTz`TJ+Y5;GUEtX%OdoWMAK|aJ!kBYMgby> zjtY?dna!Z&HWs96`yr)(RAXd&PPyKsPk?UI-aRQbuNF?g>Ai7ua$J89318=!KruheTnwA(c++i0GzI!0~Ld+{L2=jmzuo$|{^ADADKdV@QT2a&Vug?5HMllQV4C`D{54NmhN zS=o!Wn?2E&^}rtX3rTO6+0=+g`PLaaNsW+5bi>3QkRfO7qMo@qwMkKJ`%3C#e^}U0 z2lH6!YA7A0M-*z)o!P2XW@cn>IurzJroE_^$5cDN9GvBHiJ9$F?`m4nM;(OUrVo#k z`%+NIvw5^*oKs-nNLZBdf6=kJ`kYZrMpKDZ7wu^Eqre_dODk3NS^r`@vsc|NDyVbD zc{NbeMJB}&i1RGv1#I>)X57Scq=w;W%*3gE1G)avUtltn6pCP?tWo7W&U-UR7ZLp~ zyAZ%rczbiO%_y-%wx7@3jYdR|NnsgQw>vt=hxBO8uVwYKEM;Ai zxQ{-)VFhf0YIJ_xtb_A{NZ>?*_B|W!qtT_4&Q54eZ9?3jFfyz?!=kLVv(c9TbBKvq zsM{KBs>;8_#q$I$ftloWk@0=kk{-k~1QqQg#|G7AF6d#8iE#(rSLLTc-Cu>Tnv_0s zi)SqAfNUMMI5)M$Kp`&RN|+l(ONdyTyHz*uQT94zzD$bXgO!I#I);rtTq?XBcXTvij2K9F?dh+KIB7LhUp08yHQ>x2SX+Tp6r0*A@kYT7gXn%l?wjc}+NF(>GX9B%8e$ z*KWD82dz~`yM5(pmAZPIjlX!+1l2z`h3xCxC8jwUE&IF^EZl z$+O)lLeMRW?7fd-JH!?nMiiu7U!`?QZ#T&u#C}p_8X@-g_A(>v65*&w7~|@l)qK1W z>HV$_&S^`EiS@%K<+f=`=+7YH^17%6Ole{fq=IJ0mH;So=n$3XW$A3ZU2X0xbsLZ; zvfRU=JVA>-ysZjtw9L*b)|^v~J!%%#?((jv;8<2%ekzGEc`4-%;=M4&(4D!M@SH+| zwZHw8Q9l0KB-&&GcgvU1x=sNLK%tq|8GV${%U+eUQJv3`eopYQv0Qz71N!hnzlD5) zS7aK8^o9d~E0(Kfg1$!xeB7L_KCNPE{eyh*tx`rh$49S4IIl z>)0~oEM*kfBmgkcVY1z%(8URIdhSuH?DosFucq8Y4cKn zE#DvaudMSRj~I>lCy8DN1cQlgYwCNe_OKF-HIp*yy563i2#G<*8gAM8sp|9Kz{LY{ z{Q6Ex)1?z$b9_a`2pR1l3AQy8Y;Qxd5HYNWdD$F`3Lkeb(gu0aBL<*i+x*6ZM8B)~ z_$FtO0Ec|SnkcgZ>ht zCC`rS?b_smFNdAvnoZ|~Y4B8$k(7gF4!=nJlxsH)F(Oi`1yDJHBD%l!?1=k3#ZE8m zBT(#6UwRrL46N5PtC^=oW@Vg7rj?tbUKWdU$(h~m7(rS_dL*E%F0WfDJx>J$hLbkY zQ|W#_5h%vZttv6`o)l!F^m>u8F%xTvwstWBtpCmIBT~Z2`@NjItZ0B!vYct(;JURN z@=O4)vi(S{zCs!Xj)lc2Q_GI?$4n(?C{Nlm)TZ;bwBW+8+*iYMFW+7ErkxIFn1fK% zQ|~YDUqN(?E=ZhISlTb2J-VX1Wbm4=^(KV3!zQR+iPJwvT{}0wfaCqr9e`XizZAdA$(;%VKejZ!)&v zY?py!h5Z=+zc~o>o68M3;vdIuY`B=4R~mqg1br*1C;cZ`oHGrbpvgCGCfDBQ++Py^ zf#Zt32&BI~*jYElytJv=^Q-(pIKs)CAs}*j|AurxE~EWvU$kjr^AVH63i1q%$Rtbc z*?ruPt-Yq%2##45Z;fvXp=Ox{1z(i=fp~WF|HwN~1`TE30LD zsFw;??CEz#iNaUyYP-vLFQ8u3GdW5?BxcQO7&g@1+)66QxTqoMw-L@t!gNLrk~U@h z-*8uBdhbCGX{9)Q&+iChVH-x0m+M!Mr@E;;SRv-Mm(@DzskW(n-wi+`n$rSHR$%a1 zqxS^8)}H`_bMfl4T4oo4>P}Y5LB}Rd-EtrYeRe`}GI20oS{A3@zvnsO2rJbtq!g4& z-OAdcUbRAXJHru#x%yg48bQn<^pL%;W1E!H9Mvx2{Nwbi4>vKRK7@`%Xd`RC$kRb` zA~PO`WC_Pn*3dW(Lo@G>uVs~x6D)a`mY;){$6$m2D!L67DbB|8ydqdekS}o&r9PYN zbk2M6gNADdOq$vy+#7#-S@Bh5VV_L$__Q`Y#-5I-{wb$aq)%kB_3KGUlK{raA!mHr zY@l540MF!ePR)0vo7v~9VX=Y5dm=u%!nAclNCO!SpDw(3(ms=L(T84*4YLJ{q%JX`Gbx|!$00MhT(yBU7T&nEjT-ok+P^VuA! zO-7Z>OjGP%q#lBbvsl*B%qc@e7}sOGA`vAxC#r2aAJxnP)qB!@Z`*VJ!#Tn4@Sp_G zAiN0B{yhr=M+Ov?4z_Y7mOv_Ydc}LvCw@735L(pi_cGJH@rRNT;x7Sf;o%$4o@Uq$ znmCQ@`~av0k-2*yCO>M0gfJ|LGfgnAc8fm6Vi|MbbVRKY#l5#_B^=a`6_vEKHMHfl z)wPdqgF~6Fx2!-q3Qk?H|I1@1<$7?l1j4cLjksr=IX)0xj_G3T@NPlX2FX1jKV z0^WW?o%W*PKxoKa{hzPjs1wQc!%plLxH`^%8P=^?c$b(WvH1LG;aPH&%+XK>4rC38 zMK==lBrBnn(~G^uLwAnaGA+E~>%Gm!%dG9(8=X0Qt&t84mMl^4gs_*fCMy#g7g~AR zb`rg5RE4k{8^35a1#mFZ=dh&1Wd!q}c^(CG)&oh;r*}{>5Rb7=2gb;Cv$Ro1yA|IY zqY%Rcf}keWe8F@9#+4RjIJ>Bl8a6S$-fOuYU2~<{Y(

3qQ06JBUc+VBF?O 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 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/ssr/snapshots/rough-rect-rerender.png b/__tests__/ssr/snapshots/rough-rect-rerender.png new file mode 100644 index 0000000000000000000000000000000000000000..fc0b0329a389ba2e13554bb57e93a546aa1d4014 GIT binary patch literal 4383 zcmeHLX;4#F6vm}mtQr*+G!oh=$kq~=%!r5*Q7IyoMQE{XQ5nGwl?WLjF_1W78-XYm zpfdxkbd2{`0kbB=jq>dj3*Rm*61 z^|xB0xw(0EcQy78joit}X?wh&ogUV9E8F_c0@4;98JW;S539}#wD&o@faKNG)m`86 zTl>w`p|L^B=~cH=+q?esj6M0PxN6(!{`4nq4(`E;w?+b0&>-5nE)~j0<_}<{h+0uqiK!~!grn1 zd2`6kd)n8x&I<~llchQO7!{RGQKuq|Jxcc6km)&UTXCzPbT)Fc-uMc(fI!Y}ry`4k zAh4~lKKjKC>!V%^NHn$Kw6RACFof;2qlJu;giAVD-|@yN2d59adobG#Kv2lYG8VZG z8zYb62^rSM_TQI;{flIh2Qb`@LI#7;w|zBJmQyJiu+rwilKYkfH zoY#UNQZq6>azY{rf}9XLxu|EL46U|D)=3s?59+Eu!cb2rz)8;H)#DwC7vAV6aBN)z zhx7(T!}pt#)WaAYubZbyj7*k#0kig4LTeZV&P1a*b9XGtU_}Z}Vu^77ozkVSU9Z>3 z>nC58@0@&5noX38qzy3AWhHZ*j+M4oGjk}2GZ!Gxt+{1~vhJ2li8HFX@4mHBy`1V| zw;XmEnex(?EANcTl&Zz#BDiZ@fJVU~%bxin0}&~&0}+J5wW8koRsfwpgh?n7WsCS2 z0+JwmY^wk|9LLJKMigh~1B%D%PdwBw{l^N$$rKQSdms_DN}le%J5S*!B92yd;0J&7 zJ~4V9j%2B1^O?Zdz*v&cX|0V zrXQG+Hi5uqdZ5i`PJe7f12k$tsWmNm0Y)FUj&P*|LoOWlkf!-dGBB!hvL-Ws35Wx2 zU^{~-cXHq91f)qCl(}QMEYO%nIsu;w$t-!TP#wz|kV`+F#?IXlNz z3SO2K4e4x0`<0o|pBB8+OtZ^qXVOb#(KC(oebb*a)1s;Wk*2RV&>@Os76KB}Er!}~ z$z_>)v&D!-)ZHk(O+{;~FMHG9ug_|nVy9`r7%5is;^X5zl`OuFKB41y%!5i^Ex5sD zrsTh2CB?@#q&Zf{^&B&X6b#8^S;KKX_a9QHi*Ba)46RT>&d06HLJV=d=Qj*d1-Ge? zWI30c0>lg0RXjD`zQiqK_O7VQW8FDn< z%Miz#XEx~+Y)nxOHl~gX2r6o2g|D$kNthEdeG=HT!4StwylsH5Ca@tg)|6xH$YMAd zdz2?LEYEC$|p#Uj;G me-i;d2CxlWpVh!=tV*s{{j^#X(+R$KnD}`4?W@>x + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/ssr/snapshots/rough-rect-stroke.png b/__tests__/ssr/snapshots/rough-rect-stroke.png new file mode 100644 index 0000000000000000000000000000000000000000..c1a0dd397a6da375af2de02b2727b6f856bed076 GIT binary patch literal 21191 zcmeHvc|6ry`*w4hL)auTrKAiEh*B~nWhlESnTJM^5+zDzJ0(Rz5|uOv7LgnU6O%SuP-`@py`D5YOO$_G|I`FSgl#yHC*Xpkis(ia5 zH|4^=MB-m>aP|KhxNR$bUC=E)s8Rbr-)_IQrmSUZ6zl&oq8b0oX5%j4n<1wgTkh)S zdG+_@UpesQ-OlH?##w!Awa-2@{oC$*-gS2t&K)~B$ugMFrG0Y4ozYp&1rK6Qobvne zd{M^F?{h8kCr8a+abQW(<&~R6{`~gw^WIekNA<-0Ibuh=>{*b!wEpzRSC5hE>C7^kp%RiSR!3aXYAyy>g|5{6sO&QDUBcb0z%({hJ0k zn)lmA@OF8)gdXOMbXL*m;qlP0U+Q&cMR@pUxh*0YPJuh?U83esdhJ~yuBBznMArNx zv-Qk$RzAA#ecxj}aT{4bp9#aicPU8eH75;oiS|(+ajMBmOKYa|DEj7?Ra0XY6B!`0 zRDR;eSN5abz`V6;a$asB#WL7ObOn469l&%SsNU-P(sC06DlmPfbrQ$GKQ zq>&wx=R@L58_lhUJvuY=MRh21numC4O}5gmsQGP1SFW5mJ3ec--N2aEcFme}p+cXD zOAba_Iz8;Ud}(d}`mM94EKvFOPn#@1#q@~(1lOKLL+LX-#!Xk-v;1j_#_dDuQ9eHf z45ANy>k2thebFGwY;zJ%q^R1S#(VCQ)DxGAv0kPyF3TESD!==wd9IpTbW)NuD{|iE z!b@wDM#`){b^l-|BVe{9IyjZ*^Z;ghr|Hpwt8xA#t%OKILZx zcniY*HqUS~UfD$F*Kelu_cSf_ImcSE?_F_a^n$Xpi{|dAz0p=5BG4UT?eyU6BGE1P zL@K_2dEXtW8fUL31^-*!FgRrAaJuS?>Cf_UV2=l@(> z5v9Os78uTJ>eo~hxM1&FWBII44FwfG9vWh-Da-l}C+Z!~aBb1m_OrUNrKrMZJ(G3K z{HE=;*Lh1HUs{U?lI6aFJ<>j3=XWb~P{hwZ4 z-2FO_v2EKnKR-X0#{0tu%FZoS*TshltGmm8cz(Oc(AHLR(e@|zPo6rZt!rarlPs5- zKe*)f_NNyNqUJMHoEz@zdw8hg0t|)x0p-n^I|~f2th<=Dvp&OL*`eI}@{`i=iDN~& z6lfAH?8oE}Rf(5JmhjD(ajd(}?zn4H;phSSsDPlUVq#VP6NI{M@2H*sJZtxH84Zot z^_LB8oG=(OE!^$TZ?C(Z`nsCTHr%k#uZWzN?)Kq1MwWb}t*fcX{=r!R3KkP4>+6RX zkMHi^%_=U|E-Wlei&)@f`0>@fP=^BF(RCDMSFT)PJk;o&NaJ-ES-AE7!;Lo{1^mzu z6LUnSIQXrvD8k6Ln9a7Wzjsh&5RoIFQl59{N7t7hpYqpVStp~s>8|@ccMY*A!f~pu zBYaXeTrYoieREm3)L1L8?$K@Kr;Dn-ysw>Oe12Hu(Xmtb1O)usUhK|qd!X`KdgBcX zgnA&xX@^n}y!y19&E*wG$28nKC?s|8Yp2(jryDf}`&#-!LPMn%EfTP+JfpPt!*c=k z2}1L6gNqo)-Cj!_?^1LN7nYXo4dj!-{EJ@Qn95$4w2C*jGG0^M3Ny&AZ7qxF7QhUr zV*bLbW7XVdZ@M+x@L8(WLkv_2^SQFWr!BqZ%Ym|ZP0h%T$CuY<*z3#BnKS3fmGxuo z2Ku^LB8$eiL_3{JSa)%C-L@B*^L9MDR*+#`FhXv_wV+g^W&MbjQS#m0-F5vPm*d}7 zCytFQYiRGr$RaQ@yM|C!5{1=Gr-zpuDk4?8k*#lSt(JV{**?R|6BBB*^vg88Fwv&s zVE#JK?h>JN=~=VZVQOPFdMg(ogN6LZ<^EPKHTHhZQGHs4;imeH=r>%l>eREb??m$mPvYhZ0Id)Z?y4s#r z9(Jy0Z%}Y>!TT>K!&7WqOT&+zIyH^*o$S)FTEEKmWYFCR zGE0>C)O5w$;%0jj_{a8y}vo;%xo7vp!l-z8o!`mfJw5kgkk)$V-aa-it_at4pI^l!yO+;-gI$|51J_%#3Sj;{UOM^LVGH& z_Nd=}g#PPulD<0s`W$b8-y?>BK){#)FeG25Ad-Je!ESNDJb@ZkJfR zSkU0eh|zs*QC3rVwjS;Hjck-m_yFn03#%aeQCA9D0DC^gR>X$qL$HxG*R@vS~TS_4da(c zJT_gW2UB4iyX?@}tXBs@ZHfY_k&`=Pm+T8EKRq|1y1RvweiJDnVDgL*PK!-@Rh&k5 zF@K%@s#WLR+N;c*8?sk8wo39R%WAEAm5U5EMqNn3G6_RvV958)ay^t%^S;aFA%m8n zs3~UddZCN4>Y|Ewe?dyJ6<)lPq2~6cxa!rtgTIe7aEdrv|8?FW^V{16BF~&*C@ z&W1btLaFAz_Wm(1`gBa?Oc{Ss^P4AcyV!Vb$@7XXEnSsiU#3+RtCq93gYW2=Nf$5y zeb@?o*dv8?w|5B9SdzEgU5vrck~+>g>M%Iaukq!{`nqlP88V?l3hX_7T{f{)EJjZd zw3gp=D`@{K&p;ODrNHgs(!lT&CzhX~FjGSBu=H2AZ-fbIFE!XPG8phtQ$@lR&yLeYf z+{m$$(>%Iu<)Mgh$}$`(`ralUPs{DCQtuN%QP=hI(!ka)W?(T!kDqqGD%-WCi+RIB ztKACqWbcG9b_DX=bj z$v!!NxuQKit@=pQfpJ*v>O1>(umHGfZtvJg#fY^wW^p%r`flrMn{J2T7Hm0SEYK`$ypVG!B-GLFClw(?hR+-m5%8D0;=}@hEVoD7PYPk;Zep z`jzKxx@C<@Th~!@aY7_ecTev_O*>iy;icc-CNjdq!;w~|s$VvWzqC2a*=*VOw^FnU zaZ-9=kFJ?7kVoXPYbjCYVsO&3vc26LacsjGornb>kvL-Wmf1n|5qps?v-Z>h4Ka z`QF@1#Cw0A14L$rM0IQX(-2Cdm__R#o|N*^aH$U3R($;Y!V4THvay3)_Pl*00r_m~zlJz0(o z1fRC%?80%(iwN(5zLw)_;+CB5tiK6)D&DJSoI#{~K^<}v73QZ`H(s&GQ5L@UxyHcE zRKQ^M>hW9dx|b;LtWzY2sKczkvu|!B5GauZL|Bn*yq9l6iv4Gh3>!d8kogNKeW>8m zFj>XPo3rL)i>+jK@9TZDcFaV^VUV!-$#U**9>fIls_kTC9qv5*@4Adw@q?m|&le3g zc0Wqgn}XX3NJv?8M)AnE*FNIvsi@;VLqA^6S(n5!eeuqj7zPoanyA33zq|$#Yz%9~%R1D04LsOwYW>i^3(_7=`k8hVTsA=+MC-Ali z#3aP2TGmCZz0!4FUHRs^B`2@|_pbvfTt%gD(y!v}=>hlh%b5kjR zb;qNGk-AZz#^AO2UDGVnJZ?hkkxy0MI6Z z(=jl#k~8Z2=LZB?4}3}WDe3wA*a%ol9^1qI$*pbcdt*yF!d{G|J>|1Y4=#?x zTJ^x|D2 zsGP<6-OVLRW2T6$0SHh+q^I(|f2Q&C@*Z&jiTV8Q=>%D^ z<6|qZ@(gKmm))L?NOMqq8bEg>@~CW5f#|=SIp8S^DbPt zpm=FbbRnRv;@3~Fji7VqA^mV}K3o>sjTGnB-{YXmVyr+WNWTffK=7fs4CpEC$&D>B z<~JRiq>avLKraQO%ijM<%xBfFR5f?WfrYy59C4?{SN9;K^UH!{NRx18mS#OX5{qiL zx1(k>?lGl@XycEsyS6_~DM9j2TYvAsKJ3eY?yoO)FF=rhYP%EfV~J~?Q+e&hZw1C& z^7iRfA!4(tUVVxtCMI>kELL$c?&n43uEafU<$$#O>a-dt_CY~G_p9DLy&8P%SV_i# zFWX}gyRO*ZEP(gHQ<1ukP0bSD9QH0`pXzBN_21CaqiM8vf1A*r_NoW{z3u51clHJ^ zJM`Tce1;u1BQ$;2i^a~b^NywOtXJ+dy}IETGP|wtlD)I3I#*%t(m!`R4g^o}Vy0Tg zEj{=ZmBj$lO2nOpItOw>{?D(|DLc?`5eYkA6J{JkLz96njAN$$)c)gr%n2aiB9ylfUWs-~z^2m*debiPFSf-S^L~7u6Q}PY_mhnF+FV(dpqi zGZGBqkf3jR|2$yn-S6PuS$8D-)G5EXxf^eE4gUCK*IIr$6y&HS$)md&`ARGi_&{4* zyRj7@Iqo@Su*&1Zcq7Kl6qUxIbuaY zVPTi_j*In?YCwCd21JO;YaF=LRAJ%Z@I^Z|kuBZ3}b^5 zejiTjgBT$xgserr_l%V^tkb~%)u8Y!WF#BnQ31aOR*pT{@#G5s@nzp<6F6c3P2eSe z+zJU-kzn2tz_GuN|1{=KnLrVAxj%2C95P4xHH#d+-zPwaY3|WAQ(_?I_bH$W5&ZL6 znvl?ceJ&;BkB{X}*1ykS$y!GV-?qD-@)C)!5c)TYUuKW|CF4ENt;a$ipgP;t?uJE< zZ}(#(&8GL*fw|w`U8UG&BR{*Y%Y>LGG~eQWRPFnVR3*3E*_(jWzW3b|N-Wmx;3=d} z5eb>I{!*G}ucMr4^5HmC^TRYqBP2a}Aa zJ&J1U$A+9DK)&>8b2qTCd+n$XW<6))4N+O6bHxP10Ajc;QIeSm1ru^hJoxP+6eVz4 z7HKvlf`0z^GNw9F&(1X2csQsv#4i-v36a1pXguCI@I~&>_s<2C%(O?TgOOMxHIdxJ zZs~4JLR9=?uaR1H6IG)9d5}J5&YCr*0`dmWgb7lK;Ddl;Y#{Dc&|e|eFtBN5Af@)9 z^a%<71UyhB^rQLnGe0|AN^iD#hIAf8Kz4IUD2lw4Q&lXnXVgU~rGBZ6(y2;U}`)(EqRXF=VLg@8BKz{z@i zV_VZ3$%wjrU*wR4N|g7suCnxO6Yv6ynUn}6YT?ehsTC1M%Ysv(;YCzqYLW8`st_L0 zKsan@Xoh7cWx8*B_3x2)b#*1w)mrZqUs45R-~BY#)2&llTKW-qIZ1h{{jCv3X=~1D zL}TntNz0FnU_k!449=lSB}irWt72vU%7V4C(ncny*^U3K^(n)z#IE z$Cr&RV`P2fX*%&Xh|EXgcIWj63?Dhh`kGb#IZUyazrVi?mOL2gIDP*oOVIz-*Eiix zYXL-}f_`V;`?rrTPgxl_xugnVK&(TX-BeEKV_jG3LMBJJYlppd9AWc9lnYviT>*IAcNn8@n&p>H!#w$U1y)mjmCyevYNIwY5j;=|&g<*=YUD3MwzIIkRV343#_ zI}y!`h#z{pI*?i-iM2qMj^(H3s0wR%D3UsnjY4V&;Ih`jLR1%PL_o}Em67aCm+*19 z!*_;-7R_FNX<}Zc^UIJ_#BI}i$da?rWnxh-nvq&tF;?7*ONjcgsDc<^u}5>T>=_MD z<%_FNHv>Y{sX=~;q~NHGRg0izfm5O1I5U!TK+n_MK=MfgC6SPja0K-FleifhuOA<> zK=4P)Vo%*yc5T)MfGZKNd0ZynV9&=C_lbqd*l7wZ#ag`k72?^m^eqzpsd<|PE3mt_ z)+CKHggE0{outn%C~tN+?t)IJ?L_fqvB;QqqD%JjsDpc*_x|}EDV9jP8_25eaWTS2 zgeyz8qAgR0mW-67BK1N~b)$@dk^KI7xQX6f9#kFVZ^y)p%jp(9pgI z?7KX2-t?3Z2UL1mP{_N$cHt&qJBV(OfH4(*slS9h~TPmQ(rnG^skI{ts^g=Zz^#7`4lq}#aeuEKqgtr08NB0xK$#VEydI76VZD zXjNCqUsDR%&NRhzoI11%Gs?o4_Tv#6o;}tR8H$GyA&vHr&aa@R1p0Sk3%5TB8VWyW z=-Bj+c80Fy^Mxd}bg|ou(P?@Bj&)o@((Ihipy%WnOZ+Y(-BMjTQJwYLJJbQpjg&Wd zSuSFhz53gto+O(bMNp*!{iCL8r`w{id7+VU3=}{_#kmqidJfV*G~5;1UHi~A^STGb zSJzROE@gG-i$LVtw_9V0;8kE#yY4~V2O;#YKEGn5ZkT8=L?h_2fA2Bjx?Lj7{rpaZ zL;6odHih`G5DE!I>mU-Y*vG|>N1$VnX2+S#;+4{!%Fll^)zGRL zLEKbo)~oJl-=_AZ+ZEe#YXE+$(NzT>Oyz-JzAtm=uuZ|%) zKN{cO&Sc@IH2}{zbofp@B?qC?pd$8Y$KsT?5NIAeiDJ<@Wv8pSgl^ql*Ga^fOld4Glt&6C& zXuKUI70U_Qg1lw!88j&Jh6WF^aD%*JVqtNz=R8Ij*xO4}?I6Y2(0{yuBB&Av@}o-) z^t-&i<_Rn?Pnx#a+@D`xpfP0&WIx#lm_b+7B{(oXv{F*q4;bk&qzvT)=z^8K#bmNX z)%Xmwv__z!)|oJokdK;VyV!vG2U9QErkKOAqgIXk;+=KNA>RPIBtp7o?0fel!7Saj zj^?8_)r!+Ya^VH-ah(&VFP>PTCw|B;0`RD(M99k8YoMEBdVQ0C?4ciD+hTU-6{xzs znK-!6xq(sPe7~sZ;o4d0@7|ico5DEk@LT`Us;Q~T454R)GT^c<*TYqw(3~M@2v~XA z##lDThHTe5wL{+*?#}HV!v-N?DBJVU{19Pm8EurVce26(aNLM0Rak?eFnX-@%$nP+2tbpU9-F=B1^Br zG%`T7q?DEUWJivfcs~Qo^4z#7D3oqiP^+dOO2_%tzL%K_2f%W`&)Dq#tm%h-oZQj6 ziuK_|Rs@;;0Npt2kb=id7F~t+xT697kop>5KfW|T`dMXYI4cp7rX7akPc2O#GvYZX zBOrR&F`JJPTUrb=@r8mypIli}=ue7!l@R{_R__TZki3BcZO&4DT%~ zh5zi7f|VFe|8Flz*Vfgw_4?j%dEvGiKU_=RGF7MoqB{d%c79YSfMzdHYtaQAx`5}@ z)LMg?@P{4gI&g1P;rlNz+YHLgnG+nyTs%0h79bkh`Q@$E7o_2jB-cVD*g`avH^Rtq zP<49Im$f5!sjshZf6Hgcn~*32TwW4g2l!RI9#B(zlE^}81Y6zR|B3p^3@DZx;`7LaD{nQFpsbW@EH+QXgOLtlld4N!VQqK^7NB--y8=yT27{n{{0RIQ6}`Le#okpwXd%g}RD zb!{HS#s|CHeW}X52>RSb0h5X#GdU%1x-G{}vnfj6a9zY_HNmi61*o#EHc^XRX6`@m zRXXwW=e^YSrW6OA+cg8TiHsC@5ox3E&Y>TR5i=as{U0%Fo#)ZuWKCC@Oi<^34`8az z=TEQWIbsJVTBVdjvsFadD~3o@3hL8V5yhzmb?OTG(PY|{!rNiD2E+RZ~h+?!iklm@?M<(njEjqXgALwvP? zewp5|h{lB3=`qQdW0mK{Kr$!ccHsDlsq+8m(Tzo?#xA=wi3E`_v85rd00$)2L;$JT zkPJoGyAo5n4NL3xrcwe87pe;CNT~M6r3^IGib>!_bFZ)p1-hG=?|rC~OemxyfRxp# zVF{6k3)f-1vETql0S9eSqZmG7hd!II0P9YGQlcu)V{UB=L^*di=9)o;PlV-D$ zM#I8X-rUo+8j~liWIM_o+>PsUxd?(@hdr1;vIXE*67ZU;+JVor335nF`=OPz?)>uM z)>z@W_%nKpIjKtB49Wb$is2)&v_D6oxwL1!Q2LTKIw98BUb zSj2^tYg_I{!l2T$1AQl8n=y8Xc;s^tLSl*Fc9k(IQ+%K?A2WgAO-f8e{y>|8#k~Up zEs!|tutsJJm&S$IPoA$F`gw12b8}kmmuH(*`=M!4=i?kUW8++;W};9~SEd`lNt4!# zev8{@RQsn_^#D3Nds>?SZtH-7tT&q&#qGNg0q%8t}nL zAEI9%*M>lt{qL@(x=fQ~tJ zIoUu4r2QL0q)i9=3OL6JE6DY144Xf!nzJrG>3%IFB7MdeGvVXXX?JEyQSZLV$33PUT-wjG~GG>icd>Dbj+ zV87V;BmY0S>tkE2ULBZ_%EJ}Z9Kg*<8n7BWS@eDn)N{MNpI*hCI5E`=Ry|+r0PBgO zswYTaq!xDHIwn4jjm&Tbom_wmb~YOKlDyddM{(EMGCx;B0;v9P4tM;f zOX_SAF(j1f0GkQ{Gb^+#+R%77|I0icjPX(`MDwg`AN&(U4;(Nd9?v4di8Px|G~mP% zftJmXTms`@82tY2lM%vlE9Q^1$trwKSSs0$2zwJsH6-3h0w|UwP!pPOQ4ib-cI~Kx zw|3M{HUP+S?fFt`Wfu(7@rg->*U(lgdaYtUhGye$7if1E+=!6I(^6h&~h?jD7GW zudlmy)2G{K+m_51j#_+0b+umMsyR!#>yDN?isf{QzLCDN<(OZ+(~HFLwd-a_Ne35} zswUssv8SWmIdPVH`MH-Lw3E6M6>}E#=hc3z?(1e{a;7}00?_M@J1!OtfHbNZvU$UWC&6?r%ju7A|m2w%!Lb* zqM5twSPZ2RDw+dbBdO`ihAGpPwv9dI%xcu8u9|c^z10Q=)FwO@pPQ>8I(qbI4`Fyu z!%&xaCkJ+)jE)Xgf`TCq+qOdWaW3v{c7ojl1$E-!k1kDHt8O}BPK zG9$Y-7mp*x%q=k|brMZj0|Q>?yuWXw@&JU!ih^&mk-9vnBZR!9p`ZVt2zB-9DU;Ps zG-)8$(5X|Wti8}J$G>y&KkMMfoIntaW*L!V%>)d<9qt>T)2#?fW#sHU-x<2u+rDR; z8L7jMwz$gO5m0malno27x?SFjzkPTyOK{pu_NG78Gx{5+> z*N8H_R{twxmTtso%NfWo)M$Qyt>+19p#+-+z{I{Ta?Og8p^FPT5|fjIKzti70%nRX z^E!jlm4W_ngV)f{Z+koIcO|FaLizL4l4!tOiXLD3l~G?`?@{*fVLMi&xbE(L1!vrq z4xo~2?u3C!*{?FMR7%EPPO)I6oE*=T5lC4rXDXn;TeV(BQ&XG+Nt!3HC|RzI9NQPr z3K+wbsfS#?9NLT$8Gy>m%RS&^dHW(uAthubQwiMLUrIq?N=un+ytI_mNIXOzhq3EF zLEE&vqQVuW5YU#faO>2t%E~pODXT9KvWL8A3xIT-l3=o2F#OZ5_D)U<(E5XG7M-Jt zGs+I**-(CzOi$aRTuD~jHy-e|F;ABBHa%^cEO*72xh^5aVvV1H_FI1;ZZQMGBL|o> zsfInhy{<$UpQKuet8BDz<<Lm`mT>6$7wis{xCp2Ap6X#8g!pTt<@UX#_FXg+H{! zin5^KxjbI0(sT(i#)#VDF045;u;AW}+>?Rmuedc+9JdGaSaOdUa*yTxIy}fdh1NcM z$k@zm6+o5idJ~fs-rmc?Iy-mX$ay1j@`@a2^Gaq1+z}+!;%@9A#Y(SZvQT<6uu)l{ z&=g+h4!oNKZ31muhNRX)5gCY?M-}BOB*TLgJ-V#9fijtjohWpug3<>M93Vq7xZWLv zTA|6+4f8;^;G}}cnt1IRD^TnJk6zULEyh#|t6{8MHZ`|Juza1>aEl4K-eJ& zj@6_MP1Oo>QuKh@&-FKD!!R?=GGfOcqkX_aE`$@>F9tp~V$rTonH#CA1=v@PjNVkO zmvf&sh{XuY5dmM`b2KqF2T(Rr3RE*PGF&1eB8up`Xw-roGbjaH(!#Lb-?$rASg7TE z_rqcm`Z6{<=lCDj9AxNOT8dc`Rwfa(?+W5mbFfcp?b(Gku!dx-L1+i@C{B0(u!+nO zQJOzHj8sW8jzLjQ2MyYkxl@1JwmDEZ+pwWqV^J} zf{EMDo_68Zt!at3Zk?K-B{4s3m)uQ7O4bV0_vwDLa!M2G`l5l4`|}gQzDVb^`~0?= zJ~TV0Epl@mFg=>YO(cZRR#1?whlpjCxl=d{Hbin*HUKEi;GlbZ1rX12&z?O*8!sS>=vmOjJw>EoM=4Mbw?4 z^_QbG=e$d~T3TLScxHjqWRl^yumadA!I~q!IDZdc zgOz^eH@2;>%bKz?#-6-eX8?LoprFWXfDcymq2`bVb=PHO$Eu)5V1o`313m%=DE5d| ze+b*r+H@p~dJ>pX`ZwI1dlrv+0qa%PkIOT9V zWOBLz1)?xF?tUyx$NDvZh>q4XG2#6^&vaG_&l_F>(=zHo=NJ_IYlSM0RucoG^YAV2i(Sgtu8xeX2j8PY$18>5vkW^Qn&VeB2w-Ps< zs5`0Z+){(98?Kw(+R8hbDPw}2Opc;zs5dBUIyySowqrQBiZQc+jIa&+YPYCDLJmzi zc`YsNggtIshw0ke7%++Pt!qMs7PC7sB}t2^?@z_M%~sOX{g_DjH6+j2r3VG=sxRnd z2bb6~rf75x!_u`NXdR$Ucx;1?ABG-;iK(eJ0xlR7KnKnDRZJ8wRhYV{JiW-;eK|K* zRE2ueq!xIfcnUA`Qgw!9tPC7oiBA0iis(x76%aaeA>#Efg;{RC#yt&oxRCs|}=CL3}$4Un5>BmeqZ3+o$#QZ`6Z8@W|Ta1*3 zU~S1?#R!ttEc5tfhp6r}ApzPK2k}ZT!9fN|oa71O34=Wll5|YwakwVBAqN}Sr203Y^_NrS>55*`c&XmmVZw^&( zDLx!9AStS=?ef>^%r(O(L^{}LCwD3j zm(qq9=)#Xwx$qaL);Ha-K^MD;`*YJK5oeNYkU#vpk)&HL;zkG6dL$ zc3uNNzu}t0I9v9=)X5-UFZkw&mSEX)_syWmk_+zvIJi+pLxTn1>8Pj$&JC)p>AQ1z z?O;!|fR8P^KHY9CnS0G{I!+=EYOrF(@G$V4mbRSsb4A^i3m&?F4>dcyeUvawNT`Ke zoX%*#vTV!++2Vs;V+WEhUIeHZx@shz;(Bh^`e>cx&YH(+<8N)bE2!t{s#J!S;#xljRY&v9v&`(4*puS9u^POO_6~OMt$3(MH z&(l*4eU!^cE*_Lr5K)duu^u_iA#+^-)q#YL#+bWF!b5EP0?Nk&e68*nW9*&;%+(L(fRv8%JQx@PrpeT9Q z0nAn~^}j~t4~*tu0X$$_F=6J?9;c&SAa$kBu3MZ(r9`#oRwq!)@)D%T$>OujaX%#e z6P>Hi^;`hchRlKm{3@t_q=OmH_S^M>Bzf>Az7ks{RPh68+n>t8m0kcs+O-FAw{!ka z_rfMc>QsXO6|I#Ql&Z!CqT_AOH}1TX6NP|jap=oa3RP8T?OdrU1}Dx!Aj8_?NbYH0 z-w^}T1O=6G#9T6*43Y&*>B8S;n71I5s>!eV^k=@;`1xt*0o5vW@y4J{#iHX&VxFzM zEGPo!i5l4f#7~3~?bj_ZlzgFxfFPZLnJ*0c%%-)yy=5xzNuUXy#PjD5-?7tRU?#&2QWGDhE1WtA})Tkoc_l6CEVS4yu4X7<- z{%D{RL`YXNa9jsvrv%+Jpc&#-Ko6~LZJ6oJf@s&Hi3Oa33O23f&iflwHkLE>1yR&Y z0W2WOyFNyLfI3m+G*w=(pu6YC>!EYV&UVGNT%{li$hMixtls3dxRF12fJD&nn3&L* ztqVhn-UxN8o;E*Iej{mA3n$)((hUP~${{ygF41r9%7W&vT8M=Z_4M?F*i?BQ?op4N z51B7iVF?CSB&{jioLcB~7%m2_<23Ln(HTqj-md_uj9zwViLSgLZBh?93qq%{$*15= z-a+n=05f8NLno^sNF+=&zpPGVbimpj4*G|DPAw1OGzJSrN{9^8Dsdwh3ILJr z6taIi=k+`0R-Ri*+ih42AQaUdat7OAalu@}lc`lV>5@M?rdMYJ>TW zCYiF1CFERo{?LznJ1^*HK|Gd-6MgvZUFo!3w(z3u)4+a;w=zPzn~XHO=X%>vahgAT zL0=%if(_QL>0)v+j~*Z>9S>T40S)Lz2D+Ll<-l(!*$2DUZQ4|x?b@P9UY?ktzT-pp z(_x2TfvvPSBIF1z=m9Ktt%oEaN+=O4=Fy+!^FxIN@rQiTxpkRq0r&M`!jd|<>*XEt zaNFA3+jqU(?Ol|r`tTQ_)*TkQ`IdEKdpunTCL%r5Kxe3>VUQGiYx4(BYa`%VpcOkI z1AnY1}GlEr(Oja@9najM`{9u3OdX=c2NmGb=R*CTiK;8@Rx z`kSoOjmLeL?3*bT=powdx|3P>$l|BFDU+*|GhF z^^3ZW4r~0Nuc^n6?s5y;b#&L`qD-Y_$(A$l=N5KO=YGYw?Tpbo+|}`z@m_wy;NbqM zbc`F{#L{-zHYtwm*U=wWx43Sx^VyLGhn>4scRnvJ@jEPgME2XKz@I<5l|}oe^?mI$ zXZa@TCFF`~&lC+<LAonOIp>Tvj1R!ym&lkfL&M{d zp^=g7ym^!Up5Sq74oRkau-_+_h0l)Feo}dL%bj+BxF3MNC~io{%8uX$>@p^ z`0@=IuX<3h*%ja9Czwizjb$49dx%z@8_nc~f-w(b!XLvm=BcS!K5G8miMC2Xy21+_ z#v4Inpgv5k<-vJeeRF`TsB$^m|Bxi*BZn_59$9{W{h8%6 z8|SQxk88KvPrZq$f#|Np*zmt1~dng73D|F6Vhp{Ia=fCbCJJgG24ejQ|n zD{1nfrigkuG&=+$9m2;~WUTVX(<#tYLeu~Lxqo?UXusyZi-zkI?K(a22P%i@>lkX^ I(6aXZKb=S7B>(^b literal 0 HcmV?d00001 diff --git a/__tests__/ssr/snapshots/rough-rect-stroke.svg b/__tests__/ssr/snapshots/rough-rect-stroke.svg new file mode 100644 index 0000000..a7cb1bb --- /dev/null +++ b/__tests__/ssr/snapshots/rough-rect-stroke.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/core/examples/main.ts b/packages/core/examples/main.ts index ac547bc..cd5b409 100644 --- a/packages/core/examples/main.ts +++ b/packages/core/examples/main.ts @@ -1,3 +1,4 @@ +import { set } from '@antv/util'; import { Canvas, Circle, @@ -32,21 +33,18 @@ const canvas = await new Canvas({ shaderCompilerPath: '/glsl_wgsl_compiler_bg.wasm', }).initialized; -const rect1 = new RoughPolyline({ - points: [ - [50, 50], - [50, 150], - [150, 50], - ], - stroke: 'black', - strokeWidth: 2, - roughness: 2, - // fill: 'none', +const rect = new RoughRect({ + x: 50, + y: 50, + width: 100, + height: 100, + fill: 'black', + // fillStyle: 'dots', }); -canvas.appendChild(rect1); +canvas.appendChild(rect); canvas.render(); -console.log(toSVGElement(serializeNode(rect1))); +// console.log(toSVGElement(serializeNode(rect1))); // const animate = () => { // canvas.render(); diff --git a/packages/core/src/drawcalls/BatchManager.ts b/packages/core/src/drawcalls/BatchManager.ts index 81d5d3e..ec30120 100644 --- a/packages/core/src/drawcalls/BatchManager.ts +++ b/packages/core/src/drawcalls/BatchManager.ts @@ -205,6 +205,36 @@ export class BatchManager { uniformBuffer: Buffer, uniformLegacyObject: Record, ) { + const geometryDirtyDrawcalls = []; + const materialDirtyDrawcalls = []; + const geometryDirtyShapes = []; + const materialDirtyShapes = []; + this.#drawcallsToFlush.forEach((drawcall) => { + drawcall.shapes.forEach((shape) => { + if (shape.geometryDirtyFlag) { + geometryDirtyShapes.push(shape); + geometryDirtyDrawcalls.push(drawcall); + } + if (shape.materialDirtyFlag) { + materialDirtyShapes.push(shape); + materialDirtyDrawcalls.push(drawcall); + } + }); + }); + + geometryDirtyDrawcalls.forEach( + (drawcall) => (drawcall.geometryDirty = true), + ); + materialDirtyDrawcalls.forEach( + (drawcall) => (drawcall.materialDirty = true), + ); + geometryDirtyShapes.forEach((shape) => { + if (shape.geometryDirtyFlag) { + shape.preCreateGeometry?.(); + shape.geometryDirtyFlag = false; + } + }); + materialDirtyShapes.forEach((shape) => (shape.materialDirtyFlag = false)); this.#drawcallsToFlush.forEach((drawcall) => { drawcall.submit(renderPass, uniformBuffer, uniformLegacyObject); }); diff --git a/packages/core/src/drawcalls/Drawcall.ts b/packages/core/src/drawcalls/Drawcall.ts index 9596a58..c585d0d 100644 --- a/packages/core/src/drawcalls/Drawcall.ts +++ b/packages/core/src/drawcalls/Drawcall.ts @@ -9,15 +9,15 @@ export const ZINDEX_FACTOR = 100000; export abstract class Drawcall { uid = uid(); - protected shapes: Shape[] = []; + shapes: Shape[] = []; /** * Create a new batch if the number of instances exceeds. */ protected maxInstances = Infinity; - protected geometryDirty = true; - protected materialDirty = true; + geometryDirty = true; + materialDirty = true; destroyed = false; constructor( @@ -47,20 +47,10 @@ export abstract class Drawcall { uniformBuffer: Buffer, uniformLegacyObject: Record, ) { - if (this.shapes.some((shape) => shape.geometryDirtyFlag)) { - this.shapes.forEach((shape) => (shape.geometryDirtyFlag = false)); - this.geometryDirty = true; - } - if (this.geometryDirty) { this.createGeometry(); } - if (this.shapes.some((shape) => shape.materialDirtyFlag)) { - this.shapes.forEach((shape) => (shape.materialDirtyFlag = false)); - this.materialDirty = true; - } - if (this.materialDirty) { this.createMaterial(uniformBuffer); } diff --git a/packages/core/src/drawcalls/ShadowRect.ts b/packages/core/src/drawcalls/ShadowRect.ts index 231b067..dcbf5bc 100644 --- a/packages/core/src/drawcalls/ShadowRect.ts +++ b/packages/core/src/drawcalls/ShadowRect.ts @@ -16,14 +16,17 @@ import { TransparentBlack, StencilOp, } from '@antv/g-device-api'; -import { Rect, Shape } from '../shapes'; +import { Rect, RoughRect, Shape } from '../shapes'; import { Drawcall, ZINDEX_FACTOR } from './Drawcall'; import { vert, frag, Location } from '../shaders/shadow_rect'; import { paddingMat3 } from '../utils'; export class ShadowRect extends Drawcall { static check(shape: Shape) { - return shape instanceof Rect && shape.dropShadowBlurRadius > 0; + return ( + (shape instanceof Rect || shape instanceof RoughRect) && + shape.dropShadowBlurRadius > 0 + ); } #program: Program; diff --git a/packages/core/src/drawcalls/SmoothPolyline.ts b/packages/core/src/drawcalls/SmoothPolyline.ts index 956c36a..ac2da00 100644 --- a/packages/core/src/drawcalls/SmoothPolyline.ts +++ b/packages/core/src/drawcalls/SmoothPolyline.ts @@ -117,7 +117,7 @@ export class SmoothPolyline extends Drawcall { shape instanceof RoughEllipse || shape instanceof RoughPath) && this.index === 2) || - (shape instanceof RoughRect && this.index === 3) || + (shape instanceof RoughRect && this.index !== 2) || shape instanceof RoughPolyline, ); diff --git a/packages/core/src/plugins/Renderer.ts b/packages/core/src/plugins/Renderer.ts index 1f0bafb..51382f8 100644 --- a/packages/core/src/plugins/Renderer.ts +++ b/packages/core/src/plugins/Renderer.ts @@ -250,7 +250,7 @@ export class Renderer implements Plugin { this.#zIndexCounter = 1; }); - hooks.endFrame.tap(({ all, modified, removed }) => { + hooks.endFrame.tap(({ all, removed }) => { // Use Set difference is much faster. // @see https://stackoverflow.com/questions/1723168/what-is-the-fastest-or-most-elegant-way-to-compute-a-set-difference-using-javasc // @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/difference diff --git a/packages/core/src/shapes/Path.ts b/packages/core/src/shapes/Path.ts index 4fd68c9..ae023fe 100644 --- a/packages/core/src/shapes/Path.ts +++ b/packages/core/src/shapes/Path.ts @@ -34,6 +34,8 @@ export function PathWrapper(Base: TBase) { batchable = false; + onGeometryChanged?: () => void; + static getGeometryBounds( attributes: Partial< Pick & { points: [number, number][][] } @@ -84,6 +86,7 @@ export function PathWrapper(Base: TBase) { this.geometryBoundsDirtyFlag = true; this.renderBoundsDirtyFlag = true; this.boundsDirtyFlag = true; + this.onGeometryChanged?.(); } } diff --git a/packages/core/src/shapes/RoughCircle.ts b/packages/core/src/shapes/RoughCircle.ts index eea3c5f..186aba5 100644 --- a/packages/core/src/shapes/RoughCircle.ts +++ b/packages/core/src/shapes/RoughCircle.ts @@ -14,7 +14,6 @@ export class RoughCircle extends Rough(CircleWrapper(Shape)) { // cx / cy / r also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/core/src/shapes/RoughEllipse.ts b/packages/core/src/shapes/RoughEllipse.ts index 0166d42..d0388ee 100644 --- a/packages/core/src/shapes/RoughEllipse.ts +++ b/packages/core/src/shapes/RoughEllipse.ts @@ -14,7 +14,6 @@ export class RoughEllipse extends Rough(EllipseWrapper(Shape)) { // cx / cy / rx / ry also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/core/src/shapes/RoughPath.ts b/packages/core/src/shapes/RoughPath.ts index 161c1d6..6361541 100644 --- a/packages/core/src/shapes/RoughPath.ts +++ b/packages/core/src/shapes/RoughPath.ts @@ -10,9 +10,12 @@ export interface RoughPathAttributes extends PathAttributes, IRough {} export class RoughPath extends Rough(PathWrapper(Shape)) { constructor(attributes: Partial = {}) { super(attributes); - } - // TODO: points also regenerates the drawable + // d also regenerates the drawable + this.onGeometryChanged = () => { + this.geometryDirtyFlag = true; + }; + } generateDrawable() { const { d } = this; diff --git a/packages/core/src/shapes/RoughPolyline.ts b/packages/core/src/shapes/RoughPolyline.ts index 1038b8e..27381a4 100644 --- a/packages/core/src/shapes/RoughPolyline.ts +++ b/packages/core/src/shapes/RoughPolyline.ts @@ -14,7 +14,6 @@ export class RoughPolyline extends Rough(PolylineWrapper(Shape)) { // points also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/core/src/shapes/RoughRect.ts b/packages/core/src/shapes/RoughRect.ts index 15e3b01..7ecd51e 100644 --- a/packages/core/src/shapes/RoughRect.ts +++ b/packages/core/src/shapes/RoughRect.ts @@ -14,7 +14,6 @@ export class RoughRect extends Rough(RectWrapper(Shape)) { // x / y / width / height also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/core/src/shapes/Shape.ts b/packages/core/src/shapes/Shape.ts index a71d7f9..cc32c97 100644 --- a/packages/core/src/shapes/Shape.ts +++ b/packages/core/src/shapes/Shape.ts @@ -49,6 +49,11 @@ export interface Shape materialDirtyFlag: boolean; + /** + * After `geometryDirtyFlag` enabled, the preCreateGeometry method is called on the next . + */ + preCreateGeometry?(): void; + /** * Hit testing. */ @@ -111,7 +116,7 @@ function Shapable>(Base: TBase) { child.transform._parentID = -1; this.children.push(child); - if (!isUndefined(child.zIndex)) { + if (this.sorted?.length || !isUndefined(child.zIndex)) { this.sortDirtyFlag = true; } @@ -132,9 +137,7 @@ function Shapable>(Base: TBase) { if (index !== -1) { this.sorted.splice(index, 1); } - } - - if (!isUndefined(child.zIndex)) { + } else if (!isUndefined(child.zIndex)) { this.sortDirtyFlag = true; } diff --git a/packages/core/src/shapes/mixins/Rough.ts b/packages/core/src/shapes/mixins/Rough.ts index 9677451..d92e377 100644 --- a/packages/core/src/shapes/mixins/Rough.ts +++ b/packages/core/src/shapes/mixins/Rough.ts @@ -204,7 +204,8 @@ export function Rough(Base: TBase) { this.#fillLineDash = fillLineDash; this.#fillLineDashOffset = fillLineDashOffset; - this.generate(); + this.preCreateGeometry?.(); + this.geometryDirtyFlag = false; } get seed() { @@ -215,7 +216,6 @@ export function Rough(Base: TBase) { this.#seed = seed; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -227,7 +227,6 @@ export function Rough(Base: TBase) { this.#roughness = roughness; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -239,7 +238,6 @@ export function Rough(Base: TBase) { this.#bowing = bowing; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -251,7 +249,6 @@ export function Rough(Base: TBase) { this.#fillStyle = fillStyle; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -263,7 +260,6 @@ export function Rough(Base: TBase) { this.#fillWeight = fillWeight; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -275,7 +271,6 @@ export function Rough(Base: TBase) { this.#hachureAngle = hachureAngle; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -287,7 +282,6 @@ export function Rough(Base: TBase) { this.#hachureGap = hachureGap; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -299,7 +293,6 @@ export function Rough(Base: TBase) { this.#curveStepCount = curveStepCount; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -311,7 +304,6 @@ export function Rough(Base: TBase) { this.#curveFitting = curveFitting; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -323,7 +315,6 @@ export function Rough(Base: TBase) { this.#disableMultiStroke = disableMultiStroke; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -335,7 +326,6 @@ export function Rough(Base: TBase) { this.#disableMultiStrokeFill = disableMultiStrokeFill; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -347,7 +337,6 @@ export function Rough(Base: TBase) { this.#simplification = simplification; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -359,7 +348,6 @@ export function Rough(Base: TBase) { this.#dashOffset = dashOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -371,7 +359,6 @@ export function Rough(Base: TBase) { this.#dashGap = dashGap; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -383,7 +370,6 @@ export function Rough(Base: TBase) { this.#zigzagOffset = zigzagOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -395,7 +381,6 @@ export function Rough(Base: TBase) { this.#preserveVertices = preserveVertices; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -410,7 +395,6 @@ export function Rough(Base: TBase) { this.#fillLineDash = fillLineDash; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -422,7 +406,6 @@ export function Rough(Base: TBase) { this.#fillLineDashOffset = fillLineDashOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -479,10 +462,7 @@ export function Rough(Base: TBase) { }); } - /** - * generate rough shape - */ - generate() { + preCreateGeometry() { const drawable = this.generateDrawable(); this.drawableSets = drawable.sets; diff --git a/packages/core/src/utils/serialize.ts b/packages/core/src/utils/serialize.ts index 2e63bbc..2b2cef0 100644 --- a/packages/core/src/utils/serialize.ts +++ b/packages/core/src/utils/serialize.ts @@ -722,7 +722,8 @@ export function toSVGElement(node: SerializedNode, doc?: Document) { exportInnerShadow(node, element, $g, doc); } if (dropShadowBlurRadius > 0) { - exportDropShadow(node, element, $g, doc); + // RoughRect has no element, use $g instead. + exportDropShadow(node, element || $g, $g, doc); } // avoid `fill="[object ImageBitmap]"` if (hasFillImage) { diff --git a/packages/lesson_013/src/drawcalls/BatchManager.ts b/packages/lesson_013/src/drawcalls/BatchManager.ts index db54df8..ec30120 100644 --- a/packages/lesson_013/src/drawcalls/BatchManager.ts +++ b/packages/lesson_013/src/drawcalls/BatchManager.ts @@ -32,28 +32,23 @@ SHAPE_DRAWCALL_CTORS.set(Rect, [ShadowRect, SDF, SmoothPolyline]); SHAPE_DRAWCALL_CTORS.set(Polyline, [SmoothPolyline]); // SHAPE_DRAWCALL_CTORS.set(Path, [SDFPath]); SHAPE_DRAWCALL_CTORS.set(Path, [Mesh, SmoothPolyline]); -// @ts-expect-error RoughCircle is not a constructor SHAPE_DRAWCALL_CTORS.set(RoughCircle, [ Mesh, // fillStyle === 'solid' SmoothPolyline, // fill SmoothPolyline, // stroke ]); -// @ts-expect-error RoughCircle is not a constructor SHAPE_DRAWCALL_CTORS.set(RoughEllipse, [ Mesh, // fillStyle === 'solid' SmoothPolyline, // fill SmoothPolyline, // stroke ]); -// @ts-expect-error RoughCircle is not a constructor SHAPE_DRAWCALL_CTORS.set(RoughRect, [ ShadowRect, Mesh, // fillStyle === 'solid' SmoothPolyline, // fill SmoothPolyline, // stroke ]); -// @ts-expect-error RoughCircle is not a constructor SHAPE_DRAWCALL_CTORS.set(RoughPolyline, [SmoothPolyline]); -// @ts-expect-error RoughCircle is not a constructor SHAPE_DRAWCALL_CTORS.set(RoughPath, [ Mesh, // fillStyle === 'solid' SmoothPolyline, // fill @@ -210,6 +205,36 @@ export class BatchManager { uniformBuffer: Buffer, uniformLegacyObject: Record, ) { + const geometryDirtyDrawcalls = []; + const materialDirtyDrawcalls = []; + const geometryDirtyShapes = []; + const materialDirtyShapes = []; + this.#drawcallsToFlush.forEach((drawcall) => { + drawcall.shapes.forEach((shape) => { + if (shape.geometryDirtyFlag) { + geometryDirtyShapes.push(shape); + geometryDirtyDrawcalls.push(drawcall); + } + if (shape.materialDirtyFlag) { + materialDirtyShapes.push(shape); + materialDirtyDrawcalls.push(drawcall); + } + }); + }); + + geometryDirtyDrawcalls.forEach( + (drawcall) => (drawcall.geometryDirty = true), + ); + materialDirtyDrawcalls.forEach( + (drawcall) => (drawcall.materialDirty = true), + ); + geometryDirtyShapes.forEach((shape) => { + if (shape.geometryDirtyFlag) { + shape.preCreateGeometry?.(); + shape.geometryDirtyFlag = false; + } + }); + materialDirtyShapes.forEach((shape) => (shape.materialDirtyFlag = false)); this.#drawcallsToFlush.forEach((drawcall) => { drawcall.submit(renderPass, uniformBuffer, uniformLegacyObject); }); diff --git a/packages/lesson_013/src/drawcalls/Drawcall.ts b/packages/lesson_013/src/drawcalls/Drawcall.ts index 9596a58..c585d0d 100644 --- a/packages/lesson_013/src/drawcalls/Drawcall.ts +++ b/packages/lesson_013/src/drawcalls/Drawcall.ts @@ -9,15 +9,15 @@ export const ZINDEX_FACTOR = 100000; export abstract class Drawcall { uid = uid(); - protected shapes: Shape[] = []; + shapes: Shape[] = []; /** * Create a new batch if the number of instances exceeds. */ protected maxInstances = Infinity; - protected geometryDirty = true; - protected materialDirty = true; + geometryDirty = true; + materialDirty = true; destroyed = false; constructor( @@ -47,20 +47,10 @@ export abstract class Drawcall { uniformBuffer: Buffer, uniformLegacyObject: Record, ) { - if (this.shapes.some((shape) => shape.geometryDirtyFlag)) { - this.shapes.forEach((shape) => (shape.geometryDirtyFlag = false)); - this.geometryDirty = true; - } - if (this.geometryDirty) { this.createGeometry(); } - if (this.shapes.some((shape) => shape.materialDirtyFlag)) { - this.shapes.forEach((shape) => (shape.materialDirtyFlag = false)); - this.materialDirty = true; - } - if (this.materialDirty) { this.createMaterial(uniformBuffer); } diff --git a/packages/lesson_013/src/drawcalls/ShadowRect.ts b/packages/lesson_013/src/drawcalls/ShadowRect.ts index 231b067..dcbf5bc 100644 --- a/packages/lesson_013/src/drawcalls/ShadowRect.ts +++ b/packages/lesson_013/src/drawcalls/ShadowRect.ts @@ -16,14 +16,17 @@ import { TransparentBlack, StencilOp, } from '@antv/g-device-api'; -import { Rect, Shape } from '../shapes'; +import { Rect, RoughRect, Shape } from '../shapes'; import { Drawcall, ZINDEX_FACTOR } from './Drawcall'; import { vert, frag, Location } from '../shaders/shadow_rect'; import { paddingMat3 } from '../utils'; export class ShadowRect extends Drawcall { static check(shape: Shape) { - return shape instanceof Rect && shape.dropShadowBlurRadius > 0; + return ( + (shape instanceof Rect || shape instanceof RoughRect) && + shape.dropShadowBlurRadius > 0 + ); } #program: Program; diff --git a/packages/lesson_013/src/drawcalls/SmoothPolyline.ts b/packages/lesson_013/src/drawcalls/SmoothPolyline.ts index 956c36a..ac2da00 100644 --- a/packages/lesson_013/src/drawcalls/SmoothPolyline.ts +++ b/packages/lesson_013/src/drawcalls/SmoothPolyline.ts @@ -117,7 +117,7 @@ export class SmoothPolyline extends Drawcall { shape instanceof RoughEllipse || shape instanceof RoughPath) && this.index === 2) || - (shape instanceof RoughRect && this.index === 3) || + (shape instanceof RoughRect && this.index !== 2) || shape instanceof RoughPolyline, ); diff --git a/packages/lesson_013/src/shapes/Path.ts b/packages/lesson_013/src/shapes/Path.ts index ae2a24c..ae023fe 100644 --- a/packages/lesson_013/src/shapes/Path.ts +++ b/packages/lesson_013/src/shapes/Path.ts @@ -34,6 +34,8 @@ export function PathWrapper(Base: TBase) { batchable = false; + onGeometryChanged?: () => void; + static getGeometryBounds( attributes: Partial< Pick & { points: [number, number][][] } @@ -84,6 +86,7 @@ export function PathWrapper(Base: TBase) { this.geometryBoundsDirtyFlag = true; this.renderBoundsDirtyFlag = true; this.boundsDirtyFlag = true; + this.onGeometryChanged?.(); } } @@ -131,22 +134,21 @@ export function PathWrapper(Base: TBase) { if (this.renderBoundsDirtyFlag) { this.renderBoundsDirtyFlag = false; - const { strokeWidth, strokeLinecap, strokeLinejoin, strokeMiterlimit } = - this; + const { strokeWidth, strokeLinecap } = this; let style_expansion = 0.5; if (strokeLinecap === 'square') { style_expansion = Math.SQRT1_2; } - const stroke_is_rectilinear = true; - if ( - strokeLinejoin === 'miter' && - style_expansion < Math.SQRT2 * strokeMiterlimit && - !stroke_is_rectilinear - ) { - style_expansion = Math.SQRT2 * strokeMiterlimit; - } + // const stroke_is_rectilinear = true; + // if ( + // strokeLinejoin === 'miter' && + // style_expansion < Math.SQRT2 * strokeMiterlimit && + // !stroke_is_rectilinear + // ) { + // style_expansion = Math.SQRT2 * strokeMiterlimit; + // } style_expansion *= strokeWidth; diff --git a/packages/lesson_013/src/shapes/RoughCircle.ts b/packages/lesson_013/src/shapes/RoughCircle.ts index eea3c5f..186aba5 100644 --- a/packages/lesson_013/src/shapes/RoughCircle.ts +++ b/packages/lesson_013/src/shapes/RoughCircle.ts @@ -14,7 +14,6 @@ export class RoughCircle extends Rough(CircleWrapper(Shape)) { // cx / cy / r also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/lesson_013/src/shapes/RoughEllipse.ts b/packages/lesson_013/src/shapes/RoughEllipse.ts index 0166d42..d0388ee 100644 --- a/packages/lesson_013/src/shapes/RoughEllipse.ts +++ b/packages/lesson_013/src/shapes/RoughEllipse.ts @@ -14,7 +14,6 @@ export class RoughEllipse extends Rough(EllipseWrapper(Shape)) { // cx / cy / rx / ry also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/lesson_013/src/shapes/RoughPath.ts b/packages/lesson_013/src/shapes/RoughPath.ts index 161c1d6..6361541 100644 --- a/packages/lesson_013/src/shapes/RoughPath.ts +++ b/packages/lesson_013/src/shapes/RoughPath.ts @@ -10,9 +10,12 @@ export interface RoughPathAttributes extends PathAttributes, IRough {} export class RoughPath extends Rough(PathWrapper(Shape)) { constructor(attributes: Partial = {}) { super(attributes); - } - // TODO: points also regenerates the drawable + // d also regenerates the drawable + this.onGeometryChanged = () => { + this.geometryDirtyFlag = true; + }; + } generateDrawable() { const { d } = this; diff --git a/packages/lesson_013/src/shapes/RoughPolyline.ts b/packages/lesson_013/src/shapes/RoughPolyline.ts index 1038b8e..27381a4 100644 --- a/packages/lesson_013/src/shapes/RoughPolyline.ts +++ b/packages/lesson_013/src/shapes/RoughPolyline.ts @@ -14,7 +14,6 @@ export class RoughPolyline extends Rough(PolylineWrapper(Shape)) { // points also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/lesson_013/src/shapes/RoughRect.ts b/packages/lesson_013/src/shapes/RoughRect.ts index 15e3b01..7ecd51e 100644 --- a/packages/lesson_013/src/shapes/RoughRect.ts +++ b/packages/lesson_013/src/shapes/RoughRect.ts @@ -14,7 +14,6 @@ export class RoughRect extends Rough(RectWrapper(Shape)) { // x / y / width / height also regenerates the drawable this.onGeometryChanged = () => { this.geometryDirtyFlag = true; - this.generate(); }; } diff --git a/packages/lesson_013/src/shapes/Shape.ts b/packages/lesson_013/src/shapes/Shape.ts index ef2bb08..fbf0f8b 100644 --- a/packages/lesson_013/src/shapes/Shape.ts +++ b/packages/lesson_013/src/shapes/Shape.ts @@ -44,6 +44,11 @@ export interface Shape materialDirtyFlag: boolean; + /** + * After `geometryDirtyFlag` enabled, the preCreateGeometry method is called on the next . + */ + preCreateGeometry?(): void; + /** * Hit testing. */ @@ -54,6 +59,7 @@ export interface Shape ): boolean; getBounds(): AABB; + getGeometryBounds(): AABB; getRenderBounds(): AABB; /** diff --git a/packages/lesson_013/src/shapes/mixins/Rough.ts b/packages/lesson_013/src/shapes/mixins/Rough.ts index 9677451..d92e377 100644 --- a/packages/lesson_013/src/shapes/mixins/Rough.ts +++ b/packages/lesson_013/src/shapes/mixins/Rough.ts @@ -204,7 +204,8 @@ export function Rough(Base: TBase) { this.#fillLineDash = fillLineDash; this.#fillLineDashOffset = fillLineDashOffset; - this.generate(); + this.preCreateGeometry?.(); + this.geometryDirtyFlag = false; } get seed() { @@ -215,7 +216,6 @@ export function Rough(Base: TBase) { this.#seed = seed; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -227,7 +227,6 @@ export function Rough(Base: TBase) { this.#roughness = roughness; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -239,7 +238,6 @@ export function Rough(Base: TBase) { this.#bowing = bowing; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -251,7 +249,6 @@ export function Rough(Base: TBase) { this.#fillStyle = fillStyle; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -263,7 +260,6 @@ export function Rough(Base: TBase) { this.#fillWeight = fillWeight; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -275,7 +271,6 @@ export function Rough(Base: TBase) { this.#hachureAngle = hachureAngle; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -287,7 +282,6 @@ export function Rough(Base: TBase) { this.#hachureGap = hachureGap; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -299,7 +293,6 @@ export function Rough(Base: TBase) { this.#curveStepCount = curveStepCount; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -311,7 +304,6 @@ export function Rough(Base: TBase) { this.#curveFitting = curveFitting; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -323,7 +315,6 @@ export function Rough(Base: TBase) { this.#disableMultiStroke = disableMultiStroke; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -335,7 +326,6 @@ export function Rough(Base: TBase) { this.#disableMultiStrokeFill = disableMultiStrokeFill; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -347,7 +337,6 @@ export function Rough(Base: TBase) { this.#simplification = simplification; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -359,7 +348,6 @@ export function Rough(Base: TBase) { this.#dashOffset = dashOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -371,7 +359,6 @@ export function Rough(Base: TBase) { this.#dashGap = dashGap; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -383,7 +370,6 @@ export function Rough(Base: TBase) { this.#zigzagOffset = zigzagOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -395,7 +381,6 @@ export function Rough(Base: TBase) { this.#preserveVertices = preserveVertices; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -410,7 +395,6 @@ export function Rough(Base: TBase) { this.#fillLineDash = fillLineDash; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -422,7 +406,6 @@ export function Rough(Base: TBase) { this.#fillLineDashOffset = fillLineDashOffset; this.renderDirtyFlag = true; this.geometryDirtyFlag = true; - this.generate(); } } @@ -479,10 +462,7 @@ export function Rough(Base: TBase) { }); } - /** - * generate rough shape - */ - generate() { + preCreateGeometry() { const drawable = this.generateDrawable(); this.drawableSets = drawable.sets; diff --git a/packages/lesson_013/src/utils/serialize.ts b/packages/lesson_013/src/utils/serialize.ts index 391e927..d15cb87 100644 --- a/packages/lesson_013/src/utils/serialize.ts +++ b/packages/lesson_013/src/utils/serialize.ts @@ -721,7 +721,7 @@ export function toSVGElement(node: SerializedNode, doc?: Document) { exportInnerShadow(node, element, $g, doc); } if (dropShadowBlurRadius > 0) { - exportDropShadow(node, element, $g, doc); + exportDropShadow(node, element || $g, $g, doc); } // avoid `fill="[object ImageBitmap]"` if (hasFillImage) {