From 2952d9825b592a9fed7dc6e6fe91c60c9df108c0 Mon Sep 17 00:00:00 2001 From: toesbieya <1647775459@qq.com> Date: Mon, 18 May 2020 00:29:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=87=A0=E4=B8=AA?= =?UTF-8?q?=E7=99=BB=E9=99=86=E6=B3=A8=E5=86=8C=E9=A1=B5=E7=9A=84=E8=83=8C?= =?UTF-8?q?=E6=99=AF=E5=8A=A8=E7=94=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vue/public/static/img/dot1.png | Bin 0 -> 7207 bytes vue/public/static/img/dot2.png | Bin 0 -> 690 bytes vue/public/static/img/dot3.png | Bin 0 -> 1893 bytes vue/public/static/img/dot4.png | Bin 0 -> 1847 bytes vue/src/assets/styles/login.scss | 20 +- vue/src/config/index.js | 3 - vue/src/layout/components/Header.vue | 2 +- .../canvasAnimation/firework/Particle.js | 44 +++ .../plugin/canvasAnimation/firework/Rocket.js | 20 ++ .../plugin/canvasAnimation/firework/Time.js | 20 ++ .../plugin/canvasAnimation/firework/Trail.js | 42 +++ .../plugin/canvasAnimation/firework/Vector.js | 22 ++ .../plugin/canvasAnimation/firework/index.js | 138 +++++++++ .../plugin/canvasAnimation/godrays/index.js | 92 ++++++ .../canvasAnimation/godrays/original.js | 261 ++++++++++++++++++ .../moveFollowMouse/Particle.js | 30 ++ .../canvasAnimation/moveFollowMouse/index.js | 68 +++++ .../canvasAnimation/particleBall/Particle.js | 90 ++++++ .../canvasAnimation/particleBall/Vector.js | 74 +++++ .../canvasAnimation/particleBall/index.js | 88 ++++++ .../canvasAnimation/particleBall/util.js | 13 + .../particleNetwork/Particle.js | 50 ++++ .../canvasAnimation/particleNetwork/index.js | 204 ++++++++++++++ .../canvasAnimation/particleWave/index.js | 157 +++++++++++ .../reflectRain}/RainDrop.js | 0 .../reflectRain}/Vector.js | 0 .../reflectRain}/index.js | 72 ++--- .../plugin/canvasAnimation/sparkRain/Spark.js | 18 ++ .../plugin/canvasAnimation/sparkRain/index.js | 86 ++++++ .../plugin/canvasAnimation/sparkRain/util.js | 3 + .../canvasAnimation/sunlight/Particle.js | 81 ++++++ .../plugin/canvasAnimation/sunlight/index.js | 94 +++++++ vue/src/store/modules/app.js | 16 +- vue/src/views/app/components/SetAnimation.vue | 43 +++ vue/src/views/app/login.vue | 45 +-- vue/src/views/app/register.vue | 33 ++- 36 files changed, 1862 insertions(+), 67 deletions(-) create mode 100644 vue/public/static/img/dot1.png create mode 100644 vue/public/static/img/dot2.png create mode 100644 vue/public/static/img/dot3.png create mode 100644 vue/public/static/img/dot4.png create mode 100644 vue/src/plugin/canvasAnimation/firework/Particle.js create mode 100644 vue/src/plugin/canvasAnimation/firework/Rocket.js create mode 100644 vue/src/plugin/canvasAnimation/firework/Time.js create mode 100644 vue/src/plugin/canvasAnimation/firework/Trail.js create mode 100644 vue/src/plugin/canvasAnimation/firework/Vector.js create mode 100644 vue/src/plugin/canvasAnimation/firework/index.js create mode 100644 vue/src/plugin/canvasAnimation/godrays/index.js create mode 100644 vue/src/plugin/canvasAnimation/godrays/original.js create mode 100644 vue/src/plugin/canvasAnimation/moveFollowMouse/Particle.js create mode 100644 vue/src/plugin/canvasAnimation/moveFollowMouse/index.js create mode 100644 vue/src/plugin/canvasAnimation/particleBall/Particle.js create mode 100644 vue/src/plugin/canvasAnimation/particleBall/Vector.js create mode 100644 vue/src/plugin/canvasAnimation/particleBall/index.js create mode 100644 vue/src/plugin/canvasAnimation/particleBall/util.js create mode 100644 vue/src/plugin/canvasAnimation/particleNetwork/Particle.js create mode 100644 vue/src/plugin/canvasAnimation/particleNetwork/index.js create mode 100644 vue/src/plugin/canvasAnimation/particleWave/index.js rename vue/src/plugin/{rain => canvasAnimation/reflectRain}/RainDrop.js (100%) rename vue/src/plugin/{rain => canvasAnimation/reflectRain}/Vector.js (100%) rename vue/src/plugin/{rain => canvasAnimation/reflectRain}/index.js (90%) create mode 100644 vue/src/plugin/canvasAnimation/sparkRain/Spark.js create mode 100644 vue/src/plugin/canvasAnimation/sparkRain/index.js create mode 100644 vue/src/plugin/canvasAnimation/sparkRain/util.js create mode 100644 vue/src/plugin/canvasAnimation/sunlight/Particle.js create mode 100644 vue/src/plugin/canvasAnimation/sunlight/index.js create mode 100644 vue/src/views/app/components/SetAnimation.vue diff --git a/vue/public/static/img/dot1.png b/vue/public/static/img/dot1.png new file mode 100644 index 0000000000000000000000000000000000000000..ab5dd81098e069a4d72fe133f1470a302a0118d4 GIT binary patch literal 7207 zcmX9@byQSe7adSy=#B}7R9YIOTN*?i>KQ{)?e-&*gz zd*7+O_c`y6yVi?TQ+b1n1;PRV0J!pU((1_7{NIiF4EcN`Y+;F9o?A&MO8@|M@z{S% z(2(yaF6wV20o6YsdjJ4xkeZT)jM4`uSUMDv1}07*B8QUz5&@)%gn$45Bo#y)NsJeZ zM;J#)lt@I8NJ1Kq56ggpQz=MdaH$XwiX>913<%PK+=G(H$>I2*R0>ck8GbZAG!2X$ zjZFq8LI#i}U{fRzVn0Fc4R4J-hL zR}R2W#V3Q4;U?gcCL&Rwpj2|Q1TttE1eytfW`U7m{~{4ofMfsxoB(MgiUm?5s7RAZ zsS!|EE{r0H0-Q`ikxD_Fghvzsq)LZSW&XQBDU`riAT;a0I*5Nyq;{kinhr*Kk;I4+ zaiG~?sw^;RJSjyA33WOZb^tVg6GaeFWkLa(04ijiEC`Ywk~wMe zGo*HC1{jt>1w+!yg20ee5y%t>X$mP7a+CI-1zG(6xEW9+x@Ng1k^nU_J`+ljLJUm@ zA!#79VCi5;3MDiX3_->tK{LT5F(k}SbpN`Yfuss1NhX4&K_LIN;=lBNG{}+&|H(lb zktx|Aqy-X-ha`-whP2?r@u{-G;1n=&xJW*bWJ)AkXf_0CM79nIgcMGeOpL@L|8L^R zL}WjqDIiGZKNk`UmPv(F@lW!97Q!TCPau$-f8KuqIbax4W)_4b0hc0`1d0@ujU)s8 zrzjhl3xOdMk&!uI>`-hfBrbB?$OdMB{ccHTk)P(AtGdcNfVUN|Jcb~uDJ~HUM2sWQ z@P*&I(xiADns+KRPGr)lDleSuVhDA_A~1_XF`p4iGYIDBklQtk=etMXys7~E zbGT!^GnD6ngyc7vf)@renw>ueHfJ!;jdF;2kXx}7wf915p0$6;uEdefPRJOngog;G zy2r2E^?84J7MS*p*Sf1H$?V&1^tTtN(KT(N{>y2hh?v)r%cYwwMC*a|G$ZeEymV_0 zw?a>TNlmjbPsv%29Q@3W7#vx7U3+nIaStD7kawDHnYbzIoBm6Fm^YCXe{io408p67 zOG{{2uT*LssJ{C})g*HCVSMkk-_%V4g>rg}=si_m9l{JY5wm}-X*`M|-L5{f>5hWOgFiD?M=QGe7 zHlF3A^nI}SM4y7FuSW=mkyus5Z4!7@YNd9XF9CZV zj9PkqkmdeF?-@8CI7Fal^f0Afo@IaAp!y|y@HY!b#E=Qc&a{E(9_C5D*G5$LJTIz* zoB(_e65h^?-^_fkz;~|aX1EnuE^HZ$P;`l--{lC1#qG7s2~Co^yDS}v*)L@~NaG(m z*z(NSnU9B{|mEB>GjZi7j@m81;VL{ zpH#DM!8BecXEK5djY}$%{6{VtnggPwODj1|ZDV91Y@os+LmcWwn(={M zR?S!7w{4?$^!?($V8deUmI^&_Z-aLP^CbpuzgEUl=hYiM(XOlRK6-xSwQh*jBMQ4F44lStd6iy)m_~#W$n1NKZ#n&Jc&Ni%Xpdy2 zawk(t6|j3!=a5W>_L*x;P_8EW4-*S3=KcWHctkB-?E9hpGFFkVi_-SBa-C|-@r8fe zCpxmuO>+g-uSy0VoYv?s*+B2=7@c3%%2{A@rMwo&Ft_p-;z%(KYYKYP*ezbwhnmQj zI8-|MARixcFtVZ%U;Me(bgxc_l|k(45}?!?XT)^n9r3K_h1+9=zITW$F4~rKQNFMU1gI)2UxZp3d%Zi5+_m zZpa@a_}xVI&z@JCIy&uZ7ZUh%v~|kRMh4c7||vuK}uy57F|yZj~wArLy~FeSm=Z?K$f|RqAD@(DbB(kr zW~1JRn&v{jM6Jj+=~1@=(uv=i>H4TkFh~j09~BF%cs9!22$0;*;x>if*qOi}d5?@oE#>74vkNEI&&&vG^B=R29k=}Shxt-0b?q(U&6%z`;9phqmFNDP(J@B3 zRdQe@8$0hHnL2SYVSZ{iX%(BN`9T0p6pEy>FMQv|M9Qu&{@eMtjl-@5$L-ghi@j}E z@*Vbl*Dj33uJCVa)<*ec24QIG2erE2ttHvbY|(Ttf#T^#_c}ojJsJFvNUGYVZ(0dv zp1-D+SX(<(scl;P1ece*s;)cTgR=ye`!W}sKJB56uH`ZCvZgfO^V$;%rn1FIk9lDn zlMmId0-H)VfDKM#}I37R}L)k=

