u-charts.js 270 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984
  1. /*
  2. * uCharts (R)
  3. * 高性能跨平台图表库,支持H5、APP、小程序(微信/支付宝/百度/头条/QQ/360/快手)、Vue、Taro等支持canvas的框架平台
  4. * Copyright (C) 2018-2022 QIUN (R) 秋云 https://www.ucharts.cn All rights reserved.
  5. * Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  6. * 复制使用请保留本段注释,感谢支持开源!
  7. *
  8. * uCharts (R) 官方网站
  9. * https://www.uCharts.cn
  10. *
  11. * 开源地址:
  12. * https://gitee.com/uCharts/uCharts
  13. *
  14. * uni-app插件市场地址:
  15. * http://ext.dcloud.net.cn/plugin?id=271
  16. *
  17. */
  18. 'use strict';
  19. var config = {
  20. version: 'v2.5.0-20230101',
  21. yAxisWidth: 15,
  22. xAxisHeight: 22,
  23. padding: [10, 10, 10, 10],
  24. rotate: false,
  25. fontSize: 13,
  26. fontColor: '#666666',
  27. dataPointShape: ['circle', 'circle', 'circle', 'circle'],
  28. color: ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'],
  29. linearColor: ['#0EE2F8', '#2BDCA8', '#FA7D8D', '#EB88E2', '#2AE3A0', '#0EE2F8', '#EB88E2', '#6773E3',
  30. '#F78A85'],
  31. pieChartLinePadding: 15,
  32. pieChartTextPadding: 5,
  33. titleFontSize: 20,
  34. subtitleFontSize: 15,
  35. radarLabelTextMargin: 13,
  36. };
  37. var assign = function(target, ...varArgs) {
  38. if (target == null) {
  39. throw new TypeError('[uCharts] Cannot convert undefined or null to object');
  40. }
  41. if (!varArgs || varArgs.length <= 0) {
  42. return target;
  43. }
  44. // 深度合并对象
  45. function deepAssign(obj1, obj2) {
  46. for (let key in obj2) {
  47. obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ?
  48. deepAssign(obj1[key], obj2[key]) : obj1[key] = obj2[key];
  49. }
  50. return obj1;
  51. }
  52. varArgs.forEach(val => {
  53. target = deepAssign(target, val);
  54. });
  55. return target;
  56. };
  57. var util = {
  58. toFixed: function toFixed(num, limit) {
  59. limit = limit || 2;
  60. if (this.isFloat(num)) {
  61. num = num.toFixed(limit);
  62. }
  63. return num;
  64. },
  65. isFloat: function isFloat(num) {
  66. return num % 1 !== 0;
  67. },
  68. approximatelyEqual: function approximatelyEqual(num1, num2) {
  69. return Math.abs(num1 - num2) < 1e-10;
  70. },
  71. isSameSign: function isSameSign(num1, num2) {
  72. return Math.abs(num1) === num1 && Math.abs(num2) === num2 || Math.abs(num1) !== num1 && Math.abs(
  73. num2) !== num2;
  74. },
  75. isSameXCoordinateArea: function isSameXCoordinateArea(p1, p2) {
  76. return this.isSameSign(p1.x, p2.x);
  77. },
  78. isCollision: function isCollision(obj1, obj2) {
  79. obj1.end = {};
  80. obj1.end.x = obj1.start.x + obj1.width;
  81. obj1.end.y = obj1.start.y - obj1.height;
  82. obj2.end = {};
  83. obj2.end.x = obj2.start.x + obj2.width;
  84. obj2.end.y = obj2.start.y - obj2.height;
  85. var flag = obj2.start.x > obj1.end.x || obj2.end.x < obj1.start.x || obj2.end.y > obj1.start.y || obj2
  86. .start.y < obj1.end.y;
  87. return !flag;
  88. }
  89. };
  90. //兼容H5点击事件
  91. function getH5Offset(e) {
  92. e.mp = {
  93. changedTouches: []
  94. };
  95. e.mp.changedTouches.push({
  96. x: e.offsetX,
  97. y: e.offsetY
  98. });
  99. return e;
  100. }
  101. // hex 转 rgba
  102. function hexToRgb(hexValue, opc) {
  103. var rgx = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  104. var hex = hexValue.replace(rgx, function(m, r, g, b) {
  105. return r + r + g + g + b + b;
  106. });
  107. var rgb = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  108. var r = parseInt(rgb[1], 16);
  109. var g = parseInt(rgb[2], 16);
  110. var b = parseInt(rgb[3], 16);
  111. return 'rgba(' + r + ',' + g + ',' + b + ',' + opc + ')';
  112. }
  113. function findRange(num, type, limit) {
  114. if (isNaN(num)) {
  115. throw new Error('[uCharts] series数据需为Number格式');
  116. }
  117. limit = limit || 10;
  118. type = type ? type : 'upper';
  119. var multiple = 1;
  120. while (limit < 1) {
  121. limit *= 10;
  122. multiple *= 10;
  123. }
  124. if (type === 'upper') {
  125. num = Math.ceil(num * multiple);
  126. } else {
  127. num = Math.floor(num * multiple);
  128. }
  129. while (num % limit !== 0) {
  130. if (type === 'upper') {
  131. if (num == num + 1) { //修复数据值过大num++无效的bug by 向日葵 @xrk_jy
  132. break;
  133. }
  134. num++;
  135. } else {
  136. num--;
  137. }
  138. }
  139. return num / multiple;
  140. }
  141. function calCandleMA(dayArr, nameArr, colorArr, kdata) {
  142. let seriesTemp = [];
  143. for (let k = 0; k < dayArr.length; k++) {
  144. let seriesItem = {
  145. data: [],
  146. name: nameArr[k],
  147. color: colorArr[k]
  148. };
  149. for (let i = 0, len = kdata.length; i < len; i++) {
  150. if (i < dayArr[k]) {
  151. seriesItem.data.push(null);
  152. continue;
  153. }
  154. let sum = 0;
  155. for (let j = 0; j < dayArr[k]; j++) {
  156. sum += kdata[i - j][1];
  157. }
  158. seriesItem.data.push(+(sum / dayArr[k]).toFixed(3));
  159. }
  160. seriesTemp.push(seriesItem);
  161. }
  162. return seriesTemp;
  163. }
  164. function calValidDistance(self, distance, chartData, config, opts) {
  165. var dataChartAreaWidth = opts.width - opts.area[1] - opts.area[3];
  166. var dataChartWidth = chartData.eachSpacing * (opts.chartData.xAxisData.xAxisPoints.length - 1);
  167. if (opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount
  168. .widthRatio > 1) {
  169. if (opts.extra.mount.widthRatio > 2) opts.extra.mount.widthRatio = 2
  170. dataChartWidth += (opts.extra.mount.widthRatio - 1) * chartData.eachSpacing;
  171. }
  172. var validDistance = distance;
  173. if (distance >= 0) {
  174. validDistance = 0;
  175. self.uevent.trigger('scrollLeft');
  176. self.scrollOption.position = 'left'
  177. opts.xAxis.scrollPosition = 'left';
  178. } else if (Math.abs(distance) >= dataChartWidth - dataChartAreaWidth) {
  179. validDistance = dataChartAreaWidth - dataChartWidth;
  180. self.uevent.trigger('scrollRight');
  181. self.scrollOption.position = 'right'
  182. opts.xAxis.scrollPosition = 'right';
  183. } else {
  184. self.scrollOption.position = distance
  185. opts.xAxis.scrollPosition = distance;
  186. }
  187. return validDistance;
  188. }
  189. function isInAngleRange(angle, startAngle, endAngle) {
  190. function adjust(angle) {
  191. while (angle < 0) {
  192. angle += 2 * Math.PI;
  193. }
  194. while (angle > 2 * Math.PI) {
  195. angle -= 2 * Math.PI;
  196. }
  197. return angle;
  198. }
  199. angle = adjust(angle);
  200. startAngle = adjust(startAngle);
  201. endAngle = adjust(endAngle);
  202. if (startAngle > endAngle) {
  203. endAngle += 2 * Math.PI;
  204. if (angle < startAngle) {
  205. angle += 2 * Math.PI;
  206. }
  207. }
  208. return angle >= startAngle && angle <= endAngle;
  209. }
  210. function createCurveControlPoints(points, i) {
  211. function isNotMiddlePoint(points, i) {
  212. if (points[i - 1] && points[i + 1]) {
  213. return points[i].y >= Math.max(points[i - 1].y, points[i + 1].y) || points[i].y <= Math.min(points[i - 1].y,
  214. points[i + 1].y);
  215. } else {
  216. return false;
  217. }
  218. }
  219. function isNotMiddlePointX(points, i) {
  220. if (points[i - 1] && points[i + 1]) {
  221. return points[i].x >= Math.max(points[i - 1].x, points[i + 1].x) || points[i].x <= Math.min(points[i - 1].x,
  222. points[i + 1].x);
  223. } else {
  224. return false;
  225. }
  226. }
  227. var a = 0.2;
  228. var b = 0.2;
  229. var pAx = null;
  230. var pAy = null;
  231. var pBx = null;
  232. var pBy = null;
  233. if (i < 1) {
  234. pAx = points[0].x + (points[1].x - points[0].x) * a;
  235. pAy = points[0].y + (points[1].y - points[0].y) * a;
  236. } else {
  237. pAx = points[i].x + (points[i + 1].x - points[i - 1].x) * a;
  238. pAy = points[i].y + (points[i + 1].y - points[i - 1].y) * a;
  239. }
  240. if (i > points.length - 3) {
  241. var last = points.length - 1;
  242. pBx = points[last].x - (points[last].x - points[last - 1].x) * b;
  243. pBy = points[last].y - (points[last].y - points[last - 1].y) * b;
  244. } else {
  245. pBx = points[i + 1].x - (points[i + 2].x - points[i].x) * b;
  246. pBy = points[i + 1].y - (points[i + 2].y - points[i].y) * b;
  247. }
  248. if (isNotMiddlePoint(points, i + 1)) {
  249. pBy = points[i + 1].y;
  250. }
  251. if (isNotMiddlePoint(points, i)) {
  252. pAy = points[i].y;
  253. }
  254. if (isNotMiddlePointX(points, i + 1)) {
  255. pBx = points[i + 1].x;
  256. }
  257. if (isNotMiddlePointX(points, i)) {
  258. pAx = points[i].x;
  259. }
  260. if (pAy >= Math.max(points[i].y, points[i + 1].y) || pAy <= Math.min(points[i].y, points[i + 1].y)) {
  261. pAy = points[i].y;
  262. }
  263. if (pBy >= Math.max(points[i].y, points[i + 1].y) || pBy <= Math.min(points[i].y, points[i + 1].y)) {
  264. pBy = points[i + 1].y;
  265. }
  266. if (pAx >= Math.max(points[i].x, points[i + 1].x) || pAx <= Math.min(points[i].x, points[i + 1].x)) {
  267. pAx = points[i].x;
  268. }
  269. if (pBx >= Math.max(points[i].x, points[i + 1].x) || pBx <= Math.min(points[i].x, points[i + 1].x)) {
  270. pBx = points[i + 1].x;
  271. }
  272. return {
  273. ctrA: {
  274. x: pAx,
  275. y: pAy
  276. },
  277. ctrB: {
  278. x: pBx,
  279. y: pBy
  280. }
  281. };
  282. }
  283. function convertCoordinateOrigin(x, y, center) {
  284. return {
  285. x: center.x + x,
  286. y: center.y - y
  287. };
  288. }
  289. function avoidCollision(obj, target) {
  290. if (target) {
  291. // is collision test
  292. while (util.isCollision(obj, target)) {
  293. if (obj.start.x > 0) {
  294. obj.start.y--;
  295. } else if (obj.start.x < 0) {
  296. obj.start.y++;
  297. } else {
  298. if (obj.start.y > 0) {
  299. obj.start.y++;
  300. } else {
  301. obj.start.y--;
  302. }
  303. }
  304. }
  305. }
  306. return obj;
  307. }
  308. function fixPieSeries(series, opts, config) {
  309. let pieSeriesArr = [];
  310. if (series.length > 0 && series[0].data.constructor.toString().indexOf('Array') > -1) {
  311. opts._pieSeries_ = series;
  312. let oldseries = series[0].data;
  313. for (var i = 0; i < oldseries.length; i++) {
  314. oldseries[i].formatter = series[0].formatter;
  315. oldseries[i].data = oldseries[i].value;
  316. pieSeriesArr.push(oldseries[i]);
  317. }
  318. opts.series = pieSeriesArr;
  319. } else {
  320. pieSeriesArr = series;
  321. }
  322. return pieSeriesArr;
  323. }
  324. function fillSeries(series, opts, config) {
  325. var index = 0;
  326. for (var i = 0; i < series.length; i++) {
  327. let item = series[i];
  328. if (!item.color) {
  329. item.color = config.color[index];
  330. index = (index + 1) % config.color.length;
  331. }
  332. if (!item.linearIndex) {
  333. item.linearIndex = i;
  334. }
  335. if (!item.index) {
  336. item.index = 0;
  337. }
  338. if (!item.type) {
  339. item.type = opts.type;
  340. }
  341. if (typeof item.show == "undefined") {
  342. item.show = true;
  343. }
  344. if (!item.type) {
  345. item.type = opts.type;
  346. }
  347. if (!item.pointShape) {
  348. item.pointShape = "circle";
  349. }
  350. if (!item.legendShape) {
  351. switch (item.type) {
  352. case 'line':
  353. item.legendShape = "line";
  354. break;
  355. case 'column':
  356. case 'bar':
  357. item.legendShape = "rect";
  358. break;
  359. case 'area':
  360. case 'mount':
  361. item.legendShape = "triangle";
  362. break;
  363. default:
  364. item.legendShape = "circle";
  365. }
  366. }
  367. }
  368. return series;
  369. }
  370. function fillCustomColor(linearType, customColor, series, config) {
  371. var newcolor = customColor || [];
  372. if (linearType == 'custom' && newcolor.length == 0) {
  373. newcolor = config.linearColor;
  374. }
  375. if (linearType == 'custom' && newcolor.length < series.length) {
  376. let chazhi = series.length - newcolor.length;
  377. for (var i = 0; i < chazhi; i++) {
  378. newcolor.push(config.linearColor[(i + 1) % config.linearColor.length]);
  379. }
  380. }
  381. return newcolor;
  382. }
  383. function getDataRange(minData, maxData) {
  384. var limit = 0;
  385. var range = maxData - minData;
  386. if (range >= 10000) {
  387. limit = 1000;
  388. } else if (range >= 1000) {
  389. limit = 100;
  390. } else if (range >= 100) {
  391. limit = 10;
  392. } else if (range >= 10) {
  393. limit = 5;
  394. } else if (range >= 1) {
  395. limit = 1;
  396. } else if (range >= 0.1) {
  397. limit = 0.1;
  398. } else if (range >= 0.01) {
  399. limit = 0.01;
  400. } else if (range >= 0.001) {
  401. limit = 0.001;
  402. } else if (range >= 0.0001) {
  403. limit = 0.0001;
  404. } else if (range >= 0.00001) {
  405. limit = 0.00001;
  406. } else {
  407. limit = 0.000001;
  408. }
  409. return {
  410. minRange: findRange(minData, 'lower', limit),
  411. maxRange: findRange(maxData, 'upper', limit)
  412. };
  413. }
  414. function measureText(text, fontSize, context) {
  415. var width = 0;
  416. text = String(text);
  417. // #ifdef MP-ALIPAY || MP-BAIDU || APP-NVUE
  418. context = false;
  419. // #endif
  420. if (context !== false && context !== undefined && context.setFontSize && context.measureText) {
  421. context.setFontSize(fontSize);
  422. return context.measureText(text).width;
  423. } else {
  424. var text = text.split('');
  425. for (let i = 0; i < text.length; i++) {
  426. let item = text[i];
  427. if (/[a-zA-Z]/.test(item)) {
  428. width += 7;
  429. } else if (/[0-9]/.test(item)) {
  430. width += 5.5;
  431. } else if (/\./.test(item)) {
  432. width += 2.7;
  433. } else if (/-/.test(item)) {
  434. width += 3.25;
  435. } else if (/:/.test(item)) {
  436. width += 2.5;
  437. } else if (/[\u4e00-\u9fa5]/.test(item)) {
  438. width += 10;
  439. } else if (/\(|\)/.test(item)) {
  440. width += 3.73;
  441. } else if (/\s/.test(item)) {
  442. width += 2.5;
  443. } else if (/%/.test(item)) {
  444. width += 8;
  445. } else {
  446. width += 10;
  447. }
  448. }
  449. return width * fontSize / 10;
  450. }
  451. }
  452. function dataCombine(series) {
  453. return series.reduce(function(a, b) {
  454. return (a.data ? a.data : a).concat(b.data);
  455. }, []);
  456. }
  457. function dataCombineStack(series, len) {
  458. var sum = new Array(len);
  459. for (var j = 0; j < sum.length; j++) {
  460. sum[j] = 0;
  461. }
  462. for (var i = 0; i < series.length; i++) {
  463. for (var j = 0; j < sum.length; j++) {
  464. sum[j] += series[i].data[j];
  465. }
  466. }
  467. return series.reduce(function(a, b) {
  468. return (a.data ? a.data : a).concat(b.data).concat(sum);
  469. }, []);
  470. }
  471. function getTouches(touches, opts, e) {
  472. let x, y;
  473. if (touches.clientX) {
  474. if (opts.rotate) {
  475. y = opts.height - touches.clientX * opts.pix;
  476. x = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pix / 2) * (opts.pix - 1)) * opts.pix;
  477. } else {
  478. x = touches.clientX * opts.pix;
  479. y = (touches.pageY - e.currentTarget.offsetTop - (opts.height / opts.pix / 2) * (opts.pix - 1)) * opts.pix;
  480. }
  481. } else {
  482. if (opts.rotate) {
  483. y = opts.height - touches.x * opts.pix;
  484. x = touches.y * opts.pix;
  485. } else {
  486. x = touches.x * opts.pix;
  487. y = touches.y * opts.pix;
  488. }
  489. }
  490. return {
  491. x: x,
  492. y: y
  493. }
  494. }
  495. function getSeriesDataItem(series, index, group) {
  496. var data = [];
  497. var newSeries = [];
  498. var indexIsArr = index.constructor.toString().indexOf('Array') > -1;
  499. if (indexIsArr) {
  500. let tempSeries = filterSeries(series);
  501. for (var i = 0; i < group.length; i++) {
  502. newSeries.push(tempSeries[group[i]]);
  503. }
  504. } else {
  505. newSeries = series;
  506. };
  507. for (let i = 0; i < newSeries.length; i++) {
  508. let item = newSeries[i];
  509. let tmpindex = -1;
  510. if (indexIsArr) {
  511. tmpindex = index[i];
  512. } else {
  513. tmpindex = index;
  514. }
  515. if (item.data[tmpindex] !== null && typeof item.data[tmpindex] !== 'undefined' && item.show) {
  516. let seriesItem = {};
  517. seriesItem.color = item.color;
  518. seriesItem.type = item.type;
  519. seriesItem.style = item.style;
  520. seriesItem.pointShape = item.pointShape;
  521. seriesItem.disableLegend = item.disableLegend;
  522. seriesItem.legendShape = item.legendShape;
  523. seriesItem.name = item.name;
  524. seriesItem.show = item.show;
  525. seriesItem.data = item.formatter ? item.formatter(item.data[tmpindex]) : item.data[tmpindex];
  526. data.push(seriesItem);
  527. }
  528. }
  529. return data;
  530. }
  531. function getMaxTextListLength(list, fontSize, context) {
  532. var lengthList = list.map(function(item) {
  533. return measureText(item, fontSize, context);
  534. });
  535. return Math.max.apply(null, lengthList);
  536. }
  537. function getRadarCoordinateSeries(length) {
  538. var eachAngle = 2 * Math.PI / length;
  539. var CoordinateSeries = [];
  540. for (var i = 0; i < length; i++) {
  541. CoordinateSeries.push(eachAngle * i);
  542. }
  543. return CoordinateSeries.map(function(item) {
  544. return -1 * item + Math.PI / 2;
  545. });
  546. }
  547. function getToolTipData(seriesData, opts, index, group, categories) {
  548. var option = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
  549. var calPoints = opts.chartData.calPoints ? opts.chartData.calPoints : [];
  550. let points = {};
  551. if (group.length > 0) {
  552. let filterPoints = [];
  553. for (let i = 0; i < group.length; i++) {
  554. filterPoints.push(calPoints[group[i]])
  555. }
  556. points = filterPoints[0][index[0]];
  557. } else {
  558. for (let i = 0; i < calPoints.length; i++) {
  559. if (calPoints[i][index]) {
  560. points = calPoints[i][index];
  561. break;
  562. }
  563. }
  564. };
  565. var textList = seriesData.map(function(item) {
  566. let titleText = null;
  567. if (opts.categories && opts.categories.length > 0) {
  568. titleText = categories[index];
  569. };
  570. return {
  571. text: option.formatter ? option.formatter(item, titleText, index, opts) : item.name + ': ' + item
  572. .data,
  573. color: item.color,
  574. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  575. .legendShape
  576. };
  577. });
  578. var offset = {
  579. x: Math.round(points.x),
  580. y: Math.round(points.y)
  581. };
  582. return {
  583. textList: textList,
  584. offset: offset
  585. };
  586. }
  587. function getMixToolTipData(seriesData, opts, index, categories) {
  588. var option = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
  589. var points = opts.chartData.xAxisPoints[index] + opts.chartData.eachSpacing / 2;
  590. var textList = seriesData.map(function(item) {
  591. return {
  592. text: option.formatter ? option.formatter(item, categories[index], index, opts) : item.name + ': ' +
  593. item.data,
  594. color: item.color,
  595. disableLegend: item.disableLegend ? true : false,
  596. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  597. .legendShape
  598. };
  599. });
  600. textList = textList.filter(function(item) {
  601. if (item.disableLegend !== true) {
  602. return item;
  603. }
  604. });
  605. var offset = {
  606. x: Math.round(points),
  607. y: 0
  608. };
  609. return {
  610. textList: textList,
  611. offset: offset
  612. };
  613. }
  614. function getCandleToolTipData(series, seriesData, opts, index, categories, extra) {
  615. var option = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {};
  616. var calPoints = opts.chartData.calPoints;
  617. let upColor = extra.color.upFill;
  618. let downColor = extra.color.downFill;
  619. //颜色顺序为开盘,收盘,最低,最高
  620. let color = [upColor, upColor, downColor, upColor];
  621. var textList = [];
  622. seriesData.map(function(item) {
  623. if (index == 0) {
  624. if (item.data[1] - item.data[0] < 0) {
  625. color[1] = downColor;
  626. } else {
  627. color[1] = upColor;
  628. }
  629. } else {
  630. if (item.data[0] < series[index - 1][1]) {
  631. color[0] = downColor;
  632. }
  633. if (item.data[1] < item.data[0]) {
  634. color[1] = downColor;
  635. }
  636. if (item.data[2] > series[index - 1][1]) {
  637. color[2] = upColor;
  638. }
  639. if (item.data[3] < series[index - 1][1]) {
  640. color[3] = downColor;
  641. }
  642. }
  643. let text1 = {
  644. text: '开盘:' + item.data[0],
  645. color: color[0],
  646. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  647. .legendShape
  648. };
  649. let text2 = {
  650. text: '收盘:' + item.data[1],
  651. color: color[1],
  652. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  653. .legendShape
  654. };
  655. let text3 = {
  656. text: '最低:' + item.data[2],
  657. color: color[2],
  658. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  659. .legendShape
  660. };
  661. let text4 = {
  662. text: '最高:' + item.data[3],
  663. color: color[3],
  664. legendShape: opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : opts.extra.tooltip
  665. .legendShape
  666. };
  667. textList.push(text1, text2, text3, text4);
  668. });
  669. var validCalPoints = [];
  670. var offset = {
  671. x: 0,
  672. y: 0
  673. };
  674. for (let i = 0; i < calPoints.length; i++) {
  675. let points = calPoints[i];
  676. if (typeof points[index] !== 'undefined' && points[index] !== null) {
  677. validCalPoints.push(points[index]);
  678. }
  679. }
  680. offset.x = Math.round(validCalPoints[0][0].x);
  681. return {
  682. textList: textList,
  683. offset: offset
  684. };
  685. }
  686. function filterSeries(series) {
  687. let tempSeries = [];
  688. for (let i = 0; i < series.length; i++) {
  689. if (series[i].show == true) {
  690. tempSeries.push(series[i])
  691. }
  692. }
  693. return tempSeries;
  694. }
  695. function findCurrentIndex(currentPoints, calPoints, opts, config) {
  696. var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
  697. var current = {
  698. index: -1,
  699. group: []
  700. };
  701. var spacing = opts.chartData.eachSpacing / 2;
  702. let xAxisPoints = [];
  703. if (calPoints && calPoints.length > 0) {
  704. if (!opts.categories) {
  705. spacing = 0;
  706. } else {
  707. for (let i = 1; i < opts.chartData.xAxisPoints.length; i++) {
  708. xAxisPoints.push(opts.chartData.xAxisPoints[i] - spacing);
  709. }
  710. if ((opts.type == 'line' || opts.type == 'area') && opts.xAxis.boundaryGap == 'justify') {
  711. xAxisPoints = opts.chartData.xAxisPoints;
  712. }
  713. }
  714. if (isInExactChartArea(currentPoints, opts, config)) {
  715. if (!opts.categories) {
  716. let timePoints = Array(calPoints.length);
  717. for (let i = 0; i < calPoints.length; i++) {
  718. timePoints[i] = Array(calPoints[i].length)
  719. for (let j = 0; j < calPoints[i].length; j++) {
  720. timePoints[i][j] = (Math.abs(calPoints[i][j].x - currentPoints.x));
  721. }
  722. };
  723. let pointValue = Array(timePoints.length);
  724. let pointIndex = Array(timePoints.length);
  725. for (let i = 0; i < timePoints.length; i++) {
  726. pointValue[i] = Math.min.apply(null, timePoints[i]);
  727. pointIndex[i] = timePoints[i].indexOf(pointValue[i]);
  728. }
  729. let minValue = Math.min.apply(null, pointValue);
  730. current.index = [];
  731. for (let i = 0; i < pointValue.length; i++) {
  732. if (pointValue[i] == minValue) {
  733. current.group.push(i);
  734. current.index.push(pointIndex[i]);
  735. }
  736. };
  737. } else {
  738. xAxisPoints.forEach(function(item, index) {
  739. if (currentPoints.x + offset + spacing > item) {
  740. current.index = index;
  741. }
  742. });
  743. }
  744. }
  745. }
  746. return current;
  747. }
  748. function findBarChartCurrentIndex(currentPoints, calPoints, opts, config) {
  749. var offset = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
  750. var current = {
  751. index: -1,
  752. group: []
  753. };
  754. var spacing = opts.chartData.eachSpacing / 2;
  755. let yAxisPoints = opts.chartData.yAxisPoints;
  756. if (calPoints && calPoints.length > 0) {
  757. if (isInExactChartArea(currentPoints, opts, config)) {
  758. yAxisPoints.forEach(function(item, index) {
  759. if (currentPoints.y + offset + spacing > item) {
  760. current.index = index;
  761. }
  762. });
  763. }
  764. }
  765. return current;
  766. }
  767. function findLegendIndex(currentPoints, legendData, opts) {
  768. let currentIndex = -1;
  769. let gap = 0;
  770. if (isInExactLegendArea(currentPoints, legendData.area)) {
  771. let points = legendData.points;
  772. let index = -1;
  773. for (let i = 0, len = points.length; i < len; i++) {
  774. let item = points[i];
  775. for (let j = 0; j < item.length; j++) {
  776. index += 1;
  777. let area = item[j]['area'];
  778. if (area && currentPoints.x > area[0] - gap && currentPoints.x < area[2] + gap && currentPoints.y >
  779. area[1] - gap && currentPoints.y < area[3] + gap) {
  780. currentIndex = index;
  781. break;
  782. }
  783. }
  784. }
  785. return currentIndex;
  786. }
  787. return currentIndex;
  788. }
  789. function isInExactLegendArea(currentPoints, area) {
  790. return currentPoints.x > area.start.x && currentPoints.x < area.end.x && currentPoints.y > area.start.y &&
  791. currentPoints.y < area.end.y;
  792. }
  793. function isInExactChartArea(currentPoints, opts, config) {
  794. return currentPoints.x <= opts.width - opts.area[1] + 10 && currentPoints.x >= opts.area[3] - 10 && currentPoints
  795. .y >= opts.area[0] && currentPoints.y <= opts.height - opts.area[2];
  796. }
  797. function findRadarChartCurrentIndex(currentPoints, radarData, count) {
  798. var eachAngleArea = 2 * Math.PI / count;
  799. var currentIndex = -1;
  800. if (isInExactPieChartArea(currentPoints, radarData.center, radarData.radius)) {
  801. var fixAngle = function fixAngle(angle) {
  802. if (angle < 0) {
  803. angle += 2 * Math.PI;
  804. }
  805. if (angle > 2 * Math.PI) {
  806. angle -= 2 * Math.PI;
  807. }
  808. return angle;
  809. };
  810. var angle = Math.atan2(radarData.center.y - currentPoints.y, currentPoints.x - radarData.center.x);
  811. angle = -1 * angle;
  812. if (angle < 0) {
  813. angle += 2 * Math.PI;
  814. }
  815. var angleList = radarData.angleList.map(function(item) {
  816. item = fixAngle(-1 * item);
  817. return item;
  818. });
  819. angleList.forEach(function(item, index) {
  820. var rangeStart = fixAngle(item - eachAngleArea / 2);
  821. var rangeEnd = fixAngle(item + eachAngleArea / 2);
  822. if (rangeEnd < rangeStart) {
  823. rangeEnd += 2 * Math.PI;
  824. }
  825. if (angle >= rangeStart && angle <= rangeEnd || angle + 2 * Math.PI >= rangeStart && angle + 2 *
  826. Math.PI <= rangeEnd) {
  827. currentIndex = index;
  828. }
  829. });
  830. }
  831. return currentIndex;
  832. }
  833. function findFunnelChartCurrentIndex(currentPoints, funnelData) {
  834. var currentIndex = -1;
  835. for (var i = 0, len = funnelData.series.length; i < len; i++) {
  836. var item = funnelData.series[i];
  837. if (currentPoints.x > item.funnelArea[0] && currentPoints.x < item.funnelArea[2] && currentPoints.y > item
  838. .funnelArea[1] && currentPoints.y < item.funnelArea[3]) {
  839. currentIndex = i;
  840. break;
  841. }
  842. }
  843. return currentIndex;
  844. }
  845. function findWordChartCurrentIndex(currentPoints, wordData) {
  846. var currentIndex = -1;
  847. for (var i = 0, len = wordData.length; i < len; i++) {
  848. var item = wordData[i];
  849. if (currentPoints.x > item.area[0] && currentPoints.x < item.area[2] && currentPoints.y > item.area[1] &&
  850. currentPoints.y < item.area[3]) {
  851. currentIndex = i;
  852. break;
  853. }
  854. }
  855. return currentIndex;
  856. }
  857. function findMapChartCurrentIndex(currentPoints, opts) {
  858. var currentIndex = -1;
  859. var cData = opts.chartData.mapData;
  860. var data = opts.series;
  861. var tmp = pointToCoordinate(currentPoints.y, currentPoints.x, cData.bounds, cData.scale, cData.xoffset, cData
  862. .yoffset);
  863. var poi = [tmp.x, tmp.y];
  864. for (var i = 0, len = data.length; i < len; i++) {
  865. var item = data[i].geometry.coordinates;
  866. if (isPoiWithinPoly(poi, item, opts.chartData.mapData.mercator)) {
  867. currentIndex = i;
  868. break;
  869. }
  870. }
  871. return currentIndex;
  872. }
  873. function findRoseChartCurrentIndex(currentPoints, pieData, opts) {
  874. var currentIndex = -1;
  875. var series = getRoseDataPoints(opts._series_, opts.extra.rose.type, pieData.radius, pieData.radius);
  876. if (pieData && pieData.center && isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
  877. var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
  878. angle = -angle;
  879. if (opts.extra.rose && opts.extra.rose.offsetAngle) {
  880. angle = angle - opts.extra.rose.offsetAngle * Math.PI / 180;
  881. }
  882. for (var i = 0, len = series.length; i < len; i++) {
  883. if (isInAngleRange(angle, series[i]._start_, series[i]._start_ + series[i]._rose_proportion_ * 2 * Math
  884. .PI)) {
  885. currentIndex = i;
  886. break;
  887. }
  888. }
  889. }
  890. return currentIndex;
  891. }
  892. function findPieChartCurrentIndex(currentPoints, pieData, opts) {
  893. var currentIndex = -1;
  894. var series = getPieDataPoints(pieData.series);
  895. if (pieData && pieData.center && isInExactPieChartArea(currentPoints, pieData.center, pieData.radius)) {
  896. var angle = Math.atan2(pieData.center.y - currentPoints.y, currentPoints.x - pieData.center.x);
  897. angle = -angle;
  898. if (opts.extra.pie && opts.extra.pie.offsetAngle) {
  899. angle = angle - opts.extra.pie.offsetAngle * Math.PI / 180;
  900. }
  901. if (opts.extra.ring && opts.extra.ring.offsetAngle) {
  902. angle = angle - opts.extra.ring.offsetAngle * Math.PI / 180;
  903. }
  904. for (var i = 0, len = series.length; i < len; i++) {
  905. if (isInAngleRange(angle, series[i]._start_, series[i]._start_ + series[i]._proportion_ * 2 * Math.PI)) {
  906. currentIndex = i;
  907. break;
  908. }
  909. }
  910. }
  911. return currentIndex;
  912. }
  913. function isInExactPieChartArea(currentPoints, center, radius) {
  914. return Math.pow(currentPoints.x - center.x, 2) + Math.pow(currentPoints.y - center.y, 2) <= Math.pow(radius, 2);
  915. }
  916. function splitPoints(points, eachSeries) {
  917. var newPoints = [];
  918. var items = [];
  919. points.forEach(function(item, index) {
  920. if (eachSeries.connectNulls) {
  921. if (item !== null) {
  922. items.push(item);
  923. }
  924. } else {
  925. if (item !== null) {
  926. items.push(item);
  927. } else {
  928. if (items.length) {
  929. newPoints.push(items);
  930. }
  931. items = [];
  932. }
  933. }
  934. });
  935. if (items.length) {
  936. newPoints.push(items);
  937. }
  938. return newPoints;
  939. }
  940. function calLegendData(series, opts, config, chartData, context) {
  941. let legendData = {
  942. area: {
  943. start: {
  944. x: 0,
  945. y: 0
  946. },
  947. end: {
  948. x: 0,
  949. y: 0
  950. },
  951. width: 0,
  952. height: 0,
  953. wholeWidth: 0,
  954. wholeHeight: 0
  955. },
  956. points: [],
  957. widthArr: [],
  958. heightArr: []
  959. };
  960. if (opts.legend.show === false) {
  961. chartData.legendData = legendData;
  962. return legendData;
  963. }
  964. let padding = opts.legend.padding * opts.pix;
  965. let margin = opts.legend.margin * opts.pix;
  966. let fontSize = opts.legend.fontSize ? opts.legend.fontSize * opts.pix : config.fontSize;
  967. let shapeWidth = 15 * opts.pix;
  968. let shapeRight = 5 * opts.pix;
  969. let lineHeight = Math.max(opts.legend.lineHeight * opts.pix, fontSize);
  970. if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
  971. let legendList = [];
  972. let widthCount = 0;
  973. let widthCountArr = [];
  974. let currentRow = [];
  975. for (let i = 0; i < series.length; i++) {
  976. let item = series[i];
  977. const legendText = item.legendText ? item.legendText : item.name;
  978. let itemWidth = shapeWidth + shapeRight + measureText(legendText || 'undefined', fontSize, context) + opts
  979. .legend.itemGap * opts.pix;
  980. if (widthCount + itemWidth > opts.width - opts.area[1] - opts.area[3]) {
  981. legendList.push(currentRow);
  982. widthCountArr.push(widthCount - opts.legend.itemGap * opts.pix);
  983. widthCount = itemWidth;
  984. currentRow = [item];
  985. } else {
  986. widthCount += itemWidth;
  987. currentRow.push(item);
  988. }
  989. }
  990. if (currentRow.length) {
  991. legendList.push(currentRow);
  992. widthCountArr.push(widthCount - opts.legend.itemGap * opts.pix);
  993. legendData.widthArr = widthCountArr;
  994. let legendWidth = Math.max.apply(null, widthCountArr);
  995. switch (opts.legend.float) {
  996. case 'left':
  997. legendData.area.start.x = opts.area[3];
  998. legendData.area.end.x = opts.area[3] + legendWidth + 2 * padding;
  999. break;
  1000. case 'right':
  1001. legendData.area.start.x = opts.width - opts.area[1] - legendWidth - 2 * padding;
  1002. legendData.area.end.x = opts.width - opts.area[1];
  1003. break;
  1004. default:
  1005. legendData.area.start.x = (opts.width - legendWidth) / 2 - padding;
  1006. legendData.area.end.x = (opts.width + legendWidth) / 2 + padding;
  1007. }
  1008. legendData.area.width = legendWidth + 2 * padding;
  1009. legendData.area.wholeWidth = legendWidth + 2 * padding;
  1010. legendData.area.height = legendList.length * lineHeight + 2 * padding;
  1011. legendData.area.wholeHeight = legendList.length * lineHeight + 2 * padding + 2 * margin;
  1012. legendData.points = legendList;
  1013. }
  1014. } else {
  1015. let len = series.length;
  1016. let maxHeight = opts.height - opts.area[0] - opts.area[2] - 2 * margin - 2 * padding;
  1017. let maxLength = Math.min(Math.floor(maxHeight / lineHeight), len);
  1018. legendData.area.height = maxLength * lineHeight + padding * 2;
  1019. legendData.area.wholeHeight = maxLength * lineHeight + padding * 2;
  1020. switch (opts.legend.float) {
  1021. case 'top':
  1022. legendData.area.start.y = opts.area[0] + margin;
  1023. legendData.area.end.y = opts.area[0] + margin + legendData.area.height;
  1024. break;
  1025. case 'bottom':
  1026. legendData.area.start.y = opts.height - opts.area[2] - margin - legendData.area.height;
  1027. legendData.area.end.y = opts.height - opts.area[2] - margin;
  1028. break;
  1029. default:
  1030. legendData.area.start.y = (opts.height - legendData.area.height) / 2;
  1031. legendData.area.end.y = (opts.height + legendData.area.height) / 2;
  1032. }
  1033. let lineNum = len % maxLength === 0 ? len / maxLength : Math.floor((len / maxLength) + 1);
  1034. let currentRow = [];
  1035. for (let i = 0; i < lineNum; i++) {
  1036. let temp = series.slice(i * maxLength, i * maxLength + maxLength);
  1037. currentRow.push(temp);
  1038. }
  1039. legendData.points = currentRow;
  1040. if (currentRow.length) {
  1041. for (let i = 0; i < currentRow.length; i++) {
  1042. let item = currentRow[i];
  1043. let maxWidth = 0;
  1044. for (let j = 0; j < item.length; j++) {
  1045. let itemWidth = shapeWidth + shapeRight + measureText(item[j].name || 'undefined', fontSize,
  1046. context) + opts.legend.itemGap * opts.pix;
  1047. if (itemWidth > maxWidth) {
  1048. maxWidth = itemWidth;
  1049. }
  1050. }
  1051. legendData.widthArr.push(maxWidth);
  1052. legendData.heightArr.push(item.length * lineHeight + padding * 2);
  1053. }
  1054. let legendWidth = 0
  1055. for (let i = 0; i < legendData.widthArr.length; i++) {
  1056. legendWidth += legendData.widthArr[i];
  1057. }
  1058. legendData.area.width = legendWidth - opts.legend.itemGap * opts.pix + 2 * padding;
  1059. legendData.area.wholeWidth = legendData.area.width + padding;
  1060. }
  1061. }
  1062. switch (opts.legend.position) {
  1063. case 'top':
  1064. legendData.area.start.y = opts.area[0] + margin;
  1065. legendData.area.end.y = opts.area[0] + margin + legendData.area.height;
  1066. break;
  1067. case 'bottom':
  1068. legendData.area.start.y = opts.height - opts.area[2] - legendData.area.height - margin;
  1069. legendData.area.end.y = opts.height - opts.area[2] - margin;
  1070. break;
  1071. case 'left':
  1072. legendData.area.start.x = opts.area[3];
  1073. legendData.area.end.x = opts.area[3] + legendData.area.width;
  1074. break;
  1075. case 'right':
  1076. legendData.area.start.x = opts.width - opts.area[1] - legendData.area.width;
  1077. legendData.area.end.x = opts.width - opts.area[1];
  1078. break;
  1079. }
  1080. chartData.legendData = legendData;
  1081. return legendData;
  1082. }
  1083. function calCategoriesData(categories, opts, config, eachSpacing, context) {
  1084. var result = {
  1085. angle: 0,
  1086. xAxisHeight: opts.xAxis.lineHeight * opts.pix + opts.xAxis.marginTop * opts.pix
  1087. };
  1088. var fontSize = opts.xAxis.fontSize * opts.pix;
  1089. var categoriesTextLenth = categories.map(function(item, index) {
  1090. var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item, index, opts) : item;
  1091. return measureText(String(xitem), fontSize, context);
  1092. });
  1093. var maxTextLength = Math.max.apply(this, categoriesTextLenth);
  1094. if (opts.xAxis.rotateLabel == true) {
  1095. result.angle = opts.xAxis.rotateAngle * Math.PI / 180;
  1096. let tempHeight = opts.xAxis.marginTop * opts.pix * 2 + Math.abs(maxTextLength * Math.sin(result.angle))
  1097. tempHeight = tempHeight < fontSize + opts.xAxis.marginTop * opts.pix * 2 ? tempHeight + opts.xAxis.marginTop *
  1098. opts.pix * 2 : tempHeight;
  1099. result.xAxisHeight = tempHeight;
  1100. }
  1101. if (opts.enableScroll && opts.xAxis.scrollShow) {
  1102. result.xAxisHeight += 6 * opts.pix;
  1103. }
  1104. if (opts.xAxis.disabled) {
  1105. result.xAxisHeight = 0;
  1106. }
  1107. return result;
  1108. }
  1109. function getXAxisTextList(series, opts, config, stack) {
  1110. var index = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : -1;
  1111. var data;
  1112. if (stack == 'stack') {
  1113. data = dataCombineStack(series, opts.categories.length);
  1114. } else {
  1115. data = dataCombine(series);
  1116. }
  1117. var sorted = [];
  1118. // remove null from data
  1119. data = data.filter(function(item) {
  1120. //return item !== null;
  1121. if (typeof item === 'object' && item !== null) {
  1122. if (item.constructor.toString().indexOf('Array') > -1) {
  1123. return item !== null;
  1124. } else {
  1125. return item.value !== null;
  1126. }
  1127. } else {
  1128. return item !== null;
  1129. }
  1130. });
  1131. data.map(function(item) {
  1132. if (typeof item === 'object') {
  1133. if (item.constructor.toString().indexOf('Array') > -1) {
  1134. if (opts.type == 'candle') {
  1135. item.map(function(subitem) {
  1136. sorted.push(subitem);
  1137. })
  1138. } else {
  1139. sorted.push(item[0]);
  1140. }
  1141. } else {
  1142. sorted.push(item.value);
  1143. }
  1144. } else {
  1145. sorted.push(item);
  1146. }
  1147. })
  1148. var minData = 0;
  1149. var maxData = 0;
  1150. if (sorted.length > 0) {
  1151. minData = Math.min.apply(this, sorted);
  1152. maxData = Math.max.apply(this, sorted);
  1153. }
  1154. //为了兼容v1.9.0之前的项目
  1155. if (index > -1) {
  1156. if (typeof opts.xAxis.data[index].min === 'number') {
  1157. minData = Math.min(opts.xAxis.data[index].min, minData);
  1158. }
  1159. if (typeof opts.xAxis.data[index].max === 'number') {
  1160. maxData = Math.max(opts.xAxis.data[index].max, maxData);
  1161. }
  1162. } else {
  1163. if (typeof opts.xAxis.min === 'number') {
  1164. minData = Math.min(opts.xAxis.min, minData);
  1165. }
  1166. if (typeof opts.xAxis.max === 'number') {
  1167. maxData = Math.max(opts.xAxis.max, maxData);
  1168. }
  1169. }
  1170. if (minData === maxData) {
  1171. var rangeSpan = maxData || 10;
  1172. maxData += rangeSpan;
  1173. }
  1174. //var dataRange = getDataRange(minData, maxData);
  1175. var minRange = minData;
  1176. var maxRange = maxData;
  1177. var range = [];
  1178. var eachRange = (maxRange - minRange) / opts.xAxis.splitNumber;
  1179. for (var i = 0; i <= opts.xAxis.splitNumber; i++) {
  1180. range.push(minRange + eachRange * i);
  1181. }
  1182. return range;
  1183. }
  1184. function calXAxisData(series, opts, config, context) {
  1185. //堆叠图重算Y轴
  1186. var columnstyle = assign({}, {
  1187. type: ""
  1188. }, opts.extra.bar);
  1189. var result = {
  1190. angle: 0,
  1191. xAxisHeight: opts.xAxis.lineHeight * opts.pix + opts.xAxis.marginTop * opts.pix
  1192. };
  1193. result.ranges = getXAxisTextList(series, opts, config, columnstyle.type);
  1194. result.rangesFormat = result.ranges.map(function(item) {
  1195. //item = opts.xAxis.formatter ? opts.xAxis.formatter(item) : util.toFixed(item, 2);
  1196. item = util.toFixed(item, 2);
  1197. return item;
  1198. });
  1199. var xAxisScaleValues = result.ranges.map(function(item) {
  1200. // 如果刻度值是浮点数,则保留两位小数
  1201. item = util.toFixed(item, 2);
  1202. // 若有自定义格式则调用自定义的格式化函数
  1203. //item = opts.xAxis.formatter ? opts.xAxis.formatter(Number(item)) : item;
  1204. return item;
  1205. });
  1206. result = Object.assign(result, getXAxisPoints(xAxisScaleValues, opts, config));
  1207. // 计算X轴刻度的属性譬如每个刻度的间隔,刻度的起始点\结束点以及总长
  1208. var eachSpacing = result.eachSpacing;
  1209. var textLength = xAxisScaleValues.map(function(item) {
  1210. return measureText(item, opts.xAxis.fontSize * opts.pix, context);
  1211. });
  1212. if (opts.xAxis.disabled === true) {
  1213. result.xAxisHeight = 0;
  1214. }
  1215. return result;
  1216. }
  1217. function getRadarDataPoints(angleList, center, radius, series, opts) {
  1218. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  1219. var radarOption = opts.extra.radar || {};
  1220. radarOption.max = radarOption.max || 0;
  1221. var maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series)));
  1222. var data = [];
  1223. for (let i = 0; i < series.length; i++) {
  1224. let each = series[i];
  1225. let listItem = {};
  1226. listItem.color = each.color;
  1227. listItem.legendShape = each.legendShape;
  1228. listItem.pointShape = each.pointShape;
  1229. listItem.data = [];
  1230. each.data.forEach(function(item, index) {
  1231. let tmp = {};
  1232. tmp.angle = angleList[index];
  1233. tmp.proportion = item / maxData;
  1234. tmp.value = item;
  1235. tmp.position = convertCoordinateOrigin(radius * tmp.proportion * process * Math.cos(tmp.angle),
  1236. radius * tmp.proportion * process * Math.sin(tmp.angle), center);
  1237. listItem.data.push(tmp);
  1238. });
  1239. data.push(listItem);
  1240. }
  1241. return data;
  1242. }
  1243. function getPieDataPoints(series, radius) {
  1244. var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  1245. var count = 0;
  1246. var _start_ = 0;
  1247. for (let i = 0; i < series.length; i++) {
  1248. let item = series[i];
  1249. item.data = item.data === null ? 0 : item.data;
  1250. count += item.data;
  1251. }
  1252. for (let i = 0; i < series.length; i++) {
  1253. let item = series[i];
  1254. item.data = item.data === null ? 0 : item.data;
  1255. if (count === 0) {
  1256. item._proportion_ = 1 / series.length * process;
  1257. } else {
  1258. item._proportion_ = item.data / count * process;
  1259. }
  1260. item._radius_ = radius;
  1261. }
  1262. for (let i = 0; i < series.length; i++) {
  1263. let item = series[i];
  1264. item._start_ = _start_;
  1265. _start_ += 2 * item._proportion_ * Math.PI;
  1266. }
  1267. return series;
  1268. }
  1269. function getFunnelDataPoints(series, radius, option, eachSpacing) {
  1270. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  1271. for (let i = 0; i < series.length; i++) {
  1272. if (option.type == 'funnel') {
  1273. series[i].radius = series[i].data / series[0].data * radius * process;
  1274. } else {
  1275. series[i].radius = (eachSpacing * (series.length - i)) / (eachSpacing * series.length) * radius * process;
  1276. }
  1277. series[i]._proportion_ = series[i].data / series[0].data;
  1278. }
  1279. // if(option.type !== 'pyramid'){
  1280. // series.reverse();
  1281. // }
  1282. return series;
  1283. }
  1284. function getRoseDataPoints(series, type, minRadius, radius) {
  1285. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  1286. var count = 0;
  1287. var _start_ = 0;
  1288. var dataArr = [];
  1289. for (let i = 0; i < series.length; i++) {
  1290. let item = series[i];
  1291. item.data = item.data === null ? 0 : item.data;
  1292. count += item.data;
  1293. dataArr.push(item.data);
  1294. }
  1295. var minData = Math.min.apply(null, dataArr);
  1296. var maxData = Math.max.apply(null, dataArr);
  1297. var radiusLength = radius - minRadius;
  1298. for (let i = 0; i < series.length; i++) {
  1299. let item = series[i];
  1300. item.data = item.data === null ? 0 : item.data;
  1301. if (count === 0) {
  1302. item._proportion_ = 1 / series.length * process;
  1303. item._rose_proportion_ = 1 / series.length * process;
  1304. } else {
  1305. item._proportion_ = item.data / count * process;
  1306. if (type == 'area') {
  1307. item._rose_proportion_ = 1 / series.length * process;
  1308. } else {
  1309. item._rose_proportion_ = item.data / count * process;
  1310. }
  1311. }
  1312. item._radius_ = minRadius + radiusLength * ((item.data - minData) / (maxData - minData)) || radius;
  1313. }
  1314. for (let i = 0; i < series.length; i++) {
  1315. let item = series[i];
  1316. item._start_ = _start_;
  1317. _start_ += 2 * item._rose_proportion_ * Math.PI;
  1318. }
  1319. return series;
  1320. }
  1321. function getArcbarDataPoints(series, arcbarOption) {
  1322. var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  1323. if (process == 1) {
  1324. process = 0.999999;
  1325. }
  1326. for (let i = 0; i < series.length; i++) {
  1327. let item = series[i];
  1328. item.data = item.data === null ? 0 : item.data;
  1329. let totalAngle;
  1330. if (arcbarOption.type == 'circle') {
  1331. totalAngle = 2;
  1332. } else {
  1333. if (arcbarOption.direction == 'ccw') {
  1334. if (arcbarOption.startAngle < arcbarOption.endAngle) {
  1335. totalAngle = 2 + arcbarOption.startAngle - arcbarOption.endAngle;
  1336. } else {
  1337. totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
  1338. }
  1339. } else {
  1340. if (arcbarOption.endAngle < arcbarOption.startAngle) {
  1341. totalAngle = 2 + arcbarOption.endAngle - arcbarOption.startAngle;
  1342. } else {
  1343. totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
  1344. }
  1345. }
  1346. }
  1347. item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;
  1348. if (arcbarOption.direction == 'ccw') {
  1349. item._proportion_ = arcbarOption.startAngle - totalAngle * item.data * process;
  1350. }
  1351. if (item._proportion_ >= 2) {
  1352. item._proportion_ = item._proportion_ % 2;
  1353. }
  1354. }
  1355. return series;
  1356. }
  1357. function getGaugeArcbarDataPoints(series, arcbarOption) {
  1358. var process = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
  1359. if (process == 1) {
  1360. process = 0.999999;
  1361. }
  1362. for (let i = 0; i < series.length; i++) {
  1363. let item = series[i];
  1364. item.data = item.data === null ? 0 : item.data;
  1365. let totalAngle;
  1366. if (arcbarOption.type == 'circle') {
  1367. totalAngle = 2;
  1368. } else {
  1369. if (arcbarOption.endAngle < arcbarOption.startAngle) {
  1370. totalAngle = 2 + arcbarOption.endAngle - arcbarOption.startAngle;
  1371. } else {
  1372. totalAngle = arcbarOption.startAngle - arcbarOption.endAngle;
  1373. }
  1374. }
  1375. item._proportion_ = totalAngle * item.data * process + arcbarOption.startAngle;
  1376. if (item._proportion_ >= 2) {
  1377. item._proportion_ = item._proportion_ % 2;
  1378. }
  1379. }
  1380. return series;
  1381. }
  1382. function getGaugeAxisPoints(categories, startAngle, endAngle) {
  1383. let totalAngle;
  1384. if (endAngle < startAngle) {
  1385. totalAngle = 2 + endAngle - startAngle;
  1386. } else {
  1387. totalAngle = startAngle - endAngle;
  1388. }
  1389. let tempStartAngle = startAngle;
  1390. for (let i = 0; i < categories.length; i++) {
  1391. categories[i].value = categories[i].value === null ? 0 : categories[i].value;
  1392. categories[i]._startAngle_ = tempStartAngle;
  1393. categories[i]._endAngle_ = totalAngle * categories[i].value + startAngle;
  1394. if (categories[i]._endAngle_ >= 2) {
  1395. categories[i]._endAngle_ = categories[i]._endAngle_ % 2;
  1396. }
  1397. tempStartAngle = categories[i]._endAngle_;
  1398. }
  1399. return categories;
  1400. }
  1401. function getGaugeDataPoints(series, categories, gaugeOption) {
  1402. let process = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
  1403. for (let i = 0; i < series.length; i++) {
  1404. let item = series[i];
  1405. item.data = item.data === null ? 0 : item.data;
  1406. if (gaugeOption.pointer.color == 'auto') {
  1407. for (let i = 0; i < categories.length; i++) {
  1408. if (item.data <= categories[i].value) {
  1409. item.color = categories[i].color;
  1410. break;
  1411. }
  1412. }
  1413. } else {
  1414. item.color = gaugeOption.pointer.color;
  1415. }
  1416. let totalAngle;
  1417. if (gaugeOption.endAngle < gaugeOption.startAngle) {
  1418. totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
  1419. } else {
  1420. totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
  1421. }
  1422. item._endAngle_ = totalAngle * item.data + gaugeOption.startAngle;
  1423. item._oldAngle_ = gaugeOption.oldAngle;
  1424. if (gaugeOption.oldAngle < gaugeOption.endAngle) {
  1425. item._oldAngle_ += 2;
  1426. }
  1427. if (item.data >= gaugeOption.oldData) {
  1428. item._proportion_ = (item._endAngle_ - item._oldAngle_) * process + gaugeOption.oldAngle;
  1429. } else {
  1430. item._proportion_ = item._oldAngle_ - (item._oldAngle_ - item._endAngle_) * process;
  1431. }
  1432. if (item._proportion_ >= 2) {
  1433. item._proportion_ = item._proportion_ % 2;
  1434. }
  1435. }
  1436. return series;
  1437. }
  1438. function getPieTextMaxLength(series, config, context, opts) {
  1439. series = getPieDataPoints(series);
  1440. let maxLength = 0;
  1441. for (let i = 0; i < series.length; i++) {
  1442. let item = series[i];
  1443. let text = item.formatter ? item.formatter(+item._proportion_.toFixed(2)) : util.toFixed(item._proportion_ *
  1444. 100) + '%';
  1445. maxLength = Math.max(maxLength, measureText(text, item.textSize * opts.pix || config.fontSize, context));
  1446. }
  1447. return maxLength;
  1448. }
  1449. function fixColumeData(points, eachSpacing, columnLen, index, config, opts) {
  1450. return points.map(function(item) {
  1451. if (item === null) {
  1452. return null;
  1453. }
  1454. var seriesGap = 0;
  1455. var categoryGap = 0;
  1456. if (opts.type == 'mix') {
  1457. seriesGap = opts.extra.mix.column.seriesGap * opts.pix || 0;
  1458. categoryGap = opts.extra.mix.column.categoryGap * opts.pix || 0;
  1459. } else {
  1460. seriesGap = opts.extra.column.seriesGap * opts.pix || 0;
  1461. categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
  1462. }
  1463. seriesGap = Math.min(seriesGap, eachSpacing / columnLen)
  1464. categoryGap = Math.min(categoryGap, eachSpacing / columnLen)
  1465. item.width = Math.ceil((eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) / columnLen);
  1466. if (opts.extra.mix && opts.extra.mix.column.width && +opts.extra.mix.column.width > 0) {
  1467. item.width = Math.min(item.width, +opts.extra.mix.column.width * opts.pix);
  1468. }
  1469. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  1470. item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
  1471. }
  1472. if (item.width <= 0) {
  1473. item.width = 1;
  1474. }
  1475. item.x += (index + 0.5 - columnLen / 2) * (item.width + seriesGap);
  1476. return item;
  1477. });
  1478. }
  1479. function fixBarData(points, eachSpacing, columnLen, index, config, opts) {
  1480. return points.map(function(item) {
  1481. if (item === null) {
  1482. return null;
  1483. }
  1484. var seriesGap = 0;
  1485. var categoryGap = 0;
  1486. seriesGap = opts.extra.bar.seriesGap * opts.pix || 0;
  1487. categoryGap = opts.extra.bar.categoryGap * opts.pix || 0;
  1488. seriesGap = Math.min(seriesGap, eachSpacing / columnLen)
  1489. categoryGap = Math.min(categoryGap, eachSpacing / columnLen)
  1490. item.width = Math.ceil((eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) / columnLen);
  1491. if (opts.extra.bar && opts.extra.bar.width && +opts.extra.bar.width > 0) {
  1492. item.width = Math.min(item.width, +opts.extra.bar.width * opts.pix);
  1493. }
  1494. if (item.width <= 0) {
  1495. item.width = 1;
  1496. }
  1497. item.y += (index + 0.5 - columnLen / 2) * (item.width + seriesGap);
  1498. return item;
  1499. });
  1500. }
  1501. function fixColumeMeterData(points, eachSpacing, columnLen, index, config, opts, border) {
  1502. var categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
  1503. return points.map(function(item) {
  1504. if (item === null) {
  1505. return null;
  1506. }
  1507. item.width = eachSpacing - 2 * categoryGap;
  1508. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  1509. item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
  1510. }
  1511. if (index > 0) {
  1512. item.width -= border;
  1513. }
  1514. return item;
  1515. });
  1516. }
  1517. function fixColumeStackData(points, eachSpacing, columnLen, index, config, opts, series) {
  1518. var categoryGap = opts.extra.column.categoryGap * opts.pix || 0;
  1519. return points.map(function(item, indexn) {
  1520. if (item === null) {
  1521. return null;
  1522. }
  1523. item.width = Math.ceil(eachSpacing - 2 * categoryGap);
  1524. if (opts.extra.column && opts.extra.column.width && +opts.extra.column.width > 0) {
  1525. item.width = Math.min(item.width, +opts.extra.column.width * opts.pix);
  1526. }
  1527. if (item.width <= 0) {
  1528. item.width = 1;
  1529. }
  1530. return item;
  1531. });
  1532. }
  1533. function fixBarStackData(points, eachSpacing, columnLen, index, config, opts, series) {
  1534. var categoryGap = opts.extra.bar.categoryGap * opts.pix || 0;
  1535. return points.map(function(item, indexn) {
  1536. if (item === null) {
  1537. return null;
  1538. }
  1539. item.width = Math.ceil(eachSpacing - 2 * categoryGap);
  1540. if (opts.extra.bar && opts.extra.bar.width && +opts.extra.bar.width > 0) {
  1541. item.width = Math.min(item.width, +opts.extra.bar.width * opts.pix);
  1542. }
  1543. if (item.width <= 0) {
  1544. item.width = 1;
  1545. }
  1546. return item;
  1547. });
  1548. }
  1549. function getXAxisPoints(categories, opts, config) {
  1550. var spacingValid = opts.width - opts.area[1] - opts.area[3];
  1551. var dataCount = opts.enableScroll ? Math.min(opts.xAxis.itemCount, categories.length) : categories.length;
  1552. if ((opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type == 'bubble' || opts.type ==
  1553. 'bar') && dataCount > 1 && opts.xAxis.boundaryGap == 'justify') {
  1554. dataCount -= 1;
  1555. }
  1556. var widthRatio = 0;
  1557. if (opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount
  1558. .widthRatio > 1) {
  1559. if (opts.extra.mount.widthRatio > 2) opts.extra.mount.widthRatio = 2
  1560. widthRatio = opts.extra.mount.widthRatio - 1;
  1561. dataCount += widthRatio;
  1562. }
  1563. var eachSpacing = spacingValid / dataCount;
  1564. var xAxisPoints = [];
  1565. var startX = opts.area[3];
  1566. var endX = opts.width - opts.area[1];
  1567. categories.forEach(function(item, index) {
  1568. xAxisPoints.push(startX + widthRatio / 2 * eachSpacing + index * eachSpacing);
  1569. });
  1570. if (opts.xAxis.boundaryGap !== 'justify') {
  1571. if (opts.enableScroll === true) {
  1572. xAxisPoints.push(startX + widthRatio * eachSpacing + categories.length * eachSpacing);
  1573. } else {
  1574. xAxisPoints.push(endX);
  1575. }
  1576. }
  1577. return {
  1578. xAxisPoints: xAxisPoints,
  1579. startX: startX,
  1580. endX: endX,
  1581. eachSpacing: eachSpacing
  1582. };
  1583. }
  1584. function getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
  1585. var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
  1586. var points = [];
  1587. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1588. data.forEach(function(item, index) {
  1589. if (item === null) {
  1590. points.push(null);
  1591. } else {
  1592. var cPoints = [];
  1593. item.forEach(function(items, indexs) {
  1594. var point = {};
  1595. point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
  1596. var value = items.value || items;
  1597. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1598. height *= process;
  1599. point.y = opts.height - Math.round(height) - opts.area[2];
  1600. cPoints.push(point);
  1601. });
  1602. points.push(cPoints);
  1603. }
  1604. });
  1605. return points;
  1606. }
  1607. function getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config) {
  1608. var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
  1609. var boundaryGap = 'center';
  1610. if (opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type == 'bubble') {
  1611. boundaryGap = opts.xAxis.boundaryGap;
  1612. }
  1613. var points = [];
  1614. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1615. var validWidth = opts.width - opts.area[1] - opts.area[3];
  1616. data.forEach(function(item, index) {
  1617. if (item === null) {
  1618. points.push(null);
  1619. } else {
  1620. var point = {};
  1621. point.color = item.color;
  1622. point.x = xAxisPoints[index];
  1623. var value = item;
  1624. if (typeof item === 'object' && item !== null) {
  1625. if (item.constructor.toString().indexOf('Array') > -1) {
  1626. let xranges, xminRange, xmaxRange;
  1627. xranges = [].concat(opts.chartData.xAxisData.ranges);
  1628. xminRange = xranges.shift();
  1629. xmaxRange = xranges.pop();
  1630. value = item[1];
  1631. point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
  1632. if (opts.type == 'bubble') {
  1633. point.r = item[2];
  1634. point.t = item[3];
  1635. }
  1636. } else {
  1637. value = item.value;
  1638. }
  1639. }
  1640. if (boundaryGap == 'center') {
  1641. point.x += eachSpacing / 2;
  1642. }
  1643. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1644. height *= process;
  1645. point.y = opts.height - height - opts.area[2];
  1646. points.push(point);
  1647. }
  1648. });
  1649. return points;
  1650. }
  1651. function getLineDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, lineOption, process) {
  1652. var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
  1653. var boundaryGap = opts.xAxis.boundaryGap;
  1654. var points = [];
  1655. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1656. var validWidth = opts.width - opts.area[1] - opts.area[3];
  1657. data.forEach(function(item, index) {
  1658. if (item === null) {
  1659. points.push(null);
  1660. } else {
  1661. var point = {};
  1662. point.color = item.color;
  1663. if (lineOption.animation == 'vertical') {
  1664. point.x = xAxisPoints[index];
  1665. var value = item;
  1666. if (typeof item === 'object' && item !== null) {
  1667. if (item.constructor.toString().indexOf('Array') > -1) {
  1668. let xranges, xminRange, xmaxRange;
  1669. xranges = [].concat(opts.chartData.xAxisData.ranges);
  1670. xminRange = xranges.shift();
  1671. xmaxRange = xranges.pop();
  1672. value = item[1];
  1673. point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
  1674. } else {
  1675. value = item.value;
  1676. }
  1677. }
  1678. if (boundaryGap == 'center') {
  1679. point.x += eachSpacing / 2;
  1680. }
  1681. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1682. height *= process;
  1683. point.y = opts.height - height - opts.area[2];
  1684. points.push(point);
  1685. } else {
  1686. point.x = xAxisPoints[0] + eachSpacing * index * process;
  1687. var value = item;
  1688. if (boundaryGap == 'center') {
  1689. point.x += eachSpacing / 2;
  1690. }
  1691. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1692. point.y = opts.height - height - opts.area[2];
  1693. points.push(point);
  1694. }
  1695. }
  1696. });
  1697. return points;
  1698. }
  1699. function getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, zeroPoints, process) {
  1700. var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
  1701. var points = [];
  1702. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1703. var validWidth = opts.width - opts.area[1] - opts.area[3];
  1704. data.forEach(function(item, index) {
  1705. if (item === null) {
  1706. points.push(null);
  1707. } else {
  1708. var point = {};
  1709. point.color = item.color;
  1710. point.x = xAxisPoints[index];
  1711. var value = item;
  1712. if (typeof item === 'object' && item !== null) {
  1713. if (item.constructor.toString().indexOf('Array') > -1) {
  1714. let xranges, xminRange, xmaxRange;
  1715. xranges = [].concat(opts.chartData.xAxisData.ranges);
  1716. xminRange = xranges.shift();
  1717. xmaxRange = xranges.pop();
  1718. value = item[1];
  1719. point.x = opts.area[3] + validWidth * (item[0] - xminRange) / (xmaxRange - xminRange);
  1720. } else {
  1721. value = item.value;
  1722. }
  1723. }
  1724. point.x += eachSpacing / 2;
  1725. var height = validHeight * (value * process - minRange) / (maxRange - minRange);
  1726. point.y = opts.height - height - opts.area[2];
  1727. points.push(point);
  1728. }
  1729. });
  1730. return points;
  1731. }
  1732. function getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption, zeroPoints) {
  1733. var process = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 1;
  1734. var points = [];
  1735. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1736. var validWidth = opts.width - opts.area[1] - opts.area[3];
  1737. var mountWidth = eachSpacing * mountOption.widthRatio;
  1738. series.forEach(function(item, index) {
  1739. if (item === null) {
  1740. points.push(null);
  1741. } else {
  1742. var point = {};
  1743. point.color = item.color;
  1744. point.x = xAxisPoints[index];
  1745. point.x += eachSpacing / 2;
  1746. var value = item.data;
  1747. var height = validHeight * (value * process - minRange) / (maxRange - minRange);
  1748. point.y = opts.height - height - opts.area[2];
  1749. point.value = value;
  1750. point.width = mountWidth;
  1751. points.push(point);
  1752. }
  1753. });
  1754. return points;
  1755. }
  1756. function getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config) {
  1757. var process = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : 1;
  1758. var points = [];
  1759. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1760. var validWidth = opts.width - opts.area[1] - opts.area[3];
  1761. data.forEach(function(item, index) {
  1762. if (item === null) {
  1763. points.push(null);
  1764. } else {
  1765. var point = {};
  1766. point.color = item.color;
  1767. point.y = yAxisPoints[index];
  1768. var value = item;
  1769. if (typeof item === 'object' && item !== null) {
  1770. value = item.value;
  1771. }
  1772. var height = validWidth * (value - minRange) / (maxRange - minRange);
  1773. height *= process;
  1774. point.height = height;
  1775. point.value = value;
  1776. point.x = height + opts.area[3];
  1777. points.push(point);
  1778. }
  1779. });
  1780. return points;
  1781. }
  1782. function getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, seriesIndex,
  1783. stackSeries) {
  1784. var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1;
  1785. var points = [];
  1786. var validHeight = opts.height - opts.area[0] - opts.area[2];
  1787. data.forEach(function(item, index) {
  1788. if (item === null) {
  1789. points.push(null);
  1790. } else {
  1791. var point = {};
  1792. point.color = item.color;
  1793. point.x = xAxisPoints[index] + Math.round(eachSpacing / 2);
  1794. if (seriesIndex > 0) {
  1795. var value = 0;
  1796. for (let i = 0; i <= seriesIndex; i++) {
  1797. value += stackSeries[i].data[index];
  1798. }
  1799. var value0 = value - item;
  1800. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1801. var height0 = validHeight * (value0 - minRange) / (maxRange - minRange);
  1802. } else {
  1803. var value = item;
  1804. if (typeof item === 'object' && item !== null) {
  1805. value = item.value;
  1806. }
  1807. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1808. var height0 = 0;
  1809. }
  1810. var heightc = height0;
  1811. height *= process;
  1812. heightc *= process;
  1813. point.y = opts.height - Math.round(height) - opts.area[2];
  1814. point.y0 = opts.height - Math.round(heightc) - opts.area[2];
  1815. points.push(point);
  1816. }
  1817. });
  1818. return points;
  1819. }
  1820. function getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config, seriesIndex,
  1821. stackSeries) {
  1822. var process = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : 1;
  1823. var points = [];
  1824. var validHeight = opts.width - opts.area[1] - opts.area[3];
  1825. data.forEach(function(item, index) {
  1826. if (item === null) {
  1827. points.push(null);
  1828. } else {
  1829. var point = {};
  1830. point.color = item.color;
  1831. point.y = yAxisPoints[index];
  1832. if (seriesIndex > 0) {
  1833. var value = 0;
  1834. for (let i = 0; i <= seriesIndex; i++) {
  1835. value += stackSeries[i].data[index];
  1836. }
  1837. var value0 = value - item;
  1838. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1839. var height0 = validHeight * (value0 - minRange) / (maxRange - minRange);
  1840. } else {
  1841. var value = item;
  1842. if (typeof item === 'object' && item !== null) {
  1843. value = item.value;
  1844. }
  1845. var height = validHeight * (value - minRange) / (maxRange - minRange);
  1846. var height0 = 0;
  1847. }
  1848. var heightc = height0;
  1849. height *= process;
  1850. heightc *= process;
  1851. point.height = height - heightc;
  1852. point.x = opts.area[3] + height;
  1853. point.x0 = opts.area[3] + heightc;
  1854. points.push(point);
  1855. }
  1856. });
  1857. return points;
  1858. }
  1859. function getYAxisTextList(series, opts, config, stack, yData) {
  1860. var index = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : -1;
  1861. var data;
  1862. if (stack == 'stack') {
  1863. data = dataCombineStack(series, opts.categories.length);
  1864. } else {
  1865. data = dataCombine(series);
  1866. }
  1867. var sorted = [];
  1868. // remove null from data
  1869. data = data.filter(function(item) {
  1870. //return item !== null;
  1871. if (typeof item === 'object' && item !== null) {
  1872. if (item.constructor.toString().indexOf('Array') > -1) {
  1873. return item !== null;
  1874. } else {
  1875. return item.value !== null;
  1876. }
  1877. } else {
  1878. return item !== null;
  1879. }
  1880. });
  1881. data.map(function(item) {
  1882. if (typeof item === 'object') {
  1883. if (item.constructor.toString().indexOf('Array') > -1) {
  1884. if (opts.type == 'candle') {
  1885. item.map(function(subitem) {
  1886. sorted.push(subitem);
  1887. })
  1888. } else {
  1889. sorted.push(item[1]);
  1890. }
  1891. } else {
  1892. sorted.push(item.value);
  1893. }
  1894. } else {
  1895. sorted.push(item);
  1896. }
  1897. })
  1898. var minData = yData.min || 0;
  1899. var maxData = yData.max || 0;
  1900. if (sorted.length > 0) {
  1901. minData = Math.min.apply(this, sorted);
  1902. maxData = Math.max.apply(this, sorted);
  1903. }
  1904. if (minData === maxData) {
  1905. if (maxData == 0) {
  1906. maxData = 10;
  1907. } else {
  1908. minData = 0;
  1909. }
  1910. }
  1911. var dataRange = getDataRange(minData, maxData);
  1912. var minRange = (yData.min === undefined || yData.min === null) ? dataRange.minRange : yData.min;
  1913. var maxRange = (yData.max === undefined || yData.max === null) ? dataRange.maxRange : yData.max;
  1914. var eachRange = (maxRange - minRange) / opts.yAxis.splitNumber;
  1915. var range = [];
  1916. for (var i = 0; i <= opts.yAxis.splitNumber; i++) {
  1917. range.push(minRange + eachRange * i);
  1918. }
  1919. return range.reverse();
  1920. }
  1921. function calYAxisData(series, opts, config, context) {
  1922. //堆叠图重算Y轴
  1923. var columnstyle = assign({}, {
  1924. type: ""
  1925. }, opts.extra.column);
  1926. //如果是多Y轴,重新计算
  1927. var YLength = opts.yAxis.data.length;
  1928. var newSeries = new Array(YLength);
  1929. if (YLength > 0) {
  1930. for (let i = 0; i < YLength; i++) {
  1931. newSeries[i] = [];
  1932. for (let j = 0; j < series.length; j++) {
  1933. if (series[j].index == i) {
  1934. newSeries[i].push(series[j]);
  1935. }
  1936. }
  1937. }
  1938. var rangesArr = new Array(YLength);
  1939. var rangesFormatArr = new Array(YLength);
  1940. var yAxisWidthArr = new Array(YLength);
  1941. for (let i = 0; i < YLength; i++) {
  1942. let yData = opts.yAxis.data[i];
  1943. //如果总开关不显示,强制每个Y轴为不显示
  1944. if (opts.yAxis.disabled == true) {
  1945. yData.disabled = true;
  1946. }
  1947. if (yData.type === 'categories') {
  1948. if (!yData.formatter) {
  1949. yData.formatter = (val, index, opts) => {
  1950. return val + (yData.unit || '')
  1951. };
  1952. }
  1953. yData.categories = yData.categories || opts.categories;
  1954. rangesArr[i] = yData.categories;
  1955. } else {
  1956. if (!yData.formatter) {
  1957. yData.formatter = (val, index, opts) => {
  1958. return util.toFixed(val, yData.tofix || 0) + (yData.unit || '')
  1959. };
  1960. }
  1961. rangesArr[i] = getYAxisTextList(newSeries[i], opts, config, columnstyle.type, yData, i);
  1962. }
  1963. let yAxisFontSizes = yData.fontSize * opts.pix || config.fontSize;
  1964. yAxisWidthArr[i] = {
  1965. position: yData.position ? yData.position : 'left',
  1966. width: 0
  1967. };
  1968. rangesFormatArr[i] = rangesArr[i].map(function(items, index) {
  1969. items = yData.formatter(items, index, opts);
  1970. yAxisWidthArr[i].width = Math.max(yAxisWidthArr[i].width, measureText(items, yAxisFontSizes,
  1971. context) + 5);
  1972. return items;
  1973. });
  1974. let calibration = yData.calibration ? 4 * opts.pix : 0;
  1975. yAxisWidthArr[i].width += calibration + 3 * opts.pix;
  1976. if (yData.disabled === true) {
  1977. yAxisWidthArr[i].width = 0;
  1978. }
  1979. }
  1980. } else {
  1981. var rangesArr = new Array(1);
  1982. var rangesFormatArr = new Array(1);
  1983. var yAxisWidthArr = new Array(1);
  1984. if (opts.type === 'bar') {
  1985. rangesArr[0] = opts.categories;
  1986. if (!opts.yAxis.formatter) {
  1987. opts.yAxis.formatter = (val, index, opts) => {
  1988. return val + (opts.yAxis.unit || '')
  1989. }
  1990. }
  1991. } else {
  1992. if (!opts.yAxis.formatter) {
  1993. opts.yAxis.formatter = (val, index, opts) => {
  1994. return val.toFixed(opts.yAxis.tofix) + (opts.yAxis.unit || '')
  1995. }
  1996. }
  1997. rangesArr[0] = getYAxisTextList(series, opts, config, columnstyle.type, {});
  1998. }
  1999. yAxisWidthArr[0] = {
  2000. position: 'left',
  2001. width: 0
  2002. };
  2003. var yAxisFontSize = opts.yAxis.fontSize * opts.pix || config.fontSize;
  2004. rangesFormatArr[0] = rangesArr[0].map(function(item, index) {
  2005. item = opts.yAxis.formatter(item, index, opts);
  2006. yAxisWidthArr[0].width = Math.max(yAxisWidthArr[0].width, measureText(item, yAxisFontSize,
  2007. context) + 5);
  2008. return item;
  2009. });
  2010. yAxisWidthArr[0].width += 3 * opts.pix;
  2011. if (opts.yAxis.disabled === true) {
  2012. yAxisWidthArr[0] = {
  2013. position: 'left',
  2014. width: 0
  2015. };
  2016. opts.yAxis.data[0] = {
  2017. disabled: true
  2018. };
  2019. } else {
  2020. opts.yAxis.data[0] = {
  2021. disabled: false,
  2022. position: 'left',
  2023. max: opts.yAxis.max,
  2024. min: opts.yAxis.min,
  2025. formatter: opts.yAxis.formatter
  2026. };
  2027. if (opts.type === 'bar') {
  2028. opts.yAxis.data[0].categories = opts.categories;
  2029. opts.yAxis.data[0].type = 'categories';
  2030. }
  2031. }
  2032. }
  2033. return {
  2034. rangesFormat: rangesFormatArr,
  2035. ranges: rangesArr,
  2036. yAxisWidth: yAxisWidthArr
  2037. };
  2038. }
  2039. function calTooltipYAxisData(point, series, opts, config, eachSpacing) {
  2040. let ranges = [].concat(opts.chartData.yAxisData.ranges);
  2041. let spacingValid = opts.height - opts.area[0] - opts.area[2];
  2042. let minAxis = opts.area[0];
  2043. let items = [];
  2044. for (let i = 0; i < ranges.length; i++) {
  2045. let maxVal = Math.max.apply(this, ranges[i]);
  2046. let minVal = Math.min.apply(this, ranges[i]);
  2047. let item = maxVal - (maxVal - minVal) * (point - minAxis) / spacingValid;
  2048. item = opts.yAxis.data && opts.yAxis.data[i].formatter ? opts.yAxis.data[i].formatter(item, i, opts) : item
  2049. .toFixed(0);
  2050. items.push(String(item))
  2051. }
  2052. return items;
  2053. }
  2054. function calMarkLineData(points, opts) {
  2055. let minRange, maxRange;
  2056. let spacingValid = opts.height - opts.area[0] - opts.area[2];
  2057. for (let i = 0; i < points.length; i++) {
  2058. points[i].yAxisIndex = points[i].yAxisIndex ? points[i].yAxisIndex : 0;
  2059. let range = [].concat(opts.chartData.yAxisData.ranges[points[i].yAxisIndex]);
  2060. minRange = range.pop();
  2061. maxRange = range.shift();
  2062. let height = spacingValid * (points[i].value - minRange) / (maxRange - minRange);
  2063. points[i].y = opts.height - Math.round(height) - opts.area[2];
  2064. }
  2065. return points;
  2066. }
  2067. function contextRotate(context, opts) {
  2068. if (opts.rotateLock !== true) {
  2069. context.translate(opts.height, 0);
  2070. context.rotate(90 * Math.PI / 180);
  2071. } else if (opts._rotate_ !== true) {
  2072. context.translate(opts.height, 0);
  2073. context.rotate(90 * Math.PI / 180);
  2074. opts._rotate_ = true;
  2075. }
  2076. }
  2077. function drawPointShape(points, color, shape, context, opts) {
  2078. context.beginPath();
  2079. if (opts.dataPointShapeType == 'hollow') {
  2080. context.setStrokeStyle(color);
  2081. context.setFillStyle(opts.background);
  2082. context.setLineWidth(2 * opts.pix);
  2083. } else {
  2084. context.setStrokeStyle("#ffffff");
  2085. context.setFillStyle(color);
  2086. context.setLineWidth(1 * opts.pix);
  2087. }
  2088. if (shape === 'diamond') {
  2089. points.forEach(function(item, index) {
  2090. if (item !== null) {
  2091. context.moveTo(item.x, item.y - 4.5);
  2092. context.lineTo(item.x - 4.5, item.y);
  2093. context.lineTo(item.x, item.y + 4.5);
  2094. context.lineTo(item.x + 4.5, item.y);
  2095. context.lineTo(item.x, item.y - 4.5);
  2096. }
  2097. });
  2098. } else if (shape === 'circle') {
  2099. points.forEach(function(item, index) {
  2100. if (item !== null) {
  2101. context.moveTo(item.x + 2.5 * opts.pix, item.y);
  2102. context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
  2103. }
  2104. });
  2105. } else if (shape === 'square') {
  2106. points.forEach(function(item, index) {
  2107. if (item !== null) {
  2108. context.moveTo(item.x - 3.5, item.y - 3.5);
  2109. context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
  2110. }
  2111. });
  2112. } else if (shape === 'triangle') {
  2113. points.forEach(function(item, index) {
  2114. if (item !== null) {
  2115. context.moveTo(item.x, item.y - 4.5);
  2116. context.lineTo(item.x - 4.5, item.y + 4.5);
  2117. context.lineTo(item.x + 4.5, item.y + 4.5);
  2118. context.lineTo(item.x, item.y - 4.5);
  2119. }
  2120. });
  2121. } else if (shape === 'none') {
  2122. return;
  2123. }
  2124. context.closePath();
  2125. context.fill();
  2126. context.stroke();
  2127. }
  2128. function drawActivePoint(points, color, shape, context, opts, option, seriesIndex) {
  2129. if (!opts.tooltip) {
  2130. return
  2131. }
  2132. if (opts.tooltip.group.length > 0 && opts.tooltip.group.includes(seriesIndex) == false) {
  2133. return
  2134. }
  2135. var pointIndex = typeof opts.tooltip.index === 'number' ? opts.tooltip.index : opts.tooltip.index[opts.tooltip.group
  2136. .indexOf(seriesIndex)];
  2137. context.beginPath();
  2138. if (option.activeType == 'hollow') {
  2139. context.setStrokeStyle(color);
  2140. context.setFillStyle(opts.background);
  2141. context.setLineWidth(2 * opts.pix);
  2142. } else {
  2143. context.setStrokeStyle("#ffffff");
  2144. context.setFillStyle(color);
  2145. context.setLineWidth(1 * opts.pix);
  2146. }
  2147. if (shape === 'diamond') {
  2148. points.forEach(function(item, index) {
  2149. if (item !== null && pointIndex == index) {
  2150. context.moveTo(item.x, item.y - 4.5);
  2151. context.lineTo(item.x - 4.5, item.y);
  2152. context.lineTo(item.x, item.y + 4.5);
  2153. context.lineTo(item.x + 4.5, item.y);
  2154. context.lineTo(item.x, item.y - 4.5);
  2155. }
  2156. });
  2157. } else if (shape === 'circle') {
  2158. points.forEach(function(item, index) {
  2159. if (item !== null && pointIndex == index) {
  2160. context.moveTo(item.x + 2.5 * opts.pix, item.y);
  2161. context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
  2162. }
  2163. });
  2164. } else if (shape === 'square') {
  2165. points.forEach(function(item, index) {
  2166. if (item !== null && pointIndex == index) {
  2167. context.moveTo(item.x - 3.5, item.y - 3.5);
  2168. context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
  2169. }
  2170. });
  2171. } else if (shape === 'triangle') {
  2172. points.forEach(function(item, index) {
  2173. if (item !== null && pointIndex == index) {
  2174. context.moveTo(item.x, item.y - 4.5);
  2175. context.lineTo(item.x - 4.5, item.y + 4.5);
  2176. context.lineTo(item.x + 4.5, item.y + 4.5);
  2177. context.lineTo(item.x, item.y - 4.5);
  2178. }
  2179. });
  2180. } else if (shape === 'none') {
  2181. return;
  2182. }
  2183. context.closePath();
  2184. context.fill();
  2185. context.stroke();
  2186. }
  2187. function drawRingTitle(opts, config, context, center) {
  2188. var titlefontSize = opts.title.fontSize || config.titleFontSize;
  2189. var subtitlefontSize = opts.subtitle.fontSize || config.subtitleFontSize;
  2190. var title = opts.title.name || '';
  2191. var subtitle = opts.subtitle.name || '';
  2192. var titleFontColor = opts.title.color || opts.fontColor;
  2193. var subtitleFontColor = opts.subtitle.color || opts.fontColor;
  2194. var titleHeight = title ? titlefontSize : 0;
  2195. var subtitleHeight = subtitle ? subtitlefontSize : 0;
  2196. var margin = 5;
  2197. if (subtitle) {
  2198. var textWidth = measureText(subtitle, subtitlefontSize * opts.pix, context);
  2199. var startX = center.x - textWidth / 2 + (opts.subtitle.offsetX || 0) * opts.pix;
  2200. var startY = center.y + subtitlefontSize * opts.pix / 2 + (opts.subtitle.offsetY || 0) * opts.pix;
  2201. if (title) {
  2202. startY += (titleHeight * opts.pix + margin) / 2;
  2203. }
  2204. context.beginPath();
  2205. context.setFontSize(subtitlefontSize * opts.pix);
  2206. context.setFillStyle(subtitleFontColor);
  2207. context.fillText(subtitle, startX, startY);
  2208. context.closePath();
  2209. context.stroke();
  2210. }
  2211. if (title) {
  2212. var _textWidth = measureText(title, titlefontSize * opts.pix, context);
  2213. var _startX = center.x - _textWidth / 2 + (opts.title.offsetX || 0);
  2214. var _startY = center.y + titlefontSize * opts.pix / 2 + (opts.title.offsetY || 0) * opts.pix;
  2215. if (subtitle) {
  2216. _startY -= (subtitleHeight * opts.pix + margin) / 2;
  2217. }
  2218. context.beginPath();
  2219. context.setFontSize(titlefontSize * opts.pix);
  2220. context.setFillStyle(titleFontColor);
  2221. context.fillText(title, _startX, _startY);
  2222. context.closePath();
  2223. context.stroke();
  2224. }
  2225. }
  2226. function drawPointText(points, series, config, context, opts) {
  2227. // 绘制数据文案
  2228. var data = series.data;
  2229. var textOffset = series.textOffset ? series.textOffset : 0;
  2230. points.forEach(function(item, index) {
  2231. if (item !== null) {
  2232. context.beginPath();
  2233. var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
  2234. context.setFontSize(fontSize);
  2235. context.setFillStyle(series.textColor || opts.fontColor);
  2236. var value = data[index]
  2237. if (typeof data[index] === 'object' && data[index] !== null) {
  2238. if (data[index].constructor.toString().indexOf('Array') > -1) {
  2239. value = data[index][1];
  2240. } else {
  2241. value = data[index].value
  2242. }
  2243. }
  2244. var formatVal = series.formatter ? series.formatter(value, index, series, opts) : value;
  2245. context.setTextAlign('center');
  2246. context.fillText(String(formatVal), item.x, item.y - 4 + textOffset * opts.pix);
  2247. context.closePath();
  2248. context.stroke();
  2249. context.setTextAlign('left');
  2250. }
  2251. });
  2252. }
  2253. function drawColumePointText(points, series, config, context, opts) {
  2254. // 绘制数据文案
  2255. var data = series.data;
  2256. var textOffset = series.textOffset ? series.textOffset : 0;
  2257. var Position = opts.extra.column.labelPosition;
  2258. points.forEach(function(item, index) {
  2259. if (item !== null) {
  2260. context.beginPath();
  2261. var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
  2262. context.setFontSize(fontSize);
  2263. context.setFillStyle(series.textColor || opts.fontColor);
  2264. var value = data[index]
  2265. if (typeof data[index] === 'object' && data[index] !== null) {
  2266. if (data[index].constructor.toString().indexOf('Array') > -1) {
  2267. value = data[index][1];
  2268. } else {
  2269. value = data[index].value
  2270. }
  2271. }
  2272. var formatVal = series.formatter ? series.formatter(value, index, series, opts) : value;
  2273. context.setTextAlign('center');
  2274. var startY = item.y - 4 * opts.pix + textOffset * opts.pix;
  2275. if (item.y > series.zeroPoints) {
  2276. startY = item.y + textOffset * opts.pix + fontSize;
  2277. }
  2278. if (Position == 'insideTop') {
  2279. startY = item.y + fontSize + textOffset * opts.pix;
  2280. if (item.y > series.zeroPoints) {
  2281. startY = item.y - textOffset * opts.pix - 4 * opts.pix;
  2282. }
  2283. }
  2284. if (Position == 'center') {
  2285. startY = item.y + textOffset * opts.pix + (opts.height - opts.area[2] - item.y + fontSize) / 2;
  2286. if (series.zeroPoints < opts.height - opts.area[2]) {
  2287. startY = item.y + textOffset * opts.pix + (series.zeroPoints - item.y + fontSize) / 2;
  2288. }
  2289. if (item.y > series.zeroPoints) {
  2290. startY = item.y - textOffset * opts.pix - (item.y - series.zeroPoints - fontSize) / 2;
  2291. }
  2292. if (opts.extra.column.type == 'stack') {
  2293. startY = item.y + textOffset * opts.pix + (item.y0 - item.y + fontSize) / 2;
  2294. }
  2295. }
  2296. if (Position == 'bottom') {
  2297. startY = opts.height - opts.area[2] + textOffset * opts.pix - 4 * opts.pix;
  2298. if (series.zeroPoints < opts.height - opts.area[2]) {
  2299. startY = series.zeroPoints + textOffset * opts.pix - 4 * opts.pix;
  2300. }
  2301. if (item.y > series.zeroPoints) {
  2302. startY = series.zeroPoints - textOffset * opts.pix + fontSize + 2 * opts.pix;
  2303. }
  2304. if (opts.extra.column.type == 'stack') {
  2305. startY = item.y0 + textOffset * opts.pix - 4 * opts.pix;
  2306. }
  2307. }
  2308. context.fillText(String(formatVal), item.x, startY);
  2309. context.closePath();
  2310. context.stroke();
  2311. context.setTextAlign('left');
  2312. }
  2313. });
  2314. }
  2315. function drawMountPointText(points, series, config, context, opts, zeroPoints) {
  2316. // 绘制数据文案
  2317. var data = series.data;
  2318. var textOffset = series.textOffset ? series.textOffset : 0;
  2319. var Position = opts.extra.mount.labelPosition;
  2320. points.forEach(function(item, index) {
  2321. if (item !== null) {
  2322. context.beginPath();
  2323. var fontSize = series[index].textSize ? series[index].textSize * opts.pix : config.fontSize;
  2324. context.setFontSize(fontSize);
  2325. context.setFillStyle(series[index].textColor || opts.fontColor);
  2326. var value = item.value
  2327. var formatVal = series[index].formatter ? series[index].formatter(value, index, series, opts) :
  2328. value;
  2329. context.setTextAlign('center');
  2330. var startY = item.y - 4 * opts.pix + textOffset * opts.pix;
  2331. if (item.y > zeroPoints) {
  2332. startY = item.y + textOffset * opts.pix + fontSize;
  2333. }
  2334. context.fillText(String(formatVal), item.x, startY);
  2335. context.closePath();
  2336. context.stroke();
  2337. context.setTextAlign('left');
  2338. }
  2339. });
  2340. }
  2341. function drawBarPointText(points, series, config, context, opts) {
  2342. // 绘制数据文案
  2343. var data = series.data;
  2344. var textOffset = series.textOffset ? series.textOffset : 0;
  2345. points.forEach(function(item, index) {
  2346. if (item !== null) {
  2347. context.beginPath();
  2348. var fontSize = series.textSize ? series.textSize * opts.pix : config.fontSize;
  2349. context.setFontSize(fontSize);
  2350. context.setFillStyle(series.textColor || opts.fontColor);
  2351. var value = data[index]
  2352. if (typeof data[index] === 'object' && data[index] !== null) {
  2353. value = data[index].value;
  2354. }
  2355. var formatVal = series.formatter ? series.formatter(value, index, series, opts) : value;
  2356. context.setTextAlign('left');
  2357. context.fillText(String(formatVal), item.x + 4 * opts.pix, item.y + fontSize / 2 - 3);
  2358. context.closePath();
  2359. context.stroke();
  2360. }
  2361. });
  2362. }
  2363. function drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context) {
  2364. radius -= gaugeOption.width / 2 + gaugeOption.labelOffset * opts.pix;
  2365. radius = radius < 10 ? 10 : radius;
  2366. let totalAngle;
  2367. if (gaugeOption.endAngle < gaugeOption.startAngle) {
  2368. totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
  2369. } else {
  2370. totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
  2371. }
  2372. let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  2373. let totalNumber = gaugeOption.endNumber - gaugeOption.startNumber;
  2374. let splitNumber = totalNumber / gaugeOption.splitLine.splitNumber;
  2375. let nowAngle = gaugeOption.startAngle;
  2376. let nowNumber = gaugeOption.startNumber;
  2377. for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
  2378. var pos = {
  2379. x: radius * Math.cos(nowAngle * Math.PI),
  2380. y: radius * Math.sin(nowAngle * Math.PI)
  2381. };
  2382. var labelText = gaugeOption.formatter ? gaugeOption.formatter(nowNumber, i, opts) : nowNumber;
  2383. pos.x += centerPosition.x - measureText(labelText, config.fontSize, context) / 2;
  2384. pos.y += centerPosition.y;
  2385. var startX = pos.x;
  2386. var startY = pos.y;
  2387. context.beginPath();
  2388. context.setFontSize(config.fontSize);
  2389. context.setFillStyle(gaugeOption.labelColor || opts.fontColor);
  2390. context.fillText(labelText, startX, startY + config.fontSize / 2);
  2391. context.closePath();
  2392. context.stroke();
  2393. nowAngle += splitAngle;
  2394. if (nowAngle >= 2) {
  2395. nowAngle = nowAngle % 2;
  2396. }
  2397. nowNumber += splitNumber;
  2398. }
  2399. }
  2400. function drawRadarLabel(angleList, radius, centerPosition, opts, config, context) {
  2401. var radarOption = opts.extra.radar || {};
  2402. angleList.forEach(function(angle, index) {
  2403. if (radarOption.labelPointShow === true && opts.categories[index] !== '') {
  2404. var posPoint = {
  2405. x: radius * Math.cos(angle),
  2406. y: radius * Math.sin(angle)
  2407. };
  2408. var posPointAxis = convertCoordinateOrigin(posPoint.x, posPoint.y, centerPosition);
  2409. context.setFillStyle(radarOption.labelPointColor);
  2410. context.beginPath();
  2411. context.arc(posPointAxis.x, posPointAxis.y, radarOption.labelPointRadius * opts.pix, 0, 2 * Math.PI,
  2412. false);
  2413. context.closePath();
  2414. context.fill();
  2415. }
  2416. if (radarOption.labelShow === true) {
  2417. var pos = {
  2418. x: (radius + config.radarLabelTextMargin * opts.pix) * Math.cos(angle),
  2419. y: (radius + config.radarLabelTextMargin * opts.pix) * Math.sin(angle)
  2420. };
  2421. var posRelativeCanvas = convertCoordinateOrigin(pos.x, pos.y, centerPosition);
  2422. var startX = posRelativeCanvas.x;
  2423. var startY = posRelativeCanvas.y;
  2424. if (util.approximatelyEqual(pos.x, 0)) {
  2425. startX -= measureText(opts.categories[index] || '', config.fontSize, context) / 2;
  2426. } else if (pos.x < 0) {
  2427. startX -= measureText(opts.categories[index] || '', config.fontSize, context);
  2428. }
  2429. context.beginPath();
  2430. context.setFontSize(config.fontSize);
  2431. context.setFillStyle(radarOption.labelColor || opts.fontColor);
  2432. context.fillText(opts.categories[index] || '', startX, startY + config.fontSize / 2);
  2433. context.closePath();
  2434. context.stroke();
  2435. }
  2436. });
  2437. }
  2438. function drawPieText(series, opts, config, context, radius, center) {
  2439. var lineRadius = config.pieChartLinePadding;
  2440. var textObjectCollection = [];
  2441. var lastTextObject = null;
  2442. var seriesConvert = series.map(function(item, index) {
  2443. var text = item.formatter ? item.formatter(item, index, series, opts) : util.toFixed(item._proportion_
  2444. .toFixed(4) * 100) + '%';
  2445. text = item.labelText ? item.labelText : text;
  2446. var arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._proportion_ / 2);
  2447. if (item._rose_proportion_) {
  2448. arc = 2 * Math.PI - (item._start_ + 2 * Math.PI * item._rose_proportion_ / 2);
  2449. }
  2450. var color = item.color;
  2451. var radius = item._radius_;
  2452. return {
  2453. arc: arc,
  2454. text: text,
  2455. color: color,
  2456. radius: radius,
  2457. textColor: item.textColor,
  2458. textSize: item.textSize,
  2459. labelShow: item.labelShow
  2460. };
  2461. });
  2462. for (let i = 0; i < seriesConvert.length; i++) {
  2463. let item = seriesConvert[i];
  2464. // line end
  2465. let orginX1 = Math.cos(item.arc) * (item.radius + lineRadius);
  2466. let orginY1 = Math.sin(item.arc) * (item.radius + lineRadius);
  2467. // line start
  2468. let orginX2 = Math.cos(item.arc) * item.radius;
  2469. let orginY2 = Math.sin(item.arc) * item.radius;
  2470. // text start
  2471. let orginX3 = orginX1 >= 0 ? orginX1 + config.pieChartTextPadding : orginX1 - config.pieChartTextPadding;
  2472. let orginY3 = orginY1;
  2473. let textWidth = measureText(item.text, item.textSize * opts.pix || config.fontSize, context);
  2474. let startY = orginY3;
  2475. if (lastTextObject && util.isSameXCoordinateArea(lastTextObject.start, {
  2476. x: orginX3
  2477. })) {
  2478. if (orginX3 > 0) {
  2479. startY = Math.min(orginY3, lastTextObject.start.y);
  2480. } else if (orginX1 < 0) {
  2481. startY = Math.max(orginY3, lastTextObject.start.y);
  2482. } else {
  2483. if (orginY3 > 0) {
  2484. startY = Math.max(orginY3, lastTextObject.start.y);
  2485. } else {
  2486. startY = Math.min(orginY3, lastTextObject.start.y);
  2487. }
  2488. }
  2489. }
  2490. if (orginX3 < 0) {
  2491. orginX3 -= textWidth;
  2492. }
  2493. let textObject = {
  2494. lineStart: {
  2495. x: orginX2,
  2496. y: orginY2
  2497. },
  2498. lineEnd: {
  2499. x: orginX1,
  2500. y: orginY1
  2501. },
  2502. start: {
  2503. x: orginX3,
  2504. y: startY
  2505. },
  2506. width: textWidth,
  2507. height: config.fontSize,
  2508. text: item.text,
  2509. color: item.color,
  2510. textColor: item.textColor,
  2511. textSize: item.textSize
  2512. };
  2513. lastTextObject = avoidCollision(textObject, lastTextObject);
  2514. textObjectCollection.push(lastTextObject);
  2515. }
  2516. for (let i = 0; i < textObjectCollection.length; i++) {
  2517. if (seriesConvert[i].labelShow === false) {
  2518. continue;
  2519. }
  2520. let item = textObjectCollection[i];
  2521. let lineStartPoistion = convertCoordinateOrigin(item.lineStart.x, item.lineStart.y, center);
  2522. let lineEndPoistion = convertCoordinateOrigin(item.lineEnd.x, item.lineEnd.y, center);
  2523. let textPosition = convertCoordinateOrigin(item.start.x, item.start.y, center);
  2524. context.setLineWidth(1 * opts.pix);
  2525. context.setFontSize(item.textSize * opts.pix || config.fontSize);
  2526. context.beginPath();
  2527. context.setStrokeStyle(item.color);
  2528. context.setFillStyle(item.color);
  2529. context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
  2530. let curveStartX = item.start.x < 0 ? textPosition.x + item.width : textPosition.x;
  2531. let textStartX = item.start.x < 0 ? textPosition.x - 5 : textPosition.x + 5;
  2532. context.quadraticCurveTo(lineEndPoistion.x, lineEndPoistion.y, curveStartX, textPosition.y);
  2533. context.moveTo(lineStartPoistion.x, lineStartPoistion.y);
  2534. context.stroke();
  2535. context.closePath();
  2536. context.beginPath();
  2537. context.moveTo(textPosition.x + item.width, textPosition.y);
  2538. context.arc(curveStartX, textPosition.y, 2 * opts.pix, 0, 2 * Math.PI);
  2539. context.closePath();
  2540. context.fill();
  2541. context.beginPath();
  2542. context.setFontSize(item.textSize * opts.pix || config.fontSize);
  2543. context.setFillStyle(item.textColor || opts.fontColor);
  2544. context.fillText(item.text, textStartX, textPosition.y + 3);
  2545. context.closePath();
  2546. context.stroke();
  2547. context.closePath();
  2548. }
  2549. }
  2550. function drawToolTipSplitLine(offsetX, opts, config, context) {
  2551. var toolTipOption = opts.extra.tooltip || {};
  2552. toolTipOption.gridType = toolTipOption.gridType == undefined ? 'solid' : toolTipOption.gridType;
  2553. toolTipOption.dashLength = toolTipOption.dashLength == undefined ? 4 : toolTipOption.dashLength;
  2554. var startY = opts.area[0];
  2555. var endY = opts.height - opts.area[2];
  2556. if (toolTipOption.gridType == 'dash') {
  2557. context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
  2558. }
  2559. context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  2560. context.setLineWidth(1 * opts.pix);
  2561. context.beginPath();
  2562. context.moveTo(offsetX, startY);
  2563. context.lineTo(offsetX, endY);
  2564. context.stroke();
  2565. context.setLineDash([]);
  2566. if (toolTipOption.xAxisLabel) {
  2567. let labelText = opts.categories[opts.tooltip.index];
  2568. context.setFontSize(config.fontSize);
  2569. let textWidth = measureText(labelText, config.fontSize, context);
  2570. let textX = offsetX - 0.5 * textWidth;
  2571. let textY = endY + 2 * opts.pix;
  2572. context.beginPath();
  2573. context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption
  2574. .labelBgOpacity || config.toolTipOpacity));
  2575. context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
  2576. context.setLineWidth(1 * opts.pix);
  2577. context.rect(textX - toolTipOption.boxPadding * opts.pix, textY, textWidth + 2 * toolTipOption.boxPadding * opts
  2578. .pix, config.fontSize + 2 * toolTipOption.boxPadding * opts.pix);
  2579. context.closePath();
  2580. context.stroke();
  2581. context.fill();
  2582. context.beginPath();
  2583. context.setFontSize(config.fontSize);
  2584. context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
  2585. context.fillText(String(labelText), textX, textY + toolTipOption.boxPadding * opts.pix + config.fontSize);
  2586. context.closePath();
  2587. context.stroke();
  2588. }
  2589. }
  2590. function drawMarkLine(opts, config, context) {
  2591. let markLineOption = assign({}, {
  2592. type: 'solid',
  2593. dashLength: 4,
  2594. data: []
  2595. }, opts.extra.markLine);
  2596. let startX = opts.area[3];
  2597. let endX = opts.width - opts.area[1];
  2598. let points = calMarkLineData(markLineOption.data, opts);
  2599. for (let i = 0; i < points.length; i++) {
  2600. let item = assign({}, {
  2601. lineColor: '#DE4A42',
  2602. showLabel: false,
  2603. labelFontSize: 13,
  2604. labelPadding: 6,
  2605. labelFontColor: '#666666',
  2606. labelBgColor: '#DFE8FF',
  2607. labelBgOpacity: 0.8,
  2608. labelAlign: 'left',
  2609. labelOffsetX: 0,
  2610. labelOffsetY: 0,
  2611. }, points[i]);
  2612. if (markLineOption.type == 'dash') {
  2613. context.setLineDash([markLineOption.dashLength, markLineOption.dashLength]);
  2614. }
  2615. context.setStrokeStyle(item.lineColor);
  2616. context.setLineWidth(1 * opts.pix);
  2617. context.beginPath();
  2618. context.moveTo(startX, item.y);
  2619. context.lineTo(endX, item.y);
  2620. context.stroke();
  2621. context.setLineDash([]);
  2622. if (item.showLabel) {
  2623. let fontSize = item.labelFontSize * opts.pix;
  2624. let labelText = item.labelText ? item.labelText : item.value;
  2625. context.setFontSize(fontSize);
  2626. let textWidth = measureText(labelText, fontSize, context);
  2627. let bgWidth = textWidth + item.labelPadding * opts.pix * 2;
  2628. let bgStartX = item.labelAlign == 'left' ? opts.area[3] - bgWidth : opts.width - opts.area[1];
  2629. bgStartX += item.labelOffsetX;
  2630. let bgStartY = item.y - 0.5 * fontSize - item.labelPadding * opts.pix;
  2631. bgStartY += item.labelOffsetY;
  2632. let textX = bgStartX + item.labelPadding * opts.pix;
  2633. let textY = item.y;
  2634. context.setFillStyle(hexToRgb(item.labelBgColor, item.labelBgOpacity));
  2635. context.setStrokeStyle(item.labelBgColor);
  2636. context.setLineWidth(1 * opts.pix);
  2637. context.beginPath();
  2638. context.rect(bgStartX, bgStartY, bgWidth, fontSize + 2 * item.labelPadding * opts.pix);
  2639. context.closePath();
  2640. context.stroke();
  2641. context.fill();
  2642. context.setFontSize(fontSize);
  2643. context.setTextAlign('left');
  2644. context.setFillStyle(item.labelFontColor);
  2645. context.fillText(String(labelText), textX, bgStartY + fontSize + item.labelPadding * opts.pix / 2);
  2646. context.stroke();
  2647. context.setTextAlign('left');
  2648. }
  2649. }
  2650. }
  2651. function drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints) {
  2652. var toolTipOption = assign({}, {
  2653. gridType: 'solid',
  2654. dashLength: 4
  2655. }, opts.extra.tooltip);
  2656. var startX = opts.area[3];
  2657. var endX = opts.width - opts.area[1];
  2658. if (toolTipOption.gridType == 'dash') {
  2659. context.setLineDash([toolTipOption.dashLength, toolTipOption.dashLength]);
  2660. }
  2661. context.setStrokeStyle(toolTipOption.gridColor || '#cccccc');
  2662. context.setLineWidth(1 * opts.pix);
  2663. context.beginPath();
  2664. context.moveTo(startX, opts.tooltip.offset.y);
  2665. context.lineTo(endX, opts.tooltip.offset.y);
  2666. context.stroke();
  2667. context.setLineDash([]);
  2668. if (toolTipOption.yAxisLabel) {
  2669. let boxPadding = toolTipOption.boxPadding * opts.pix;
  2670. let labelText = calTooltipYAxisData(opts.tooltip.offset.y, opts.series, opts, config, eachSpacing);
  2671. let widthArr = opts.chartData.yAxisData.yAxisWidth;
  2672. let tStartLeft = opts.area[3];
  2673. let tStartRight = opts.width - opts.area[1];
  2674. for (let i = 0; i < labelText.length; i++) {
  2675. context.setFontSize(toolTipOption.fontSize * opts.pix);
  2676. let textWidth = measureText(labelText[i], toolTipOption.fontSize * opts.pix, context);
  2677. let bgStartX, bgEndX, bgWidth;
  2678. if (widthArr[i].position == 'left') {
  2679. bgStartX = tStartLeft - (textWidth + boxPadding * 2) - 2 * opts.pix;
  2680. bgEndX = Math.max(bgStartX, bgStartX + textWidth + boxPadding * 2);
  2681. } else {
  2682. bgStartX = tStartRight + 2 * opts.pix;
  2683. bgEndX = Math.max(bgStartX + widthArr[i].width, bgStartX + textWidth + boxPadding * 2);
  2684. }
  2685. bgWidth = bgEndX - bgStartX;
  2686. let textX = bgStartX + (bgWidth - textWidth) / 2;
  2687. let textY = opts.tooltip.offset.y;
  2688. context.beginPath();
  2689. context.setFillStyle(hexToRgb(toolTipOption.labelBgColor || config.toolTipBackground, toolTipOption
  2690. .labelBgOpacity || config.toolTipOpacity));
  2691. context.setStrokeStyle(toolTipOption.labelBgColor || config.toolTipBackground);
  2692. context.setLineWidth(1 * opts.pix);
  2693. context.rect(bgStartX, textY - 0.5 * config.fontSize - boxPadding, bgWidth, config.fontSize + 2 *
  2694. boxPadding);
  2695. context.closePath();
  2696. context.stroke();
  2697. context.fill();
  2698. context.beginPath();
  2699. context.setFontSize(config.fontSize);
  2700. context.setFillStyle(toolTipOption.labelFontColor || opts.fontColor);
  2701. context.fillText(labelText[i], textX, textY + 0.5 * config.fontSize);
  2702. context.closePath();
  2703. context.stroke();
  2704. if (widthArr[i].position == 'left') {
  2705. tStartLeft -= (widthArr[i].width + opts.yAxis.padding * opts.pix);
  2706. } else {
  2707. tStartRight += widthArr[i].width + opts.yAxis.padding * opts.pix;
  2708. }
  2709. }
  2710. }
  2711. }
  2712. function drawToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
  2713. var toolTipOption = assign({}, {
  2714. activeBgColor: '#000000',
  2715. activeBgOpacity: 0.08,
  2716. activeWidth: eachSpacing
  2717. }, opts.extra.column);
  2718. toolTipOption.activeWidth = toolTipOption.activeWidth > eachSpacing ? eachSpacing : toolTipOption.activeWidth;
  2719. var startY = opts.area[0];
  2720. var endY = opts.height - opts.area[2];
  2721. context.beginPath();
  2722. context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
  2723. context.rect(offsetX - toolTipOption.activeWidth / 2, startY, toolTipOption.activeWidth, endY - startY);
  2724. context.closePath();
  2725. context.fill();
  2726. context.setFillStyle("#FFFFFF");
  2727. }
  2728. function drawBarToolTipSplitArea(offsetX, opts, config, context, eachSpacing) {
  2729. var toolTipOption = assign({}, {
  2730. activeBgColor: '#000000',
  2731. activeBgOpacity: 0.08
  2732. }, opts.extra.bar);
  2733. var startX = opts.area[3];
  2734. var endX = opts.width - opts.area[1];
  2735. context.beginPath();
  2736. context.setFillStyle(hexToRgb(toolTipOption.activeBgColor, toolTipOption.activeBgOpacity));
  2737. context.rect(startX, offsetX - eachSpacing / 2, endX - startX, eachSpacing);
  2738. context.closePath();
  2739. context.fill();
  2740. context.setFillStyle("#FFFFFF");
  2741. }
  2742. function drawToolTip(textList, offset, opts, config, context, eachSpacing, xAxisPoints) {
  2743. var toolTipOption = assign({}, {
  2744. showBox: true,
  2745. showArrow: true,
  2746. showCategory: false,
  2747. bgColor: '#000000',
  2748. bgOpacity: 0.7,
  2749. borderColor: '#000000',
  2750. borderWidth: 0,
  2751. borderRadius: 0,
  2752. borderOpacity: 0.7,
  2753. boxPadding: 3,
  2754. fontColor: '#FFFFFF',
  2755. fontSize: 13,
  2756. lineHeight: 20,
  2757. legendShow: true,
  2758. legendShape: 'auto',
  2759. splitLine: true,
  2760. }, opts.extra.tooltip);
  2761. if (toolTipOption.showCategory == true && opts.categories) {
  2762. textList.unshift({
  2763. text: opts.categories[opts.tooltip.index],
  2764. color: null
  2765. })
  2766. }
  2767. var fontSize = toolTipOption.fontSize * opts.pix;
  2768. var lineHeight = toolTipOption.lineHeight * opts.pix;
  2769. var boxPadding = toolTipOption.boxPadding * opts.pix;
  2770. var legendWidth = fontSize;
  2771. var legendMarginRight = 5 * opts.pix;
  2772. if (toolTipOption.legendShow == false) {
  2773. legendWidth = 0;
  2774. legendMarginRight = 0;
  2775. }
  2776. var arrowWidth = toolTipOption.showArrow ? 8 * opts.pix : 0;
  2777. var isOverRightBorder = false;
  2778. if (opts.type == 'line' || opts.type == 'mount' || opts.type == 'area' || opts.type == 'candle' || opts.type ==
  2779. 'mix') {
  2780. if (toolTipOption.splitLine == true) {
  2781. drawToolTipSplitLine(opts.tooltip.offset.x, opts, config, context);
  2782. }
  2783. }
  2784. offset = assign({
  2785. x: 0,
  2786. y: 0
  2787. }, offset);
  2788. offset.y -= 8 * opts.pix;
  2789. var textWidth = textList.map(function(item) {
  2790. return measureText(item.text, fontSize, context);
  2791. });
  2792. var toolTipWidth = legendWidth + legendMarginRight + 4 * boxPadding + Math.max.apply(null, textWidth);
  2793. var toolTipHeight = 2 * boxPadding + textList.length * lineHeight;
  2794. if (toolTipOption.showBox == false) {
  2795. return
  2796. }
  2797. // if beyond the right border
  2798. if (offset.x - Math.abs(opts._scrollDistance_ || 0) + arrowWidth + toolTipWidth > opts.width) {
  2799. isOverRightBorder = true;
  2800. }
  2801. if (toolTipHeight + offset.y > opts.height) {
  2802. offset.y = opts.height - toolTipHeight;
  2803. }
  2804. // draw background rect
  2805. context.beginPath();
  2806. context.setFillStyle(hexToRgb(toolTipOption.bgColor, toolTipOption.bgOpacity));
  2807. context.setLineWidth(toolTipOption.borderWidth * opts.pix);
  2808. context.setStrokeStyle(hexToRgb(toolTipOption.borderColor, toolTipOption.borderOpacity));
  2809. var radius = toolTipOption.borderRadius;
  2810. if (isOverRightBorder) {
  2811. // 增加左侧仍然超出的判断
  2812. if (toolTipWidth + arrowWidth > opts.width) {
  2813. offset.x = opts.width + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width)
  2814. }
  2815. if (toolTipWidth > offset.x) {
  2816. offset.x = opts.width + Math.abs(opts._scrollDistance_ || 0) + arrowWidth + (toolTipWidth - opts.width)
  2817. }
  2818. if (toolTipOption.showArrow) {
  2819. context.moveTo(offset.x, offset.y + 10 * opts.pix);
  2820. context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
  2821. }
  2822. context.arc(offset.x - arrowWidth - radius, offset.y + toolTipHeight - radius, radius, 0, Math.PI / 2, false);
  2823. context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + toolTipHeight - radius,
  2824. radius,
  2825. Math.PI / 2, Math.PI, false);
  2826. context.arc(offset.x - arrowWidth - Math.round(toolTipWidth) + radius, offset.y + radius, radius, -Math.PI, -
  2827. Math.PI / 2, false);
  2828. context.arc(offset.x - arrowWidth - radius, offset.y + radius, radius, -Math.PI / 2, 0, false);
  2829. if (toolTipOption.showArrow) {
  2830. context.lineTo(offset.x - arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
  2831. context.lineTo(offset.x, offset.y + 10 * opts.pix);
  2832. }
  2833. } else {
  2834. if (toolTipOption.showArrow) {
  2835. context.moveTo(offset.x, offset.y + 10 * opts.pix);
  2836. context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix - 5 * opts.pix);
  2837. }
  2838. context.arc(offset.x + arrowWidth + radius, offset.y + radius, radius, -Math.PI, -Math.PI / 2, false);
  2839. context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + radius, radius, -Math.PI / 2,
  2840. 0,
  2841. false);
  2842. context.arc(offset.x + arrowWidth + Math.round(toolTipWidth) - radius, offset.y + toolTipHeight - radius,
  2843. radius, 0,
  2844. Math.PI / 2, false);
  2845. context.arc(offset.x + arrowWidth + radius, offset.y + toolTipHeight - radius, radius, Math.PI / 2, Math.PI,
  2846. false);
  2847. if (toolTipOption.showArrow) {
  2848. context.lineTo(offset.x + arrowWidth, offset.y + 10 * opts.pix + 5 * opts.pix);
  2849. context.lineTo(offset.x, offset.y + 10 * opts.pix);
  2850. }
  2851. }
  2852. context.closePath();
  2853. context.fill();
  2854. if (toolTipOption.borderWidth > 0) {
  2855. context.stroke();
  2856. }
  2857. // draw legend
  2858. if (toolTipOption.legendShow) {
  2859. textList.forEach(function(item, index) {
  2860. if (item.color !== null) {
  2861. context.beginPath();
  2862. context.setFillStyle(item.color);
  2863. var startX = offset.x + arrowWidth + 2 * boxPadding;
  2864. var startY = offset.y + (lineHeight - fontSize) / 2 + lineHeight * index + boxPadding + 1;
  2865. if (isOverRightBorder) {
  2866. startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding;
  2867. }
  2868. switch (item.legendShape) {
  2869. case 'line':
  2870. context.moveTo(startX, startY + 0.5 * legendWidth - 2 * opts.pix);
  2871. context.fillRect(startX, startY + 0.5 * legendWidth - 2 * opts.pix, legendWidth, 4 *
  2872. opts.pix);
  2873. break;
  2874. case 'triangle':
  2875. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
  2876. context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
  2877. context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
  2878. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
  2879. break;
  2880. case 'diamond':
  2881. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
  2882. context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * legendWidth);
  2883. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth + 5 * opts.pix);
  2884. context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * legendWidth);
  2885. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
  2886. break;
  2887. case 'circle':
  2888. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth);
  2889. context.arc(startX + 7.5 * opts.pix, startY + 0.5 * legendWidth, 5 * opts.pix, 0, 2 *
  2890. Math.PI);
  2891. break;
  2892. case 'rect':
  2893. context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
  2894. context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 *
  2895. opts.pix);
  2896. break;
  2897. case 'square':
  2898. context.moveTo(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix);
  2899. context.fillRect(startX + 2 * opts.pix, startY + 0.5 * legendWidth - 5 * opts.pix, 10 *
  2900. opts.pix, 10 * opts.pix);
  2901. break;
  2902. default:
  2903. context.moveTo(startX, startY + 0.5 * legendWidth - 5 * opts.pix);
  2904. context.fillRect(startX, startY + 0.5 * legendWidth - 5 * opts.pix, 15 * opts.pix, 10 *
  2905. opts.pix);
  2906. }
  2907. context.closePath();
  2908. context.fill();
  2909. }
  2910. });
  2911. }
  2912. // draw text list
  2913. textList.forEach(function(item, index) {
  2914. var startX = offset.x + arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
  2915. if (isOverRightBorder) {
  2916. startX = offset.x - toolTipWidth - arrowWidth + 2 * boxPadding + legendWidth + legendMarginRight;
  2917. }
  2918. var startY = offset.y + lineHeight * index + (lineHeight - fontSize) / 2 - 1 + boxPadding + fontSize;
  2919. context.beginPath();
  2920. context.setFontSize(fontSize);
  2921. context.setTextBaseline('normal');
  2922. context.setFillStyle(toolTipOption.fontColor);
  2923. context.fillText(item.text, startX, startY);
  2924. context.closePath();
  2925. context.stroke();
  2926. });
  2927. }
  2928. function drawColumnDataPoints(series, opts, config, context) {
  2929. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  2930. let xAxisData = opts.chartData.xAxisData,
  2931. xAxisPoints = xAxisData.xAxisPoints,
  2932. eachSpacing = xAxisData.eachSpacing;
  2933. let columnOption = assign({}, {
  2934. type: 'group',
  2935. width: eachSpacing / 2,
  2936. meterBorder: 4,
  2937. meterFillColor: '#FFFFFF',
  2938. barBorderCircle: false,
  2939. barBorderRadius: [],
  2940. seriesGap: 2,
  2941. linearType: 'none',
  2942. linearOpacity: 1,
  2943. customColor: [],
  2944. colorStop: 0,
  2945. labelPosition: 'outside'
  2946. }, opts.extra.column);
  2947. let calPoints = [];
  2948. context.save();
  2949. let leftNum = -2;
  2950. let rightNum = xAxisPoints.length + 2;
  2951. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  2952. context.translate(opts._scrollDistance_, 0);
  2953. leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
  2954. rightNum = leftNum + opts.xAxis.itemCount + 4;
  2955. }
  2956. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  2957. drawToolTipSplitArea(opts.tooltip.offset.x, opts, config, context, eachSpacing);
  2958. }
  2959. columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
  2960. series.forEach(function(eachSeries, seriesIndex) {
  2961. let ranges, minRange, maxRange;
  2962. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  2963. minRange = ranges.pop();
  2964. maxRange = ranges.shift();
  2965. // 计算0轴坐标
  2966. let spacingValid = opts.height - opts.area[0] - opts.area[2];
  2967. let zeroHeight = spacingValid * (0 - minRange) / (maxRange - minRange);
  2968. let zeroPoints = opts.height - Math.round(zeroHeight) - opts.area[2];
  2969. eachSeries.zeroPoints = zeroPoints;
  2970. var data = eachSeries.data;
  2971. switch (columnOption.type) {
  2972. case 'group':
  2973. var points = getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts,
  2974. config, zeroPoints, process);
  2975. var tooltipPoints = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts,
  2976. config, seriesIndex, series, process);
  2977. calPoints.push(tooltipPoints);
  2978. points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
  2979. for (let i = 0; i < points.length; i++) {
  2980. let item = points[i];
  2981. //fix issues/I27B1N yyoinge & Joeshu
  2982. if (item !== null && i > leftNum && i < rightNum) {
  2983. var startX = item.x - item.width / 2;
  2984. var height = opts.height - item.y - opts.area[2];
  2985. context.beginPath();
  2986. var fillColor = item.color || eachSeries.color
  2987. var strokeColor = item.color || eachSeries.color
  2988. if (columnOption.linearType !== 'none') {
  2989. var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
  2990. //透明渐变
  2991. if (columnOption.linearType == 'opacity') {
  2992. grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
  2993. grd.addColorStop(1, hexToRgb(fillColor, 1));
  2994. } else {
  2995. grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex],
  2996. columnOption.linearOpacity));
  2997. grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[
  2998. eachSeries.linearIndex], columnOption.linearOpacity));
  2999. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3000. }
  3001. fillColor = grd
  3002. }
  3003. // 圆角边框
  3004. if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) ||
  3005. columnOption.barBorderCircle === true) {
  3006. const left = startX;
  3007. const top = item.y > zeroPoints ? zeroPoints : item.y;
  3008. const width = item.width;
  3009. const height = Math.abs(zeroPoints - item.y);
  3010. if (columnOption.barBorderCircle) {
  3011. columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
  3012. }
  3013. if (item.y > zeroPoints) {
  3014. columnOption.barBorderRadius = [0, 0, width / 2, width / 2];
  3015. }
  3016. let [r0, r1, r2, r3] = columnOption.barBorderRadius;
  3017. let minRadius = Math.min(width / 2, height / 2);
  3018. r0 = r0 > minRadius ? minRadius : r0;
  3019. r1 = r1 > minRadius ? minRadius : r1;
  3020. r2 = r2 > minRadius ? minRadius : r2;
  3021. r3 = r3 > minRadius ? minRadius : r3;
  3022. r0 = r0 < 0 ? 0 : r0;
  3023. r1 = r1 < 0 ? 0 : r1;
  3024. r2 = r2 < 0 ? 0 : r2;
  3025. r3 = r3 < 0 ? 0 : r3;
  3026. context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
  3027. context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
  3028. context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
  3029. context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
  3030. } else {
  3031. context.moveTo(startX, item.y);
  3032. context.lineTo(startX + item.width, item.y);
  3033. context.lineTo(startX + item.width, zeroPoints);
  3034. context.lineTo(startX, zeroPoints);
  3035. context.lineTo(startX, item.y);
  3036. context.setLineWidth(1)
  3037. context.setStrokeStyle(strokeColor);
  3038. }
  3039. context.setFillStyle(fillColor);
  3040. context.closePath();
  3041. //context.stroke();
  3042. context.fill();
  3043. }
  3044. };
  3045. break;
  3046. case 'stack':
  3047. // 绘制堆叠数据图
  3048. var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts,
  3049. config, seriesIndex, series, process);
  3050. calPoints.push(points);
  3051. points = fixColumeStackData(points, eachSpacing, series.length, seriesIndex, config, opts,
  3052. series);
  3053. for (let i = 0; i < points.length; i++) {
  3054. let item = points[i];
  3055. if (item !== null && i > leftNum && i < rightNum) {
  3056. context.beginPath();
  3057. var fillColor = item.color || eachSeries.color;
  3058. var startX = item.x - item.width / 2 + 1;
  3059. var height = opts.height - item.y - opts.area[2];
  3060. var height0 = opts.height - item.y0 - opts.area[2];
  3061. if (seriesIndex > 0) {
  3062. height -= height0;
  3063. }
  3064. context.setFillStyle(fillColor);
  3065. context.moveTo(startX, item.y);
  3066. context.fillRect(startX, item.y, item.width, height);
  3067. context.closePath();
  3068. context.fill();
  3069. }
  3070. };
  3071. break;
  3072. case 'meter':
  3073. // 绘制温度计数据图
  3074. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3075. process);
  3076. calPoints.push(points);
  3077. points = fixColumeMeterData(points, eachSpacing, series.length, seriesIndex, config, opts,
  3078. columnOption.meterBorder);
  3079. for (let i = 0; i < points.length; i++) {
  3080. let item = points[i];
  3081. if (item !== null && i > leftNum && i < rightNum) {
  3082. //画背景颜色
  3083. context.beginPath();
  3084. if (seriesIndex == 0 && columnOption.meterBorder > 0) {
  3085. context.setStrokeStyle(eachSeries.color);
  3086. context.setLineWidth(columnOption.meterBorder * opts.pix);
  3087. }
  3088. if (seriesIndex == 0) {
  3089. context.setFillStyle(columnOption.meterFillColor);
  3090. } else {
  3091. context.setFillStyle(item.color || eachSeries.color);
  3092. }
  3093. var startX = item.x - item.width / 2;
  3094. var height = opts.height - item.y - opts.area[2];
  3095. if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) ||
  3096. columnOption.barBorderCircle === true) {
  3097. const left = startX;
  3098. const top = item.y;
  3099. const width = item.width;
  3100. const height = zeroPoints - item.y;
  3101. if (columnOption.barBorderCircle) {
  3102. columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
  3103. }
  3104. let [r0, r1, r2, r3] = columnOption.barBorderRadius;
  3105. let minRadius = Math.min(width / 2, height / 2);
  3106. r0 = r0 > minRadius ? minRadius : r0;
  3107. r1 = r1 > minRadius ? minRadius : r1;
  3108. r2 = r2 > minRadius ? minRadius : r2;
  3109. r3 = r3 > minRadius ? minRadius : r3;
  3110. r0 = r0 < 0 ? 0 : r0;
  3111. r1 = r1 < 0 ? 0 : r1;
  3112. r2 = r2 < 0 ? 0 : r2;
  3113. r3 = r3 < 0 ? 0 : r3;
  3114. context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
  3115. context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
  3116. context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
  3117. context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
  3118. context.fill();
  3119. } else {
  3120. context.moveTo(startX, item.y);
  3121. context.lineTo(startX + item.width, item.y);
  3122. context.lineTo(startX + item.width, zeroPoints);
  3123. context.lineTo(startX, zeroPoints);
  3124. context.lineTo(startX, item.y);
  3125. context.fill();
  3126. }
  3127. if (seriesIndex == 0 && columnOption.meterBorder > 0) {
  3128. context.closePath();
  3129. context.stroke();
  3130. }
  3131. }
  3132. }
  3133. break;
  3134. }
  3135. });
  3136. if (opts.dataLabel !== false && process === 1) {
  3137. series.forEach(function(eachSeries, seriesIndex) {
  3138. let ranges, minRange, maxRange;
  3139. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3140. minRange = ranges.pop();
  3141. maxRange = ranges.shift();
  3142. var data = eachSeries.data;
  3143. switch (columnOption.type) {
  3144. case 'group':
  3145. var points = getColumnDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts,
  3146. config, process);
  3147. points = fixColumeData(points, eachSpacing, series.length, seriesIndex, config, opts);
  3148. drawColumePointText(points, eachSeries, config, context, opts);
  3149. break;
  3150. case 'stack':
  3151. var points = getStackDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts,
  3152. config, seriesIndex, series, process);
  3153. drawColumePointText(points, eachSeries, config, context, opts);
  3154. break;
  3155. case 'meter':
  3156. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3157. process);
  3158. drawColumePointText(points, eachSeries, config, context, opts);
  3159. break;
  3160. }
  3161. });
  3162. }
  3163. context.restore();
  3164. return {
  3165. xAxisPoints: xAxisPoints,
  3166. calPoints: calPoints,
  3167. eachSpacing: eachSpacing
  3168. };
  3169. }
  3170. function drawMountDataPoints(series, opts, config, context) {
  3171. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  3172. let xAxisData = opts.chartData.xAxisData,
  3173. xAxisPoints = xAxisData.xAxisPoints,
  3174. eachSpacing = xAxisData.eachSpacing;
  3175. let mountOption = assign({}, {
  3176. type: 'mount',
  3177. widthRatio: 1,
  3178. borderWidth: 1,
  3179. barBorderCircle: false,
  3180. barBorderRadius: [],
  3181. linearType: 'none',
  3182. linearOpacity: 1,
  3183. customColor: [],
  3184. colorStop: 0,
  3185. }, opts.extra.mount);
  3186. mountOption.widthRatio = mountOption.widthRatio <= 0 ? 0 : mountOption.widthRatio;
  3187. mountOption.widthRatio = mountOption.widthRatio >= 2 ? 2 : mountOption.widthRatio;
  3188. let calPoints = [];
  3189. context.save();
  3190. let leftNum = -2;
  3191. let rightNum = xAxisPoints.length + 2;
  3192. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  3193. context.translate(opts._scrollDistance_, 0);
  3194. leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
  3195. rightNum = leftNum + opts.xAxis.itemCount + 4;
  3196. }
  3197. mountOption.customColor = fillCustomColor(mountOption.linearType, mountOption.customColor, series, config);
  3198. let ranges, minRange, maxRange;
  3199. ranges = [].concat(opts.chartData.yAxisData.ranges[0]);
  3200. minRange = ranges.pop();
  3201. maxRange = ranges.shift();
  3202. // 计算0轴坐标
  3203. let spacingValid = opts.height - opts.area[0] - opts.area[2];
  3204. let zeroHeight = spacingValid * (0 - minRange) / (maxRange - minRange);
  3205. let zeroPoints = opts.height - Math.round(zeroHeight) - opts.area[2];
  3206. var points = getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption, zeroPoints,
  3207. process);
  3208. switch (mountOption.type) {
  3209. case 'bar':
  3210. for (let i = 0; i < points.length; i++) {
  3211. let item = points[i];
  3212. if (item !== null && i > leftNum && i < rightNum) {
  3213. var startX = item.x - eachSpacing * mountOption.widthRatio / 2;
  3214. var height = opts.height - item.y - opts.area[2];
  3215. context.beginPath();
  3216. var fillColor = item.color || series[i].color
  3217. var strokeColor = item.color || series[i].color
  3218. if (mountOption.linearType !== 'none') {
  3219. var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
  3220. //透明渐变
  3221. if (mountOption.linearType == 'opacity') {
  3222. grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
  3223. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3224. } else {
  3225. grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption
  3226. .linearOpacity));
  3227. grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i]
  3228. .linearIndex], mountOption.linearOpacity));
  3229. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3230. }
  3231. fillColor = grd
  3232. }
  3233. // 圆角边框
  3234. if ((mountOption.barBorderRadius && mountOption.barBorderRadius.length === 4) || mountOption
  3235. .barBorderCircle === true) {
  3236. const left = startX;
  3237. const top = item.y > zeroPoints ? zeroPoints : item.y;
  3238. const width = item.width;
  3239. const height = Math.abs(zeroPoints - item.y);
  3240. if (mountOption.barBorderCircle) {
  3241. mountOption.barBorderRadius = [width / 2, width / 2, 0, 0];
  3242. }
  3243. if (item.y > zeroPoints) {
  3244. mountOption.barBorderRadius = [0, 0, width / 2, width / 2];
  3245. }
  3246. let [r0, r1, r2, r3] = mountOption.barBorderRadius;
  3247. let minRadius = Math.min(width / 2, height / 2);
  3248. r0 = r0 > minRadius ? minRadius : r0;
  3249. r1 = r1 > minRadius ? minRadius : r1;
  3250. r2 = r2 > minRadius ? minRadius : r2;
  3251. r3 = r3 > minRadius ? minRadius : r3;
  3252. r0 = r0 < 0 ? 0 : r0;
  3253. r1 = r1 < 0 ? 0 : r1;
  3254. r2 = r2 < 0 ? 0 : r2;
  3255. r3 = r3 < 0 ? 0 : r3;
  3256. context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
  3257. context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
  3258. context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
  3259. context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
  3260. } else {
  3261. context.moveTo(startX, item.y);
  3262. context.lineTo(startX + item.width, item.y);
  3263. context.lineTo(startX + item.width, zeroPoints);
  3264. context.lineTo(startX, zeroPoints);
  3265. context.lineTo(startX, item.y);
  3266. }
  3267. context.setStrokeStyle(strokeColor);
  3268. context.setFillStyle(fillColor);
  3269. if (mountOption.borderWidth > 0) {
  3270. context.setLineWidth(mountOption.borderWidth * opts.pix);
  3271. context.closePath();
  3272. context.stroke();
  3273. }
  3274. context.fill();
  3275. }
  3276. };
  3277. break;
  3278. case 'triangle':
  3279. for (let i = 0; i < points.length; i++) {
  3280. let item = points[i];
  3281. if (item !== null && i > leftNum && i < rightNum) {
  3282. var startX = item.x - eachSpacing * mountOption.widthRatio / 2;
  3283. var height = opts.height - item.y - opts.area[2];
  3284. context.beginPath();
  3285. var fillColor = item.color || series[i].color
  3286. var strokeColor = item.color || series[i].color
  3287. if (mountOption.linearType !== 'none') {
  3288. var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
  3289. //透明渐变
  3290. if (mountOption.linearType == 'opacity') {
  3291. grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
  3292. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3293. } else {
  3294. grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption
  3295. .linearOpacity));
  3296. grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i]
  3297. .linearIndex], mountOption.linearOpacity));
  3298. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3299. }
  3300. fillColor = grd
  3301. }
  3302. context.moveTo(startX, zeroPoints);
  3303. context.lineTo(item.x, item.y);
  3304. context.lineTo(startX + item.width, zeroPoints);
  3305. context.setStrokeStyle(strokeColor);
  3306. context.setFillStyle(fillColor);
  3307. if (mountOption.borderWidth > 0) {
  3308. context.setLineWidth(mountOption.borderWidth * opts.pix);
  3309. context.stroke();
  3310. }
  3311. context.fill();
  3312. }
  3313. };
  3314. break;
  3315. case 'mount':
  3316. for (let i = 0; i < points.length; i++) {
  3317. let item = points[i];
  3318. if (item !== null && i > leftNum && i < rightNum) {
  3319. var startX = item.x - eachSpacing * mountOption.widthRatio / 2;
  3320. var height = opts.height - item.y - opts.area[2];
  3321. context.beginPath();
  3322. var fillColor = item.color || series[i].color
  3323. var strokeColor = item.color || series[i].color
  3324. if (mountOption.linearType !== 'none') {
  3325. var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
  3326. //透明渐变
  3327. if (mountOption.linearType == 'opacity') {
  3328. grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
  3329. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3330. } else {
  3331. grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption
  3332. .linearOpacity));
  3333. grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i]
  3334. .linearIndex], mountOption.linearOpacity));
  3335. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3336. }
  3337. fillColor = grd
  3338. }
  3339. context.moveTo(startX, zeroPoints);
  3340. context.bezierCurveTo(item.x - item.width / 4, zeroPoints, item.x - item.width / 4, item.y, item.x,
  3341. item.y);
  3342. context.bezierCurveTo(item.x + item.width / 4, item.y, item.x + item.width / 4, zeroPoints, startX +
  3343. item.width, zeroPoints);
  3344. context.setStrokeStyle(strokeColor);
  3345. context.setFillStyle(fillColor);
  3346. if (mountOption.borderWidth > 0) {
  3347. context.setLineWidth(mountOption.borderWidth * opts.pix);
  3348. context.stroke();
  3349. }
  3350. context.fill();
  3351. }
  3352. };
  3353. break;
  3354. case 'sharp':
  3355. for (let i = 0; i < points.length; i++) {
  3356. let item = points[i];
  3357. if (item !== null && i > leftNum && i < rightNum) {
  3358. var startX = item.x - eachSpacing * mountOption.widthRatio / 2;
  3359. var height = opts.height - item.y - opts.area[2];
  3360. context.beginPath();
  3361. var fillColor = item.color || series[i].color
  3362. var strokeColor = item.color || series[i].color
  3363. if (mountOption.linearType !== 'none') {
  3364. var grd = context.createLinearGradient(startX, item.y, startX, zeroPoints);
  3365. //透明渐变
  3366. if (mountOption.linearType == 'opacity') {
  3367. grd.addColorStop(0, hexToRgb(fillColor, mountOption.linearOpacity));
  3368. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3369. } else {
  3370. grd.addColorStop(0, hexToRgb(mountOption.customColor[series[i].linearIndex], mountOption
  3371. .linearOpacity));
  3372. grd.addColorStop(mountOption.colorStop, hexToRgb(mountOption.customColor[series[i]
  3373. .linearIndex], mountOption.linearOpacity));
  3374. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3375. }
  3376. fillColor = grd
  3377. }
  3378. context.moveTo(startX, zeroPoints);
  3379. context.quadraticCurveTo(item.x - 0, zeroPoints - height / 4, item.x, item.y);
  3380. context.quadraticCurveTo(item.x + 0, zeroPoints - height / 4, startX + item.width, zeroPoints)
  3381. context.setStrokeStyle(strokeColor);
  3382. context.setFillStyle(fillColor);
  3383. if (mountOption.borderWidth > 0) {
  3384. context.setLineWidth(mountOption.borderWidth * opts.pix);
  3385. context.stroke();
  3386. }
  3387. context.fill();
  3388. }
  3389. };
  3390. break;
  3391. }
  3392. if (opts.dataLabel !== false && process === 1) {
  3393. let ranges, minRange, maxRange;
  3394. ranges = [].concat(opts.chartData.yAxisData.ranges[0]);
  3395. minRange = ranges.pop();
  3396. maxRange = ranges.shift();
  3397. var points = getMountDataPoints(series, minRange, maxRange, xAxisPoints, eachSpacing, opts, mountOption,
  3398. zeroPoints, process);
  3399. drawMountPointText(points, series, config, context, opts, zeroPoints);
  3400. }
  3401. context.restore();
  3402. return {
  3403. xAxisPoints: xAxisPoints,
  3404. calPoints: points,
  3405. eachSpacing: eachSpacing
  3406. };
  3407. }
  3408. function drawBarDataPoints(series, opts, config, context) {
  3409. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  3410. let yAxisPoints = [];
  3411. let eachSpacing = (opts.height - opts.area[0] - opts.area[2]) / opts.categories.length;
  3412. for (let i = 0; i < opts.categories.length; i++) {
  3413. yAxisPoints.push(opts.area[0] + eachSpacing / 2 + eachSpacing * i);
  3414. }
  3415. let columnOption = assign({}, {
  3416. type: 'group',
  3417. width: eachSpacing / 2,
  3418. meterBorder: 4,
  3419. meterFillColor: '#FFFFFF',
  3420. barBorderCircle: false,
  3421. barBorderRadius: [],
  3422. seriesGap: 2,
  3423. linearType: 'none',
  3424. linearOpacity: 1,
  3425. customColor: [],
  3426. colorStop: 0,
  3427. }, opts.extra.bar);
  3428. let calPoints = [];
  3429. context.save();
  3430. let leftNum = -2;
  3431. let rightNum = yAxisPoints.length + 2;
  3432. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  3433. drawBarToolTipSplitArea(opts.tooltip.offset.y, opts, config, context, eachSpacing);
  3434. }
  3435. columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
  3436. series.forEach(function(eachSeries, seriesIndex) {
  3437. let ranges, minRange, maxRange;
  3438. ranges = [].concat(opts.chartData.xAxisData.ranges);
  3439. maxRange = ranges.pop();
  3440. minRange = ranges.shift();
  3441. var data = eachSeries.data;
  3442. switch (columnOption.type) {
  3443. case 'group':
  3444. var points = getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts, config,
  3445. process);
  3446. var tooltipPoints = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing,
  3447. opts, config, seriesIndex, series, process);
  3448. calPoints.push(tooltipPoints);
  3449. points = fixBarData(points, eachSpacing, series.length, seriesIndex, config, opts);
  3450. for (let i = 0; i < points.length; i++) {
  3451. let item = points[i];
  3452. //fix issues/I27B1N yyoinge & Joeshu
  3453. if (item !== null && i > leftNum && i < rightNum) {
  3454. //var startX = item.x - item.width / 2;
  3455. var startX = opts.area[3];
  3456. var startY = item.y - item.width / 2;
  3457. var height = item.height;
  3458. context.beginPath();
  3459. var fillColor = item.color || eachSeries.color
  3460. var strokeColor = item.color || eachSeries.color
  3461. if (columnOption.linearType !== 'none') {
  3462. var grd = context.createLinearGradient(startX, item.y, item.x, item.y);
  3463. //透明渐变
  3464. if (columnOption.linearType == 'opacity') {
  3465. grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
  3466. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3467. } else {
  3468. grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex],
  3469. columnOption.linearOpacity));
  3470. grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[
  3471. eachSeries.linearIndex], columnOption.linearOpacity));
  3472. grd.addColorStop(1, hexToRgb(fillColor, 1));
  3473. }
  3474. fillColor = grd
  3475. }
  3476. // 圆角边框
  3477. if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) ||
  3478. columnOption.barBorderCircle === true) {
  3479. const left = startX;
  3480. const width = item.width;
  3481. const top = item.y - item.width / 2;
  3482. const height = item.height;
  3483. if (columnOption.barBorderCircle) {
  3484. columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
  3485. }
  3486. let [r0, r1, r2, r3] = columnOption.barBorderRadius;
  3487. let minRadius = Math.min(width / 2, height / 2);
  3488. r0 = r0 > minRadius ? minRadius : r0;
  3489. r1 = r1 > minRadius ? minRadius : r1;
  3490. r2 = r2 > minRadius ? minRadius : r2;
  3491. r3 = r3 > minRadius ? minRadius : r3;
  3492. r0 = r0 < 0 ? 0 : r0;
  3493. r1 = r1 < 0 ? 0 : r1;
  3494. r2 = r2 < 0 ? 0 : r2;
  3495. r3 = r3 < 0 ? 0 : r3;
  3496. context.arc(left + r3, top + r3, r3, -Math.PI, -Math.PI / 2);
  3497. context.arc(item.x - r0, top + r0, r0, -Math.PI / 2, 0);
  3498. context.arc(item.x - r1, top + width - r1, r1, 0, Math.PI / 2);
  3499. context.arc(left + r2, top + width - r2, r2, Math.PI / 2, Math.PI);
  3500. } else {
  3501. context.moveTo(startX, startY);
  3502. context.lineTo(item.x, startY);
  3503. context.lineTo(item.x, startY + item.width);
  3504. context.lineTo(startX, startY + item.width);
  3505. context.lineTo(startX, startY);
  3506. context.setLineWidth(1)
  3507. context.setStrokeStyle(strokeColor);
  3508. }
  3509. context.setFillStyle(fillColor);
  3510. context.closePath();
  3511. //context.stroke();
  3512. context.fill();
  3513. }
  3514. };
  3515. break;
  3516. case 'stack':
  3517. // 绘制堆叠数据图
  3518. var points = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts,
  3519. config, seriesIndex, series, process);
  3520. calPoints.push(points);
  3521. points = fixBarStackData(points, eachSpacing, series.length, seriesIndex, config, opts, series);
  3522. for (let i = 0; i < points.length; i++) {
  3523. let item = points[i];
  3524. if (item !== null && i > leftNum && i < rightNum) {
  3525. context.beginPath();
  3526. var fillColor = item.color || eachSeries.color;
  3527. var startX = item.x0;
  3528. context.setFillStyle(fillColor);
  3529. context.moveTo(startX, item.y - item.width / 2);
  3530. context.fillRect(startX, item.y - item.width / 2, item.height, item.width);
  3531. context.closePath();
  3532. context.fill();
  3533. }
  3534. };
  3535. break;
  3536. }
  3537. });
  3538. if (opts.dataLabel !== false && process === 1) {
  3539. series.forEach(function(eachSeries, seriesIndex) {
  3540. let ranges, minRange, maxRange;
  3541. ranges = [].concat(opts.chartData.xAxisData.ranges);
  3542. maxRange = ranges.pop();
  3543. minRange = ranges.shift();
  3544. var data = eachSeries.data;
  3545. switch (columnOption.type) {
  3546. case 'group':
  3547. var points = getBarDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts,
  3548. config, process);
  3549. points = fixBarData(points, eachSpacing, series.length, seriesIndex, config, opts);
  3550. drawBarPointText(points, eachSeries, config, context, opts);
  3551. break;
  3552. case 'stack':
  3553. var points = getBarStackDataPoints(data, minRange, maxRange, yAxisPoints, eachSpacing, opts,
  3554. config, seriesIndex, series, process);
  3555. drawBarPointText(points, eachSeries, config, context, opts);
  3556. break;
  3557. }
  3558. });
  3559. }
  3560. return {
  3561. yAxisPoints: yAxisPoints,
  3562. calPoints: calPoints,
  3563. eachSpacing: eachSpacing
  3564. };
  3565. }
  3566. function drawCandleDataPoints(series, seriesMA, opts, config, context) {
  3567. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  3568. var candleOption = assign({}, {
  3569. color: {},
  3570. average: {}
  3571. }, opts.extra.candle);
  3572. candleOption.color = assign({}, {
  3573. upLine: '#f04864',
  3574. upFill: '#f04864',
  3575. downLine: '#2fc25b',
  3576. downFill: '#2fc25b'
  3577. }, candleOption.color);
  3578. candleOption.average = assign({}, {
  3579. show: false,
  3580. name: [],
  3581. day: [],
  3582. color: config.color
  3583. }, candleOption.average);
  3584. opts.extra.candle = candleOption;
  3585. let xAxisData = opts.chartData.xAxisData,
  3586. xAxisPoints = xAxisData.xAxisPoints,
  3587. eachSpacing = xAxisData.eachSpacing;
  3588. let calPoints = [];
  3589. context.save();
  3590. let leftNum = -2;
  3591. let rightNum = xAxisPoints.length + 2;
  3592. let leftSpace = 0;
  3593. let rightSpace = opts.width + eachSpacing;
  3594. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  3595. context.translate(opts._scrollDistance_, 0);
  3596. leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
  3597. rightNum = leftNum + opts.xAxis.itemCount + 4;
  3598. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  3599. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  3600. }
  3601. //画均线
  3602. if (candleOption.average.show || seriesMA) { //Merge pull request !12 from 邱贵翔
  3603. seriesMA.forEach(function(eachSeries, seriesIndex) {
  3604. let ranges, minRange, maxRange;
  3605. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3606. minRange = ranges.pop();
  3607. maxRange = ranges.shift();
  3608. var data = eachSeries.data;
  3609. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3610. process);
  3611. var splitPointList = splitPoints(points, eachSeries);
  3612. for (let i = 0; i < splitPointList.length; i++) {
  3613. let points = splitPointList[i];
  3614. context.beginPath();
  3615. context.setStrokeStyle(eachSeries.color);
  3616. context.setLineWidth(1);
  3617. if (points.length === 1) {
  3618. context.moveTo(points[0].x, points[0].y);
  3619. context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  3620. } else {
  3621. context.moveTo(points[0].x, points[0].y);
  3622. let startPoint = 0;
  3623. for (let j = 0; j < points.length; j++) {
  3624. let item = points[j];
  3625. if (startPoint == 0 && item.x > leftSpace) {
  3626. context.moveTo(item.x, item.y);
  3627. startPoint = 1;
  3628. }
  3629. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3630. var ctrlPoint = createCurveControlPoints(points, j - 1);
  3631. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x,
  3632. ctrlPoint.ctrB.y, item.x,
  3633. item.y);
  3634. }
  3635. }
  3636. context.moveTo(points[0].x, points[0].y);
  3637. }
  3638. context.closePath();
  3639. context.stroke();
  3640. }
  3641. });
  3642. }
  3643. //画K线
  3644. series.forEach(function(eachSeries, seriesIndex) {
  3645. let ranges, minRange, maxRange;
  3646. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3647. minRange = ranges.pop();
  3648. maxRange = ranges.shift();
  3649. var data = eachSeries.data;
  3650. var points = getCandleDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3651. process);
  3652. calPoints.push(points);
  3653. var splitPointList = splitPoints(points, eachSeries);
  3654. for (let i = 0; i < splitPointList[0].length; i++) {
  3655. if (i > leftNum && i < rightNum) {
  3656. let item = splitPointList[0][i];
  3657. context.beginPath();
  3658. //如果上涨
  3659. if (data[i][1] - data[i][0] > 0) {
  3660. context.setStrokeStyle(candleOption.color.upLine);
  3661. context.setFillStyle(candleOption.color.upFill);
  3662. context.setLineWidth(1 * opts.pix);
  3663. context.moveTo(item[3].x, item[3].y); //顶点
  3664. context.lineTo(item[1].x, item[1].y); //收盘中间点
  3665. context.lineTo(item[1].x - eachSpacing / 4, item[1].y); //收盘左侧点
  3666. context.lineTo(item[0].x - eachSpacing / 4, item[0].y); //开盘左侧点
  3667. context.lineTo(item[0].x, item[0].y); //开盘中间点
  3668. context.lineTo(item[2].x, item[2].y); //底点
  3669. context.lineTo(item[0].x, item[0].y); //开盘中间点
  3670. context.lineTo(item[0].x + eachSpacing / 4, item[0].y); //开盘右侧点
  3671. context.lineTo(item[1].x + eachSpacing / 4, item[1].y); //收盘右侧点
  3672. context.lineTo(item[1].x, item[1].y); //收盘中间点
  3673. context.moveTo(item[3].x, item[3].y); //顶点
  3674. } else {
  3675. context.setStrokeStyle(candleOption.color.downLine);
  3676. context.setFillStyle(candleOption.color.downFill);
  3677. context.setLineWidth(1 * opts.pix);
  3678. context.moveTo(item[3].x, item[3].y); //顶点
  3679. context.lineTo(item[0].x, item[0].y); //开盘中间点
  3680. context.lineTo(item[0].x - eachSpacing / 4, item[0].y); //开盘左侧点
  3681. context.lineTo(item[1].x - eachSpacing / 4, item[1].y); //收盘左侧点
  3682. context.lineTo(item[1].x, item[1].y); //收盘中间点
  3683. context.lineTo(item[2].x, item[2].y); //底点
  3684. context.lineTo(item[1].x, item[1].y); //收盘中间点
  3685. context.lineTo(item[1].x + eachSpacing / 4, item[1].y); //收盘右侧点
  3686. context.lineTo(item[0].x + eachSpacing / 4, item[0].y); //开盘右侧点
  3687. context.lineTo(item[0].x, item[0].y); //开盘中间点
  3688. context.moveTo(item[3].x, item[3].y); //顶点
  3689. }
  3690. context.closePath();
  3691. context.fill();
  3692. context.stroke();
  3693. }
  3694. }
  3695. });
  3696. context.restore();
  3697. return {
  3698. xAxisPoints: xAxisPoints,
  3699. calPoints: calPoints,
  3700. eachSpacing: eachSpacing
  3701. };
  3702. }
  3703. function drawAreaDataPoints(series, opts, config, context) {
  3704. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  3705. var areaOption = assign({}, {
  3706. type: 'straight',
  3707. opacity: 0.2,
  3708. addLine: false,
  3709. width: 2,
  3710. gradient: false,
  3711. activeType: 'none'
  3712. }, opts.extra.area);
  3713. let xAxisData = opts.chartData.xAxisData,
  3714. xAxisPoints = xAxisData.xAxisPoints,
  3715. eachSpacing = xAxisData.eachSpacing;
  3716. let endY = opts.height - opts.area[2];
  3717. let calPoints = [];
  3718. context.save();
  3719. let leftSpace = 0;
  3720. let rightSpace = opts.width + eachSpacing;
  3721. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  3722. context.translate(opts._scrollDistance_, 0);
  3723. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  3724. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  3725. }
  3726. series.forEach(function(eachSeries, seriesIndex) {
  3727. let ranges, minRange, maxRange;
  3728. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3729. minRange = ranges.pop();
  3730. maxRange = ranges.shift();
  3731. let data = eachSeries.data;
  3732. let points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  3733. calPoints.push(points);
  3734. let splitPointList = splitPoints(points, eachSeries);
  3735. for (let i = 0; i < splitPointList.length; i++) {
  3736. let points = splitPointList[i];
  3737. // 绘制区域数
  3738. context.beginPath();
  3739. context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  3740. if (areaOption.gradient) {
  3741. let gradient = context.createLinearGradient(0, opts.area[0], 0, opts.height - opts.area[2]);
  3742. gradient.addColorStop('0', hexToRgb(eachSeries.color, areaOption.opacity));
  3743. gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
  3744. context.setFillStyle(gradient);
  3745. } else {
  3746. context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  3747. }
  3748. context.setLineWidth(areaOption.width * opts.pix);
  3749. if (points.length > 1) {
  3750. let firstPoint = points[0];
  3751. let lastPoint = points[points.length - 1];
  3752. context.moveTo(firstPoint.x, firstPoint.y);
  3753. let startPoint = 0;
  3754. if (areaOption.type === 'curve') {
  3755. for (let j = 0; j < points.length; j++) {
  3756. let item = points[j];
  3757. if (startPoint == 0 && item.x > leftSpace) {
  3758. context.moveTo(item.x, item.y);
  3759. startPoint = 1;
  3760. }
  3761. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3762. let ctrlPoint = createCurveControlPoints(points, j - 1);
  3763. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x,
  3764. ctrlPoint.ctrB.y, item.x, item.y);
  3765. }
  3766. };
  3767. }
  3768. if (areaOption.type === 'straight') {
  3769. for (let j = 0; j < points.length; j++) {
  3770. let item = points[j];
  3771. if (startPoint == 0 && item.x > leftSpace) {
  3772. context.moveTo(item.x, item.y);
  3773. startPoint = 1;
  3774. }
  3775. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3776. context.lineTo(item.x, item.y);
  3777. }
  3778. };
  3779. }
  3780. if (areaOption.type === 'step') {
  3781. for (let j = 0; j < points.length; j++) {
  3782. let item = points[j];
  3783. if (startPoint == 0 && item.x > leftSpace) {
  3784. context.moveTo(item.x, item.y);
  3785. startPoint = 1;
  3786. }
  3787. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3788. context.lineTo(item.x, points[j - 1].y);
  3789. context.lineTo(item.x, item.y);
  3790. }
  3791. };
  3792. }
  3793. context.lineTo(lastPoint.x, endY);
  3794. context.lineTo(firstPoint.x, endY);
  3795. context.lineTo(firstPoint.x, firstPoint.y);
  3796. } else {
  3797. let item = points[0];
  3798. context.moveTo(item.x - eachSpacing / 2, item.y);
  3799. // context.lineTo(item.x + eachSpacing / 2, item.y);
  3800. // context.lineTo(item.x + eachSpacing / 2, endY);
  3801. // context.lineTo(item.x - eachSpacing / 2, endY);
  3802. // context.moveTo(item.x - eachSpacing / 2, item.y);
  3803. }
  3804. context.closePath();
  3805. context.fill();
  3806. //画连线
  3807. if (areaOption.addLine) {
  3808. if (eachSeries.lineType == 'dash') {
  3809. let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
  3810. dashLength *= opts.pix;
  3811. context.setLineDash([dashLength, dashLength]);
  3812. }
  3813. context.beginPath();
  3814. context.setStrokeStyle(eachSeries.color);
  3815. context.setLineWidth(areaOption.width * opts.pix);
  3816. if (points.length === 1) {
  3817. context.moveTo(points[0].x, points[0].y);
  3818. // context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  3819. } else {
  3820. context.moveTo(points[0].x, points[0].y);
  3821. let startPoint = 0;
  3822. if (areaOption.type === 'curve') {
  3823. for (let j = 0; j < points.length; j++) {
  3824. let item = points[j];
  3825. if (startPoint == 0 && item.x > leftSpace) {
  3826. context.moveTo(item.x, item.y);
  3827. startPoint = 1;
  3828. }
  3829. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3830. let ctrlPoint = createCurveControlPoints(points, j - 1);
  3831. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x,
  3832. ctrlPoint.ctrB.y, item.x, item.y);
  3833. }
  3834. };
  3835. }
  3836. if (areaOption.type === 'straight') {
  3837. for (let j = 0; j < points.length; j++) {
  3838. let item = points[j];
  3839. if (startPoint == 0 && item.x > leftSpace) {
  3840. context.moveTo(item.x, item.y);
  3841. startPoint = 1;
  3842. }
  3843. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3844. context.lineTo(item.x, item.y);
  3845. }
  3846. };
  3847. }
  3848. if (areaOption.type === 'step') {
  3849. for (let j = 0; j < points.length; j++) {
  3850. let item = points[j];
  3851. if (startPoint == 0 && item.x > leftSpace) {
  3852. context.moveTo(item.x, item.y);
  3853. startPoint = 1;
  3854. }
  3855. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  3856. context.lineTo(item.x, points[j - 1].y);
  3857. context.lineTo(item.x, item.y);
  3858. }
  3859. };
  3860. }
  3861. context.moveTo(points[0].x, points[0].y);
  3862. }
  3863. context.stroke();
  3864. context.setLineDash([]);
  3865. }
  3866. }
  3867. //画点
  3868. if (opts.dataPointShape !== false) {
  3869. drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
  3870. }
  3871. drawActivePoint(points, eachSeries.color, eachSeries.pointShape, context, opts, areaOption,
  3872. seriesIndex);
  3873. });
  3874. if (opts.dataLabel !== false && process === 1) {
  3875. series.forEach(function(eachSeries, seriesIndex) {
  3876. let ranges, minRange, maxRange;
  3877. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3878. minRange = ranges.pop();
  3879. maxRange = ranges.shift();
  3880. var data = eachSeries.data;
  3881. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3882. process);
  3883. drawPointText(points, eachSeries, config, context, opts);
  3884. });
  3885. }
  3886. context.restore();
  3887. return {
  3888. xAxisPoints: xAxisPoints,
  3889. calPoints: calPoints,
  3890. eachSpacing: eachSpacing
  3891. };
  3892. }
  3893. function drawScatterDataPoints(series, opts, config, context) {
  3894. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  3895. var scatterOption = assign({}, {
  3896. type: 'circle'
  3897. }, opts.extra.scatter);
  3898. let xAxisData = opts.chartData.xAxisData,
  3899. xAxisPoints = xAxisData.xAxisPoints,
  3900. eachSpacing = xAxisData.eachSpacing;
  3901. var calPoints = [];
  3902. context.save();
  3903. let leftSpace = 0;
  3904. let rightSpace = opts.width + eachSpacing;
  3905. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  3906. context.translate(opts._scrollDistance_, 0);
  3907. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  3908. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  3909. }
  3910. series.forEach(function(eachSeries, seriesIndex) {
  3911. let ranges, minRange, maxRange;
  3912. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3913. minRange = ranges.pop();
  3914. maxRange = ranges.shift();
  3915. var data = eachSeries.data;
  3916. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  3917. context.beginPath();
  3918. context.setStrokeStyle(eachSeries.color);
  3919. context.setFillStyle(eachSeries.color);
  3920. context.setLineWidth(1 * opts.pix);
  3921. var shape = eachSeries.pointShape;
  3922. if (shape === 'diamond') {
  3923. points.forEach(function(item, index) {
  3924. if (item !== null) {
  3925. context.moveTo(item.x, item.y - 4.5);
  3926. context.lineTo(item.x - 4.5, item.y);
  3927. context.lineTo(item.x, item.y + 4.5);
  3928. context.lineTo(item.x + 4.5, item.y);
  3929. context.lineTo(item.x, item.y - 4.5);
  3930. }
  3931. });
  3932. } else if (shape === 'circle') {
  3933. points.forEach(function(item, index) {
  3934. if (item !== null) {
  3935. context.moveTo(item.x + 2.5 * opts.pix, item.y);
  3936. context.arc(item.x, item.y, 3 * opts.pix, 0, 2 * Math.PI, false);
  3937. }
  3938. });
  3939. } else if (shape === 'square') {
  3940. points.forEach(function(item, index) {
  3941. if (item !== null) {
  3942. context.moveTo(item.x - 3.5, item.y - 3.5);
  3943. context.rect(item.x - 3.5, item.y - 3.5, 7, 7);
  3944. }
  3945. });
  3946. } else if (shape === 'triangle') {
  3947. points.forEach(function(item, index) {
  3948. if (item !== null) {
  3949. context.moveTo(item.x, item.y - 4.5);
  3950. context.lineTo(item.x - 4.5, item.y + 4.5);
  3951. context.lineTo(item.x + 4.5, item.y + 4.5);
  3952. context.lineTo(item.x, item.y - 4.5);
  3953. }
  3954. });
  3955. } else if (shape === 'triangle') {
  3956. return;
  3957. }
  3958. context.closePath();
  3959. context.fill();
  3960. context.stroke();
  3961. });
  3962. if (opts.dataLabel !== false && process === 1) {
  3963. series.forEach(function(eachSeries, seriesIndex) {
  3964. let ranges, minRange, maxRange;
  3965. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  3966. minRange = ranges.pop();
  3967. maxRange = ranges.shift();
  3968. var data = eachSeries.data;
  3969. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  3970. process);
  3971. drawPointText(points, eachSeries, config, context, opts);
  3972. });
  3973. }
  3974. context.restore();
  3975. return {
  3976. xAxisPoints: xAxisPoints,
  3977. calPoints: calPoints,
  3978. eachSpacing: eachSpacing
  3979. };
  3980. }
  3981. function drawBubbleDataPoints(series, opts, config, context) {
  3982. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  3983. var bubbleOption = assign({}, {
  3984. opacity: 1,
  3985. border: 2
  3986. }, opts.extra.bubble);
  3987. let xAxisData = opts.chartData.xAxisData,
  3988. xAxisPoints = xAxisData.xAxisPoints,
  3989. eachSpacing = xAxisData.eachSpacing;
  3990. var calPoints = [];
  3991. context.save();
  3992. let leftSpace = 0;
  3993. let rightSpace = opts.width + eachSpacing;
  3994. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  3995. context.translate(opts._scrollDistance_, 0);
  3996. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  3997. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  3998. }
  3999. series.forEach(function(eachSeries, seriesIndex) {
  4000. let ranges, minRange, maxRange;
  4001. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  4002. minRange = ranges.pop();
  4003. maxRange = ranges.shift();
  4004. var data = eachSeries.data;
  4005. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  4006. context.beginPath();
  4007. context.setStrokeStyle(eachSeries.color);
  4008. context.setLineWidth(bubbleOption.border * opts.pix);
  4009. context.setFillStyle(hexToRgb(eachSeries.color, bubbleOption.opacity));
  4010. points.forEach(function(item, index) {
  4011. context.moveTo(item.x + item.r, item.y);
  4012. context.arc(item.x, item.y, item.r * opts.pix, 0, 2 * Math.PI, false);
  4013. });
  4014. context.closePath();
  4015. context.fill();
  4016. context.stroke();
  4017. if (opts.dataLabel !== false && process === 1) {
  4018. points.forEach(function(item, index) {
  4019. context.beginPath();
  4020. var fontSize = eachSeries.textSize * opts.pix || config.fontSize;
  4021. context.setFontSize(fontSize);
  4022. context.setFillStyle(eachSeries.textColor || "#FFFFFF");
  4023. context.setTextAlign('center');
  4024. context.fillText(String(item.t), item.x, item.y + fontSize / 2);
  4025. context.closePath();
  4026. context.stroke();
  4027. context.setTextAlign('left');
  4028. });
  4029. }
  4030. });
  4031. context.restore();
  4032. return {
  4033. xAxisPoints: xAxisPoints,
  4034. calPoints: calPoints,
  4035. eachSpacing: eachSpacing
  4036. };
  4037. }
  4038. function drawLineDataPoints(series, opts, config, context) {
  4039. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  4040. var lineOption = assign({}, {
  4041. type: 'straight',
  4042. width: 2,
  4043. activeType: 'none',
  4044. linearType: 'none',
  4045. onShadow: false,
  4046. animation: 'vertical',
  4047. }, opts.extra.line);
  4048. lineOption.width *= opts.pix;
  4049. let xAxisData = opts.chartData.xAxisData,
  4050. xAxisPoints = xAxisData.xAxisPoints,
  4051. eachSpacing = xAxisData.eachSpacing;
  4052. var calPoints = [];
  4053. context.save();
  4054. let leftSpace = 0;
  4055. let rightSpace = opts.width + eachSpacing;
  4056. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  4057. context.translate(opts._scrollDistance_, 0);
  4058. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  4059. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  4060. }
  4061. series.forEach(function(eachSeries, seriesIndex) {
  4062. // 这段很神奇的代码用于解决ios16的setStrokeStyle失效的bug
  4063. context.beginPath();
  4064. context.setStrokeStyle(eachSeries.color);
  4065. context.moveTo(-10000, -10000);
  4066. context.lineTo(-10001, -10001);
  4067. context.stroke();
  4068. let ranges, minRange, maxRange;
  4069. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  4070. minRange = ranges.pop();
  4071. maxRange = ranges.shift();
  4072. var data = eachSeries.data;
  4073. var points = getLineDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  4074. lineOption, process);
  4075. calPoints.push(points);
  4076. var splitPointList = splitPoints(points, eachSeries);
  4077. if (eachSeries.lineType == 'dash') {
  4078. let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
  4079. dashLength *= opts.pix;
  4080. context.setLineDash([dashLength, dashLength]);
  4081. }
  4082. context.beginPath();
  4083. var strokeColor = eachSeries.color;
  4084. if (lineOption.linearType !== 'none' && eachSeries.linearColor && eachSeries.linearColor.length > 0) {
  4085. var grd = context.createLinearGradient(opts.chartData.xAxisData.startX, opts.height / 2, opts
  4086. .chartData.xAxisData.endX, opts.height / 2);
  4087. for (var i = 0; i < eachSeries.linearColor.length; i++) {
  4088. grd.addColorStop(eachSeries.linearColor[i][0], hexToRgb(eachSeries.linearColor[i][1], 1));
  4089. }
  4090. strokeColor = grd
  4091. }
  4092. context.setStrokeStyle(strokeColor);
  4093. if (lineOption.onShadow == true && eachSeries.setShadow && eachSeries.setShadow.length > 0) {
  4094. context.setShadow(eachSeries.setShadow[0], eachSeries.setShadow[1], eachSeries.setShadow[2],
  4095. eachSeries.setShadow[3]);
  4096. } else {
  4097. context.setShadow(0, 0, 0, 'rgba(0,0,0,0)');
  4098. }
  4099. context.setLineWidth(lineOption.width);
  4100. splitPointList.forEach(function(points, index) {
  4101. if (points.length === 1) {
  4102. context.moveTo(points[0].x, points[0].y);
  4103. // context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  4104. } else {
  4105. context.moveTo(points[0].x, points[0].y);
  4106. let startPoint = 0;
  4107. if (lineOption.type === 'curve') {
  4108. for (let j = 0; j < points.length; j++) {
  4109. let item = points[j];
  4110. if (startPoint == 0 && item.x > leftSpace) {
  4111. context.moveTo(item.x, item.y);
  4112. startPoint = 1;
  4113. }
  4114. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4115. var ctrlPoint = createCurveControlPoints(points, j - 1);
  4116. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x,
  4117. ctrlPoint.ctrB.y, item.x, item.y);
  4118. }
  4119. };
  4120. }
  4121. if (lineOption.type === 'straight') {
  4122. for (let j = 0; j < points.length; j++) {
  4123. let item = points[j];
  4124. if (startPoint == 0 && item.x > leftSpace) {
  4125. context.moveTo(item.x, item.y);
  4126. startPoint = 1;
  4127. }
  4128. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4129. context.lineTo(item.x, item.y);
  4130. }
  4131. };
  4132. }
  4133. if (lineOption.type === 'step') {
  4134. for (let j = 0; j < points.length; j++) {
  4135. let item = points[j];
  4136. if (startPoint == 0 && item.x > leftSpace) {
  4137. context.moveTo(item.x, item.y);
  4138. startPoint = 1;
  4139. }
  4140. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4141. context.lineTo(item.x, points[j - 1].y);
  4142. context.lineTo(item.x, item.y);
  4143. }
  4144. };
  4145. }
  4146. context.moveTo(points[0].x, points[0].y);
  4147. }
  4148. });
  4149. context.stroke();
  4150. context.setLineDash([]);
  4151. if (opts.dataPointShape !== false) {
  4152. drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
  4153. }
  4154. drawActivePoint(points, eachSeries.color, eachSeries.pointShape, context, opts, lineOption);
  4155. });
  4156. if (opts.dataLabel !== false && process === 1) {
  4157. series.forEach(function(eachSeries, seriesIndex) {
  4158. let ranges, minRange, maxRange;
  4159. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  4160. minRange = ranges.pop();
  4161. maxRange = ranges.shift();
  4162. var data = eachSeries.data;
  4163. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  4164. process);
  4165. drawPointText(points, eachSeries, config, context, opts);
  4166. });
  4167. }
  4168. context.restore();
  4169. return {
  4170. xAxisPoints: xAxisPoints,
  4171. calPoints: calPoints,
  4172. eachSpacing: eachSpacing
  4173. };
  4174. }
  4175. function drawMixDataPoints(series, opts, config, context) {
  4176. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  4177. let xAxisData = opts.chartData.xAxisData,
  4178. xAxisPoints = xAxisData.xAxisPoints,
  4179. eachSpacing = xAxisData.eachSpacing;
  4180. let columnOption = assign({}, {
  4181. width: eachSpacing / 2,
  4182. barBorderCircle: false,
  4183. barBorderRadius: [],
  4184. seriesGap: 2,
  4185. linearType: 'none',
  4186. linearOpacity: 1,
  4187. customColor: [],
  4188. colorStop: 0,
  4189. }, opts.extra.mix.column);
  4190. let areaOption = assign({}, {
  4191. opacity: 0.2,
  4192. gradient: false
  4193. }, opts.extra.mix.area);
  4194. let lineOption = assign({}, {
  4195. width: 2
  4196. }, opts.extra.mix.line);
  4197. let endY = opts.height - opts.area[2];
  4198. let calPoints = [];
  4199. var columnIndex = 0;
  4200. var columnLength = 0;
  4201. series.forEach(function(eachSeries, seriesIndex) {
  4202. if (eachSeries.type == 'column') {
  4203. columnLength += 1;
  4204. }
  4205. });
  4206. context.save();
  4207. let leftNum = -2;
  4208. let rightNum = xAxisPoints.length + 2;
  4209. let leftSpace = 0;
  4210. let rightSpace = opts.width + eachSpacing;
  4211. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  4212. context.translate(opts._scrollDistance_, 0);
  4213. leftNum = Math.floor(-opts._scrollDistance_ / eachSpacing) - 2;
  4214. rightNum = leftNum + opts.xAxis.itemCount + 4;
  4215. leftSpace = -opts._scrollDistance_ - eachSpacing * 2 + opts.area[3];
  4216. rightSpace = leftSpace + (opts.xAxis.itemCount + 4) * eachSpacing;
  4217. }
  4218. columnOption.customColor = fillCustomColor(columnOption.linearType, columnOption.customColor, series, config);
  4219. series.forEach(function(eachSeries, seriesIndex) {
  4220. let ranges, minRange, maxRange;
  4221. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  4222. minRange = ranges.pop();
  4223. maxRange = ranges.shift();
  4224. var data = eachSeries.data;
  4225. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config, process);
  4226. calPoints.push(points);
  4227. // 绘制柱状数据图
  4228. if (eachSeries.type == 'column') {
  4229. points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
  4230. for (let i = 0; i < points.length; i++) {
  4231. let item = points[i];
  4232. if (item !== null && i > leftNum && i < rightNum) {
  4233. var startX = item.x - item.width / 2;
  4234. var height = opts.height - item.y - opts.area[2];
  4235. context.beginPath();
  4236. var fillColor = item.color || eachSeries.color
  4237. var strokeColor = item.color || eachSeries.color
  4238. if (columnOption.linearType !== 'none') {
  4239. var grd = context.createLinearGradient(startX, item.y, startX, opts.height - opts.area[
  4240. 2]);
  4241. //透明渐变
  4242. if (columnOption.linearType == 'opacity') {
  4243. grd.addColorStop(0, hexToRgb(fillColor, columnOption.linearOpacity));
  4244. grd.addColorStop(1, hexToRgb(fillColor, 1));
  4245. } else {
  4246. grd.addColorStop(0, hexToRgb(columnOption.customColor[eachSeries.linearIndex],
  4247. columnOption.linearOpacity));
  4248. grd.addColorStop(columnOption.colorStop, hexToRgb(columnOption.customColor[
  4249. eachSeries.linearIndex], columnOption.linearOpacity));
  4250. grd.addColorStop(1, hexToRgb(fillColor, 1));
  4251. }
  4252. fillColor = grd
  4253. }
  4254. // 圆角边框
  4255. if ((columnOption.barBorderRadius && columnOption.barBorderRadius.length === 4) ||
  4256. columnOption.barBorderCircle) {
  4257. const left = startX;
  4258. const top = item.y;
  4259. const width = item.width;
  4260. const height = opts.height - opts.area[2] - item.y;
  4261. if (columnOption.barBorderCircle) {
  4262. columnOption.barBorderRadius = [width / 2, width / 2, 0, 0];
  4263. }
  4264. let [r0, r1, r2, r3] = columnOption.barBorderRadius;
  4265. let minRadius = Math.min(width / 2, height / 2);
  4266. r0 = r0 > minRadius ? minRadius : r0;
  4267. r1 = r1 > minRadius ? minRadius : r1;
  4268. r2 = r2 > minRadius ? minRadius : r2;
  4269. r3 = r3 > minRadius ? minRadius : r3;
  4270. r0 = r0 < 0 ? 0 : r0;
  4271. r1 = r1 < 0 ? 0 : r1;
  4272. r2 = r2 < 0 ? 0 : r2;
  4273. r3 = r3 < 0 ? 0 : r3;
  4274. context.arc(left + r0, top + r0, r0, -Math.PI, -Math.PI / 2);
  4275. context.arc(left + width - r1, top + r1, r1, -Math.PI / 2, 0);
  4276. context.arc(left + width - r2, top + height - r2, r2, 0, Math.PI / 2);
  4277. context.arc(left + r3, top + height - r3, r3, Math.PI / 2, Math.PI);
  4278. } else {
  4279. context.moveTo(startX, item.y);
  4280. context.lineTo(startX + item.width, item.y);
  4281. context.lineTo(startX + item.width, opts.height - opts.area[2]);
  4282. context.lineTo(startX, opts.height - opts.area[2]);
  4283. context.lineTo(startX, item.y);
  4284. context.setLineWidth(1)
  4285. context.setStrokeStyle(strokeColor);
  4286. }
  4287. context.setFillStyle(fillColor);
  4288. context.closePath();
  4289. context.fill();
  4290. }
  4291. }
  4292. columnIndex += 1;
  4293. }
  4294. //绘制区域图数据
  4295. if (eachSeries.type == 'area') {
  4296. let splitPointList = splitPoints(points, eachSeries);
  4297. for (let i = 0; i < splitPointList.length; i++) {
  4298. let points = splitPointList[i];
  4299. // 绘制区域数据
  4300. context.beginPath();
  4301. context.setStrokeStyle(eachSeries.color);
  4302. context.setStrokeStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  4303. if (areaOption.gradient) {
  4304. let gradient = context.createLinearGradient(0, opts.area[0], 0, opts.height - opts.area[2]);
  4305. gradient.addColorStop('0', hexToRgb(eachSeries.color, areaOption.opacity));
  4306. gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
  4307. context.setFillStyle(gradient);
  4308. } else {
  4309. context.setFillStyle(hexToRgb(eachSeries.color, areaOption.opacity));
  4310. }
  4311. context.setLineWidth(2 * opts.pix);
  4312. if (points.length > 1) {
  4313. var firstPoint = points[0];
  4314. let lastPoint = points[points.length - 1];
  4315. context.moveTo(firstPoint.x, firstPoint.y);
  4316. let startPoint = 0;
  4317. if (eachSeries.style === 'curve') {
  4318. for (let j = 0; j < points.length; j++) {
  4319. let item = points[j];
  4320. if (startPoint == 0 && item.x > leftSpace) {
  4321. context.moveTo(item.x, item.y);
  4322. startPoint = 1;
  4323. }
  4324. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4325. var ctrlPoint = createCurveControlPoints(points, j - 1);
  4326. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB.x,
  4327. ctrlPoint.ctrB.y, item.x, item.y);
  4328. }
  4329. };
  4330. } else {
  4331. for (let j = 0; j < points.length; j++) {
  4332. let item = points[j];
  4333. if (startPoint == 0 && item.x > leftSpace) {
  4334. context.moveTo(item.x, item.y);
  4335. startPoint = 1;
  4336. }
  4337. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4338. context.lineTo(item.x, item.y);
  4339. }
  4340. };
  4341. }
  4342. context.lineTo(lastPoint.x, endY);
  4343. context.lineTo(firstPoint.x, endY);
  4344. context.lineTo(firstPoint.x, firstPoint.y);
  4345. } else {
  4346. let item = points[0];
  4347. context.moveTo(item.x - eachSpacing / 2, item.y);
  4348. // context.lineTo(item.x + eachSpacing / 2, item.y);
  4349. // context.lineTo(item.x + eachSpacing / 2, endY);
  4350. // context.lineTo(item.x - eachSpacing / 2, endY);
  4351. // context.moveTo(item.x - eachSpacing / 2, item.y);
  4352. }
  4353. context.closePath();
  4354. context.fill();
  4355. }
  4356. }
  4357. // 绘制折线数据图
  4358. if (eachSeries.type == 'line') {
  4359. var splitPointList = splitPoints(points, eachSeries);
  4360. splitPointList.forEach(function(points, index) {
  4361. if (eachSeries.lineType == 'dash') {
  4362. let dashLength = eachSeries.dashLength ? eachSeries.dashLength : 8;
  4363. dashLength *= opts.pix;
  4364. context.setLineDash([dashLength, dashLength]);
  4365. }
  4366. context.beginPath();
  4367. context.setStrokeStyle(eachSeries.color);
  4368. context.setLineWidth(lineOption.width * opts.pix);
  4369. if (points.length === 1) {
  4370. context.moveTo(points[0].x, points[0].y);
  4371. // context.arc(points[0].x, points[0].y, 1, 0, 2 * Math.PI);
  4372. } else {
  4373. context.moveTo(points[0].x, points[0].y);
  4374. let startPoint = 0;
  4375. if (eachSeries.style == 'curve') {
  4376. for (let j = 0; j < points.length; j++) {
  4377. let item = points[j];
  4378. if (startPoint == 0 && item.x > leftSpace) {
  4379. context.moveTo(item.x, item.y);
  4380. startPoint = 1;
  4381. }
  4382. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4383. var ctrlPoint = createCurveControlPoints(points, j - 1);
  4384. context.bezierCurveTo(ctrlPoint.ctrA.x, ctrlPoint.ctrA.y, ctrlPoint.ctrB
  4385. .x, ctrlPoint.ctrB.y,
  4386. item.x, item.y);
  4387. }
  4388. }
  4389. } else {
  4390. for (let j = 0; j < points.length; j++) {
  4391. let item = points[j];
  4392. if (startPoint == 0 && item.x > leftSpace) {
  4393. context.moveTo(item.x, item.y);
  4394. startPoint = 1;
  4395. }
  4396. if (j > 0 && item.x > leftSpace && item.x < rightSpace) {
  4397. context.lineTo(item.x, item.y);
  4398. }
  4399. }
  4400. }
  4401. context.moveTo(points[0].x, points[0].y);
  4402. }
  4403. context.stroke();
  4404. context.setLineDash([]);
  4405. });
  4406. }
  4407. // 绘制点数据图
  4408. if (eachSeries.type == 'point') {
  4409. eachSeries.addPoint = true;
  4410. }
  4411. if (eachSeries.addPoint == true && eachSeries.type !== 'column') {
  4412. drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
  4413. }
  4414. });
  4415. if (opts.dataLabel !== false && process === 1) {
  4416. var columnIndex = 0;
  4417. series.forEach(function(eachSeries, seriesIndex) {
  4418. let ranges, minRange, maxRange;
  4419. ranges = [].concat(opts.chartData.yAxisData.ranges[eachSeries.index]);
  4420. minRange = ranges.pop();
  4421. maxRange = ranges.shift();
  4422. var data = eachSeries.data;
  4423. var points = getDataPoints(data, minRange, maxRange, xAxisPoints, eachSpacing, opts, config,
  4424. process);
  4425. if (eachSeries.type !== 'column') {
  4426. drawPointText(points, eachSeries, config, context, opts);
  4427. } else {
  4428. points = fixColumeData(points, eachSpacing, columnLength, columnIndex, config, opts);
  4429. drawPointText(points, eachSeries, config, context, opts);
  4430. columnIndex += 1;
  4431. }
  4432. });
  4433. }
  4434. context.restore();
  4435. return {
  4436. xAxisPoints: xAxisPoints,
  4437. calPoints: calPoints,
  4438. eachSpacing: eachSpacing,
  4439. }
  4440. }
  4441. function drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints) {
  4442. var toolTipOption = opts.extra.tooltip || {};
  4443. if (toolTipOption.horizentalLine && opts.tooltip && process === 1 && (opts.type == 'line' || opts.type == 'area' ||
  4444. opts.type == 'column' || opts.type == 'mount' || opts.type == 'candle' || opts.type == 'mix')) {
  4445. drawToolTipHorizentalLine(opts, config, context, eachSpacing, xAxisPoints)
  4446. }
  4447. context.save();
  4448. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0 && opts.enableScroll === true) {
  4449. context.translate(opts._scrollDistance_, 0);
  4450. }
  4451. if (opts.tooltip && opts.tooltip.textList && opts.tooltip.textList.length && process === 1) {
  4452. drawToolTip(opts.tooltip.textList, opts.tooltip.offset, opts, config, context, eachSpacing, xAxisPoints);
  4453. }
  4454. context.restore();
  4455. }
  4456. function drawXAxis(categories, opts, config, context) {
  4457. let xAxisData = opts.chartData.xAxisData,
  4458. xAxisPoints = xAxisData.xAxisPoints,
  4459. startX = xAxisData.startX,
  4460. endX = xAxisData.endX,
  4461. eachSpacing = xAxisData.eachSpacing;
  4462. var boundaryGap = 'center';
  4463. if (opts.type == 'bar' || opts.type == 'line' || opts.type == 'area' || opts.type == 'scatter' || opts.type ==
  4464. 'bubble') {
  4465. boundaryGap = opts.xAxis.boundaryGap;
  4466. }
  4467. var startY = opts.height - opts.area[2];
  4468. var endY = opts.area[0];
  4469. //绘制滚动条
  4470. if (opts.enableScroll && opts.xAxis.scrollShow) {
  4471. var scrollY = opts.height - opts.area[2] + config.xAxisHeight;
  4472. var scrollScreenWidth = endX - startX;
  4473. var scrollTotalWidth = eachSpacing * (xAxisPoints.length - 1);
  4474. if (opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount
  4475. .widthRatio > 1) {
  4476. if (opts.extra.mount.widthRatio > 2) opts.extra.mount.widthRatio = 2
  4477. scrollTotalWidth += (opts.extra.mount.widthRatio - 1) * eachSpacing;
  4478. }
  4479. var scrollWidth = scrollScreenWidth * scrollScreenWidth / scrollTotalWidth;
  4480. var scrollLeft = 0;
  4481. if (opts._scrollDistance_) {
  4482. scrollLeft = -opts._scrollDistance_ * (scrollScreenWidth) / scrollTotalWidth;
  4483. }
  4484. context.beginPath();
  4485. context.setLineCap('round');
  4486. context.setLineWidth(6 * opts.pix);
  4487. context.setStrokeStyle(opts.xAxis.scrollBackgroundColor || "#EFEBEF");
  4488. context.moveTo(startX, scrollY);
  4489. context.lineTo(endX, scrollY);
  4490. context.stroke();
  4491. context.closePath();
  4492. context.beginPath();
  4493. context.setLineCap('round');
  4494. context.setLineWidth(6 * opts.pix);
  4495. context.setStrokeStyle(opts.xAxis.scrollColor || "#A6A6A6");
  4496. context.moveTo(startX + scrollLeft, scrollY);
  4497. context.lineTo(startX + scrollLeft + scrollWidth, scrollY);
  4498. context.stroke();
  4499. context.closePath();
  4500. context.setLineCap('butt');
  4501. }
  4502. context.save();
  4503. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
  4504. context.translate(opts._scrollDistance_, 0);
  4505. }
  4506. //绘制X轴刻度线
  4507. if (opts.xAxis.calibration === true) {
  4508. context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
  4509. context.setLineCap('butt');
  4510. context.setLineWidth(1 * opts.pix);
  4511. xAxisPoints.forEach(function(item, index) {
  4512. if (index > 0) {
  4513. context.beginPath();
  4514. context.moveTo(item - eachSpacing / 2, startY);
  4515. context.lineTo(item - eachSpacing / 2, startY + 3 * opts.pix);
  4516. context.closePath();
  4517. context.stroke();
  4518. }
  4519. });
  4520. }
  4521. //绘制X轴网格
  4522. if (opts.xAxis.disableGrid !== true) {
  4523. context.setStrokeStyle(opts.xAxis.gridColor || "#cccccc");
  4524. context.setLineCap('butt');
  4525. context.setLineWidth(1 * opts.pix);
  4526. if (opts.xAxis.gridType == 'dash') {
  4527. context.setLineDash([opts.xAxis.dashLength * opts.pix, opts.xAxis.dashLength * opts.pix]);
  4528. }
  4529. opts.xAxis.gridEval = opts.xAxis.gridEval || 1;
  4530. xAxisPoints.forEach(function(item, index) {
  4531. if (index % opts.xAxis.gridEval == 0) {
  4532. context.beginPath();
  4533. context.moveTo(item, startY);
  4534. context.lineTo(item, endY);
  4535. context.stroke();
  4536. }
  4537. });
  4538. context.setLineDash([]);
  4539. }
  4540. //绘制X轴文案
  4541. if (opts.xAxis.disabled !== true) {
  4542. // 对X轴列表做抽稀处理
  4543. //默认全部显示X轴标签
  4544. let maxXAxisListLength = categories.length;
  4545. //如果设置了X轴单屏数量
  4546. if (opts.xAxis.labelCount) {
  4547. //如果设置X轴密度
  4548. if (opts.xAxis.itemCount) {
  4549. maxXAxisListLength = Math.ceil(categories.length / opts.xAxis.itemCount * opts.xAxis.labelCount);
  4550. } else {
  4551. maxXAxisListLength = opts.xAxis.labelCount;
  4552. }
  4553. maxXAxisListLength -= 1;
  4554. }
  4555. let ratio = Math.ceil(categories.length / maxXAxisListLength);
  4556. let newCategories = [];
  4557. let cgLength = categories.length;
  4558. for (let i = 0; i < cgLength; i++) {
  4559. if (i % ratio !== 0) {
  4560. newCategories.push("");
  4561. } else {
  4562. newCategories.push(categories[i]);
  4563. }
  4564. }
  4565. newCategories[cgLength - 1] = categories[cgLength - 1];
  4566. var xAxisFontSize = opts.xAxis.fontSize * opts.pix || config.fontSize;
  4567. if (config._xAxisTextAngle_ === 0) {
  4568. newCategories.forEach(function(item, index) {
  4569. var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item, index, opts) : item;
  4570. var offset = -measureText(String(xitem), xAxisFontSize, context) / 2;
  4571. if (boundaryGap == 'center') {
  4572. offset += eachSpacing / 2;
  4573. }
  4574. var scrollHeight = 0;
  4575. if (opts.xAxis.scrollShow) {
  4576. scrollHeight = 6 * opts.pix;
  4577. }
  4578. // 如果在主视图区域内
  4579. var _scrollDistance_ = opts._scrollDistance_ || 0;
  4580. var truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[
  4581. index];
  4582. if ((truePoints - Math.abs(_scrollDistance_)) >= (opts.area[3] - 1) && (truePoints - Math.abs(
  4583. _scrollDistance_)) <= (opts.width - opts.area[1] + 1)) {
  4584. context.beginPath();
  4585. context.setFontSize(xAxisFontSize);
  4586. context.setFillStyle(opts.xAxis.fontColor || opts.fontColor);
  4587. context.fillText(String(xitem), xAxisPoints[index] + offset, startY + opts.xAxis.marginTop *
  4588. opts.pix + (opts.xAxis.lineHeight - opts.xAxis.fontSize) * opts.pix / 2 + opts.xAxis
  4589. .fontSize * opts.pix);
  4590. context.closePath();
  4591. context.stroke();
  4592. }
  4593. });
  4594. } else {
  4595. newCategories.forEach(function(item, index) {
  4596. var xitem = opts.xAxis.formatter ? opts.xAxis.formatter(item) : item;
  4597. // 如果在主视图区域内
  4598. var _scrollDistance_ = opts._scrollDistance_ || 0;
  4599. var truePoints = boundaryGap == 'center' ? xAxisPoints[index] + eachSpacing / 2 : xAxisPoints[
  4600. index];
  4601. if ((truePoints - Math.abs(_scrollDistance_)) >= (opts.area[3] - 1) && (truePoints - Math.abs(
  4602. _scrollDistance_)) <= (opts.width - opts.area[1] + 1)) {
  4603. context.save();
  4604. context.beginPath();
  4605. context.setFontSize(xAxisFontSize);
  4606. context.setFillStyle(opts.xAxis.fontColor || opts.fontColor);
  4607. var textWidth = measureText(String(xitem), xAxisFontSize, context);
  4608. var offsetX = xAxisPoints[index];
  4609. if (boundaryGap == 'center') {
  4610. offsetX = xAxisPoints[index] + eachSpacing / 2;
  4611. }
  4612. var scrollHeight = 0;
  4613. if (opts.xAxis.scrollShow) {
  4614. scrollHeight = 6 * opts.pix;
  4615. }
  4616. var offsetY = startY + opts.xAxis.marginTop * opts.pix + xAxisFontSize - xAxisFontSize *
  4617. Math.abs(Math.sin(config._xAxisTextAngle_));
  4618. if (opts.xAxis.rotateAngle < 0) {
  4619. offsetX -= xAxisFontSize / 2;
  4620. textWidth = 0;
  4621. } else {
  4622. offsetX += xAxisFontSize / 2;
  4623. textWidth = -textWidth;
  4624. }
  4625. context.translate(offsetX, offsetY);
  4626. context.rotate(-1 * config._xAxisTextAngle_);
  4627. context.fillText(String(xitem), textWidth, 0);
  4628. context.closePath();
  4629. context.stroke();
  4630. context.restore();
  4631. }
  4632. });
  4633. }
  4634. }
  4635. context.restore();
  4636. //画X轴标题
  4637. if (opts.xAxis.title) {
  4638. context.beginPath();
  4639. context.setFontSize(opts.xAxis.titleFontSize * opts.pix);
  4640. context.setFillStyle(opts.xAxis.titleFontColor);
  4641. context.fillText(String(opts.xAxis.title), opts.width - opts.area[1] + opts.xAxis.titleOffsetX * opts.pix, opts
  4642. .height - opts.area[2] + opts.xAxis.marginTop * opts.pix + (opts.xAxis.lineHeight - opts.xAxis
  4643. .titleFontSize) * opts.pix / 2 + (opts.xAxis.titleFontSize + opts.xAxis.titleOffsetY) * opts.pix);
  4644. context.closePath();
  4645. context.stroke();
  4646. }
  4647. //绘制X轴轴线
  4648. if (opts.xAxis.axisLine) {
  4649. context.beginPath();
  4650. context.setStrokeStyle(opts.xAxis.axisLineColor);
  4651. context.setLineWidth(1 * opts.pix);
  4652. context.moveTo(startX, opts.height - opts.area[2]);
  4653. context.lineTo(endX, opts.height - opts.area[2]);
  4654. context.stroke();
  4655. }
  4656. }
  4657. function drawYAxisGrid(categories, opts, config, context) {
  4658. if (opts.yAxis.disableGrid === true) {
  4659. return;
  4660. }
  4661. let spacingValid = opts.height - opts.area[0] - opts.area[2];
  4662. let eachSpacing = spacingValid / opts.yAxis.splitNumber;
  4663. let startX = opts.area[3];
  4664. let xAxisPoints = opts.chartData.xAxisData.xAxisPoints,
  4665. xAxiseachSpacing = opts.chartData.xAxisData.eachSpacing;
  4666. let TotalWidth = xAxiseachSpacing * (xAxisPoints.length - 1);
  4667. if (opts.type == 'mount' && opts.extra && opts.extra.mount && opts.extra.mount.widthRatio && opts.extra.mount
  4668. .widthRatio > 1) {
  4669. if (opts.extra.mount.widthRatio > 2) opts.extra.mount.widthRatio = 2
  4670. TotalWidth += (opts.extra.mount.widthRatio - 1) * xAxiseachSpacing;
  4671. }
  4672. let endX = startX + TotalWidth;
  4673. let points = [];
  4674. let startY = 1
  4675. if (opts.xAxis.axisLine === false) {
  4676. startY = 0
  4677. }
  4678. for (let i = startY; i < opts.yAxis.splitNumber + 1; i++) {
  4679. points.push(opts.height - opts.area[2] - eachSpacing * i);
  4680. }
  4681. context.save();
  4682. if (opts._scrollDistance_ && opts._scrollDistance_ !== 0) {
  4683. context.translate(opts._scrollDistance_, 0);
  4684. }
  4685. if (opts.yAxis.gridType == 'dash') {
  4686. context.setLineDash([opts.yAxis.dashLength * opts.pix, opts.yAxis.dashLength * opts.pix]);
  4687. }
  4688. context.setStrokeStyle(opts.yAxis.gridColor);
  4689. context.setLineWidth(1 * opts.pix);
  4690. points.forEach(function(item, index) {
  4691. context.beginPath();
  4692. context.moveTo(startX, item);
  4693. context.lineTo(endX, item);
  4694. context.stroke();
  4695. });
  4696. context.setLineDash([]);
  4697. context.restore();
  4698. }
  4699. function drawYAxis(series, opts, config, context) {
  4700. if (opts.yAxis.disabled === true) {
  4701. return;
  4702. }
  4703. var spacingValid = opts.height - opts.area[0] - opts.area[2];
  4704. var eachSpacing = spacingValid / opts.yAxis.splitNumber;
  4705. var startX = opts.area[3];
  4706. var endX = opts.width - opts.area[1];
  4707. var endY = opts.height - opts.area[2];
  4708. // set YAxis background
  4709. context.beginPath();
  4710. context.setFillStyle(opts.background);
  4711. if (opts.enableScroll == true && opts.xAxis.scrollPosition && opts.xAxis.scrollPosition !== 'left') {
  4712. context.fillRect(0, 0, startX, endY + 2 * opts.pix);
  4713. }
  4714. if (opts.enableScroll == true && opts.xAxis.scrollPosition && opts.xAxis.scrollPosition !== 'right') {
  4715. context.fillRect(endX, 0, opts.width, endY + 2 * opts.pix);
  4716. }
  4717. context.closePath();
  4718. context.stroke();
  4719. let tStartLeft = opts.area[3];
  4720. let tStartRight = opts.width - opts.area[1];
  4721. let tStartCenter = opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2;
  4722. if (opts.yAxis.data) {
  4723. for (let i = 0; i < opts.yAxis.data.length; i++) {
  4724. let yData = opts.yAxis.data[i];
  4725. var points = [];
  4726. if (yData.type === 'categories') {
  4727. for (let i = 0; i <= yData.categories.length; i++) {
  4728. points.push(opts.area[0] + spacingValid / yData.categories.length / 2 + spacingValid / yData
  4729. .categories.length * i);
  4730. }
  4731. } else {
  4732. for (let i = 0; i <= opts.yAxis.splitNumber; i++) {
  4733. points.push(opts.area[0] + eachSpacing * i);
  4734. }
  4735. }
  4736. if (yData.disabled !== true) {
  4737. let rangesFormat = opts.chartData.yAxisData.rangesFormat[i];
  4738. let yAxisFontSize = yData.fontSize ? yData.fontSize * opts.pix : config.fontSize;
  4739. let yAxisWidth = opts.chartData.yAxisData.yAxisWidth[i];
  4740. let textAlign = yData.textAlign || "right";
  4741. //画Y轴刻度及文案
  4742. rangesFormat.forEach(function(item, index) {
  4743. var pos = points[index];
  4744. context.beginPath();
  4745. context.setFontSize(yAxisFontSize);
  4746. context.setLineWidth(1 * opts.pix);
  4747. context.setStrokeStyle(yData.axisLineColor || '#cccccc');
  4748. context.setFillStyle(yData.fontColor || opts.fontColor);
  4749. let tmpstrat = 0;
  4750. let gapwidth = 4 * opts.pix;
  4751. if (yAxisWidth.position == 'left') {
  4752. //画刻度线
  4753. if (yData.calibration == true) {
  4754. context.moveTo(tStartLeft, pos);
  4755. context.lineTo(tStartLeft - 3 * opts.pix, pos);
  4756. gapwidth += 3 * opts.pix;
  4757. }
  4758. //画文字
  4759. switch (textAlign) {
  4760. case "left":
  4761. context.setTextAlign('left');
  4762. tmpstrat = tStartLeft - yAxisWidth.width
  4763. break;
  4764. case "right":
  4765. context.setTextAlign('right');
  4766. tmpstrat = tStartLeft - gapwidth
  4767. break;
  4768. default:
  4769. context.setTextAlign('center');
  4770. tmpstrat = tStartLeft - yAxisWidth.width / 2
  4771. }
  4772. context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
  4773. } else if (yAxisWidth.position == 'right') {
  4774. //画刻度线
  4775. if (yData.calibration == true) {
  4776. context.moveTo(tStartRight, pos);
  4777. context.lineTo(tStartRight + 3 * opts.pix, pos);
  4778. gapwidth += 3 * opts.pix;
  4779. }
  4780. switch (textAlign) {
  4781. case "left":
  4782. context.setTextAlign('left');
  4783. tmpstrat = tStartRight + gapwidth
  4784. break;
  4785. case "right":
  4786. context.setTextAlign('right');
  4787. tmpstrat = tStartRight + yAxisWidth.width
  4788. break;
  4789. default:
  4790. context.setTextAlign('center');
  4791. tmpstrat = tStartRight + yAxisWidth.width / 2
  4792. }
  4793. context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
  4794. } else if (yAxisWidth.position == 'center') {
  4795. //画刻度线
  4796. if (yData.calibration == true) {
  4797. context.moveTo(tStartCenter, pos);
  4798. context.lineTo(tStartCenter - 3 * opts.pix, pos);
  4799. gapwidth += 3 * opts.pix;
  4800. }
  4801. //画文字
  4802. switch (textAlign) {
  4803. case "left":
  4804. context.setTextAlign('left');
  4805. tmpstrat = tStartCenter - yAxisWidth.width
  4806. break;
  4807. case "right":
  4808. context.setTextAlign('right');
  4809. tmpstrat = tStartCenter - gapwidth
  4810. break;
  4811. default:
  4812. context.setTextAlign('center');
  4813. tmpstrat = tStartCenter - yAxisWidth.width / 2
  4814. }
  4815. context.fillText(String(item), tmpstrat, pos + yAxisFontSize / 2 - 3 * opts.pix);
  4816. }
  4817. context.closePath();
  4818. context.stroke();
  4819. context.setTextAlign('left');
  4820. });
  4821. //画Y轴轴线
  4822. if (yData.axisLine !== false) {
  4823. context.beginPath();
  4824. context.setStrokeStyle(yData.axisLineColor || '#cccccc');
  4825. context.setLineWidth(1 * opts.pix);
  4826. if (yAxisWidth.position == 'left') {
  4827. context.moveTo(tStartLeft, opts.height - opts.area[2]);
  4828. context.lineTo(tStartLeft, opts.area[0]);
  4829. } else if (yAxisWidth.position == 'right') {
  4830. context.moveTo(tStartRight, opts.height - opts.area[2]);
  4831. context.lineTo(tStartRight, opts.area[0]);
  4832. } else if (yAxisWidth.position == 'center') {
  4833. context.moveTo(tStartCenter, opts.height - opts.area[2]);
  4834. context.lineTo(tStartCenter, opts.area[0]);
  4835. }
  4836. context.stroke();
  4837. }
  4838. //画Y轴标题
  4839. if (opts.yAxis.showTitle) {
  4840. let titleFontSize = yData.titleFontSize * opts.pix || config.fontSize;
  4841. let title = yData.title;
  4842. context.beginPath();
  4843. context.setFontSize(titleFontSize);
  4844. context.setFillStyle(yData.titleFontColor || opts.fontColor);
  4845. if (yAxisWidth.position == 'left') {
  4846. context.fillText(title, tStartLeft - measureText(title, titleFontSize, context) / 2 + (yData
  4847. .titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
  4848. } else if (yAxisWidth.position == 'right') {
  4849. context.fillText(title, tStartRight - measureText(title, titleFontSize, context) / 2 + (yData
  4850. .titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
  4851. } else if (yAxisWidth.position == 'center') {
  4852. context.fillText(title, tStartCenter - measureText(title, titleFontSize, context) / 2 + (yData
  4853. .titleOffsetX || 0), opts.area[0] - (10 - (yData.titleOffsetY || 0)) * opts.pix);
  4854. }
  4855. context.closePath();
  4856. context.stroke();
  4857. }
  4858. if (yAxisWidth.position == 'left') {
  4859. tStartLeft -= (yAxisWidth.width + opts.yAxis.padding * opts.pix);
  4860. } else {
  4861. tStartRight += yAxisWidth.width + opts.yAxis.padding * opts.pix;
  4862. }
  4863. }
  4864. }
  4865. }
  4866. }
  4867. function drawLegend(series, opts, config, context, chartData) {
  4868. if (opts.legend.show === false) {
  4869. return;
  4870. }
  4871. let legendData = chartData.legendData;
  4872. let legendList = legendData.points;
  4873. let legendArea = legendData.area;
  4874. let padding = opts.legend.padding * opts.pix;
  4875. let fontSize = opts.legend.fontSize * opts.pix;
  4876. let shapeWidth = 15 * opts.pix;
  4877. let shapeRight = 5 * opts.pix;
  4878. let itemGap = opts.legend.itemGap * opts.pix;
  4879. let lineHeight = Math.max(opts.legend.lineHeight * opts.pix, fontSize);
  4880. //画背景及边框
  4881. context.beginPath();
  4882. context.setLineWidth(opts.legend.borderWidth * opts.pix);
  4883. context.setStrokeStyle(opts.legend.borderColor);
  4884. context.setFillStyle(opts.legend.backgroundColor);
  4885. context.moveTo(legendArea.start.x, legendArea.start.y);
  4886. context.rect(legendArea.start.x, legendArea.start.y, legendArea.width, legendArea.height);
  4887. context.closePath();
  4888. context.fill();
  4889. context.stroke();
  4890. legendList.forEach(function(itemList, listIndex) {
  4891. let width = 0;
  4892. let height = 0;
  4893. width = legendData.widthArr[listIndex];
  4894. height = legendData.heightArr[listIndex];
  4895. let startX = 0;
  4896. let startY = 0;
  4897. if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
  4898. switch (opts.legend.float) {
  4899. case 'left':
  4900. startX = legendArea.start.x + padding;
  4901. break;
  4902. case 'right':
  4903. startX = legendArea.start.x + legendArea.width - width;
  4904. break;
  4905. default:
  4906. startX = legendArea.start.x + (legendArea.width - width) / 2;
  4907. }
  4908. startY = legendArea.start.y + padding + listIndex * lineHeight;
  4909. } else {
  4910. if (listIndex == 0) {
  4911. width = 0;
  4912. } else {
  4913. width = legendData.widthArr[listIndex - 1];
  4914. }
  4915. startX = legendArea.start.x + padding + width;
  4916. startY = legendArea.start.y + padding + (legendArea.height - height) / 2;
  4917. }
  4918. context.setFontSize(config.fontSize);
  4919. for (let i = 0; i < itemList.length; i++) {
  4920. let item = itemList[i];
  4921. item.area = [0, 0, 0, 0];
  4922. item.area[0] = startX;
  4923. item.area[1] = startY;
  4924. item.area[3] = startY + lineHeight;
  4925. context.beginPath();
  4926. context.setLineWidth(1 * opts.pix);
  4927. context.setStrokeStyle(item.show ? item.color : opts.legend.hiddenColor);
  4928. context.setFillStyle(item.show ? item.color : opts.legend.hiddenColor);
  4929. switch (item.legendShape) {
  4930. case 'line':
  4931. context.moveTo(startX, startY + 0.5 * lineHeight - 2 * opts.pix);
  4932. context.fillRect(startX, startY + 0.5 * lineHeight - 2 * opts.pix, 15 * opts.pix, 4 * opts
  4933. .pix);
  4934. break;
  4935. case 'triangle':
  4936. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
  4937. context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
  4938. context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
  4939. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
  4940. break;
  4941. case 'diamond':
  4942. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
  4943. context.lineTo(startX + 2.5 * opts.pix, startY + 0.5 * lineHeight);
  4944. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight + 5 * opts.pix);
  4945. context.lineTo(startX + 12.5 * opts.pix, startY + 0.5 * lineHeight);
  4946. context.lineTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
  4947. break;
  4948. case 'circle':
  4949. context.moveTo(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight);
  4950. context.arc(startX + 7.5 * opts.pix, startY + 0.5 * lineHeight, 5 * opts.pix, 0, 2 * Math
  4951. .PI);
  4952. break;
  4953. case 'rect':
  4954. context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
  4955. context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts
  4956. .pix);
  4957. break;
  4958. case 'square':
  4959. context.moveTo(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix);
  4960. context.fillRect(startX + 5 * opts.pix, startY + 0.5 * lineHeight - 5 * opts.pix, 10 * opts
  4961. .pix, 10 * opts.pix);
  4962. break;
  4963. case 'none':
  4964. break;
  4965. default:
  4966. context.moveTo(startX, startY + 0.5 * lineHeight - 5 * opts.pix);
  4967. context.fillRect(startX, startY + 0.5 * lineHeight - 5 * opts.pix, 15 * opts.pix, 10 * opts
  4968. .pix);
  4969. }
  4970. context.closePath();
  4971. context.fill();
  4972. context.stroke();
  4973. startX += shapeWidth + shapeRight;
  4974. let fontTrans = 0.5 * lineHeight + 0.5 * fontSize - 2;
  4975. const legendText = item.legendText ? item.legendText : item.name;
  4976. context.beginPath();
  4977. context.setFontSize(fontSize);
  4978. context.setFillStyle(item.show ? opts.legend.fontColor : opts.legend.hiddenColor);
  4979. context.fillText(legendText, startX, startY + fontTrans);
  4980. context.closePath();
  4981. context.stroke();
  4982. if (opts.legend.position == 'top' || opts.legend.position == 'bottom') {
  4983. startX += measureText(legendText, fontSize, context) + itemGap;
  4984. item.area[2] = startX;
  4985. } else {
  4986. item.area[2] = startX + measureText(legendText, fontSize, context) + itemGap;;
  4987. startX -= shapeWidth + shapeRight;
  4988. startY += lineHeight;
  4989. }
  4990. }
  4991. });
  4992. }
  4993. function drawPieDataPoints(series, opts, config, context) {
  4994. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  4995. var pieOption = assign({}, {
  4996. activeOpacity: 0.5,
  4997. activeRadius: 10,
  4998. offsetAngle: 0,
  4999. labelWidth: 15,
  5000. ringWidth: 30,
  5001. customRadius: 0,
  5002. border: false,
  5003. borderWidth: 2,
  5004. borderColor: '#FFFFFF',
  5005. centerColor: '#FFFFFF',
  5006. linearType: 'none',
  5007. customColor: [],
  5008. }, opts.type == "pie" ? opts.extra.pie : opts.extra.ring);
  5009. var centerPosition = {
  5010. x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
  5011. y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  5012. };
  5013. if (config.pieChartLinePadding == 0) {
  5014. config.pieChartLinePadding = pieOption.activeRadius * opts.pix;
  5015. }
  5016. var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config
  5017. .pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config
  5018. .pieChartLinePadding - config.pieChartTextPadding);
  5019. radius = radius < 10 ? 10 : radius;
  5020. if (pieOption.customRadius > 0) {
  5021. radius = pieOption.customRadius * opts.pix;
  5022. }
  5023. series = getPieDataPoints(series, radius, process);
  5024. var activeRadius = pieOption.activeRadius * opts.pix;
  5025. pieOption.customColor = fillCustomColor(pieOption.linearType, pieOption.customColor, series, config);
  5026. series = series.map(function(eachSeries) {
  5027. eachSeries._start_ += (pieOption.offsetAngle) * Math.PI / 180;
  5028. return eachSeries;
  5029. });
  5030. series.forEach(function(eachSeries, seriesIndex) {
  5031. if (opts.tooltip) {
  5032. if (opts.tooltip.index == seriesIndex) {
  5033. context.beginPath();
  5034. context.setFillStyle(hexToRgb(eachSeries.color, pieOption.activeOpacity || 0.5));
  5035. context.moveTo(centerPosition.x, centerPosition.y);
  5036. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_ + activeRadius, eachSeries
  5037. ._start_, eachSeries._start_ + 2 * eachSeries._proportion_ * Math.PI);
  5038. context.closePath();
  5039. context.fill();
  5040. }
  5041. }
  5042. context.beginPath();
  5043. context.setLineWidth(pieOption.borderWidth * opts.pix);
  5044. context.lineJoin = "round";
  5045. context.setStrokeStyle(pieOption.borderColor);
  5046. var fillcolor = eachSeries.color;
  5047. if (pieOption.linearType == 'custom') {
  5048. var grd;
  5049. if (context.createCircularGradient) {
  5050. grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_)
  5051. } else {
  5052. grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x,
  5053. centerPosition.y, eachSeries._radius_)
  5054. }
  5055. grd.addColorStop(0, hexToRgb(pieOption.customColor[eachSeries.linearIndex], 1))
  5056. grd.addColorStop(1, hexToRgb(eachSeries.color, 1))
  5057. fillcolor = grd
  5058. }
  5059. context.setFillStyle(fillcolor);
  5060. context.moveTo(centerPosition.x, centerPosition.y);
  5061. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries
  5062. ._start_ + 2 * eachSeries._proportion_ * Math.PI);
  5063. context.closePath();
  5064. context.fill();
  5065. if (pieOption.border == true) {
  5066. context.stroke();
  5067. }
  5068. });
  5069. if (opts.type === 'ring') {
  5070. var innerPieWidth = radius * 0.6;
  5071. if (typeof pieOption.ringWidth === 'number' && pieOption.ringWidth > 0) {
  5072. innerPieWidth = Math.max(0, radius - pieOption.ringWidth * opts.pix);
  5073. }
  5074. context.beginPath();
  5075. context.setFillStyle(pieOption.centerColor);
  5076. context.moveTo(centerPosition.x, centerPosition.y);
  5077. context.arc(centerPosition.x, centerPosition.y, innerPieWidth, 0, 2 * Math.PI);
  5078. context.closePath();
  5079. context.fill();
  5080. }
  5081. if (opts.dataLabel !== false && process === 1) {
  5082. drawPieText(series, opts, config, context, radius, centerPosition);
  5083. }
  5084. if (process === 1 && opts.type === 'ring') {
  5085. drawRingTitle(opts, config, context, centerPosition);
  5086. }
  5087. return {
  5088. center: centerPosition,
  5089. radius: radius,
  5090. series: series
  5091. };
  5092. }
  5093. function drawRoseDataPoints(series, opts, config, context) {
  5094. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  5095. var roseOption = assign({}, {
  5096. type: 'area',
  5097. activeOpacity: 0.5,
  5098. activeRadius: 10,
  5099. offsetAngle: 0,
  5100. labelWidth: 15,
  5101. border: false,
  5102. borderWidth: 2,
  5103. borderColor: '#FFFFFF',
  5104. linearType: 'none',
  5105. customColor: [],
  5106. }, opts.extra.rose);
  5107. if (config.pieChartLinePadding == 0) {
  5108. config.pieChartLinePadding = roseOption.activeRadius * opts.pix;
  5109. }
  5110. var centerPosition = {
  5111. x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
  5112. y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  5113. };
  5114. var radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - config.pieChartLinePadding - config
  5115. .pieChartTextPadding - config._pieTextMaxLength_, (opts.height - opts.area[0] - opts.area[2]) / 2 - config
  5116. .pieChartLinePadding - config.pieChartTextPadding);
  5117. radius = radius < 10 ? 10 : radius;
  5118. var minRadius = roseOption.minRadius || radius * 0.5;
  5119. if (radius < minRadius) {
  5120. radius = minRadius + 10;
  5121. }
  5122. series = getRoseDataPoints(series, roseOption.type, minRadius, radius, process);
  5123. var activeRadius = roseOption.activeRadius * opts.pix;
  5124. roseOption.customColor = fillCustomColor(roseOption.linearType, roseOption.customColor, series, config);
  5125. series = series.map(function(eachSeries) {
  5126. eachSeries._start_ += (roseOption.offsetAngle || 0) * Math.PI / 180;
  5127. return eachSeries;
  5128. });
  5129. series.forEach(function(eachSeries, seriesIndex) {
  5130. if (opts.tooltip) {
  5131. if (opts.tooltip.index == seriesIndex) {
  5132. context.beginPath();
  5133. context.setFillStyle(hexToRgb(eachSeries.color, roseOption.activeOpacity || 0.5));
  5134. context.moveTo(centerPosition.x, centerPosition.y);
  5135. context.arc(centerPosition.x, centerPosition.y, activeRadius + eachSeries._radius_, eachSeries
  5136. ._start_, eachSeries._start_ + 2 * eachSeries._rose_proportion_ * Math.PI);
  5137. context.closePath();
  5138. context.fill();
  5139. }
  5140. }
  5141. context.beginPath();
  5142. context.setLineWidth(roseOption.borderWidth * opts.pix);
  5143. context.lineJoin = "round";
  5144. context.setStrokeStyle(roseOption.borderColor);
  5145. var fillcolor = eachSeries.color;
  5146. if (roseOption.linearType == 'custom') {
  5147. var grd;
  5148. if (context.createCircularGradient) {
  5149. grd = context.createCircularGradient(centerPosition.x, centerPosition.y, eachSeries._radius_)
  5150. } else {
  5151. grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x,
  5152. centerPosition.y, eachSeries._radius_)
  5153. }
  5154. grd.addColorStop(0, hexToRgb(roseOption.customColor[eachSeries.linearIndex], 1))
  5155. grd.addColorStop(1, hexToRgb(eachSeries.color, 1))
  5156. fillcolor = grd
  5157. }
  5158. context.setFillStyle(fillcolor);
  5159. context.moveTo(centerPosition.x, centerPosition.y);
  5160. context.arc(centerPosition.x, centerPosition.y, eachSeries._radius_, eachSeries._start_, eachSeries
  5161. ._start_ + 2 * eachSeries._rose_proportion_ * Math.PI);
  5162. context.closePath();
  5163. context.fill();
  5164. if (roseOption.border == true) {
  5165. context.stroke();
  5166. }
  5167. });
  5168. if (opts.dataLabel !== false && process === 1) {
  5169. drawPieText(series, opts, config, context, radius, centerPosition);
  5170. }
  5171. return {
  5172. center: centerPosition,
  5173. radius: radius,
  5174. series: series
  5175. };
  5176. }
  5177. function drawArcbarDataPoints(series, opts, config, context) {
  5178. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  5179. var arcbarOption = assign({}, {
  5180. startAngle: 0.75,
  5181. endAngle: 0.25,
  5182. type: 'default',
  5183. direction: 'cw',
  5184. lineCap: 'round',
  5185. width: 12,
  5186. gap: 2,
  5187. linearType: 'none',
  5188. customColor: [],
  5189. }, opts.extra.arcbar);
  5190. series = getArcbarDataPoints(series, arcbarOption, process);
  5191. var centerPosition;
  5192. if (arcbarOption.centerX || arcbarOption.centerY) {
  5193. centerPosition = {
  5194. x: arcbarOption.centerX ? arcbarOption.centerX : opts.width / 2,
  5195. y: arcbarOption.centerY ? arcbarOption.centerY : opts.height / 2
  5196. };
  5197. } else {
  5198. centerPosition = {
  5199. x: opts.width / 2,
  5200. y: opts.height / 2
  5201. };
  5202. }
  5203. var radius;
  5204. if (arcbarOption.radius) {
  5205. radius = arcbarOption.radius;
  5206. } else {
  5207. radius = Math.min(centerPosition.x, centerPosition.y);
  5208. radius -= 5 * opts.pix;
  5209. radius -= arcbarOption.width / 2;
  5210. }
  5211. radius = radius < 10 ? 10 : radius;
  5212. arcbarOption.customColor = fillCustomColor(arcbarOption.linearType, arcbarOption.customColor, series, config);
  5213. for (let i = 0; i < series.length; i++) {
  5214. let eachSeries = series[i];
  5215. //背景颜色
  5216. context.setLineWidth(arcbarOption.width * opts.pix);
  5217. context.setStrokeStyle(arcbarOption.backgroundColor || '#E9E9E9');
  5218. context.setLineCap(arcbarOption.lineCap);
  5219. context.beginPath();
  5220. if (arcbarOption.type == 'default') {
  5221. context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap *
  5222. opts.pix) * i, arcbarOption.startAngle * Math.PI, arcbarOption.endAngle * Math.PI, arcbarOption
  5223. .direction == 'ccw');
  5224. } else {
  5225. context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap *
  5226. opts.pix) * i, 0, 2 * Math.PI, arcbarOption.direction == 'ccw');
  5227. }
  5228. context.stroke();
  5229. //进度条
  5230. var fillColor = eachSeries.color
  5231. if (arcbarOption.linearType == 'custom') {
  5232. var grd = context.createLinearGradient(centerPosition.x - radius, centerPosition.y, centerPosition.x +
  5233. radius, centerPosition.y);
  5234. grd.addColorStop(1, hexToRgb(arcbarOption.customColor[eachSeries.linearIndex], 1))
  5235. grd.addColorStop(0, hexToRgb(eachSeries.color, 1))
  5236. fillColor = grd;
  5237. }
  5238. context.setLineWidth(arcbarOption.width * opts.pix);
  5239. context.setStrokeStyle(fillColor);
  5240. context.setLineCap(arcbarOption.lineCap);
  5241. context.beginPath();
  5242. context.arc(centerPosition.x, centerPosition.y, radius - (arcbarOption.width * opts.pix + arcbarOption.gap *
  5243. opts.pix) * i, arcbarOption.startAngle * Math.PI, eachSeries._proportion_ * Math.PI, arcbarOption
  5244. .direction == 'ccw');
  5245. context.stroke();
  5246. }
  5247. drawRingTitle(opts, config, context, centerPosition);
  5248. return {
  5249. center: centerPosition,
  5250. radius: radius,
  5251. series: series
  5252. };
  5253. }
  5254. function drawGaugeDataPoints(categories, series, opts, config, context) {
  5255. var process = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 1;
  5256. var gaugeOption = assign({}, {
  5257. type: 'default',
  5258. startAngle: 0.75,
  5259. endAngle: 0.25,
  5260. width: 15,
  5261. labelOffset: 13,
  5262. splitLine: {
  5263. fixRadius: 0,
  5264. splitNumber: 10,
  5265. width: 15,
  5266. color: '#FFFFFF',
  5267. childNumber: 5,
  5268. childWidth: 5
  5269. },
  5270. pointer: {
  5271. width: 15,
  5272. color: 'auto'
  5273. }
  5274. }, opts.extra.gauge);
  5275. if (gaugeOption.oldAngle == undefined) {
  5276. gaugeOption.oldAngle = gaugeOption.startAngle;
  5277. }
  5278. if (gaugeOption.oldData == undefined) {
  5279. gaugeOption.oldData = 0;
  5280. }
  5281. categories = getGaugeAxisPoints(categories, gaugeOption.startAngle, gaugeOption.endAngle);
  5282. var centerPosition = {
  5283. x: opts.width / 2,
  5284. y: opts.height / 2
  5285. };
  5286. var radius = Math.min(centerPosition.x, centerPosition.y);
  5287. radius -= 5 * opts.pix;
  5288. radius -= gaugeOption.width / 2;
  5289. radius = radius < 10 ? 10 : radius;
  5290. var innerRadius = radius - gaugeOption.width;
  5291. var totalAngle = 0;
  5292. //判断仪表盘的样式:default百度样式,progress新样式
  5293. if (gaugeOption.type == 'progress') {
  5294. //## 第一步画中心圆形背景和进度条背景
  5295. //中心圆形背景
  5296. var pieRadius = radius - gaugeOption.width * 3;
  5297. context.beginPath();
  5298. let gradient = context.createLinearGradient(centerPosition.x, centerPosition.y - pieRadius, centerPosition.x,
  5299. centerPosition.y + pieRadius);
  5300. //配置渐变填充(起点:中心点向上减半径;结束点中心点向下加半径)
  5301. gradient.addColorStop('0', hexToRgb(series[0].color, 0.3));
  5302. gradient.addColorStop('1.0', hexToRgb("#FFFFFF", 0.1));
  5303. context.setFillStyle(gradient);
  5304. context.arc(centerPosition.x, centerPosition.y, pieRadius, 0, 2 * Math.PI, false);
  5305. context.fill();
  5306. //画进度条背景
  5307. context.setLineWidth(gaugeOption.width);
  5308. context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
  5309. context.setLineCap('round');
  5310. context.beginPath();
  5311. context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, gaugeOption
  5312. .endAngle * Math.PI, false);
  5313. context.stroke();
  5314. //## 第二步画刻度线
  5315. if (gaugeOption.endAngle < gaugeOption.startAngle) {
  5316. totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
  5317. } else {
  5318. totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
  5319. }
  5320. let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  5321. let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
  5322. let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
  5323. let endX = -radius - gaugeOption.width - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
  5324. context.save();
  5325. context.translate(centerPosition.x, centerPosition.y);
  5326. context.rotate((gaugeOption.startAngle - 1) * Math.PI);
  5327. let len = gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1;
  5328. let proc = series[0].data * process;
  5329. for (let i = 0; i < len; i++) {
  5330. context.beginPath();
  5331. //刻度线随进度变色
  5332. if (proc > (i / len)) {
  5333. context.setStrokeStyle(hexToRgb(series[0].color, 1));
  5334. } else {
  5335. context.setStrokeStyle(hexToRgb(series[0].color, 0.3));
  5336. }
  5337. context.setLineWidth(3 * opts.pix);
  5338. context.moveTo(startX, 0);
  5339. context.lineTo(endX, 0);
  5340. context.stroke();
  5341. context.rotate(childAngle * Math.PI);
  5342. }
  5343. context.restore();
  5344. //## 第三步画进度条
  5345. series = getGaugeArcbarDataPoints(series, gaugeOption, process);
  5346. context.setLineWidth(gaugeOption.width);
  5347. context.setStrokeStyle(series[0].color);
  5348. context.setLineCap('round');
  5349. context.beginPath();
  5350. context.arc(centerPosition.x, centerPosition.y, innerRadius, gaugeOption.startAngle * Math.PI, series[0]
  5351. ._proportion_ * Math.PI, false);
  5352. context.stroke();
  5353. //## 第四步画指针
  5354. let pointerRadius = radius - gaugeOption.width * 2.5;
  5355. context.save();
  5356. context.translate(centerPosition.x, centerPosition.y);
  5357. context.rotate((series[0]._proportion_ - 1) * Math.PI);
  5358. context.beginPath();
  5359. context.setLineWidth(gaugeOption.width / 3);
  5360. let gradient3 = context.createLinearGradient(0, -pointerRadius * 0.6, 0, pointerRadius * 0.6);
  5361. gradient3.addColorStop('0', hexToRgb('#FFFFFF', 0));
  5362. gradient3.addColorStop('0.5', hexToRgb(series[0].color, 1));
  5363. gradient3.addColorStop('1.0', hexToRgb('#FFFFFF', 0));
  5364. context.setStrokeStyle(gradient3);
  5365. context.arc(0, 0, pointerRadius, 0.85 * Math.PI, 1.15 * Math.PI, false);
  5366. context.stroke();
  5367. context.beginPath();
  5368. context.setLineWidth(1);
  5369. context.setStrokeStyle(series[0].color);
  5370. context.setFillStyle(series[0].color);
  5371. context.moveTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
  5372. context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2 - 4, 0);
  5373. context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, 4);
  5374. context.lineTo(-pointerRadius - gaugeOption.width / 3 / 2, -4);
  5375. context.stroke();
  5376. context.fill();
  5377. context.restore();
  5378. //default百度样式
  5379. } else {
  5380. //画背景
  5381. context.setLineWidth(gaugeOption.width);
  5382. context.setLineCap('butt');
  5383. for (let i = 0; i < categories.length; i++) {
  5384. let eachCategories = categories[i];
  5385. context.beginPath();
  5386. context.setStrokeStyle(eachCategories.color);
  5387. context.arc(centerPosition.x, centerPosition.y, radius, eachCategories._startAngle_ * Math.PI,
  5388. eachCategories._endAngle_ * Math.PI, false);
  5389. context.stroke();
  5390. }
  5391. context.save();
  5392. //画刻度线
  5393. if (gaugeOption.endAngle < gaugeOption.startAngle) {
  5394. totalAngle = 2 + gaugeOption.endAngle - gaugeOption.startAngle;
  5395. } else {
  5396. totalAngle = gaugeOption.startAngle - gaugeOption.endAngle;
  5397. }
  5398. let splitAngle = totalAngle / gaugeOption.splitLine.splitNumber;
  5399. let childAngle = totalAngle / gaugeOption.splitLine.splitNumber / gaugeOption.splitLine.childNumber;
  5400. let startX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius;
  5401. let endX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine.width;
  5402. let childendX = -radius - gaugeOption.width * 0.5 - gaugeOption.splitLine.fixRadius + gaugeOption.splitLine
  5403. .childWidth;
  5404. context.translate(centerPosition.x, centerPosition.y);
  5405. context.rotate((gaugeOption.startAngle - 1) * Math.PI);
  5406. for (let i = 0; i < gaugeOption.splitLine.splitNumber + 1; i++) {
  5407. context.beginPath();
  5408. context.setStrokeStyle(gaugeOption.splitLine.color);
  5409. context.setLineWidth(2 * opts.pix);
  5410. context.moveTo(startX, 0);
  5411. context.lineTo(endX, 0);
  5412. context.stroke();
  5413. context.rotate(splitAngle * Math.PI);
  5414. }
  5415. context.restore();
  5416. context.save();
  5417. context.translate(centerPosition.x, centerPosition.y);
  5418. context.rotate((gaugeOption.startAngle - 1) * Math.PI);
  5419. for (let i = 0; i < gaugeOption.splitLine.splitNumber * gaugeOption.splitLine.childNumber + 1; i++) {
  5420. context.beginPath();
  5421. context.setStrokeStyle(gaugeOption.splitLine.color);
  5422. context.setLineWidth(1 * opts.pix);
  5423. context.moveTo(startX, 0);
  5424. context.lineTo(childendX, 0);
  5425. context.stroke();
  5426. context.rotate(childAngle * Math.PI);
  5427. }
  5428. context.restore();
  5429. //画指针
  5430. series = getGaugeDataPoints(series, categories, gaugeOption, process);
  5431. for (let i = 0; i < series.length; i++) {
  5432. let eachSeries = series[i];
  5433. context.save();
  5434. context.translate(centerPosition.x, centerPosition.y);
  5435. context.rotate((eachSeries._proportion_ - 1) * Math.PI);
  5436. context.beginPath();
  5437. context.setFillStyle(eachSeries.color);
  5438. context.moveTo(gaugeOption.pointer.width, 0);
  5439. context.lineTo(0, -gaugeOption.pointer.width / 2);
  5440. context.lineTo(-innerRadius, 0);
  5441. context.lineTo(0, gaugeOption.pointer.width / 2);
  5442. context.lineTo(gaugeOption.pointer.width, 0);
  5443. context.closePath();
  5444. context.fill();
  5445. context.beginPath();
  5446. context.setFillStyle('#FFFFFF');
  5447. context.arc(0, 0, gaugeOption.pointer.width / 6, 0, 2 * Math.PI, false);
  5448. context.fill();
  5449. context.restore();
  5450. }
  5451. if (opts.dataLabel !== false) {
  5452. drawGaugeLabel(gaugeOption, radius, centerPosition, opts, config, context);
  5453. }
  5454. }
  5455. //画仪表盘标题,副标题
  5456. drawRingTitle(opts, config, context, centerPosition);
  5457. if (process === 1 && opts.type === 'gauge') {
  5458. opts.extra.gauge.oldAngle = series[0]._proportion_;
  5459. opts.extra.gauge.oldData = series[0].data;
  5460. }
  5461. return {
  5462. center: centerPosition,
  5463. radius: radius,
  5464. innerRadius: innerRadius,
  5465. categories: categories,
  5466. totalAngle: totalAngle
  5467. };
  5468. }
  5469. function drawRadarDataPoints(series, opts, config, context) {
  5470. var process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  5471. var radarOption = assign({}, {
  5472. gridColor: '#cccccc',
  5473. gridType: 'radar',
  5474. gridEval: 1,
  5475. axisLabel: false,
  5476. axisLabelTofix: 0,
  5477. labelShow: true,
  5478. labelColor: '#666666',
  5479. labelPointShow: false,
  5480. labelPointRadius: 3,
  5481. labelPointColor: '#cccccc',
  5482. opacity: 0.2,
  5483. gridCount: 3,
  5484. border: false,
  5485. borderWidth: 2,
  5486. linearType: 'none',
  5487. customColor: [],
  5488. }, opts.extra.radar);
  5489. var coordinateAngle = getRadarCoordinateSeries(opts.categories.length);
  5490. var centerPosition = {
  5491. x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
  5492. y: opts.area[0] + (opts.height - opts.area[0] - opts.area[2]) / 2
  5493. };
  5494. var xr = (opts.width - opts.area[1] - opts.area[3]) / 2
  5495. var yr = (opts.height - opts.area[0] - opts.area[2]) / 2
  5496. var radius = Math.min(xr - (getMaxTextListLength(opts.categories, config.fontSize, context) + config
  5497. .radarLabelTextMargin), yr - config.radarLabelTextMargin);
  5498. radius -= config.radarLabelTextMargin * opts.pix;
  5499. radius = radius < 10 ? 10 : radius;
  5500. radius = radarOption.radius ? radarOption.radius : radius;
  5501. // 画分割线
  5502. context.beginPath();
  5503. context.setLineWidth(1 * opts.pix);
  5504. context.setStrokeStyle(radarOption.gridColor);
  5505. coordinateAngle.forEach(function(angle, index) {
  5506. var pos = convertCoordinateOrigin(radius * Math.cos(angle), radius * Math.sin(angle), centerPosition);
  5507. context.moveTo(centerPosition.x, centerPosition.y);
  5508. if (index % radarOption.gridEval == 0) {
  5509. context.lineTo(pos.x, pos.y);
  5510. }
  5511. });
  5512. context.stroke();
  5513. context.closePath();
  5514. // 画背景网格
  5515. var _loop = function _loop(i) {
  5516. var startPos = {};
  5517. context.beginPath();
  5518. context.setLineWidth(1 * opts.pix);
  5519. context.setStrokeStyle(radarOption.gridColor);
  5520. if (radarOption.gridType == 'radar') {
  5521. coordinateAngle.forEach(function(angle, index) {
  5522. var pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(angle),
  5523. radius /
  5524. radarOption.gridCount * i * Math.sin(angle), centerPosition);
  5525. if (index === 0) {
  5526. startPos = pos;
  5527. context.moveTo(pos.x, pos.y);
  5528. } else {
  5529. context.lineTo(pos.x, pos.y);
  5530. }
  5531. });
  5532. context.lineTo(startPos.x, startPos.y);
  5533. } else {
  5534. var pos = convertCoordinateOrigin(radius / radarOption.gridCount * i * Math.cos(1.5), radius /
  5535. radarOption.gridCount * i * Math.sin(1.5), centerPosition);
  5536. context.arc(centerPosition.x, centerPosition.y, centerPosition.y - pos.y, 0, 2 * Math.PI, false);
  5537. }
  5538. context.stroke();
  5539. context.closePath();
  5540. };
  5541. for (var i = 1; i <= radarOption.gridCount; i++) {
  5542. _loop(i);
  5543. }
  5544. radarOption.customColor = fillCustomColor(radarOption.linearType, radarOption.customColor, series, config);
  5545. var radarDataPoints = getRadarDataPoints(coordinateAngle, centerPosition, radius, series, opts, process);
  5546. radarDataPoints.forEach(function(eachSeries, seriesIndex) {
  5547. // 绘制区域数据
  5548. context.beginPath();
  5549. context.setLineWidth(radarOption.borderWidth * opts.pix);
  5550. context.setStrokeStyle(eachSeries.color);
  5551. var fillcolor = hexToRgb(eachSeries.color, radarOption.opacity);
  5552. if (radarOption.linearType == 'custom') {
  5553. var grd;
  5554. if (context.createCircularGradient) {
  5555. grd = context.createCircularGradient(centerPosition.x, centerPosition.y, radius)
  5556. } else {
  5557. grd = context.createRadialGradient(centerPosition.x, centerPosition.y, 0, centerPosition.x,
  5558. centerPosition.y, radius)
  5559. }
  5560. grd.addColorStop(0, hexToRgb(radarOption.customColor[series[seriesIndex].linearIndex], radarOption
  5561. .opacity))
  5562. grd.addColorStop(1, hexToRgb(eachSeries.color, radarOption.opacity))
  5563. fillcolor = grd
  5564. }
  5565. context.setFillStyle(fillcolor);
  5566. eachSeries.data.forEach(function(item, index) {
  5567. if (index === 0) {
  5568. context.moveTo(item.position.x, item.position.y);
  5569. } else {
  5570. context.lineTo(item.position.x, item.position.y);
  5571. }
  5572. });
  5573. context.closePath();
  5574. context.fill();
  5575. if (radarOption.border === true) {
  5576. context.stroke();
  5577. }
  5578. context.closePath();
  5579. if (opts.dataPointShape !== false) {
  5580. var points = eachSeries.data.map(function(item) {
  5581. return item.position;
  5582. });
  5583. drawPointShape(points, eachSeries.color, eachSeries.pointShape, context, opts);
  5584. }
  5585. });
  5586. // 画刻度值
  5587. if (radarOption.axisLabel === true) {
  5588. const maxData = Math.max(radarOption.max, Math.max.apply(null, dataCombine(series)));
  5589. const stepLength = radius / radarOption.gridCount;
  5590. const fontSize = opts.fontSize * opts.pix;
  5591. context.setFontSize(fontSize);
  5592. context.setFillStyle(opts.fontColor);
  5593. context.setTextAlign('left');
  5594. for (var i = 0; i < radarOption.gridCount + 1; i++) {
  5595. let label = i * maxData / radarOption.gridCount;
  5596. label = label.toFixed(radarOption.axisLabelTofix);
  5597. context.fillText(String(label), centerPosition.x + 3 * opts.pix, centerPosition.y - i * stepLength +
  5598. fontSize / 2);
  5599. }
  5600. }
  5601. // draw label text
  5602. drawRadarLabel(coordinateAngle, radius, centerPosition, opts, config, context);
  5603. // draw dataLabel
  5604. if (opts.dataLabel !== false && process === 1) {
  5605. radarDataPoints.forEach(function(eachSeries, seriesIndex) {
  5606. context.beginPath();
  5607. var fontSize = eachSeries.textSize * opts.pix || config.fontSize;
  5608. context.setFontSize(fontSize);
  5609. context.setFillStyle(eachSeries.textColor || opts.fontColor);
  5610. eachSeries.data.forEach(function(item, index) {
  5611. //如果是中心点垂直的上下点位
  5612. if (Math.abs(item.position.x - centerPosition.x) < 2) {
  5613. //如果在上面
  5614. if (item.position.y < centerPosition.y) {
  5615. context.setTextAlign('center');
  5616. context.fillText(item.value, item.position.x, item.position.y - 4);
  5617. } else {
  5618. context.setTextAlign('center');
  5619. context.fillText(item.value, item.position.x, item.position.y + fontSize + 2);
  5620. }
  5621. } else {
  5622. //如果在左侧
  5623. if (item.position.x < centerPosition.x) {
  5624. context.setTextAlign('right');
  5625. context.fillText(item.value, item.position.x - 4, item.position.y + fontSize /
  5626. 2 - 2);
  5627. } else {
  5628. context.setTextAlign('left');
  5629. context.fillText(item.value, item.position.x + 4, item.position.y + fontSize /
  5630. 2 - 2);
  5631. }
  5632. }
  5633. });
  5634. context.closePath();
  5635. context.stroke();
  5636. });
  5637. context.setTextAlign('left');
  5638. }
  5639. return {
  5640. center: centerPosition,
  5641. radius: radius,
  5642. angleList: coordinateAngle
  5643. };
  5644. }
  5645. // 经纬度转墨卡托
  5646. function lonlat2mercator(longitude, latitude) {
  5647. var mercator = Array(2);
  5648. var x = longitude * 20037508.34 / 180;
  5649. var y = Math.log(Math.tan((90 + latitude) * Math.PI / 360)) / (Math.PI / 180);
  5650. y = y * 20037508.34 / 180;
  5651. mercator[0] = x;
  5652. mercator[1] = y;
  5653. return mercator;
  5654. }
  5655. // 墨卡托转经纬度
  5656. function mercator2lonlat(longitude, latitude) {
  5657. var lonlat = Array(2)
  5658. var x = longitude / 20037508.34 * 180;
  5659. var y = latitude / 20037508.34 * 180;
  5660. y = 180 / Math.PI * (2 * Math.atan(Math.exp(y * Math.PI / 180)) - Math.PI / 2);
  5661. lonlat[0] = x;
  5662. lonlat[1] = y;
  5663. return lonlat;
  5664. }
  5665. function getBoundingBox(data) {
  5666. var bounds = {},
  5667. coords;
  5668. bounds.xMin = 180;
  5669. bounds.xMax = 0;
  5670. bounds.yMin = 90;
  5671. bounds.yMax = 0
  5672. for (var i = 0; i < data.length; i++) {
  5673. var coorda = data[i].geometry.coordinates
  5674. for (var k = 0; k < coorda.length; k++) {
  5675. coords = coorda[k];
  5676. if (coords.length == 1) {
  5677. coords = coords[0]
  5678. }
  5679. for (var j = 0; j < coords.length; j++) {
  5680. var longitude = coords[j][0];
  5681. var latitude = coords[j][1];
  5682. var point = {
  5683. x: longitude,
  5684. y: latitude
  5685. }
  5686. bounds.xMin = bounds.xMin < point.x ? bounds.xMin : point.x;
  5687. bounds.xMax = bounds.xMax > point.x ? bounds.xMax : point.x;
  5688. bounds.yMin = bounds.yMin < point.y ? bounds.yMin : point.y;
  5689. bounds.yMax = bounds.yMax > point.y ? bounds.yMax : point.y;
  5690. }
  5691. }
  5692. }
  5693. return bounds;
  5694. }
  5695. function coordinateToPoint(latitude, longitude, bounds, scale, xoffset, yoffset) {
  5696. return {
  5697. x: (longitude - bounds.xMin) * scale + xoffset,
  5698. y: (bounds.yMax - latitude) * scale + yoffset
  5699. };
  5700. }
  5701. function pointToCoordinate(pointY, pointX, bounds, scale, xoffset, yoffset) {
  5702. return {
  5703. x: (pointX - xoffset) / scale + bounds.xMin,
  5704. y: bounds.yMax - (pointY - yoffset) / scale
  5705. };
  5706. }
  5707. function isRayIntersectsSegment(poi, s_poi, e_poi) {
  5708. if (s_poi[1] == e_poi[1]) {
  5709. return false;
  5710. }
  5711. if (s_poi[1] > poi[1] && e_poi[1] > poi[1]) {
  5712. return false;
  5713. }
  5714. if (s_poi[1] < poi[1] && e_poi[1] < poi[1]) {
  5715. return false;
  5716. }
  5717. if (s_poi[1] == poi[1] && e_poi[1] > poi[1]) {
  5718. return false;
  5719. }
  5720. if (e_poi[1] == poi[1] && s_poi[1] > poi[1]) {
  5721. return false;
  5722. }
  5723. if (s_poi[0] < poi[0] && e_poi[1] < poi[1]) {
  5724. return false;
  5725. }
  5726. let xseg = e_poi[0] - (e_poi[0] - s_poi[0]) * (e_poi[1] - poi[1]) / (e_poi[1] - s_poi[1]);
  5727. if (xseg < poi[0]) {
  5728. return false;
  5729. } else {
  5730. return true;
  5731. }
  5732. }
  5733. function isPoiWithinPoly(poi, poly, mercator) {
  5734. let sinsc = 0;
  5735. for (let i = 0; i < poly.length; i++) {
  5736. let epoly = poly[i][0];
  5737. if (poly.length == 1) {
  5738. epoly = poly[i][0]
  5739. }
  5740. for (let j = 0; j < epoly.length - 1; j++) {
  5741. let s_poi = epoly[j];
  5742. let e_poi = epoly[j + 1];
  5743. if (mercator) {
  5744. s_poi = lonlat2mercator(epoly[j][0], epoly[j][1]);
  5745. e_poi = lonlat2mercator(epoly[j + 1][0], epoly[j + 1][1]);
  5746. }
  5747. if (isRayIntersectsSegment(poi, s_poi, e_poi)) {
  5748. sinsc += 1;
  5749. }
  5750. }
  5751. }
  5752. if (sinsc % 2 == 1) {
  5753. return true;
  5754. } else {
  5755. return false;
  5756. }
  5757. }
  5758. function drawMapDataPoints(series, opts, config, context) {
  5759. var mapOption = assign({}, {
  5760. border: true,
  5761. mercator: false,
  5762. borderWidth: 1,
  5763. active: true,
  5764. borderColor: '#666666',
  5765. fillOpacity: 0.6,
  5766. activeBorderColor: '#f04864',
  5767. activeFillColor: '#facc14',
  5768. activeFillOpacity: 1
  5769. }, opts.extra.map);
  5770. var coords, point;
  5771. var data = series;
  5772. var bounds = getBoundingBox(data);
  5773. if (mapOption.mercator) {
  5774. var max = lonlat2mercator(bounds.xMax, bounds.yMax)
  5775. var min = lonlat2mercator(bounds.xMin, bounds.yMin)
  5776. bounds.xMax = max[0]
  5777. bounds.yMax = max[1]
  5778. bounds.xMin = min[0]
  5779. bounds.yMin = min[1]
  5780. }
  5781. var xScale = opts.width / Math.abs(bounds.xMax - bounds.xMin);
  5782. var yScale = opts.height / Math.abs(bounds.yMax - bounds.yMin);
  5783. var scale = xScale < yScale ? xScale : yScale;
  5784. var xoffset = opts.width / 2 - Math.abs(bounds.xMax - bounds.xMin) / 2 * scale;
  5785. var yoffset = opts.height / 2 - Math.abs(bounds.yMax - bounds.yMin) / 2 * scale;
  5786. for (var i = 0; i < data.length; i++) {
  5787. context.beginPath();
  5788. context.setLineWidth(mapOption.borderWidth * opts.pix);
  5789. context.setStrokeStyle(mapOption.borderColor);
  5790. context.setFillStyle(hexToRgb(series[i].color, series[i].fillOpacity || mapOption.fillOpacity));
  5791. if (mapOption.active == true && opts.tooltip) {
  5792. if (opts.tooltip.index == i) {
  5793. context.setStrokeStyle(mapOption.activeBorderColor);
  5794. context.setFillStyle(hexToRgb(mapOption.activeFillColor, mapOption.activeFillOpacity));
  5795. }
  5796. }
  5797. var coorda = data[i].geometry.coordinates
  5798. for (var k = 0; k < coorda.length; k++) {
  5799. coords = coorda[k];
  5800. if (coords.length == 1) {
  5801. coords = coords[0]
  5802. }
  5803. for (var j = 0; j < coords.length; j++) {
  5804. var gaosi = Array(2);
  5805. if (mapOption.mercator) {
  5806. gaosi = lonlat2mercator(coords[j][0], coords[j][1])
  5807. } else {
  5808. gaosi = coords[j]
  5809. }
  5810. point = coordinateToPoint(gaosi[1], gaosi[0], bounds, scale, xoffset, yoffset)
  5811. if (j === 0) {
  5812. context.beginPath();
  5813. context.moveTo(point.x, point.y);
  5814. } else {
  5815. context.lineTo(point.x, point.y);
  5816. }
  5817. }
  5818. context.fill();
  5819. if (mapOption.border == true) {
  5820. context.stroke();
  5821. }
  5822. }
  5823. }
  5824. if (opts.dataLabel == true) {
  5825. for (var i = 0; i < data.length; i++) {
  5826. var centerPoint = data[i].properties.centroid;
  5827. if (centerPoint) {
  5828. if (mapOption.mercator) {
  5829. centerPoint = lonlat2mercator(data[i].properties.centroid[0], data[i].properties.centroid[1])
  5830. }
  5831. point = coordinateToPoint(centerPoint[1], centerPoint[0], bounds, scale, xoffset, yoffset);
  5832. let fontSize = data[i].textSize * opts.pix || config.fontSize;
  5833. let fontColor = data[i].textColor || opts.fontColor;
  5834. if (mapOption.active && mapOption.activeTextColor && opts.tooltip && opts.tooltip.index == i) {
  5835. fontColor = mapOption.activeTextColor;
  5836. }
  5837. let text = data[i].properties.name;
  5838. context.beginPath();
  5839. context.setFontSize(fontSize)
  5840. context.setFillStyle(fontColor)
  5841. context.fillText(text, point.x - measureText(text, fontSize, context) / 2, point.y + fontSize / 2);
  5842. context.closePath();
  5843. context.stroke();
  5844. }
  5845. }
  5846. }
  5847. opts.chartData.mapData = {
  5848. bounds: bounds,
  5849. scale: scale,
  5850. xoffset: xoffset,
  5851. yoffset: yoffset,
  5852. mercator: mapOption.mercator
  5853. }
  5854. drawToolTipBridge(opts, config, context, 1);
  5855. context.draw();
  5856. }
  5857. function normalInt(min, max, iter) {
  5858. iter = iter == 0 ? 1 : iter;
  5859. var arr = [];
  5860. for (var i = 0; i < iter; i++) {
  5861. arr[i] = Math.random();
  5862. };
  5863. return Math.floor(arr.reduce(function(i, j) {
  5864. return i + j
  5865. }) / iter * (max - min)) + min;
  5866. };
  5867. function collisionNew(area, points, width, height) {
  5868. var isIn = false;
  5869. for (let i = 0; i < points.length; i++) {
  5870. if (points[i].area) {
  5871. if (area[3] < points[i].area[1] || area[0] > points[i].area[2] || area[1] > points[i].area[3] || area[2] <
  5872. points[i].area[0]) {
  5873. if (area[0] < 0 || area[1] < 0 || area[2] > width || area[3] > height) {
  5874. isIn = true;
  5875. break;
  5876. } else {
  5877. isIn = false;
  5878. }
  5879. } else {
  5880. isIn = true;
  5881. break;
  5882. }
  5883. }
  5884. }
  5885. return isIn;
  5886. };
  5887. function getWordCloudPoint(opts, type, context) {
  5888. let points = opts.series;
  5889. switch (type) {
  5890. case 'normal':
  5891. for (let i = 0; i < points.length; i++) {
  5892. let text = points[i].name;
  5893. let tHeight = points[i].textSize * opts.pix;
  5894. let tWidth = measureText(text, tHeight, context);
  5895. let x, y;
  5896. let area;
  5897. let breaknum = 0;
  5898. while (true) {
  5899. breaknum++;
  5900. x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
  5901. y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
  5902. area = [x - 5 + opts.width / 2, y - 5 - tHeight + opts.height / 2, x + tWidth + 5 + opts.width / 2,
  5903. y + 5 +
  5904. opts.height / 2
  5905. ];
  5906. let isCollision = collisionNew(area, points, opts.width, opts.height);
  5907. if (!isCollision) break;
  5908. if (breaknum == 1000) {
  5909. area = [-100, -100, -100, -100];
  5910. break;
  5911. }
  5912. };
  5913. points[i].area = area;
  5914. }
  5915. break;
  5916. case 'vertical':
  5917. function Spin() {
  5918. //获取均匀随机值,是否旋转,旋转的概率为(1-0.5)
  5919. if (Math.random() > 0.7) {
  5920. return true;
  5921. } else {
  5922. return false
  5923. };
  5924. };
  5925. for (let i = 0; i < points.length; i++) {
  5926. let text = points[i].name;
  5927. let tHeight = points[i].textSize * opts.pix;
  5928. let tWidth = measureText(text, tHeight, context);
  5929. let isSpin = Spin();
  5930. let x, y, area, areav;
  5931. let breaknum = 0;
  5932. while (true) {
  5933. breaknum++;
  5934. let isCollision;
  5935. if (isSpin) {
  5936. x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
  5937. y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
  5938. area = [y - 5 - tWidth + opts.width / 2, (-x - 5 + opts.height / 2), y + 5 + opts.width / 2, (-
  5939. x + tHeight + 5 + opts.height / 2)];
  5940. areav = [opts.width - (opts.width / 2 - opts.height / 2) - (-x + tHeight + 5 + opts.height /
  5941. 2) - 5, (opts.height / 2 - opts.width / 2) + (y - 5 - tWidth + opts.width / 2) - 5, opts
  5942. .width - (opts.width / 2 - opts.height / 2) - (-x + tHeight + 5 + opts.height / 2) +
  5943. tHeight, (opts.height / 2 - opts.width / 2) + (y - 5 - tWidth + opts.width / 2) +
  5944. tWidth + 5
  5945. ];
  5946. isCollision = collisionNew(areav, points, opts.height, opts.width);
  5947. } else {
  5948. x = normalInt(-opts.width / 2, opts.width / 2, 5) - tWidth / 2;
  5949. y = normalInt(-opts.height / 2, opts.height / 2, 5) + tHeight / 2;
  5950. area = [x - 5 + opts.width / 2, y - 5 - tHeight + opts.height / 2, x + tWidth + 5 + opts.width /
  5951. 2, y + 5 + opts.height / 2
  5952. ];
  5953. isCollision = collisionNew(area, points, opts.width, opts.height);
  5954. }
  5955. if (!isCollision) break;
  5956. if (breaknum == 1000) {
  5957. area = [-1000, -1000, -1000, -1000];
  5958. break;
  5959. }
  5960. };
  5961. if (isSpin) {
  5962. points[i].area = areav;
  5963. points[i].areav = area;
  5964. } else {
  5965. points[i].area = area;
  5966. }
  5967. points[i].rotate = isSpin;
  5968. };
  5969. break;
  5970. }
  5971. return points;
  5972. }
  5973. function drawWordCloudDataPoints(series, opts, config, context) {
  5974. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  5975. let wordOption = assign({}, {
  5976. type: 'normal',
  5977. autoColors: true
  5978. }, opts.extra.word);
  5979. if (!opts.chartData.wordCloudData) {
  5980. opts.chartData.wordCloudData = getWordCloudPoint(opts, wordOption.type, context);
  5981. }
  5982. context.beginPath();
  5983. context.setFillStyle(opts.background);
  5984. context.rect(0, 0, opts.width, opts.height);
  5985. context.fill();
  5986. context.save();
  5987. let points = opts.chartData.wordCloudData;
  5988. context.translate(opts.width / 2, opts.height / 2);
  5989. for (let i = 0; i < points.length; i++) {
  5990. context.save();
  5991. if (points[i].rotate) {
  5992. context.rotate(90 * Math.PI / 180);
  5993. }
  5994. let text = points[i].name;
  5995. let tHeight = points[i].textSize * opts.pix;
  5996. let tWidth = measureText(text, tHeight, context);
  5997. context.beginPath();
  5998. context.setStrokeStyle(points[i].color);
  5999. context.setFillStyle(points[i].color);
  6000. context.setFontSize(tHeight);
  6001. if (points[i].rotate) {
  6002. if (points[i].areav[0] > 0) {
  6003. if (opts.tooltip) {
  6004. if (opts.tooltip.index == i) {
  6005. context.strokeText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 -
  6006. process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
  6007. } else {
  6008. context.fillText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 -
  6009. process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
  6010. }
  6011. } else {
  6012. context.fillText(text, (points[i].areav[0] + 5 - opts.width / 2) * process - tWidth * (1 -
  6013. process) / 2, (points[i].areav[1] + 5 + tHeight - opts.height / 2) * process);
  6014. }
  6015. }
  6016. } else {
  6017. if (points[i].area[0] > 0) {
  6018. if (opts.tooltip) {
  6019. if (opts.tooltip.index == i) {
  6020. context.strokeText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 -
  6021. process) / 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
  6022. } else {
  6023. context.fillText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 -
  6024. process) / 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
  6025. }
  6026. } else {
  6027. context.fillText(text, (points[i].area[0] + 5 - opts.width / 2) * process - tWidth * (1 - process) /
  6028. 2, (points[i].area[1] + 5 + tHeight - opts.height / 2) * process);
  6029. }
  6030. }
  6031. }
  6032. context.stroke();
  6033. context.restore();
  6034. }
  6035. context.restore();
  6036. }
  6037. function drawFunnelDataPoints(series, opts, config, context) {
  6038. let process = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 1;
  6039. let funnelOption = assign({}, {
  6040. type: 'funnel',
  6041. activeWidth: 10,
  6042. activeOpacity: 0.3,
  6043. border: false,
  6044. borderWidth: 2,
  6045. borderColor: '#FFFFFF',
  6046. fillOpacity: 1,
  6047. minSize: 0,
  6048. labelAlign: 'right',
  6049. linearType: 'none',
  6050. customColor: [],
  6051. }, opts.extra.funnel);
  6052. let eachSpacing = (opts.height - opts.area[0] - opts.area[2]) / series.length;
  6053. let centerPosition = {
  6054. x: opts.area[3] + (opts.width - opts.area[1] - opts.area[3]) / 2,
  6055. y: opts.height - opts.area[2]
  6056. };
  6057. let activeWidth = funnelOption.activeWidth * opts.pix;
  6058. let radius = Math.min((opts.width - opts.area[1] - opts.area[3]) / 2 - activeWidth, (opts.height - opts.area[0] -
  6059. opts.area[2]) / 2 - activeWidth);
  6060. let seriesNew = getFunnelDataPoints(series, radius, funnelOption, eachSpacing, process);
  6061. context.save();
  6062. context.translate(centerPosition.x, centerPosition.y);
  6063. funnelOption.customColor = fillCustomColor(funnelOption.linearType, funnelOption.customColor, series, config);
  6064. if (funnelOption.type == 'pyramid') {
  6065. for (let i = 0; i < seriesNew.length; i++) {
  6066. if (i == seriesNew.length - 1) {
  6067. if (opts.tooltip) {
  6068. if (opts.tooltip.index == i) {
  6069. context.beginPath();
  6070. context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
  6071. context.moveTo(-activeWidth, -eachSpacing);
  6072. context.lineTo(-seriesNew[i].radius - activeWidth, 0);
  6073. context.lineTo(seriesNew[i].radius + activeWidth, 0);
  6074. context.lineTo(activeWidth, -eachSpacing);
  6075. context.lineTo(-activeWidth, -eachSpacing);
  6076. context.closePath();
  6077. context.fill();
  6078. }
  6079. }
  6080. seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (i +
  6081. 1), centerPosition.x + seriesNew[i].radius, centerPosition.y - eachSpacing * i];
  6082. context.beginPath();
  6083. context.setLineWidth(funnelOption.borderWidth * opts.pix);
  6084. context.setStrokeStyle(funnelOption.borderColor);
  6085. var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
  6086. if (funnelOption.linearType == 'custom') {
  6087. var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -
  6088. eachSpacing);
  6089. grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6090. grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption
  6091. .fillOpacity));
  6092. grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6093. fillColor = grd
  6094. }
  6095. context.setFillStyle(fillColor);
  6096. context.moveTo(0, -eachSpacing);
  6097. context.lineTo(-seriesNew[i].radius, 0);
  6098. context.lineTo(seriesNew[i].radius, 0);
  6099. context.lineTo(0, -eachSpacing);
  6100. context.closePath();
  6101. context.fill();
  6102. if (funnelOption.border == true) {
  6103. context.stroke();
  6104. }
  6105. } else {
  6106. if (opts.tooltip) {
  6107. if (opts.tooltip.index == i) {
  6108. context.beginPath();
  6109. context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
  6110. context.moveTo(0, 0);
  6111. context.lineTo(-seriesNew[i].radius - activeWidth, 0);
  6112. context.lineTo(-seriesNew[i + 1].radius - activeWidth, -eachSpacing);
  6113. context.lineTo(seriesNew[i + 1].radius + activeWidth, -eachSpacing);
  6114. context.lineTo(seriesNew[i].radius + activeWidth, 0);
  6115. context.lineTo(0, 0);
  6116. context.closePath();
  6117. context.fill();
  6118. }
  6119. }
  6120. seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (i +
  6121. 1), centerPosition.x + seriesNew[i].radius, centerPosition.y - eachSpacing * i];
  6122. context.beginPath();
  6123. context.setLineWidth(funnelOption.borderWidth * opts.pix);
  6124. context.setStrokeStyle(funnelOption.borderColor);
  6125. var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
  6126. if (funnelOption.linearType == 'custom') {
  6127. var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -
  6128. eachSpacing);
  6129. grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6130. grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption
  6131. .fillOpacity));
  6132. grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6133. fillColor = grd
  6134. }
  6135. context.setFillStyle(fillColor);
  6136. context.moveTo(0, 0);
  6137. context.lineTo(-seriesNew[i].radius, 0);
  6138. context.lineTo(-seriesNew[i + 1].radius, -eachSpacing);
  6139. context.lineTo(seriesNew[i + 1].radius, -eachSpacing);
  6140. context.lineTo(seriesNew[i].radius, 0);
  6141. context.lineTo(0, 0);
  6142. context.closePath();
  6143. context.fill();
  6144. if (funnelOption.border == true) {
  6145. context.stroke();
  6146. }
  6147. }
  6148. context.translate(0, -eachSpacing)
  6149. }
  6150. } else {
  6151. context.translate(0, -(seriesNew.length - 1) * eachSpacing);
  6152. for (let i = 0; i < seriesNew.length; i++) {
  6153. if (i == seriesNew.length - 1) {
  6154. if (opts.tooltip) {
  6155. if (opts.tooltip.index == i) {
  6156. context.beginPath();
  6157. context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
  6158. context.moveTo(-activeWidth - funnelOption.minSize / 2, 0);
  6159. context.lineTo(-seriesNew[i].radius - activeWidth, -eachSpacing);
  6160. context.lineTo(seriesNew[i].radius + activeWidth, -eachSpacing);
  6161. context.lineTo(activeWidth + funnelOption.minSize / 2, 0);
  6162. context.lineTo(-activeWidth - funnelOption.minSize / 2, 0);
  6163. context.closePath();
  6164. context.fill();
  6165. }
  6166. }
  6167. seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing,
  6168. centerPosition.x + seriesNew[i].radius, centerPosition.y
  6169. ];
  6170. context.beginPath();
  6171. context.setLineWidth(funnelOption.borderWidth * opts.pix);
  6172. context.setStrokeStyle(funnelOption.borderColor);
  6173. var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
  6174. if (funnelOption.linearType == 'custom') {
  6175. var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -
  6176. eachSpacing);
  6177. grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6178. grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption
  6179. .fillOpacity));
  6180. grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6181. fillColor = grd
  6182. }
  6183. context.setFillStyle(fillColor);
  6184. context.moveTo(0, 0);
  6185. context.lineTo(-funnelOption.minSize / 2, 0);
  6186. context.lineTo(-seriesNew[i].radius, -eachSpacing);
  6187. context.lineTo(seriesNew[i].radius, -eachSpacing);
  6188. context.lineTo(funnelOption.minSize / 2, 0);
  6189. context.lineTo(0, 0);
  6190. context.closePath();
  6191. context.fill();
  6192. if (funnelOption.border == true) {
  6193. context.stroke();
  6194. }
  6195. } else {
  6196. if (opts.tooltip) {
  6197. if (opts.tooltip.index == i) {
  6198. context.beginPath();
  6199. context.setFillStyle(hexToRgb(seriesNew[i].color, funnelOption.activeOpacity));
  6200. context.moveTo(0, 0);
  6201. context.lineTo(-seriesNew[i + 1].radius - activeWidth, 0);
  6202. context.lineTo(-seriesNew[i].radius - activeWidth, -eachSpacing);
  6203. context.lineTo(seriesNew[i].radius + activeWidth, -eachSpacing);
  6204. context.lineTo(seriesNew[i + 1].radius + activeWidth, 0);
  6205. context.lineTo(0, 0);
  6206. context.closePath();
  6207. context.fill();
  6208. }
  6209. }
  6210. seriesNew[i].funnelArea = [centerPosition.x - seriesNew[i].radius, centerPosition.y - eachSpacing * (
  6211. seriesNew.length - i), centerPosition.x + seriesNew[i].radius, centerPosition.y -
  6212. eachSpacing * (seriesNew.length - i - 1)
  6213. ];
  6214. context.beginPath();
  6215. context.setLineWidth(funnelOption.borderWidth * opts.pix);
  6216. context.setStrokeStyle(funnelOption.borderColor);
  6217. var fillColor = hexToRgb(seriesNew[i].color, funnelOption.fillOpacity);
  6218. if (funnelOption.linearType == 'custom') {
  6219. var grd = context.createLinearGradient(seriesNew[i].radius, -eachSpacing, -seriesNew[i].radius, -
  6220. eachSpacing);
  6221. grd.addColorStop(0, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6222. grd.addColorStop(0.5, hexToRgb(funnelOption.customColor[seriesNew[i].linearIndex], funnelOption
  6223. .fillOpacity));
  6224. grd.addColorStop(1, hexToRgb(seriesNew[i].color, funnelOption.fillOpacity));
  6225. fillColor = grd
  6226. }
  6227. context.setFillStyle(fillColor);
  6228. context.moveTo(0, 0);
  6229. context.lineTo(-seriesNew[i + 1].radius, 0);
  6230. context.lineTo(-seriesNew[i].radius, -eachSpacing);
  6231. context.lineTo(seriesNew[i].radius, -eachSpacing);
  6232. context.lineTo(seriesNew[i + 1].radius, 0);
  6233. context.lineTo(0, 0);
  6234. context.closePath();
  6235. context.fill();
  6236. if (funnelOption.border == true) {
  6237. context.stroke();
  6238. }
  6239. }
  6240. context.translate(0, eachSpacing)
  6241. }
  6242. }
  6243. context.restore();
  6244. if (opts.dataLabel !== false && process === 1) {
  6245. drawFunnelText(seriesNew, opts, context, eachSpacing, funnelOption.labelAlign, activeWidth, centerPosition);
  6246. }
  6247. if (process === 1) {
  6248. drawFunnelCenterText(seriesNew, opts, context, eachSpacing, funnelOption.labelAlign, activeWidth,
  6249. centerPosition);
  6250. }
  6251. return {
  6252. center: centerPosition,
  6253. radius: radius,
  6254. series: seriesNew
  6255. };
  6256. }
  6257. function drawFunnelText(series, opts, context, eachSpacing, labelAlign, activeWidth, centerPosition) {
  6258. for (let i = 0; i < series.length; i++) {
  6259. let item = series[i];
  6260. if (item.labelShow === false) {
  6261. continue;
  6262. }
  6263. let startX, endX, startY, fontSize;
  6264. let text = item.formatter ? item.formatter(item, i, series, opts) : util.toFixed(item._proportion_ * 100) + '%';
  6265. text = item.labelText ? item.labelText : text;
  6266. if (labelAlign == 'right') {
  6267. if (i == series.length - 1) {
  6268. startX = (item.funnelArea[2] + centerPosition.x) / 2;
  6269. } else {
  6270. startX = (item.funnelArea[2] + series[i + 1].funnelArea[2]) / 2;
  6271. }
  6272. endX = startX + activeWidth * 2;
  6273. startY = item.funnelArea[1] + eachSpacing / 2;
  6274. fontSize = item.textSize * opts.pix || opts.fontSize * opts.pix;
  6275. context.setLineWidth(1 * opts.pix);
  6276. context.setStrokeStyle(item.color);
  6277. context.setFillStyle(item.color);
  6278. context.beginPath();
  6279. context.moveTo(startX, startY);
  6280. context.lineTo(endX, startY);
  6281. context.stroke();
  6282. context.closePath();
  6283. context.beginPath();
  6284. context.moveTo(endX, startY);
  6285. context.arc(endX, startY, 2 * opts.pix, 0, 2 * Math.PI);
  6286. context.closePath();
  6287. context.fill();
  6288. context.beginPath();
  6289. context.setFontSize(fontSize);
  6290. context.setFillStyle(item.textColor || opts.fontColor);
  6291. context.fillText(text, endX + 5, startY + fontSize / 2 - 2);
  6292. context.closePath();
  6293. context.stroke();
  6294. context.closePath();
  6295. }
  6296. if (labelAlign == 'left') {
  6297. if (i == series.length - 1) {
  6298. startX = (item.funnelArea[0] + centerPosition.x) / 2;
  6299. } else {
  6300. startX = (item.funnelArea[0] + series[i + 1].funnelArea[0]) / 2;
  6301. }
  6302. endX = startX - activeWidth * 2;
  6303. startY = item.funnelArea[1] + eachSpacing / 2;
  6304. fontSize = item.textSize * opts.pix || opts.fontSize * opts.pix;
  6305. context.setLineWidth(1 * opts.pix);
  6306. context.setStrokeStyle(item.color);
  6307. context.setFillStyle(item.color);
  6308. context.beginPath();
  6309. context.moveTo(startX, startY);
  6310. context.lineTo(endX, startY);
  6311. context.stroke();
  6312. context.closePath();
  6313. context.beginPath();
  6314. context.moveTo(endX, startY);
  6315. context.arc(endX, startY, 2, 0, 2 * Math.PI);
  6316. context.closePath();
  6317. context.fill();
  6318. context.beginPath();
  6319. context.setFontSize(fontSize);
  6320. context.setFillStyle(item.textColor || opts.fontColor);
  6321. context.fillText(text, endX - 5 - measureText(text, fontSize, context), startY + fontSize / 2 - 2);
  6322. context.closePath();
  6323. context.stroke();
  6324. context.closePath();
  6325. }
  6326. }
  6327. }
  6328. function drawFunnelCenterText(series, opts, context, eachSpacing, labelAlign, activeWidth, centerPosition) {
  6329. for (let i = 0; i < series.length; i++) {
  6330. let item = series[i];
  6331. let startY, fontSize;
  6332. if (item.centerText) {
  6333. startY = item.funnelArea[1] + eachSpacing / 2;
  6334. fontSize = item.centerTextSize * opts.pix || opts.fontSize * opts.pix;
  6335. context.beginPath();
  6336. context.setFontSize(fontSize);
  6337. context.setFillStyle(item.centerTextColor || "#FFFFFF");
  6338. context.fillText(item.centerText, centerPosition.x - measureText(item.centerText, fontSize, context) / 2,
  6339. startY + fontSize / 2 - 2);
  6340. context.closePath();
  6341. context.stroke();
  6342. context.closePath();
  6343. }
  6344. }
  6345. }
  6346. function drawCanvas(opts, context) {
  6347. context.save();
  6348. context.translate(0, 0.5);
  6349. context.restore();
  6350. context.draw();
  6351. }
  6352. var Timing = {
  6353. easeIn: function easeIn(pos) {
  6354. return Math.pow(pos, 3);
  6355. },
  6356. easeOut: function easeOut(pos) {
  6357. return Math.pow(pos - 1, 3) + 1;
  6358. },
  6359. easeInOut: function easeInOut(pos) {
  6360. if ((pos /= 0.5) < 1) {
  6361. return 0.5 * Math.pow(pos, 3);
  6362. } else {
  6363. return 0.5 * (Math.pow(pos - 2, 3) + 2);
  6364. }
  6365. },
  6366. linear: function linear(pos) {
  6367. return pos;
  6368. }
  6369. };
  6370. function Animation(opts) {
  6371. this.isStop = false;
  6372. opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;
  6373. opts.timing = opts.timing || 'easeInOut';
  6374. var delay = 17;
  6375. function createAnimationFrame() {
  6376. if (typeof setTimeout !== 'undefined') {
  6377. return function(step, delay) {
  6378. setTimeout(function() {
  6379. var timeStamp = +new Date();
  6380. step(timeStamp);
  6381. }, delay);
  6382. };
  6383. } else if (typeof requestAnimationFrame !== 'undefined') {
  6384. return requestAnimationFrame;
  6385. } else {
  6386. return function(step) {
  6387. step(null);
  6388. };
  6389. }
  6390. };
  6391. var animationFrame = createAnimationFrame();
  6392. var startTimeStamp = null;
  6393. var _step = function step(timestamp) {
  6394. if (timestamp === null || this.isStop === true) {
  6395. opts.onProcess && opts.onProcess(1);
  6396. opts.onAnimationFinish && opts.onAnimationFinish();
  6397. return;
  6398. }
  6399. if (startTimeStamp === null) {
  6400. startTimeStamp = timestamp;
  6401. }
  6402. if (timestamp - startTimeStamp < opts.duration) {
  6403. var process = (timestamp - startTimeStamp) / opts.duration;
  6404. var timingFunction = Timing[opts.timing];
  6405. process = timingFunction(process);
  6406. opts.onProcess && opts.onProcess(process);
  6407. animationFrame(_step, delay);
  6408. } else {
  6409. opts.onProcess && opts.onProcess(1);
  6410. opts.onAnimationFinish && opts.onAnimationFinish();
  6411. }
  6412. };
  6413. _step = _step.bind(this);
  6414. animationFrame(_step, delay);
  6415. }
  6416. Animation.prototype.stop = function() {
  6417. this.isStop = true;
  6418. };
  6419. function drawCharts(type, opts, config, context) {
  6420. var _this = this;
  6421. var series = opts.series;
  6422. //兼容ECharts饼图类数据格式
  6423. if (type === 'pie' || type === 'ring' || type === 'mount' || type === 'rose' || type === 'funnel') {
  6424. series = fixPieSeries(series, opts, config);
  6425. }
  6426. var categories = opts.categories;
  6427. if (type === 'mount') {
  6428. categories = [];
  6429. for (let j = 0; j < series.length; j++) {
  6430. if (series[j].show !== false) categories.push(series[j].name)
  6431. }
  6432. opts.categories = categories;
  6433. }
  6434. series = fillSeries(series, opts, config);
  6435. var duration = opts.animation ? opts.duration : 0;
  6436. _this.animationInstance && _this.animationInstance.stop();
  6437. var seriesMA = null;
  6438. if (type == 'candle') {
  6439. let average = assign({}, opts.extra.candle.average);
  6440. if (average.show) {
  6441. seriesMA = calCandleMA(average.day, average.name, average.color, series[0].data);
  6442. seriesMA = fillSeries(seriesMA, opts, config);
  6443. opts.seriesMA = seriesMA;
  6444. } else if (opts.seriesMA) {
  6445. seriesMA = opts.seriesMA = fillSeries(opts.seriesMA, opts, config);
  6446. } else {
  6447. seriesMA = series;
  6448. }
  6449. } else {
  6450. seriesMA = series;
  6451. }
  6452. /* 过滤掉show=false的series */
  6453. opts._series_ = series = filterSeries(series);
  6454. //重新计算图表区域
  6455. opts.area = new Array(4);
  6456. //复位绘图区域
  6457. for (let j = 0; j < 4; j++) {
  6458. opts.area[j] = opts.padding[j] * opts.pix;
  6459. }
  6460. //通过计算三大区域:图例、X轴、Y轴的大小,确定绘图区域
  6461. var _calLegendData = calLegendData(seriesMA, opts, config, opts.chartData, context),
  6462. legendHeight = _calLegendData.area.wholeHeight,
  6463. legendWidth = _calLegendData.area.wholeWidth;
  6464. switch (opts.legend.position) {
  6465. case 'top':
  6466. opts.area[0] += legendHeight;
  6467. break;
  6468. case 'bottom':
  6469. opts.area[2] += legendHeight;
  6470. break;
  6471. case 'left':
  6472. opts.area[3] += legendWidth;
  6473. break;
  6474. case 'right':
  6475. opts.area[1] += legendWidth;
  6476. break;
  6477. }
  6478. let _calYAxisData = {},
  6479. yAxisWidth = 0;
  6480. if (opts.type === 'line' || opts.type === 'column' || opts.type === 'mount' || opts.type === 'area' || opts.type ===
  6481. 'mix' || opts.type === 'candle' || opts.type === 'scatter' || opts.type === 'bubble' || opts.type === 'bar') {
  6482. _calYAxisData = calYAxisData(series, opts, config, context);
  6483. yAxisWidth = _calYAxisData.yAxisWidth;
  6484. //如果显示Y轴标题
  6485. if (opts.yAxis.showTitle) {
  6486. let maxTitleHeight = 0;
  6487. for (let i = 0; i < opts.yAxis.data.length; i++) {
  6488. maxTitleHeight = Math.max(maxTitleHeight, opts.yAxis.data[i].titleFontSize ? opts.yAxis.data[i]
  6489. .titleFontSize * opts.pix : config.fontSize)
  6490. }
  6491. opts.area[0] += maxTitleHeight;
  6492. }
  6493. let rightIndex = 0,
  6494. leftIndex = 0;
  6495. //计算主绘图区域左右位置
  6496. for (let i = 0; i < yAxisWidth.length; i++) {
  6497. if (yAxisWidth[i].position == 'left') {
  6498. if (leftIndex > 0) {
  6499. opts.area[3] += yAxisWidth[i].width + opts.yAxis.padding * opts.pix;
  6500. } else {
  6501. opts.area[3] += yAxisWidth[i].width;
  6502. }
  6503. leftIndex += 1;
  6504. } else if (yAxisWidth[i].position == 'right') {
  6505. if (rightIndex > 0) {
  6506. opts.area[1] += yAxisWidth[i].width + opts.yAxis.padding * opts.pix;
  6507. } else {
  6508. opts.area[1] += yAxisWidth[i].width;
  6509. }
  6510. rightIndex += 1;
  6511. }
  6512. }
  6513. } else {
  6514. config.yAxisWidth = yAxisWidth;
  6515. }
  6516. opts.chartData.yAxisData = _calYAxisData;
  6517. if (opts.categories && opts.categories.length && opts.type !== 'radar' && opts.type !== 'gauge' && opts.type !==
  6518. 'bar') {
  6519. opts.chartData.xAxisData = getXAxisPoints(opts.categories, opts, config);
  6520. let _calCategoriesData = calCategoriesData(opts.categories, opts, config, opts.chartData.xAxisData.eachSpacing,
  6521. context),
  6522. xAxisHeight = _calCategoriesData.xAxisHeight,
  6523. angle = _calCategoriesData.angle;
  6524. config.xAxisHeight = xAxisHeight;
  6525. config._xAxisTextAngle_ = angle;
  6526. opts.area[2] += xAxisHeight;
  6527. opts.chartData.categoriesData = _calCategoriesData;
  6528. } else {
  6529. if (opts.type === 'line' || opts.type === 'area' || opts.type === 'scatter' || opts.type === 'bubble' || opts
  6530. .type === 'bar') {
  6531. opts.chartData.xAxisData = calXAxisData(series, opts, config, context);
  6532. categories = opts.chartData.xAxisData.rangesFormat;
  6533. let _calCategoriesData = calCategoriesData(categories, opts, config, opts.chartData.xAxisData.eachSpacing,
  6534. context),
  6535. xAxisHeight = _calCategoriesData.xAxisHeight,
  6536. angle = _calCategoriesData.angle;
  6537. config.xAxisHeight = xAxisHeight;
  6538. config._xAxisTextAngle_ = angle;
  6539. opts.area[2] += xAxisHeight;
  6540. opts.chartData.categoriesData = _calCategoriesData;
  6541. } else {
  6542. opts.chartData.xAxisData = {
  6543. xAxisPoints: []
  6544. };
  6545. }
  6546. }
  6547. //计算右对齐偏移距离
  6548. if (opts.enableScroll && opts.xAxis.scrollAlign == 'right' && opts._scrollDistance_ === undefined) {
  6549. let offsetLeft = 0,
  6550. xAxisPoints = opts.chartData.xAxisData.xAxisPoints,
  6551. startX = opts.chartData.xAxisData.startX,
  6552. endX = opts.chartData.xAxisData.endX,
  6553. eachSpacing = opts.chartData.xAxisData.eachSpacing;
  6554. let totalWidth = eachSpacing * (xAxisPoints.length - 1);
  6555. let screenWidth = endX - startX;
  6556. offsetLeft = screenWidth - totalWidth;
  6557. _this.scrollOption.currentOffset = offsetLeft;
  6558. _this.scrollOption.startTouchX = offsetLeft;
  6559. _this.scrollOption.distance = 0;
  6560. _this.scrollOption.lastMoveTime = 0;
  6561. opts._scrollDistance_ = offsetLeft;
  6562. }
  6563. if (type === 'pie' || type === 'ring' || type === 'rose') {
  6564. config._pieTextMaxLength_ = opts.dataLabel === false ? 0 : getPieTextMaxLength(seriesMA, config, context, opts);
  6565. }
  6566. switch (type) {
  6567. case 'word':
  6568. this.animationInstance = new Animation({
  6569. timing: opts.timing,
  6570. duration: duration,
  6571. onProcess: function(process) {
  6572. context.clearRect(0, 0, opts.width, opts.height);
  6573. if (opts.rotate) {
  6574. contextRotate(context, opts);
  6575. }
  6576. drawWordCloudDataPoints(series, opts, config, context, process);
  6577. drawCanvas(opts, context);
  6578. },
  6579. onAnimationFinish: function onAnimationFinish() {
  6580. _this.uevent.trigger('renderComplete');
  6581. }
  6582. });
  6583. break;
  6584. case 'map':
  6585. context.clearRect(0, 0, opts.width, opts.height);
  6586. drawMapDataPoints(series, opts, config, context);
  6587. setTimeout(() => {
  6588. this.uevent.trigger('renderComplete');
  6589. }, 50)
  6590. break;
  6591. case 'funnel':
  6592. this.animationInstance = new Animation({
  6593. timing: opts.timing,
  6594. duration: duration,
  6595. onProcess: function(process) {
  6596. context.clearRect(0, 0, opts.width, opts.height);
  6597. if (opts.rotate) {
  6598. contextRotate(context, opts);
  6599. }
  6600. opts.chartData.funnelData = drawFunnelDataPoints(series, opts, config, context,
  6601. process);
  6602. drawLegend(opts.series, opts, config, context, opts.chartData);
  6603. drawToolTipBridge(opts, config, context, process);
  6604. drawCanvas(opts, context);
  6605. },
  6606. onAnimationFinish: function onAnimationFinish() {
  6607. _this.uevent.trigger('renderComplete');
  6608. }
  6609. });
  6610. break;
  6611. case 'line':
  6612. this.animationInstance = new Animation({
  6613. timing: opts.timing,
  6614. duration: duration,
  6615. onProcess: function onProcess(process) {
  6616. context.clearRect(0, 0, opts.width, opts.height);
  6617. if (opts.rotate) {
  6618. contextRotate(context, opts);
  6619. }
  6620. drawYAxisGrid(categories, opts, config, context);
  6621. drawXAxis(categories, opts, config, context);
  6622. var _drawLineDataPoints = drawLineDataPoints(series, opts, config, context, process),
  6623. xAxisPoints = _drawLineDataPoints.xAxisPoints,
  6624. calPoints = _drawLineDataPoints.calPoints,
  6625. eachSpacing = _drawLineDataPoints.eachSpacing;
  6626. opts.chartData.xAxisPoints = xAxisPoints;
  6627. opts.chartData.calPoints = calPoints;
  6628. opts.chartData.eachSpacing = eachSpacing;
  6629. drawYAxis(series, opts, config, context);
  6630. if (opts.enableMarkLine !== false && process === 1) {
  6631. drawMarkLine(opts, config, context);
  6632. }
  6633. drawLegend(opts.series, opts, config, context, opts.chartData);
  6634. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6635. drawCanvas(opts, context);
  6636. },
  6637. onAnimationFinish: function onAnimationFinish() {
  6638. _this.uevent.trigger('renderComplete');
  6639. }
  6640. });
  6641. break;
  6642. case 'scatter':
  6643. this.animationInstance = new Animation({
  6644. timing: opts.timing,
  6645. duration: duration,
  6646. onProcess: function onProcess(process) {
  6647. context.clearRect(0, 0, opts.width, opts.height);
  6648. if (opts.rotate) {
  6649. contextRotate(context, opts);
  6650. }
  6651. drawYAxisGrid(categories, opts, config, context);
  6652. drawXAxis(categories, opts, config, context);
  6653. var _drawScatterDataPoints = drawScatterDataPoints(series, opts, config, context,
  6654. process),
  6655. xAxisPoints = _drawScatterDataPoints.xAxisPoints,
  6656. calPoints = _drawScatterDataPoints.calPoints,
  6657. eachSpacing = _drawScatterDataPoints.eachSpacing;
  6658. opts.chartData.xAxisPoints = xAxisPoints;
  6659. opts.chartData.calPoints = calPoints;
  6660. opts.chartData.eachSpacing = eachSpacing;
  6661. drawYAxis(series, opts, config, context);
  6662. if (opts.enableMarkLine !== false && process === 1) {
  6663. drawMarkLine(opts, config, context);
  6664. }
  6665. drawLegend(opts.series, opts, config, context, opts.chartData);
  6666. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6667. drawCanvas(opts, context);
  6668. },
  6669. onAnimationFinish: function onAnimationFinish() {
  6670. _this.uevent.trigger('renderComplete');
  6671. }
  6672. });
  6673. break;
  6674. case 'bubble':
  6675. this.animationInstance = new Animation({
  6676. timing: opts.timing,
  6677. duration: duration,
  6678. onProcess: function onProcess(process) {
  6679. context.clearRect(0, 0, opts.width, opts.height);
  6680. if (opts.rotate) {
  6681. contextRotate(context, opts);
  6682. }
  6683. drawYAxisGrid(categories, opts, config, context);
  6684. drawXAxis(categories, opts, config, context);
  6685. var _drawBubbleDataPoints = drawBubbleDataPoints(series, opts, config, context,
  6686. process),
  6687. xAxisPoints = _drawBubbleDataPoints.xAxisPoints,
  6688. calPoints = _drawBubbleDataPoints.calPoints,
  6689. eachSpacing = _drawBubbleDataPoints.eachSpacing;
  6690. opts.chartData.xAxisPoints = xAxisPoints;
  6691. opts.chartData.calPoints = calPoints;
  6692. opts.chartData.eachSpacing = eachSpacing;
  6693. drawYAxis(series, opts, config, context);
  6694. if (opts.enableMarkLine !== false && process === 1) {
  6695. drawMarkLine(opts, config, context);
  6696. }
  6697. drawLegend(opts.series, opts, config, context, opts.chartData);
  6698. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6699. drawCanvas(opts, context);
  6700. },
  6701. onAnimationFinish: function onAnimationFinish() {
  6702. _this.uevent.trigger('renderComplete');
  6703. }
  6704. });
  6705. break;
  6706. case 'mix':
  6707. this.animationInstance = new Animation({
  6708. timing: opts.timing,
  6709. duration: duration,
  6710. onProcess: function onProcess(process) {
  6711. context.clearRect(0, 0, opts.width, opts.height);
  6712. if (opts.rotate) {
  6713. contextRotate(context, opts);
  6714. }
  6715. drawYAxisGrid(categories, opts, config, context);
  6716. drawXAxis(categories, opts, config, context);
  6717. var _drawMixDataPoints = drawMixDataPoints(series, opts, config, context, process),
  6718. xAxisPoints = _drawMixDataPoints.xAxisPoints,
  6719. calPoints = _drawMixDataPoints.calPoints,
  6720. eachSpacing = _drawMixDataPoints.eachSpacing;
  6721. opts.chartData.xAxisPoints = xAxisPoints;
  6722. opts.chartData.calPoints = calPoints;
  6723. opts.chartData.eachSpacing = eachSpacing;
  6724. drawYAxis(series, opts, config, context);
  6725. if (opts.enableMarkLine !== false && process === 1) {
  6726. drawMarkLine(opts, config, context);
  6727. }
  6728. drawLegend(opts.series, opts, config, context, opts.chartData);
  6729. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6730. drawCanvas(opts, context);
  6731. },
  6732. onAnimationFinish: function onAnimationFinish() {
  6733. _this.uevent.trigger('renderComplete');
  6734. }
  6735. });
  6736. break;
  6737. case 'column':
  6738. this.animationInstance = new Animation({
  6739. timing: opts.timing,
  6740. duration: duration,
  6741. onProcess: function onProcess(process) {
  6742. context.clearRect(0, 0, opts.width, opts.height);
  6743. if (opts.rotate) {
  6744. contextRotate(context, opts);
  6745. }
  6746. drawYAxisGrid(categories, opts, config, context);
  6747. drawXAxis(categories, opts, config, context);
  6748. var _drawColumnDataPoints = drawColumnDataPoints(series, opts, config, context,
  6749. process),
  6750. xAxisPoints = _drawColumnDataPoints.xAxisPoints,
  6751. calPoints = _drawColumnDataPoints.calPoints,
  6752. eachSpacing = _drawColumnDataPoints.eachSpacing;
  6753. opts.chartData.xAxisPoints = xAxisPoints;
  6754. opts.chartData.calPoints = calPoints;
  6755. opts.chartData.eachSpacing = eachSpacing;
  6756. drawYAxis(series, opts, config, context);
  6757. if (opts.enableMarkLine !== false && process === 1) {
  6758. drawMarkLine(opts, config, context);
  6759. }
  6760. drawLegend(opts.series, opts, config, context, opts.chartData);
  6761. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6762. drawCanvas(opts, context);
  6763. },
  6764. onAnimationFinish: function onAnimationFinish() {
  6765. _this.uevent.trigger('renderComplete');
  6766. }
  6767. });
  6768. break;
  6769. case 'mount':
  6770. this.animationInstance = new Animation({
  6771. timing: opts.timing,
  6772. duration: duration,
  6773. onProcess: function onProcess(process) {
  6774. context.clearRect(0, 0, opts.width, opts.height);
  6775. if (opts.rotate) {
  6776. contextRotate(context, opts);
  6777. }
  6778. drawYAxisGrid(categories, opts, config, context);
  6779. drawXAxis(categories, opts, config, context);
  6780. var _drawMountDataPoints = drawMountDataPoints(series, opts, config, context, process),
  6781. xAxisPoints = _drawMountDataPoints.xAxisPoints,
  6782. calPoints = _drawMountDataPoints.calPoints,
  6783. eachSpacing = _drawMountDataPoints.eachSpacing;
  6784. opts.chartData.xAxisPoints = xAxisPoints;
  6785. opts.chartData.calPoints = calPoints;
  6786. opts.chartData.eachSpacing = eachSpacing;
  6787. drawYAxis(series, opts, config, context);
  6788. if (opts.enableMarkLine !== false && process === 1) {
  6789. drawMarkLine(opts, config, context);
  6790. }
  6791. drawLegend(opts.series, opts, config, context, opts.chartData);
  6792. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6793. drawCanvas(opts, context);
  6794. },
  6795. onAnimationFinish: function onAnimationFinish() {
  6796. _this.uevent.trigger('renderComplete');
  6797. }
  6798. });
  6799. break;
  6800. case 'bar':
  6801. this.animationInstance = new Animation({
  6802. timing: opts.timing,
  6803. duration: duration,
  6804. onProcess: function onProcess(process) {
  6805. context.clearRect(0, 0, opts.width, opts.height);
  6806. if (opts.rotate) {
  6807. contextRotate(context, opts);
  6808. }
  6809. drawXAxis(categories, opts, config, context);
  6810. var _drawBarDataPoints = drawBarDataPoints(series, opts, config, context, process),
  6811. yAxisPoints = _drawBarDataPoints.yAxisPoints,
  6812. calPoints = _drawBarDataPoints.calPoints,
  6813. eachSpacing = _drawBarDataPoints.eachSpacing;
  6814. opts.chartData.yAxisPoints = yAxisPoints;
  6815. opts.chartData.xAxisPoints = opts.chartData.xAxisData.xAxisPoints;
  6816. opts.chartData.calPoints = calPoints;
  6817. opts.chartData.eachSpacing = eachSpacing;
  6818. drawYAxis(series, opts, config, context);
  6819. if (opts.enableMarkLine !== false && process === 1) {
  6820. drawMarkLine(opts, config, context);
  6821. }
  6822. drawLegend(opts.series, opts, config, context, opts.chartData);
  6823. drawToolTipBridge(opts, config, context, process, eachSpacing, yAxisPoints);
  6824. drawCanvas(opts, context);
  6825. },
  6826. onAnimationFinish: function onAnimationFinish() {
  6827. _this.uevent.trigger('renderComplete');
  6828. }
  6829. });
  6830. break;
  6831. case 'area':
  6832. this.animationInstance = new Animation({
  6833. timing: opts.timing,
  6834. duration: duration,
  6835. onProcess: function onProcess(process) {
  6836. context.clearRect(0, 0, opts.width, opts.height);
  6837. if (opts.rotate) {
  6838. contextRotate(context, opts);
  6839. }
  6840. drawYAxisGrid(categories, opts, config, context);
  6841. drawXAxis(categories, opts, config, context);
  6842. var _drawAreaDataPoints = drawAreaDataPoints(series, opts, config, context, process),
  6843. xAxisPoints = _drawAreaDataPoints.xAxisPoints,
  6844. calPoints = _drawAreaDataPoints.calPoints,
  6845. eachSpacing = _drawAreaDataPoints.eachSpacing;
  6846. opts.chartData.xAxisPoints = xAxisPoints;
  6847. opts.chartData.calPoints = calPoints;
  6848. opts.chartData.eachSpacing = eachSpacing;
  6849. drawYAxis(series, opts, config, context);
  6850. if (opts.enableMarkLine !== false && process === 1) {
  6851. drawMarkLine(opts, config, context);
  6852. }
  6853. drawLegend(opts.series, opts, config, context, opts.chartData);
  6854. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  6855. drawCanvas(opts, context);
  6856. },
  6857. onAnimationFinish: function onAnimationFinish() {
  6858. _this.uevent.trigger('renderComplete');
  6859. }
  6860. });
  6861. break;
  6862. case 'ring':
  6863. this.animationInstance = new Animation({
  6864. timing: opts.timing,
  6865. duration: duration,
  6866. onProcess: function onProcess(process) {
  6867. context.clearRect(0, 0, opts.width, opts.height);
  6868. if (opts.rotate) {
  6869. contextRotate(context, opts);
  6870. }
  6871. opts.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
  6872. drawLegend(opts.series, opts, config, context, opts.chartData);
  6873. drawToolTipBridge(opts, config, context, process);
  6874. drawCanvas(opts, context);
  6875. },
  6876. onAnimationFinish: function onAnimationFinish() {
  6877. _this.uevent.trigger('renderComplete');
  6878. }
  6879. });
  6880. break;
  6881. case 'pie':
  6882. this.animationInstance = new Animation({
  6883. timing: opts.timing,
  6884. duration: duration,
  6885. onProcess: function onProcess(process) {
  6886. context.clearRect(0, 0, opts.width, opts.height);
  6887. if (opts.rotate) {
  6888. contextRotate(context, opts);
  6889. }
  6890. opts.chartData.pieData = drawPieDataPoints(series, opts, config, context, process);
  6891. drawLegend(opts.series, opts, config, context, opts.chartData);
  6892. drawToolTipBridge(opts, config, context, process);
  6893. drawCanvas(opts, context);
  6894. },
  6895. onAnimationFinish: function onAnimationFinish() {
  6896. _this.uevent.trigger('renderComplete');
  6897. }
  6898. });
  6899. break;
  6900. case 'rose':
  6901. this.animationInstance = new Animation({
  6902. timing: opts.timing,
  6903. duration: duration,
  6904. onProcess: function onProcess(process) {
  6905. context.clearRect(0, 0, opts.width, opts.height);
  6906. if (opts.rotate) {
  6907. contextRotate(context, opts);
  6908. }
  6909. opts.chartData.pieData = drawRoseDataPoints(series, opts, config, context, process);
  6910. drawLegend(opts.series, opts, config, context, opts.chartData);
  6911. drawToolTipBridge(opts, config, context, process);
  6912. drawCanvas(opts, context);
  6913. },
  6914. onAnimationFinish: function onAnimationFinish() {
  6915. _this.uevent.trigger('renderComplete');
  6916. }
  6917. });
  6918. break;
  6919. case 'radar':
  6920. this.animationInstance = new Animation({
  6921. timing: opts.timing,
  6922. duration: duration,
  6923. onProcess: function onProcess(process) {
  6924. context.clearRect(0, 0, opts.width, opts.height);
  6925. if (opts.rotate) {
  6926. contextRotate(context, opts);
  6927. }
  6928. opts.chartData.radarData = drawRadarDataPoints(series, opts, config, context, process);
  6929. drawLegend(opts.series, opts, config, context, opts.chartData);
  6930. drawToolTipBridge(opts, config, context, process);
  6931. drawCanvas(opts, context);
  6932. },
  6933. onAnimationFinish: function onAnimationFinish() {
  6934. _this.uevent.trigger('renderComplete');
  6935. }
  6936. });
  6937. break;
  6938. case 'arcbar':
  6939. this.animationInstance = new Animation({
  6940. timing: opts.timing,
  6941. duration: duration,
  6942. onProcess: function onProcess(process) {
  6943. context.clearRect(0, 0, opts.width, opts.height);
  6944. if (opts.rotate) {
  6945. contextRotate(context, opts);
  6946. }
  6947. opts.chartData.arcbarData = drawArcbarDataPoints(series, opts, config, context,
  6948. process);
  6949. drawCanvas(opts, context);
  6950. },
  6951. onAnimationFinish: function onAnimationFinish() {
  6952. _this.uevent.trigger('renderComplete');
  6953. }
  6954. });
  6955. break;
  6956. case 'gauge':
  6957. this.animationInstance = new Animation({
  6958. timing: opts.timing,
  6959. duration: duration,
  6960. onProcess: function onProcess(process) {
  6961. context.clearRect(0, 0, opts.width, opts.height);
  6962. if (opts.rotate) {
  6963. contextRotate(context, opts);
  6964. }
  6965. opts.chartData.gaugeData = drawGaugeDataPoints(categories, series, opts, config,
  6966. context, process);
  6967. drawCanvas(opts, context);
  6968. },
  6969. onAnimationFinish: function onAnimationFinish() {
  6970. _this.uevent.trigger('renderComplete');
  6971. }
  6972. });
  6973. break;
  6974. case 'candle':
  6975. this.animationInstance = new Animation({
  6976. timing: opts.timing,
  6977. duration: duration,
  6978. onProcess: function onProcess(process) {
  6979. context.clearRect(0, 0, opts.width, opts.height);
  6980. if (opts.rotate) {
  6981. contextRotate(context, opts);
  6982. }
  6983. drawYAxisGrid(categories, opts, config, context);
  6984. drawXAxis(categories, opts, config, context);
  6985. var _drawCandleDataPoints = drawCandleDataPoints(series, seriesMA, opts, config,
  6986. context, process),
  6987. xAxisPoints = _drawCandleDataPoints.xAxisPoints,
  6988. calPoints = _drawCandleDataPoints.calPoints,
  6989. eachSpacing = _drawCandleDataPoints.eachSpacing;
  6990. opts.chartData.xAxisPoints = xAxisPoints;
  6991. opts.chartData.calPoints = calPoints;
  6992. opts.chartData.eachSpacing = eachSpacing;
  6993. drawYAxis(series, opts, config, context);
  6994. if (opts.enableMarkLine !== false && process === 1) {
  6995. drawMarkLine(opts, config, context);
  6996. }
  6997. if (seriesMA) {
  6998. drawLegend(seriesMA, opts, config, context, opts.chartData);
  6999. } else {
  7000. drawLegend(opts.series, opts, config, context, opts.chartData);
  7001. }
  7002. drawToolTipBridge(opts, config, context, process, eachSpacing, xAxisPoints);
  7003. drawCanvas(opts, context);
  7004. },
  7005. onAnimationFinish: function onAnimationFinish() {
  7006. _this.uevent.trigger('renderComplete');
  7007. }
  7008. });
  7009. break;
  7010. }
  7011. }
  7012. function uChartsEvent() {
  7013. this.events = {};
  7014. }
  7015. uChartsEvent.prototype.addEventListener = function(type, listener) {
  7016. this.events[type] = this.events[type] || [];
  7017. this.events[type].push(listener);
  7018. };
  7019. uChartsEvent.prototype.delEventListener = function(type) {
  7020. this.events[type] = [];
  7021. };
  7022. uChartsEvent.prototype.trigger = function() {
  7023. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  7024. args[_key] = arguments[_key];
  7025. }
  7026. var type = args[0];
  7027. var params = args.slice(1);
  7028. if (!!this.events[type]) {
  7029. this.events[type].forEach(function(listener) {
  7030. try {
  7031. listener.apply(null, params);
  7032. } catch (e) {
  7033. //console.log('[uCharts] '+e);
  7034. }
  7035. });
  7036. }
  7037. };
  7038. var uCharts = function uCharts(opts) {
  7039. opts.pix = opts.pixelRatio ? opts.pixelRatio : 1;
  7040. opts.fontSize = opts.fontSize ? opts.fontSize : 13;
  7041. opts.fontColor = opts.fontColor ? opts.fontColor : config.fontColor;
  7042. if (opts.background == "" || opts.background == "none") {
  7043. opts.background = "#FFFFFF"
  7044. }
  7045. opts.title = assign({}, opts.title);
  7046. opts.subtitle = assign({}, opts.subtitle);
  7047. opts.duration = opts.duration ? opts.duration : 1000;
  7048. opts.yAxis = assign({}, {
  7049. data: [],
  7050. showTitle: false,
  7051. disabled: false,
  7052. disableGrid: false,
  7053. gridSet: 'number',
  7054. splitNumber: 5,
  7055. gridType: 'solid',
  7056. dashLength: 4 * opts.pix,
  7057. gridColor: '#cccccc',
  7058. padding: 10,
  7059. fontColor: '#666666'
  7060. }, opts.yAxis);
  7061. opts.xAxis = assign({}, {
  7062. rotateLabel: false,
  7063. rotateAngle: 45,
  7064. disabled: false,
  7065. disableGrid: false,
  7066. splitNumber: 5,
  7067. calibration: false,
  7068. fontColor: '#666666',
  7069. fontSize: 13,
  7070. lineHeight: 20,
  7071. marginTop: 0,
  7072. gridType: 'solid',
  7073. dashLength: 4,
  7074. scrollAlign: 'left',
  7075. boundaryGap: 'center',
  7076. axisLine: true,
  7077. axisLineColor: '#cccccc',
  7078. titleFontSize: 13,
  7079. titleOffsetY: 0,
  7080. titleOffsetX: 0,
  7081. titleFontColor: '#666666'
  7082. }, opts.xAxis);
  7083. opts.xAxis.scrollPosition = opts.xAxis.scrollAlign;
  7084. opts.legend = assign({}, {
  7085. show: true,
  7086. position: 'bottom',
  7087. float: 'center',
  7088. backgroundColor: 'rgba(0,0,0,0)',
  7089. borderColor: 'rgba(0,0,0,0)',
  7090. borderWidth: 0,
  7091. padding: 5,
  7092. margin: 5,
  7093. itemGap: 10,
  7094. fontSize: opts.fontSize,
  7095. lineHeight: opts.fontSize,
  7096. fontColor: opts.fontColor,
  7097. formatter: {},
  7098. hiddenColor: '#CECECE'
  7099. }, opts.legend);
  7100. opts.extra = assign({
  7101. tooltip: {
  7102. legendShape: 'auto'
  7103. }
  7104. }, opts.extra);
  7105. opts.rotate = opts.rotate ? true : false;
  7106. opts.animation = opts.animation ? true : false;
  7107. opts.rotate = opts.rotate ? true : false;
  7108. opts.canvas2d = opts.canvas2d ? true : false;
  7109. let config$$1 = assign({}, config);
  7110. config$$1.color = opts.color ? opts.color : config$$1.color;
  7111. if (opts.type == 'pie') {
  7112. config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.pie.labelWidth * opts.pix ||
  7113. config$$1.pieChartLinePadding * opts.pix;
  7114. }
  7115. if (opts.type == 'ring') {
  7116. config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.ring.labelWidth * opts.pix ||
  7117. config$$1.pieChartLinePadding * opts.pix;
  7118. }
  7119. if (opts.type == 'rose') {
  7120. config$$1.pieChartLinePadding = opts.dataLabel === false ? 0 : opts.extra.rose.labelWidth * opts.pix ||
  7121. config$$1.pieChartLinePadding * opts.pix;
  7122. }
  7123. config$$1.pieChartTextPadding = opts.dataLabel === false ? 0 : config$$1.pieChartTextPadding * opts.pix;
  7124. //屏幕旋转
  7125. config$$1.rotate = opts.rotate;
  7126. if (opts.rotate) {
  7127. let tempWidth = opts.width;
  7128. let tempHeight = opts.height;
  7129. opts.width = tempHeight;
  7130. opts.height = tempWidth;
  7131. }
  7132. //适配高分屏
  7133. opts.padding = opts.padding ? opts.padding : config$$1.padding;
  7134. config$$1.yAxisWidth = config.yAxisWidth * opts.pix;
  7135. config$$1.fontSize = opts.fontSize * opts.pix;
  7136. config$$1.titleFontSize = config.titleFontSize * opts.pix;
  7137. config$$1.subtitleFontSize = config.subtitleFontSize * opts.pix;
  7138. if (!opts.context) {
  7139. throw new Error('[uCharts] 未获取到context!注意:v2.0版本后,需要自行获取canvas的绘图上下文并传入opts.context!');
  7140. }
  7141. this.context = opts.context;
  7142. if (!this.context.setTextAlign) {
  7143. this.context.setStrokeStyle = function(e) {
  7144. return this.strokeStyle = e;
  7145. }
  7146. this.context.setLineWidth = function(e) {
  7147. return this.lineWidth = e;
  7148. }
  7149. this.context.setLineCap = function(e) {
  7150. return this.lineCap = e;
  7151. }
  7152. this.context.setFontSize = function(e) {
  7153. return this.font = e + "px sans-serif";
  7154. }
  7155. this.context.setFillStyle = function(e) {
  7156. return this.fillStyle = e;
  7157. }
  7158. this.context.setTextAlign = function(e) {
  7159. return this.textAlign = e;
  7160. }
  7161. this.context.setTextBaseline = function(e) {
  7162. return this.textBaseline = e;
  7163. }
  7164. this.context.setShadow = function(offsetX, offsetY, blur, color) {
  7165. this.shadowColor = color;
  7166. this.shadowOffsetX = offsetX;
  7167. this.shadowOffsetY = offsetY;
  7168. this.shadowBlur = blur;
  7169. }
  7170. this.context.draw = function() {}
  7171. }
  7172. //兼容NVUEsetLineDash
  7173. if (!this.context.setLineDash) {
  7174. this.context.setLineDash = function(e) {}
  7175. }
  7176. opts.chartData = {};
  7177. this.uevent = new uChartsEvent();
  7178. this.scrollOption = {
  7179. currentOffset: 0,
  7180. startTouchX: 0,
  7181. distance: 0,
  7182. lastMoveTime: 0
  7183. };
  7184. this.opts = opts;
  7185. this.config = config$$1;
  7186. drawCharts.call(this, opts.type, opts, config$$1, this.context);
  7187. };
  7188. uCharts.prototype.updateData = function() {
  7189. let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  7190. this.opts = assign({}, this.opts, data);
  7191. this.opts.updateData = true;
  7192. let scrollPosition = data.scrollPosition || 'current';
  7193. switch (scrollPosition) {
  7194. case 'current':
  7195. this.opts._scrollDistance_ = this.scrollOption.currentOffset;
  7196. break;
  7197. case 'left':
  7198. this.opts._scrollDistance_ = 0;
  7199. this.scrollOption = {
  7200. currentOffset: 0,
  7201. startTouchX: 0,
  7202. distance: 0,
  7203. lastMoveTime: 0
  7204. };
  7205. break;
  7206. case 'right':
  7207. let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config, this.context),
  7208. yAxisWidth = _calYAxisData.yAxisWidth;
  7209. this.config.yAxisWidth = yAxisWidth;
  7210. let offsetLeft = 0;
  7211. let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
  7212. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  7213. startX = _getXAxisPoints0.startX,
  7214. endX = _getXAxisPoints0.endX,
  7215. eachSpacing = _getXAxisPoints0.eachSpacing;
  7216. let totalWidth = eachSpacing * (xAxisPoints.length - 1);
  7217. let screenWidth = endX - startX;
  7218. offsetLeft = screenWidth - totalWidth;
  7219. this.scrollOption = {
  7220. currentOffset: offsetLeft,
  7221. startTouchX: offsetLeft,
  7222. distance: 0,
  7223. lastMoveTime: 0
  7224. };
  7225. this.opts._scrollDistance_ = offsetLeft;
  7226. break;
  7227. }
  7228. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  7229. };
  7230. uCharts.prototype.zoom = function() {
  7231. var val = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.opts.xAxis.itemCount;
  7232. if (this.opts.enableScroll !== true) {
  7233. console.log('[uCharts] 请启用滚动条后使用')
  7234. return;
  7235. }
  7236. //当前屏幕中间点
  7237. let centerPoint = Math.round(Math.abs(this.scrollOption.currentOffset) / this.opts.chartData.eachSpacing) + Math
  7238. .round(this.opts.xAxis.itemCount / 2);
  7239. this.opts.animation = false;
  7240. this.opts.xAxis.itemCount = val.itemCount;
  7241. //重新计算x轴偏移距离
  7242. let _calYAxisData = calYAxisData(this.opts.series, this.opts, this.config, this.context),
  7243. yAxisWidth = _calYAxisData.yAxisWidth;
  7244. this.config.yAxisWidth = yAxisWidth;
  7245. let offsetLeft = 0;
  7246. let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
  7247. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  7248. startX = _getXAxisPoints0.startX,
  7249. endX = _getXAxisPoints0.endX,
  7250. eachSpacing = _getXAxisPoints0.eachSpacing;
  7251. let centerLeft = eachSpacing * centerPoint;
  7252. let screenWidth = endX - startX;
  7253. let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
  7254. offsetLeft = screenWidth / 2 - centerLeft;
  7255. if (offsetLeft > 0) {
  7256. offsetLeft = 0;
  7257. }
  7258. if (offsetLeft < MaxLeft) {
  7259. offsetLeft = MaxLeft;
  7260. }
  7261. this.scrollOption = {
  7262. currentOffset: offsetLeft,
  7263. startTouchX: 0,
  7264. distance: 0,
  7265. lastMoveTime: 0
  7266. };
  7267. calValidDistance(this, offsetLeft, this.opts.chartData, this.config, this.opts);
  7268. this.opts._scrollDistance_ = offsetLeft;
  7269. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  7270. };
  7271. uCharts.prototype.dobuleZoom = function(e) {
  7272. if (this.opts.enableScroll !== true) {
  7273. console.log('[uCharts] 请启用滚动条后使用')
  7274. return;
  7275. }
  7276. const tcs = e.changedTouches;
  7277. if (tcs.length < 2) {
  7278. return;
  7279. }
  7280. for (var i = 0; i < tcs.length; i++) {
  7281. tcs[i].x = tcs[i].x ? tcs[i].x : tcs[i].clientX;
  7282. tcs[i].y = tcs[i].y ? tcs[i].y : tcs[i].clientY;
  7283. }
  7284. const ntcs = [getTouches(tcs[0], this.opts, e), getTouches(tcs[1], this.opts, e)];
  7285. const xlength = Math.abs(ntcs[0].x - ntcs[1].x);
  7286. // 记录初始的两指之间的数据
  7287. if (!this.scrollOption.moveCount) {
  7288. let cts0 = {
  7289. changedTouches: [{
  7290. x: tcs[0].x,
  7291. y: this.opts.area[0] / this.opts.pix + 2
  7292. }]
  7293. };
  7294. let cts1 = {
  7295. changedTouches: [{
  7296. x: tcs[1].x,
  7297. y: this.opts.area[0] / this.opts.pix + 2
  7298. }]
  7299. };
  7300. if (this.opts.rotate) {
  7301. cts0 = {
  7302. changedTouches: [{
  7303. x: this.opts.height / this.opts.pix - this.opts.area[0] / this.opts.pix - 2,
  7304. y: tcs[0].y
  7305. }]
  7306. };
  7307. cts1 = {
  7308. changedTouches: [{
  7309. x: this.opts.height / this.opts.pix - this.opts.area[0] / this.opts.pix - 2,
  7310. y: tcs[1].y
  7311. }]
  7312. };
  7313. }
  7314. const moveCurrent1 = this.getCurrentDataIndex(cts0).index;
  7315. const moveCurrent2 = this.getCurrentDataIndex(cts1).index;
  7316. const moveCount = Math.abs(moveCurrent1 - moveCurrent2);
  7317. this.scrollOption.moveCount = moveCount;
  7318. this.scrollOption.moveCurrent1 = Math.min(moveCurrent1, moveCurrent2);
  7319. this.scrollOption.moveCurrent2 = Math.max(moveCurrent1, moveCurrent2);
  7320. return;
  7321. }
  7322. let currentEachSpacing = xlength / this.scrollOption.moveCount;
  7323. let itemCount = (this.opts.width - this.opts.area[1] - this.opts.area[3]) / currentEachSpacing;
  7324. itemCount = itemCount <= 2 ? 2 : itemCount;
  7325. itemCount = itemCount >= this.opts.categories.length ? this.opts.categories.length : itemCount;
  7326. this.opts.animation = false;
  7327. this.opts.xAxis.itemCount = itemCount;
  7328. // 重新计算滚动条偏移距离
  7329. let offsetLeft = 0;
  7330. let _getXAxisPoints0 = getXAxisPoints(this.opts.categories, this.opts, this.config),
  7331. xAxisPoints = _getXAxisPoints0.xAxisPoints,
  7332. startX = _getXAxisPoints0.startX,
  7333. endX = _getXAxisPoints0.endX,
  7334. eachSpacing = _getXAxisPoints0.eachSpacing;
  7335. let currentLeft = eachSpacing * this.scrollOption.moveCurrent1;
  7336. let screenWidth = endX - startX;
  7337. let MaxLeft = screenWidth - eachSpacing * (xAxisPoints.length - 1);
  7338. offsetLeft = -currentLeft + Math.min(ntcs[0].x, ntcs[1].x) - this.opts.area[3] - eachSpacing;
  7339. if (offsetLeft > 0) {
  7340. offsetLeft = 0;
  7341. }
  7342. if (offsetLeft < MaxLeft) {
  7343. offsetLeft = MaxLeft;
  7344. }
  7345. this.scrollOption.currentOffset = offsetLeft;
  7346. this.scrollOption.startTouchX = 0;
  7347. this.scrollOption.distance = 0;
  7348. calValidDistance(this, offsetLeft, this.opts.chartData, this.config, this.opts);
  7349. this.opts._scrollDistance_ = offsetLeft;
  7350. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  7351. }
  7352. uCharts.prototype.stopAnimation = function() {
  7353. this.animationInstance && this.animationInstance.stop();
  7354. };
  7355. uCharts.prototype.addEventListener = function(type, listener) {
  7356. this.uevent.addEventListener(type, listener);
  7357. };
  7358. uCharts.prototype.delEventListener = function(type) {
  7359. this.uevent.delEventListener(type);
  7360. };
  7361. uCharts.prototype.getCurrentDataIndex = function(e) {
  7362. var touches = null;
  7363. if (e.changedTouches) {
  7364. touches = e.changedTouches[0];
  7365. } else {
  7366. touches = e.mp.changedTouches[0];
  7367. }
  7368. if (touches) {
  7369. let _touches$ = getTouches(touches, this.opts, e);
  7370. if (this.opts.type === 'pie' || this.opts.type === 'ring') {
  7371. return findPieChartCurrentIndex({
  7372. x: _touches$.x,
  7373. y: _touches$.y
  7374. }, this.opts.chartData.pieData, this.opts);
  7375. } else if (this.opts.type === 'rose') {
  7376. return findRoseChartCurrentIndex({
  7377. x: _touches$.x,
  7378. y: _touches$.y
  7379. }, this.opts.chartData.pieData, this.opts);
  7380. } else if (this.opts.type === 'radar') {
  7381. return findRadarChartCurrentIndex({
  7382. x: _touches$.x,
  7383. y: _touches$.y
  7384. }, this.opts.chartData.radarData, this.opts.categories.length);
  7385. } else if (this.opts.type === 'funnel') {
  7386. return findFunnelChartCurrentIndex({
  7387. x: _touches$.x,
  7388. y: _touches$.y
  7389. }, this.opts.chartData.funnelData);
  7390. } else if (this.opts.type === 'map') {
  7391. return findMapChartCurrentIndex({
  7392. x: _touches$.x,
  7393. y: _touches$.y
  7394. }, this.opts);
  7395. } else if (this.opts.type === 'word') {
  7396. return findWordChartCurrentIndex({
  7397. x: _touches$.x,
  7398. y: _touches$.y
  7399. }, this.opts.chartData.wordCloudData);
  7400. } else if (this.opts.type === 'bar') {
  7401. return findBarChartCurrentIndex({
  7402. x: _touches$.x,
  7403. y: _touches$.y
  7404. }, this.opts.chartData.calPoints, this.opts, this.config, Math.abs(this.scrollOption
  7405. .currentOffset));
  7406. } else {
  7407. return findCurrentIndex({
  7408. x: _touches$.x,
  7409. y: _touches$.y
  7410. }, this.opts.chartData.calPoints, this.opts, this.config, Math.abs(this.scrollOption
  7411. .currentOffset));
  7412. }
  7413. }
  7414. return -1;
  7415. };
  7416. uCharts.prototype.getLegendDataIndex = function(e) {
  7417. var touches = null;
  7418. if (e.changedTouches) {
  7419. touches = e.changedTouches[0];
  7420. } else {
  7421. touches = e.mp.changedTouches[0];
  7422. }
  7423. if (touches) {
  7424. let _touches$ = getTouches(touches, this.opts, e);
  7425. return findLegendIndex({
  7426. x: _touches$.x,
  7427. y: _touches$.y
  7428. }, this.opts.chartData.legendData);
  7429. }
  7430. return -1;
  7431. };
  7432. uCharts.prototype.touchLegend = function(e) {
  7433. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  7434. var touches = null;
  7435. if (e.changedTouches) {
  7436. touches = e.changedTouches[0];
  7437. } else {
  7438. touches = e.mp.changedTouches[0];
  7439. }
  7440. if (touches) {
  7441. var _touches$ = getTouches(touches, this.opts, e);
  7442. var index = this.getLegendDataIndex(e);
  7443. if (index >= 0) {
  7444. if (this.opts.type == 'candle') {
  7445. this.opts.seriesMA[index].show = !this.opts.seriesMA[index].show;
  7446. } else {
  7447. this.opts.series[index].show = !this.opts.series[index].show;
  7448. }
  7449. this.opts.animation = option.animation ? true : false;
  7450. this.opts._scrollDistance_ = this.scrollOption.currentOffset;
  7451. drawCharts.call(this, this.opts.type, this.opts, this.config, this.context);
  7452. }
  7453. }
  7454. };
  7455. uCharts.prototype.showToolTip = function(e) {
  7456. var option = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  7457. var touches = null;
  7458. if (e.changedTouches) {
  7459. touches = e.changedTouches[0];
  7460. } else {
  7461. touches = e.mp.changedTouches[0];
  7462. }
  7463. if (!touches) {
  7464. console.log("[uCharts] 未获取到event坐标信息");
  7465. }
  7466. var _touches$ = getTouches(touches, this.opts, e);
  7467. var currentOffset = this.scrollOption.currentOffset;
  7468. var opts = assign({}, this.opts, {
  7469. _scrollDistance_: currentOffset,
  7470. animation: false
  7471. });
  7472. if (this.opts.type === 'line' || this.opts.type === 'area' || this.opts.type === 'column' || this.opts.type ===
  7473. 'scatter' || this.opts.type === 'bubble') {
  7474. var current = this.getCurrentDataIndex(e);
  7475. var index = option.index == undefined ? current.index : option.index;
  7476. if (index > -1 || index.length > 0) {
  7477. var seriesData = getSeriesDataItem(this.opts.series, index, current.group);
  7478. if (seriesData.length !== 0) {
  7479. var _getToolTipData = getToolTipData(seriesData, this.opts, index, current.group, this.opts
  7480. .categories, option),
  7481. textList = _getToolTipData.textList,
  7482. offset = _getToolTipData.offset;
  7483. offset.y = _touches$.y;
  7484. opts.tooltip = {
  7485. textList: option.textList !== undefined ? option.textList : textList,
  7486. offset: option.offset !== undefined ? option.offset : offset,
  7487. option: option,
  7488. index: index,
  7489. group: current.group
  7490. };
  7491. }
  7492. }
  7493. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7494. }
  7495. if (this.opts.type === 'mount') {
  7496. var index = option.index == undefined ? this.getCurrentDataIndex(e).index : option.index;
  7497. if (index > -1) {
  7498. var opts = assign({}, this.opts, {
  7499. animation: false
  7500. });
  7501. var seriesData = assign({}, opts._series_[index]);
  7502. var textList = [{
  7503. text: option.formatter ? option.formatter(seriesData, undefined, index, opts) : seriesData
  7504. .name + ': ' + seriesData.data,
  7505. color: seriesData.color,
  7506. legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this
  7507. .opts.extra.tooltip.legendShape
  7508. }];
  7509. var offset = {
  7510. x: opts.chartData.calPoints[index].x,
  7511. y: _touches$.y
  7512. };
  7513. opts.tooltip = {
  7514. textList: option.textList ? option.textList : textList,
  7515. offset: option.offset !== undefined ? option.offset : offset,
  7516. option: option,
  7517. index: index
  7518. };
  7519. }
  7520. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7521. }
  7522. if (this.opts.type === 'bar') {
  7523. var current = this.getCurrentDataIndex(e);
  7524. var index = option.index == undefined ? current.index : option.index;
  7525. if (index > -1 || index.length > 0) {
  7526. var seriesData = getSeriesDataItem(this.opts.series, index, current.group);
  7527. if (seriesData.length !== 0) {
  7528. var _getToolTipData = getToolTipData(seriesData, this.opts, index, current.group, this.opts
  7529. .categories, option),
  7530. textList = _getToolTipData.textList,
  7531. offset = _getToolTipData.offset;
  7532. offset.x = _touches$.x;
  7533. opts.tooltip = {
  7534. textList: option.textList !== undefined ? option.textList : textList,
  7535. offset: option.offset !== undefined ? option.offset : offset,
  7536. option: option,
  7537. index: index
  7538. };
  7539. }
  7540. }
  7541. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7542. }
  7543. if (this.opts.type === 'mix') {
  7544. var current = this.getCurrentDataIndex(e);
  7545. var index = option.index == undefined ? current.index : option.index;
  7546. if (index > -1) {
  7547. var currentOffset = this.scrollOption.currentOffset;
  7548. var opts = assign({}, this.opts, {
  7549. _scrollDistance_: currentOffset,
  7550. animation: false
  7551. });
  7552. var seriesData = getSeriesDataItem(this.opts.series, index);
  7553. if (seriesData.length !== 0) {
  7554. var _getMixToolTipData = getMixToolTipData(seriesData, this.opts, index, this.opts.categories,
  7555. option),
  7556. textList = _getMixToolTipData.textList,
  7557. offset = _getMixToolTipData.offset;
  7558. offset.y = _touches$.y;
  7559. opts.tooltip = {
  7560. textList: option.textList ? option.textList : textList,
  7561. offset: option.offset !== undefined ? option.offset : offset,
  7562. option: option,
  7563. index: index
  7564. };
  7565. }
  7566. }
  7567. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7568. }
  7569. if (this.opts.type === 'candle') {
  7570. var current = this.getCurrentDataIndex(e);
  7571. var index = option.index == undefined ? current.index : option.index;
  7572. if (index > -1) {
  7573. var currentOffset = this.scrollOption.currentOffset;
  7574. var opts = assign({}, this.opts, {
  7575. _scrollDistance_: currentOffset,
  7576. animation: false
  7577. });
  7578. var seriesData = getSeriesDataItem(this.opts.series, index);
  7579. if (seriesData.length !== 0) {
  7580. var _getToolTipData = getCandleToolTipData(this.opts.series[0].data, seriesData, this.opts, index,
  7581. this.opts.categories, this.opts.extra.candle, option),
  7582. textList = _getToolTipData.textList,
  7583. offset = _getToolTipData.offset;
  7584. offset.y = _touches$.y;
  7585. opts.tooltip = {
  7586. textList: option.textList ? option.textList : textList,
  7587. offset: option.offset !== undefined ? option.offset : offset,
  7588. option: option,
  7589. index: index
  7590. };
  7591. }
  7592. }
  7593. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7594. }
  7595. if (this.opts.type === 'pie' || this.opts.type === 'ring' || this.opts.type === 'rose' || this.opts.type ===
  7596. 'funnel') {
  7597. var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
  7598. if (index > -1) {
  7599. var opts = assign({}, this.opts, {
  7600. animation: false
  7601. });
  7602. var seriesData = assign({}, opts._series_[index]);
  7603. var textList = [{
  7604. text: option.formatter ? option.formatter(seriesData, undefined, index, opts) : seriesData
  7605. .name + ': ' + seriesData.data,
  7606. color: seriesData.color,
  7607. legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this
  7608. .opts.extra.tooltip.legendShape
  7609. }];
  7610. var offset = {
  7611. x: _touches$.x,
  7612. y: _touches$.y
  7613. };
  7614. opts.tooltip = {
  7615. textList: option.textList ? option.textList : textList,
  7616. offset: option.offset !== undefined ? option.offset : offset,
  7617. option: option,
  7618. index: index
  7619. };
  7620. }
  7621. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7622. }
  7623. if (this.opts.type === 'map') {
  7624. var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
  7625. if (index > -1) {
  7626. var opts = assign({}, this.opts, {
  7627. animation: false
  7628. });
  7629. var seriesData = assign({}, this.opts.series[index]);
  7630. seriesData.name = seriesData.properties.name
  7631. var textList = [{
  7632. text: option.formatter ? option.formatter(seriesData, undefined, index, this.opts) :
  7633. seriesData.name,
  7634. color: seriesData.color,
  7635. legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this
  7636. .opts.extra.tooltip.legendShape
  7637. }];
  7638. var offset = {
  7639. x: _touches$.x,
  7640. y: _touches$.y
  7641. };
  7642. opts.tooltip = {
  7643. textList: option.textList ? option.textList : textList,
  7644. offset: option.offset !== undefined ? option.offset : offset,
  7645. option: option,
  7646. index: index
  7647. };
  7648. }
  7649. opts.updateData = false;
  7650. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7651. }
  7652. if (this.opts.type === 'word') {
  7653. var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
  7654. if (index > -1) {
  7655. var opts = assign({}, this.opts, {
  7656. animation: false
  7657. });
  7658. var seriesData = assign({}, this.opts.series[index]);
  7659. var textList = [{
  7660. text: option.formatter ? option.formatter(seriesData, undefined, index, this.opts) :
  7661. seriesData.name,
  7662. color: seriesData.color,
  7663. legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? seriesData.legendShape : this
  7664. .opts.extra.tooltip.legendShape
  7665. }];
  7666. var offset = {
  7667. x: _touches$.x,
  7668. y: _touches$.y
  7669. };
  7670. opts.tooltip = {
  7671. textList: option.textList ? option.textList : textList,
  7672. offset: option.offset !== undefined ? option.offset : offset,
  7673. option: option,
  7674. index: index
  7675. };
  7676. }
  7677. opts.updateData = false;
  7678. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7679. }
  7680. if (this.opts.type === 'radar') {
  7681. var index = option.index == undefined ? this.getCurrentDataIndex(e) : option.index;
  7682. if (index > -1) {
  7683. var opts = assign({}, this.opts, {
  7684. animation: false
  7685. });
  7686. var seriesData = getSeriesDataItem(this.opts.series, index);
  7687. if (seriesData.length !== 0) {
  7688. var textList = seriesData.map((item) => {
  7689. return {
  7690. text: option.formatter ? option.formatter(item, this.opts.categories[index], index,
  7691. this.opts) : item.name + ': ' + item.data,
  7692. color: item.color,
  7693. legendShape: this.opts.extra.tooltip.legendShape == 'auto' ? item.legendShape : this
  7694. .opts.extra.tooltip.legendShape
  7695. };
  7696. });
  7697. var offset = {
  7698. x: _touches$.x,
  7699. y: _touches$.y
  7700. };
  7701. opts.tooltip = {
  7702. textList: option.textList ? option.textList : textList,
  7703. offset: option.offset !== undefined ? option.offset : offset,
  7704. option: option,
  7705. index: index
  7706. };
  7707. }
  7708. }
  7709. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7710. }
  7711. };
  7712. uCharts.prototype.translate = function(distance) {
  7713. this.scrollOption = {
  7714. currentOffset: distance,
  7715. startTouchX: distance,
  7716. distance: 0,
  7717. lastMoveTime: 0
  7718. };
  7719. let opts = assign({}, this.opts, {
  7720. _scrollDistance_: distance,
  7721. animation: false
  7722. });
  7723. drawCharts.call(this, this.opts.type, opts, this.config, this.context);
  7724. };
  7725. uCharts.prototype.scrollStart = function(e) {
  7726. var touches = null;
  7727. if (e.changedTouches) {
  7728. touches = e.changedTouches[0];
  7729. } else {
  7730. touches = e.mp.changedTouches[0];
  7731. }
  7732. var _touches$ = getTouches(touches, this.opts, e);
  7733. if (touches && this.opts.enableScroll === true) {
  7734. this.scrollOption.startTouchX = _touches$.x;
  7735. }
  7736. };
  7737. uCharts.prototype.scroll = function(e) {
  7738. if (this.scrollOption.lastMoveTime === 0) {
  7739. this.scrollOption.lastMoveTime = Date.now();
  7740. }
  7741. let Limit = this.opts.touchMoveLimit || 60;
  7742. let currMoveTime = Date.now();
  7743. let duration = currMoveTime - this.scrollOption.lastMoveTime;
  7744. if (duration < Math.floor(1000 / Limit)) return;
  7745. if (this.scrollOption.startTouchX == 0) return;
  7746. this.scrollOption.lastMoveTime = currMoveTime;
  7747. var touches = null;
  7748. if (e.changedTouches) {
  7749. touches = e.changedTouches[0];
  7750. } else {
  7751. touches = e.mp.changedTouches[0];
  7752. }
  7753. if (touches && this.opts.enableScroll === true) {
  7754. var _touches$ = getTouches(touches, this.opts, e);
  7755. var _distance;
  7756. _distance = _touches$.x - this.scrollOption.startTouchX;
  7757. var currentOffset = this.scrollOption.currentOffset;
  7758. var validDistance = calValidDistance(this, currentOffset + _distance, this.opts.chartData, this.config, this
  7759. .opts);
  7760. this.scrollOption.distance = _distance = validDistance - currentOffset;
  7761. var opts = assign({}, this.opts, {
  7762. _scrollDistance_: currentOffset + _distance,
  7763. animation: false
  7764. });
  7765. this.opts = opts;
  7766. drawCharts.call(this, opts.type, opts, this.config, this.context);
  7767. return currentOffset + _distance;
  7768. }
  7769. };
  7770. uCharts.prototype.scrollEnd = function(e) {
  7771. if (this.opts.enableScroll === true) {
  7772. var _scrollOption = this.scrollOption,
  7773. currentOffset = _scrollOption.currentOffset,
  7774. distance = _scrollOption.distance;
  7775. this.scrollOption.currentOffset = currentOffset + distance;
  7776. this.scrollOption.distance = 0;
  7777. this.scrollOption.moveCount = 0;
  7778. }
  7779. };
  7780. export default uCharts;