PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /var/softaculous/sitepad/editor/site-data/plugins/siteseo/assets/js
Viewing File: /var/softaculous/sitepad/editor/site-data/plugins/siteseo/assets/js/gsc-charts.js
jQuery(document).ready(function($){ // Function to check if we should show sample data or zeros function should_show_sample_data(){ let chartElements = document.querySelectorAll('[data-sample]'); if(chartElements.length > 0){ return chartElements[0].getAttribute('data-sample') === '1'; } return true; } let actual_data = window.siteseo_chart_data; let is_sample_data = should_show_sample_data(); let main_chart_data = is_sample_data ? { dates : ['jan', 'feb', 'march', 'april', 'may', 'jun', 'july', 'Aug'], impressions: [950000, 1100000, 1250000, 1300000, 1200000, 1000000, 900000, 1100000], clicks: [6000, 9000, 10000, 9500, 8700, 7500, 6800, 11000] } : { // here show actual data dates: actual_data.chart_data.dates || 0, impressions: actual_data.chart_data.impressions || 0, clicks: actual_data.chart_data.clicks || 0 }; let device_data = is_sample_data ? { total_clicks : '1.8k', device : ['Mobile', 'Desktop', 'Tablet'], clicks : [65, 30, 5] } : { total_clicks : actual_data.total_devices_clicks || 0, device: actual_data.device_audience.map(item => item.device), clicks: actual_data.device_audience.map(item => item.clicks) }; let country_data = is_sample_data ? { name : ['United States', 'India', 'United Kingdom', 'Canada', 'Germany'], clicks : [1200, 850, 620, 400, 250] } : { name : actual_data.country_audience.map(item => item.country), clicks : actual_data.country_audience.map(item => item.clicks) }; // Helper function to extract numeric values from arrays function extract_numeric_values(dataArray){ if(!dataArray || !Array.isArray(dataArray)) return []; // Filter out only numeric values and non-array objects return dataArray.filter(item => typeof item === 'number' && !isNaN(item)); } let keyword_line_data = is_sample_data ? { top3 : [30, 31, 32, 32, 31, 28, 29, 30], pos4_10 : [38, 42, 45, 47, 44, 43, 35, 44], pos11_50 : [25, 20, 18, 16, 17, 22, 30, 22], pos50_100 : [6, 4, 4, 3, 4, 7, 9, 3], dates : ['Nov 1', 'Nov 10', 'Nov 20', 'Dec 1', 'Dec 10', 'Dec 20', 'Jan 1', 'Jan 10'] } : { top3: extract_numeric_values(actual_data.keyword_data.top3) || 0, pos4_10: extract_numeric_values(actual_data.keyword_data.pos4_10) || 0, pos11_50: extract_numeric_values(actual_data.keyword_data.pos11_50) || 0, pos50_100: extract_numeric_values(actual_data.keyword_data.pos50_100) || 0, dates: actual_data.keyword_data.dates, }; let keyword_bar_data = is_sample_data ? [5, 10, 52, 30] : [ actual_data.keyword_distribution.top3 || 0, actual_data.keyword_distribution.pos4_10 || 0, actual_data.keyword_distribution.pos11_50 || 0, actual_data.keyword_distribution.pos50_100 || 0 ]; let metric_chart_data = is_sample_data ? { impressions: [100, 90, 80, 70, 60, 50, 40, 30], clicks: [10, 11, 10, 12, 11, 12, 13, 14], ctr: [10.0, 12.2, 12.5, 17.1, 18.3, 24.0, 32.5, 46.6], position: [15, 16, 17, 18, 19, 20, 21, 22], dates: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'] } : { impressions: actual_data.chart_data.impressions || 0, clicks: actual_data.chart_data.clicks || 0, ctr: actual_data.chart_data.ctr || 0, position: actual_data.chart_data.position || 0, dates:actual_data.chart_data.dates || 0 }; // Main Chart if(document.getElementById('seo_statistics')){ let ctx = document.getElementById('seo_statistics').getContext('2d'); let seo_statistics = new Chart(ctx, { type: 'line', data: { labels: main_chart_data.dates, datasets: [ { label: 'Search Impressions', data: main_chart_data.impressions, borderColor: is_sample_data ? 'rgba(0, 123, 255, 1)' : 'rgba(0, 123, 255, 0.8)', backgroundColor: is_sample_data ? 'rgba(0, 123, 255, 0.2)' : 'rgba(0, 123, 255, 0.1)', fill: true, yAxisID: 'yImpressions', tension: 0.4, pointRadius: 0.1, borderWidth:2 }, { label: 'Search Clicks', data: main_chart_data.clicks, borderColor: is_sample_data ? 'rgba(40, 167, 69, 1)' : 'rgba(40, 167, 69, 0.8)', backgroundColor: is_sample_data ? 'rgba(40, 167, 69, 0.1)' : 'rgba(40, 167, 69, 0.1)', fill: true, yAxisID: 'yClicks', tension: 0.4, pointRadius: 0.1, borderWidth:2 } ] }, options: { responsive: true, interaction: { mode: 'index', intersect: false }, plugins: { legend: { position: 'bottom' }, title: { display: false }, tooltip: { enabled: true } }, scales: { x: { grid: { display: false }, ticks: { stepSize: 10, callback: function(value,index){ return index % 10 === 0 ? this.getLabelForValue(value) : ''; }, }, }, yImpressions: { type: 'linear', position: 'left', beginAtZero: true, ticks: { stepSize: 3, callback: function(value) { return value >= 1000 ? (value / 1000) + 'K' : value; }, }, grid: { display: true }, border: { display: true } }, yClicks: { type: 'linear', position: 'right', beginAtZero: true, ticks: { stepSize: 0.5, callback: function(value) { return value >= 1000 ? (value / 1000) + 'K' : value; } }, grid: { display: false }, border: { display: false } } } } }); } // Keyword Multi Line Chart if(document.getElementById('siteseo_keyword_muti_line_chart')){ let keywords = document.getElementById('siteseo_keyword_muti_line_chart').getContext('2d'); // Check if we have actual data for the line chart let has_actual_line_data = !is_sample_data && keyword_line_data.top3.length > 0 && keyword_line_data.dates.length > 0; let all_data = [ ...keyword_line_data.top3, ...keyword_line_data.pos4_10, ...keyword_line_data.pos11_50, ...keyword_line_data.pos50_100 ]; let max_value = Math.max(...all_data); // Improved dynamic Y-axis max calculation let y_axis_max; if(max_value <= 5){ // For very small values, use smaller increments y_axis_max = Math.ceil(max_value / 1) * 1; // round up to nearest whole number if(y_axis_max === max_value) y_axis_max += 1; // add some padding } else if(max_value <= 20){ // For medium values, use smaller increments y_axis_max = Math.ceil(max_value / 5) * 5; } else { // For larger values, use normal increments y_axis_max = Math.ceil(max_value / 10) * 10; } // Ensure minimum y_axis_max for very small values if (y_axis_max < 5) y_axis_max = 5; let siteseo_keyword_muti_line_chart = new Chart(keywords, { type: 'line', data: { labels: has_actual_line_data ? keyword_line_data.dates : keyword_line_data.dates, datasets: [ { label: 'Top 3 Position', data: has_actual_line_data ? keyword_line_data.top3 : keyword_line_data.top3, borderColor: 'rgba(0, 90, 224, 0.7)', backgroundColor: 'rgba(0, 90, 224, 0.15)', fill: 'origin', tension: 0.4, borderWidth: 2, pointRadius: 0.1, pointHoverRadius: 5, pointBackgroundColor: 'rgba(0, 90, 224, 1)', pointBorderColor: '#ffffff', pointBorderWidth: 1, pointStyle: 'circle' }, { label: '4-10 Position', data: has_actual_line_data ? keyword_line_data.pos4_10 : keyword_line_data.pos4_10, borderColor: 'rgba(0, 170, 9, 0.7)', backgroundColor: 'rgba(0, 170, 9, 0.15)', fill: 'origin', tension: 0.4, borderWidth: 2, pointRadius: 0.1, pointHoverRadius: 5, pointBackgroundColor: 'rgba(0, 170, 9, 1)', pointBorderColor: '#ffffff', pointBorderWidth: 1, pointStyle: 'circle' }, { label: '11-50 Position', data: has_actual_line_data ? keyword_line_data.pos11_50 : keyword_line_data.pos11_50, borderColor: 'rgba(255, 140, 0, 0.7)', backgroundColor: 'rgba(255, 140, 0, 0.15)', fill: 'origin', tension: 0.4, borderWidth: 2, pointRadius: 0.1, pointHoverRadius: 5, pointBackgroundColor: 'rgba(255, 140, 0, 1)', pointBorderColor: '#ffffff', pointBorderWidth: 1, pointStyle: 'circle' }, { label: '50-100 Position', data: has_actual_line_data ? keyword_line_data.pos50_100 : keyword_line_data.pos50_100, borderColor: 'rgba(220, 20, 60, 0.7)', backgroundColor: 'rgba(220, 20, 60, 0.15)', fill: 'origin', tension: 0.4, borderWidth: 2, pointRadius: 0.1, pointHoverRadius: 5, pointBackgroundColor: 'rgba(220, 20, 60, 1)', pointBorderColor: '#ffffff', pointBorderWidth: 1, pointStyle: 'circle' } ] }, options: { responsive: true, plugins: { legend: { position: 'bottom', labels: { usePointStyle: true, padding: 20, boxWidth: 12 } }, title: { display: true, text: has_actual_line_data ? 'Keyword Position Trends' : 'Top Positions' }, tooltip: { enabled: true, mode: 'index', intersect: false, backgroundColor: 'rgba(0, 0, 0, 0.8)', padding: 12, cornerRadius: 6, displayColors: true, callbacks: { title: function(tooltipItems) { return tooltipItems[0].label; }, label: function(context) { return `${context.dataset.label}: ${context.parsed.y}`; } } } }, interaction: { mode: 'index', intersect: false }, elements: { line: { cubicInterpolationMode: 'monotone' } }, scales: { x: { grid: { display: false }, border: { display: false }, ticks: { font: { size: 11 }, callback: function(value, index, ticks) { // Show label for every 10th date only return index % 8 === 0 ? this.getLabelForValue(value) : ''; } } }, y: { beginAtZero: true, max: y_axis_max, grid: { color: 'rgba(0, 0, 0, 0.05)' }, ticks: { stepSize: y_axis_max <= 10 ? 1 : (y_axis_max <= 20 ? 5 : 10), callback: function(value) { return value; }, font: { size: 11 } } } }, animation: { duration: 1000, easing: 'easeOutQuart' }, hover: { mode: 'index', intersect: false } } }); } // Keyword Bar Chart if(document.getElementById('siteseo_keyword_bar_chart')){ let bar_chart = document.getElementById('siteseo_keyword_bar_chart').getContext('2d'); let max_bar_value = Math.max(...keyword_bar_data); let y_axis_max_bar = Math.ceil(max_bar_value / 10) * 10; // round up to nearest 10 if(y_axis_max_bar < 50) y_axis_max_bar = 50; // minimum 50 if(y_axis_max_bar > 100) y_axis_max_bar = 100; // maximum 100 let siteseo_keyword_bar_chart = new Chart(bar_chart, { type: 'bar', data: { labels: ['Top 3 Position', '4-10 Position', '11-50 Position', '50-100 Position'], datasets: [{ data: keyword_bar_data, backgroundColor: [ '#1d6ecc', '#3aaf60', '#f59b2d', '#e3485d' ], borderWidth: 0 }] }, options: { responsive: true, plugins: { legend: { display: false }, title: { display: true, text: is_sample_data ? 'Keyword Distribution' : 'Keyword Position Distribution' }, tooltip: { callbacks: { label: function(context) { return `${context.parsed.y}%`; } } } }, scales: { x: { grid: { display: false }, border: { display: false } }, y: { beginAtZero: true, min: 0, max: y_axis_max_bar, ticks: { stepSize: Math.round(y_axis_max_bar / 2), callback: function(value){ return value + "%"; } } } } } }); } // Metric Charts (Impressions, Clicks, CTR, Position) let chart_config = { type: 'line', options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: true, mode: 'index', intersect: false, callbacks: { title: function(tooltipItems){ // Show date instead of "Day X" let data_index = tooltipItems[0].dataIndex; if(metric_chart_data.dates && metric_chart_data.dates[data_index]){ return metric_chart_data.dates[data_index]; } return `Day ${data_index + 1}`; }, label: function(context){ let label = context.dataset.label || ''; if (label) { label += ': '; } if(context.parsed.y !== null){ // Format numbers appropriately if(context.dataset.label?.toLowerCase().includes('ctr')){ label += context.parsed.y.toFixed(2) + '%'; } else if(context.dataset.label?.toLowerCase().includes('position')){ label += context.parsed.y.toFixed(1); } else{ label += context.parsed.y.toLocaleString(); } } return label; } } } }, scales: { x: { display: false }, y: { display: false, beginAtZero: true } }, elements: { point: { radius: 0.01, hoverRadius: 6, hoverBackgroundColor: '#fff', hoverBorderWidth: 2 } }, layout: { padding: { top: 5, bottom: 5, left: 0, right: 0 } }, tension: 0.4, interaction: { mode: 'index', intersect: false }, hover: { mode: 'index', intersect: false } } }; // Function to generate colors based on performance using only 4 colors function get_performance_based_color(metric_type, data){ if(!data || data.length < 2) return '#3498db'; // Default blue let first_value = data[0]; let last_value = data[data.length - 1]; let percentageChange = ((last_value - first_value) / first_value) * 100; // Define the 4 colors const colors = { blue: '#3498db', green: '#2ecc71', red: '#e74c3c', yellow: '#f39c12' }; // Performance logic for each metric type switch(metric_type){ case 'impressions': // Higher is better if(last_value > first_value * 1.1) return colors.green; if(last_value > first_value) return colors.blue; if(last_value >= first_value * 0.9) return colors.yellow; return colors.red; case 'clicks': // Higher is better if(last_value > first_value * 1.15) return colors.green; // >15% increase - Green if(last_value > first_value) return colors.blue; // Any increase - Blue if(last_value >= first_value * 0.85) return colors.yellow; // <15% decrease - Yellow return colors.red; // >15% decrease - Red case 'ctr': // Higher is better if(last_value > first_value * 1.2) return colors.green; // >20% increase - Green if(last_value > first_value) return colors.blue; // Any increase - Blue if(last_value >= first_value * 0.8) return colors.yellow; // <20% decrease - Yellow return colors.red; // >20% decrease - Red case 'position': // Lower is better if(last_value < first_value * 0.8) return colors.green; // >20% improvement - Green if(last_value < first_value) return colors.blue; // Any improvement - Blue if(last_value <= first_value * 1.2) return colors.yellow; // <20% decline - Yellow return colors.red; // >20% decline - Red default: return colors.blue; // Default blue } } // Function to create metric charts let create_chart = (ctxId, data, metricType) => { if(!document.getElementById(ctxId)) return; let ctx = document.getElementById(ctxId).getContext('2d'); // Get color based on performance let chart_color = get_performance_based_color(metricType, data); let gradient = ctx.createLinearGradient(0, 0, 0, 80); gradient.addColorStop(0, `rgba(${hex_to_rgb(chart_color)}, 0.2)`); gradient.addColorStop(1, `rgba(${hex_to_rgb(chart_color)}, 0)`); // Get label for dataset const labels = { 'impressions': 'Impressions', 'clicks': 'Clicks', 'ctr': 'CTR', 'position': 'Position' }; new Chart(ctx, { ...chart_config, data: { // Use dates if available, otherwise use generic day labels labels: metric_chart_data.dates || Array.from({ length: data.length }, (_, i) => `Day ${i + 1}`), datasets: [{ label: labels[metricType] || metricType, data: data, borderColor: chart_color, borderWidth: 2, backgroundColor: gradient, fill: true, pointBackgroundColor: chart_color, pointBorderColor: '#fff', pointBorderWidth: 2, pointHoverBackgroundColor: '#fff', pointHoverBorderColor: chart_color, pointHoverBorderWidth: 3 }] } }); }; // Helper function to convert hex to rgb function hex_to_rgb(hex){ hex = hex.replace(/^#/, ''); let bigint = parseInt(hex, 16); let r = (bigint >> 16) & 255; let g = (bigint >> 8) & 255; let b = bigint & 255; return `${r}, ${g}, ${b}`; } // Create metric charts if(document.getElementById('siteseo_impressions_chart')){ create_chart('siteseo_impressions_chart', metric_chart_data.impressions, 'impressions'); } if(document.getElementById('siteseo_clicks_chart')){ create_chart('siteseo_clicks_chart', metric_chart_data.clicks, 'clicks'); } if(document.getElementById('siteseo_ctr_chart')){ create_chart('siteseo_ctr_chart', metric_chart_data.ctr, 'ctr'); } if(document.getElementById('siteseo_position_chart')){ create_chart('siteseo_position_chart', metric_chart_data.position, 'position'); } // Country data let ctx = document.getElementById('siteseo_country_statics').getContext('2d'); let my_Chart = new Chart(ctx, { type: 'bar', data: { labels: country_data.name, datasets: [{ label: 'Clicks', data: country_data.clicks, backgroundColor: '#1d6ecc', borderRadius: 5, barThickness: 'flex', maxBarThickness: 20, }] }, options: { indexAxis: 'y', responsive: false, // Disable responsive maintainAspectRatio: false, // Disable aspect ratio maintenance scales: { x: { beginAtZero: true, grid: { display: false } }, y: { grid: { display: false } } }, plugins: { legend: { display: false }, tooltip: { enabled: true } } } }); // Device data let devices_audience = document.getElementById('siteseo_device_statics').getContext('2d'); let pie_chart = new Chart(devices_audience, { type: 'doughnut', data: { labels: device_data.device, datasets: [{ data: device_data.clicks, backgroundColor : ['#1d6ecc','#3aaf60', '#f59b2d'], borderWidth: 0 }] }, options: { responsive: false, // Keep this as false maintainAspectRatio: false, // Keep this as false cutout: '70%', plugins: { legend: { display: true, position: 'bottom', labels: { usePointStyle: true, pointStyle: 'circle' } }, tooltip: { enabled: true, callbacks: { label: function(context) { return `${context.label}: ${context.raw} clicks`; } } }, title: { display: false } } }, plugins: [{ id: 'centerText', afterDraw: (chart) => { const {ctx, chartArea: {width, height}} = chart; ctx.save(); // Display total clicks ctx.font = 'bold 22px sans-serif'; ctx.fillStyle = '#111'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(device_data.total_clicks, width / 2, height / 2 - 10); // Display "clicks" label ctx.font = '12px sans-serif'; ctx.fillStyle = '#888'; ctx.fillText('Total clicks', width / 2, height / 2 + 12); ctx.restore(); } }] }); });