ihaS+`S?H>A-*2mq`)X9nA3NA#BvG;wu@-l@!tOJ*GUibzf)Svb0RUmAe8BMgZ6ey0-l7<-wmi2Fnz zLdhD7(>CuXe@Fcmr|}gJ_wsv>8X%;fk$< z4_rDZyxkc5NFWz^OZoj6h0wf6Cm4Csc;aE)W$?C6YriikuOU^=1s_y;FFjuL9xW1o zR$a{zxVv?-n(YX4k@@*)3XL7#W|8#t?3}|%$0@|fb=V@ufQbBWEPj3Xv?>Q>gLzlW zEq^G5j`bXBgmn!Ol?-l6Kc0&Fs;HmEdFD_}cTQHPv&F{s&~b2`{PXKnEQz}jx&x6Tk(&QjQ^L8~PK4MUq&|8tcLR$*oF9ehRl?@>Fc$zqA)$ZfR z?AI>aQ*(1aleAS-vkoion*$wx)deKM-Q>| zteI6$Ti=zsGej>K{gXAtQRN7*h??J;1K%XDMPk-7q6GmNBO~X~q%lEqYV@>Nyf&!A zcu<0 zIa+d%s>+>g|GV|a)~-7gHDVscIpb6ey$(_=L*8W!;?l}5cL?_Om!U2BLpCO7G+ECMjY z6j1u*3Ig#wxGrA1FPUVn&n=uL*mKyo2F{cY*X3`Bk0JWWyK>?_I=K||2G0QQ;b)u99bskzD zVuxS%91cc|@!2>0x_{tRych<4OnFvZ+SXsv+`m0f?mAQpE9|x|X~+ui%nZK2eb)*Ep3$JGzE2d@yk;vrn;# z;l~u0%P|TCv=`mu7y7M!p1wBpfvBLpZ^CdV`r%v`e2jwIz(8uIR`)VHMrG1;?y|YM z1hg%pE>6KCgRG1U=eW29SswJ_w~HIreY-AHWut1fcna882lK~;lj5i2enXX`EL3RW zk!N0s!hMBKIXfz0(ETKO3*J>Qqhbev&QFoK>4o5i1Q%_81zACdxX3FJR{_8n%nLyfVB?Q~2KcA@d=ia+~QA!OT4fr~7sOPSKXbPs=sGorn3SU0le)P*1nHY07 z$e3QhOPKm>+)#J#Waeab9KENA_&D*;TPcBA>{NJ`Cw8zZ`mC4P3#L$x zq$wBulo|eE>bSrp)qZB73RYt9yiw*we3SMD-EJDLekG4yxnNyS5{WOOvFqTq`>phL z+mrw(&8O((ZteG1O?z?(%S>k8clYI0|KGjMU5l0G7fKvS3uH%8&JBjPnMWDAS7g$zzK!#-h0)ka$|Tj(e%{PHTy(~C6X8*yWz&ky5{d3LRH;Xr@1#j$mSfai-0 z%|#xJCmTQL0k5EF0b+4&&BwJ>)=QppAq6dxBo(fb+r90)Acp06@M#^3le;$3;8)f9@j}iM_I`A@@}>g=SX5pp4q0B*os5+29szsoY?h*ODz)HNss6@LOCf~fmq78g* zz*2sY$Ri>#^l9E}ENvmBvk)+sjwuE#$)!${{!C|h)Df4Yx^G>QI|wAaBo?S~_WwYZ zOSyMqG&^ca&7v25O6;nrA_m;2pnpTekn>H|eM(hw{bk6Y{%KP5Wm1)GXHwe@!7_iU zf4y&-B97R%N!8A5?ltZ|+^iDnY7wWzfikB_^Cq`LZm68MKX^l(7FRL+C8y6B#dTs# z|3rGk2Ih;?Ox6^w$8ED+dEZI@oZk0z$bbAX_RT*{bd<#@yw(Uat$p!cu6hG?;04JI zp=N-vtd;Nu@szvu+g?l8-c4@bAXt{Oya@4e)R2#T_}q>{6miD-*|xDosw!k9B%ITM9WpG_~zqp{LQ4yS>?zcF>a*w2_+lg&Dl z4^T*rg`CrXjp|jhY)waaw3EH42x|%KN#{nb)MqE2^io{T(slG}(Hw(?FgE|4w64!o z#>cAsbWw{I1-1Nd(;WvGe!O8ar==99;4`XHi`Q&kfS&NL<7G_+aUB9^DaZ)xO~e!BC&+8bM+}PFc z75bL&QEJB2mNy-Z2WPFhMaU*_nKz}~S>}p9tEd;}9m(Gnj1v)H_8S@|D+Ax|Hv*5h z2AgkdpWTH>1=dSnq=;`OEshh{8rO$$5r^Z)XwYS7oY$0;5OK<&;E|m#a)fL~*sflB zBsQh15;P>LvOm27__Rh2V4lb&t~)W)=02B0C+@PbPu?3D4WPBsjlABkJ9qvw?1tr9 z{sVNYQq6TRVxE_8LPmQIyuQKMChn>=_w@7am*|Gm^o9&(hjP+5ncHLP065{53kl5# z3YYSZGa5AiWt_Oc_)VOb_k15*$TRx#&`_?Uu_K+fr2p={;@L9$BjYKc|6DcF^#s== zc7=gMU5)>lVWFMzUistbe@pmH zsDP!Xh}*;EmF0!V#)WOn{GL+xOFSB0EgUXW#l>OAl=2SNmmH_r5%V5f!gY#^}-d&nRu!f!=vU#@pu^*ykx*H^V?w@>1j47X=_bvtS{I@!=t;T>DW=0??8 zkb!0aS8)oB5&xW7UA01Qq&e1OtORRcA~oNihl7#aE+2?7(_4HMnyESy-|l=Ve{wYx zugK8-)ueUq50;I}#msjN&z}$+r!SHxCqos}>_n@@{qOu=sz0M=*eF}9dJ1S>#Lqh2 zX@C|8J6KGvg))H~{d6ejR_hZc&aEF*wB5cLnF^QaVYQ56*sxRqI}NJ!+fz7q%5bgALyC?d3K&hmN;|9e46K5QQ3O|in^BA z%&U5g_>!NG@z-7fIqlJg9~98j5hIy5504__9hb>!9sDO&0e)gaLeVEnnQik{-!bC{ zHJbS96TV`eB*Wf&Onj(&aOjMl@(+2JU7qK)g@L0*w_ANldi;j5d&yAviG|E;7fKW2 z0yE1E(D!a{_6(6YFcu4fyPXHEtLZjgTg@5dy(UwYSs-T#k#J7`T3=z#8N~^q9x2)R zJk7B{`z>>)Zhm0?Zi-0$_BmTl=J3{__g=qx%}e3ZQ%B66qY0vSPcmU1sSK`iEmMKa zB&IZ0C~=&0$@!zRqd1$L1_lp}BOHrOhSD>aqf8P#gqv$D8mw5XF^nw~DkrGQw4uFq zc3%kyQ-k%--G#1vY?4YJ-WnA(yW!))I8Q0Nr>8%wZR8o4tu>%IZP8#3tB6a#X%mNe zVQyGPFfRptfK$&>LpvuJO}KL%x;x!0xClpaO`Z!%h3mB)MW>Ehj#xl3h@vV)G6E*? zn?|LSa2c@U2pID8-09{p6pC}BaLPP6Tj6Vhw<3Lj)!6PCn(%pAOu=sTcCg8cs>fO5j(zGRTO*0|1FDB790Y~y7%C^}O&<>%y;(x4I$(#P|JR7;{Y0(u~-5pExHuywP zL|-Lm#t`@tvEKxJJ*ZjZf};N}T5+|o$(U33)ipaw#j`QAp6L48(#iBE9{;DY2o%O(MlgrXkG;TItTfdK_xjrC<8JYw zX-X`W`~W*F2zviV!T1=Iy#X~9r_>bdWJYtJ7*zVv#fA-M27}0ugXoHcJfXDdJs=kr z0quEgd7(>q>lC*Xo!4!5ksUmuzeET*l*YB^n=!C`B{cbb(s7YAd43uP>y%qvq2HGL zf~DHhnS)bi5xShO3rv9)6Gr6*QUvIjfvj)4zUA?g;1In6<4j(h{8fGsCjc3cu88k8 zH|Cq4#?uDizw4wSZ_3fv{2rhIy%-=t%?v&~uuF}k4MN;nY_=E}rL|B{XCC6?)uYd_L zZCaFIW}=Z`@z9RGwtw~NFdOKD>hz=*D3s%&5vil4F&oB>dXEtxFk}-L@fUU6HIvVS z8fQnRYSs#G1|{yA9CXo|Z`G;w{WbsVLYDXhs8F}kHQ`eLYrbMxZ`ByWfWsOdTxd*VK5u#sl3#1uiLWLhqA`A#D@fImTcRDYeSVGCKHCd zg0Mzc!?^f+-*XJ@^xhtG1xZZv%jz-or&9YX$>Oba?AfCiV)NdDM06`@@UqMJleGlC zPIH{!l*&?S+IjD4KJ*whs599Z#$HF>GyR=BAjh{<&e)WLvkq8DOV*XzdTaj-zhsRq znsK%<^@wlL%dqlMgwtGcJIhiH`$>VW7#41bJp5Pq5a}w>@(Vkr(dNQOK4(IExvkRI mV}eUGk&4k9(u#&p0GuLs(TeX(j>z9B0C^b|>1s*ip#K3V23X+$ literal 0 HcmV?d00001 diff --git a/vue/public/static/img/dot2.png b/vue/public/static/img/dot2.png new file mode 100644 index 0000000000000000000000000000000000000000..14cf520a67d5527ece22d1c260b9c33d7bcc722c GIT binary patch literal 690 zcmeAS@N?(olHy`uVBq!ia0vp^8X(NU3?z3ec*FxKmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIDo0X`wFKADA@nwn~AYF1WO>gwu1ww9Kb1{eUj5QdJ9PH1Q-kgct)4J3hT zAj*Iw&=@dJ6DST;4^aS72{Z>{0>nUw;XuU@22dqL79vtEBRm6WmR3oSUob<=7v9iK zQ=hzV7nYpD{K)Fx+8UK*jAv~(y_tFL*7WJ`YinO`p4on`qvO`?;yXS-Pfhl8aSX9I z-5T0nc36QYWZBy{d(+ER|Nj3jYS_!$8&@Dy+;HqA!;0Hw|8KnMs*ZeP*8f+mXxqO% z31{`LT5(GIiW&J{n;;-QIZ*n#<)#B)j!W+^owY+zYQ~$6wDip>5|7z(o_+aXpYmZr zpY?`sXCJNMz7}Z5a%bw>jV}_n*4Gs8*ca`acCTGo|LTK%2fyw*_;uUK*LnWT{y+9> zzVIwao-drmbjUE7bxll9Ad8`#cEigvRGLBb1D)-~+r)|s2N$yIxy%NcfAp|DkpXK(S#i&>HI!u5dE&!v|q zTi&`Hd{$reVav@wKODlBwak3fa_e)9hoio;V35YFz!2#!bK@l|bP5emyG<_ijrq|L zZIHVBLQI@S)Dyn5OK+JL?^s=W-}GB=ZF>8)GOxxO-k^`?3N>SrUzN7EdEC5a81JTh zODQ#_pXp}v;ltY|SWOeE@_dl2u6@>T9_zFzX@bAsd%UTyzjm`aad-Wy*NdmTetdI> b-9HAubEm~>tt&-rd>gTe~DWM4fD0~v! literal 0 HcmV?d00001 diff --git a/vue/public/static/img/dot3.png b/vue/public/static/img/dot3.png new file mode 100644 index 0000000000000000000000000000000000000000..6234e9fd79d5a47b909605ffff552b5cdbe38795 GIT binary patch literal 1893 zcmW+$2~ZSg79Nh_T$CedP#{dnA<+;hvI4{O^nJ|0AcsRZ4T`P-0i^_m1Uw)*z!Gi> zM_CfUP>KQuN`hb_ha$lhO;FGQ0b!JIn29J$hywd2Ro#ET{`% z5ctk;90$83^kW#3VW2G#1CkIBEK3j+j*}RMV^BcR7(_S;)PWvB(GZIe1jiZJrfC)! z6NCiEDM-aI5`#>FK%r1el7@0^6`@rP0o01c1cIO_iu;PhD8m3rv9>>sVz_n}ha3Ww zLI`~z(-*-YN9c<}D~e{cglH{c;1AFs08ju9Y!st7%YqevO92fWxY8_0z;FU^!4P-{ ztDzE@h{f37h&Y%7K7dO=63k&3j^#KMCB&$9C>$ptp$fr(2@ZKQD;DE00*a)yc^oXD zoe+yr@E-sPiUM6g7{vJ^D9n_TNEn*sScya;1)U7dpfC)Y@%Hfr^J$8qX<8)4e1szK z5D}w*1LlELX!rM6fhk_C6T1v&B{3y9AcU9EEVr@|n(67h(Ksp^%9|_TijtSl&owt& zwN$)`k~hOrJ|CqlQ>tw=^Q&dbd&;ua$vQQn$QWqQC^QX|18TK!GE=1((5UYzRyCRG zIt`*KL)1B|j`!*^RgMFb>P#f3PIWKD?3oUnaaKa%yS(qF%3q(i3pamh>|AO#)S5Wb znm84a_&P5CaoEVa!B*jujGy=u(J0G2F0s;k^BgXS16RotRbL`6lzP z<>y1yd!N@U7(3^niIQIf-*sDU+xXQ-*B4AYdil(LhvI!HDyQM-l>W8k1C<}-6&RUr zmsd0x?tUSl14K(PqpygRKhLG)#Y)Nlx>uA4T;*#Qm)mNUr3>yW3!ZNJrM2&e_@A;i zR#s*>B>i%6D&J>R;^pI7e)fnmxzeN4^VWc>(APlbv$?l!$FJ`_d{Femr>40UdT}=l*%}$xa~@scT|NEBBsp z|Imb97ujl<=JBF7D#g}qLdV0-Ki%L8ujlOPUB@ps#wGi?@YkX)jLsPSBuFeg+#e@s zu_rpWBF^uHn{+B%Sf3A4(-g5kU7AWrSmf>GB5h;C&lnM2kwblp`a#7bI`rtS*2SqT%x~PT(XDN~BbwMISvr0&=c;AUlb*AK z5{LP~Q#KC#brvDK$}Q$yMb}iUR1(xzl+O1?j2~UFG%^0r-8o63OXOd_+kVG|dZwGo zcl;>rJnv1!+$VZ1o>@75MIMD=75X^l*=+C18E^Eq7TmU7>-09XN%IZrr>oY^riLfv z#}#_CnTBocHF8sIi8;FY7Tve>P0Q~Oi%%s)mrG7xnDfwouwm`Tvcx^2N!OA;3nP}C zQ-e#8pjJh4j#D?fSB2+43+y^{Yvt~V`|bZ+uo^igyP0BrQn`0fnzii#8vWJ3$9BAL zWa+30`{B9ckg(vI$L>y%)tXMbMTvuLUgOEo;?B9I)}-&Z)CzXi=1#lVOS0S|vgOQ| zMf@y0WaR3w3psRk$Y5)95B|mkz$n?uyxEZ0fMx`gFzR z|E(LIu^N9I@#$Q=T}N(X{BITF>ZiO>%_&*`+e2+vrjCAcQ#F-ddt}9L_uJMg&xv}0 z`{Tie@n0r0volr4A`Q~NOKllyeO>o+YF3{uk%VPgR{zzva(VJ$Lw18Fy0Rl_ef<}s z1@YrM^XIzHZI>6>B~L8)%uFjYhW)GVhei&mEW$Q9s*dfcEy<-{4?jt7S^l=_;%ryK zwWRLWRI6px(w3IxKe9Kf`4#s=(^u~o{71g~NpDg~*xHPji)}||{P9phC=#{kPMX#}pxYg;Y Y&vbMAFWRfAL+~%-N$3Eok%-CqKe^})(EtDd literal 0 HcmV?d00001 diff --git a/vue/public/static/img/dot4.png b/vue/public/static/img/dot4.png new file mode 100644 index 0000000000000000000000000000000000000000..da8971b25551efdac215cf6dabc2ab4979ed7724 GIT binary patch literal 1847 zcmW+$30PBS7LC+c**aK3jXRxypcMoZEZYo}y)?9t$Mn`}2> zu~_E8L4M)zwln-Uz5(OSy+Jg*)*tiv(1*op_}X+;%!c*4`0zkqR^8yvmn@c%%}1ep z|4>;R!!Q^|5F`Zwq)0?j@K6$oL?95r5lJ#QPBM&yBtuNfB@!Y40u)5RgrcBm zB!Zx@3As|K6!?%N31}oqQxuJ2I7vzfAS7aNQUr++LKJAjZe(O6K}ab8rwx&ijuRvy zl|nj-5di+XPzoZE-N8Vn~01AE{DVo?+qfItx-OArKu1F=McpfI5gT|fbzHq--SNm49{lt?1ML<}>i z5DHPy1Ww^3#fMIT)j~`FbDno#J9X0ry@j%oUMXOd^Fh4hktY+LCKEa8EBC)(y|jfX(ony0l&$YyYa#dtli7o>Eh%3 z?$wot2b2dcM8=K@#ssMg722s1tOr{&tNrp-QO^w3G&%OS@#NUo=itrRy3aU{NvB8a_6p{?>pC(xi^p> zYi??8R`n=x`0X1rIFIN*bDU?D9lB=Q7Sy|)*KYj&F7`-0u|BrJT5oODJLUfJ&EcSG z>v$~3RB|Axy=HRe-Sa<8jGajfi0^3O23?TUL!%K8XvM5w@5an{o0Z+|Sw@$;^2UA?ZeGRZHsZCZC^;{`|md=)&~}ie}rp z+}T{G{FqbQIcYoW6CWj^SYhQIOPBsm8oCYh?Vf(C@{%^`~+*xc+v_5B@pV&HCu3fQ?t#Hnu_b;ku94t3CDC#_L;T(#Nav zZ>3fH{5FNCRa{5oPxS$={fLK~-d1Q~Uu;o$cW+#;3(q|8YA+`*xnKPCCU2I4Q`cRc$9wi;!mxI)OM?fj5D5L>FulCs^&kcMvE^O%nvOG zBqSe9OJ!X&cCv3(S4>A|Qs2A?P+jqG+`7O1PgZLEVTJ}+7?L}8OVypAZr1} zk^5|HYi-9MPwV0p^2KC8=aOga{d+4iT=k7EOjUd<`Lc2yyvtDD0j=+sxF z{7zim@t$Cg`fEEi}~BP>#Sr}j9!wX0-#@$^>SvS{1r{P2j@ mJ9*{PEAr*JKtg!SdyQ?p$v>*g(NquLE>^HV&#%sxN&gMl;XMEV literal 0 HcmV?d00001 diff --git a/vue/src/assets/styles/login.scss b/vue/src/assets/styles/login.scss index d5dd539..c8599ec 100644 --- a/vue/src/assets/styles/login.scss +++ b/vue/src/assets/styles/login.scss @@ -25,9 +25,10 @@ $cursor: #fff; .login-container { flex: 1; - padding: 32px 0; + padding: 32px 35px; text-align: center; - width: 384px; + width: 520px; + max-width: 100%; margin: 0 auto; .title { @@ -38,13 +39,21 @@ $cursor: #fff; color: #eee; font-weight: bold; position: relative; + + .set-animation { + color: #fff; + position: absolute; + top: 115px; + font-size: 18px; + right: 10px; + cursor: pointer; + } } .svg-container { - padding: 6px 5px 6px 15px; + padding: 6px 5px 6px 0; color: $dark_gray; vertical-align: middle; - width: 30px; display: inline-block; } @@ -82,8 +91,9 @@ $cursor: #fff; .el-form-item { border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 5px; background: rgba(0, 0, 0, 0.1); - margin-bottom: 30px; + margin-bottom: 22px; } } } diff --git a/vue/src/config/index.js b/vue/src/config/index.js index 8b56055..ac1eff1 100644 --- a/vue/src/config/index.js +++ b/vue/src/config/index.js @@ -8,9 +8,6 @@ module.exports = { //socketUrl: 'wss://toesbieya.cn', socketUrl: 'localhost:12580', - //登录页开启背景动画 - loginBackgroundAnimate: true, - sidebarLogoUrl: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png', errorLog: ['production', 'development'], diff --git a/vue/src/layout/components/Header.vue b/vue/src/layout/components/Header.vue index 60d5dce..fcb9f76 100644 --- a/vue/src/layout/components/Header.vue +++ b/vue/src/layout/components/Header.vue @@ -39,7 +39,7 @@ }, watch: { hideHeader(v) { - this.$store.commit('app/SET_HASHEADER', !v) + this.$store.commit('app/setHasHeader', !v) v ? this.addEvent() : this.removeEvent() } }, diff --git a/vue/src/plugin/canvasAnimation/firework/Particle.js b/vue/src/plugin/canvasAnimation/firework/Particle.js new file mode 100644 index 0000000..b9633ee --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/Particle.js @@ -0,0 +1,44 @@ +import Vector from "./Vector" +import Time from "./Time" + +export default class Particle { + constructor(position, velocity = new Vector(), color = 'white', radius = 1, lifetime = 1, mass = 1) { + this.position = position + this.velocity = velocity + this.color = color + this.radius = radius + this.lifetime = lifetime + this.mass = mass + + this.isInCanvas = true + this.createdOn = Time.now() + } + + update(time) { + if (!this.getRemainingLifetime()) return + + this.velocity.add(Particle.GRAVITATION.clone().multiplyScalar(this.mass)) + this.position.add(this.velocity.clone().multiplyScalar(time.delta)) + } + + render(canvas, context) { + const remainingLifetime = this.getRemainingLifetime() + + if (!remainingLifetime) return + + const radius = this.radius * remainingLifetime + + context.globalAlpha = remainingLifetime + context.globalCompositeOperation = 'lighter' + context.fillStyle = this.color + + context.beginPath() + context.arc(this.position.x, this.position.y, radius, 0, Math.PI * 2) + context.fill() + } + + getRemainingLifetime() { + const elapsedLifetime = Time.now() - this.createdOn + return Math.max(0, this.lifetime - elapsedLifetime) / this.lifetime + } +} diff --git a/vue/src/plugin/canvasAnimation/firework/Rocket.js b/vue/src/plugin/canvasAnimation/firework/Rocket.js new file mode 100644 index 0000000..1232862 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/Rocket.js @@ -0,0 +1,20 @@ +import Vector from "./Vector" +import Trail from "./Trail" + +export default class Rocket extends Trail { + constructor(childFactory, explosionFactory, position, velocity = new Vector()) { + super(childFactory, position, velocity) + + this.explosionFactory = explosionFactory + this.lifetime = 10 + } + + update(time) { + if (this.getRemainingLifetime() && this.velocity.y > 0) { + this.explosionFactory(this) + this.lifetime = 0 + } + + super.update(time) + } +} diff --git a/vue/src/plugin/canvasAnimation/firework/Time.js b/vue/src/plugin/canvasAnimation/firework/Time.js new file mode 100644 index 0000000..82e460b --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/Time.js @@ -0,0 +1,20 @@ +export default class Time { + constructor() { + const now = Time.now() + this.delta = 0 + this.elapsed = 0 + this.start = now + this.previous = now + } + + update() { + const now = Time.now() + this.delta = now - this.previous + this.elapsed = now - this.start + this.previous = now + } + + static now() { + return Date.now() / 1000 + } +} diff --git a/vue/src/plugin/canvasAnimation/firework/Trail.js b/vue/src/plugin/canvasAnimation/firework/Trail.js new file mode 100644 index 0000000..8b55393 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/Trail.js @@ -0,0 +1,42 @@ +import Vector from "./Vector" +import Particle from "./Particle" + +export default class Trail extends Particle { + constructor(childFactory, position, velocity = new Vector(), lifetime = 1, mass = 1) { + super(position, velocity) + + this.childFactory = childFactory + this.children = [] + this.lifetime = lifetime + this.mass = mass + + this.isAlive = true + } + + update(time) { + super.update(time) + + // Add a new child on every frame + if (this.isAlive && this.getRemainingLifetime()) { + this.children.push(this.childFactory(this)) + } + + // Remove particles that are dead + this.children = this.children.filter(function (child) { + if (child instanceof Trail) return child.isAlive + + return child.getRemainingLifetime() + }) + + // Kill trail if all particles fade away + if (!this.children.length) this.isAlive = false + + // Update particles + this.children.forEach(child => child.update(time)) + } + + render(canvas, context) { + // Render all children + this.children.forEach(child => child.render(canvas, context)) + } +} diff --git a/vue/src/plugin/canvasAnimation/firework/Vector.js b/vue/src/plugin/canvasAnimation/firework/Vector.js new file mode 100644 index 0000000..ad93ff5 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/Vector.js @@ -0,0 +1,22 @@ +export default class Vector { + constructor(x = 0, y = 0) { + this.x = x + this.y = y + } + + add(v) { + this.x += v.x + this.y += v.y + return this + } + + multiplyScalar(s) { + this.x *= s + this.y *= s + return this + } + + clone() { + return new Vector(this.x, this.y) + } +} diff --git a/vue/src/plugin/canvasAnimation/firework/index.js b/vue/src/plugin/canvasAnimation/firework/index.js new file mode 100644 index 0000000..21c9cd0 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/firework/index.js @@ -0,0 +1,138 @@ +import Vector from "./Vector" +import Time from "./Time" +import Particle from "./Particle" +import Trail from "./Trail" +import Rocket from "./Rocket" + +Particle.GRAVITATION = new Vector(0, 9.81) + +const getTrustParticleFactory = function () { + function getColor() { + const hue = Math.floor(Math.random() * 15 + 30) + return `hsl(${hue}, 100%, 75%` + } + + return function () { + const position = this.position.clone() + const velocity = this.velocity.clone().multiplyScalar(-.1) + velocity.x += (Math.random() - .5) * 8 + const color = getColor() + const radius = 1 + Math.random() + const lifetime = .5 + Math.random() * .5 + const mass = .01 + + return new Particle(position, velocity, color, radius, lifetime, mass) + } +} + +const getExplosionFactory = function (baseHue) { + function getColor() { + const hue = Math.floor(baseHue + Math.random() * 15) % 360 + const lightness = Math.floor(Math.pow(Math.random(), 2) * 50 + 50) + return `hsl(${hue}, 100%, ${lightness}%` + } + + function getChildFactory() { + return function (parent) { + const direction = Math.random() * Math.PI * 2 + const force = 8 + const velocity = new Vector(Math.cos(direction) * force, Math.sin(direction) * force) + const color = getColor() + const radius = 1 + Math.random() + const lifetime = 1 + const mass = .1 + + return new Particle(parent.position.clone(), velocity, color, radius, lifetime, mass) + } + } + + function getTrail(position) { + const direction = Math.random() * Math.PI * 2 + const force = Math.random() * 128 + const velocity = new Vector(Math.cos(direction) * force, Math.sin(direction) * force) + const lifetime = .5 + Math.random() + const mass = .075 + + return new Trail(getChildFactory(), position, velocity, lifetime, mass) + } + + return function (parent) { + let trails = 32 + while (trails--) { + parent.children.push(getTrail(parent.position.clone())) + } + } +} + +export default class Firework { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext('2d') + this.time = new Time() + this.rockets = [] + this.rAF = null + this.timer = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.addRocket = this.addRocket.bind(this) + this.start() + } + + start() { + window.addEventListener('resize', this.resize) + document.addEventListener('click', this.addRocket) + this.timer = window.setInterval(this.addRocket, 1000) + this.resize() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + window.removeEventListener('click', this.addRocket) + this.stopSign = true + this.rockets = [] + this.time = undefined + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + this.timer && window.clearInterval(this.timer) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.time.update() + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + + for (let i = 0; i < this.rockets.length; i++) { + this.rockets[i].update(this.time) + this.rockets[i].render(this.canvas, this.ctx) + } + } + + addRocket() { + const trustParticleFactory = getTrustParticleFactory() + const explosionFactory = getExplosionFactory(Math.random() * 360) + + const position = new Vector(Math.random() * this.canvas.width, this.canvas.height) + const thrust = window.innerHeight * .75 + const angle = Math.PI / -2 + (Math.random() - .5) * Math.PI / 8 + const velocity = new Vector(Math.cos(angle) * thrust, Math.sin(angle) * thrust) + const lifetime = 3 + + this.rockets.push(new Rocket(trustParticleFactory, explosionFactory, position, velocity, lifetime)) + + this.rockets = this.rockets.filter(rocket => rocket.isAlive) + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + } +} diff --git a/vue/src/plugin/canvasAnimation/godrays/index.js b/vue/src/plugin/canvasAnimation/godrays/index.js new file mode 100644 index 0000000..009a9b9 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/godrays/index.js @@ -0,0 +1,92 @@ +function mountainHeight(position, roughness) { + let frequencies = [1721, 947, 547, 233, 73, 31, 7] + return frequencies.reduce((height, freq) => height * roughness - Math.cos(freq * position), 0) +} + +export default class Godrays { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext('2d') + this.frame = 0 + this.godraysCanvas = canvas.cloneNode() + this.godraysCtx = this.godraysCanvas.getContext('2d') + this.rAF = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.start() + } + + start() { + window.addEventListener('resize', this.resize) + this.resize() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + this.stopSign = true + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + this.godraysCtx.clearRect(0, 0, this.godraysCanvas.width, this.godraysCanvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.canvas.width = 512 + this.canvas.height = 256 + this.godraysCanvas.width = 128 + this.godraysCanvas.height = 64 + let sunY = Math.cos(this.frame++ / 512) * 24 + let emissionGradient = this.godraysCtx.createRadialGradient( + this.godraysCanvas.width / 2, this.godraysCanvas.height / 2 + sunY, // The sun's center. + 0, // Start radius. + this.godraysCanvas.width / 2, this.godraysCanvas.height / 2 + sunY, // Sun's center again. + 44 // End radius. + ) + this.godraysCtx.fillStyle = emissionGradient + emissionGradient.addColorStop(.1, '#0C0804') // Color for pixels in radius 0 to 4.4 (44 * .1). + emissionGradient.addColorStop(.2, '#060201') // Color for everything past radius 8.8. + this.godraysCtx.fillRect(0, 0, this.godraysCanvas.width, this.godraysCanvas.height) + this.godraysCtx.fillStyle = '#000' + let skyGradient = this.ctx.createLinearGradient(0, 0, 0, this.canvas.height) + skyGradient.addColorStop(0, '#2a3e55') // Blueish at the top. + skyGradient.addColorStop(.7, '#8d4835') // Reddish at the bottom. + this.ctx.fillStyle = skyGradient + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) + + for (let i = 0; i < 4; i++) { + this.ctx.fillStyle = `hsl(7, 23%, ${23 - i * 6}%)` + for (let x = this.canvas.width; x--;) { + let mountainPosition = (this.frame + this.frame * i * i) / 3000 + x / 2000 + let mountainRoughness = i / 19 - .5 + let y = 128 + i * 25 + mountainHeight(mountainPosition, mountainRoughness) * 45 + this.ctx.fillRect(x, y, 1, 999) + this.godraysCtx.fillRect(x / 4, y / 4 + 1, 1, 999) + } + } + this.ctx.globalCompositeOperation = this.godraysCtx.globalCompositeOperation = 'lighter' + for (let scaleFactor = 1.07; scaleFactor < 5; scaleFactor *= scaleFactor) { + this.godraysCtx.drawImage( + this.godraysCanvas, + (this.godraysCanvas.width - this.godraysCanvas.width * scaleFactor) / 2, + (this.godraysCanvas.height - this.godraysCanvas.height * scaleFactor) / 2 - sunY * scaleFactor + sunY, + this.godraysCanvas.width * scaleFactor, + this.godraysCanvas.height * scaleFactor + ) + } + this.ctx.drawImage(this.godraysCanvas, 0, 0, this.canvas.width, this.canvas.height) + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + } +} diff --git a/vue/src/plugin/canvasAnimation/godrays/original.js b/vue/src/plugin/canvasAnimation/godrays/original.js new file mode 100644 index 0000000..203405f --- /dev/null +++ b/vue/src/plugin/canvasAnimation/godrays/original.js @@ -0,0 +1,261 @@ +// Currently in Chrome you need to click the "Get Adobe Flash" button so it'll ask you if you want to +// allow flash to run. + +// The rest of this is formatted as: +// // Explanation of the compressed code +// // ... +// +// // Commented out, compressed code +// +// Readable (more or less) version of the code +// ... + +document.addEventListener("DOMContentLoaded", go) + +function go() { + "use strict" + // JS1K's HTML shim gives us a canvas (a) and its 2D context (c) for free. We'll set them up here. + + let canvas = document.querySelector('canvas') + let ctx = canvas.getContext('2d') + + // First off - we define an abbreviation function. This takes an object, iterates over its properties + // and stores their names as strings in a 2 or 3 letter variable ("this" is the window object). + // + // p[0]+p[6] will evaluate to the 1st and 7th letter (or the 1st+"undefined" if there's no 7th), + // [p[20]] will be an empty string if the property's name is too short ([undefined] gets coerced to + // an empty string). + // + // This is a variation on Marijn Haverbeke's technique - see https://marijnhaverbeke.nl/js1k/ + // + // We won't be using it in the readable version of the demo. + + // A=o=>{for(p in o)this[p[0]+p[6]+[p[20]]]=p} + + // Next we abbreviate all the properties in our window object because requestAnimationFrame() is + // kind of long. We can't call A(window) because it will try to abbreviate all our abbreviations (since + // it stores them in the window object) so we'll use it on "top" which has the same properties. + // We really just need a shorter requestAnimationFrame(). + // + // Sidenote: this is a clear violation of JS1K rules, which is why it's very important not to read them + // before the competition is over. + + // A(top) + + // Now, since our demo is fairly heavy we use a small canvas, but we want it to be fullscreen on a + // black background, so we waste ~90 bytes on some CSS to stretch it (currently "object-fit:contain" + // doesn't work for canvas on MS browsers). + // + // To avoid wasting 90 bytes just on this, we take this opportunity to define P and Q as 'width' and + // 'height' for later. This is probably a mistake since I ended up packing it with regpack anyway. + // + // The weird bit at the end is an ES6 template literal being abused to call the array's join method + // with something that will be coerced into the string ':100%;'. + + // a.style=[P='width',Q='height','object-fit:contain;background:#000'].join`:100%;` + + canvas.style = 'width: 100%; height: 100%; object-fit:contain; background:#000;' + + // Now we need a frame counter. + + // t=0 + + let frame = 0 + + // B() is the requestAnimationFrame callback. + + // B=_=>{ + + function onFrame() { + // Set width and height on our canvases, we'll be using a smaller canvas for the godrays. This + // also clears and resets their states. While we're at it, we'll store their dimensions in one + // letter vars for later. + + // w=a[P]=512 + // h=a[Q]=256 + // W=E[P]=128 + // H=E[Q]=64 + + canvas.width = 512 + canvas.height = 256 + godraysCanvas.width = 128 + godraysCanvas.height = 64 + + // Set the sun's vertical position. + + // T=C(t++/w)*24 + + let sunY = Math.cos(frame++ / 512) * 24 // This is actually the offset from the middle of the canvas. + + // Get the 2D context for our godrays canvas, and create abbreviations for all the context properties. + + // A(F=E.getContext`2d`) + + let godraysCtx = godraysCanvas.getContext('2d') + + // Now we set the godrays' context fillstyle (window.fy is 'fillStyle') to a newly created gradient + // (cr is 'createRadialGradient') which we also run through our abbreviator. + + // A(F[fy]=g=F[cR](H,32+T,0,H,32+T,44)) // Could have shaved one more char here... + + let emissionGradient = godraysCtx.createRadialGradient( + godraysCanvas.width / 2, godraysCanvas.height / 2 + sunY, // The sun's center. + 0, // Start radius. + godraysCanvas.width / 2, godraysCanvas.height / 2 + sunY, // Sun's center again. + 44 // End radius. + ) + godraysCtx.fillStyle = emissionGradient + + // Now we addColorStops. This needs to be a dark gradient because our godrays effect will basically + // overlay it on top of itself many many times, so anything lighter will result in lots of white. + // + // If you're not space-bound you can add another stop or two, maybe fade out to black, but this + // actually looks good enough. + + // g[ao](.1,'#0C0804') + // g[ao](.2,'#060201') + + emissionGradient.addColorStop(.1, '#0C0804') // Color for pixels in radius 0 to 4.4 (44 * .1). + emissionGradient.addColorStop(.2, '#060201') // Color for everything past radius 8.8. + + // Now paint the gradient all over our godrays canvas. + + // F[fc](0,0,W,H) + + godraysCtx.fillRect(0, 0, godraysCanvas.width, godraysCanvas.height) + + // And set the fillstyle to black, we'll use it to paint our occlusion (mountains). + + // F[fy]='#000' + + godraysCtx.fillStyle = '#000' + + // For our 1K demo, we paint our sky a solid #644 reddish-brown. But here - let's do it right. + + // c[fy]=g='#644' + // c[fc](0,0,w,h) + + let skyGradient = ctx.createLinearGradient(0, 0, 0, canvas.height) + skyGradient.addColorStop(0, '#2a3e55') // Blueish at the top. + skyGradient.addColorStop(.7, '#8d4835') // Reddish at the bottom. + ctx.fillStyle = skyGradient + ctx.fillRect(0, 0, canvas.width, canvas.height) + + // Our mountains will be made by summing up sine waves of varying frequencies and amplitudes. + + // m=(f,j)=>[1721,947,547,233,73,31,7].reduce((a,v)=>a*j-C(f*v),0) + + function mountainHeight(position, roughness) { + // Our frequencies (prime numbers to avoid extra repetitions). + let frequencies = [1721, 947, 547, 233, 73, 31, 7] + // Add them up. + return frequencies.reduce((height, freq) => height * roughness - Math.cos(freq * position), 0) + } + + // Draw 4 layers of mountains. + + // for(i=0;i<4;i++)for(X=w,c[fy]=`hsl(7,23%,${23-i*6}%`;X--;F[fc](X/4,U/4+1,1,w))c[fc](X,U=W+i*25+m((t+t*i*i)/1e3+X/2e3,i/19-.5)*45,1,w) + + for (let i = 0; i < 4; i++) { + // Set the main canvas fillStyle to a shade of brown with variable lightness (darker at the front). + ctx.fillStyle = `hsl(7, 23%, ${23 - i * 6}%)` + // For each column in our canvas... + for (let x = canvas.width; x--;) { + // Ok, I don't really remember the details here, basically the (frame+frame*i*i) makes the + // near mountains move faster than the far ones. We divide by large numbers because our + // mountains repeat at position 1/7*Math.PI*2 or something like that... + let mountainPosition = (frame + frame * i * i) / 1000 + x / 2000 + // Make further mountains more jagged, adds a bit of realism and also makes the godrays + // look nicer. + let mountainRoughness = i / 19 - .5 + // 128 is the middle, i * 25 moves the nearer mountains lower on the screen. + let y = 128 + i * 25 + mountainHeight(mountainPosition, mountainRoughness) * 45 + // Paint a 1px-wide rectangle from the mountain's top to below the bottom of the canvas. + ctx.fillRect(x, y, 1, 999) // 999 can be any large number... + // Paint the same thing in black on the godrays emission canvas, which is 1/4 the size, + // and move it one pixel down (otherwise there can be a tiny underlit space between the + // mountains and the sky). + godraysCtx.fillRect(x / 4, y / 4 + 1, 1, 999) + } + } + + // The godrays are generated by adding up RGB values, gCt is the bane of all js golfers - + // globalCompositeOperation. Set it to 'lighter' on both canvases. + + // c[gCt]=F[gCt]='lighter' + + ctx.globalCompositeOperation = godraysCtx.globalCompositeOperation = 'lighter' + + // NOW - let's light this motherfucker up! We'll make several passes over our emission canvas, + // each time adding an enlarged copy of it to itself so at the first pass we get 2 copies, then 4, + // then 8, then 16 etc... We square our scale factor at each iteration. + + // for(s=1.07;s<5;s*=s)F[da](E,(W-W*s)/2,(H-H*s)/2-T*s+T,W*s,H*s) + + for (let scaleFactor = 1.07; scaleFactor < 5; scaleFactor *= scaleFactor) { + // The x, y, width and height arguments for drawImage keep the light source (godraysCanvas.width + // / 2, godraysCanvas.height / 2 + sunY) in the same spot on the enlarged copy. It basically boils + // down to multiplying a 2D matrix by itself. There's probably a better way to do this, but I + // couldn't figure it out. + godraysCtx.drawImage( + godraysCanvas, + (godraysCanvas.width - godraysCanvas.width * scaleFactor) / 2, + (godraysCanvas.height - godraysCanvas.height * scaleFactor) / 2 - sunY * scaleFactor + sunY, + godraysCanvas.width * scaleFactor, + godraysCanvas.height * scaleFactor + ) + } + + // Now that our godrays are rendered, draw them to our output canvas (whose globalCompositeOperation + // is already set to 'lighter'). + + // c[da](E,0,0,w,h) + + ctx.drawImage(godraysCanvas, 0, 0, canvas.width, canvas.height) + + // All done. + + // this[rte](B)} + + requestAnimationFrame(onFrame) + } + + // Call our requestAnimationFrame handler to start rendering. Since it takes no arguments use the argument + // list to create our godrays canvas with cloneNode, which also takes no arguments... use it to setup a + // Math.cos shortcut (we'll skip this in our longform version). + + // B(E=a.cloneNode(C=Math.cos)) + + let godraysCanvas = canvas.cloneNode() + onFrame() + + // Phew... that took a while, but we're finally done with the visuals. Now for the audio part - + // + // The synthesizer is based on the Karplus-Strong algorithm which uses a very short delay loop as a + // resonator. I was initially aiming for a realistic string quartet but time and space constraints + // have forced me to massively compromise. + // + // + // The music is a 64-note melody that ends up an octave above where it started, spread out in a 4-voice + // canon. We pre-render a single voice and then add up 4 in our ScriptProcessor callback. + + // Big hairy render loop, let's break it to pieces and explain... + + // for(M=[Y=[V=J=I=i=0]];i>6))/12)))|0]*.8||0 + + let encodedMelody = "!!----,*,(444420/20/-0/---,,--//((4444202/;;;;986986420/00--//,," + + // M=[Y=[V=J=I=i=0]] + let voiceBuffer = [] // M = [...] + let ksDelayBuffer = [] // Y = [...] + let sampleOffset = 0 // V = 0 (used later) + let J = 0 // What the hell is J???? + + // Oh fuck it. It's 4am and I have no idea how this thing works. Maybe I'll write it up later. + // Besides, you just came here for the godrays, right? + + // A(G=new AudioContext) + // A(S=G[cSr](w*8,0,1)) + // S[oo]=e=>{A(e);A(o=e[oB]);for(i=0;i0&&M[T%J])T=V-(K/32*9)*J} + // S.connect(G[da]) +} diff --git a/vue/src/plugin/canvasAnimation/moveFollowMouse/Particle.js b/vue/src/plugin/canvasAnimation/moveFollowMouse/Particle.js new file mode 100644 index 0000000..d7df772 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/moveFollowMouse/Particle.js @@ -0,0 +1,30 @@ +export default class Particle { + constructor() { + this.angleX = Math.random() * Math.PI * 2 + this.angleY = Math.random() * Math.PI * 2 + this.speedX = Math.random() + this.speedY = Math.random() + this.radius = 500 + } + + update({ctx, width, height, gravityDistance, mousePos}, speed = 0.035) { + let x = Math.cos(this.angleX) * this.radius, + y = Math.sin(this.angleY) * this.radius, + currentSpeedX = this.speedX * speed, + currentSpeedY = this.speedY * speed + + if (Math.abs(mousePos.x - width / 2 - x) < gravityDistance && Math.abs(mousePos.y - height / 2 - y) < gravityDistance) { + currentSpeedX = currentSpeedX * (Math.abs(mousePos.x - width / 2 - x) / gravityDistance) * 0.5 + currentSpeedY = currentSpeedY * (Math.abs(mousePos.y - height / 2 - y) / gravityDistance) * 0.5 + } + + this.angleX += currentSpeedX + this.angleY += currentSpeedY + + ctx.beginPath() + ctx.fillStyle = "white" + + ctx.arc(width / 2 + x, height / 2 + y, 2.5, 0, Math.PI * 2, false) + ctx.fill() + } +} diff --git a/vue/src/plugin/canvasAnimation/moveFollowMouse/index.js b/vue/src/plugin/canvasAnimation/moveFollowMouse/index.js new file mode 100644 index 0000000..21a6c7d --- /dev/null +++ b/vue/src/plugin/canvasAnimation/moveFollowMouse/index.js @@ -0,0 +1,68 @@ +import Particle from "./Particle" + +export default class MoveFollowMouse { + constructor(canvas, {num = 10, gravityDistance = 100} = {}) { + this.canvas = canvas + this.ctx = canvas.getContext('2d') + this.rAF = null + this.stopSign = false + this.particles = [] + this.num = num + this.gravityDistance = gravityDistance + this.mousePos = {x: 0, y: 0} + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.getMousePos = this.getMousePos.bind(this) + this.start() + } + + start() { + for (let i = 0; i < this.num; i += 1) { + this.particles.push(new Particle()) + } + window.addEventListener('resize', this.resize) + window.addEventListener('mousemove', this.getMousePos) + this.resize() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + window.removeEventListener('mousemove', this.getMousePos) + this.stopSign = true + this.particles = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.ctx.clearRect(0, 0, this.width, this.height) + for (let i = 0; i < this.num; i += 1) { + this.particles[i].update({ + ctx: this.ctx, + width: this.width, + height: this.height, + gravityDistance: this.gravityDistance, + mousePos: this.mousePos + }) + } + } + + getMousePos(evt) { + const rect = this.canvas.getBoundingClientRect() + this.mousePos = {x: evt.clientX - rect.left, y: evt.clientY - rect.top} + } + + resize() { + this.width = this.canvas.width = window.innerWidth + this.height = this.canvas.height = window.innerHeight + } +} diff --git a/vue/src/plugin/canvasAnimation/particleBall/Particle.js b/vue/src/plugin/canvasAnimation/particleBall/Particle.js new file mode 100644 index 0000000..bc9d857 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleBall/Particle.js @@ -0,0 +1,90 @@ +import Vector from "./Vector" +import util from "./util" + +export default class Particle { + constructor({add, sphereRad, fLen, dotImageList}) { + this.distPos = { + theta: add === true ? Math.PI / 2 : Math.random() * Math.PI, + phi: 2 * Math.random() * Math.PI + } + + this.distPos.x = sphereRad * Math.sin(this.distPos.theta) * Math.cos(this.distPos.phi) + this.distPos.y = sphereRad * Math.sin(this.distPos.theta) * Math.sin(this.distPos.phi) + this.distPos.z = sphereRad * Math.cos(this.distPos.theta) + this.distVec = new Vector(this.distPos.x, this.distPos.y, this.distPos.z) + this.unitVec = this.distVec.unit() + + this.startVec = this.distVec.multiply(1 + Math.random() * 2) + this.x = this.startVec.x + this.y = this.startVec.y + this.z = this.startVec.z + + this.veloRate = 1 + Math.random() + this.velo = this.unitVec.negative().multiply(this.veloRate) + this.finalVelo = 0 + this.m = fLen / (fLen - this.z) + + this.age = this.life = 50 + Math.floor(Math.random() * 500) + this.turnAngle = 0 + this.wanderTime = 200 + this.radius = 1 + Math.random() * 3 + + let colorRandom = Math.floor(Math.random() * 4) + switch (colorRandom) { + case 0: + this.img = dotImageList[0] + this.color = "rgba(70,255,140," + break + case 1: + this.img = dotImageList[1] + this.color = "rgba(90,90,90," + break + case 2: + this.img = dotImageList[2] + break + case 3: + this.img = dotImageList[3] + break + } + } + + update({sphereRad, fLen, turnSpeed}) { + this.nowPos = new Vector(this.x, this.y, this.z) + this.nowPosUnit = this.nowPos.unit() + + if (this.wanderTime > 0 && this.nowPos.length() > (sphereRad * 1.2)) { + this.wanderTime-- + this.velo.x += 0.1 * (Math.random() * 2 - 1) + this.velo.y += 0.1 * (Math.random() * 2 - 1) + this.velo.z += 0.1 * (Math.random() * 2 - 1) + this.x = this.x + this.velo.x + this.y = this.y + this.velo.y + this.z = this.z + this.velo.z + this.op = util.map(this.nowPos.length(), sphereRad, this.startVec.length(), 1, 0) + } + else if (this.nowPos.length() > sphereRad) { + if (this.finalPos === 0) { + this.finalPos = this.nowPosUnit.multiply(sphereRad) + } + if (this.finalVelo === 0) { + this.finalVelo = this.nowPosUnit.negative().multiply(this.veloRate) + } + this.x = this.x + this.finalVelo.x + this.y = this.y + this.finalVelo.y + this.z = this.z + this.finalVelo.z + this.op = util.map(this.nowPos.length(), sphereRad, this.startVec.length(), 1, 0) + } + else { + this.op = this.life / (this.age / 2) + this.turnAngle = (this.turnAngle + turnSpeed) % (Math.PI * 2) + let cosAngle = Math.cos(turnSpeed) + let sinAngle = Math.sin(turnSpeed) + this.x = cosAngle * this.nowPos.x + sinAngle * this.nowPos.z + this.z = -sinAngle * this.nowPos.x + cosAngle * this.nowPos.z + this.y = this.nowPos.y + this.life-- + } + + this.m = fLen / (fLen - this.z) + } +} diff --git a/vue/src/plugin/canvasAnimation/particleBall/Vector.js b/vue/src/plugin/canvasAnimation/particleBall/Vector.js new file mode 100644 index 0000000..533cdea --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleBall/Vector.js @@ -0,0 +1,74 @@ +export default class Vector { + constructor(x, y, z) { + this.x = x || 0 + this.y = y || 0 + this.z = z || 0 + } + + negative() { + return new Vector(-this.x, -this.y, -this.z) + } + + add(v) { + if (v instanceof Vector) return new Vector(this.x + v.x, this.y + v.y, this.z + v.z) + else return new Vector(this.x + v, this.y + v, this.z + v) + } + + subtract(v) { + if (v instanceof Vector) return new Vector(this.x - v.x, this.y - v.y, this.z - v.z) + else return new Vector(this.x - v, this.y - v, this.z - v) + } + + multiply(v) { + if (v instanceof Vector) return new Vector(this.x * v.x, this.y * v.y, this.z * v.z) + else return new Vector(this.x * v, this.y * v, this.z * v) + } + + divide(v) { + if (v instanceof Vector) return new Vector(this.x / v.x, this.y / v.y, this.z / v.z) + else return new Vector(this.x / v, this.y / v, this.z / v) + } + + dot(v) { + return this.x * v.x + this.y * v.y + this.z * v.z + } + + cross(v) { + return new Vector( + this.y * v.z - this.z * v.y, + this.z * v.x - this.x * v.z, + this.x * v.y - this.y * v.x + ) + } + + length() { + return Math.sqrt(this.dot(this)) + } + + unit() { + return this.divide(this.length()) + } + + min() { + return Math.min(Math.min(this.x, this.y), this.z) + } + + max() { + return Math.max(Math.max(this.x, this.y), this.z) + } + + angleTo(a) { + return Math.acos(this.dot(a) / (this.length() * a.length())) + } + + clone() { + return new Vector(this.x, this.y, this.z) + } + + init(x, y, z) { + this.x = x + this.y = y + this.z = z + return this + } +} diff --git a/vue/src/plugin/canvasAnimation/particleBall/index.js b/vue/src/plugin/canvasAnimation/particleBall/index.js new file mode 100644 index 0000000..e012cab --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleBall/index.js @@ -0,0 +1,88 @@ +import Particle from "./Particle" + +export default class ParticleBall { + constructor(canvas, {sphereRad = 130, fLen = 300, maxParticle = 400, turnSpeed = 0.005} = {}) { + this.canvas = canvas + this.ctx = canvas.getContext("2d") + this.rAF = null + this.stopSign = false + this.sphereRad = sphereRad + this.fLen = fLen + this.maxParticle = maxParticle + this.turnSpeed = turnSpeed + this.particles = [] + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.start() + } + + start() { + window.addEventListener('resize', this.resize) + this.resize() + this.initDot() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + this.stopSign = true + this.particles = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.ctx.clearRect(0, 0, this.width, this.height) + if (this.particles.length < this.maxParticle) { + this.particles.push(new Particle({ + sphereRad: this.sphereRad, + fLen: this.fLen, + dotImageList: this.dotImageList + })) + } + for (let i = 0; i < this.particles.length; i++) { + let p = this.particles[i] + if (p.life === 0) { + this.particles.splice(i, 1) + this.particles.push(new Particle({ + sphereRad: this.sphereRad, + fLen: this.fLen, + dotImageList: this.dotImageList + })) + } + + p.update({sphereRad: this.sphereRad, fLen: this.fLen, turnSpeed: this.turnSpeed}) + + if (p.m > 0) { + this.ctx.save() + this.ctx.globalAlpha = p.op + this.ctx.drawImage(p.img, p.x * p.m + this.CenterX, this.CenterY - p.y * p.m, p.radius * p.m * 2, p.radius * p.m * 2) + this.ctx.restore() + } + } + } + + resize() { + this.width = this.canvas.width = window.innerWidth + this.height = this.canvas.height = window.innerHeight + this.CenterX = this.width / 2 + this.CenterY = this.height / 2 + } + + initDot() { + this.dotImageList = [] + for (let i = 1; i <= 4; i++) { + let dotImage = new Image() + dotImage.src = "/static/img/dot" + i + ".png" + this.dotImageList.push(dotImage) + } + } +} diff --git a/vue/src/plugin/canvasAnimation/particleBall/util.js b/vue/src/plugin/canvasAnimation/particleBall/util.js new file mode 100644 index 0000000..cd82df7 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleBall/util.js @@ -0,0 +1,13 @@ +const util = { + norm: function (value, min, max) { + return (value - min) / (max - min) + }, + lerp: function (norm, min, max) { + return min + norm * (max - min) + }, + map: function (value, sourceMin, sourceMax, destMin, destMax) { + return this.lerp(this.norm(value, sourceMin, sourceMax), destMin, destMax) + } +} + +export default util diff --git a/vue/src/plugin/canvasAnimation/particleNetwork/Particle.js b/vue/src/plugin/canvasAnimation/particleNetwork/Particle.js new file mode 100644 index 0000000..0f9db69 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleNetwork/Particle.js @@ -0,0 +1,50 @@ +function getLimitedRandom(min, max, roundToInteger) { + let number = Math.random() * (max - min) + min + if (roundToInteger) number = Math.round(number) + return number +} + +function returnRandomArrayItem(array) { + return array[Math.floor(Math.random() * array.length)] +} + +export default class Particle { + constructor(parent, x, y) { + this.network = parent + this.canvas = parent.canvas + this.ctx = parent.ctx + this.particleColor = returnRandomArrayItem(this.network.options.particleColors) + this.radius = getLimitedRandom(1.5, 2.5) + this.opacity = 0 + this.x = x || Math.random() * this.canvas.width + this.y = y || Math.random() * this.canvas.height + this.velocity = { + x: (Math.random() - 0.5) * parent.options.velocity, + y: (Math.random() - 0.5) * parent.options.velocity + } + } + + update() { + this.opacity = this.opacity < 1 ? this.opacity + 0.01 : 1 + + // Change dir if outside map + if (this.x > this.canvas.width + 100 || this.x < -100) { + this.velocity.x = -this.velocity.x + } + if (this.y > this.canvas.height + 100 || this.y < -100) { + this.velocity.y = -this.velocity.y + } + + // Update position + this.x += this.velocity.x + this.y += this.velocity.y + } + + draw() { + this.ctx.beginPath() + this.ctx.fillStyle = this.particleColor + this.ctx.globalAlpha = this.opacity + this.ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI) + this.ctx.fill() + } +} diff --git a/vue/src/plugin/canvasAnimation/particleNetwork/index.js b/vue/src/plugin/canvasAnimation/particleNetwork/index.js new file mode 100644 index 0000000..4157e93 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleNetwork/index.js @@ -0,0 +1,204 @@ +import Particle from "./Particle" + +export default class ParticleNetwork { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext("2d") + this.options = { + velocity: 1, // the higher the faster + density: 15000, // the lower the denser + netLineDistance: 200, + netLineColor: '#929292', + particleColors: ['#aaa'] // ['#6D4E5C', '#aaa', '#FFC458' ] + } + this.rAF = null + this.timer = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.start() + } + + start() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + this.createParticles(true) + this.bindUiActions() + this.loop() + } + + stop() { + this.unbindUiActions() + this.stopSign = true + this.particles = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + this.ctx.globalAlpha = 1 + + // Draw connections + for (let i = 0; i < this.particles.length; i++) { + for (let j = this.particles.length - 1; j > i; j--) { + let distance, p1 = this.particles[i], p2 = this.particles[j] + + // check very simply if the two points are even a candidate for further measurements + distance = Math.min(Math.abs(p1.x - p2.x), Math.abs(p1.y - p2.y)) + if (distance > this.options.netLineDistance) continue + + // the two points seem close enough, now let's measure precisely + distance = Math.sqrt( + Math.pow(p1.x - p2.x, 2) + + Math.pow(p1.y - p2.y, 2) + ) + if (distance > this.options.netLineDistance) continue + + this.ctx.beginPath() + this.ctx.strokeStyle = this.options.netLineColor + this.ctx.globalAlpha = (this.options.netLineDistance - distance) / this.options.netLineDistance * p1.opacity * p2.opacity + this.ctx.lineWidth = 0.7 + this.ctx.moveTo(p1.x, p1.y) + this.ctx.lineTo(p2.x, p2.y) + this.ctx.stroke() + } + } + + // Draw particles + for (let i = 0; i < this.particles.length; i++) { + this.particles[i].update() + this.particles[i].draw() + } + } + + createParticles(isInitial) { + // Initialise / reset particles + this.particles = [] + let quantity = this.canvas.width * this.canvas.height / this.options.density + + if (isInitial) { + let counter = 0 + window.clearInterval(this.timer) + this.timer = setInterval(() => { + if (counter < quantity - 1) this.particles.push(new Particle(this)) + else clearInterval(this.timer) + counter++ + }, 250) + } + else for (let i = 0; i < quantity; i++) this.particles.push(new Particle(this)) + } + + createInteractionParticle() { + this.interactionParticle = new Particle(this) + this.interactionParticle.velocity = {x: 0, y: 0} + this.particles.push(this.interactionParticle) + return this.interactionParticle + } + + removeInteractionParticle() { + let index = this.particles.indexOf(this.interactionParticle) + if (index > -1) { + this.interactionParticle = undefined + this.particles.splice(index, 1) + } + } + + bindUiActions() { + this.spawnQuantity = 3 + this.mouseIsDown = false + this.touchIsMoving = false + + this.onMouseMove = function (e) { + !this.interactionParticle && this.createInteractionParticle() + this.interactionParticle.x = e.offsetX + this.interactionParticle.y = e.offsetY + }.bind(this) + + this.onTouchMove = function (e) { + e.preventDefault() + this.touchIsMoving = true + !this.interactionParticle && this.createInteractionParticle() + this.interactionParticle.x = e.changedTouches[0].clientX + this.interactionParticle.y = e.changedTouches[0].clientY + }.bind(this) + + this.onMouseDown = function (e) { + this.mouseIsDown = true + let counter = 0 + let quantity = this.spawnQuantity + let intervalId = setInterval(function () { + if (this.mouseIsDown) { + if (counter === 1) quantity = 1 + for (let i = 0; i < quantity; i++) { + if (this.interactionParticle) { + this.particles.push(new Particle(this, this.interactionParticle.x, this.interactionParticle.y)) + } + } + } + else window.clearInterval(intervalId) + counter++ + }.bind(this), 50) + }.bind(this) + + this.onTouchStart = function (e) { + e.preventDefault() + setTimeout(function () { + if (!this.touchIsMoving) { + for (let i = 0; i < this.spawnQuantity; i++) { + this.particles.push(new Particle(this, e.changedTouches[0].clientX, e.changedTouches[0].clientY)) + } + } + }.bind(this), 200) + }.bind(this) + + this.onMouseUp = function (e) { + this.mouseIsDown = false + }.bind(this) + + this.onMouseOut = function (e) { + this.removeInteractionParticle() + }.bind(this) + + this.onTouchEnd = function (e) { + e.preventDefault() + this.touchIsMoving = false + this.removeInteractionParticle() + }.bind(this) + + window.addEventListener('resize', this.resize) + window.addEventListener('mousemove', this.onMouseMove) + window.addEventListener('touchmove', this.onTouchMove) + window.addEventListener('mousedown', this.onMouseDown) + window.addEventListener('touchstart', this.onTouchStart) + window.addEventListener('mouseup', this.onMouseUp) + window.addEventListener('mouseout', this.onMouseOut) + window.addEventListener('touchend', this.onTouchEnd) + } + + unbindUiActions() { + window.removeEventListener('resize', this.resize) + window.removeEventListener('mousemove', this.onMouseMove) + window.removeEventListener('touchmove', this.onTouchMove) + window.removeEventListener('mousedown', this.onMouseDown) + window.removeEventListener('touchstart', this.onTouchStart) + window.removeEventListener('mouseup', this.onMouseUp) + window.removeEventListener('mouseout', this.onMouseOut) + window.removeEventListener('touchend', this.onTouchEnd) + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + this.createParticles() + } +} diff --git a/vue/src/plugin/canvasAnimation/particleWave/index.js b/vue/src/plugin/canvasAnimation/particleWave/index.js new file mode 100644 index 0000000..af83186 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/particleWave/index.js @@ -0,0 +1,157 @@ +function colorIntToHexString(color) { + let s = color.toString(16) + return '0'.repeat(6 - s.length) + s +} + +export default class ParticleWave { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext("2d") + this.config = { + colors: { + background: 0x000000, + particle: 0x477cc2 + }, + alpha: { + particle: 1 + }, + particleCount: 10000 + } + this.particleWaveWalker = 0 + this.rAF = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.start() + } + + initParticle() { + this.particles = new Float32Array(this.config.particleCount * 2) + for (let i = 0; i < this.particles.length; i += 2) { + this.particles[i] = Math.random() + this.particles[i + 1] = Math.random() + } + } + + initParticleColor() { + this.particleColorRGB = new Float32Array(3) + this.particleColorRGB[0] = this.config.colors.particle >> 16 & 0xff + this.particleColorRGB[1] = this.config.colors.particle >> 8 & 0xff + this.particleColorRGB[2] = this.config.colors.particle & 0xff + this.particleFillStyle = 'rgb(' + this.particleColorRGB[0] + ',' + this.particleColorRGB[1] + ',' + this.particleColorRGB[2] + ')' + } + + initSmoothGradient() { + this.smoothGradient = this.ctx.createLinearGradient( + this.canvas.width / 2, + 0, + this.canvas.width / 2, + this.canvas.height + ) + this.smoothGradient.addColorStop(0.25, 'rgba(0, 0, 0, 0)') + this.smoothGradient.addColorStop(0.45, 'rgba(0, 0, 0, 0.9)') + this.smoothGradient.addColorStop(0.5, 'rgba(0, 0, 0, 1)') + this.smoothGradient.addColorStop(0.55, 'rgba(0, 0, 0, 0.9)') + this.smoothGradient.addColorStop(0.75, 'rgba(0, 0, 0, 0)') + } + + initWaterGradient() { + this.waterGradient = this.ctx.createLinearGradient( + this.canvas.width / 2, + this.canvas.height / 2, + this.canvas.width / 2, + this.canvas.height + ) + this.waterGradient.addColorStop(0, 'rgba(0, 0, 30, 0)') + this.waterGradient.addColorStop(1, 'rgba(30, 0, 60, 0.5)') + } + + start() { + window.addEventListener('resize', this.resize) + this.resize() + this.initParticle() + this.initParticleColor() + this.initSmoothGradient() + this.initWaterGradient() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + this.stopSign = true + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.ctx.fillStyle = '#' + colorIntToHexString(this.config.colors.background) + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) + this.ctx.fillStyle = this.waterGradient + this.ctx.fillRect(0, this.canvas.height / 2, this.canvas.width, this.canvas.height / 2) + + this.renderParticle() + + this.ctx.fillStyle = this.particleFillStyle + this.ctx.fillStyle = this.smoothGradient + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) + } + + renderParticle() { + this.particleWaveWalker += 0.03 + this.ctx.fillStyle = this.particleFillStyle + + let radius = {min: 1, add: 5}, + midY = this.canvas.height / 2, + midX = this.canvas.width / 2, + spreadX = 5, + spreadZ = 0.0, + modZ = 0.0, + addX = 0, + addY = 0, + p = {x: 0.0, y: 0.0, r: 0.0}, + waveControl = 10 + + for (let i = 0, xIndex, zIndex; i < this.particles.length; i += 2) { + xIndex = i + zIndex = i + 1 + this.particles[zIndex] += 0.003 + if (this.particles[zIndex] > 1) { + this.particles[zIndex] = 0 + this.particles[xIndex] = Math.random() + } + + if (this.particles[zIndex] < 0.3) continue + + modZ = Math.pow(this.particles[zIndex], 2) + spreadZ = 1 + (spreadX - 1) * modZ + addX = (0.5 - this.particles[xIndex]) * this.canvas.width * spreadZ + addY = midY * modZ * (1 + 3 / waveControl) + + p.x = midX + addX + p.y = midY + addY + p.r = radius.min + modZ * radius.add + p.y += Math.sin(this.particles[xIndex] * 50 + this.particleWaveWalker) * addY / waveControl + p.y += Math.cos(this.particles[zIndex] * 10 + this.particleWaveWalker) * addY / waveControl + p.y -= Math.cos(this.particles[zIndex] + this.particles[xIndex] * 10 + this.particleWaveWalker) * addY / waveControl + p.y -= Math.cos(this.particles[xIndex] * 50 + this.particleWaveWalker) * addY / waveControl + p.y -= Math.sin(this.particles[zIndex] * 10 + this.particleWaveWalker) * addY / waveControl + + if (p.x < 0 || p.x > this.canvas.width) continue + + this.ctx.fillRect(p.x, p.y, p.r, p.r) + } + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + } +} diff --git a/vue/src/plugin/rain/RainDrop.js b/vue/src/plugin/canvasAnimation/reflectRain/RainDrop.js similarity index 100% rename from vue/src/plugin/rain/RainDrop.js rename to vue/src/plugin/canvasAnimation/reflectRain/RainDrop.js diff --git a/vue/src/plugin/rain/Vector.js b/vue/src/plugin/canvasAnimation/reflectRain/Vector.js similarity index 100% rename from vue/src/plugin/rain/Vector.js rename to vue/src/plugin/canvasAnimation/reflectRain/Vector.js diff --git a/vue/src/plugin/rain/index.js b/vue/src/plugin/canvasAnimation/reflectRain/index.js similarity index 90% rename from vue/src/plugin/rain/index.js rename to vue/src/plugin/canvasAnimation/reflectRain/index.js index 56d8606..688bb8d 100644 --- a/vue/src/plugin/rain/index.js +++ b/vue/src/plugin/canvasAnimation/reflectRain/index.js @@ -1,7 +1,7 @@ import RainDrop from "./RainDrop" -export default class Rain { - constructor({rainDropCount, rainColor, backgroundColor}, canvas) { +export default class ReflectRain { + constructor(canvas, {rainDropCount = 500, rainColor = 'rgba(150,180,255,0.8)', backgroundColor = '#2d3a4b'} = {}) { this.props = {rainDropCount, rainColor, backgroundColor} this.rainDrops = [] this.timer = null @@ -10,17 +10,38 @@ export default class Rain { this.canvas = canvas this.ctx = canvas.getContext('2d') this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) this.start() } - resize() { - this.dimensions = { - width: window.innerWidth, - height: window.innerHeight + start() { + window.addEventListener('resize', this.resize) + this.resize() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + this.stopSign = true + this.rainDrops = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + this.timer && window.clearTimeout(this.timer) + return } - this.canvas.width = this.dimensions.width - this.canvas.height = this.dimensions.height - this.floor = this.dimensions.height * 0.7 + if (this.rainDrops.length < this.props.rainDropCount) { + this.timer = window.setTimeout(() => this.rainDrops.push(new RainDrop(this)), Math.random() * 200) + } + else if (this.timer) { + window.clearTimeout(this.timer) + this.timer = null + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) } draw() { @@ -49,32 +70,13 @@ export default class Rain { this.ctx.restore() } - start() { - window.addEventListener('resize', this.resize) - this.resize() - this.loop() - } - - stop() { - window.removeEventListener('resize', this.resize) - this.stopSign = true - this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) - } - - loop() { - if (this.stopSign) { - this.rAF && window.cancelAnimationFrame(this.rAF) - this.timer && window.clearTimeout(this.timer) - return - } - if (this.rainDrops.length < this.props.rainDropCount) { - this.timer = window.setTimeout(() => this.rainDrops.push(new RainDrop(this)), Math.random() * 200) - } - else if (this.timer) { - window.clearTimeout(this.timer) - this.timer = null + resize() { + this.dimensions = { + width: window.innerWidth, + height: window.innerHeight } - this.draw() - this.rAF = window.requestAnimationFrame(this.loop.bind(this)) + this.canvas.width = this.dimensions.width + this.canvas.height = this.dimensions.height + this.floor = this.dimensions.height * 0.7 } } diff --git a/vue/src/plugin/canvasAnimation/sparkRain/Spark.js b/vue/src/plugin/canvasAnimation/sparkRain/Spark.js new file mode 100644 index 0000000..8209f7a --- /dev/null +++ b/vue/src/plugin/canvasAnimation/sparkRain/Spark.js @@ -0,0 +1,18 @@ +import {rand} from "./util" + +export default class Spark { + constructor(x, y, options) { + this.x = x + this.y = y + this.age = 0 + this.acceleration = rand(options.acceleration[0], options.acceleration[1]) + this.color = options.randColor ? rand(0, 255) + "," + rand(0, 255) + "," + rand(0, 255) : OPT.color + this.opacity = options.maxOpacity - this.age / (options.lifetime * rand(1, 10)) + } + + go(options) { + this.x += options.speed * options.direction.x * this.acceleration / 2 + this.y += options.speed * options.direction.y * this.acceleration / 2 + this.opacity = options.maxOpacity - ++this.age / options.lifetime + } +} diff --git a/vue/src/plugin/canvasAnimation/sparkRain/index.js b/vue/src/plugin/canvasAnimation/sparkRain/index.js new file mode 100644 index 0000000..749f298 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/sparkRain/index.js @@ -0,0 +1,86 @@ +import Spark from "./Spark" +import {rand} from "./util" + +export default class SparkRain { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext("2d") + this.options = { + amount: 10000, + speed: 0.1, // pixels per frame + lifetime: 500, + direction: {x: -0.5, y: 1}, + size: [1, 1], + maxOpacity: 1, + color: "150, 150, 150", + randColor: true, + acceleration: [5, 40] + } + if (window.innerWidth < 520) { + this.options.speed = 0.05 + this.options.color = "150, 150, 150" + } + this.sparks = [] + this.rAF = null + this.timer = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.addSpark = this.addSpark.bind(this) + this.start() + } + + start() { + window.addEventListener('resize', this.resize) + this.resize() + this.timer = window.setInterval( + () => this.sparks.length < this.options.amount && this.addSpark(), + 1000 / this.options.amount) + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + this.stopSign = true + this.sparks = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + this.timer && window.clearInterval(this.timer) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.ctx.fillStyle = 'rgba(0,0,0, 0.1)' + this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height) + for (let i = 0; i < this.sparks.length; i++) { + this.sparks[i].opacity <= 0 ? this.sparks.splice(i, 1) : this.drawSpark(this.sparks[i]) + } + } + + addSpark() { + let x = rand(-200, this.canvas.width + 200) + let y = rand(-200, this.canvas.height + 200) + this.sparks.push(new Spark(x, y, this.options)) + } + + drawSpark(spark) { + spark.go(this.options) + this.ctx.beginPath() + this.ctx.fillStyle = `rgba(${spark.color},${spark.opacity})` + this.ctx.rect(spark.x, spark.y, this.options.size[0], this.options.size[1]) + this.ctx.fill() + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + } +} + diff --git a/vue/src/plugin/canvasAnimation/sparkRain/util.js b/vue/src/plugin/canvasAnimation/sparkRain/util.js new file mode 100644 index 0000000..004fa74 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/sparkRain/util.js @@ -0,0 +1,3 @@ +export function rand(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min +} diff --git a/vue/src/plugin/canvasAnimation/sunlight/Particle.js b/vue/src/plugin/canvasAnimation/sunlight/Particle.js new file mode 100644 index 0000000..4ad797e --- /dev/null +++ b/vue/src/plugin/canvasAnimation/sunlight/Particle.js @@ -0,0 +1,81 @@ +function rand(min, max) { + return Math.random() * (max - min) + min +} + +export default class Particle { + constructor() { + this.reset() + } + + reset() { + this.x = 0 + this.y = 0 + this.z = 0 + this.vx = rand(-0.5, 0.5) + this.vy = rand(-0.5, 0.5) + this.vz = rand(-0.25, 0.5) + this.s = 0 + this.sx = 0 + this.sy = 0 + this.life = 1 + this.decay = rand(0.005, 0.02) + this.radius = rand(5, 15) + this.sradius = this.radius + this.rradius = this.radius + this.hue = 0 + this.alpha = 1 + this.angle = 0 + } + + step($) { + this.vx *= $.mouse.down ? 1.1 : 1.04 + this.vy *= $.mouse.down ? 1.1 : 1.04 + this.vz *= $.mouse.down ? 1.1 : 1.04 + this.x += this.vx + this.y += this.vy + this.z += this.vz + this.s = $.fl / ($.fl + this.z) + this.sx = this.x * this.s + this.sy = this.y * this.s + this.sradius = this.radius * this.s + this.rradius = Math.max(0.0001, this.sradius * this.life) + this.angle = Math.atan2(this.sy, this.sx) + this.hue = (this.angle / (Math.PI * 2)) * 180 + $.tick * 4 + this.alpha = this.life + if (this.z < $.bounds.z.min) return this.reset() + if (this.life > 0) this.life -= this.decay + else this.reset() + } + + draw($) { + $.ctx.beginPath() + $.ctx.arc(this.sx, this.sy, this.rradius * 2, 0, Math.PI * 2) + $.ctx.fillStyle = 'hsla(' + (this.hue + 60) + ', 60%, 30%, ' + this.alpha / 3 + ')' + $.ctx.fill() + $.ctx.strokeStyle = 'hsla(' + (this.hue - 60) + ', 60%, 30%, ' + this.alpha / 2 + ')' + $.ctx.stroke() + + let angle1 = this.angle + Math.PI / 2, + angle2 = this.angle, + angle3 = this.angle - Math.PI / 2 + + $.ctx.beginPath() + $.ctx.moveTo(0, 0) + $.ctx.lineTo(this.sx + Math.cos(angle1) * this.rradius, this.sy + Math.sin(angle1) * this.rradius) + $.ctx.lineTo(this.sx + Math.cos(angle2) * this.rradius * 6, this.sy + Math.sin(angle2) * this.rradius * 6) + $.ctx.lineTo(this.sx + Math.cos(angle3) * this.rradius, this.sy + Math.sin(angle3) * this.rradius) + $.ctx.closePath() + $.ctx.fillStyle = 'hsla(' + this.hue + ', 50%, 30%, ' + this.alpha / 2 + ')' + $.ctx.fill() + + $.ctx.beginPath() + $.ctx.moveTo(this.sx + Math.cos(angle2) * this.rradius * 6, this.sy + Math.sin(angle2) * this.rradius * 6) + $.ctx.lineTo(0, 0) + $.ctx.strokeStyle = 'hsla(' + this.hue + ', 50%, 30%, ' + this.alpha + ')' + $.ctx.stroke() + + let sparkleRadius = this.rradius * 4 + $.ctx.fillStyle = 'hsla(' + (this.hue + 180) + ', 100%, 50%, ' + this.alpha * 2 + ')' + $.ctx.fillRect((this.sx + rand(-sparkleRadius, sparkleRadius)), (this.sy + rand(-sparkleRadius, sparkleRadius)), 1, 1) + } +} diff --git a/vue/src/plugin/canvasAnimation/sunlight/index.js b/vue/src/plugin/canvasAnimation/sunlight/index.js new file mode 100644 index 0000000..2e44ec8 --- /dev/null +++ b/vue/src/plugin/canvasAnimation/sunlight/index.js @@ -0,0 +1,94 @@ +import Particle from "./Particle" + +export default class Sunlight { + constructor(canvas) { + this.canvas = canvas + this.ctx = canvas.getContext('2d') + this.parts = [] + this.mouse = {down: 0} + this.rAF = null + this.stopSign = false + this.resize = this.resize.bind(this) + this.loop = this.loop.bind(this) + this.mousedown = this.mousedown.bind(this) + this.mouseup = this.mouseup.bind(this) + this.start() + } + + start() { + window.addEventListener('resize', this.resize) + window.addEventListener('mouseup', this.mouseup) + window.addEventListener('mousedown', this.mousedown) + this.resize() + this.loop() + } + + stop() { + window.removeEventListener('resize', this.resize) + window.removeEventListener('mouseup', this.mouseup) + window.removeEventListener('mousedown', this.mousedown) + this.stopSign = true + this.parts = [] + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + this.step() + this.ctx.globalCompositeOperation = 'destination-out' + this.ctx.fillStyle = 'hsla(0, 0%, 0%, 0.6)' + this.ctx.fillRect(0, 0, this.width, this.height) + this.ctx.globalCompositeOperation = 'lighter' + this.ctx.save() + this.ctx.translate(this.width / 2, this.height / 2) + this.ctx.rotate(this.tick / 300) + let i = this.parts.length + while (i--) { + this.parts[i].draw(this) + } + this.ctx.restore() + } + + step() { + if (this.tick % 2 === 0 && this.parts.length < 200) { + this.parts.push(new Particle()) + } + let i = this.parts.length + while (i--) { + this.parts[i].step(this) + } + this.tick += this.mouse.down ? 3 : 1 + } + + mousedown() { + this.mouse.down = 1 + } + + mouseup() { + this.mouse.down = 0 + } + + resize() { + this.tick = 0 + this.width = window.innerWidth + this.height = window.innerHeight + this.canvas.width = this.width + this.canvas.height = this.height + this.mouse.down = 0 + this.fl = 300 + this.bounds = { + x: {min: -this.width / 2, max: this.width / 2}, + y: {min: -this.height / 2, max: this.height / 2}, + z: {min: -this.fl, max: 1000} + } + this.parts.length = 0 + } +} diff --git a/vue/src/store/modules/app.js b/vue/src/store/modules/app.js index 3377743..32e411a 100644 --- a/vue/src/store/modules/app.js +++ b/vue/src/store/modules/app.js @@ -4,6 +4,10 @@ const localSettings = getLocalPersonalSettings() const state = { device: 'pc', + //登陆页背景动画 + loginPageBackgroundAnimation: 'reflectRain', + //注册页背景动画 + registerPageBackgroundAnimation: 'firework', //路由页面滚动高度 scrollTop: 0, //右侧块是否含有头部 @@ -11,13 +15,19 @@ const state = { } const mutations = { - SET_DEVICE: (state, device) => { + setDevice: (state, device) => { state.device = device }, - SET_SCROLLTOP(state, scrollTop) { + setLoginPageBackgroundAnimation: (state, value) => { + state.loginPageBackgroundAnimation = value + }, + setRegisterPageBackgroundAnimation: (state, value) => { + state.registerPageBackgroundAnimation = value + }, + setScrollTop(state, scrollTop) { state.scrollTop = scrollTop }, - SET_HASHEADER(state, hasHeader) { + setHasHeader(state, hasHeader) { state.hasHeader = hasHeader } } diff --git a/vue/src/views/app/components/SetAnimation.vue b/vue/src/views/app/components/SetAnimation.vue new file mode 100644 index 0000000..fa7a8ed --- /dev/null +++ b/vue/src/views/app/components/SetAnimation.vue @@ -0,0 +1,43 @@ + + + diff --git a/vue/src/views/app/login.vue b/vue/src/views/app/login.vue index ab374dd..27aeaad 100644 --- a/vue/src/views/app/login.vue +++ b/vue/src/views/app/login.vue @@ -2,7 +2,10 @@