c3.js 301 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332
  1. (function (window) {
  2. 'use strict';
  3. /*global define, module, exports, require */
  4. var c3 = { version: "0.4.11-rc4" };
  5. var c3_chart_fn,
  6. c3_chart_internal_fn,
  7. c3_chart_internal_axis_fn;
  8. function API(owner) {
  9. this.owner = owner;
  10. }
  11. function inherit(base, derived) {
  12. if (Object.create) {
  13. derived.prototype = Object.create(base.prototype);
  14. } else {
  15. var f = function f() {};
  16. f.prototype = base.prototype;
  17. derived.prototype = new f();
  18. }
  19. derived.prototype.constructor = derived;
  20. return derived;
  21. }
  22. function Chart(config) {
  23. var $$ = this.internal = new ChartInternal(this);
  24. $$.loadConfig(config);
  25. $$.beforeInit(config);
  26. $$.init();
  27. $$.afterInit(config);
  28. // bind "this" to nested API
  29. (function bindThis(fn, target, argThis) {
  30. Object.keys(fn).forEach(function (key) {
  31. target[key] = fn[key].bind(argThis);
  32. if (Object.keys(fn[key]).length > 0) {
  33. bindThis(fn[key], target[key], argThis);
  34. }
  35. });
  36. })(c3_chart_fn, this, this);
  37. }
  38. function ChartInternal(api) {
  39. var $$ = this;
  40. $$.d3 = window.d3 ? window.d3 : typeof require !== 'undefined' ? require("d3") : undefined;
  41. $$.api = api;
  42. $$.config = $$.getDefaultConfig();
  43. $$.data = {};
  44. $$.cache = {};
  45. $$.axes = {};
  46. }
  47. c3.generate = function (config) {
  48. return new Chart(config);
  49. };
  50. c3.chart = {
  51. fn: Chart.prototype,
  52. internal: {
  53. fn: ChartInternal.prototype,
  54. axis: {
  55. fn: Axis.prototype
  56. }
  57. }
  58. };
  59. c3_chart_fn = c3.chart.fn;
  60. c3_chart_internal_fn = c3.chart.internal.fn;
  61. c3_chart_internal_axis_fn = c3.chart.internal.axis.fn;
  62. c3_chart_internal_fn.beforeInit = function () {
  63. // can do something
  64. };
  65. c3_chart_internal_fn.afterInit = function () {
  66. // can do something
  67. };
  68. c3_chart_internal_fn.init = function () {
  69. var $$ = this, config = $$.config;
  70. $$.initParams();
  71. if (config.data_url) {
  72. $$.convertUrlToData(config.data_url, config.data_mimeType, config.data_headers, config.data_keys, $$.initWithData);
  73. }
  74. else if (config.data_json) {
  75. $$.initWithData($$.convertJsonToData(config.data_json, config.data_keys));
  76. }
  77. else if (config.data_rows) {
  78. $$.initWithData($$.convertRowsToData(config.data_rows));
  79. }
  80. else if (config.data_columns) {
  81. $$.initWithData($$.convertColumnsToData(config.data_columns));
  82. }
  83. else {
  84. throw Error('url or json or rows or columns is required.');
  85. }
  86. };
  87. c3_chart_internal_fn.initParams = function () {
  88. var $$ = this, d3 = $$.d3, config = $$.config;
  89. // MEMO: clipId needs to be unique because it conflicts when multiple charts exist
  90. $$.clipId = "c3-" + (+new Date()) + '-clip',
  91. $$.clipIdForXAxis = $$.clipId + '-xaxis',
  92. $$.clipIdForYAxis = $$.clipId + '-yaxis',
  93. $$.clipIdForGrid = $$.clipId + '-grid',
  94. $$.clipIdForSubchart = $$.clipId + '-subchart',
  95. $$.clipPath = $$.getClipPath($$.clipId),
  96. $$.clipPathForXAxis = $$.getClipPath($$.clipIdForXAxis),
  97. $$.clipPathForYAxis = $$.getClipPath($$.clipIdForYAxis);
  98. $$.clipPathForGrid = $$.getClipPath($$.clipIdForGrid),
  99. $$.clipPathForSubchart = $$.getClipPath($$.clipIdForSubchart),
  100. $$.dragStart = null;
  101. $$.dragging = false;
  102. $$.flowing = false;
  103. $$.cancelClick = false;
  104. $$.mouseover = false;
  105. $$.transiting = false;
  106. $$.color = $$.generateColor();
  107. $$.levelColor = $$.generateLevelColor();
  108. $$.dataTimeFormat = config.data_xLocaltime ? d3.time.format : d3.time.format.utc;
  109. $$.axisTimeFormat = config.axis_x_localtime ? d3.time.format : d3.time.format.utc;
  110. $$.defaultAxisTimeFormat = $$.axisTimeFormat.multi([
  111. [".%L", function (d) { return d.getMilliseconds(); }],
  112. [":%S", function (d) { return d.getSeconds(); }],
  113. ["%I:%M", function (d) { return d.getMinutes(); }],
  114. ["%I %p", function (d) { return d.getHours(); }],
  115. ["%-m/%-d", function (d) { return d.getDay() && d.getDate() !== 1; }],
  116. ["%-m/%-d", function (d) { return d.getDate() !== 1; }],
  117. ["%-m/%-d", function (d) { return d.getMonth(); }],
  118. ["%Y/%-m/%-d", function () { return true; }]
  119. ]);
  120. $$.hiddenTargetIds = [];
  121. $$.hiddenLegendIds = [];
  122. $$.focusedTargetIds = [];
  123. $$.defocusedTargetIds = [];
  124. $$.xOrient = config.axis_rotated ? "left" : "bottom";
  125. $$.yOrient = config.axis_rotated ? (config.axis_y_inner ? "top" : "bottom") : (config.axis_y_inner ? "right" : "left");
  126. $$.y2Orient = config.axis_rotated ? (config.axis_y2_inner ? "bottom" : "top") : (config.axis_y2_inner ? "left" : "right");
  127. $$.subXOrient = config.axis_rotated ? "left" : "bottom";
  128. $$.isLegendRight = config.legend_position === 'right';
  129. $$.isLegendInset = config.legend_position === 'inset';
  130. $$.isLegendTop = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'top-right';
  131. $$.isLegendLeft = config.legend_inset_anchor === 'top-left' || config.legend_inset_anchor === 'bottom-left';
  132. $$.legendStep = 0;
  133. $$.legendItemWidth = 0;
  134. $$.legendItemHeight = 0;
  135. $$.currentMaxTickWidths = {
  136. x: 0,
  137. y: 0,
  138. y2: 0
  139. };
  140. $$.rotated_padding_left = 30;
  141. $$.rotated_padding_right = config.axis_rotated && !config.axis_x_show ? 0 : 30;
  142. $$.rotated_padding_top = 5;
  143. $$.withoutFadeIn = {};
  144. $$.intervalForObserveInserted = undefined;
  145. $$.axes.subx = d3.selectAll([]); // needs when excluding subchart.js
  146. };
  147. c3_chart_internal_fn.initChartElements = function () {
  148. if (this.initBar) { this.initBar(); }
  149. if (this.initLine) { this.initLine(); }
  150. if (this.initArc) { this.initArc(); }
  151. if (this.initGauge) { this.initGauge(); }
  152. if (this.initText) { this.initText(); }
  153. };
  154. c3_chart_internal_fn.initWithData = function (data) {
  155. var $$ = this, d3 = $$.d3, config = $$.config;
  156. var defs, main, binding = true;
  157. $$.axis = new Axis($$);
  158. if ($$.initPie) { $$.initPie(); }
  159. if ($$.initBrush) { $$.initBrush(); }
  160. if ($$.initZoom) { $$.initZoom(); }
  161. if (!config.bindto) {
  162. $$.selectChart = d3.selectAll([]);
  163. }
  164. else if (typeof config.bindto.node === 'function') {
  165. $$.selectChart = config.bindto;
  166. }
  167. else {
  168. $$.selectChart = d3.select(config.bindto);
  169. }
  170. if ($$.selectChart.empty()) {
  171. $$.selectChart = d3.select(document.createElement('div')).style('opacity', 0);
  172. $$.observeInserted($$.selectChart);
  173. binding = false;
  174. }
  175. $$.selectChart.html("").classed("c3", true);
  176. // Init data as targets
  177. $$.data.xs = {};
  178. $$.data.targets = $$.convertDataToTargets(data);
  179. if (config.data_filter) {
  180. $$.data.targets = $$.data.targets.filter(config.data_filter);
  181. }
  182. // Set targets to hide if needed
  183. if (config.data_hide) {
  184. $$.addHiddenTargetIds(config.data_hide === true ? $$.mapToIds($$.data.targets) : config.data_hide);
  185. }
  186. if (config.legend_hide) {
  187. $$.addHiddenLegendIds(config.legend_hide === true ? $$.mapToIds($$.data.targets) : config.legend_hide);
  188. }
  189. // when gauge, hide legend // TODO: fix
  190. if ($$.hasType('gauge')) {
  191. config.legend_show = false;
  192. }
  193. // Init sizes and scales
  194. $$.updateSizes();
  195. $$.updateScales();
  196. // Set domains for each scale
  197. $$.x.domain(d3.extent($$.getXDomain($$.data.targets)));
  198. $$.y.domain($$.getYDomain($$.data.targets, 'y'));
  199. $$.y2.domain($$.getYDomain($$.data.targets, 'y2'));
  200. $$.subX.domain($$.x.domain());
  201. $$.subY.domain($$.y.domain());
  202. $$.subY2.domain($$.y2.domain());
  203. // Save original x domain for zoom update
  204. $$.orgXDomain = $$.x.domain();
  205. // Set initialized scales to brush and zoom
  206. if ($$.brush) { $$.brush.scale($$.subX); }
  207. if (config.zoom_enabled) { $$.zoom.scale($$.x); }
  208. /*-- Basic Elements --*/
  209. // Define svgs
  210. $$.svg = $$.selectChart.append("svg")
  211. .style("overflow", "hidden")
  212. .on('mouseenter', function () { return config.onmouseover.call($$); })
  213. .on('mouseleave', function () { return config.onmouseout.call($$); });
  214. if ($$.config.svg_classname) {
  215. $$.svg.attr('class', $$.config.svg_classname);
  216. }
  217. // Define defs
  218. defs = $$.svg.append("defs");
  219. $$.clipChart = $$.appendClip(defs, $$.clipId);
  220. $$.clipXAxis = $$.appendClip(defs, $$.clipIdForXAxis);
  221. $$.clipYAxis = $$.appendClip(defs, $$.clipIdForYAxis);
  222. $$.clipGrid = $$.appendClip(defs, $$.clipIdForGrid);
  223. $$.clipSubchart = $$.appendClip(defs, $$.clipIdForSubchart);
  224. $$.updateSvgSize();
  225. // Define regions
  226. main = $$.main = $$.svg.append("g").attr("transform", $$.getTranslate('main'));
  227. if ($$.initSubchart) { $$.initSubchart(); }
  228. if ($$.initTooltip) { $$.initTooltip(); }
  229. if ($$.initLegend) { $$.initLegend(); }
  230. if ($$.initTitle) { $$.initTitle(); }
  231. /*-- Main Region --*/
  232. // text when empty
  233. main.append("text")
  234. .attr("class", CLASS.text + ' ' + CLASS.empty)
  235. .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers.
  236. .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE.
  237. // Regions
  238. $$.initRegion();
  239. // Grids
  240. $$.initGrid();
  241. // Define g for chart area
  242. main.append('g')
  243. .attr("clip-path", $$.clipPath)
  244. .attr('class', CLASS.chart);
  245. // Grid lines
  246. if (config.grid_lines_front) { $$.initGridLines(); }
  247. // Cover whole with rects for events
  248. $$.initEventRect();
  249. // Define g for chart
  250. $$.initChartElements();
  251. // if zoom privileged, insert rect to forefront
  252. // TODO: is this needed?
  253. main.insert('rect', config.zoom_privileged ? null : 'g.' + CLASS.regions)
  254. .attr('class', CLASS.zoomRect)
  255. .attr('width', $$.width)
  256. .attr('height', $$.height)
  257. .style('opacity', 0)
  258. .on("dblclick.zoom", null);
  259. // Set default extent if defined
  260. if (config.axis_x_extent) { $$.brush.extent($$.getDefaultExtent()); }
  261. // Add Axis
  262. $$.axis.init();
  263. // Set targets
  264. $$.updateTargets($$.data.targets);
  265. // Draw with targets
  266. if (binding) {
  267. $$.updateDimension();
  268. $$.config.oninit.call($$);
  269. $$.redraw({
  270. withTransition: false,
  271. withTransform: true,
  272. withUpdateXDomain: true,
  273. withUpdateOrgXDomain: true,
  274. withTransitionForAxis: false
  275. });
  276. }
  277. // Bind resize event
  278. $$.bindResize();
  279. // export element of the chart
  280. $$.api.element = $$.selectChart.node();
  281. };
  282. c3_chart_internal_fn.smoothLines = function (el, type) {
  283. var $$ = this;
  284. if (type === 'grid') {
  285. el.each(function () {
  286. var g = $$.d3.select(this),
  287. x1 = g.attr('x1'),
  288. x2 = g.attr('x2'),
  289. y1 = g.attr('y1'),
  290. y2 = g.attr('y2');
  291. g.attr({
  292. 'x1': Math.ceil(x1),
  293. 'x2': Math.ceil(x2),
  294. 'y1': Math.ceil(y1),
  295. 'y2': Math.ceil(y2)
  296. });
  297. });
  298. }
  299. };
  300. c3_chart_internal_fn.updateSizes = function () {
  301. var $$ = this, config = $$.config;
  302. var legendHeight = $$.legend ? $$.getLegendHeight() : 0,
  303. legendWidth = $$.legend ? $$.getLegendWidth() : 0,
  304. legendHeightForBottom = $$.isLegendRight || $$.isLegendInset ? 0 : legendHeight,
  305. hasArc = $$.hasArcType(),
  306. xAxisHeight = config.axis_rotated || hasArc ? 0 : $$.getHorizontalAxisHeight('x'),
  307. subchartHeight = config.subchart_show && !hasArc ? (config.subchart_size_height + xAxisHeight) : 0;
  308. $$.currentWidth = $$.getCurrentWidth();
  309. $$.currentHeight = $$.getCurrentHeight();
  310. // for main
  311. $$.margin = config.axis_rotated ? {
  312. top: $$.getHorizontalAxisHeight('y2') + $$.getCurrentPaddingTop(),
  313. right: hasArc ? 0 : $$.getCurrentPaddingRight(),
  314. bottom: $$.getHorizontalAxisHeight('y') + legendHeightForBottom + $$.getCurrentPaddingBottom(),
  315. left: subchartHeight + (hasArc ? 0 : $$.getCurrentPaddingLeft())
  316. } : {
  317. top: 4 + $$.getCurrentPaddingTop(), // for top tick text
  318. right: hasArc ? 0 : $$.getCurrentPaddingRight(),
  319. bottom: xAxisHeight + subchartHeight + legendHeightForBottom + $$.getCurrentPaddingBottom(),
  320. left: hasArc ? 0 : $$.getCurrentPaddingLeft()
  321. };
  322. // for subchart
  323. $$.margin2 = config.axis_rotated ? {
  324. top: $$.margin.top,
  325. right: NaN,
  326. bottom: 20 + legendHeightForBottom,
  327. left: $$.rotated_padding_left
  328. } : {
  329. top: $$.currentHeight - subchartHeight - legendHeightForBottom,
  330. right: NaN,
  331. bottom: xAxisHeight + legendHeightForBottom,
  332. left: $$.margin.left
  333. };
  334. // for legend
  335. $$.margin3 = {
  336. top: 0,
  337. right: NaN,
  338. bottom: 0,
  339. left: 0
  340. };
  341. if ($$.updateSizeForLegend) { $$.updateSizeForLegend(legendHeight, legendWidth); }
  342. $$.width = $$.currentWidth - $$.margin.left - $$.margin.right;
  343. $$.height = $$.currentHeight - $$.margin.top - $$.margin.bottom;
  344. if ($$.width < 0) { $$.width = 0; }
  345. if ($$.height < 0) { $$.height = 0; }
  346. $$.width2 = config.axis_rotated ? $$.margin.left - $$.rotated_padding_left - $$.rotated_padding_right : $$.width;
  347. $$.height2 = config.axis_rotated ? $$.height : $$.currentHeight - $$.margin2.top - $$.margin2.bottom;
  348. if ($$.width2 < 0) { $$.width2 = 0; }
  349. if ($$.height2 < 0) { $$.height2 = 0; }
  350. // for arc
  351. $$.arcWidth = $$.width - ($$.isLegendRight ? legendWidth + 10 : 0);
  352. $$.arcHeight = $$.height - ($$.isLegendRight ? 0 : 10);
  353. if ($$.hasType('gauge')) {
  354. $$.arcHeight += $$.height - $$.getGaugeLabelHeight();
  355. }
  356. if ($$.updateRadius) { $$.updateRadius(); }
  357. if ($$.isLegendRight && hasArc) {
  358. $$.margin3.left = $$.arcWidth / 2 + $$.radiusExpanded * 1.1;
  359. }
  360. };
  361. c3_chart_internal_fn.updateTargets = function (targets) {
  362. var $$ = this;
  363. /*-- Main --*/
  364. //-- Text --//
  365. $$.updateTargetsForText(targets);
  366. //-- Bar --//
  367. $$.updateTargetsForBar(targets);
  368. //-- Line --//
  369. $$.updateTargetsForLine(targets);
  370. //-- Arc --//
  371. if ($$.hasArcType() && $$.updateTargetsForArc) { $$.updateTargetsForArc(targets); }
  372. /*-- Sub --*/
  373. if ($$.updateTargetsForSubchart) { $$.updateTargetsForSubchart(targets); }
  374. // Fade-in each chart
  375. $$.showTargets();
  376. };
  377. c3_chart_internal_fn.showTargets = function () {
  378. var $$ = this;
  379. $$.svg.selectAll('.' + CLASS.target).filter(function (d) { return $$.isTargetToShow(d.id); })
  380. .transition().duration($$.config.transition_duration)
  381. .style("opacity", 1);
  382. };
  383. c3_chart_internal_fn.redraw = function (options, transitions) {
  384. var $$ = this, main = $$.main, d3 = $$.d3, config = $$.config;
  385. var areaIndices = $$.getShapeIndices($$.isAreaType), barIndices = $$.getShapeIndices($$.isBarType), lineIndices = $$.getShapeIndices($$.isLineType);
  386. var withY, withSubchart, withTransition, withTransitionForExit, withTransitionForAxis,
  387. withTransform, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain, withLegend,
  388. withEventRect, withDimension, withUpdateXAxis;
  389. var hideAxis = $$.hasArcType();
  390. var drawArea, drawBar, drawLine, xForText, yForText;
  391. var duration, durationForExit, durationForAxis;
  392. var waitForDraw, flow;
  393. var targetsToShow = $$.filterTargetsToShow($$.data.targets), tickValues, i, intervalForCulling, xDomainForZoom;
  394. var xv = $$.xv.bind($$), cx, cy;
  395. options = options || {};
  396. withY = getOption(options, "withY", true);
  397. withSubchart = getOption(options, "withSubchart", true);
  398. withTransition = getOption(options, "withTransition", true);
  399. withTransform = getOption(options, "withTransform", false);
  400. withUpdateXDomain = getOption(options, "withUpdateXDomain", false);
  401. withUpdateOrgXDomain = getOption(options, "withUpdateOrgXDomain", false);
  402. withTrimXDomain = getOption(options, "withTrimXDomain", true);
  403. withUpdateXAxis = getOption(options, "withUpdateXAxis", withUpdateXDomain);
  404. withLegend = getOption(options, "withLegend", false);
  405. withEventRect = getOption(options, "withEventRect", true);
  406. withDimension = getOption(options, "withDimension", true);
  407. withTransitionForExit = getOption(options, "withTransitionForExit", withTransition);
  408. withTransitionForAxis = getOption(options, "withTransitionForAxis", withTransition);
  409. duration = withTransition ? config.transition_duration : 0;
  410. durationForExit = withTransitionForExit ? duration : 0;
  411. durationForAxis = withTransitionForAxis ? duration : 0;
  412. transitions = transitions || $$.axis.generateTransitions(durationForAxis);
  413. // update legend and transform each g
  414. if (withLegend && config.legend_show) {
  415. $$.updateLegend($$.mapToIds($$.data.targets), options, transitions);
  416. } else if (withDimension) {
  417. // need to update dimension (e.g. axis.y.tick.values) because y tick values should change
  418. // no need to update axis in it because they will be updated in redraw()
  419. $$.updateDimension(true);
  420. }
  421. // MEMO: needed for grids calculation
  422. if ($$.isCategorized() && targetsToShow.length === 0) {
  423. $$.x.domain([0, $$.axes.x.selectAll('.tick').size()]);
  424. }
  425. if (targetsToShow.length) {
  426. $$.updateXDomain(targetsToShow, withUpdateXDomain, withUpdateOrgXDomain, withTrimXDomain);
  427. if (!config.axis_x_tick_values) {
  428. tickValues = $$.axis.updateXAxisTickValues(targetsToShow);
  429. }
  430. } else {
  431. $$.xAxis.tickValues([]);
  432. $$.subXAxis.tickValues([]);
  433. }
  434. if (config.zoom_rescale && !options.flow) {
  435. xDomainForZoom = $$.x.orgDomain();
  436. }
  437. $$.y.domain($$.getYDomain(targetsToShow, 'y', xDomainForZoom));
  438. $$.y2.domain($$.getYDomain(targetsToShow, 'y2', xDomainForZoom));
  439. if (!config.axis_y_tick_values && config.axis_y_tick_count) {
  440. $$.yAxis.tickValues($$.axis.generateTickValues($$.y.domain(), config.axis_y_tick_count));
  441. }
  442. if (!config.axis_y2_tick_values && config.axis_y2_tick_count) {
  443. $$.y2Axis.tickValues($$.axis.generateTickValues($$.y2.domain(), config.axis_y2_tick_count));
  444. }
  445. // axes
  446. $$.axis.redraw(transitions, hideAxis);
  447. // Update axis label
  448. $$.axis.updateLabels(withTransition);
  449. // show/hide if manual culling needed
  450. if ((withUpdateXDomain || withUpdateXAxis) && targetsToShow.length) {
  451. if (config.axis_x_tick_culling && tickValues) {
  452. for (i = 1; i < tickValues.length; i++) {
  453. if (tickValues.length / i < config.axis_x_tick_culling_max) {
  454. intervalForCulling = i;
  455. break;
  456. }
  457. }
  458. $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').each(function (e) {
  459. var index = tickValues.indexOf(e);
  460. if (index >= 0) {
  461. d3.select(this).style('display', index % intervalForCulling ? 'none' : 'block');
  462. }
  463. });
  464. } else {
  465. $$.svg.selectAll('.' + CLASS.axisX + ' .tick text').style('display', 'block');
  466. }
  467. }
  468. // setup drawer - MEMO: these must be called after axis updated
  469. drawArea = $$.generateDrawArea ? $$.generateDrawArea(areaIndices, false) : undefined;
  470. drawBar = $$.generateDrawBar ? $$.generateDrawBar(barIndices) : undefined;
  471. drawLine = $$.generateDrawLine ? $$.generateDrawLine(lineIndices, false) : undefined;
  472. xForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, true);
  473. yForText = $$.generateXYForText(areaIndices, barIndices, lineIndices, false);
  474. // Update sub domain
  475. if (withY) {
  476. $$.subY.domain($$.getYDomain(targetsToShow, 'y'));
  477. $$.subY2.domain($$.getYDomain(targetsToShow, 'y2'));
  478. }
  479. // xgrid focus
  480. $$.updateXgridFocus();
  481. // Data empty label positioning and text.
  482. main.select("text." + CLASS.text + '.' + CLASS.empty)
  483. .attr("x", $$.width / 2)
  484. .attr("y", $$.height / 2)
  485. .text(config.data_empty_label_text)
  486. .transition()
  487. .style('opacity', targetsToShow.length ? 0 : 1);
  488. // grid
  489. $$.updateGrid(duration);
  490. // rect for regions
  491. $$.updateRegion(duration);
  492. // bars
  493. $$.updateBar(durationForExit);
  494. // lines, areas and cricles
  495. $$.updateLine(durationForExit);
  496. $$.updateArea(durationForExit);
  497. $$.updateCircle();
  498. // text
  499. if ($$.hasDataLabel()) {
  500. $$.updateText(durationForExit);
  501. }
  502. // title
  503. if ($$.redrawTitle) { $$.redrawTitle(); }
  504. // arc
  505. if ($$.redrawArc) { $$.redrawArc(duration, durationForExit, withTransform); }
  506. // subchart
  507. if ($$.redrawSubchart) {
  508. $$.redrawSubchart(withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices);
  509. }
  510. // circles for select
  511. main.selectAll('.' + CLASS.selectedCircles)
  512. .filter($$.isBarType.bind($$))
  513. .selectAll('circle')
  514. .remove();
  515. // event rects will redrawn when flow called
  516. if (config.interaction_enabled && !options.flow && withEventRect) {
  517. $$.redrawEventRect();
  518. if ($$.updateZoom) { $$.updateZoom(); }
  519. }
  520. // update circleY based on updated parameters
  521. $$.updateCircleY();
  522. // generate circle x/y functions depending on updated params
  523. cx = ($$.config.axis_rotated ? $$.circleY : $$.circleX).bind($$);
  524. cy = ($$.config.axis_rotated ? $$.circleX : $$.circleY).bind($$);
  525. if (options.flow) {
  526. flow = $$.generateFlow({
  527. targets: targetsToShow,
  528. flow: options.flow,
  529. duration: options.flow.duration,
  530. drawBar: drawBar,
  531. drawLine: drawLine,
  532. drawArea: drawArea,
  533. cx: cx,
  534. cy: cy,
  535. xv: xv,
  536. xForText: xForText,
  537. yForText: yForText
  538. });
  539. }
  540. if ((duration || flow) && $$.isTabVisible()) { // Only use transition if tab visible. See #938.
  541. // transition should be derived from one transition
  542. d3.transition().duration(duration).each(function () {
  543. var transitionsToWait = [];
  544. // redraw and gather transitions
  545. [
  546. $$.redrawBar(drawBar, true),
  547. $$.redrawLine(drawLine, true),
  548. $$.redrawArea(drawArea, true),
  549. $$.redrawCircle(cx, cy, true),
  550. $$.redrawText(xForText, yForText, options.flow, true),
  551. $$.redrawRegion(true),
  552. $$.redrawGrid(true),
  553. ].forEach(function (transitions) {
  554. transitions.forEach(function (transition) {
  555. transitionsToWait.push(transition);
  556. });
  557. });
  558. // Wait for end of transitions to call flow and onrendered callback
  559. waitForDraw = $$.generateWait();
  560. transitionsToWait.forEach(function (t) {
  561. waitForDraw.add(t);
  562. });
  563. })
  564. .call(waitForDraw, function () {
  565. if (flow) {
  566. flow();
  567. }
  568. if (config.onrendered) {
  569. config.onrendered.call($$);
  570. }
  571. });
  572. }
  573. else {
  574. $$.redrawBar(drawBar);
  575. $$.redrawLine(drawLine);
  576. $$.redrawArea(drawArea);
  577. $$.redrawCircle(cx, cy);
  578. $$.redrawText(xForText, yForText, options.flow);
  579. $$.redrawRegion();
  580. $$.redrawGrid();
  581. if (config.onrendered) {
  582. config.onrendered.call($$);
  583. }
  584. }
  585. // update fadein condition
  586. $$.mapToIds($$.data.targets).forEach(function (id) {
  587. $$.withoutFadeIn[id] = true;
  588. });
  589. };
  590. c3_chart_internal_fn.updateAndRedraw = function (options) {
  591. var $$ = this, config = $$.config, transitions;
  592. options = options || {};
  593. // same with redraw
  594. options.withTransition = getOption(options, "withTransition", true);
  595. options.withTransform = getOption(options, "withTransform", false);
  596. options.withLegend = getOption(options, "withLegend", false);
  597. // NOT same with redraw
  598. options.withUpdateXDomain = true;
  599. options.withUpdateOrgXDomain = true;
  600. options.withTransitionForExit = false;
  601. options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition);
  602. // MEMO: this needs to be called before updateLegend and it means this ALWAYS needs to be called)
  603. $$.updateSizes();
  604. // MEMO: called in updateLegend in redraw if withLegend
  605. if (!(options.withLegend && config.legend_show)) {
  606. transitions = $$.axis.generateTransitions(options.withTransitionForAxis ? config.transition_duration : 0);
  607. // Update scales
  608. $$.updateScales();
  609. $$.updateSvgSize();
  610. // Update g positions
  611. $$.transformAll(options.withTransitionForTransform, transitions);
  612. }
  613. // Draw with new sizes & scales
  614. $$.redraw(options, transitions);
  615. };
  616. c3_chart_internal_fn.redrawWithoutRescale = function () {
  617. this.redraw({
  618. withY: false,
  619. withSubchart: false,
  620. withEventRect: false,
  621. withTransitionForAxis: false
  622. });
  623. };
  624. c3_chart_internal_fn.isTimeSeries = function () {
  625. return this.config.axis_x_type === 'timeseries';
  626. };
  627. c3_chart_internal_fn.isCategorized = function () {
  628. return this.config.axis_x_type.indexOf('categor') >= 0;
  629. };
  630. c3_chart_internal_fn.isCustomX = function () {
  631. var $$ = this, config = $$.config;
  632. return !$$.isTimeSeries() && (config.data_x || notEmpty(config.data_xs));
  633. };
  634. c3_chart_internal_fn.isTimeSeriesY = function () {
  635. return this.config.axis_y_type === 'timeseries';
  636. };
  637. c3_chart_internal_fn.getTranslate = function (target) {
  638. var $$ = this, config = $$.config, x, y;
  639. if (target === 'main') {
  640. x = asHalfPixel($$.margin.left);
  641. y = asHalfPixel($$.margin.top);
  642. } else if (target === 'context') {
  643. x = asHalfPixel($$.margin2.left);
  644. y = asHalfPixel($$.margin2.top);
  645. } else if (target === 'legend') {
  646. x = $$.margin3.left;
  647. y = $$.margin3.top;
  648. } else if (target === 'x') {
  649. x = 0;
  650. y = config.axis_rotated ? 0 : $$.height;
  651. } else if (target === 'y') {
  652. x = 0;
  653. y = config.axis_rotated ? $$.height : 0;
  654. } else if (target === 'y2') {
  655. x = config.axis_rotated ? 0 : $$.width;
  656. y = config.axis_rotated ? 1 : 0;
  657. } else if (target === 'subx') {
  658. x = 0;
  659. y = config.axis_rotated ? 0 : $$.height2;
  660. } else if (target === 'arc') {
  661. x = $$.arcWidth / 2;
  662. y = $$.arcHeight / 2;
  663. }
  664. return "translate(" + x + "," + y + ")";
  665. };
  666. c3_chart_internal_fn.initialOpacity = function (d) {
  667. return d.value !== null && this.withoutFadeIn[d.id] ? 1 : 0;
  668. };
  669. c3_chart_internal_fn.initialOpacityForCircle = function (d) {
  670. return d.value !== null && this.withoutFadeIn[d.id] ? this.opacityForCircle(d) : 0;
  671. };
  672. c3_chart_internal_fn.opacityForCircle = function (d) {
  673. var opacity = this.config.point_show ? 1 : 0;
  674. return isValue(d.value) ? (this.isScatterType(d) ? 0.5 : opacity) : 0;
  675. };
  676. c3_chart_internal_fn.opacityForText = function () {
  677. return this.hasDataLabel() ? 1 : 0;
  678. };
  679. c3_chart_internal_fn.xx = function (d) {
  680. return d ? this.x(d.x) : null;
  681. };
  682. c3_chart_internal_fn.xv = function (d) {
  683. var $$ = this, value = d.value;
  684. if ($$.isTimeSeries()) {
  685. value = $$.parseDate(d.value);
  686. }
  687. else if ($$.isCategorized() && typeof d.value === 'string') {
  688. value = $$.config.axis_x_categories.indexOf(d.value);
  689. }
  690. return Math.ceil($$.x(value));
  691. };
  692. c3_chart_internal_fn.yv = function (d) {
  693. var $$ = this,
  694. yScale = d.axis && d.axis === 'y2' ? $$.y2 : $$.y;
  695. return Math.ceil(yScale(d.value));
  696. };
  697. c3_chart_internal_fn.subxx = function (d) {
  698. return d ? this.subX(d.x) : null;
  699. };
  700. c3_chart_internal_fn.transformMain = function (withTransition, transitions) {
  701. var $$ = this,
  702. xAxis, yAxis, y2Axis;
  703. if (transitions && transitions.axisX) {
  704. xAxis = transitions.axisX;
  705. } else {
  706. xAxis = $$.main.select('.' + CLASS.axisX);
  707. if (withTransition) { xAxis = xAxis.transition(); }
  708. }
  709. if (transitions && transitions.axisY) {
  710. yAxis = transitions.axisY;
  711. } else {
  712. yAxis = $$.main.select('.' + CLASS.axisY);
  713. if (withTransition) { yAxis = yAxis.transition(); }
  714. }
  715. if (transitions && transitions.axisY2) {
  716. y2Axis = transitions.axisY2;
  717. } else {
  718. y2Axis = $$.main.select('.' + CLASS.axisY2);
  719. if (withTransition) { y2Axis = y2Axis.transition(); }
  720. }
  721. (withTransition ? $$.main.transition() : $$.main).attr("transform", $$.getTranslate('main'));
  722. xAxis.attr("transform", $$.getTranslate('x'));
  723. yAxis.attr("transform", $$.getTranslate('y'));
  724. y2Axis.attr("transform", $$.getTranslate('y2'));
  725. $$.main.select('.' + CLASS.chartArcs).attr("transform", $$.getTranslate('arc'));
  726. };
  727. c3_chart_internal_fn.transformAll = function (withTransition, transitions) {
  728. var $$ = this;
  729. $$.transformMain(withTransition, transitions);
  730. if ($$.config.subchart_show) { $$.transformContext(withTransition, transitions); }
  731. if ($$.legend) { $$.transformLegend(withTransition); }
  732. };
  733. c3_chart_internal_fn.updateSvgSize = function () {
  734. var $$ = this,
  735. brush = $$.svg.select(".c3-brush .background");
  736. $$.svg.attr('width', $$.currentWidth).attr('height', $$.currentHeight);
  737. $$.svg.selectAll(['#' + $$.clipId, '#' + $$.clipIdForGrid]).select('rect')
  738. .attr('width', $$.width)
  739. .attr('height', $$.height);
  740. $$.svg.select('#' + $$.clipIdForXAxis).select('rect')
  741. .attr('x', $$.getXAxisClipX.bind($$))
  742. .attr('y', $$.getXAxisClipY.bind($$))
  743. .attr('width', $$.getXAxisClipWidth.bind($$))
  744. .attr('height', $$.getXAxisClipHeight.bind($$));
  745. $$.svg.select('#' + $$.clipIdForYAxis).select('rect')
  746. .attr('x', $$.getYAxisClipX.bind($$))
  747. .attr('y', $$.getYAxisClipY.bind($$))
  748. .attr('width', $$.getYAxisClipWidth.bind($$))
  749. .attr('height', $$.getYAxisClipHeight.bind($$));
  750. $$.svg.select('#' + $$.clipIdForSubchart).select('rect')
  751. .attr('width', $$.width)
  752. .attr('height', brush.size() ? brush.attr('height') : 0);
  753. $$.svg.select('.' + CLASS.zoomRect)
  754. .attr('width', $$.width)
  755. .attr('height', $$.height);
  756. // MEMO: parent div's height will be bigger than svg when <!DOCTYPE html>
  757. $$.selectChart.style('max-height', $$.currentHeight + "px");
  758. };
  759. c3_chart_internal_fn.updateDimension = function (withoutAxis) {
  760. var $$ = this;
  761. if (!withoutAxis) {
  762. if ($$.config.axis_rotated) {
  763. $$.axes.x.call($$.xAxis);
  764. $$.axes.subx.call($$.subXAxis);
  765. } else {
  766. $$.axes.y.call($$.yAxis);
  767. $$.axes.y2.call($$.y2Axis);
  768. }
  769. }
  770. $$.updateSizes();
  771. $$.updateScales();
  772. $$.updateSvgSize();
  773. $$.transformAll(false);
  774. };
  775. c3_chart_internal_fn.observeInserted = function (selection) {
  776. var $$ = this, observer;
  777. if (typeof MutationObserver === 'undefined') {
  778. window.console.error("MutationObserver not defined.");
  779. return;
  780. }
  781. observer= new MutationObserver(function (mutations) {
  782. mutations.forEach(function (mutation) {
  783. if (mutation.type === 'childList' && mutation.previousSibling) {
  784. observer.disconnect();
  785. // need to wait for completion of load because size calculation requires the actual sizes determined after that completion
  786. $$.intervalForObserveInserted = window.setInterval(function () {
  787. // parentNode will NOT be null when completed
  788. if (selection.node().parentNode) {
  789. window.clearInterval($$.intervalForObserveInserted);
  790. $$.updateDimension();
  791. if ($$.brush) { $$.brush.update(); }
  792. $$.config.oninit.call($$);
  793. $$.redraw({
  794. withTransform: true,
  795. withUpdateXDomain: true,
  796. withUpdateOrgXDomain: true,
  797. withTransition: false,
  798. withTransitionForTransform: false,
  799. withLegend: true
  800. });
  801. selection.transition().style('opacity', 1);
  802. }
  803. }, 10);
  804. }
  805. });
  806. });
  807. observer.observe(selection.node(), {attributes: true, childList: true, characterData: true});
  808. };
  809. c3_chart_internal_fn.bindResize = function () {
  810. var $$ = this, config = $$.config;
  811. $$.resizeFunction = $$.generateResize();
  812. $$.resizeFunction.add(function () {
  813. config.onresize.call($$);
  814. });
  815. if (config.resize_auto) {
  816. $$.resizeFunction.add(function () {
  817. if ($$.resizeTimeout !== undefined) {
  818. window.clearTimeout($$.resizeTimeout);
  819. }
  820. $$.resizeTimeout = window.setTimeout(function () {
  821. delete $$.resizeTimeout;
  822. $$.api.flush();
  823. }, 100);
  824. });
  825. }
  826. $$.resizeFunction.add(function () {
  827. config.onresized.call($$);
  828. });
  829. if (window.attachEvent) {
  830. window.attachEvent('onresize', $$.resizeFunction);
  831. } else if (window.addEventListener) {
  832. window.addEventListener('resize', $$.resizeFunction, false);
  833. } else {
  834. // fallback to this, if this is a very old browser
  835. var wrapper = window.onresize;
  836. if (!wrapper) {
  837. // create a wrapper that will call all charts
  838. wrapper = $$.generateResize();
  839. } else if (!wrapper.add || !wrapper.remove) {
  840. // there is already a handler registered, make sure we call it too
  841. wrapper = $$.generateResize();
  842. wrapper.add(window.onresize);
  843. }
  844. // add this graph to the wrapper, we will be removed if the user calls destroy
  845. wrapper.add($$.resizeFunction);
  846. window.onresize = wrapper;
  847. }
  848. };
  849. c3_chart_internal_fn.generateResize = function () {
  850. var resizeFunctions = [];
  851. function callResizeFunctions() {
  852. resizeFunctions.forEach(function (f) {
  853. f();
  854. });
  855. }
  856. callResizeFunctions.add = function (f) {
  857. resizeFunctions.push(f);
  858. };
  859. callResizeFunctions.remove = function (f) {
  860. for (var i = 0; i < resizeFunctions.length; i++) {
  861. if (resizeFunctions[i] === f) {
  862. resizeFunctions.splice(i, 1);
  863. break;
  864. }
  865. }
  866. };
  867. return callResizeFunctions;
  868. };
  869. c3_chart_internal_fn.endall = function (transition, callback) {
  870. var n = 0;
  871. transition
  872. .each(function () { ++n; })
  873. .each("end", function () {
  874. if (!--n) { callback.apply(this, arguments); }
  875. });
  876. };
  877. c3_chart_internal_fn.generateWait = function () {
  878. var transitionsToWait = [],
  879. f = function (transition, callback) {
  880. var timer = setInterval(function () {
  881. var done = 0;
  882. transitionsToWait.forEach(function (t) {
  883. if (t.empty()) {
  884. done += 1;
  885. return;
  886. }
  887. try {
  888. t.transition();
  889. } catch (e) {
  890. done += 1;
  891. }
  892. });
  893. if (done === transitionsToWait.length) {
  894. clearInterval(timer);
  895. if (callback) { callback(); }
  896. }
  897. }, 10);
  898. };
  899. f.add = function (transition) {
  900. transitionsToWait.push(transition);
  901. };
  902. return f;
  903. };
  904. c3_chart_internal_fn.parseDate = function (date) {
  905. var $$ = this, parsedDate;
  906. if (date instanceof Date) {
  907. parsedDate = date;
  908. } else if (typeof date === 'string') {
  909. parsedDate = $$.dataTimeFormat($$.config.data_xFormat).parse(date);
  910. } else if (typeof date === 'number' && !isNaN(date)) {
  911. parsedDate = new Date(+date);
  912. }
  913. if (!parsedDate || isNaN(+parsedDate)) {
  914. window.console.error("Failed to parse x '" + date + "' to Date object");
  915. }
  916. return parsedDate;
  917. };
  918. c3_chart_internal_fn.isTabVisible = function () {
  919. var hidden;
  920. if (typeof document.hidden !== "undefined") { // Opera 12.10 and Firefox 18 and later support
  921. hidden = "hidden";
  922. } else if (typeof document.mozHidden !== "undefined") {
  923. hidden = "mozHidden";
  924. } else if (typeof document.msHidden !== "undefined") {
  925. hidden = "msHidden";
  926. } else if (typeof document.webkitHidden !== "undefined") {
  927. hidden = "webkitHidden";
  928. }
  929. return document[hidden] ? false : true;
  930. };
  931. c3_chart_internal_fn.getDefaultConfig = function () {
  932. var config = {
  933. bindto: '#chart',
  934. svg_classname: undefined,
  935. size_width: undefined,
  936. size_height: undefined,
  937. padding_left: undefined,
  938. padding_right: undefined,
  939. padding_top: undefined,
  940. padding_bottom: undefined,
  941. resize_auto: true,
  942. zoom_enabled: false,
  943. zoom_extent: undefined,
  944. zoom_privileged: false,
  945. zoom_rescale: false,
  946. zoom_onzoom: function () {},
  947. zoom_onzoomstart: function () {},
  948. zoom_onzoomend: function () {},
  949. zoom_x_min: undefined,
  950. zoom_x_max: undefined,
  951. interaction_enabled: true,
  952. onmouseover: function () {},
  953. onmouseout: function () {},
  954. onresize: function () {},
  955. onresized: function () {},
  956. oninit: function () {},
  957. onrendered: function () {},
  958. transition_duration: 350,
  959. data_x: undefined,
  960. data_xs: {},
  961. data_xFormat: '%Y-%m-%d',
  962. data_xLocaltime: true,
  963. data_xSort: true,
  964. data_idConverter: function (id) { return id; },
  965. data_names: {},
  966. data_classes: {},
  967. data_groups: [],
  968. data_axes: {},
  969. data_type: undefined,
  970. data_types: {},
  971. data_labels: {},
  972. data_order: 'desc',
  973. data_regions: {},
  974. data_color: undefined,
  975. data_colors: {},
  976. data_hide: false,
  977. data_filter: undefined,
  978. data_selection_enabled: false,
  979. data_selection_grouped: false,
  980. data_selection_isselectable: function () { return true; },
  981. data_selection_multiple: true,
  982. data_selection_draggable: false,
  983. data_onclick: function () {},
  984. data_onmouseover: function () {},
  985. data_onmouseout: function () {},
  986. data_onselected: function () {},
  987. data_onunselected: function () {},
  988. data_url: undefined,
  989. data_headers: undefined,
  990. data_json: undefined,
  991. data_rows: undefined,
  992. data_columns: undefined,
  993. data_mimeType: undefined,
  994. data_keys: undefined,
  995. // configuration for no plot-able data supplied.
  996. data_empty_label_text: "",
  997. // subchart
  998. subchart_show: false,
  999. subchart_size_height: 60,
  1000. subchart_axis_x_show: true,
  1001. subchart_onbrush: function () {},
  1002. // color
  1003. color_pattern: [],
  1004. color_threshold: {},
  1005. // legend
  1006. legend_show: true,
  1007. legend_hide: false,
  1008. legend_position: 'bottom',
  1009. legend_inset_anchor: 'top-left',
  1010. legend_inset_x: 10,
  1011. legend_inset_y: 0,
  1012. legend_inset_step: undefined,
  1013. legend_item_onclick: undefined,
  1014. legend_item_onmouseover: undefined,
  1015. legend_item_onmouseout: undefined,
  1016. legend_equally: false,
  1017. legend_padding: 0,
  1018. legend_item_tile_width: 10,
  1019. legend_item_tile_height: 10,
  1020. // axis
  1021. axis_rotated: false,
  1022. axis_x_show: true,
  1023. axis_x_type: 'indexed',
  1024. axis_x_localtime: true,
  1025. axis_x_categories: [],
  1026. axis_x_tick_centered: false,
  1027. axis_x_tick_format: undefined,
  1028. axis_x_tick_culling: {},
  1029. axis_x_tick_culling_max: 10,
  1030. axis_x_tick_count: undefined,
  1031. axis_x_tick_fit: true,
  1032. axis_x_tick_values: null,
  1033. axis_x_tick_rotate: 0,
  1034. axis_x_tick_outer: true,
  1035. axis_x_tick_multiline: true,
  1036. axis_x_tick_width: null,
  1037. axis_x_max: undefined,
  1038. axis_x_min: undefined,
  1039. axis_x_padding: {},
  1040. axis_x_height: undefined,
  1041. axis_x_extent: undefined,
  1042. axis_x_label: {},
  1043. axis_y_show: true,
  1044. axis_y_type: undefined,
  1045. axis_y_max: undefined,
  1046. axis_y_min: undefined,
  1047. axis_y_inverted: false,
  1048. axis_y_center: undefined,
  1049. axis_y_inner: undefined,
  1050. axis_y_label: {},
  1051. axis_y_tick_format: undefined,
  1052. axis_y_tick_outer: true,
  1053. axis_y_tick_values: null,
  1054. axis_y_tick_rotate: 0,
  1055. axis_y_tick_count: undefined,
  1056. axis_y_tick_time_value: undefined,
  1057. axis_y_tick_time_interval: undefined,
  1058. axis_y_padding: {},
  1059. axis_y_default: undefined,
  1060. axis_y2_show: false,
  1061. axis_y2_max: undefined,
  1062. axis_y2_min: undefined,
  1063. axis_y2_inverted: false,
  1064. axis_y2_center: undefined,
  1065. axis_y2_inner: undefined,
  1066. axis_y2_label: {},
  1067. axis_y2_tick_format: undefined,
  1068. axis_y2_tick_outer: true,
  1069. axis_y2_tick_values: null,
  1070. axis_y2_tick_count: undefined,
  1071. axis_y2_padding: {},
  1072. axis_y2_default: undefined,
  1073. // grid
  1074. grid_x_show: false,
  1075. grid_x_type: 'tick',
  1076. grid_x_lines: [],
  1077. grid_y_show: false,
  1078. // not used
  1079. // grid_y_type: 'tick',
  1080. grid_y_lines: [],
  1081. grid_y_ticks: 10,
  1082. grid_focus_show: true,
  1083. grid_lines_front: true,
  1084. // point - point of each data
  1085. point_show: true,
  1086. point_r: 2.5,
  1087. point_sensitivity: 10,
  1088. point_focus_expand_enabled: true,
  1089. point_focus_expand_r: undefined,
  1090. point_select_r: undefined,
  1091. // line
  1092. line_connectNull: false,
  1093. line_step_type: 'step',
  1094. // bar
  1095. bar_width: undefined,
  1096. bar_width_ratio: 0.6,
  1097. bar_width_max: undefined,
  1098. bar_zerobased: true,
  1099. // area
  1100. area_zerobased: true,
  1101. // pie
  1102. pie_label_show: true,
  1103. pie_label_format: undefined,
  1104. pie_label_threshold: 0.05,
  1105. pie_expand: {},
  1106. pie_expand_duration: 50,
  1107. // gauge
  1108. gauge_label_show: true,
  1109. gauge_label_format: undefined,
  1110. gauge_min: 0,
  1111. gauge_max: 100,
  1112. gauge_units: undefined,
  1113. gauge_width: undefined,
  1114. gauge_expand: {},
  1115. gauge_expand_duration: 50,
  1116. // donut
  1117. donut_label_show: true,
  1118. donut_label_format: undefined,
  1119. donut_label_threshold: 0.05,
  1120. donut_width: undefined,
  1121. donut_title: "",
  1122. donut_expand: {},
  1123. donut_expand_duration: 50,
  1124. // spline
  1125. spline_interpolation_type: 'cardinal',
  1126. // region - region to change style
  1127. regions: [],
  1128. // tooltip - show when mouseover on each data
  1129. tooltip_show: true,
  1130. tooltip_grouped: true,
  1131. tooltip_format_title: undefined,
  1132. tooltip_format_name: undefined,
  1133. tooltip_format_value: undefined,
  1134. tooltip_position: undefined,
  1135. tooltip_contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
  1136. return this.getTooltipContent ? this.getTooltipContent(d, defaultTitleFormat, defaultValueFormat, color) : '';
  1137. },
  1138. tooltip_init_show: false,
  1139. tooltip_init_x: 0,
  1140. tooltip_init_position: {top: '0px', left: '50px'},
  1141. tooltip_onshow: function () {},
  1142. tooltip_onhide: function () {},
  1143. // title
  1144. title_text: undefined,
  1145. title_padding: {
  1146. top: 0,
  1147. right: 0,
  1148. bottom: 0,
  1149. left: 0
  1150. },
  1151. title_position: 'top-center',
  1152. };
  1153. Object.keys(this.additionalConfig).forEach(function (key) {
  1154. config[key] = this.additionalConfig[key];
  1155. }, this);
  1156. return config;
  1157. };
  1158. c3_chart_internal_fn.additionalConfig = {};
  1159. c3_chart_internal_fn.loadConfig = function (config) {
  1160. var this_config = this.config, target, keys, read;
  1161. function find() {
  1162. var key = keys.shift();
  1163. // console.log("key =>", key, ", target =>", target);
  1164. if (key && target && typeof target === 'object' && key in target) {
  1165. target = target[key];
  1166. return find();
  1167. }
  1168. else if (!key) {
  1169. return target;
  1170. }
  1171. else {
  1172. return undefined;
  1173. }
  1174. }
  1175. Object.keys(this_config).forEach(function (key) {
  1176. target = config;
  1177. keys = key.split('_');
  1178. read = find();
  1179. // console.log("CONFIG : ", key, read);
  1180. if (isDefined(read)) {
  1181. this_config[key] = read;
  1182. }
  1183. });
  1184. };
  1185. c3_chart_internal_fn.getScale = function (min, max, forTimeseries) {
  1186. return (forTimeseries ? this.d3.time.scale() : this.d3.scale.linear()).range([min, max]);
  1187. };
  1188. c3_chart_internal_fn.getX = function (min, max, domain, offset) {
  1189. var $$ = this,
  1190. scale = $$.getScale(min, max, $$.isTimeSeries()),
  1191. _scale = domain ? scale.domain(domain) : scale, key;
  1192. // Define customized scale if categorized axis
  1193. if ($$.isCategorized()) {
  1194. offset = offset || function () { return 0; };
  1195. scale = function (d, raw) {
  1196. var v = _scale(d) + offset(d);
  1197. return raw ? v : Math.ceil(v);
  1198. };
  1199. } else {
  1200. scale = function (d, raw) {
  1201. var v = _scale(d);
  1202. return raw ? v : Math.ceil(v);
  1203. };
  1204. }
  1205. // define functions
  1206. for (key in _scale) {
  1207. scale[key] = _scale[key];
  1208. }
  1209. scale.orgDomain = function () {
  1210. return _scale.domain();
  1211. };
  1212. // define custom domain() for categorized axis
  1213. if ($$.isCategorized()) {
  1214. scale.domain = function (domain) {
  1215. if (!arguments.length) {
  1216. domain = this.orgDomain();
  1217. return [domain[0], domain[1] + 1];
  1218. }
  1219. _scale.domain(domain);
  1220. return scale;
  1221. };
  1222. }
  1223. return scale;
  1224. };
  1225. c3_chart_internal_fn.getY = function (min, max, domain) {
  1226. var scale = this.getScale(min, max, this.isTimeSeriesY());
  1227. if (domain) { scale.domain(domain); }
  1228. return scale;
  1229. };
  1230. c3_chart_internal_fn.getYScale = function (id) {
  1231. return this.axis.getId(id) === 'y2' ? this.y2 : this.y;
  1232. };
  1233. c3_chart_internal_fn.getSubYScale = function (id) {
  1234. return this.axis.getId(id) === 'y2' ? this.subY2 : this.subY;
  1235. };
  1236. c3_chart_internal_fn.updateScales = function () {
  1237. var $$ = this, config = $$.config,
  1238. forInit = !$$.x;
  1239. // update edges
  1240. $$.xMin = config.axis_rotated ? 1 : 0;
  1241. $$.xMax = config.axis_rotated ? $$.height : $$.width;
  1242. $$.yMin = config.axis_rotated ? 0 : $$.height;
  1243. $$.yMax = config.axis_rotated ? $$.width : 1;
  1244. $$.subXMin = $$.xMin;
  1245. $$.subXMax = $$.xMax;
  1246. $$.subYMin = config.axis_rotated ? 0 : $$.height2;
  1247. $$.subYMax = config.axis_rotated ? $$.width2 : 1;
  1248. // update scales
  1249. $$.x = $$.getX($$.xMin, $$.xMax, forInit ? undefined : $$.x.orgDomain(), function () { return $$.xAxis.tickOffset(); });
  1250. $$.y = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y_default : $$.y.domain());
  1251. $$.y2 = $$.getY($$.yMin, $$.yMax, forInit ? config.axis_y2_default : $$.y2.domain());
  1252. $$.subX = $$.getX($$.xMin, $$.xMax, $$.orgXDomain, function (d) { return d % 1 ? 0 : $$.subXAxis.tickOffset(); });
  1253. $$.subY = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y_default : $$.subY.domain());
  1254. $$.subY2 = $$.getY($$.subYMin, $$.subYMax, forInit ? config.axis_y2_default : $$.subY2.domain());
  1255. // update axes
  1256. $$.xAxisTickFormat = $$.axis.getXAxisTickFormat();
  1257. $$.xAxisTickValues = $$.axis.getXAxisTickValues();
  1258. $$.yAxisTickValues = $$.axis.getYAxisTickValues();
  1259. $$.y2AxisTickValues = $$.axis.getY2AxisTickValues();
  1260. $$.xAxis = $$.axis.getXAxis($$.x, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
  1261. $$.subXAxis = $$.axis.getXAxis($$.subX, $$.subXOrient, $$.xAxisTickFormat, $$.xAxisTickValues, config.axis_x_tick_outer);
  1262. $$.yAxis = $$.axis.getYAxis($$.y, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, config.axis_y_tick_outer);
  1263. $$.y2Axis = $$.axis.getYAxis($$.y2, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, config.axis_y2_tick_outer);
  1264. // Set initialized scales to brush and zoom
  1265. if (!forInit) {
  1266. if ($$.brush) { $$.brush.scale($$.subX); }
  1267. if (config.zoom_enabled) { $$.zoom.scale($$.x); }
  1268. }
  1269. // update for arc
  1270. if ($$.updateArc) { $$.updateArc(); }
  1271. };
  1272. c3_chart_internal_fn.getYDomainMin = function (targets) {
  1273. var $$ = this, config = $$.config,
  1274. ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
  1275. j, k, baseId, idsInGroup, id, hasNegativeValue;
  1276. if (config.data_groups.length > 0) {
  1277. hasNegativeValue = $$.hasNegativeValueInTargets(targets);
  1278. for (j = 0; j < config.data_groups.length; j++) {
  1279. // Determine baseId
  1280. idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
  1281. if (idsInGroup.length === 0) { continue; }
  1282. baseId = idsInGroup[0];
  1283. // Consider negative values
  1284. if (hasNegativeValue && ys[baseId]) {
  1285. ys[baseId].forEach(function (v, i) {
  1286. ys[baseId][i] = v < 0 ? v : 0;
  1287. });
  1288. }
  1289. // Compute min
  1290. for (k = 1; k < idsInGroup.length; k++) {
  1291. id = idsInGroup[k];
  1292. if (! ys[id]) { continue; }
  1293. ys[id].forEach(function (v, i) {
  1294. if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasNegativeValue && +v > 0)) {
  1295. ys[baseId][i] += +v;
  1296. }
  1297. });
  1298. }
  1299. }
  1300. }
  1301. return $$.d3.min(Object.keys(ys).map(function (key) { return $$.d3.min(ys[key]); }));
  1302. };
  1303. c3_chart_internal_fn.getYDomainMax = function (targets) {
  1304. var $$ = this, config = $$.config,
  1305. ids = $$.mapToIds(targets), ys = $$.getValuesAsIdKeyed(targets),
  1306. j, k, baseId, idsInGroup, id, hasPositiveValue;
  1307. if (config.data_groups.length > 0) {
  1308. hasPositiveValue = $$.hasPositiveValueInTargets(targets);
  1309. for (j = 0; j < config.data_groups.length; j++) {
  1310. // Determine baseId
  1311. idsInGroup = config.data_groups[j].filter(function (id) { return ids.indexOf(id) >= 0; });
  1312. if (idsInGroup.length === 0) { continue; }
  1313. baseId = idsInGroup[0];
  1314. // Consider positive values
  1315. if (hasPositiveValue && ys[baseId]) {
  1316. ys[baseId].forEach(function (v, i) {
  1317. ys[baseId][i] = v > 0 ? v : 0;
  1318. });
  1319. }
  1320. // Compute max
  1321. for (k = 1; k < idsInGroup.length; k++) {
  1322. id = idsInGroup[k];
  1323. if (! ys[id]) { continue; }
  1324. ys[id].forEach(function (v, i) {
  1325. if ($$.axis.getId(id) === $$.axis.getId(baseId) && ys[baseId] && !(hasPositiveValue && +v < 0)) {
  1326. ys[baseId][i] += +v;
  1327. }
  1328. });
  1329. }
  1330. }
  1331. }
  1332. return $$.d3.max(Object.keys(ys).map(function (key) { return $$.d3.max(ys[key]); }));
  1333. };
  1334. c3_chart_internal_fn.getYDomain = function (targets, axisId, xDomain) {
  1335. var $$ = this, config = $$.config,
  1336. targetsByAxisId = targets.filter(function (t) { return $$.axis.getId(t.id) === axisId; }),
  1337. yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId,
  1338. yMin = axisId === 'y2' ? config.axis_y2_min : config.axis_y_min,
  1339. yMax = axisId === 'y2' ? config.axis_y2_max : config.axis_y_max,
  1340. yDomainMin = $$.getYDomainMin(yTargets),
  1341. yDomainMax = $$.getYDomainMax(yTargets),
  1342. domain, domainLength, padding, padding_top, padding_bottom,
  1343. center = axisId === 'y2' ? config.axis_y2_center : config.axis_y_center,
  1344. yDomainAbs, lengths, diff, ratio, isAllPositive, isAllNegative,
  1345. isZeroBased = ($$.hasType('bar', yTargets) && config.bar_zerobased) || ($$.hasType('area', yTargets) && config.area_zerobased),
  1346. isInverted = axisId === 'y2' ? config.axis_y2_inverted : config.axis_y_inverted,
  1347. showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated,
  1348. showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated;
  1349. // MEMO: avoid inverting domain unexpectedly
  1350. yDomainMin = isValue(yMin) ? yMin : isValue(yMax) ? (yDomainMin < yMax ? yDomainMin : yMax - 10) : yDomainMin;
  1351. yDomainMax = isValue(yMax) ? yMax : isValue(yMin) ? (yMin < yDomainMax ? yDomainMax : yMin + 10) : yDomainMax;
  1352. if (yTargets.length === 0) { // use current domain if target of axisId is none
  1353. return axisId === 'y2' ? $$.y2.domain() : $$.y.domain();
  1354. }
  1355. if (isNaN(yDomainMin)) { // set minimum to zero when not number
  1356. yDomainMin = 0;
  1357. }
  1358. if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin
  1359. yDomainMax = yDomainMin;
  1360. }
  1361. if (yDomainMin === yDomainMax) {
  1362. yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0;
  1363. }
  1364. isAllPositive = yDomainMin >= 0 && yDomainMax >= 0;
  1365. isAllNegative = yDomainMin <= 0 && yDomainMax <= 0;
  1366. // Cancel zerobased if axis_*_min / axis_*_max specified
  1367. if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) {
  1368. isZeroBased = false;
  1369. }
  1370. // Bar/Area chart should be 0-based if all positive|negative
  1371. if (isZeroBased) {
  1372. if (isAllPositive) { yDomainMin = 0; }
  1373. if (isAllNegative) { yDomainMax = 0; }
  1374. }
  1375. domainLength = Math.abs(yDomainMax - yDomainMin);
  1376. padding = padding_top = padding_bottom = domainLength * 0.1;
  1377. if (typeof center !== 'undefined') {
  1378. yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax));
  1379. yDomainMax = center + yDomainAbs;
  1380. yDomainMin = center - yDomainAbs;
  1381. }
  1382. // add padding for data label
  1383. if (showHorizontalDataLabel) {
  1384. lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'width');
  1385. diff = diffDomain($$.y.range());
  1386. ratio = [lengths[0] / diff, lengths[1] / diff];
  1387. padding_top += domainLength * (ratio[1] / (1 - ratio[0] - ratio[1]));
  1388. padding_bottom += domainLength * (ratio[0] / (1 - ratio[0] - ratio[1]));
  1389. } else if (showVerticalDataLabel) {
  1390. lengths = $$.getDataLabelLength(yDomainMin, yDomainMax, 'height');
  1391. padding_top += $$.axis.convertPixelsToAxisPadding(lengths[1], domainLength);
  1392. padding_bottom += $$.axis.convertPixelsToAxisPadding(lengths[0], domainLength);
  1393. }
  1394. if (axisId === 'y' && notEmpty(config.axis_y_padding)) {
  1395. padding_top = $$.axis.getPadding(config.axis_y_padding, 'top', padding_top, domainLength);
  1396. padding_bottom = $$.axis.getPadding(config.axis_y_padding, 'bottom', padding_bottom, domainLength);
  1397. }
  1398. if (axisId === 'y2' && notEmpty(config.axis_y2_padding)) {
  1399. padding_top = $$.axis.getPadding(config.axis_y2_padding, 'top', padding_top, domainLength);
  1400. padding_bottom = $$.axis.getPadding(config.axis_y2_padding, 'bottom', padding_bottom, domainLength);
  1401. }
  1402. // Bar/Area chart should be 0-based if all positive|negative
  1403. if (isZeroBased) {
  1404. if (isAllPositive) { padding_bottom = yDomainMin; }
  1405. if (isAllNegative) { padding_top = -yDomainMax; }
  1406. }
  1407. domain = [yDomainMin - padding_bottom, yDomainMax + padding_top];
  1408. return isInverted ? domain.reverse() : domain;
  1409. };
  1410. c3_chart_internal_fn.getXDomainMin = function (targets) {
  1411. var $$ = this, config = $$.config;
  1412. return isDefined(config.axis_x_min) ?
  1413. ($$.isTimeSeries() ? this.parseDate(config.axis_x_min) : config.axis_x_min) :
  1414. $$.d3.min(targets, function (t) { return $$.d3.min(t.values, function (v) { return v.x; }); });
  1415. };
  1416. c3_chart_internal_fn.getXDomainMax = function (targets) {
  1417. var $$ = this, config = $$.config;
  1418. return isDefined(config.axis_x_max) ?
  1419. ($$.isTimeSeries() ? this.parseDate(config.axis_x_max) : config.axis_x_max) :
  1420. $$.d3.max(targets, function (t) { return $$.d3.max(t.values, function (v) { return v.x; }); });
  1421. };
  1422. c3_chart_internal_fn.getXDomainPadding = function (domain) {
  1423. var $$ = this, config = $$.config,
  1424. diff = domain[1] - domain[0],
  1425. maxDataCount, padding, paddingLeft, paddingRight;
  1426. if ($$.isCategorized()) {
  1427. padding = 0;
  1428. } else if ($$.hasType('bar')) {
  1429. maxDataCount = $$.getMaxDataCount();
  1430. padding = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5;
  1431. } else {
  1432. padding = diff * 0.01;
  1433. }
  1434. if (typeof config.axis_x_padding === 'object' && notEmpty(config.axis_x_padding)) {
  1435. paddingLeft = isValue(config.axis_x_padding.left) ? config.axis_x_padding.left : padding;
  1436. paddingRight = isValue(config.axis_x_padding.right) ? config.axis_x_padding.right : padding;
  1437. } else if (typeof config.axis_x_padding === 'number') {
  1438. paddingLeft = paddingRight = config.axis_x_padding;
  1439. } else {
  1440. paddingLeft = paddingRight = padding;
  1441. }
  1442. return {left: paddingLeft, right: paddingRight};
  1443. };
  1444. c3_chart_internal_fn.getXDomain = function (targets) {
  1445. var $$ = this,
  1446. xDomain = [$$.getXDomainMin(targets), $$.getXDomainMax(targets)],
  1447. firstX = xDomain[0], lastX = xDomain[1],
  1448. padding = $$.getXDomainPadding(xDomain),
  1449. min = 0, max = 0;
  1450. // show center of x domain if min and max are the same
  1451. if ((firstX - lastX) === 0 && !$$.isCategorized()) {
  1452. if ($$.isTimeSeries()) {
  1453. firstX = new Date(firstX.getTime() * 0.5);
  1454. lastX = new Date(lastX.getTime() * 1.5);
  1455. } else {
  1456. firstX = firstX === 0 ? 1 : (firstX * 0.5);
  1457. lastX = lastX === 0 ? -1 : (lastX * 1.5);
  1458. }
  1459. }
  1460. if (firstX || firstX === 0) {
  1461. min = $$.isTimeSeries() ? new Date(firstX.getTime() - padding.left) : firstX - padding.left;
  1462. }
  1463. if (lastX || lastX === 0) {
  1464. max = $$.isTimeSeries() ? new Date(lastX.getTime() + padding.right) : lastX + padding.right;
  1465. }
  1466. return [min, max];
  1467. };
  1468. c3_chart_internal_fn.updateXDomain = function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) {
  1469. var $$ = this, config = $$.config;
  1470. if (withUpdateOrgXDomain) {
  1471. $$.x.domain(domain ? domain : $$.d3.extent($$.getXDomain(targets)));
  1472. $$.orgXDomain = $$.x.domain();
  1473. if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
  1474. $$.subX.domain($$.x.domain());
  1475. if ($$.brush) { $$.brush.scale($$.subX); }
  1476. }
  1477. if (withUpdateXDomain) {
  1478. $$.x.domain(domain ? domain : (!$$.brush || $$.brush.empty()) ? $$.orgXDomain : $$.brush.extent());
  1479. if (config.zoom_enabled) { $$.zoom.scale($$.x).updateScaleExtent(); }
  1480. }
  1481. // Trim domain when too big by zoom mousemove event
  1482. if (withTrim) { $$.x.domain($$.trimXDomain($$.x.orgDomain())); }
  1483. return $$.x.domain();
  1484. };
  1485. c3_chart_internal_fn.trimXDomain = function (domain) {
  1486. var zoomDomain = this.getZoomDomain(),
  1487. min = zoomDomain[0], max = zoomDomain[1];
  1488. if (domain[0] <= min) {
  1489. domain[1] = +domain[1] + (min - domain[0]);
  1490. domain[0] = min;
  1491. }
  1492. if (max <= domain[1]) {
  1493. domain[0] = +domain[0] - (domain[1] - max);
  1494. domain[1] = max;
  1495. }
  1496. return domain;
  1497. };
  1498. c3_chart_internal_fn.isX = function (key) {
  1499. var $$ = this, config = $$.config;
  1500. return (config.data_x && key === config.data_x) || (notEmpty(config.data_xs) && hasValue(config.data_xs, key));
  1501. };
  1502. c3_chart_internal_fn.isNotX = function (key) {
  1503. return !this.isX(key);
  1504. };
  1505. c3_chart_internal_fn.getXKey = function (id) {
  1506. var $$ = this, config = $$.config;
  1507. return config.data_x ? config.data_x : notEmpty(config.data_xs) ? config.data_xs[id] : null;
  1508. };
  1509. c3_chart_internal_fn.getXValuesOfXKey = function (key, targets) {
  1510. var $$ = this,
  1511. xValues, ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : [];
  1512. ids.forEach(function (id) {
  1513. if ($$.getXKey(id) === key) {
  1514. xValues = $$.data.xs[id];
  1515. }
  1516. });
  1517. return xValues;
  1518. };
  1519. c3_chart_internal_fn.getIndexByX = function (x) {
  1520. var $$ = this,
  1521. data = $$.filterByX($$.data.targets, x);
  1522. return data.length ? data[0].index : null;
  1523. };
  1524. c3_chart_internal_fn.getXValue = function (id, i) {
  1525. var $$ = this;
  1526. return id in $$.data.xs && $$.data.xs[id] && isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i;
  1527. };
  1528. c3_chart_internal_fn.getOtherTargetXs = function () {
  1529. var $$ = this,
  1530. idsForX = Object.keys($$.data.xs);
  1531. return idsForX.length ? $$.data.xs[idsForX[0]] : null;
  1532. };
  1533. c3_chart_internal_fn.getOtherTargetX = function (index) {
  1534. var xs = this.getOtherTargetXs();
  1535. return xs && index < xs.length ? xs[index] : null;
  1536. };
  1537. c3_chart_internal_fn.addXs = function (xs) {
  1538. var $$ = this;
  1539. Object.keys(xs).forEach(function (id) {
  1540. $$.config.data_xs[id] = xs[id];
  1541. });
  1542. };
  1543. c3_chart_internal_fn.hasMultipleX = function (xs) {
  1544. return this.d3.set(Object.keys(xs).map(function (id) { return xs[id]; })).size() > 1;
  1545. };
  1546. c3_chart_internal_fn.isMultipleX = function () {
  1547. return notEmpty(this.config.data_xs) || !this.config.data_xSort || this.hasType('scatter');
  1548. };
  1549. c3_chart_internal_fn.addName = function (data) {
  1550. var $$ = this, name;
  1551. if (data) {
  1552. name = $$.config.data_names[data.id];
  1553. data.name = name !== undefined ? name : data.id;
  1554. }
  1555. return data;
  1556. };
  1557. c3_chart_internal_fn.getValueOnIndex = function (values, index) {
  1558. var valueOnIndex = values.filter(function (v) { return v.index === index; });
  1559. return valueOnIndex.length ? valueOnIndex[0] : null;
  1560. };
  1561. c3_chart_internal_fn.updateTargetX = function (targets, x) {
  1562. var $$ = this;
  1563. targets.forEach(function (t) {
  1564. t.values.forEach(function (v, i) {
  1565. v.x = $$.generateTargetX(x[i], t.id, i);
  1566. });
  1567. $$.data.xs[t.id] = x;
  1568. });
  1569. };
  1570. c3_chart_internal_fn.updateTargetXs = function (targets, xs) {
  1571. var $$ = this;
  1572. targets.forEach(function (t) {
  1573. if (xs[t.id]) {
  1574. $$.updateTargetX([t], xs[t.id]);
  1575. }
  1576. });
  1577. };
  1578. c3_chart_internal_fn.generateTargetX = function (rawX, id, index) {
  1579. var $$ = this, x;
  1580. if ($$.isTimeSeries()) {
  1581. x = rawX ? $$.parseDate(rawX) : $$.parseDate($$.getXValue(id, index));
  1582. }
  1583. else if ($$.isCustomX() && !$$.isCategorized()) {
  1584. x = isValue(rawX) ? +rawX : $$.getXValue(id, index);
  1585. }
  1586. else {
  1587. x = index;
  1588. }
  1589. return x;
  1590. };
  1591. c3_chart_internal_fn.cloneTarget = function (target) {
  1592. return {
  1593. id : target.id,
  1594. id_org : target.id_org,
  1595. values : target.values.map(function (d) {
  1596. return {x: d.x, value: d.value, id: d.id};
  1597. })
  1598. };
  1599. };
  1600. c3_chart_internal_fn.updateXs = function () {
  1601. var $$ = this;
  1602. if ($$.data.targets.length) {
  1603. $$.xs = [];
  1604. $$.data.targets[0].values.forEach(function (v) {
  1605. $$.xs[v.index] = v.x;
  1606. });
  1607. }
  1608. };
  1609. c3_chart_internal_fn.getPrevX = function (i) {
  1610. var x = this.xs[i - 1];
  1611. return typeof x !== 'undefined' ? x : null;
  1612. };
  1613. c3_chart_internal_fn.getNextX = function (i) {
  1614. var x = this.xs[i + 1];
  1615. return typeof x !== 'undefined' ? x : null;
  1616. };
  1617. c3_chart_internal_fn.getMaxDataCount = function () {
  1618. var $$ = this;
  1619. return $$.d3.max($$.data.targets, function (t) { return t.values.length; });
  1620. };
  1621. c3_chart_internal_fn.getMaxDataCountTarget = function (targets) {
  1622. var length = targets.length, max = 0, maxTarget;
  1623. if (length > 1) {
  1624. targets.forEach(function (t) {
  1625. if (t.values.length > max) {
  1626. maxTarget = t;
  1627. max = t.values.length;
  1628. }
  1629. });
  1630. } else {
  1631. maxTarget = length ? targets[0] : null;
  1632. }
  1633. return maxTarget;
  1634. };
  1635. c3_chart_internal_fn.getEdgeX = function (targets) {
  1636. var $$ = this;
  1637. return !targets.length ? [0, 0] : [
  1638. $$.d3.min(targets, function (t) { return t.values[0].x; }),
  1639. $$.d3.max(targets, function (t) { return t.values[t.values.length - 1].x; })
  1640. ];
  1641. };
  1642. c3_chart_internal_fn.mapToIds = function (targets) {
  1643. return targets.map(function (d) { return d.id; });
  1644. };
  1645. c3_chart_internal_fn.mapToTargetIds = function (ids) {
  1646. var $$ = this;
  1647. return ids ? [].concat(ids) : $$.mapToIds($$.data.targets);
  1648. };
  1649. c3_chart_internal_fn.hasTarget = function (targets, id) {
  1650. var ids = this.mapToIds(targets), i;
  1651. for (i = 0; i < ids.length; i++) {
  1652. if (ids[i] === id) {
  1653. return true;
  1654. }
  1655. }
  1656. return false;
  1657. };
  1658. c3_chart_internal_fn.isTargetToShow = function (targetId) {
  1659. return this.hiddenTargetIds.indexOf(targetId) < 0;
  1660. };
  1661. c3_chart_internal_fn.isLegendToShow = function (targetId) {
  1662. return this.hiddenLegendIds.indexOf(targetId) < 0;
  1663. };
  1664. c3_chart_internal_fn.filterTargetsToShow = function (targets) {
  1665. var $$ = this;
  1666. return targets.filter(function (t) { return $$.isTargetToShow(t.id); });
  1667. };
  1668. c3_chart_internal_fn.mapTargetsToUniqueXs = function (targets) {
  1669. var $$ = this;
  1670. var xs = $$.d3.set($$.d3.merge(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))).values();
  1671. xs = $$.isTimeSeries() ? xs.map(function (x) { return new Date(+x); }) : xs.map(function (x) { return +x; });
  1672. return xs.sort(function (a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; });
  1673. };
  1674. c3_chart_internal_fn.addHiddenTargetIds = function (targetIds) {
  1675. this.hiddenTargetIds = this.hiddenTargetIds.concat(targetIds);
  1676. };
  1677. c3_chart_internal_fn.removeHiddenTargetIds = function (targetIds) {
  1678. this.hiddenTargetIds = this.hiddenTargetIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
  1679. };
  1680. c3_chart_internal_fn.addHiddenLegendIds = function (targetIds) {
  1681. this.hiddenLegendIds = this.hiddenLegendIds.concat(targetIds);
  1682. };
  1683. c3_chart_internal_fn.removeHiddenLegendIds = function (targetIds) {
  1684. this.hiddenLegendIds = this.hiddenLegendIds.filter(function (id) { return targetIds.indexOf(id) < 0; });
  1685. };
  1686. c3_chart_internal_fn.getValuesAsIdKeyed = function (targets) {
  1687. var ys = {};
  1688. targets.forEach(function (t) {
  1689. ys[t.id] = [];
  1690. t.values.forEach(function (v) {
  1691. ys[t.id].push(v.value);
  1692. });
  1693. });
  1694. return ys;
  1695. };
  1696. c3_chart_internal_fn.checkValueInTargets = function (targets, checker) {
  1697. var ids = Object.keys(targets), i, j, values;
  1698. for (i = 0; i < ids.length; i++) {
  1699. values = targets[ids[i]].values;
  1700. for (j = 0; j < values.length; j++) {
  1701. if (checker(values[j].value)) {
  1702. return true;
  1703. }
  1704. }
  1705. }
  1706. return false;
  1707. };
  1708. c3_chart_internal_fn.hasNegativeValueInTargets = function (targets) {
  1709. return this.checkValueInTargets(targets, function (v) { return v < 0; });
  1710. };
  1711. c3_chart_internal_fn.hasPositiveValueInTargets = function (targets) {
  1712. return this.checkValueInTargets(targets, function (v) { return v > 0; });
  1713. };
  1714. c3_chart_internal_fn.isOrderDesc = function () {
  1715. var config = this.config;
  1716. return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'desc';
  1717. };
  1718. c3_chart_internal_fn.isOrderAsc = function () {
  1719. var config = this.config;
  1720. return typeof(config.data_order) === 'string' && config.data_order.toLowerCase() === 'asc';
  1721. };
  1722. c3_chart_internal_fn.orderTargets = function (targets) {
  1723. var $$ = this, config = $$.config, orderAsc = $$.isOrderAsc(), orderDesc = $$.isOrderDesc();
  1724. if (orderAsc || orderDesc) {
  1725. targets.sort(function (t1, t2) {
  1726. var reducer = function (p, c) { return p + Math.abs(c.value); };
  1727. var t1Sum = t1.values.reduce(reducer, 0),
  1728. t2Sum = t2.values.reduce(reducer, 0);
  1729. return orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum;
  1730. });
  1731. } else if (isFunction(config.data_order)) {
  1732. targets.sort(config.data_order);
  1733. } // TODO: accept name array for order
  1734. return targets;
  1735. };
  1736. c3_chart_internal_fn.filterByX = function (targets, x) {
  1737. return this.d3.merge(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; });
  1738. };
  1739. c3_chart_internal_fn.filterRemoveNull = function (data) {
  1740. return data.filter(function (d) { return isValue(d.value); });
  1741. };
  1742. c3_chart_internal_fn.filterByXDomain = function (targets, xDomain) {
  1743. return targets.map(function (t) {
  1744. return {
  1745. id: t.id,
  1746. id_org: t.id_org,
  1747. values: t.values.filter(function (v) {
  1748. return xDomain[0] <= v.x && v.x <= xDomain[1];
  1749. })
  1750. };
  1751. });
  1752. };
  1753. c3_chart_internal_fn.hasDataLabel = function () {
  1754. var config = this.config;
  1755. if (typeof config.data_labels === 'boolean' && config.data_labels) {
  1756. return true;
  1757. } else if (typeof config.data_labels === 'object' && notEmpty(config.data_labels)) {
  1758. return true;
  1759. }
  1760. return false;
  1761. };
  1762. c3_chart_internal_fn.getDataLabelLength = function (min, max, key) {
  1763. var $$ = this,
  1764. lengths = [0, 0], paddingCoef = 1.3;
  1765. $$.selectChart.select('svg').selectAll('.dummy')
  1766. .data([min, max])
  1767. .enter().append('text')
  1768. .text(function (d) { return $$.dataLabelFormat(d.id)(d); })
  1769. .each(function (d, i) {
  1770. lengths[i] = this.getBoundingClientRect()[key] * paddingCoef;
  1771. })
  1772. .remove();
  1773. return lengths;
  1774. };
  1775. c3_chart_internal_fn.isNoneArc = function (d) {
  1776. return this.hasTarget(this.data.targets, d.id);
  1777. },
  1778. c3_chart_internal_fn.isArc = function (d) {
  1779. return 'data' in d && this.hasTarget(this.data.targets, d.data.id);
  1780. };
  1781. c3_chart_internal_fn.findSameXOfValues = function (values, index) {
  1782. var i, targetX = values[index].x, sames = [];
  1783. for (i = index - 1; i >= 0; i--) {
  1784. if (targetX !== values[i].x) { break; }
  1785. sames.push(values[i]);
  1786. }
  1787. for (i = index; i < values.length; i++) {
  1788. if (targetX !== values[i].x) { break; }
  1789. sames.push(values[i]);
  1790. }
  1791. return sames;
  1792. };
  1793. c3_chart_internal_fn.findClosestFromTargets = function (targets, pos) {
  1794. var $$ = this, candidates;
  1795. // map to array of closest points of each target
  1796. candidates = targets.map(function (target) {
  1797. return $$.findClosest(target.values, pos);
  1798. });
  1799. // decide closest point and return
  1800. return $$.findClosest(candidates, pos);
  1801. };
  1802. c3_chart_internal_fn.findClosest = function (values, pos) {
  1803. var $$ = this, minDist = $$.config.point_sensitivity, closest;
  1804. // find mouseovering bar
  1805. values.filter(function (v) { return v && $$.isBarType(v.id); }).forEach(function (v) {
  1806. var shape = $$.main.select('.' + CLASS.bars + $$.getTargetSelectorSuffix(v.id) + ' .' + CLASS.bar + '-' + v.index).node();
  1807. if (!closest && $$.isWithinBar(shape)) {
  1808. closest = v;
  1809. }
  1810. });
  1811. // find closest point from non-bar
  1812. values.filter(function (v) { return v && !$$.isBarType(v.id); }).forEach(function (v) {
  1813. var d = $$.dist(v, pos);
  1814. if (d < minDist) {
  1815. minDist = d;
  1816. closest = v;
  1817. }
  1818. });
  1819. return closest;
  1820. };
  1821. c3_chart_internal_fn.dist = function (data, pos) {
  1822. var $$ = this, config = $$.config,
  1823. xIndex = config.axis_rotated ? 1 : 0,
  1824. yIndex = config.axis_rotated ? 0 : 1,
  1825. y = $$.circleY(data, data.index),
  1826. x = $$.x(data.x);
  1827. return Math.sqrt(Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2));
  1828. };
  1829. c3_chart_internal_fn.convertValuesToStep = function (values) {
  1830. var converted = [].concat(values), i;
  1831. if (!this.isCategorized()) {
  1832. return values;
  1833. }
  1834. for (i = values.length + 1; 0 < i; i--) {
  1835. converted[i] = converted[i - 1];
  1836. }
  1837. converted[0] = {
  1838. x: converted[0].x - 1,
  1839. value: converted[0].value,
  1840. id: converted[0].id
  1841. };
  1842. converted[values.length + 1] = {
  1843. x: converted[values.length].x + 1,
  1844. value: converted[values.length].value,
  1845. id: converted[values.length].id
  1846. };
  1847. return converted;
  1848. };
  1849. c3_chart_internal_fn.updateDataAttributes = function (name, attrs) {
  1850. var $$ = this, config = $$.config, current = config['data_' + name];
  1851. if (typeof attrs === 'undefined') { return current; }
  1852. Object.keys(attrs).forEach(function (id) {
  1853. current[id] = attrs[id];
  1854. });
  1855. $$.redraw({withLegend: true});
  1856. return current;
  1857. };
  1858. c3_chart_internal_fn.convertUrlToData = function (url, mimeType, headers, keys, done) {
  1859. var $$ = this, type = mimeType ? mimeType : 'csv';
  1860. var req = $$.d3.xhr(url);
  1861. if (headers) {
  1862. Object.keys(headers).forEach(function (header) {
  1863. req.header(header, headers[header]);
  1864. });
  1865. }
  1866. req.get(function (error, data) {
  1867. var d;
  1868. if (!data) {
  1869. throw new Error(error.responseURL + ' ' + error.status + ' (' + error.statusText + ')');
  1870. }
  1871. if (type === 'json') {
  1872. d = $$.convertJsonToData(JSON.parse(data.response), keys);
  1873. } else if (type === 'tsv') {
  1874. d = $$.convertTsvToData(data.response);
  1875. } else {
  1876. d = $$.convertCsvToData(data.response);
  1877. }
  1878. done.call($$, d);
  1879. });
  1880. };
  1881. c3_chart_internal_fn.convertXsvToData = function (xsv, parser) {
  1882. var rows = parser.parseRows(xsv), d;
  1883. if (rows.length === 1) {
  1884. d = [{}];
  1885. rows[0].forEach(function (id) {
  1886. d[0][id] = null;
  1887. });
  1888. } else {
  1889. d = parser.parse(xsv);
  1890. }
  1891. return d;
  1892. };
  1893. c3_chart_internal_fn.convertCsvToData = function (csv) {
  1894. return this.convertXsvToData(csv, this.d3.csv);
  1895. };
  1896. c3_chart_internal_fn.convertTsvToData = function (tsv) {
  1897. return this.convertXsvToData(tsv, this.d3.tsv);
  1898. };
  1899. c3_chart_internal_fn.convertJsonToData = function (json, keys) {
  1900. var $$ = this,
  1901. new_rows = [], targetKeys, data;
  1902. if (keys) { // when keys specified, json would be an array that includes objects
  1903. if (keys.x) {
  1904. targetKeys = keys.value.concat(keys.x);
  1905. $$.config.data_x = keys.x;
  1906. } else {
  1907. targetKeys = keys.value;
  1908. }
  1909. new_rows.push(targetKeys);
  1910. json.forEach(function (o) {
  1911. var new_row = [];
  1912. targetKeys.forEach(function (key) {
  1913. // convert undefined to null because undefined data will be removed in convertDataToTargets()
  1914. var v = isUndefined(o[key]) ? null : o[key];
  1915. new_row.push(v);
  1916. });
  1917. new_rows.push(new_row);
  1918. });
  1919. data = $$.convertRowsToData(new_rows);
  1920. } else {
  1921. Object.keys(json).forEach(function (key) {
  1922. new_rows.push([key].concat(json[key]));
  1923. });
  1924. data = $$.convertColumnsToData(new_rows);
  1925. }
  1926. return data;
  1927. };
  1928. c3_chart_internal_fn.convertRowsToData = function (rows) {
  1929. var keys = rows[0], new_row = {}, new_rows = [], i, j;
  1930. for (i = 1; i < rows.length; i++) {
  1931. new_row = {};
  1932. for (j = 0; j < rows[i].length; j++) {
  1933. if (isUndefined(rows[i][j])) {
  1934. throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
  1935. }
  1936. new_row[keys[j]] = rows[i][j];
  1937. }
  1938. new_rows.push(new_row);
  1939. }
  1940. return new_rows;
  1941. };
  1942. c3_chart_internal_fn.convertColumnsToData = function (columns) {
  1943. var new_rows = [], i, j, key;
  1944. for (i = 0; i < columns.length; i++) {
  1945. key = columns[i][0];
  1946. for (j = 1; j < columns[i].length; j++) {
  1947. if (isUndefined(new_rows[j - 1])) {
  1948. new_rows[j - 1] = {};
  1949. }
  1950. if (isUndefined(columns[i][j])) {
  1951. throw new Error("Source data is missing a component at (" + i + "," + j + ")!");
  1952. }
  1953. new_rows[j - 1][key] = columns[i][j];
  1954. }
  1955. }
  1956. return new_rows;
  1957. };
  1958. c3_chart_internal_fn.convertDataToTargets = function (data, appendXs) {
  1959. var $$ = this, config = $$.config,
  1960. ids = $$.d3.keys(data[0]).filter($$.isNotX, $$),
  1961. xs = $$.d3.keys(data[0]).filter($$.isX, $$),
  1962. targets;
  1963. // save x for update data by load when custom x and c3.x API
  1964. ids.forEach(function (id) {
  1965. var xKey = $$.getXKey(id);
  1966. if ($$.isCustomX() || $$.isTimeSeries()) {
  1967. // if included in input data
  1968. if (xs.indexOf(xKey) >= 0) {
  1969. $$.data.xs[id] = (appendXs && $$.data.xs[id] ? $$.data.xs[id] : []).concat(
  1970. data.map(function (d) { return d[xKey]; })
  1971. .filter(isValue)
  1972. .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })
  1973. );
  1974. }
  1975. // if not included in input data, find from preloaded data of other id's x
  1976. else if (config.data_x) {
  1977. $$.data.xs[id] = $$.getOtherTargetXs();
  1978. }
  1979. // if not included in input data, find from preloaded data
  1980. else if (notEmpty(config.data_xs)) {
  1981. $$.data.xs[id] = $$.getXValuesOfXKey(xKey, $$.data.targets);
  1982. }
  1983. // MEMO: if no x included, use same x of current will be used
  1984. } else {
  1985. $$.data.xs[id] = data.map(function (d, i) { return i; });
  1986. }
  1987. });
  1988. // check x is defined
  1989. ids.forEach(function (id) {
  1990. if (!$$.data.xs[id]) {
  1991. throw new Error('x is not defined for id = "' + id + '".');
  1992. }
  1993. });
  1994. // convert to target
  1995. targets = ids.map(function (id, index) {
  1996. var convertedId = config.data_idConverter(id);
  1997. return {
  1998. id: convertedId,
  1999. id_org: id,
  2000. values: data.map(function (d, i) {
  2001. var xKey = $$.getXKey(id), rawX = d[xKey], x = $$.generateTargetX(rawX, id, i),
  2002. value = d[id] !== null && !isNaN(d[id]) ? +d[id] : null;
  2003. // use x as categories if custom x and categorized
  2004. if ($$.isCustomX() && $$.isCategorized() && index === 0 && rawX) {
  2005. if (i === 0) { config.axis_x_categories = []; }
  2006. config.axis_x_categories.push(rawX);
  2007. }
  2008. // mark as x = undefined if value is undefined and filter to remove after mapped
  2009. if (isUndefined(d[id]) || $$.data.xs[id].length <= i) {
  2010. x = undefined;
  2011. }
  2012. return {x: x, value: value, id: convertedId};
  2013. }).filter(function (v) { return isDefined(v.x); })
  2014. };
  2015. });
  2016. // finish targets
  2017. targets.forEach(function (t) {
  2018. var i;
  2019. // sort values by its x
  2020. if (config.data_xSort) {
  2021. t.values = t.values.sort(function (v1, v2) {
  2022. var x1 = v1.x || v1.x === 0 ? v1.x : Infinity,
  2023. x2 = v2.x || v2.x === 0 ? v2.x : Infinity;
  2024. return x1 - x2;
  2025. });
  2026. }
  2027. // indexing each value
  2028. i = 0;
  2029. t.values.forEach(function (v) {
  2030. v.index = i++;
  2031. });
  2032. // this needs to be sorted because its index and value.index is identical
  2033. $$.data.xs[t.id].sort(function (v1, v2) {
  2034. return v1 - v2;
  2035. });
  2036. });
  2037. // cache information about values
  2038. $$.hasNegativeValue = $$.hasNegativeValueInTargets(targets);
  2039. $$.hasPositiveValue = $$.hasPositiveValueInTargets(targets);
  2040. // set target types
  2041. if (config.data_type) {
  2042. $$.setTargetType($$.mapToIds(targets).filter(function (id) { return ! (id in config.data_types); }), config.data_type);
  2043. }
  2044. // cache as original id keyed
  2045. targets.forEach(function (d) {
  2046. $$.addCache(d.id_org, d);
  2047. });
  2048. return targets;
  2049. };
  2050. c3_chart_internal_fn.load = function (targets, args) {
  2051. var $$ = this;
  2052. if (targets) {
  2053. // filter loading targets if needed
  2054. if (args.filter) {
  2055. targets = targets.filter(args.filter);
  2056. }
  2057. // set type if args.types || args.type specified
  2058. if (args.type || args.types) {
  2059. targets.forEach(function (t) {
  2060. var type = args.types && args.types[t.id] ? args.types[t.id] : args.type;
  2061. $$.setTargetType(t.id, type);
  2062. });
  2063. }
  2064. // Update/Add data
  2065. $$.data.targets.forEach(function (d) {
  2066. for (var i = 0; i < targets.length; i++) {
  2067. if (d.id === targets[i].id) {
  2068. d.values = targets[i].values;
  2069. targets.splice(i, 1);
  2070. break;
  2071. }
  2072. }
  2073. });
  2074. $$.data.targets = $$.data.targets.concat(targets); // add remained
  2075. }
  2076. // Set targets
  2077. $$.updateTargets($$.data.targets);
  2078. // Redraw with new targets
  2079. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
  2080. if (args.done) { args.done(); }
  2081. };
  2082. c3_chart_internal_fn.loadFromArgs = function (args) {
  2083. var $$ = this;
  2084. if (args.data) {
  2085. $$.load($$.convertDataToTargets(args.data), args);
  2086. }
  2087. else if (args.url) {
  2088. $$.convertUrlToData(args.url, args.mimeType, args.headers, args.keys, function (data) {
  2089. $$.load($$.convertDataToTargets(data), args);
  2090. });
  2091. }
  2092. else if (args.json) {
  2093. $$.load($$.convertDataToTargets($$.convertJsonToData(args.json, args.keys)), args);
  2094. }
  2095. else if (args.rows) {
  2096. $$.load($$.convertDataToTargets($$.convertRowsToData(args.rows)), args);
  2097. }
  2098. else if (args.columns) {
  2099. $$.load($$.convertDataToTargets($$.convertColumnsToData(args.columns)), args);
  2100. }
  2101. else {
  2102. $$.load(null, args);
  2103. }
  2104. };
  2105. c3_chart_internal_fn.unload = function (targetIds, done) {
  2106. var $$ = this;
  2107. if (!done) {
  2108. done = function () {};
  2109. }
  2110. // filter existing target
  2111. targetIds = targetIds.filter(function (id) { return $$.hasTarget($$.data.targets, id); });
  2112. // If no target, call done and return
  2113. if (!targetIds || targetIds.length === 0) {
  2114. done();
  2115. return;
  2116. }
  2117. $$.svg.selectAll(targetIds.map(function (id) { return $$.selectorTarget(id); }))
  2118. .transition()
  2119. .style('opacity', 0)
  2120. .remove()
  2121. .call($$.endall, done);
  2122. targetIds.forEach(function (id) {
  2123. // Reset fadein for future load
  2124. $$.withoutFadeIn[id] = false;
  2125. // Remove target's elements
  2126. if ($$.legend) {
  2127. $$.legend.selectAll('.' + CLASS.legendItem + $$.getTargetSelectorSuffix(id)).remove();
  2128. }
  2129. // Remove target
  2130. $$.data.targets = $$.data.targets.filter(function (t) {
  2131. return t.id !== id;
  2132. });
  2133. });
  2134. };
  2135. c3_chart_internal_fn.categoryName = function (i) {
  2136. var config = this.config;
  2137. return i < config.axis_x_categories.length ? config.axis_x_categories[i] : i;
  2138. };
  2139. c3_chart_internal_fn.initEventRect = function () {
  2140. var $$ = this;
  2141. $$.main.select('.' + CLASS.chart).append("g")
  2142. .attr("class", CLASS.eventRects)
  2143. .style('fill-opacity', 0);
  2144. };
  2145. c3_chart_internal_fn.redrawEventRect = function () {
  2146. var $$ = this, config = $$.config,
  2147. eventRectUpdate, maxDataCountTarget,
  2148. isMultipleX = $$.isMultipleX();
  2149. // rects for mouseover
  2150. var eventRects = $$.main.select('.' + CLASS.eventRects)
  2151. .style('cursor', config.zoom_enabled ? config.axis_rotated ? 'ns-resize' : 'ew-resize' : null)
  2152. .classed(CLASS.eventRectsMultiple, isMultipleX)
  2153. .classed(CLASS.eventRectsSingle, !isMultipleX);
  2154. // clear old rects
  2155. eventRects.selectAll('.' + CLASS.eventRect).remove();
  2156. // open as public variable
  2157. $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
  2158. if (isMultipleX) {
  2159. eventRectUpdate = $$.eventRect.data([0]);
  2160. // enter : only one rect will be added
  2161. $$.generateEventRectsForMultipleXs(eventRectUpdate.enter());
  2162. // update
  2163. $$.updateEventRect(eventRectUpdate);
  2164. // exit : not needed because always only one rect exists
  2165. }
  2166. else {
  2167. // Set data and update $$.eventRect
  2168. maxDataCountTarget = $$.getMaxDataCountTarget($$.data.targets);
  2169. eventRects.datum(maxDataCountTarget ? maxDataCountTarget.values : []);
  2170. $$.eventRect = eventRects.selectAll('.' + CLASS.eventRect);
  2171. eventRectUpdate = $$.eventRect.data(function (d) { return d; });
  2172. // enter
  2173. $$.generateEventRectsForSingleX(eventRectUpdate.enter());
  2174. // update
  2175. $$.updateEventRect(eventRectUpdate);
  2176. // exit
  2177. eventRectUpdate.exit().remove();
  2178. }
  2179. };
  2180. c3_chart_internal_fn.updateEventRect = function (eventRectUpdate) {
  2181. var $$ = this, config = $$.config,
  2182. x, y, w, h, rectW, rectX;
  2183. // set update selection if null
  2184. eventRectUpdate = eventRectUpdate || $$.eventRect.data(function (d) { return d; });
  2185. if ($$.isMultipleX()) {
  2186. // TODO: rotated not supported yet
  2187. x = 0;
  2188. y = 0;
  2189. w = $$.width;
  2190. h = $$.height;
  2191. }
  2192. else {
  2193. if (($$.isCustomX() || $$.isTimeSeries()) && !$$.isCategorized()) {
  2194. // update index for x that is used by prevX and nextX
  2195. $$.updateXs();
  2196. rectW = function (d) {
  2197. var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index);
  2198. // if there this is a single data point make the eventRect full width (or height)
  2199. if (prevX === null && nextX === null) {
  2200. return config.axis_rotated ? $$.height : $$.width;
  2201. }
  2202. if (prevX === null) { prevX = $$.x.domain()[0]; }
  2203. if (nextX === null) { nextX = $$.x.domain()[1]; }
  2204. return Math.max(0, ($$.x(nextX) - $$.x(prevX)) / 2);
  2205. };
  2206. rectX = function (d) {
  2207. var prevX = $$.getPrevX(d.index), nextX = $$.getNextX(d.index),
  2208. thisX = $$.data.xs[d.id][d.index];
  2209. // if there this is a single data point position the eventRect at 0
  2210. if (prevX === null && nextX === null) {
  2211. return 0;
  2212. }
  2213. if (prevX === null) { prevX = $$.x.domain()[0]; }
  2214. return ($$.x(thisX) + $$.x(prevX)) / 2;
  2215. };
  2216. } else {
  2217. rectW = $$.getEventRectWidth();
  2218. rectX = function (d) {
  2219. return $$.x(d.x) - (rectW / 2);
  2220. };
  2221. }
  2222. x = config.axis_rotated ? 0 : rectX;
  2223. y = config.axis_rotated ? rectX : 0;
  2224. w = config.axis_rotated ? $$.width : rectW;
  2225. h = config.axis_rotated ? rectW : $$.height;
  2226. }
  2227. eventRectUpdate
  2228. .attr('class', $$.classEvent.bind($$))
  2229. .attr("x", x)
  2230. .attr("y", y)
  2231. .attr("width", w)
  2232. .attr("height", h);
  2233. };
  2234. c3_chart_internal_fn.generateEventRectsForSingleX = function (eventRectEnter) {
  2235. var $$ = this, d3 = $$.d3, config = $$.config;
  2236. eventRectEnter.append("rect")
  2237. .attr("class", $$.classEvent.bind($$))
  2238. .style("cursor", config.data_selection_enabled && config.data_selection_grouped ? "pointer" : null)
  2239. .on('mouseover', function (d) {
  2240. var index = d.index;
  2241. if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
  2242. if ($$.hasArcType()) { return; }
  2243. // Expand shapes for selection
  2244. if (config.point_focus_expand_enabled) { $$.expandCircles(index, null, true); }
  2245. $$.expandBars(index, null, true);
  2246. // Call event handler
  2247. $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
  2248. config.data_onmouseover.call($$.api, d);
  2249. });
  2250. })
  2251. .on('mouseout', function (d) {
  2252. var index = d.index;
  2253. if (!$$.config) { return; } // chart is destroyed
  2254. if ($$.hasArcType()) { return; }
  2255. $$.hideXGridFocus();
  2256. $$.hideTooltip();
  2257. // Undo expanded shapes
  2258. $$.unexpandCircles();
  2259. $$.unexpandBars();
  2260. // Call event handler
  2261. $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
  2262. config.data_onmouseout.call($$.api, d);
  2263. });
  2264. })
  2265. .on('mousemove', function (d) {
  2266. var selectedData, index = d.index,
  2267. eventRect = $$.svg.select('.' + CLASS.eventRect + '-' + index);
  2268. if ($$.dragging || $$.flowing) { return; } // do nothing while dragging/flowing
  2269. if ($$.hasArcType()) { return; }
  2270. if ($$.isStepType(d) && $$.config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
  2271. index -= 1;
  2272. }
  2273. // Show tooltip
  2274. selectedData = $$.filterTargetsToShow($$.data.targets).map(function (t) {
  2275. return $$.addName($$.getValueOnIndex(t.values, index));
  2276. });
  2277. if (config.tooltip_grouped) {
  2278. $$.showTooltip(selectedData, this);
  2279. $$.showXGridFocus(selectedData);
  2280. }
  2281. if (config.tooltip_grouped && (!config.data_selection_enabled || config.data_selection_grouped)) {
  2282. return;
  2283. }
  2284. $$.main.selectAll('.' + CLASS.shape + '-' + index)
  2285. .each(function () {
  2286. d3.select(this).classed(CLASS.EXPANDED, true);
  2287. if (config.data_selection_enabled) {
  2288. eventRect.style('cursor', config.data_selection_grouped ? 'pointer' : null);
  2289. }
  2290. if (!config.tooltip_grouped) {
  2291. $$.hideXGridFocus();
  2292. $$.hideTooltip();
  2293. if (!config.data_selection_grouped) {
  2294. $$.unexpandCircles(index);
  2295. $$.unexpandBars(index);
  2296. }
  2297. }
  2298. })
  2299. .filter(function (d) {
  2300. return $$.isWithinShape(this, d);
  2301. })
  2302. .each(function (d) {
  2303. if (config.data_selection_enabled && (config.data_selection_grouped || config.data_selection_isselectable(d))) {
  2304. eventRect.style('cursor', 'pointer');
  2305. }
  2306. if (!config.tooltip_grouped) {
  2307. $$.showTooltip([d], this);
  2308. $$.showXGridFocus([d]);
  2309. if (config.point_focus_expand_enabled) { $$.expandCircles(index, d.id, true); }
  2310. $$.expandBars(index, d.id, true);
  2311. }
  2312. });
  2313. })
  2314. .on('click', function (d) {
  2315. var index = d.index;
  2316. if ($$.hasArcType() || !$$.toggleShape) { return; }
  2317. if ($$.cancelClick) {
  2318. $$.cancelClick = false;
  2319. return;
  2320. }
  2321. if ($$.isStepType(d) && config.line_step_type === 'step-after' && d3.mouse(this)[0] < $$.x($$.getXValue(d.id, index))) {
  2322. index -= 1;
  2323. }
  2324. $$.main.selectAll('.' + CLASS.shape + '-' + index).each(function (d) {
  2325. if (config.data_selection_grouped || $$.isWithinShape(this, d)) {
  2326. $$.toggleShape(this, d, index);
  2327. $$.config.data_onclick.call($$.api, d, this);
  2328. }
  2329. });
  2330. })
  2331. .call(
  2332. config.data_selection_draggable && $$.drag ? (
  2333. d3.behavior.drag().origin(Object)
  2334. .on('drag', function () { $$.drag(d3.mouse(this)); })
  2335. .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
  2336. .on('dragend', function () { $$.dragend(); })
  2337. ) : function () {}
  2338. );
  2339. };
  2340. c3_chart_internal_fn.generateEventRectsForMultipleXs = function (eventRectEnter) {
  2341. var $$ = this, d3 = $$.d3, config = $$.config;
  2342. function mouseout() {
  2343. $$.svg.select('.' + CLASS.eventRect).style('cursor', null);
  2344. $$.hideXGridFocus();
  2345. $$.hideTooltip();
  2346. $$.unexpandCircles();
  2347. $$.unexpandBars();
  2348. }
  2349. eventRectEnter.append('rect')
  2350. .attr('x', 0)
  2351. .attr('y', 0)
  2352. .attr('width', $$.width)
  2353. .attr('height', $$.height)
  2354. .attr('class', CLASS.eventRect)
  2355. .on('mouseout', function () {
  2356. if (!$$.config) { return; } // chart is destroyed
  2357. if ($$.hasArcType()) { return; }
  2358. mouseout();
  2359. })
  2360. .on('mousemove', function () {
  2361. var targetsToShow = $$.filterTargetsToShow($$.data.targets);
  2362. var mouse, closest, sameXData, selectedData;
  2363. if ($$.dragging) { return; } // do nothing when dragging
  2364. if ($$.hasArcType(targetsToShow)) { return; }
  2365. mouse = d3.mouse(this);
  2366. closest = $$.findClosestFromTargets(targetsToShow, mouse);
  2367. if ($$.mouseover && (!closest || closest.id !== $$.mouseover.id)) {
  2368. config.data_onmouseout.call($$.api, $$.mouseover);
  2369. $$.mouseover = undefined;
  2370. }
  2371. if (! closest) {
  2372. mouseout();
  2373. return;
  2374. }
  2375. if ($$.isScatterType(closest) || !config.tooltip_grouped) {
  2376. sameXData = [closest];
  2377. } else {
  2378. sameXData = $$.filterByX(targetsToShow, closest.x);
  2379. }
  2380. // show tooltip when cursor is close to some point
  2381. selectedData = sameXData.map(function (d) {
  2382. return $$.addName(d);
  2383. });
  2384. $$.showTooltip(selectedData, this);
  2385. // expand points
  2386. if (config.point_focus_expand_enabled) {
  2387. $$.expandCircles(closest.index, closest.id, true);
  2388. }
  2389. $$.expandBars(closest.index, closest.id, true);
  2390. // Show xgrid focus line
  2391. $$.showXGridFocus(selectedData);
  2392. // Show cursor as pointer if point is close to mouse position
  2393. if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
  2394. $$.svg.select('.' + CLASS.eventRect).style('cursor', 'pointer');
  2395. if (!$$.mouseover) {
  2396. config.data_onmouseover.call($$.api, closest);
  2397. $$.mouseover = closest;
  2398. }
  2399. }
  2400. })
  2401. .on('click', function () {
  2402. var targetsToShow = $$.filterTargetsToShow($$.data.targets);
  2403. var mouse, closest;
  2404. if ($$.hasArcType(targetsToShow)) { return; }
  2405. mouse = d3.mouse(this);
  2406. closest = $$.findClosestFromTargets(targetsToShow, mouse);
  2407. if (! closest) { return; }
  2408. // select if selection enabled
  2409. if ($$.isBarType(closest.id) || $$.dist(closest, mouse) < config.point_sensitivity) {
  2410. $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(closest.id)).selectAll('.' + CLASS.shape + '-' + closest.index).each(function () {
  2411. if (config.data_selection_grouped || $$.isWithinShape(this, closest)) {
  2412. $$.toggleShape(this, closest, closest.index);
  2413. $$.config.data_onclick.call($$.api, closest, this);
  2414. }
  2415. });
  2416. }
  2417. })
  2418. .call(
  2419. config.data_selection_draggable && $$.drag ? (
  2420. d3.behavior.drag().origin(Object)
  2421. .on('drag', function () { $$.drag(d3.mouse(this)); })
  2422. .on('dragstart', function () { $$.dragstart(d3.mouse(this)); })
  2423. .on('dragend', function () { $$.dragend(); })
  2424. ) : function () {}
  2425. );
  2426. };
  2427. c3_chart_internal_fn.dispatchEvent = function (type, index, mouse) {
  2428. var $$ = this,
  2429. selector = '.' + CLASS.eventRect + (!$$.isMultipleX() ? '-' + index : ''),
  2430. eventRect = $$.main.select(selector).node(),
  2431. box = eventRect.getBoundingClientRect(),
  2432. x = box.left + (mouse ? mouse[0] : 0),
  2433. y = box.top + (mouse ? mouse[1] : 0),
  2434. event = document.createEvent("MouseEvents");
  2435. event.initMouseEvent(type, true, true, window, 0, x, y, x, y,
  2436. false, false, false, false, 0, null);
  2437. eventRect.dispatchEvent(event);
  2438. };
  2439. c3_chart_internal_fn.getCurrentWidth = function () {
  2440. var $$ = this, config = $$.config;
  2441. return config.size_width ? config.size_width : $$.getParentWidth();
  2442. };
  2443. c3_chart_internal_fn.getCurrentHeight = function () {
  2444. var $$ = this, config = $$.config,
  2445. h = config.size_height ? config.size_height : $$.getParentHeight();
  2446. return h > 0 ? h : 320 / ($$.hasType('gauge') ? 2 : 1);
  2447. };
  2448. c3_chart_internal_fn.getCurrentPaddingTop = function () {
  2449. var $$ = this,
  2450. config = $$.config,
  2451. padding = isValue(config.padding_top) ? config.padding_top : 0;
  2452. if ($$.title && $$.title.node()) {
  2453. padding += $$.getTitlePadding();
  2454. }
  2455. return padding;
  2456. };
  2457. c3_chart_internal_fn.getCurrentPaddingBottom = function () {
  2458. var config = this.config;
  2459. return isValue(config.padding_bottom) ? config.padding_bottom : 0;
  2460. };
  2461. c3_chart_internal_fn.getCurrentPaddingLeft = function (withoutRecompute) {
  2462. var $$ = this, config = $$.config;
  2463. if (isValue(config.padding_left)) {
  2464. return config.padding_left;
  2465. } else if (config.axis_rotated) {
  2466. return !config.axis_x_show ? 1 : Math.max(ceil10($$.getAxisWidthByAxisId('x', withoutRecompute)), 40);
  2467. } else if (!config.axis_y_show || config.axis_y_inner) { // && !config.axis_rotated
  2468. return $$.axis.getYAxisLabelPosition().isOuter ? 30 : 1;
  2469. } else {
  2470. return ceil10($$.getAxisWidthByAxisId('y', withoutRecompute));
  2471. }
  2472. };
  2473. c3_chart_internal_fn.getCurrentPaddingRight = function () {
  2474. var $$ = this, config = $$.config,
  2475. defaultPadding = 10, legendWidthOnRight = $$.isLegendRight ? $$.getLegendWidth() + 20 : 0;
  2476. if (isValue(config.padding_right)) {
  2477. return config.padding_right + 1; // 1 is needed not to hide tick line
  2478. } else if (config.axis_rotated) {
  2479. return defaultPadding + legendWidthOnRight;
  2480. } else if (!config.axis_y2_show || config.axis_y2_inner) { // && !config.axis_rotated
  2481. return 2 + legendWidthOnRight + ($$.axis.getY2AxisLabelPosition().isOuter ? 20 : 0);
  2482. } else {
  2483. return ceil10($$.getAxisWidthByAxisId('y2')) + legendWidthOnRight;
  2484. }
  2485. };
  2486. c3_chart_internal_fn.getParentRectValue = function (key) {
  2487. var parent = this.selectChart.node(), v;
  2488. while (parent && parent.tagName !== 'BODY') {
  2489. try {
  2490. v = parent.getBoundingClientRect()[key];
  2491. } catch(e) {
  2492. if (key === 'width') {
  2493. // In IE in certain cases getBoundingClientRect
  2494. // will cause an "unspecified error"
  2495. v = parent.offsetWidth;
  2496. }
  2497. }
  2498. if (v) {
  2499. break;
  2500. }
  2501. parent = parent.parentNode;
  2502. }
  2503. return v;
  2504. };
  2505. c3_chart_internal_fn.getParentWidth = function () {
  2506. return this.getParentRectValue('width');
  2507. };
  2508. c3_chart_internal_fn.getParentHeight = function () {
  2509. var h = this.selectChart.style('height');
  2510. return h.indexOf('px') > 0 ? +h.replace('px', '') : 0;
  2511. };
  2512. c3_chart_internal_fn.getSvgLeft = function (withoutRecompute) {
  2513. var $$ = this, config = $$.config,
  2514. hasLeftAxisRect = config.axis_rotated || (!config.axis_rotated && !config.axis_y_inner),
  2515. leftAxisClass = config.axis_rotated ? CLASS.axisX : CLASS.axisY,
  2516. leftAxis = $$.main.select('.' + leftAxisClass).node(),
  2517. svgRect = leftAxis && hasLeftAxisRect ? leftAxis.getBoundingClientRect() : {right: 0},
  2518. chartRect = $$.selectChart.node().getBoundingClientRect(),
  2519. hasArc = $$.hasArcType(),
  2520. svgLeft = svgRect.right - chartRect.left - (hasArc ? 0 : $$.getCurrentPaddingLeft(withoutRecompute));
  2521. return svgLeft > 0 ? svgLeft : 0;
  2522. };
  2523. c3_chart_internal_fn.getAxisWidthByAxisId = function (id, withoutRecompute) {
  2524. var $$ = this, position = $$.axis.getLabelPositionById(id);
  2525. return $$.axis.getMaxTickWidth(id, withoutRecompute) + (position.isInner ? 20 : 40);
  2526. };
  2527. c3_chart_internal_fn.getHorizontalAxisHeight = function (axisId) {
  2528. var $$ = this, config = $$.config, h = 30;
  2529. if (axisId === 'x' && !config.axis_x_show) { return 8; }
  2530. if (axisId === 'x' && config.axis_x_height) { return config.axis_x_height; }
  2531. if (axisId === 'y' && !config.axis_y_show) {
  2532. return config.legend_show && !$$.isLegendRight && !$$.isLegendInset ? 10 : 1;
  2533. }
  2534. if (axisId === 'y2' && !config.axis_y2_show) { return $$.rotated_padding_top; }
  2535. // Calculate x axis height when tick rotated
  2536. if (axisId === 'x' && !config.axis_rotated && config.axis_x_tick_rotate) {
  2537. h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_x_tick_rotate) / 180);
  2538. }
  2539. // Calculate y axis height when tick rotated
  2540. if (axisId === 'y' && config.axis_rotated && config.axis_y_tick_rotate) {
  2541. h = 30 + $$.axis.getMaxTickWidth(axisId) * Math.cos(Math.PI * (90 - config.axis_y_tick_rotate) / 180);
  2542. }
  2543. return h + ($$.axis.getLabelPositionById(axisId).isInner ? 0 : 10) + (axisId === 'y2' ? -10 : 0);
  2544. };
  2545. c3_chart_internal_fn.getEventRectWidth = function () {
  2546. return Math.max(0, this.xAxis.tickInterval());
  2547. };
  2548. c3_chart_internal_fn.getShapeIndices = function (typeFilter) {
  2549. var $$ = this, config = $$.config,
  2550. indices = {}, i = 0, j, k;
  2551. $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)).forEach(function (d) {
  2552. for (j = 0; j < config.data_groups.length; j++) {
  2553. if (config.data_groups[j].indexOf(d.id) < 0) { continue; }
  2554. for (k = 0; k < config.data_groups[j].length; k++) {
  2555. if (config.data_groups[j][k] in indices) {
  2556. indices[d.id] = indices[config.data_groups[j][k]];
  2557. break;
  2558. }
  2559. }
  2560. }
  2561. if (isUndefined(indices[d.id])) { indices[d.id] = i++; }
  2562. });
  2563. indices.__max__ = i - 1;
  2564. return indices;
  2565. };
  2566. c3_chart_internal_fn.getShapeX = function (offset, targetsNum, indices, isSub) {
  2567. var $$ = this, scale = isSub ? $$.subX : $$.x;
  2568. return function (d) {
  2569. var index = d.id in indices ? indices[d.id] : 0;
  2570. return d.x || d.x === 0 ? scale(d.x) - offset * (targetsNum / 2 - index) : 0;
  2571. };
  2572. };
  2573. c3_chart_internal_fn.getShapeY = function (isSub) {
  2574. var $$ = this;
  2575. return function (d) {
  2576. var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id);
  2577. return scale(d.value);
  2578. };
  2579. };
  2580. c3_chart_internal_fn.getShapeOffset = function (typeFilter, indices, isSub) {
  2581. var $$ = this,
  2582. targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))),
  2583. targetIds = targets.map(function (t) { return t.id; });
  2584. return function (d, i) {
  2585. var scale = isSub ? $$.getSubYScale(d.id) : $$.getYScale(d.id),
  2586. y0 = scale(0), offset = y0;
  2587. targets.forEach(function (t) {
  2588. var values = $$.isStepType(d) ? $$.convertValuesToStep(t.values) : t.values;
  2589. if (t.id === d.id || indices[t.id] !== indices[d.id]) { return; }
  2590. if (targetIds.indexOf(t.id) < targetIds.indexOf(d.id)) {
  2591. // check if the x values line up
  2592. if (typeof values[i] === 'undefined' || +values[i].x !== +d.x) { // "+" for timeseries
  2593. // if not, try to find the value that does line up
  2594. i = -1;
  2595. values.forEach(function (v, j) {
  2596. if (v.x === d.x) {
  2597. i = j;
  2598. }
  2599. });
  2600. }
  2601. if (i in values && values[i].value * d.value >= 0) {
  2602. offset += scale(values[i].value) - y0;
  2603. }
  2604. }
  2605. });
  2606. return offset;
  2607. };
  2608. };
  2609. c3_chart_internal_fn.isWithinShape = function (that, d) {
  2610. var $$ = this,
  2611. shape = $$.d3.select(that), isWithin;
  2612. if (!$$.isTargetToShow(d.id)) {
  2613. isWithin = false;
  2614. }
  2615. else if (that.nodeName === 'circle') {
  2616. isWithin = $$.isStepType(d) ? $$.isWithinStep(that, $$.getYScale(d.id)(d.value)) : $$.isWithinCircle(that, $$.pointSelectR(d) * 1.5);
  2617. }
  2618. else if (that.nodeName === 'path') {
  2619. isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true;
  2620. }
  2621. return isWithin;
  2622. };
  2623. c3_chart_internal_fn.getInterpolate = function (d) {
  2624. var $$ = this,
  2625. interpolation = $$.isInterpolationType($$.config.spline_interpolation_type) ? $$.config.spline_interpolation_type : 'cardinal';
  2626. return $$.isSplineType(d) ? interpolation : $$.isStepType(d) ? $$.config.line_step_type : "linear";
  2627. };
  2628. c3_chart_internal_fn.initLine = function () {
  2629. var $$ = this;
  2630. $$.main.select('.' + CLASS.chart).append("g")
  2631. .attr("class", CLASS.chartLines);
  2632. };
  2633. c3_chart_internal_fn.updateTargetsForLine = function (targets) {
  2634. var $$ = this, config = $$.config,
  2635. mainLineUpdate, mainLineEnter,
  2636. classChartLine = $$.classChartLine.bind($$),
  2637. classLines = $$.classLines.bind($$),
  2638. classAreas = $$.classAreas.bind($$),
  2639. classCircles = $$.classCircles.bind($$),
  2640. classFocus = $$.classFocus.bind($$);
  2641. mainLineUpdate = $$.main.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
  2642. .data(targets)
  2643. .attr('class', function (d) { return classChartLine(d) + classFocus(d); });
  2644. mainLineEnter = mainLineUpdate.enter().append('g')
  2645. .attr('class', classChartLine)
  2646. .style('opacity', 0)
  2647. .style("pointer-events", "none");
  2648. // Lines for each data
  2649. mainLineEnter.append('g')
  2650. .attr("class", classLines);
  2651. // Areas
  2652. mainLineEnter.append('g')
  2653. .attr('class', classAreas);
  2654. // Circles for each data point on lines
  2655. mainLineEnter.append('g')
  2656. .attr("class", function (d) { return $$.generateClass(CLASS.selectedCircles, d.id); });
  2657. mainLineEnter.append('g')
  2658. .attr("class", classCircles)
  2659. .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
  2660. // Update date for selected circles
  2661. targets.forEach(function (t) {
  2662. $$.main.selectAll('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(t.id)).selectAll('.' + CLASS.selectedCircle).each(function (d) {
  2663. d.value = t.values[d.index].value;
  2664. });
  2665. });
  2666. // MEMO: can not keep same color...
  2667. //mainLineUpdate.exit().remove();
  2668. };
  2669. c3_chart_internal_fn.updateLine = function (durationForExit) {
  2670. var $$ = this;
  2671. $$.mainLine = $$.main.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
  2672. .data($$.lineData.bind($$));
  2673. $$.mainLine.enter().append('path')
  2674. .attr('class', $$.classLine.bind($$))
  2675. .style("stroke", $$.color);
  2676. $$.mainLine
  2677. .style("opacity", $$.initialOpacity.bind($$))
  2678. .style('shape-rendering', function (d) { return $$.isStepType(d) ? 'crispEdges' : ''; })
  2679. .attr('transform', null);
  2680. $$.mainLine.exit().transition().duration(durationForExit)
  2681. .style('opacity', 0)
  2682. .remove();
  2683. };
  2684. c3_chart_internal_fn.redrawLine = function (drawLine, withTransition) {
  2685. return [
  2686. (withTransition ? this.mainLine.transition(Math.random().toString()) : this.mainLine)
  2687. .attr("d", drawLine)
  2688. .style("stroke", this.color)
  2689. .style("opacity", 1)
  2690. ];
  2691. };
  2692. c3_chart_internal_fn.generateDrawLine = function (lineIndices, isSub) {
  2693. var $$ = this, config = $$.config,
  2694. line = $$.d3.svg.line(),
  2695. getPoints = $$.generateGetLinePoints(lineIndices, isSub),
  2696. yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
  2697. xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
  2698. yValue = function (d, i) {
  2699. return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)(d.value);
  2700. };
  2701. line = config.axis_rotated ? line.x(yValue).y(xValue) : line.x(xValue).y(yValue);
  2702. if (!config.line_connectNull) { line = line.defined(function (d) { return d.value != null; }); }
  2703. return function (d) {
  2704. var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
  2705. x = isSub ? $$.x : $$.subX, y = yScaleGetter.call($$, d.id), x0 = 0, y0 = 0, path;
  2706. if ($$.isLineType(d)) {
  2707. if (config.data_regions[d.id]) {
  2708. path = $$.lineWithRegions(values, x, y, config.data_regions[d.id]);
  2709. } else {
  2710. if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
  2711. path = line.interpolate($$.getInterpolate(d))(values);
  2712. }
  2713. } else {
  2714. if (values[0]) {
  2715. x0 = x(values[0].x);
  2716. y0 = y(values[0].value);
  2717. }
  2718. path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
  2719. }
  2720. return path ? path : "M 0 0";
  2721. };
  2722. };
  2723. c3_chart_internal_fn.generateGetLinePoints = function (lineIndices, isSub) { // partial duplication of generateGetBarPoints
  2724. var $$ = this, config = $$.config,
  2725. lineTargetsNum = lineIndices.__max__ + 1,
  2726. x = $$.getShapeX(0, lineTargetsNum, lineIndices, !!isSub),
  2727. y = $$.getShapeY(!!isSub),
  2728. lineOffset = $$.getShapeOffset($$.isLineType, lineIndices, !!isSub),
  2729. yScale = isSub ? $$.getSubYScale : $$.getYScale;
  2730. return function (d, i) {
  2731. var y0 = yScale.call($$, d.id)(0),
  2732. offset = lineOffset(d, i) || y0, // offset is for stacked area chart
  2733. posX = x(d), posY = y(d);
  2734. // fix posY not to overflow opposite quadrant
  2735. if (config.axis_rotated) {
  2736. if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
  2737. }
  2738. // 1 point that marks the line position
  2739. return [
  2740. [posX, posY - (y0 - offset)],
  2741. [posX, posY - (y0 - offset)], // needed for compatibility
  2742. [posX, posY - (y0 - offset)], // needed for compatibility
  2743. [posX, posY - (y0 - offset)] // needed for compatibility
  2744. ];
  2745. };
  2746. };
  2747. c3_chart_internal_fn.lineWithRegions = function (d, x, y, _regions) {
  2748. var $$ = this, config = $$.config,
  2749. prev = -1, i, j,
  2750. s = "M", sWithRegion,
  2751. xp, yp, dx, dy, dd, diff, diffx2,
  2752. xOffset = $$.isCategorized() ? 0.5 : 0,
  2753. xValue, yValue,
  2754. regions = [];
  2755. function isWithinRegions(x, regions) {
  2756. var i;
  2757. for (i = 0; i < regions.length; i++) {
  2758. if (regions[i].start < x && x <= regions[i].end) { return true; }
  2759. }
  2760. return false;
  2761. }
  2762. // Check start/end of regions
  2763. if (isDefined(_regions)) {
  2764. for (i = 0; i < _regions.length; i++) {
  2765. regions[i] = {};
  2766. if (isUndefined(_regions[i].start)) {
  2767. regions[i].start = d[0].x;
  2768. } else {
  2769. regions[i].start = $$.isTimeSeries() ? $$.parseDate(_regions[i].start) : _regions[i].start;
  2770. }
  2771. if (isUndefined(_regions[i].end)) {
  2772. regions[i].end = d[d.length - 1].x;
  2773. } else {
  2774. regions[i].end = $$.isTimeSeries() ? $$.parseDate(_regions[i].end) : _regions[i].end;
  2775. }
  2776. }
  2777. }
  2778. // Set scales
  2779. xValue = config.axis_rotated ? function (d) { return y(d.value); } : function (d) { return x(d.x); };
  2780. yValue = config.axis_rotated ? function (d) { return x(d.x); } : function (d) { return y(d.value); };
  2781. // Define svg generator function for region
  2782. function generateM(points) {
  2783. return 'M' + points[0][0] + ' ' + points[0][1] + ' ' + points[1][0] + ' ' + points[1][1];
  2784. }
  2785. if ($$.isTimeSeries()) {
  2786. sWithRegion = function (d0, d1, j, diff) {
  2787. var x0 = d0.x.getTime(), x_diff = d1.x - d0.x,
  2788. xv0 = new Date(x0 + x_diff * j),
  2789. xv1 = new Date(x0 + x_diff * (j + diff)),
  2790. points;
  2791. if (config.axis_rotated) {
  2792. points = [[y(yp(j)), x(xv0)], [y(yp(j + diff)), x(xv1)]];
  2793. } else {
  2794. points = [[x(xv0), y(yp(j))], [x(xv1), y(yp(j + diff))]];
  2795. }
  2796. return generateM(points);
  2797. };
  2798. } else {
  2799. sWithRegion = function (d0, d1, j, diff) {
  2800. var points;
  2801. if (config.axis_rotated) {
  2802. points = [[y(yp(j), true), x(xp(j))], [y(yp(j + diff), true), x(xp(j + diff))]];
  2803. } else {
  2804. points = [[x(xp(j), true), y(yp(j))], [x(xp(j + diff), true), y(yp(j + diff))]];
  2805. }
  2806. return generateM(points);
  2807. };
  2808. }
  2809. // Generate
  2810. for (i = 0; i < d.length; i++) {
  2811. // Draw as normal
  2812. if (isUndefined(regions) || ! isWithinRegions(d[i].x, regions)) {
  2813. s += " " + xValue(d[i]) + " " + yValue(d[i]);
  2814. }
  2815. // Draw with region // TODO: Fix for horizotal charts
  2816. else {
  2817. xp = $$.getScale(d[i - 1].x + xOffset, d[i].x + xOffset, $$.isTimeSeries());
  2818. yp = $$.getScale(d[i - 1].value, d[i].value);
  2819. dx = x(d[i].x) - x(d[i - 1].x);
  2820. dy = y(d[i].value) - y(d[i - 1].value);
  2821. dd = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
  2822. diff = 2 / dd;
  2823. diffx2 = diff * 2;
  2824. for (j = diff; j <= 1; j += diffx2) {
  2825. s += sWithRegion(d[i - 1], d[i], j, diff);
  2826. }
  2827. }
  2828. prev = d[i].x;
  2829. }
  2830. return s;
  2831. };
  2832. c3_chart_internal_fn.updateArea = function (durationForExit) {
  2833. var $$ = this, d3 = $$.d3;
  2834. $$.mainArea = $$.main.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
  2835. .data($$.lineData.bind($$));
  2836. $$.mainArea.enter().append('path')
  2837. .attr("class", $$.classArea.bind($$))
  2838. .style("fill", $$.color)
  2839. .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
  2840. $$.mainArea
  2841. .style("opacity", $$.orgAreaOpacity);
  2842. $$.mainArea.exit().transition().duration(durationForExit)
  2843. .style('opacity', 0)
  2844. .remove();
  2845. };
  2846. c3_chart_internal_fn.redrawArea = function (drawArea, withTransition) {
  2847. return [
  2848. (withTransition ? this.mainArea.transition(Math.random().toString()) : this.mainArea)
  2849. .attr("d", drawArea)
  2850. .style("fill", this.color)
  2851. .style("opacity", this.orgAreaOpacity)
  2852. ];
  2853. };
  2854. c3_chart_internal_fn.generateDrawArea = function (areaIndices, isSub) {
  2855. var $$ = this, config = $$.config, area = $$.d3.svg.area(),
  2856. getPoints = $$.generateGetAreaPoints(areaIndices, isSub),
  2857. yScaleGetter = isSub ? $$.getSubYScale : $$.getYScale,
  2858. xValue = function (d) { return (isSub ? $$.subxx : $$.xx).call($$, d); },
  2859. value0 = function (d, i) {
  2860. return config.data_groups.length > 0 ? getPoints(d, i)[0][1] : yScaleGetter.call($$, d.id)($$.getAreaBaseValue(d.id));
  2861. },
  2862. value1 = function (d, i) {
  2863. return config.data_groups.length > 0 ? getPoints(d, i)[1][1] : yScaleGetter.call($$, d.id)(d.value);
  2864. };
  2865. area = config.axis_rotated ? area.x0(value0).x1(value1).y(xValue) : area.x(xValue).y0(value0).y1(value1);
  2866. if (!config.line_connectNull) {
  2867. area = area.defined(function (d) { return d.value !== null; });
  2868. }
  2869. return function (d) {
  2870. var values = config.line_connectNull ? $$.filterRemoveNull(d.values) : d.values,
  2871. x0 = 0, y0 = 0, path;
  2872. if ($$.isAreaType(d)) {
  2873. if ($$.isStepType(d)) { values = $$.convertValuesToStep(values); }
  2874. path = area.interpolate($$.getInterpolate(d))(values);
  2875. } else {
  2876. if (values[0]) {
  2877. x0 = $$.x(values[0].x);
  2878. y0 = $$.getYScale(d.id)(values[0].value);
  2879. }
  2880. path = config.axis_rotated ? "M " + y0 + " " + x0 : "M " + x0 + " " + y0;
  2881. }
  2882. return path ? path : "M 0 0";
  2883. };
  2884. };
  2885. c3_chart_internal_fn.getAreaBaseValue = function () {
  2886. return 0;
  2887. };
  2888. c3_chart_internal_fn.generateGetAreaPoints = function (areaIndices, isSub) { // partial duplication of generateGetBarPoints
  2889. var $$ = this, config = $$.config,
  2890. areaTargetsNum = areaIndices.__max__ + 1,
  2891. x = $$.getShapeX(0, areaTargetsNum, areaIndices, !!isSub),
  2892. y = $$.getShapeY(!!isSub),
  2893. areaOffset = $$.getShapeOffset($$.isAreaType, areaIndices, !!isSub),
  2894. yScale = isSub ? $$.getSubYScale : $$.getYScale;
  2895. return function (d, i) {
  2896. var y0 = yScale.call($$, d.id)(0),
  2897. offset = areaOffset(d, i) || y0, // offset is for stacked area chart
  2898. posX = x(d), posY = y(d);
  2899. // fix posY not to overflow opposite quadrant
  2900. if (config.axis_rotated) {
  2901. if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
  2902. }
  2903. // 1 point that marks the area position
  2904. return [
  2905. [posX, offset],
  2906. [posX, posY - (y0 - offset)],
  2907. [posX, posY - (y0 - offset)], // needed for compatibility
  2908. [posX, offset] // needed for compatibility
  2909. ];
  2910. };
  2911. };
  2912. c3_chart_internal_fn.updateCircle = function () {
  2913. var $$ = this;
  2914. $$.mainCircle = $$.main.selectAll('.' + CLASS.circles).selectAll('.' + CLASS.circle)
  2915. .data($$.lineOrScatterData.bind($$));
  2916. $$.mainCircle.enter().append("circle")
  2917. .attr("class", $$.classCircle.bind($$))
  2918. .attr("r", $$.pointR.bind($$))
  2919. .style("fill", $$.color);
  2920. $$.mainCircle
  2921. .style("opacity", $$.initialOpacityForCircle.bind($$));
  2922. $$.mainCircle.exit().remove();
  2923. };
  2924. c3_chart_internal_fn.redrawCircle = function (cx, cy, withTransition) {
  2925. var selectedCircles = this.main.selectAll('.' + CLASS.selectedCircle);
  2926. return [
  2927. (withTransition ? this.mainCircle.transition(Math.random().toString()) : this.mainCircle)
  2928. .style('opacity', this.opacityForCircle.bind(this))
  2929. .style("fill", this.color)
  2930. .attr("cx", cx)
  2931. .attr("cy", cy),
  2932. (withTransition ? selectedCircles.transition(Math.random().toString()) : selectedCircles)
  2933. .attr("cx", cx)
  2934. .attr("cy", cy)
  2935. ];
  2936. };
  2937. c3_chart_internal_fn.circleX = function (d) {
  2938. return d.x || d.x === 0 ? this.x(d.x) : null;
  2939. };
  2940. c3_chart_internal_fn.updateCircleY = function () {
  2941. var $$ = this, lineIndices, getPoints;
  2942. if ($$.config.data_groups.length > 0) {
  2943. lineIndices = $$.getShapeIndices($$.isLineType),
  2944. getPoints = $$.generateGetLinePoints(lineIndices);
  2945. $$.circleY = function (d, i) {
  2946. return getPoints(d, i)[0][1];
  2947. };
  2948. } else {
  2949. $$.circleY = function (d) {
  2950. return $$.getYScale(d.id)(d.value);
  2951. };
  2952. }
  2953. };
  2954. c3_chart_internal_fn.getCircles = function (i, id) {
  2955. var $$ = this;
  2956. return (id ? $$.main.selectAll('.' + CLASS.circles + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.circle + (isValue(i) ? '-' + i : ''));
  2957. };
  2958. c3_chart_internal_fn.expandCircles = function (i, id, reset) {
  2959. var $$ = this,
  2960. r = $$.pointExpandedR.bind($$);
  2961. if (reset) { $$.unexpandCircles(); }
  2962. $$.getCircles(i, id)
  2963. .classed(CLASS.EXPANDED, true)
  2964. .attr('r', r);
  2965. };
  2966. c3_chart_internal_fn.unexpandCircles = function (i) {
  2967. var $$ = this,
  2968. r = $$.pointR.bind($$);
  2969. $$.getCircles(i)
  2970. .filter(function () { return $$.d3.select(this).classed(CLASS.EXPANDED); })
  2971. .classed(CLASS.EXPANDED, false)
  2972. .attr('r', r);
  2973. };
  2974. c3_chart_internal_fn.pointR = function (d) {
  2975. var $$ = this, config = $$.config;
  2976. return $$.isStepType(d) ? 0 : (isFunction(config.point_r) ? config.point_r(d) : config.point_r);
  2977. };
  2978. c3_chart_internal_fn.pointExpandedR = function (d) {
  2979. var $$ = this, config = $$.config;
  2980. return config.point_focus_expand_enabled ? (config.point_focus_expand_r ? config.point_focus_expand_r : $$.pointR(d) * 1.75) : $$.pointR(d);
  2981. };
  2982. c3_chart_internal_fn.pointSelectR = function (d) {
  2983. var $$ = this, config = $$.config;
  2984. return config.point_select_r ? config.point_select_r : $$.pointR(d) * 4;
  2985. };
  2986. c3_chart_internal_fn.isWithinCircle = function (that, r) {
  2987. var d3 = this.d3,
  2988. mouse = d3.mouse(that), d3_this = d3.select(that),
  2989. cx = +d3_this.attr("cx"), cy = +d3_this.attr("cy");
  2990. return Math.sqrt(Math.pow(cx - mouse[0], 2) + Math.pow(cy - mouse[1], 2)) < r;
  2991. };
  2992. c3_chart_internal_fn.isWithinStep = function (that, y) {
  2993. return Math.abs(y - this.d3.mouse(that)[1]) < 30;
  2994. };
  2995. c3_chart_internal_fn.initBar = function () {
  2996. var $$ = this;
  2997. $$.main.select('.' + CLASS.chart).append("g")
  2998. .attr("class", CLASS.chartBars);
  2999. };
  3000. c3_chart_internal_fn.updateTargetsForBar = function (targets) {
  3001. var $$ = this, config = $$.config,
  3002. mainBarUpdate, mainBarEnter,
  3003. classChartBar = $$.classChartBar.bind($$),
  3004. classBars = $$.classBars.bind($$),
  3005. classFocus = $$.classFocus.bind($$);
  3006. mainBarUpdate = $$.main.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
  3007. .data(targets)
  3008. .attr('class', function (d) { return classChartBar(d) + classFocus(d); });
  3009. mainBarEnter = mainBarUpdate.enter().append('g')
  3010. .attr('class', classChartBar)
  3011. .style('opacity', 0)
  3012. .style("pointer-events", "none");
  3013. // Bars for each data
  3014. mainBarEnter.append('g')
  3015. .attr("class", classBars)
  3016. .style("cursor", function (d) { return config.data_selection_isselectable(d) ? "pointer" : null; });
  3017. };
  3018. c3_chart_internal_fn.updateBar = function (durationForExit) {
  3019. var $$ = this,
  3020. barData = $$.barData.bind($$),
  3021. classBar = $$.classBar.bind($$),
  3022. initialOpacity = $$.initialOpacity.bind($$),
  3023. color = function (d) { return $$.color(d.id); };
  3024. $$.mainBar = $$.main.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
  3025. .data(barData);
  3026. $$.mainBar.enter().append('path')
  3027. .attr("class", classBar)
  3028. .style("stroke", color)
  3029. .style("fill", color);
  3030. $$.mainBar
  3031. .style("opacity", initialOpacity);
  3032. $$.mainBar.exit().transition().duration(durationForExit)
  3033. .style('opacity', 0)
  3034. .remove();
  3035. };
  3036. c3_chart_internal_fn.redrawBar = function (drawBar, withTransition) {
  3037. return [
  3038. (withTransition ? this.mainBar.transition(Math.random().toString()) : this.mainBar)
  3039. .attr('d', drawBar)
  3040. .style("fill", this.color)
  3041. .style("opacity", 1)
  3042. ];
  3043. };
  3044. c3_chart_internal_fn.getBarW = function (axis, barTargetsNum) {
  3045. var $$ = this, config = $$.config,
  3046. w = typeof config.bar_width === 'number' ? config.bar_width : barTargetsNum ? (axis.tickInterval() * config.bar_width_ratio) / barTargetsNum : 0;
  3047. return config.bar_width_max && w > config.bar_width_max ? config.bar_width_max : w;
  3048. };
  3049. c3_chart_internal_fn.getBars = function (i, id) {
  3050. var $$ = this;
  3051. return (id ? $$.main.selectAll('.' + CLASS.bars + $$.getTargetSelectorSuffix(id)) : $$.main).selectAll('.' + CLASS.bar + (isValue(i) ? '-' + i : ''));
  3052. };
  3053. c3_chart_internal_fn.expandBars = function (i, id, reset) {
  3054. var $$ = this;
  3055. if (reset) { $$.unexpandBars(); }
  3056. $$.getBars(i, id).classed(CLASS.EXPANDED, true);
  3057. };
  3058. c3_chart_internal_fn.unexpandBars = function (i) {
  3059. var $$ = this;
  3060. $$.getBars(i).classed(CLASS.EXPANDED, false);
  3061. };
  3062. c3_chart_internal_fn.generateDrawBar = function (barIndices, isSub) {
  3063. var $$ = this, config = $$.config,
  3064. getPoints = $$.generateGetBarPoints(barIndices, isSub);
  3065. return function (d, i) {
  3066. // 4 points that make a bar
  3067. var points = getPoints(d, i);
  3068. // switch points if axis is rotated, not applicable for sub chart
  3069. var indexX = config.axis_rotated ? 1 : 0;
  3070. var indexY = config.axis_rotated ? 0 : 1;
  3071. var path = 'M ' + points[0][indexX] + ',' + points[0][indexY] + ' ' +
  3072. 'L' + points[1][indexX] + ',' + points[1][indexY] + ' ' +
  3073. 'L' + points[2][indexX] + ',' + points[2][indexY] + ' ' +
  3074. 'L' + points[3][indexX] + ',' + points[3][indexY] + ' ' +
  3075. 'z';
  3076. return path;
  3077. };
  3078. };
  3079. c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) {
  3080. var $$ = this,
  3081. axis = isSub ? $$.subXAxis : $$.xAxis,
  3082. barTargetsNum = barIndices.__max__ + 1,
  3083. barW = $$.getBarW(axis, barTargetsNum),
  3084. barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub),
  3085. barY = $$.getShapeY(!!isSub),
  3086. barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub),
  3087. yScale = isSub ? $$.getSubYScale : $$.getYScale;
  3088. return function (d, i) {
  3089. var y0 = yScale.call($$, d.id)(0),
  3090. offset = barOffset(d, i) || y0, // offset is for stacked bar chart
  3091. posX = barX(d), posY = barY(d);
  3092. // fix posY not to overflow opposite quadrant
  3093. if ($$.config.axis_rotated) {
  3094. if ((0 < d.value && posY < y0) || (d.value < 0 && y0 < posY)) { posY = y0; }
  3095. }
  3096. // 4 points that make a bar
  3097. return [
  3098. [posX, offset],
  3099. [posX, posY - (y0 - offset)],
  3100. [posX + barW, posY - (y0 - offset)],
  3101. [posX + barW, offset]
  3102. ];
  3103. };
  3104. };
  3105. c3_chart_internal_fn.isWithinBar = function (that) {
  3106. var mouse = this.d3.mouse(that), box = that.getBoundingClientRect(),
  3107. seg0 = that.pathSegList.getItem(0), seg1 = that.pathSegList.getItem(1),
  3108. x = Math.min(seg0.x, seg1.x), y = Math.min(seg0.y, seg1.y),
  3109. w = box.width, h = box.height, offset = 2,
  3110. sx = x - offset, ex = x + w + offset, sy = y + h + offset, ey = y - offset;
  3111. return sx < mouse[0] && mouse[0] < ex && ey < mouse[1] && mouse[1] < sy;
  3112. };
  3113. c3_chart_internal_fn.initText = function () {
  3114. var $$ = this;
  3115. $$.main.select('.' + CLASS.chart).append("g")
  3116. .attr("class", CLASS.chartTexts);
  3117. $$.mainText = $$.d3.selectAll([]);
  3118. };
  3119. c3_chart_internal_fn.updateTargetsForText = function (targets) {
  3120. var $$ = this, mainTextUpdate, mainTextEnter,
  3121. classChartText = $$.classChartText.bind($$),
  3122. classTexts = $$.classTexts.bind($$),
  3123. classFocus = $$.classFocus.bind($$);
  3124. mainTextUpdate = $$.main.select('.' + CLASS.chartTexts).selectAll('.' + CLASS.chartText)
  3125. .data(targets)
  3126. .attr('class', function (d) { return classChartText(d) + classFocus(d); });
  3127. mainTextEnter = mainTextUpdate.enter().append('g')
  3128. .attr('class', classChartText)
  3129. .style('opacity', 0)
  3130. .style("pointer-events", "none");
  3131. mainTextEnter.append('g')
  3132. .attr('class', classTexts);
  3133. };
  3134. c3_chart_internal_fn.updateText = function (durationForExit) {
  3135. var $$ = this, config = $$.config,
  3136. barOrLineData = $$.barOrLineData.bind($$),
  3137. classText = $$.classText.bind($$);
  3138. $$.mainText = $$.main.selectAll('.' + CLASS.texts).selectAll('.' + CLASS.text)
  3139. .data(barOrLineData);
  3140. $$.mainText.enter().append('text')
  3141. .attr("class", classText)
  3142. .attr('text-anchor', function (d) { return config.axis_rotated ? (d.value < 0 ? 'end' : 'start') : 'middle'; })
  3143. .style("stroke", 'none')
  3144. .style("fill", function (d) { return $$.color(d); })
  3145. .style("fill-opacity", 0);
  3146. $$.mainText
  3147. .text(function (d, i, j) { return $$.dataLabelFormat(d.id)(d.value, d.id, i, j); });
  3148. $$.mainText.exit()
  3149. .transition().duration(durationForExit)
  3150. .style('fill-opacity', 0)
  3151. .remove();
  3152. };
  3153. c3_chart_internal_fn.redrawText = function (xForText, yForText, forFlow, withTransition) {
  3154. return [
  3155. (withTransition ? this.mainText.transition() : this.mainText)
  3156. .attr('x', xForText)
  3157. .attr('y', yForText)
  3158. .style("fill", this.color)
  3159. .style("fill-opacity", forFlow ? 0 : this.opacityForText.bind(this))
  3160. ];
  3161. };
  3162. c3_chart_internal_fn.getTextRect = function (text, cls, element) {
  3163. var dummy = this.d3.select('body').append('div').classed('c3', true),
  3164. svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
  3165. font = this.d3.select(element).style('font'),
  3166. rect;
  3167. svg.selectAll('.dummy')
  3168. .data([text])
  3169. .enter().append('text')
  3170. .classed(cls ? cls : "", true)
  3171. .style('font', font)
  3172. .text(text)
  3173. .each(function () { rect = this.getBoundingClientRect(); });
  3174. dummy.remove();
  3175. return rect;
  3176. };
  3177. c3_chart_internal_fn.generateXYForText = function (areaIndices, barIndices, lineIndices, forX) {
  3178. var $$ = this,
  3179. getAreaPoints = $$.generateGetAreaPoints(areaIndices, false),
  3180. getBarPoints = $$.generateGetBarPoints(barIndices, false),
  3181. getLinePoints = $$.generateGetLinePoints(lineIndices, false),
  3182. getter = forX ? $$.getXForText : $$.getYForText;
  3183. return function (d, i) {
  3184. var getPoints = $$.isAreaType(d) ? getAreaPoints : $$.isBarType(d) ? getBarPoints : getLinePoints;
  3185. return getter.call($$, getPoints(d, i), d, this);
  3186. };
  3187. };
  3188. c3_chart_internal_fn.getXForText = function (points, d, textElement) {
  3189. var $$ = this,
  3190. box = textElement.getBoundingClientRect(), xPos, padding;
  3191. if ($$.config.axis_rotated) {
  3192. padding = $$.isBarType(d) ? 4 : 6;
  3193. xPos = points[2][1] + padding * (d.value < 0 ? -1 : 1);
  3194. } else {
  3195. xPos = $$.hasType('bar') ? (points[2][0] + points[0][0]) / 2 : points[0][0];
  3196. }
  3197. // show labels regardless of the domain if value is null
  3198. if (d.value === null) {
  3199. if (xPos > $$.width) {
  3200. xPos = $$.width - box.width;
  3201. } else if (xPos < 0) {
  3202. xPos = 4;
  3203. }
  3204. }
  3205. return xPos;
  3206. };
  3207. c3_chart_internal_fn.getYForText = function (points, d, textElement) {
  3208. var $$ = this,
  3209. box = textElement.getBoundingClientRect(),
  3210. yPos;
  3211. if ($$.config.axis_rotated) {
  3212. yPos = (points[0][0] + points[2][0] + box.height * 0.6) / 2;
  3213. } else {
  3214. yPos = points[2][1];
  3215. if (d.value < 0 || (d.value === 0 && !$$.hasPositiveValue)) {
  3216. yPos += box.height;
  3217. if ($$.isBarType(d) && $$.isSafari()) {
  3218. yPos -= 3;
  3219. }
  3220. else if (!$$.isBarType(d) && $$.isChrome()) {
  3221. yPos += 3;
  3222. }
  3223. } else {
  3224. yPos += $$.isBarType(d) ? -3 : -6;
  3225. }
  3226. }
  3227. // show labels regardless of the domain if value is null
  3228. if (d.value === null && !$$.config.axis_rotated) {
  3229. if (yPos < box.height) {
  3230. yPos = box.height;
  3231. } else if (yPos > this.height) {
  3232. yPos = this.height - 4;
  3233. }
  3234. }
  3235. return yPos;
  3236. };
  3237. c3_chart_internal_fn.setTargetType = function (targetIds, type) {
  3238. var $$ = this, config = $$.config;
  3239. $$.mapToTargetIds(targetIds).forEach(function (id) {
  3240. $$.withoutFadeIn[id] = (type === config.data_types[id]);
  3241. config.data_types[id] = type;
  3242. });
  3243. if (!targetIds) {
  3244. config.data_type = type;
  3245. }
  3246. };
  3247. c3_chart_internal_fn.hasType = function (type, targets) {
  3248. var $$ = this, types = $$.config.data_types, has = false;
  3249. targets = targets || $$.data.targets;
  3250. if (targets && targets.length) {
  3251. targets.forEach(function (target) {
  3252. var t = types[target.id];
  3253. if ((t && t.indexOf(type) >= 0) || (!t && type === 'line')) {
  3254. has = true;
  3255. }
  3256. });
  3257. } else if (Object.keys(types).length) {
  3258. Object.keys(types).forEach(function (id) {
  3259. if (types[id] === type) { has = true; }
  3260. });
  3261. } else {
  3262. has = $$.config.data_type === type;
  3263. }
  3264. return has;
  3265. };
  3266. c3_chart_internal_fn.hasArcType = function (targets) {
  3267. return this.hasType('pie', targets) || this.hasType('donut', targets) || this.hasType('gauge', targets);
  3268. };
  3269. c3_chart_internal_fn.isLineType = function (d) {
  3270. var config = this.config, id = isString(d) ? d : d.id;
  3271. return !config.data_types[id] || ['line', 'spline', 'area', 'area-spline', 'step', 'area-step'].indexOf(config.data_types[id]) >= 0;
  3272. };
  3273. c3_chart_internal_fn.isStepType = function (d) {
  3274. var id = isString(d) ? d : d.id;
  3275. return ['step', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
  3276. };
  3277. c3_chart_internal_fn.isSplineType = function (d) {
  3278. var id = isString(d) ? d : d.id;
  3279. return ['spline', 'area-spline'].indexOf(this.config.data_types[id]) >= 0;
  3280. };
  3281. c3_chart_internal_fn.isAreaType = function (d) {
  3282. var id = isString(d) ? d : d.id;
  3283. return ['area', 'area-spline', 'area-step'].indexOf(this.config.data_types[id]) >= 0;
  3284. };
  3285. c3_chart_internal_fn.isBarType = function (d) {
  3286. var id = isString(d) ? d : d.id;
  3287. return this.config.data_types[id] === 'bar';
  3288. };
  3289. c3_chart_internal_fn.isScatterType = function (d) {
  3290. var id = isString(d) ? d : d.id;
  3291. return this.config.data_types[id] === 'scatter';
  3292. };
  3293. c3_chart_internal_fn.isPieType = function (d) {
  3294. var id = isString(d) ? d : d.id;
  3295. return this.config.data_types[id] === 'pie';
  3296. };
  3297. c3_chart_internal_fn.isGaugeType = function (d) {
  3298. var id = isString(d) ? d : d.id;
  3299. return this.config.data_types[id] === 'gauge';
  3300. };
  3301. c3_chart_internal_fn.isDonutType = function (d) {
  3302. var id = isString(d) ? d : d.id;
  3303. return this.config.data_types[id] === 'donut';
  3304. };
  3305. c3_chart_internal_fn.isArcType = function (d) {
  3306. return this.isPieType(d) || this.isDonutType(d) || this.isGaugeType(d);
  3307. };
  3308. c3_chart_internal_fn.lineData = function (d) {
  3309. return this.isLineType(d) ? [d] : [];
  3310. };
  3311. c3_chart_internal_fn.arcData = function (d) {
  3312. return this.isArcType(d.data) ? [d] : [];
  3313. };
  3314. /* not used
  3315. function scatterData(d) {
  3316. return isScatterType(d) ? d.values : [];
  3317. }
  3318. */
  3319. c3_chart_internal_fn.barData = function (d) {
  3320. return this.isBarType(d) ? d.values : [];
  3321. };
  3322. c3_chart_internal_fn.lineOrScatterData = function (d) {
  3323. return this.isLineType(d) || this.isScatterType(d) ? d.values : [];
  3324. };
  3325. c3_chart_internal_fn.barOrLineData = function (d) {
  3326. return this.isBarType(d) || this.isLineType(d) ? d.values : [];
  3327. };
  3328. c3_chart_internal_fn.isInterpolationType = function (type) {
  3329. return ['linear', 'linear-closed', 'basis', 'basis-open', 'basis-closed', 'bundle', 'cardinal', 'cardinal-open', 'cardinal-closed', 'monotone'].indexOf(type) >= 0;
  3330. };
  3331. c3_chart_internal_fn.initGrid = function () {
  3332. var $$ = this, config = $$.config, d3 = $$.d3;
  3333. $$.grid = $$.main.append('g')
  3334. .attr("clip-path", $$.clipPathForGrid)
  3335. .attr('class', CLASS.grid);
  3336. if (config.grid_x_show) {
  3337. $$.grid.append("g").attr("class", CLASS.xgrids);
  3338. }
  3339. if (config.grid_y_show) {
  3340. $$.grid.append('g').attr('class', CLASS.ygrids);
  3341. }
  3342. if (config.grid_focus_show) {
  3343. $$.grid.append('g')
  3344. .attr("class", CLASS.xgridFocus)
  3345. .append('line')
  3346. .attr('class', CLASS.xgridFocus);
  3347. }
  3348. $$.xgrid = d3.selectAll([]);
  3349. if (!config.grid_lines_front) { $$.initGridLines(); }
  3350. };
  3351. c3_chart_internal_fn.initGridLines = function () {
  3352. var $$ = this, d3 = $$.d3;
  3353. $$.gridLines = $$.main.append('g')
  3354. .attr("clip-path", $$.clipPathForGrid)
  3355. .attr('class', CLASS.grid + ' ' + CLASS.gridLines);
  3356. $$.gridLines.append('g').attr("class", CLASS.xgridLines);
  3357. $$.gridLines.append('g').attr('class', CLASS.ygridLines);
  3358. $$.xgridLines = d3.selectAll([]);
  3359. };
  3360. c3_chart_internal_fn.updateXGrid = function (withoutUpdate) {
  3361. var $$ = this, config = $$.config, d3 = $$.d3,
  3362. xgridData = $$.generateGridData(config.grid_x_type, $$.x),
  3363. tickOffset = $$.isCategorized() ? $$.xAxis.tickOffset() : 0;
  3364. $$.xgridAttr = config.axis_rotated ? {
  3365. 'x1': 0,
  3366. 'x2': $$.width,
  3367. 'y1': function (d) { return $$.x(d) - tickOffset; },
  3368. 'y2': function (d) { return $$.x(d) - tickOffset; }
  3369. } : {
  3370. 'x1': function (d) { return $$.x(d) + tickOffset; },
  3371. 'x2': function (d) { return $$.x(d) + tickOffset; },
  3372. 'y1': 0,
  3373. 'y2': $$.height
  3374. };
  3375. $$.xgrid = $$.main.select('.' + CLASS.xgrids).selectAll('.' + CLASS.xgrid)
  3376. .data(xgridData);
  3377. $$.xgrid.enter().append('line').attr("class", CLASS.xgrid);
  3378. if (!withoutUpdate) {
  3379. $$.xgrid.attr($$.xgridAttr)
  3380. .style("opacity", function () { return +d3.select(this).attr(config.axis_rotated ? 'y1' : 'x1') === (config.axis_rotated ? $$.height : 0) ? 0 : 1; });
  3381. }
  3382. $$.xgrid.exit().remove();
  3383. };
  3384. c3_chart_internal_fn.updateYGrid = function () {
  3385. var $$ = this, config = $$.config,
  3386. gridValues = $$.yAxis.tickValues() || $$.y.ticks(config.grid_y_ticks);
  3387. $$.ygrid = $$.main.select('.' + CLASS.ygrids).selectAll('.' + CLASS.ygrid)
  3388. .data(gridValues);
  3389. $$.ygrid.enter().append('line')
  3390. .attr('class', CLASS.ygrid);
  3391. $$.ygrid.attr("x1", config.axis_rotated ? $$.y : 0)
  3392. .attr("x2", config.axis_rotated ? $$.y : $$.width)
  3393. .attr("y1", config.axis_rotated ? 0 : $$.y)
  3394. .attr("y2", config.axis_rotated ? $$.height : $$.y);
  3395. $$.ygrid.exit().remove();
  3396. $$.smoothLines($$.ygrid, 'grid');
  3397. };
  3398. c3_chart_internal_fn.gridTextAnchor = function (d) {
  3399. return d.position ? d.position : "end";
  3400. };
  3401. c3_chart_internal_fn.gridTextDx = function (d) {
  3402. return d.position === 'start' ? 4 : d.position === 'middle' ? 0 : -4;
  3403. };
  3404. c3_chart_internal_fn.xGridTextX = function (d) {
  3405. return d.position === 'start' ? -this.height : d.position === 'middle' ? -this.height / 2 : 0;
  3406. };
  3407. c3_chart_internal_fn.yGridTextX = function (d) {
  3408. return d.position === 'start' ? 0 : d.position === 'middle' ? this.width / 2 : this.width;
  3409. };
  3410. c3_chart_internal_fn.updateGrid = function (duration) {
  3411. var $$ = this, main = $$.main, config = $$.config,
  3412. xgridLine, ygridLine, yv;
  3413. // hide if arc type
  3414. $$.grid.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
  3415. main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
  3416. if (config.grid_x_show) {
  3417. $$.updateXGrid();
  3418. }
  3419. $$.xgridLines = main.select('.' + CLASS.xgridLines).selectAll('.' + CLASS.xgridLine)
  3420. .data(config.grid_x_lines);
  3421. // enter
  3422. xgridLine = $$.xgridLines.enter().append('g')
  3423. .attr("class", function (d) { return CLASS.xgridLine + (d['class'] ? ' ' + d['class'] : ''); });
  3424. xgridLine.append('line')
  3425. .style("opacity", 0);
  3426. xgridLine.append('text')
  3427. .attr("text-anchor", $$.gridTextAnchor)
  3428. .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
  3429. .attr('dx', $$.gridTextDx)
  3430. .attr('dy', -5)
  3431. .style("opacity", 0);
  3432. // udpate
  3433. // done in d3.transition() of the end of this function
  3434. // exit
  3435. $$.xgridLines.exit().transition().duration(duration)
  3436. .style("opacity", 0)
  3437. .remove();
  3438. // Y-Grid
  3439. if (config.grid_y_show) {
  3440. $$.updateYGrid();
  3441. }
  3442. $$.ygridLines = main.select('.' + CLASS.ygridLines).selectAll('.' + CLASS.ygridLine)
  3443. .data(config.grid_y_lines);
  3444. // enter
  3445. ygridLine = $$.ygridLines.enter().append('g')
  3446. .attr("class", function (d) { return CLASS.ygridLine + (d['class'] ? ' ' + d['class'] : ''); });
  3447. ygridLine.append('line')
  3448. .style("opacity", 0);
  3449. ygridLine.append('text')
  3450. .attr("text-anchor", $$.gridTextAnchor)
  3451. .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
  3452. .attr('dx', $$.gridTextDx)
  3453. .attr('dy', -5)
  3454. .style("opacity", 0);
  3455. // update
  3456. yv = $$.yv.bind($$);
  3457. $$.ygridLines.select('line')
  3458. .transition().duration(duration)
  3459. .attr("x1", config.axis_rotated ? yv : 0)
  3460. .attr("x2", config.axis_rotated ? yv : $$.width)
  3461. .attr("y1", config.axis_rotated ? 0 : yv)
  3462. .attr("y2", config.axis_rotated ? $$.height : yv)
  3463. .style("opacity", 1);
  3464. $$.ygridLines.select('text')
  3465. .transition().duration(duration)
  3466. .attr("x", config.axis_rotated ? $$.xGridTextX.bind($$) : $$.yGridTextX.bind($$))
  3467. .attr("y", yv)
  3468. .text(function (d) { return d.text; })
  3469. .style("opacity", 1);
  3470. // exit
  3471. $$.ygridLines.exit().transition().duration(duration)
  3472. .style("opacity", 0)
  3473. .remove();
  3474. };
  3475. c3_chart_internal_fn.redrawGrid = function (withTransition) {
  3476. var $$ = this, config = $$.config, xv = $$.xv.bind($$),
  3477. lines = $$.xgridLines.select('line'),
  3478. texts = $$.xgridLines.select('text');
  3479. return [
  3480. (withTransition ? lines.transition() : lines)
  3481. .attr("x1", config.axis_rotated ? 0 : xv)
  3482. .attr("x2", config.axis_rotated ? $$.width : xv)
  3483. .attr("y1", config.axis_rotated ? xv : 0)
  3484. .attr("y2", config.axis_rotated ? xv : $$.height)
  3485. .style("opacity", 1),
  3486. (withTransition ? texts.transition() : texts)
  3487. .attr("x", config.axis_rotated ? $$.yGridTextX.bind($$) : $$.xGridTextX.bind($$))
  3488. .attr("y", xv)
  3489. .text(function (d) { return d.text; })
  3490. .style("opacity", 1)
  3491. ];
  3492. };
  3493. c3_chart_internal_fn.showXGridFocus = function (selectedData) {
  3494. var $$ = this, config = $$.config,
  3495. dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
  3496. focusEl = $$.main.selectAll('line.' + CLASS.xgridFocus),
  3497. xx = $$.xx.bind($$);
  3498. if (! config.tooltip_show) { return; }
  3499. // Hide when scatter plot exists
  3500. if ($$.hasType('scatter') || $$.hasArcType()) { return; }
  3501. focusEl
  3502. .style("visibility", "visible")
  3503. .data([dataToShow[0]])
  3504. .attr(config.axis_rotated ? 'y1' : 'x1', xx)
  3505. .attr(config.axis_rotated ? 'y2' : 'x2', xx);
  3506. $$.smoothLines(focusEl, 'grid');
  3507. };
  3508. c3_chart_internal_fn.hideXGridFocus = function () {
  3509. this.main.select('line.' + CLASS.xgridFocus).style("visibility", "hidden");
  3510. };
  3511. c3_chart_internal_fn.updateXgridFocus = function () {
  3512. var $$ = this, config = $$.config;
  3513. $$.main.select('line.' + CLASS.xgridFocus)
  3514. .attr("x1", config.axis_rotated ? 0 : -10)
  3515. .attr("x2", config.axis_rotated ? $$.width : -10)
  3516. .attr("y1", config.axis_rotated ? -10 : 0)
  3517. .attr("y2", config.axis_rotated ? -10 : $$.height);
  3518. };
  3519. c3_chart_internal_fn.generateGridData = function (type, scale) {
  3520. var $$ = this,
  3521. gridData = [], xDomain, firstYear, lastYear, i,
  3522. tickNum = $$.main.select("." + CLASS.axisX).selectAll('.tick').size();
  3523. if (type === 'year') {
  3524. xDomain = $$.getXDomain();
  3525. firstYear = xDomain[0].getFullYear();
  3526. lastYear = xDomain[1].getFullYear();
  3527. for (i = firstYear; i <= lastYear; i++) {
  3528. gridData.push(new Date(i + '-01-01 00:00:00'));
  3529. }
  3530. } else {
  3531. gridData = scale.ticks(10);
  3532. if (gridData.length > tickNum) { // use only int
  3533. gridData = gridData.filter(function (d) { return ("" + d).indexOf('.') < 0; });
  3534. }
  3535. }
  3536. return gridData;
  3537. };
  3538. c3_chart_internal_fn.getGridFilterToRemove = function (params) {
  3539. return params ? function (line) {
  3540. var found = false;
  3541. [].concat(params).forEach(function (param) {
  3542. if ((('value' in param && line.value === param.value) || ('class' in param && line['class'] === param['class']))) {
  3543. found = true;
  3544. }
  3545. });
  3546. return found;
  3547. } : function () { return true; };
  3548. };
  3549. c3_chart_internal_fn.removeGridLines = function (params, forX) {
  3550. var $$ = this, config = $$.config,
  3551. toRemove = $$.getGridFilterToRemove(params),
  3552. toShow = function (line) { return !toRemove(line); },
  3553. classLines = forX ? CLASS.xgridLines : CLASS.ygridLines,
  3554. classLine = forX ? CLASS.xgridLine : CLASS.ygridLine;
  3555. $$.main.select('.' + classLines).selectAll('.' + classLine).filter(toRemove)
  3556. .transition().duration(config.transition_duration)
  3557. .style('opacity', 0).remove();
  3558. if (forX) {
  3559. config.grid_x_lines = config.grid_x_lines.filter(toShow);
  3560. } else {
  3561. config.grid_y_lines = config.grid_y_lines.filter(toShow);
  3562. }
  3563. };
  3564. c3_chart_internal_fn.initTooltip = function () {
  3565. var $$ = this, config = $$.config, i;
  3566. $$.tooltip = $$.selectChart
  3567. .style("position", "relative")
  3568. .append("div")
  3569. .attr('class', CLASS.tooltipContainer)
  3570. .style("position", "absolute")
  3571. .style("pointer-events", "none")
  3572. .style("display", "none");
  3573. // Show tooltip if needed
  3574. if (config.tooltip_init_show) {
  3575. if ($$.isTimeSeries() && isString(config.tooltip_init_x)) {
  3576. config.tooltip_init_x = $$.parseDate(config.tooltip_init_x);
  3577. for (i = 0; i < $$.data.targets[0].values.length; i++) {
  3578. if (($$.data.targets[0].values[i].x - config.tooltip_init_x) === 0) { break; }
  3579. }
  3580. config.tooltip_init_x = i;
  3581. }
  3582. $$.tooltip.html(config.tooltip_contents.call($$, $$.data.targets.map(function (d) {
  3583. return $$.addName(d.values[config.tooltip_init_x]);
  3584. }), $$.axis.getXAxisTickFormat(), $$.getYFormat($$.hasArcType()), $$.color));
  3585. $$.tooltip.style("top", config.tooltip_init_position.top)
  3586. .style("left", config.tooltip_init_position.left)
  3587. .style("display", "block");
  3588. }
  3589. };
  3590. c3_chart_internal_fn.getTooltipContent = function (d, defaultTitleFormat, defaultValueFormat, color) {
  3591. var $$ = this, config = $$.config,
  3592. titleFormat = config.tooltip_format_title || defaultTitleFormat,
  3593. nameFormat = config.tooltip_format_name || function (name) { return name; },
  3594. valueFormat = config.tooltip_format_value || defaultValueFormat,
  3595. text, i, title, value, name, bgcolor,
  3596. orderAsc = $$.isOrderAsc();
  3597. if (config.data_groups.length === 0) {
  3598. d.sort(function(a,b){
  3599. return orderAsc ? a.value - b.value : b.value - a.value;
  3600. });
  3601. } else {
  3602. var ids = $$.orderTargets($$.data.targets).map(function (i) {
  3603. return i.id;
  3604. });
  3605. d.sort(function(a, b) {
  3606. if (a.value > 0 && b.value > 0) {
  3607. return orderAsc ? ids.indexOf(a.id) - ids.indexOf(b.id) : ids.indexOf(b.id) - ids.indexOf(a.id);
  3608. } else {
  3609. return orderAsc ? a.value - b.value : b.value - a.value;
  3610. }
  3611. });
  3612. }
  3613. for (i = 0; i < d.length; i++) {
  3614. if (! (d[i] && (d[i].value || d[i].value === 0))) { continue; }
  3615. if (! text) {
  3616. title = titleFormat ? titleFormat(d[i].x) : d[i].x;
  3617. text = "<table class='" + $$.CLASS.tooltip + "'>" + (title || title === 0 ? "<tr><th colspan='2'>" + title + "</th></tr>" : "");
  3618. }
  3619. value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
  3620. if (value !== undefined) {
  3621. // Skip elements when their name is set to null
  3622. if (d[i].name === null) { continue; }
  3623. name = nameFormat(d[i].name, d[i].ratio, d[i].id, d[i].index);
  3624. bgcolor = $$.levelColor ? $$.levelColor(d[i].value) : color(d[i].id);
  3625. text += "<tr class='" + $$.CLASS.tooltipName + "-" + $$.getTargetSelectorSuffix(d[i].id) + "'>";
  3626. text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + name + "</td>";
  3627. text += "<td class='value'>" + value + "</td>";
  3628. text += "</tr>";
  3629. }
  3630. }
  3631. return text + "</table>";
  3632. };
  3633. c3_chart_internal_fn.tooltipPosition = function (dataToShow, tWidth, tHeight, element) {
  3634. var $$ = this, config = $$.config, d3 = $$.d3;
  3635. var svgLeft, tooltipLeft, tooltipRight, tooltipTop, chartRight;
  3636. var forArc = $$.hasArcType(),
  3637. mouse = d3.mouse(element);
  3638. // Determin tooltip position
  3639. if (forArc) {
  3640. tooltipLeft = (($$.width - ($$.isLegendRight ? $$.getLegendWidth() : 0)) / 2) + mouse[0];
  3641. tooltipTop = ($$.height / 2) + mouse[1] + 20;
  3642. } else {
  3643. svgLeft = $$.getSvgLeft(true);
  3644. if (config.axis_rotated) {
  3645. tooltipLeft = svgLeft + mouse[0] + 100;
  3646. tooltipRight = tooltipLeft + tWidth;
  3647. chartRight = $$.currentWidth - $$.getCurrentPaddingRight();
  3648. tooltipTop = $$.x(dataToShow[0].x) + 20;
  3649. } else {
  3650. tooltipLeft = svgLeft + $$.getCurrentPaddingLeft(true) + $$.x(dataToShow[0].x) + 20;
  3651. tooltipRight = tooltipLeft + tWidth;
  3652. chartRight = svgLeft + $$.currentWidth - $$.getCurrentPaddingRight();
  3653. tooltipTop = mouse[1] + 15;
  3654. }
  3655. if (tooltipRight > chartRight) {
  3656. // 20 is needed for Firefox to keep tooltip width
  3657. tooltipLeft -= tooltipRight - chartRight + 20;
  3658. }
  3659. if (tooltipTop + tHeight > $$.currentHeight) {
  3660. tooltipTop -= tHeight + 30;
  3661. }
  3662. }
  3663. if (tooltipTop < 0) {
  3664. tooltipTop = 0;
  3665. }
  3666. return {top: tooltipTop, left: tooltipLeft};
  3667. };
  3668. c3_chart_internal_fn.showTooltip = function (selectedData, element) {
  3669. var $$ = this, config = $$.config;
  3670. var tWidth, tHeight, position;
  3671. var forArc = $$.hasArcType(),
  3672. dataToShow = selectedData.filter(function (d) { return d && isValue(d.value); }),
  3673. positionFunction = config.tooltip_position || c3_chart_internal_fn.tooltipPosition;
  3674. if (dataToShow.length === 0 || !config.tooltip_show) {
  3675. return;
  3676. }
  3677. $$.tooltip.html(config.tooltip_contents.call($$, selectedData, $$.axis.getXAxisTickFormat(), $$.getYFormat(forArc), $$.color)).style("display", "block");
  3678. // Get tooltip dimensions
  3679. tWidth = $$.tooltip.property('offsetWidth');
  3680. tHeight = $$.tooltip.property('offsetHeight');
  3681. position = positionFunction.call(this, dataToShow, tWidth, tHeight, element);
  3682. // Set tooltip
  3683. $$.tooltip
  3684. .style("top", position.top + "px")
  3685. .style("left", position.left + 'px');
  3686. };
  3687. c3_chart_internal_fn.hideTooltip = function () {
  3688. this.tooltip.style("display", "none");
  3689. };
  3690. c3_chart_internal_fn.initLegend = function () {
  3691. var $$ = this;
  3692. $$.legendItemTextBox = {};
  3693. $$.legendHasRendered = false;
  3694. $$.legend = $$.svg.append("g").attr("transform", $$.getTranslate('legend'));
  3695. if (!$$.config.legend_show) {
  3696. $$.legend.style('visibility', 'hidden');
  3697. $$.hiddenLegendIds = $$.mapToIds($$.data.targets);
  3698. return;
  3699. }
  3700. // MEMO: call here to update legend box and tranlate for all
  3701. // MEMO: translate will be upated by this, so transform not needed in updateLegend()
  3702. $$.updateLegendWithDefaults();
  3703. };
  3704. c3_chart_internal_fn.updateLegendWithDefaults = function () {
  3705. var $$ = this;
  3706. $$.updateLegend($$.mapToIds($$.data.targets), {withTransform: false, withTransitionForTransform: false, withTransition: false});
  3707. };
  3708. c3_chart_internal_fn.updateSizeForLegend = function (legendHeight, legendWidth) {
  3709. var $$ = this, config = $$.config, insetLegendPosition = {
  3710. top: $$.isLegendTop ? $$.getCurrentPaddingTop() + config.legend_inset_y + 5.5 : $$.currentHeight - legendHeight - $$.getCurrentPaddingBottom() - config.legend_inset_y,
  3711. left: $$.isLegendLeft ? $$.getCurrentPaddingLeft() + config.legend_inset_x + 0.5 : $$.currentWidth - legendWidth - $$.getCurrentPaddingRight() - config.legend_inset_x + 0.5
  3712. };
  3713. $$.margin3 = {
  3714. top: $$.isLegendRight ? 0 : $$.isLegendInset ? insetLegendPosition.top : $$.currentHeight - legendHeight,
  3715. right: NaN,
  3716. bottom: 0,
  3717. left: $$.isLegendRight ? $$.currentWidth - legendWidth : $$.isLegendInset ? insetLegendPosition.left : 0
  3718. };
  3719. };
  3720. c3_chart_internal_fn.transformLegend = function (withTransition) {
  3721. var $$ = this;
  3722. (withTransition ? $$.legend.transition() : $$.legend).attr("transform", $$.getTranslate('legend'));
  3723. };
  3724. c3_chart_internal_fn.updateLegendStep = function (step) {
  3725. this.legendStep = step;
  3726. };
  3727. c3_chart_internal_fn.updateLegendItemWidth = function (w) {
  3728. this.legendItemWidth = w;
  3729. };
  3730. c3_chart_internal_fn.updateLegendItemHeight = function (h) {
  3731. this.legendItemHeight = h;
  3732. };
  3733. c3_chart_internal_fn.getLegendWidth = function () {
  3734. var $$ = this;
  3735. return $$.config.legend_show ? $$.isLegendRight || $$.isLegendInset ? $$.legendItemWidth * ($$.legendStep + 1) : $$.currentWidth : 0;
  3736. };
  3737. c3_chart_internal_fn.getLegendHeight = function () {
  3738. var $$ = this, h = 0;
  3739. if ($$.config.legend_show) {
  3740. if ($$.isLegendRight) {
  3741. h = $$.currentHeight;
  3742. } else {
  3743. h = Math.max(20, $$.legendItemHeight) * ($$.legendStep + 1);
  3744. }
  3745. }
  3746. return h;
  3747. };
  3748. c3_chart_internal_fn.opacityForLegend = function (legendItem) {
  3749. return legendItem.classed(CLASS.legendItemHidden) ? null : 1;
  3750. };
  3751. c3_chart_internal_fn.opacityForUnfocusedLegend = function (legendItem) {
  3752. return legendItem.classed(CLASS.legendItemHidden) ? null : 0.3;
  3753. };
  3754. c3_chart_internal_fn.toggleFocusLegend = function (targetIds, focus) {
  3755. var $$ = this;
  3756. targetIds = $$.mapToTargetIds(targetIds);
  3757. $$.legend.selectAll('.' + CLASS.legendItem)
  3758. .filter(function (id) { return targetIds.indexOf(id) >= 0; })
  3759. .classed(CLASS.legendItemFocused, focus)
  3760. .transition().duration(100)
  3761. .style('opacity', function () {
  3762. var opacity = focus ? $$.opacityForLegend : $$.opacityForUnfocusedLegend;
  3763. return opacity.call($$, $$.d3.select(this));
  3764. });
  3765. };
  3766. c3_chart_internal_fn.revertLegend = function () {
  3767. var $$ = this, d3 = $$.d3;
  3768. $$.legend.selectAll('.' + CLASS.legendItem)
  3769. .classed(CLASS.legendItemFocused, false)
  3770. .transition().duration(100)
  3771. .style('opacity', function () { return $$.opacityForLegend(d3.select(this)); });
  3772. };
  3773. c3_chart_internal_fn.showLegend = function (targetIds) {
  3774. var $$ = this, config = $$.config;
  3775. if (!config.legend_show) {
  3776. config.legend_show = true;
  3777. $$.legend.style('visibility', 'visible');
  3778. if (!$$.legendHasRendered) {
  3779. $$.updateLegendWithDefaults();
  3780. }
  3781. }
  3782. $$.removeHiddenLegendIds(targetIds);
  3783. $$.legend.selectAll($$.selectorLegends(targetIds))
  3784. .style('visibility', 'visible')
  3785. .transition()
  3786. .style('opacity', function () { return $$.opacityForLegend($$.d3.select(this)); });
  3787. };
  3788. c3_chart_internal_fn.hideLegend = function (targetIds) {
  3789. var $$ = this, config = $$.config;
  3790. if (config.legend_show && isEmpty(targetIds)) {
  3791. config.legend_show = false;
  3792. $$.legend.style('visibility', 'hidden');
  3793. }
  3794. $$.addHiddenLegendIds(targetIds);
  3795. $$.legend.selectAll($$.selectorLegends(targetIds))
  3796. .style('opacity', 0)
  3797. .style('visibility', 'hidden');
  3798. };
  3799. c3_chart_internal_fn.clearLegendItemTextBoxCache = function () {
  3800. this.legendItemTextBox = {};
  3801. };
  3802. c3_chart_internal_fn.updateLegend = function (targetIds, options, transitions) {
  3803. var $$ = this, config = $$.config;
  3804. var xForLegend, xForLegendText, xForLegendRect, yForLegend, yForLegendText, yForLegendRect, x1ForLegendTile, x2ForLegendTile, yForLegendTile;
  3805. var paddingTop = 4, paddingRight = 10, maxWidth = 0, maxHeight = 0, posMin = 10, tileWidth = config.legend_item_tile_width + 5;
  3806. var l, totalLength = 0, offsets = {}, widths = {}, heights = {}, margins = [0], steps = {}, step = 0;
  3807. var withTransition, withTransitionForTransform;
  3808. var texts, rects, tiles, background;
  3809. // Skip elements when their name is set to null
  3810. targetIds = targetIds.filter(function(id) {
  3811. return !isDefined(config.data_names[id]) || config.data_names[id] !== null;
  3812. });
  3813. options = options || {};
  3814. withTransition = getOption(options, "withTransition", true);
  3815. withTransitionForTransform = getOption(options, "withTransitionForTransform", true);
  3816. function getTextBox(textElement, id) {
  3817. if (!$$.legendItemTextBox[id]) {
  3818. $$.legendItemTextBox[id] = $$.getTextRect(textElement.textContent, CLASS.legendItem, textElement);
  3819. }
  3820. return $$.legendItemTextBox[id];
  3821. }
  3822. function updatePositions(textElement, id, index) {
  3823. var reset = index === 0, isLast = index === targetIds.length - 1,
  3824. box = getTextBox(textElement, id),
  3825. itemWidth = box.width + tileWidth + (isLast && !($$.isLegendRight || $$.isLegendInset) ? 0 : paddingRight) + config.legend_padding,
  3826. itemHeight = box.height + paddingTop,
  3827. itemLength = $$.isLegendRight || $$.isLegendInset ? itemHeight : itemWidth,
  3828. areaLength = $$.isLegendRight || $$.isLegendInset ? $$.getLegendHeight() : $$.getLegendWidth(),
  3829. margin, maxLength;
  3830. // MEMO: care about condifion of step, totalLength
  3831. function updateValues(id, withoutStep) {
  3832. if (!withoutStep) {
  3833. margin = (areaLength - totalLength - itemLength) / 2;
  3834. if (margin < posMin) {
  3835. margin = (areaLength - itemLength) / 2;
  3836. totalLength = 0;
  3837. step++;
  3838. }
  3839. }
  3840. steps[id] = step;
  3841. margins[step] = $$.isLegendInset ? 10 : margin;
  3842. offsets[id] = totalLength;
  3843. totalLength += itemLength;
  3844. }
  3845. if (reset) {
  3846. totalLength = 0;
  3847. step = 0;
  3848. maxWidth = 0;
  3849. maxHeight = 0;
  3850. }
  3851. if (config.legend_show && !$$.isLegendToShow(id)) {
  3852. widths[id] = heights[id] = steps[id] = offsets[id] = 0;
  3853. return;
  3854. }
  3855. widths[id] = itemWidth;
  3856. heights[id] = itemHeight;
  3857. if (!maxWidth || itemWidth >= maxWidth) { maxWidth = itemWidth; }
  3858. if (!maxHeight || itemHeight >= maxHeight) { maxHeight = itemHeight; }
  3859. maxLength = $$.isLegendRight || $$.isLegendInset ? maxHeight : maxWidth;
  3860. if (config.legend_equally) {
  3861. Object.keys(widths).forEach(function (id) { widths[id] = maxWidth; });
  3862. Object.keys(heights).forEach(function (id) { heights[id] = maxHeight; });
  3863. margin = (areaLength - maxLength * targetIds.length) / 2;
  3864. if (margin < posMin) {
  3865. totalLength = 0;
  3866. step = 0;
  3867. targetIds.forEach(function (id) { updateValues(id); });
  3868. }
  3869. else {
  3870. updateValues(id, true);
  3871. }
  3872. } else {
  3873. updateValues(id);
  3874. }
  3875. }
  3876. if ($$.isLegendInset) {
  3877. step = config.legend_inset_step ? config.legend_inset_step : targetIds.length;
  3878. $$.updateLegendStep(step);
  3879. }
  3880. if ($$.isLegendRight) {
  3881. xForLegend = function (id) { return maxWidth * steps[id]; };
  3882. yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
  3883. } else if ($$.isLegendInset) {
  3884. xForLegend = function (id) { return maxWidth * steps[id] + 10; };
  3885. yForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
  3886. } else {
  3887. xForLegend = function (id) { return margins[steps[id]] + offsets[id]; };
  3888. yForLegend = function (id) { return maxHeight * steps[id]; };
  3889. }
  3890. xForLegendText = function (id, i) { return xForLegend(id, i) + 4 + config.legend_item_tile_width; };
  3891. yForLegendText = function (id, i) { return yForLegend(id, i) + 9; };
  3892. xForLegendRect = function (id, i) { return xForLegend(id, i); };
  3893. yForLegendRect = function (id, i) { return yForLegend(id, i) - 5; };
  3894. x1ForLegendTile = function (id, i) { return xForLegend(id, i) - 2; };
  3895. x2ForLegendTile = function (id, i) { return xForLegend(id, i) - 2 + config.legend_item_tile_width; };
  3896. yForLegendTile = function (id, i) { return yForLegend(id, i) + 4; };
  3897. // Define g for legend area
  3898. l = $$.legend.selectAll('.' + CLASS.legendItem)
  3899. .data(targetIds)
  3900. .enter().append('g')
  3901. .attr('class', function (id) { return $$.generateClass(CLASS.legendItem, id); })
  3902. .style('visibility', function (id) { return $$.isLegendToShow(id) ? 'visible' : 'hidden'; })
  3903. .style('cursor', 'pointer')
  3904. .on('click', function (id) {
  3905. if (config.legend_item_onclick) {
  3906. config.legend_item_onclick.call($$, id);
  3907. } else {
  3908. if ($$.d3.event.altKey) {
  3909. $$.api.hide();
  3910. $$.api.show(id);
  3911. } else {
  3912. $$.api.toggle(id);
  3913. $$.isTargetToShow(id) ? $$.api.focus(id) : $$.api.revert();
  3914. }
  3915. }
  3916. })
  3917. .on('mouseover', function (id) {
  3918. if (config.legend_item_onmouseover) {
  3919. config.legend_item_onmouseover.call($$, id);
  3920. }
  3921. else {
  3922. $$.d3.select(this).classed(CLASS.legendItemFocused, true);
  3923. if (!$$.transiting && $$.isTargetToShow(id)) {
  3924. $$.api.focus(id);
  3925. }
  3926. }
  3927. })
  3928. .on('mouseout', function (id) {
  3929. if (config.legend_item_onmouseout) {
  3930. config.legend_item_onmouseout.call($$, id);
  3931. }
  3932. else {
  3933. $$.d3.select(this).classed(CLASS.legendItemFocused, false);
  3934. $$.api.revert();
  3935. }
  3936. });
  3937. l.append('text')
  3938. .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; })
  3939. .each(function (id, i) { updatePositions(this, id, i); })
  3940. .style("pointer-events", "none")
  3941. .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendText : -200)
  3942. .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendText);
  3943. l.append('rect')
  3944. .attr("class", CLASS.legendItemEvent)
  3945. .style('fill-opacity', 0)
  3946. .attr('x', $$.isLegendRight || $$.isLegendInset ? xForLegendRect : -200)
  3947. .attr('y', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendRect);
  3948. l.append('line')
  3949. .attr('class', CLASS.legendItemTile)
  3950. .style('stroke', $$.color)
  3951. .style("pointer-events", "none")
  3952. .attr('x1', $$.isLegendRight || $$.isLegendInset ? x1ForLegendTile : -200)
  3953. .attr('y1', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile)
  3954. .attr('x2', $$.isLegendRight || $$.isLegendInset ? x2ForLegendTile : -200)
  3955. .attr('y2', $$.isLegendRight || $$.isLegendInset ? -200 : yForLegendTile)
  3956. .attr('stroke-width', config.legend_item_tile_height);
  3957. // Set background for inset legend
  3958. background = $$.legend.select('.' + CLASS.legendBackground + ' rect');
  3959. if ($$.isLegendInset && maxWidth > 0 && background.size() === 0) {
  3960. background = $$.legend.insert('g', '.' + CLASS.legendItem)
  3961. .attr("class", CLASS.legendBackground)
  3962. .append('rect');
  3963. }
  3964. texts = $$.legend.selectAll('text')
  3965. .data(targetIds)
  3966. .text(function (id) { return isDefined(config.data_names[id]) ? config.data_names[id] : id; }) // MEMO: needed for update
  3967. .each(function (id, i) { updatePositions(this, id, i); });
  3968. (withTransition ? texts.transition() : texts)
  3969. .attr('x', xForLegendText)
  3970. .attr('y', yForLegendText);
  3971. rects = $$.legend.selectAll('rect.' + CLASS.legendItemEvent)
  3972. .data(targetIds);
  3973. (withTransition ? rects.transition() : rects)
  3974. .attr('width', function (id) { return widths[id]; })
  3975. .attr('height', function (id) { return heights[id]; })
  3976. .attr('x', xForLegendRect)
  3977. .attr('y', yForLegendRect);
  3978. tiles = $$.legend.selectAll('line.' + CLASS.legendItemTile)
  3979. .data(targetIds);
  3980. (withTransition ? tiles.transition() : tiles)
  3981. .style('stroke', $$.color)
  3982. .attr('x1', x1ForLegendTile)
  3983. .attr('y1', yForLegendTile)
  3984. .attr('x2', x2ForLegendTile)
  3985. .attr('y2', yForLegendTile);
  3986. if (background) {
  3987. (withTransition ? background.transition() : background)
  3988. .attr('height', $$.getLegendHeight() - 12)
  3989. .attr('width', maxWidth * (step + 1) + 10);
  3990. }
  3991. // toggle legend state
  3992. $$.legend.selectAll('.' + CLASS.legendItem)
  3993. .classed(CLASS.legendItemHidden, function (id) { return !$$.isTargetToShow(id); });
  3994. // Update all to reflect change of legend
  3995. $$.updateLegendItemWidth(maxWidth);
  3996. $$.updateLegendItemHeight(maxHeight);
  3997. $$.updateLegendStep(step);
  3998. // Update size and scale
  3999. $$.updateSizes();
  4000. $$.updateScales();
  4001. $$.updateSvgSize();
  4002. // Update g positions
  4003. $$.transformAll(withTransitionForTransform, transitions);
  4004. $$.legendHasRendered = true;
  4005. };
  4006. c3_chart_internal_fn.initTitle = function () {
  4007. var $$ = this;
  4008. $$.title = $$.svg.append("text")
  4009. .text($$.config.title_text)
  4010. .attr("class", $$.CLASS.title);
  4011. };
  4012. c3_chart_internal_fn.redrawTitle = function () {
  4013. var $$ = this;
  4014. $$.title
  4015. .attr("x", $$.xForTitle.bind($$))
  4016. .attr("y", $$.yForTitle.bind($$));
  4017. };
  4018. c3_chart_internal_fn.xForTitle = function () {
  4019. var $$ = this, config = $$.config, position = config.title_position || 'left', x;
  4020. if (position.indexOf('right') >= 0) {
  4021. x = $$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width - config.title_padding.right;
  4022. } else if (position.indexOf('center') >= 0) {
  4023. x = ($$.currentWidth - $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).width) / 2;
  4024. } else { // left
  4025. x = config.title_padding.left;
  4026. }
  4027. return x;
  4028. };
  4029. c3_chart_internal_fn.yForTitle = function () {
  4030. var $$ = this;
  4031. return $$.config.title_padding.top + $$.getTextRect($$.title.node().textContent, $$.CLASS.title, $$.title.node()).height;
  4032. };
  4033. c3_chart_internal_fn.getTitlePadding = function() {
  4034. var $$ = this;
  4035. return $$.yForTitle() + $$.config.title_padding.bottom;
  4036. };
  4037. function Axis(owner) {
  4038. API.call(this, owner);
  4039. }
  4040. inherit(API, Axis);
  4041. Axis.prototype.init = function init() {
  4042. var $$ = this.owner, config = $$.config, main = $$.main;
  4043. $$.axes.x = main.append("g")
  4044. .attr("class", CLASS.axis + ' ' + CLASS.axisX)
  4045. .attr("clip-path", $$.clipPathForXAxis)
  4046. .attr("transform", $$.getTranslate('x'))
  4047. .style("visibility", config.axis_x_show ? 'visible' : 'hidden');
  4048. $$.axes.x.append("text")
  4049. .attr("class", CLASS.axisXLabel)
  4050. .attr("transform", config.axis_rotated ? "rotate(-90)" : "")
  4051. .style("text-anchor", this.textAnchorForXAxisLabel.bind(this));
  4052. $$.axes.y = main.append("g")
  4053. .attr("class", CLASS.axis + ' ' + CLASS.axisY)
  4054. .attr("clip-path", config.axis_y_inner ? "" : $$.clipPathForYAxis)
  4055. .attr("transform", $$.getTranslate('y'))
  4056. .style("visibility", config.axis_y_show ? 'visible' : 'hidden');
  4057. $$.axes.y.append("text")
  4058. .attr("class", CLASS.axisYLabel)
  4059. .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
  4060. .style("text-anchor", this.textAnchorForYAxisLabel.bind(this));
  4061. $$.axes.y2 = main.append("g")
  4062. .attr("class", CLASS.axis + ' ' + CLASS.axisY2)
  4063. // clip-path?
  4064. .attr("transform", $$.getTranslate('y2'))
  4065. .style("visibility", config.axis_y2_show ? 'visible' : 'hidden');
  4066. $$.axes.y2.append("text")
  4067. .attr("class", CLASS.axisY2Label)
  4068. .attr("transform", config.axis_rotated ? "" : "rotate(-90)")
  4069. .style("text-anchor", this.textAnchorForY2AxisLabel.bind(this));
  4070. };
  4071. Axis.prototype.getXAxis = function getXAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
  4072. var $$ = this.owner, config = $$.config,
  4073. axisParams = {
  4074. isCategory: $$.isCategorized(),
  4075. withOuterTick: withOuterTick,
  4076. tickMultiline: config.axis_x_tick_multiline,
  4077. tickWidth: config.axis_x_tick_width,
  4078. tickTextRotate: withoutRotateTickText ? 0 : config.axis_x_tick_rotate,
  4079. withoutTransition: withoutTransition,
  4080. },
  4081. axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient);
  4082. if ($$.isTimeSeries() && tickValues && typeof tickValues !== "function") {
  4083. tickValues = tickValues.map(function (v) { return $$.parseDate(v); });
  4084. }
  4085. // Set tick
  4086. axis.tickFormat(tickFormat).tickValues(tickValues);
  4087. if ($$.isCategorized()) {
  4088. axis.tickCentered(config.axis_x_tick_centered);
  4089. if (isEmpty(config.axis_x_tick_culling)) {
  4090. config.axis_x_tick_culling = false;
  4091. }
  4092. }
  4093. return axis;
  4094. };
  4095. Axis.prototype.updateXAxisTickValues = function updateXAxisTickValues(targets, axis) {
  4096. var $$ = this.owner, config = $$.config, tickValues;
  4097. if (config.axis_x_tick_fit || config.axis_x_tick_count) {
  4098. tickValues = this.generateTickValues($$.mapTargetsToUniqueXs(targets), config.axis_x_tick_count, $$.isTimeSeries());
  4099. }
  4100. if (axis) {
  4101. axis.tickValues(tickValues);
  4102. } else {
  4103. $$.xAxis.tickValues(tickValues);
  4104. $$.subXAxis.tickValues(tickValues);
  4105. }
  4106. return tickValues;
  4107. };
  4108. Axis.prototype.getYAxis = function getYAxis(scale, orient, tickFormat, tickValues, withOuterTick, withoutTransition, withoutRotateTickText) {
  4109. var $$ = this.owner, config = $$.config,
  4110. axisParams = {
  4111. withOuterTick: withOuterTick,
  4112. withoutTransition: withoutTransition,
  4113. tickTextRotate: withoutRotateTickText ? 0 : config.axis_y_tick_rotate
  4114. },
  4115. axis = c3_axis($$.d3, axisParams).scale(scale).orient(orient).tickFormat(tickFormat);
  4116. if ($$.isTimeSeriesY()) {
  4117. axis.ticks($$.d3.time[config.axis_y_tick_time_value], config.axis_y_tick_time_interval);
  4118. } else {
  4119. axis.tickValues(tickValues);
  4120. }
  4121. return axis;
  4122. };
  4123. Axis.prototype.getId = function getId(id) {
  4124. var config = this.owner.config;
  4125. return id in config.data_axes ? config.data_axes[id] : 'y';
  4126. };
  4127. Axis.prototype.getXAxisTickFormat = function getXAxisTickFormat() {
  4128. var $$ = this.owner, config = $$.config,
  4129. format = $$.isTimeSeries() ? $$.defaultAxisTimeFormat : $$.isCategorized() ? $$.categoryName : function (v) { return v < 0 ? v.toFixed(0) : v; };
  4130. if (config.axis_x_tick_format) {
  4131. if (isFunction(config.axis_x_tick_format)) {
  4132. format = config.axis_x_tick_format;
  4133. } else if ($$.isTimeSeries()) {
  4134. format = function (date) {
  4135. return date ? $$.axisTimeFormat(config.axis_x_tick_format)(date) : "";
  4136. };
  4137. }
  4138. }
  4139. return isFunction(format) ? function (v) { return format.call($$, v); } : format;
  4140. };
  4141. Axis.prototype.getTickValues = function getTickValues(tickValues, axis) {
  4142. return tickValues ? tickValues : axis ? axis.tickValues() : undefined;
  4143. };
  4144. Axis.prototype.getXAxisTickValues = function getXAxisTickValues() {
  4145. return this.getTickValues(this.owner.config.axis_x_tick_values, this.owner.xAxis);
  4146. };
  4147. Axis.prototype.getYAxisTickValues = function getYAxisTickValues() {
  4148. return this.getTickValues(this.owner.config.axis_y_tick_values, this.owner.yAxis);
  4149. };
  4150. Axis.prototype.getY2AxisTickValues = function getY2AxisTickValues() {
  4151. return this.getTickValues(this.owner.config.axis_y2_tick_values, this.owner.y2Axis);
  4152. };
  4153. Axis.prototype.getLabelOptionByAxisId = function getLabelOptionByAxisId(axisId) {
  4154. var $$ = this.owner, config = $$.config, option;
  4155. if (axisId === 'y') {
  4156. option = config.axis_y_label;
  4157. } else if (axisId === 'y2') {
  4158. option = config.axis_y2_label;
  4159. } else if (axisId === 'x') {
  4160. option = config.axis_x_label;
  4161. }
  4162. return option;
  4163. };
  4164. Axis.prototype.getLabelText = function getLabelText(axisId) {
  4165. var option = this.getLabelOptionByAxisId(axisId);
  4166. return isString(option) ? option : option ? option.text : null;
  4167. };
  4168. Axis.prototype.setLabelText = function setLabelText(axisId, text) {
  4169. var $$ = this.owner, config = $$.config,
  4170. option = this.getLabelOptionByAxisId(axisId);
  4171. if (isString(option)) {
  4172. if (axisId === 'y') {
  4173. config.axis_y_label = text;
  4174. } else if (axisId === 'y2') {
  4175. config.axis_y2_label = text;
  4176. } else if (axisId === 'x') {
  4177. config.axis_x_label = text;
  4178. }
  4179. } else if (option) {
  4180. option.text = text;
  4181. }
  4182. };
  4183. Axis.prototype.getLabelPosition = function getLabelPosition(axisId, defaultPosition) {
  4184. var option = this.getLabelOptionByAxisId(axisId),
  4185. position = (option && typeof option === 'object' && option.position) ? option.position : defaultPosition;
  4186. return {
  4187. isInner: position.indexOf('inner') >= 0,
  4188. isOuter: position.indexOf('outer') >= 0,
  4189. isLeft: position.indexOf('left') >= 0,
  4190. isCenter: position.indexOf('center') >= 0,
  4191. isRight: position.indexOf('right') >= 0,
  4192. isTop: position.indexOf('top') >= 0,
  4193. isMiddle: position.indexOf('middle') >= 0,
  4194. isBottom: position.indexOf('bottom') >= 0
  4195. };
  4196. };
  4197. Axis.prototype.getXAxisLabelPosition = function getXAxisLabelPosition() {
  4198. return this.getLabelPosition('x', this.owner.config.axis_rotated ? 'inner-top' : 'inner-right');
  4199. };
  4200. Axis.prototype.getYAxisLabelPosition = function getYAxisLabelPosition() {
  4201. return this.getLabelPosition('y', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
  4202. };
  4203. Axis.prototype.getY2AxisLabelPosition = function getY2AxisLabelPosition() {
  4204. return this.getLabelPosition('y2', this.owner.config.axis_rotated ? 'inner-right' : 'inner-top');
  4205. };
  4206. Axis.prototype.getLabelPositionById = function getLabelPositionById(id) {
  4207. return id === 'y2' ? this.getY2AxisLabelPosition() : id === 'y' ? this.getYAxisLabelPosition() : this.getXAxisLabelPosition();
  4208. };
  4209. Axis.prototype.textForXAxisLabel = function textForXAxisLabel() {
  4210. return this.getLabelText('x');
  4211. };
  4212. Axis.prototype.textForYAxisLabel = function textForYAxisLabel() {
  4213. return this.getLabelText('y');
  4214. };
  4215. Axis.prototype.textForY2AxisLabel = function textForY2AxisLabel() {
  4216. return this.getLabelText('y2');
  4217. };
  4218. Axis.prototype.xForAxisLabel = function xForAxisLabel(forHorizontal, position) {
  4219. var $$ = this.owner;
  4220. if (forHorizontal) {
  4221. return position.isLeft ? 0 : position.isCenter ? $$.width / 2 : $$.width;
  4222. } else {
  4223. return position.isBottom ? -$$.height : position.isMiddle ? -$$.height / 2 : 0;
  4224. }
  4225. };
  4226. Axis.prototype.dxForAxisLabel = function dxForAxisLabel(forHorizontal, position) {
  4227. if (forHorizontal) {
  4228. return position.isLeft ? "0.5em" : position.isRight ? "-0.5em" : "0";
  4229. } else {
  4230. return position.isTop ? "-0.5em" : position.isBottom ? "0.5em" : "0";
  4231. }
  4232. };
  4233. Axis.prototype.textAnchorForAxisLabel = function textAnchorForAxisLabel(forHorizontal, position) {
  4234. if (forHorizontal) {
  4235. return position.isLeft ? 'start' : position.isCenter ? 'middle' : 'end';
  4236. } else {
  4237. return position.isBottom ? 'start' : position.isMiddle ? 'middle' : 'end';
  4238. }
  4239. };
  4240. Axis.prototype.xForXAxisLabel = function xForXAxisLabel() {
  4241. return this.xForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
  4242. };
  4243. Axis.prototype.xForYAxisLabel = function xForYAxisLabel() {
  4244. return this.xForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
  4245. };
  4246. Axis.prototype.xForY2AxisLabel = function xForY2AxisLabel() {
  4247. return this.xForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
  4248. };
  4249. Axis.prototype.dxForXAxisLabel = function dxForXAxisLabel() {
  4250. return this.dxForAxisLabel(!this.owner.config.axis_rotated, this.getXAxisLabelPosition());
  4251. };
  4252. Axis.prototype.dxForYAxisLabel = function dxForYAxisLabel() {
  4253. return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getYAxisLabelPosition());
  4254. };
  4255. Axis.prototype.dxForY2AxisLabel = function dxForY2AxisLabel() {
  4256. return this.dxForAxisLabel(this.owner.config.axis_rotated, this.getY2AxisLabelPosition());
  4257. };
  4258. Axis.prototype.dyForXAxisLabel = function dyForXAxisLabel() {
  4259. var $$ = this.owner, config = $$.config,
  4260. position = this.getXAxisLabelPosition();
  4261. if (config.axis_rotated) {
  4262. return position.isInner ? "1.2em" : -25 - this.getMaxTickWidth('x');
  4263. } else {
  4264. return position.isInner ? "-0.5em" : config.axis_x_height ? config.axis_x_height - 10 : "3em";
  4265. }
  4266. };
  4267. Axis.prototype.dyForYAxisLabel = function dyForYAxisLabel() {
  4268. var $$ = this.owner,
  4269. position = this.getYAxisLabelPosition();
  4270. if ($$.config.axis_rotated) {
  4271. return position.isInner ? "-0.5em" : "3em";
  4272. } else {
  4273. return position.isInner ? "1.2em" : -10 - ($$.config.axis_y_inner ? 0 : (this.getMaxTickWidth('y') + 10));
  4274. }
  4275. };
  4276. Axis.prototype.dyForY2AxisLabel = function dyForY2AxisLabel() {
  4277. var $$ = this.owner,
  4278. position = this.getY2AxisLabelPosition();
  4279. if ($$.config.axis_rotated) {
  4280. return position.isInner ? "1.2em" : "-2.2em";
  4281. } else {
  4282. return position.isInner ? "-0.5em" : 15 + ($$.config.axis_y2_inner ? 0 : (this.getMaxTickWidth('y2') + 15));
  4283. }
  4284. };
  4285. Axis.prototype.textAnchorForXAxisLabel = function textAnchorForXAxisLabel() {
  4286. var $$ = this.owner;
  4287. return this.textAnchorForAxisLabel(!$$.config.axis_rotated, this.getXAxisLabelPosition());
  4288. };
  4289. Axis.prototype.textAnchorForYAxisLabel = function textAnchorForYAxisLabel() {
  4290. var $$ = this.owner;
  4291. return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getYAxisLabelPosition());
  4292. };
  4293. Axis.prototype.textAnchorForY2AxisLabel = function textAnchorForY2AxisLabel() {
  4294. var $$ = this.owner;
  4295. return this.textAnchorForAxisLabel($$.config.axis_rotated, this.getY2AxisLabelPosition());
  4296. };
  4297. Axis.prototype.getMaxTickWidth = function getMaxTickWidth(id, withoutRecompute) {
  4298. var $$ = this.owner, config = $$.config,
  4299. maxWidth = 0, targetsToShow, scale, axis, dummy, svg;
  4300. if (withoutRecompute && $$.currentMaxTickWidths[id]) {
  4301. return $$.currentMaxTickWidths[id];
  4302. }
  4303. if ($$.svg) {
  4304. targetsToShow = $$.filterTargetsToShow($$.data.targets);
  4305. if (id === 'y') {
  4306. scale = $$.y.copy().domain($$.getYDomain(targetsToShow, 'y'));
  4307. axis = this.getYAxis(scale, $$.yOrient, config.axis_y_tick_format, $$.yAxisTickValues, false, true, true);
  4308. } else if (id === 'y2') {
  4309. scale = $$.y2.copy().domain($$.getYDomain(targetsToShow, 'y2'));
  4310. axis = this.getYAxis(scale, $$.y2Orient, config.axis_y2_tick_format, $$.y2AxisTickValues, false, true, true);
  4311. } else {
  4312. scale = $$.x.copy().domain($$.getXDomain(targetsToShow));
  4313. axis = this.getXAxis(scale, $$.xOrient, $$.xAxisTickFormat, $$.xAxisTickValues, false, true, true);
  4314. this.updateXAxisTickValues(targetsToShow, axis);
  4315. }
  4316. dummy = $$.d3.select('body').append('div').classed('c3', true);
  4317. svg = dummy.append("svg").style('visibility', 'hidden').style('position', 'fixed').style('top', 0).style('left', 0),
  4318. svg.append('g').call(axis).each(function () {
  4319. $$.d3.select(this).selectAll('text').each(function () {
  4320. var box = this.getBoundingClientRect();
  4321. if (maxWidth < box.width) { maxWidth = box.width; }
  4322. });
  4323. dummy.remove();
  4324. });
  4325. }
  4326. $$.currentMaxTickWidths[id] = maxWidth <= 0 ? $$.currentMaxTickWidths[id] : maxWidth;
  4327. return $$.currentMaxTickWidths[id];
  4328. };
  4329. Axis.prototype.updateLabels = function updateLabels(withTransition) {
  4330. var $$ = this.owner;
  4331. var axisXLabel = $$.main.select('.' + CLASS.axisX + ' .' + CLASS.axisXLabel),
  4332. axisYLabel = $$.main.select('.' + CLASS.axisY + ' .' + CLASS.axisYLabel),
  4333. axisY2Label = $$.main.select('.' + CLASS.axisY2 + ' .' + CLASS.axisY2Label);
  4334. (withTransition ? axisXLabel.transition() : axisXLabel)
  4335. .attr("x", this.xForXAxisLabel.bind(this))
  4336. .attr("dx", this.dxForXAxisLabel.bind(this))
  4337. .attr("dy", this.dyForXAxisLabel.bind(this))
  4338. .text(this.textForXAxisLabel.bind(this));
  4339. (withTransition ? axisYLabel.transition() : axisYLabel)
  4340. .attr("x", this.xForYAxisLabel.bind(this))
  4341. .attr("dx", this.dxForYAxisLabel.bind(this))
  4342. .attr("dy", this.dyForYAxisLabel.bind(this))
  4343. .text(this.textForYAxisLabel.bind(this));
  4344. (withTransition ? axisY2Label.transition() : axisY2Label)
  4345. .attr("x", this.xForY2AxisLabel.bind(this))
  4346. .attr("dx", this.dxForY2AxisLabel.bind(this))
  4347. .attr("dy", this.dyForY2AxisLabel.bind(this))
  4348. .text(this.textForY2AxisLabel.bind(this));
  4349. };
  4350. Axis.prototype.getPadding = function getPadding(padding, key, defaultValue, domainLength) {
  4351. var p = typeof padding === 'number' ? padding : padding[key];
  4352. if (!isValue(p)) {
  4353. return defaultValue;
  4354. }
  4355. if (padding.unit === 'ratio') {
  4356. return padding[key] * domainLength;
  4357. }
  4358. // assume padding is pixels if unit is not specified
  4359. return this.convertPixelsToAxisPadding(p, domainLength);
  4360. };
  4361. Axis.prototype.convertPixelsToAxisPadding = function convertPixelsToAxisPadding(pixels, domainLength) {
  4362. var $$ = this.owner,
  4363. length = $$.config.axis_rotated ? $$.width : $$.height;
  4364. return domainLength * (pixels / length);
  4365. };
  4366. Axis.prototype.generateTickValues = function generateTickValues(values, tickCount, forTimeSeries) {
  4367. var tickValues = values, targetCount, start, end, count, interval, i, tickValue;
  4368. if (tickCount) {
  4369. targetCount = isFunction(tickCount) ? tickCount() : tickCount;
  4370. // compute ticks according to tickCount
  4371. if (targetCount === 1) {
  4372. tickValues = [values[0]];
  4373. } else if (targetCount === 2) {
  4374. tickValues = [values[0], values[values.length - 1]];
  4375. } else if (targetCount > 2) {
  4376. count = targetCount - 2;
  4377. start = values[0];
  4378. end = values[values.length - 1];
  4379. interval = (end - start) / (count + 1);
  4380. // re-construct unique values
  4381. tickValues = [start];
  4382. for (i = 0; i < count; i++) {
  4383. tickValue = +start + interval * (i + 1);
  4384. tickValues.push(forTimeSeries ? new Date(tickValue) : tickValue);
  4385. }
  4386. tickValues.push(end);
  4387. }
  4388. }
  4389. if (!forTimeSeries) { tickValues = tickValues.sort(function (a, b) { return a - b; }); }
  4390. return tickValues;
  4391. };
  4392. Axis.prototype.generateTransitions = function generateTransitions(duration) {
  4393. var $$ = this.owner, axes = $$.axes;
  4394. return {
  4395. axisX: duration ? axes.x.transition().duration(duration) : axes.x,
  4396. axisY: duration ? axes.y.transition().duration(duration) : axes.y,
  4397. axisY2: duration ? axes.y2.transition().duration(duration) : axes.y2,
  4398. axisSubX: duration ? axes.subx.transition().duration(duration) : axes.subx
  4399. };
  4400. };
  4401. Axis.prototype.redraw = function redraw(transitions, isHidden) {
  4402. var $$ = this.owner;
  4403. $$.axes.x.style("opacity", isHidden ? 0 : 1);
  4404. $$.axes.y.style("opacity", isHidden ? 0 : 1);
  4405. $$.axes.y2.style("opacity", isHidden ? 0 : 1);
  4406. $$.axes.subx.style("opacity", isHidden ? 0 : 1);
  4407. transitions.axisX.call($$.xAxis);
  4408. transitions.axisY.call($$.yAxis);
  4409. transitions.axisY2.call($$.y2Axis);
  4410. transitions.axisSubX.call($$.subXAxis);
  4411. };
  4412. c3_chart_internal_fn.getClipPath = function (id) {
  4413. var isIE9 = window.navigator.appVersion.toLowerCase().indexOf("msie 9.") >= 0;
  4414. return "url(" + (isIE9 ? "" : document.URL.split('#')[0]) + "#" + id + ")";
  4415. };
  4416. c3_chart_internal_fn.appendClip = function (parent, id) {
  4417. return parent.append("clipPath").attr("id", id).append("rect");
  4418. };
  4419. c3_chart_internal_fn.getAxisClipX = function (forHorizontal) {
  4420. // axis line width + padding for left
  4421. var left = Math.max(30, this.margin.left);
  4422. return forHorizontal ? -(1 + left) : -(left - 1);
  4423. };
  4424. c3_chart_internal_fn.getAxisClipY = function (forHorizontal) {
  4425. return forHorizontal ? -20 : -this.margin.top;
  4426. };
  4427. c3_chart_internal_fn.getXAxisClipX = function () {
  4428. var $$ = this;
  4429. return $$.getAxisClipX(!$$.config.axis_rotated);
  4430. };
  4431. c3_chart_internal_fn.getXAxisClipY = function () {
  4432. var $$ = this;
  4433. return $$.getAxisClipY(!$$.config.axis_rotated);
  4434. };
  4435. c3_chart_internal_fn.getYAxisClipX = function () {
  4436. var $$ = this;
  4437. return $$.config.axis_y_inner ? -1 : $$.getAxisClipX($$.config.axis_rotated);
  4438. };
  4439. c3_chart_internal_fn.getYAxisClipY = function () {
  4440. var $$ = this;
  4441. return $$.getAxisClipY($$.config.axis_rotated);
  4442. };
  4443. c3_chart_internal_fn.getAxisClipWidth = function (forHorizontal) {
  4444. var $$ = this,
  4445. left = Math.max(30, $$.margin.left),
  4446. right = Math.max(30, $$.margin.right);
  4447. // width + axis line width + padding for left/right
  4448. return forHorizontal ? $$.width + 2 + left + right : $$.margin.left + 20;
  4449. };
  4450. c3_chart_internal_fn.getAxisClipHeight = function (forHorizontal) {
  4451. // less than 20 is not enough to show the axis label 'outer' without legend
  4452. return (forHorizontal ? this.margin.bottom : (this.margin.top + this.height)) + 20;
  4453. };
  4454. c3_chart_internal_fn.getXAxisClipWidth = function () {
  4455. var $$ = this;
  4456. return $$.getAxisClipWidth(!$$.config.axis_rotated);
  4457. };
  4458. c3_chart_internal_fn.getXAxisClipHeight = function () {
  4459. var $$ = this;
  4460. return $$.getAxisClipHeight(!$$.config.axis_rotated);
  4461. };
  4462. c3_chart_internal_fn.getYAxisClipWidth = function () {
  4463. var $$ = this;
  4464. return $$.getAxisClipWidth($$.config.axis_rotated) + ($$.config.axis_y_inner ? 20 : 0);
  4465. };
  4466. c3_chart_internal_fn.getYAxisClipHeight = function () {
  4467. var $$ = this;
  4468. return $$.getAxisClipHeight($$.config.axis_rotated);
  4469. };
  4470. c3_chart_internal_fn.initPie = function () {
  4471. var $$ = this, d3 = $$.d3, config = $$.config;
  4472. $$.pie = d3.layout.pie().value(function (d) {
  4473. return d.values.reduce(function (a, b) { return a + b.value; }, 0);
  4474. });
  4475. if (!config.data_order) {
  4476. $$.pie.sort(null);
  4477. }
  4478. };
  4479. c3_chart_internal_fn.updateRadius = function () {
  4480. var $$ = this, config = $$.config,
  4481. w = config.gauge_width || config.donut_width;
  4482. $$.radiusExpanded = Math.min($$.arcWidth, $$.arcHeight) / 2;
  4483. $$.radius = $$.radiusExpanded * 0.95;
  4484. $$.innerRadiusRatio = w ? ($$.radius - w) / $$.radius : 0.6;
  4485. $$.innerRadius = $$.hasType('donut') || $$.hasType('gauge') ? $$.radius * $$.innerRadiusRatio : 0;
  4486. };
  4487. c3_chart_internal_fn.updateArc = function () {
  4488. var $$ = this;
  4489. $$.svgArc = $$.getSvgArc();
  4490. $$.svgArcExpanded = $$.getSvgArcExpanded();
  4491. $$.svgArcExpandedSub = $$.getSvgArcExpanded(0.98);
  4492. };
  4493. c3_chart_internal_fn.updateAngle = function (d) {
  4494. var $$ = this, config = $$.config,
  4495. found = false, index = 0,
  4496. gMin, gMax, gTic, gValue;
  4497. if (!config) {
  4498. return null;
  4499. }
  4500. $$.pie($$.filterTargetsToShow($$.data.targets)).forEach(function (t) {
  4501. if (! found && t.data.id === d.data.id) {
  4502. found = true;
  4503. d = t;
  4504. d.index = index;
  4505. }
  4506. index++;
  4507. });
  4508. if (isNaN(d.startAngle)) {
  4509. d.startAngle = 0;
  4510. }
  4511. if (isNaN(d.endAngle)) {
  4512. d.endAngle = d.startAngle;
  4513. }
  4514. if ($$.isGaugeType(d.data)) {
  4515. gMin = config.gauge_min;
  4516. gMax = config.gauge_max;
  4517. gTic = (Math.PI) / (gMax - gMin);
  4518. gValue = d.value < gMin ? 0 : d.value < gMax ? d.value - gMin : (gMax - gMin);
  4519. d.startAngle = -1 * (Math.PI / 2);
  4520. d.endAngle = d.startAngle + gTic * gValue;
  4521. }
  4522. return found ? d : null;
  4523. };
  4524. c3_chart_internal_fn.getSvgArc = function () {
  4525. var $$ = this,
  4526. arc = $$.d3.svg.arc().outerRadius($$.radius).innerRadius($$.innerRadius),
  4527. newArc = function (d, withoutUpdate) {
  4528. var updated;
  4529. if (withoutUpdate) { return arc(d); } // for interpolate
  4530. updated = $$.updateAngle(d);
  4531. return updated ? arc(updated) : "M 0 0";
  4532. };
  4533. // TODO: extends all function
  4534. newArc.centroid = arc.centroid;
  4535. return newArc;
  4536. };
  4537. c3_chart_internal_fn.getSvgArcExpanded = function (rate) {
  4538. var $$ = this,
  4539. arc = $$.d3.svg.arc().outerRadius($$.radiusExpanded * (rate ? rate : 1)).innerRadius($$.innerRadius);
  4540. return function (d) {
  4541. var updated = $$.updateAngle(d);
  4542. return updated ? arc(updated) : "M 0 0";
  4543. };
  4544. };
  4545. c3_chart_internal_fn.getArc = function (d, withoutUpdate, force) {
  4546. return force || this.isArcType(d.data) ? this.svgArc(d, withoutUpdate) : "M 0 0";
  4547. };
  4548. c3_chart_internal_fn.transformForArcLabel = function (d) {
  4549. var $$ = this,
  4550. updated = $$.updateAngle(d), c, x, y, h, ratio, translate = "";
  4551. if (updated && !$$.hasType('gauge')) {
  4552. c = this.svgArc.centroid(updated);
  4553. x = isNaN(c[0]) ? 0 : c[0];
  4554. y = isNaN(c[1]) ? 0 : c[1];
  4555. h = Math.sqrt(x * x + y * y);
  4556. // TODO: ratio should be an option?
  4557. ratio = $$.radius && h ? (36 / $$.radius > 0.375 ? 1.175 - 36 / $$.radius : 0.8) * $$.radius / h : 0;
  4558. translate = "translate(" + (x * ratio) + ',' + (y * ratio) + ")";
  4559. }
  4560. return translate;
  4561. };
  4562. c3_chart_internal_fn.getArcRatio = function (d) {
  4563. var $$ = this,
  4564. whole = $$.hasType('gauge') ? Math.PI : (Math.PI * 2);
  4565. return d ? (d.endAngle - d.startAngle) / whole : null;
  4566. };
  4567. c3_chart_internal_fn.convertToArcData = function (d) {
  4568. return this.addName({
  4569. id: d.data.id,
  4570. value: d.value,
  4571. ratio: this.getArcRatio(d),
  4572. index: d.index
  4573. });
  4574. };
  4575. c3_chart_internal_fn.textForArcLabel = function (d) {
  4576. var $$ = this,
  4577. updated, value, ratio, id, format;
  4578. if (! $$.shouldShowArcLabel()) { return ""; }
  4579. updated = $$.updateAngle(d);
  4580. value = updated ? updated.value : null;
  4581. ratio = $$.getArcRatio(updated);
  4582. id = d.data.id;
  4583. if (! $$.hasType('gauge') && ! $$.meetsArcLabelThreshold(ratio)) { return ""; }
  4584. format = $$.getArcLabelFormat();
  4585. return format ? format(value, ratio, id) : $$.defaultArcValueFormat(value, ratio);
  4586. };
  4587. c3_chart_internal_fn.expandArc = function (targetIds) {
  4588. var $$ = this, interval;
  4589. // MEMO: avoid to cancel transition
  4590. if ($$.transiting) {
  4591. interval = window.setInterval(function () {
  4592. if (!$$.transiting) {
  4593. window.clearInterval(interval);
  4594. if ($$.legend.selectAll('.c3-legend-item-focused').size() > 0) {
  4595. $$.expandArc(targetIds);
  4596. }
  4597. }
  4598. }, 10);
  4599. return;
  4600. }
  4601. targetIds = $$.mapToTargetIds(targetIds);
  4602. $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).each(function (d) {
  4603. if (! $$.shouldExpand(d.data.id)) { return; }
  4604. $$.d3.select(this).selectAll('path')
  4605. .transition().duration($$.expandDuration(d.data.id))
  4606. .attr("d", $$.svgArcExpanded)
  4607. .transition().duration($$.expandDuration(d.data.id) * 2)
  4608. .attr("d", $$.svgArcExpandedSub)
  4609. .each(function (d) {
  4610. if ($$.isDonutType(d.data)) {
  4611. // callback here
  4612. }
  4613. });
  4614. });
  4615. };
  4616. c3_chart_internal_fn.unexpandArc = function (targetIds) {
  4617. var $$ = this;
  4618. if ($$.transiting) { return; }
  4619. targetIds = $$.mapToTargetIds(targetIds);
  4620. $$.svg.selectAll($$.selectorTargets(targetIds, '.' + CLASS.chartArc)).selectAll('path')
  4621. .transition().duration(function(d) {
  4622. return $$.expandDuration(d.data.id);
  4623. })
  4624. .attr("d", $$.svgArc);
  4625. $$.svg.selectAll('.' + CLASS.arc)
  4626. .style("opacity", 1);
  4627. };
  4628. c3_chart_internal_fn.expandDuration = function (id) {
  4629. var $$ = this, config = $$.config;
  4630. if ($$.isDonutType(id)) {
  4631. return config.donut_expand_duration;
  4632. } else if ($$.isGaugeType(id)) {
  4633. return config.gauge_expand_duration;
  4634. } else if ($$.isPieType(id)) {
  4635. return config.pie_expand_duration;
  4636. } else {
  4637. return 50;
  4638. }
  4639. };
  4640. c3_chart_internal_fn.shouldExpand = function (id) {
  4641. var $$ = this, config = $$.config;
  4642. return ($$.isDonutType(id) && config.donut_expand) ||
  4643. ($$.isGaugeType(id) && config.gauge_expand) ||
  4644. ($$.isPieType(id) && config.pie_expand);
  4645. };
  4646. c3_chart_internal_fn.shouldShowArcLabel = function () {
  4647. var $$ = this, config = $$.config, shouldShow = true;
  4648. if ($$.hasType('donut')) {
  4649. shouldShow = config.donut_label_show;
  4650. } else if ($$.hasType('pie')) {
  4651. shouldShow = config.pie_label_show;
  4652. }
  4653. // when gauge, always true
  4654. return shouldShow;
  4655. };
  4656. c3_chart_internal_fn.meetsArcLabelThreshold = function (ratio) {
  4657. var $$ = this, config = $$.config,
  4658. threshold = $$.hasType('donut') ? config.donut_label_threshold : config.pie_label_threshold;
  4659. return ratio >= threshold;
  4660. };
  4661. c3_chart_internal_fn.getArcLabelFormat = function () {
  4662. var $$ = this, config = $$.config,
  4663. format = config.pie_label_format;
  4664. if ($$.hasType('gauge')) {
  4665. format = config.gauge_label_format;
  4666. } else if ($$.hasType('donut')) {
  4667. format = config.donut_label_format;
  4668. }
  4669. return format;
  4670. };
  4671. c3_chart_internal_fn.getArcTitle = function () {
  4672. var $$ = this;
  4673. return $$.hasType('donut') ? $$.config.donut_title : "";
  4674. };
  4675. c3_chart_internal_fn.updateTargetsForArc = function (targets) {
  4676. var $$ = this, main = $$.main,
  4677. mainPieUpdate, mainPieEnter,
  4678. classChartArc = $$.classChartArc.bind($$),
  4679. classArcs = $$.classArcs.bind($$),
  4680. classFocus = $$.classFocus.bind($$);
  4681. mainPieUpdate = main.select('.' + CLASS.chartArcs).selectAll('.' + CLASS.chartArc)
  4682. .data($$.pie(targets))
  4683. .attr("class", function (d) { return classChartArc(d) + classFocus(d.data); });
  4684. mainPieEnter = mainPieUpdate.enter().append("g")
  4685. .attr("class", classChartArc);
  4686. mainPieEnter.append('g')
  4687. .attr('class', classArcs);
  4688. mainPieEnter.append("text")
  4689. .attr("dy", $$.hasType('gauge') ? "-.1em" : ".35em")
  4690. .style("opacity", 0)
  4691. .style("text-anchor", "middle")
  4692. .style("pointer-events", "none");
  4693. // MEMO: can not keep same color..., but not bad to update color in redraw
  4694. //mainPieUpdate.exit().remove();
  4695. };
  4696. c3_chart_internal_fn.initArc = function () {
  4697. var $$ = this;
  4698. $$.arcs = $$.main.select('.' + CLASS.chart).append("g")
  4699. .attr("class", CLASS.chartArcs)
  4700. .attr("transform", $$.getTranslate('arc'));
  4701. $$.arcs.append('text')
  4702. .attr('class', CLASS.chartArcsTitle)
  4703. .style("text-anchor", "middle")
  4704. .text($$.getArcTitle());
  4705. };
  4706. c3_chart_internal_fn.redrawArc = function (duration, durationForExit, withTransform) {
  4707. var $$ = this, d3 = $$.d3, config = $$.config, main = $$.main,
  4708. mainArc;
  4709. mainArc = main.selectAll('.' + CLASS.arcs).selectAll('.' + CLASS.arc)
  4710. .data($$.arcData.bind($$));
  4711. mainArc.enter().append('path')
  4712. .attr("class", $$.classArc.bind($$))
  4713. .style("fill", function (d) { return $$.color(d.data); })
  4714. .style("cursor", function (d) { return config.interaction_enabled && config.data_selection_isselectable(d) ? "pointer" : null; })
  4715. .style("opacity", 0)
  4716. .each(function (d) {
  4717. if ($$.isGaugeType(d.data)) {
  4718. d.startAngle = d.endAngle = -1 * (Math.PI / 2);
  4719. }
  4720. this._current = d;
  4721. });
  4722. mainArc
  4723. .attr("transform", function (d) { return !$$.isGaugeType(d.data) && withTransform ? "scale(0)" : ""; })
  4724. .style("opacity", function (d) { return d === this._current ? 0 : 1; })
  4725. .on('mouseover', config.interaction_enabled ? function (d) {
  4726. var updated, arcData;
  4727. if ($$.transiting) { // skip while transiting
  4728. return;
  4729. }
  4730. updated = $$.updateAngle(d);
  4731. if (updated) {
  4732. arcData = $$.convertToArcData(updated);
  4733. // transitions
  4734. $$.expandArc(updated.data.id);
  4735. $$.api.focus(updated.data.id);
  4736. $$.toggleFocusLegend(updated.data.id, true);
  4737. $$.config.data_onmouseover(arcData, this);
  4738. }
  4739. } : null)
  4740. .on('mousemove', config.interaction_enabled ? function (d) {
  4741. var updated = $$.updateAngle(d), arcData, selectedData;
  4742. if (updated) {
  4743. arcData = $$.convertToArcData(updated),
  4744. selectedData = [arcData];
  4745. $$.showTooltip(selectedData, this);
  4746. }
  4747. } : null)
  4748. .on('mouseout', config.interaction_enabled ? function (d) {
  4749. var updated, arcData;
  4750. if ($$.transiting) { // skip while transiting
  4751. return;
  4752. }
  4753. updated = $$.updateAngle(d);
  4754. if (updated) {
  4755. arcData = $$.convertToArcData(updated);
  4756. // transitions
  4757. $$.unexpandArc(updated.data.id);
  4758. $$.api.revert();
  4759. $$.revertLegend();
  4760. $$.hideTooltip();
  4761. $$.config.data_onmouseout(arcData, this);
  4762. }
  4763. } : null)
  4764. .on('click', config.interaction_enabled ? function (d, i) {
  4765. var updated = $$.updateAngle(d), arcData;
  4766. if (updated) {
  4767. arcData = $$.convertToArcData(updated);
  4768. if ($$.toggleShape) {
  4769. $$.toggleShape(this, arcData, i);
  4770. }
  4771. $$.config.data_onclick.call($$.api, arcData, this);
  4772. }
  4773. } : null)
  4774. .each(function () { $$.transiting = true; })
  4775. .transition().duration(duration)
  4776. .attrTween("d", function (d) {
  4777. var updated = $$.updateAngle(d), interpolate;
  4778. if (! updated) {
  4779. return function () { return "M 0 0"; };
  4780. }
  4781. // if (this._current === d) {
  4782. // this._current = {
  4783. // startAngle: Math.PI*2,
  4784. // endAngle: Math.PI*2,
  4785. // };
  4786. // }
  4787. if (isNaN(this._current.startAngle)) {
  4788. this._current.startAngle = 0;
  4789. }
  4790. if (isNaN(this._current.endAngle)) {
  4791. this._current.endAngle = this._current.startAngle;
  4792. }
  4793. interpolate = d3.interpolate(this._current, updated);
  4794. this._current = interpolate(0);
  4795. return function (t) {
  4796. var interpolated = interpolate(t);
  4797. interpolated.data = d.data; // data.id will be updated by interporator
  4798. return $$.getArc(interpolated, true);
  4799. };
  4800. })
  4801. .attr("transform", withTransform ? "scale(1)" : "")
  4802. .style("fill", function (d) {
  4803. return $$.levelColor ? $$.levelColor(d.data.values[0].value) : $$.color(d.data.id);
  4804. }) // Where gauge reading color would receive customization.
  4805. .style("opacity", 1)
  4806. .call($$.endall, function () {
  4807. $$.transiting = false;
  4808. });
  4809. mainArc.exit().transition().duration(durationForExit)
  4810. .style('opacity', 0)
  4811. .remove();
  4812. main.selectAll('.' + CLASS.chartArc).select('text')
  4813. .style("opacity", 0)
  4814. .attr('class', function (d) { return $$.isGaugeType(d.data) ? CLASS.gaugeValue : ''; })
  4815. .text($$.textForArcLabel.bind($$))
  4816. .attr("transform", $$.transformForArcLabel.bind($$))
  4817. .style('font-size', function (d) { return $$.isGaugeType(d.data) ? Math.round($$.radius / 5) + 'px' : ''; })
  4818. .transition().duration(duration)
  4819. .style("opacity", function (d) { return $$.isTargetToShow(d.data.id) && $$.isArcType(d.data) ? 1 : 0; });
  4820. main.select('.' + CLASS.chartArcsTitle)
  4821. .style("opacity", $$.hasType('donut') || $$.hasType('gauge') ? 1 : 0);
  4822. if ($$.hasType('gauge')) {
  4823. $$.arcs.select('.' + CLASS.chartArcsBackground)
  4824. .attr("d", function () {
  4825. var d = {
  4826. data: [{value: config.gauge_max}],
  4827. startAngle: -1 * (Math.PI / 2),
  4828. endAngle: Math.PI / 2
  4829. };
  4830. return $$.getArc(d, true, true);
  4831. });
  4832. $$.arcs.select('.' + CLASS.chartArcsGaugeUnit)
  4833. .attr("dy", ".75em")
  4834. .text(config.gauge_label_show ? config.gauge_units : '');
  4835. $$.arcs.select('.' + CLASS.chartArcsGaugeMin)
  4836. .attr("dx", -1 * ($$.innerRadius + (($$.radius - $$.innerRadius) / 2)) + "px")
  4837. .attr("dy", "1.2em")
  4838. .text(config.gauge_label_show ? config.gauge_min : '');
  4839. $$.arcs.select('.' + CLASS.chartArcsGaugeMax)
  4840. .attr("dx", $$.innerRadius + (($$.radius - $$.innerRadius) / 2) + "px")
  4841. .attr("dy", "1.2em")
  4842. .text(config.gauge_label_show ? config.gauge_max : '');
  4843. }
  4844. };
  4845. c3_chart_internal_fn.initGauge = function () {
  4846. var arcs = this.arcs;
  4847. if (this.hasType('gauge')) {
  4848. arcs.append('path')
  4849. .attr("class", CLASS.chartArcsBackground);
  4850. arcs.append("text")
  4851. .attr("class", CLASS.chartArcsGaugeUnit)
  4852. .style("text-anchor", "middle")
  4853. .style("pointer-events", "none");
  4854. arcs.append("text")
  4855. .attr("class", CLASS.chartArcsGaugeMin)
  4856. .style("text-anchor", "middle")
  4857. .style("pointer-events", "none");
  4858. arcs.append("text")
  4859. .attr("class", CLASS.chartArcsGaugeMax)
  4860. .style("text-anchor", "middle")
  4861. .style("pointer-events", "none");
  4862. }
  4863. };
  4864. c3_chart_internal_fn.getGaugeLabelHeight = function () {
  4865. return this.config.gauge_label_show ? 20 : 0;
  4866. };
  4867. c3_chart_internal_fn.initRegion = function () {
  4868. var $$ = this;
  4869. $$.region = $$.main.append('g')
  4870. .attr("clip-path", $$.clipPath)
  4871. .attr("class", CLASS.regions);
  4872. };
  4873. c3_chart_internal_fn.updateRegion = function (duration) {
  4874. var $$ = this, config = $$.config;
  4875. // hide if arc type
  4876. $$.region.style('visibility', $$.hasArcType() ? 'hidden' : 'visible');
  4877. $$.mainRegion = $$.main.select('.' + CLASS.regions).selectAll('.' + CLASS.region)
  4878. .data(config.regions);
  4879. $$.mainRegion.enter().append('g')
  4880. .attr('class', $$.classRegion.bind($$))
  4881. .append('rect')
  4882. .style("fill-opacity", 0);
  4883. $$.mainRegion.exit().transition().duration(duration)
  4884. .style("opacity", 0)
  4885. .remove();
  4886. };
  4887. c3_chart_internal_fn.redrawRegion = function (withTransition) {
  4888. var $$ = this,
  4889. regions = $$.mainRegion.selectAll('rect'),
  4890. x = $$.regionX.bind($$),
  4891. y = $$.regionY.bind($$),
  4892. w = $$.regionWidth.bind($$),
  4893. h = $$.regionHeight.bind($$);
  4894. return [
  4895. (withTransition ? regions.transition() : regions)
  4896. .attr("x", x)
  4897. .attr("y", y)
  4898. .attr("width", w)
  4899. .attr("height", h)
  4900. .style("fill-opacity", function (d) { return isValue(d.opacity) ? d.opacity : 0.1; })
  4901. ];
  4902. };
  4903. c3_chart_internal_fn.regionX = function (d) {
  4904. var $$ = this, config = $$.config,
  4905. xPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
  4906. if (d.axis === 'y' || d.axis === 'y2') {
  4907. xPos = config.axis_rotated ? ('start' in d ? yScale(d.start) : 0) : 0;
  4908. } else {
  4909. xPos = config.axis_rotated ? 0 : ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0);
  4910. }
  4911. return xPos;
  4912. };
  4913. c3_chart_internal_fn.regionY = function (d) {
  4914. var $$ = this, config = $$.config,
  4915. yPos, yScale = d.axis === 'y' ? $$.y : $$.y2;
  4916. if (d.axis === 'y' || d.axis === 'y2') {
  4917. yPos = config.axis_rotated ? 0 : ('end' in d ? yScale(d.end) : 0);
  4918. } else {
  4919. yPos = config.axis_rotated ? ('start' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.start) : d.start) : 0) : 0;
  4920. }
  4921. return yPos;
  4922. };
  4923. c3_chart_internal_fn.regionWidth = function (d) {
  4924. var $$ = this, config = $$.config,
  4925. start = $$.regionX(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
  4926. if (d.axis === 'y' || d.axis === 'y2') {
  4927. end = config.axis_rotated ? ('end' in d ? yScale(d.end) : $$.width) : $$.width;
  4928. } else {
  4929. end = config.axis_rotated ? $$.width : ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.width);
  4930. }
  4931. return end < start ? 0 : end - start;
  4932. };
  4933. c3_chart_internal_fn.regionHeight = function (d) {
  4934. var $$ = this, config = $$.config,
  4935. start = this.regionY(d), end, yScale = d.axis === 'y' ? $$.y : $$.y2;
  4936. if (d.axis === 'y' || d.axis === 'y2') {
  4937. end = config.axis_rotated ? $$.height : ('start' in d ? yScale(d.start) : $$.height);
  4938. } else {
  4939. end = config.axis_rotated ? ('end' in d ? $$.x($$.isTimeSeries() ? $$.parseDate(d.end) : d.end) : $$.height) : $$.height;
  4940. }
  4941. return end < start ? 0 : end - start;
  4942. };
  4943. c3_chart_internal_fn.isRegionOnX = function (d) {
  4944. return !d.axis || d.axis === 'x';
  4945. };
  4946. c3_chart_internal_fn.drag = function (mouse) {
  4947. var $$ = this, config = $$.config, main = $$.main, d3 = $$.d3;
  4948. var sx, sy, mx, my, minX, maxX, minY, maxY;
  4949. if ($$.hasArcType()) { return; }
  4950. if (! config.data_selection_enabled) { return; } // do nothing if not selectable
  4951. if (config.zoom_enabled && ! $$.zoom.altDomain) { return; } // skip if zoomable because of conflict drag dehavior
  4952. if (!config.data_selection_multiple) { return; } // skip when single selection because drag is used for multiple selection
  4953. sx = $$.dragStart[0];
  4954. sy = $$.dragStart[1];
  4955. mx = mouse[0];
  4956. my = mouse[1];
  4957. minX = Math.min(sx, mx);
  4958. maxX = Math.max(sx, mx);
  4959. minY = (config.data_selection_grouped) ? $$.margin.top : Math.min(sy, my);
  4960. maxY = (config.data_selection_grouped) ? $$.height : Math.max(sy, my);
  4961. main.select('.' + CLASS.dragarea)
  4962. .attr('x', minX)
  4963. .attr('y', minY)
  4964. .attr('width', maxX - minX)
  4965. .attr('height', maxY - minY);
  4966. // TODO: binary search when multiple xs
  4967. main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape)
  4968. .filter(function (d) { return config.data_selection_isselectable(d); })
  4969. .each(function (d, i) {
  4970. var shape = d3.select(this),
  4971. isSelected = shape.classed(CLASS.SELECTED),
  4972. isIncluded = shape.classed(CLASS.INCLUDED),
  4973. _x, _y, _w, _h, toggle, isWithin = false, box;
  4974. if (shape.classed(CLASS.circle)) {
  4975. _x = shape.attr("cx") * 1;
  4976. _y = shape.attr("cy") * 1;
  4977. toggle = $$.togglePoint;
  4978. isWithin = minX < _x && _x < maxX && minY < _y && _y < maxY;
  4979. }
  4980. else if (shape.classed(CLASS.bar)) {
  4981. box = getPathBox(this);
  4982. _x = box.x;
  4983. _y = box.y;
  4984. _w = box.width;
  4985. _h = box.height;
  4986. toggle = $$.togglePath;
  4987. isWithin = !(maxX < _x || _x + _w < minX) && !(maxY < _y || _y + _h < minY);
  4988. } else {
  4989. // line/area selection not supported yet
  4990. return;
  4991. }
  4992. if (isWithin ^ isIncluded) {
  4993. shape.classed(CLASS.INCLUDED, !isIncluded);
  4994. // TODO: included/unincluded callback here
  4995. shape.classed(CLASS.SELECTED, !isSelected);
  4996. toggle.call($$, !isSelected, shape, d, i);
  4997. }
  4998. });
  4999. };
  5000. c3_chart_internal_fn.dragstart = function (mouse) {
  5001. var $$ = this, config = $$.config;
  5002. if ($$.hasArcType()) { return; }
  5003. if (! config.data_selection_enabled) { return; } // do nothing if not selectable
  5004. $$.dragStart = mouse;
  5005. $$.main.select('.' + CLASS.chart).append('rect')
  5006. .attr('class', CLASS.dragarea)
  5007. .style('opacity', 0.1);
  5008. $$.dragging = true;
  5009. };
  5010. c3_chart_internal_fn.dragend = function () {
  5011. var $$ = this, config = $$.config;
  5012. if ($$.hasArcType()) { return; }
  5013. if (! config.data_selection_enabled) { return; } // do nothing if not selectable
  5014. $$.main.select('.' + CLASS.dragarea)
  5015. .transition().duration(100)
  5016. .style('opacity', 0)
  5017. .remove();
  5018. $$.main.selectAll('.' + CLASS.shape)
  5019. .classed(CLASS.INCLUDED, false);
  5020. $$.dragging = false;
  5021. };
  5022. c3_chart_internal_fn.selectPoint = function (target, d, i) {
  5023. var $$ = this, config = $$.config,
  5024. cx = (config.axis_rotated ? $$.circleY : $$.circleX).bind($$),
  5025. cy = (config.axis_rotated ? $$.circleX : $$.circleY).bind($$),
  5026. r = $$.pointSelectR.bind($$);
  5027. config.data_onselected.call($$.api, d, target.node());
  5028. // add selected-circle on low layer g
  5029. $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
  5030. .data([d])
  5031. .enter().append('circle')
  5032. .attr("class", function () { return $$.generateClass(CLASS.selectedCircle, i); })
  5033. .attr("cx", cx)
  5034. .attr("cy", cy)
  5035. .attr("stroke", function () { return $$.color(d); })
  5036. .attr("r", function (d) { return $$.pointSelectR(d) * 1.4; })
  5037. .transition().duration(100)
  5038. .attr("r", r);
  5039. };
  5040. c3_chart_internal_fn.unselectPoint = function (target, d, i) {
  5041. var $$ = this;
  5042. $$.config.data_onunselected.call($$.api, d, target.node());
  5043. // remove selected-circle from low layer g
  5044. $$.main.select('.' + CLASS.selectedCircles + $$.getTargetSelectorSuffix(d.id)).selectAll('.' + CLASS.selectedCircle + '-' + i)
  5045. .transition().duration(100).attr('r', 0)
  5046. .remove();
  5047. };
  5048. c3_chart_internal_fn.togglePoint = function (selected, target, d, i) {
  5049. selected ? this.selectPoint(target, d, i) : this.unselectPoint(target, d, i);
  5050. };
  5051. c3_chart_internal_fn.selectPath = function (target, d) {
  5052. var $$ = this;
  5053. $$.config.data_onselected.call($$, d, target.node());
  5054. target.transition().duration(100)
  5055. .style("fill", function () { return $$.d3.rgb($$.color(d)).brighter(0.75); });
  5056. };
  5057. c3_chart_internal_fn.unselectPath = function (target, d) {
  5058. var $$ = this;
  5059. $$.config.data_onunselected.call($$, d, target.node());
  5060. target.transition().duration(100)
  5061. .style("fill", function () { return $$.color(d); });
  5062. };
  5063. c3_chart_internal_fn.togglePath = function (selected, target, d, i) {
  5064. selected ? this.selectPath(target, d, i) : this.unselectPath(target, d, i);
  5065. };
  5066. c3_chart_internal_fn.getToggle = function (that, d) {
  5067. var $$ = this, toggle;
  5068. if (that.nodeName === 'circle') {
  5069. if ($$.isStepType(d)) {
  5070. // circle is hidden in step chart, so treat as within the click area
  5071. toggle = function () {}; // TODO: how to select step chart?
  5072. } else {
  5073. toggle = $$.togglePoint;
  5074. }
  5075. }
  5076. else if (that.nodeName === 'path') {
  5077. toggle = $$.togglePath;
  5078. }
  5079. return toggle;
  5080. };
  5081. c3_chart_internal_fn.toggleShape = function (that, d, i) {
  5082. var $$ = this, d3 = $$.d3, config = $$.config,
  5083. shape = d3.select(that), isSelected = shape.classed(CLASS.SELECTED),
  5084. toggle = $$.getToggle(that, d).bind($$);
  5085. if (config.data_selection_enabled && config.data_selection_isselectable(d)) {
  5086. if (!config.data_selection_multiple) {
  5087. $$.main.selectAll('.' + CLASS.shapes + (config.data_selection_grouped ? $$.getTargetSelectorSuffix(d.id) : "")).selectAll('.' + CLASS.shape).each(function (d, i) {
  5088. var shape = d3.select(this);
  5089. if (shape.classed(CLASS.SELECTED)) { toggle(false, shape.classed(CLASS.SELECTED, false), d, i); }
  5090. });
  5091. }
  5092. shape.classed(CLASS.SELECTED, !isSelected);
  5093. toggle(!isSelected, shape, d, i);
  5094. }
  5095. };
  5096. c3_chart_internal_fn.initBrush = function () {
  5097. var $$ = this, d3 = $$.d3;
  5098. $$.brush = d3.svg.brush().on("brush", function () { $$.redrawForBrush(); });
  5099. $$.brush.update = function () {
  5100. if ($$.context) { $$.context.select('.' + CLASS.brush).call(this); }
  5101. return this;
  5102. };
  5103. $$.brush.scale = function (scale) {
  5104. return $$.config.axis_rotated ? this.y(scale) : this.x(scale);
  5105. };
  5106. };
  5107. c3_chart_internal_fn.initSubchart = function () {
  5108. var $$ = this, config = $$.config,
  5109. context = $$.context = $$.svg.append("g").attr("transform", $$.getTranslate('context')),
  5110. visibility = config.subchart_show ? 'visible' : 'hidden';
  5111. context.style('visibility', visibility);
  5112. // Define g for chart area
  5113. context.append('g')
  5114. .attr("clip-path", $$.clipPathForSubchart)
  5115. .attr('class', CLASS.chart);
  5116. // Define g for bar chart area
  5117. context.select('.' + CLASS.chart).append("g")
  5118. .attr("class", CLASS.chartBars);
  5119. // Define g for line chart area
  5120. context.select('.' + CLASS.chart).append("g")
  5121. .attr("class", CLASS.chartLines);
  5122. // Add extent rect for Brush
  5123. context.append("g")
  5124. .attr("clip-path", $$.clipPath)
  5125. .attr("class", CLASS.brush)
  5126. .call($$.brush);
  5127. // ATTENTION: This must be called AFTER chart added
  5128. // Add Axis
  5129. $$.axes.subx = context.append("g")
  5130. .attr("class", CLASS.axisX)
  5131. .attr("transform", $$.getTranslate('subx'))
  5132. .attr("clip-path", config.axis_rotated ? "" : $$.clipPathForXAxis)
  5133. .style("visibility", config.subchart_axis_x_show ? visibility : 'hidden');
  5134. };
  5135. c3_chart_internal_fn.updateTargetsForSubchart = function (targets) {
  5136. var $$ = this, context = $$.context, config = $$.config,
  5137. contextLineEnter, contextLineUpdate, contextBarEnter, contextBarUpdate,
  5138. classChartBar = $$.classChartBar.bind($$),
  5139. classBars = $$.classBars.bind($$),
  5140. classChartLine = $$.classChartLine.bind($$),
  5141. classLines = $$.classLines.bind($$),
  5142. classAreas = $$.classAreas.bind($$);
  5143. if (config.subchart_show) {
  5144. //-- Bar --//
  5145. contextBarUpdate = context.select('.' + CLASS.chartBars).selectAll('.' + CLASS.chartBar)
  5146. .data(targets)
  5147. .attr('class', classChartBar);
  5148. contextBarEnter = contextBarUpdate.enter().append('g')
  5149. .style('opacity', 0)
  5150. .attr('class', classChartBar);
  5151. // Bars for each data
  5152. contextBarEnter.append('g')
  5153. .attr("class", classBars);
  5154. //-- Line --//
  5155. contextLineUpdate = context.select('.' + CLASS.chartLines).selectAll('.' + CLASS.chartLine)
  5156. .data(targets)
  5157. .attr('class', classChartLine);
  5158. contextLineEnter = contextLineUpdate.enter().append('g')
  5159. .style('opacity', 0)
  5160. .attr('class', classChartLine);
  5161. // Lines for each data
  5162. contextLineEnter.append("g")
  5163. .attr("class", classLines);
  5164. // Area
  5165. contextLineEnter.append("g")
  5166. .attr("class", classAreas);
  5167. //-- Brush --//
  5168. context.selectAll('.' + CLASS.brush + ' rect')
  5169. .attr(config.axis_rotated ? "width" : "height", config.axis_rotated ? $$.width2 : $$.height2);
  5170. }
  5171. };
  5172. c3_chart_internal_fn.updateBarForSubchart = function (durationForExit) {
  5173. var $$ = this;
  5174. $$.contextBar = $$.context.selectAll('.' + CLASS.bars).selectAll('.' + CLASS.bar)
  5175. .data($$.barData.bind($$));
  5176. $$.contextBar.enter().append('path')
  5177. .attr("class", $$.classBar.bind($$))
  5178. .style("stroke", 'none')
  5179. .style("fill", $$.color);
  5180. $$.contextBar
  5181. .style("opacity", $$.initialOpacity.bind($$));
  5182. $$.contextBar.exit().transition().duration(durationForExit)
  5183. .style('opacity', 0)
  5184. .remove();
  5185. };
  5186. c3_chart_internal_fn.redrawBarForSubchart = function (drawBarOnSub, withTransition, duration) {
  5187. (withTransition ? this.contextBar.transition(Math.random().toString()).duration(duration) : this.contextBar)
  5188. .attr('d', drawBarOnSub)
  5189. .style('opacity', 1);
  5190. };
  5191. c3_chart_internal_fn.updateLineForSubchart = function (durationForExit) {
  5192. var $$ = this;
  5193. $$.contextLine = $$.context.selectAll('.' + CLASS.lines).selectAll('.' + CLASS.line)
  5194. .data($$.lineData.bind($$));
  5195. $$.contextLine.enter().append('path')
  5196. .attr('class', $$.classLine.bind($$))
  5197. .style('stroke', $$.color);
  5198. $$.contextLine
  5199. .style("opacity", $$.initialOpacity.bind($$));
  5200. $$.contextLine.exit().transition().duration(durationForExit)
  5201. .style('opacity', 0)
  5202. .remove();
  5203. };
  5204. c3_chart_internal_fn.redrawLineForSubchart = function (drawLineOnSub, withTransition, duration) {
  5205. (withTransition ? this.contextLine.transition(Math.random().toString()).duration(duration) : this.contextLine)
  5206. .attr("d", drawLineOnSub)
  5207. .style('opacity', 1);
  5208. };
  5209. c3_chart_internal_fn.updateAreaForSubchart = function (durationForExit) {
  5210. var $$ = this, d3 = $$.d3;
  5211. $$.contextArea = $$.context.selectAll('.' + CLASS.areas).selectAll('.' + CLASS.area)
  5212. .data($$.lineData.bind($$));
  5213. $$.contextArea.enter().append('path')
  5214. .attr("class", $$.classArea.bind($$))
  5215. .style("fill", $$.color)
  5216. .style("opacity", function () { $$.orgAreaOpacity = +d3.select(this).style('opacity'); return 0; });
  5217. $$.contextArea
  5218. .style("opacity", 0);
  5219. $$.contextArea.exit().transition().duration(durationForExit)
  5220. .style('opacity', 0)
  5221. .remove();
  5222. };
  5223. c3_chart_internal_fn.redrawAreaForSubchart = function (drawAreaOnSub, withTransition, duration) {
  5224. (withTransition ? this.contextArea.transition(Math.random().toString()).duration(duration) : this.contextArea)
  5225. .attr("d", drawAreaOnSub)
  5226. .style("fill", this.color)
  5227. .style("opacity", this.orgAreaOpacity);
  5228. };
  5229. c3_chart_internal_fn.redrawSubchart = function (withSubchart, transitions, duration, durationForExit, areaIndices, barIndices, lineIndices) {
  5230. var $$ = this, d3 = $$.d3, config = $$.config,
  5231. drawAreaOnSub, drawBarOnSub, drawLineOnSub;
  5232. $$.context.style('visibility', config.subchart_show ? 'visible' : 'hidden');
  5233. // subchart
  5234. if (config.subchart_show) {
  5235. // reflect main chart to extent on subchart if zoomed
  5236. if (d3.event && d3.event.type === 'zoom') {
  5237. $$.brush.extent($$.x.orgDomain()).update();
  5238. }
  5239. // update subchart elements if needed
  5240. if (withSubchart) {
  5241. // extent rect
  5242. if (!$$.brush.empty()) {
  5243. $$.brush.extent($$.x.orgDomain()).update();
  5244. }
  5245. // setup drawer - MEMO: this must be called after axis updated
  5246. drawAreaOnSub = $$.generateDrawArea(areaIndices, true);
  5247. drawBarOnSub = $$.generateDrawBar(barIndices, true);
  5248. drawLineOnSub = $$.generateDrawLine(lineIndices, true);
  5249. $$.updateBarForSubchart(duration);
  5250. $$.updateLineForSubchart(duration);
  5251. $$.updateAreaForSubchart(duration);
  5252. $$.redrawBarForSubchart(drawBarOnSub, duration, duration);
  5253. $$.redrawLineForSubchart(drawLineOnSub, duration, duration);
  5254. $$.redrawAreaForSubchart(drawAreaOnSub, duration, duration);
  5255. }
  5256. }
  5257. };
  5258. c3_chart_internal_fn.redrawForBrush = function () {
  5259. var $$ = this, x = $$.x;
  5260. $$.redraw({
  5261. withTransition: false,
  5262. withY: $$.config.zoom_rescale,
  5263. withSubchart: false,
  5264. withUpdateXDomain: true,
  5265. withDimension: false
  5266. });
  5267. $$.config.subchart_onbrush.call($$.api, x.orgDomain());
  5268. };
  5269. c3_chart_internal_fn.transformContext = function (withTransition, transitions) {
  5270. var $$ = this, subXAxis;
  5271. if (transitions && transitions.axisSubX) {
  5272. subXAxis = transitions.axisSubX;
  5273. } else {
  5274. subXAxis = $$.context.select('.' + CLASS.axisX);
  5275. if (withTransition) { subXAxis = subXAxis.transition(); }
  5276. }
  5277. $$.context.attr("transform", $$.getTranslate('context'));
  5278. subXAxis.attr("transform", $$.getTranslate('subx'));
  5279. };
  5280. c3_chart_internal_fn.getDefaultExtent = function () {
  5281. var $$ = this, config = $$.config,
  5282. extent = isFunction(config.axis_x_extent) ? config.axis_x_extent($$.getXDomain($$.data.targets)) : config.axis_x_extent;
  5283. if ($$.isTimeSeries()) {
  5284. extent = [$$.parseDate(extent[0]), $$.parseDate(extent[1])];
  5285. }
  5286. return extent;
  5287. };
  5288. c3_chart_internal_fn.initZoom = function () {
  5289. var $$ = this, d3 = $$.d3, config = $$.config, startEvent;
  5290. $$.zoom = d3.behavior.zoom()
  5291. .on("zoomstart", function () {
  5292. startEvent = d3.event.sourceEvent;
  5293. $$.zoom.altDomain = d3.event.sourceEvent.altKey ? $$.x.orgDomain() : null;
  5294. config.zoom_onzoomstart.call($$.api, d3.event.sourceEvent);
  5295. })
  5296. .on("zoom", function () {
  5297. $$.redrawForZoom.call($$);
  5298. })
  5299. .on('zoomend', function () {
  5300. var event = d3.event.sourceEvent;
  5301. // if click, do nothing. otherwise, click interaction will be canceled.
  5302. if (event && startEvent.clientX === event.clientX && startEvent.clientY === event.clientY) {
  5303. return;
  5304. }
  5305. $$.redrawEventRect();
  5306. $$.updateZoom();
  5307. config.zoom_onzoomend.call($$.api, $$.x.orgDomain());
  5308. });
  5309. $$.zoom.scale = function (scale) {
  5310. return config.axis_rotated ? this.y(scale) : this.x(scale);
  5311. };
  5312. $$.zoom.orgScaleExtent = function () {
  5313. var extent = config.zoom_extent ? config.zoom_extent : [1, 10];
  5314. return [extent[0], Math.max($$.getMaxDataCount() / extent[1], extent[1])];
  5315. };
  5316. $$.zoom.updateScaleExtent = function () {
  5317. var ratio = diffDomain($$.x.orgDomain()) / diffDomain($$.getZoomDomain()),
  5318. extent = this.orgScaleExtent();
  5319. this.scaleExtent([extent[0] * ratio, extent[1] * ratio]);
  5320. return this;
  5321. };
  5322. };
  5323. c3_chart_internal_fn.getZoomDomain = function () {
  5324. var $$ = this, config = $$.config, d3 = $$.d3,
  5325. min = d3.min([$$.orgXDomain[0], config.zoom_x_min]),
  5326. max = d3.max([$$.orgXDomain[1], config.zoom_x_max]);
  5327. return [min, max];
  5328. };
  5329. c3_chart_internal_fn.updateZoom = function () {
  5330. var $$ = this, z = $$.config.zoom_enabled ? $$.zoom : function () {};
  5331. $$.main.select('.' + CLASS.zoomRect).call(z).on("dblclick.zoom", null);
  5332. $$.main.selectAll('.' + CLASS.eventRect).call(z).on("dblclick.zoom", null);
  5333. };
  5334. c3_chart_internal_fn.redrawForZoom = function () {
  5335. var $$ = this, d3 = $$.d3, config = $$.config, zoom = $$.zoom, x = $$.x;
  5336. if (!config.zoom_enabled) {
  5337. return;
  5338. }
  5339. if ($$.filterTargetsToShow($$.data.targets).length === 0) {
  5340. return;
  5341. }
  5342. if (d3.event.sourceEvent.type === 'mousemove' && zoom.altDomain) {
  5343. x.domain(zoom.altDomain);
  5344. zoom.scale(x).updateScaleExtent();
  5345. return;
  5346. }
  5347. if ($$.isCategorized() && x.orgDomain()[0] === $$.orgXDomain[0]) {
  5348. x.domain([$$.orgXDomain[0] - 1e-10, x.orgDomain()[1]]);
  5349. }
  5350. $$.redraw({
  5351. withTransition: false,
  5352. withY: config.zoom_rescale,
  5353. withSubchart: false,
  5354. withEventRect: false,
  5355. withDimension: false
  5356. });
  5357. if (d3.event.sourceEvent.type === 'mousemove') {
  5358. $$.cancelClick = true;
  5359. }
  5360. config.zoom_onzoom.call($$.api, x.orgDomain());
  5361. };
  5362. c3_chart_internal_fn.generateColor = function () {
  5363. var $$ = this, config = $$.config, d3 = $$.d3,
  5364. colors = config.data_colors,
  5365. pattern = notEmpty(config.color_pattern) ? config.color_pattern : d3.scale.category10().range(),
  5366. callback = config.data_color,
  5367. ids = [];
  5368. return function (d) {
  5369. var id = d.id || (d.data && d.data.id) || d, color;
  5370. // if callback function is provided
  5371. if (colors[id] instanceof Function) {
  5372. color = colors[id](d);
  5373. }
  5374. // if specified, choose that color
  5375. else if (colors[id]) {
  5376. color = colors[id];
  5377. }
  5378. // if not specified, choose from pattern
  5379. else {
  5380. if (ids.indexOf(id) < 0) { ids.push(id); }
  5381. color = pattern[ids.indexOf(id) % pattern.length];
  5382. colors[id] = color;
  5383. }
  5384. return callback instanceof Function ? callback(color, d) : color;
  5385. };
  5386. };
  5387. c3_chart_internal_fn.generateLevelColor = function () {
  5388. var $$ = this, config = $$.config,
  5389. colors = config.color_pattern,
  5390. threshold = config.color_threshold,
  5391. asValue = threshold.unit === 'value',
  5392. values = threshold.values && threshold.values.length ? threshold.values : [],
  5393. max = threshold.max || 100;
  5394. return notEmpty(config.color_threshold) ? function (value) {
  5395. var i, v, color = colors[colors.length - 1];
  5396. for (i = 0; i < values.length; i++) {
  5397. v = asValue ? value : (value * 100 / max);
  5398. if (v < values[i]) {
  5399. color = colors[i];
  5400. break;
  5401. }
  5402. }
  5403. return color;
  5404. } : null;
  5405. };
  5406. c3_chart_internal_fn.getYFormat = function (forArc) {
  5407. var $$ = this,
  5408. formatForY = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.yFormat,
  5409. formatForY2 = forArc && !$$.hasType('gauge') ? $$.defaultArcValueFormat : $$.y2Format;
  5410. return function (v, ratio, id) {
  5411. var format = $$.axis.getId(id) === 'y2' ? formatForY2 : formatForY;
  5412. return format.call($$, v, ratio);
  5413. };
  5414. };
  5415. c3_chart_internal_fn.yFormat = function (v) {
  5416. var $$ = this, config = $$.config,
  5417. format = config.axis_y_tick_format ? config.axis_y_tick_format : $$.defaultValueFormat;
  5418. return format(v);
  5419. };
  5420. c3_chart_internal_fn.y2Format = function (v) {
  5421. var $$ = this, config = $$.config,
  5422. format = config.axis_y2_tick_format ? config.axis_y2_tick_format : $$.defaultValueFormat;
  5423. return format(v);
  5424. };
  5425. c3_chart_internal_fn.defaultValueFormat = function (v) {
  5426. return isValue(v) ? +v : "";
  5427. };
  5428. c3_chart_internal_fn.defaultArcValueFormat = function (v, ratio) {
  5429. return (ratio * 100).toFixed(1) + '%';
  5430. };
  5431. c3_chart_internal_fn.dataLabelFormat = function (targetId) {
  5432. var $$ = this, data_labels = $$.config.data_labels,
  5433. format, defaultFormat = function (v) { return isValue(v) ? +v : ""; };
  5434. // find format according to axis id
  5435. if (typeof data_labels.format === 'function') {
  5436. format = data_labels.format;
  5437. } else if (typeof data_labels.format === 'object') {
  5438. if (data_labels.format[targetId]) {
  5439. format = data_labels.format[targetId] === true ? defaultFormat : data_labels.format[targetId];
  5440. } else {
  5441. format = function () { return ''; };
  5442. }
  5443. } else {
  5444. format = defaultFormat;
  5445. }
  5446. return format;
  5447. };
  5448. c3_chart_internal_fn.hasCaches = function (ids) {
  5449. for (var i = 0; i < ids.length; i++) {
  5450. if (! (ids[i] in this.cache)) { return false; }
  5451. }
  5452. return true;
  5453. };
  5454. c3_chart_internal_fn.addCache = function (id, target) {
  5455. this.cache[id] = this.cloneTarget(target);
  5456. };
  5457. c3_chart_internal_fn.getCaches = function (ids) {
  5458. var targets = [], i;
  5459. for (i = 0; i < ids.length; i++) {
  5460. if (ids[i] in this.cache) { targets.push(this.cloneTarget(this.cache[ids[i]])); }
  5461. }
  5462. return targets;
  5463. };
  5464. var CLASS = c3_chart_internal_fn.CLASS = {
  5465. target: 'c3-target',
  5466. chart: 'c3-chart',
  5467. chartLine: 'c3-chart-line',
  5468. chartLines: 'c3-chart-lines',
  5469. chartBar: 'c3-chart-bar',
  5470. chartBars: 'c3-chart-bars',
  5471. chartText: 'c3-chart-text',
  5472. chartTexts: 'c3-chart-texts',
  5473. chartArc: 'c3-chart-arc',
  5474. chartArcs: 'c3-chart-arcs',
  5475. chartArcsTitle: 'c3-chart-arcs-title',
  5476. chartArcsBackground: 'c3-chart-arcs-background',
  5477. chartArcsGaugeUnit: 'c3-chart-arcs-gauge-unit',
  5478. chartArcsGaugeMax: 'c3-chart-arcs-gauge-max',
  5479. chartArcsGaugeMin: 'c3-chart-arcs-gauge-min',
  5480. selectedCircle: 'c3-selected-circle',
  5481. selectedCircles: 'c3-selected-circles',
  5482. eventRect: 'c3-event-rect',
  5483. eventRects: 'c3-event-rects',
  5484. eventRectsSingle: 'c3-event-rects-single',
  5485. eventRectsMultiple: 'c3-event-rects-multiple',
  5486. zoomRect: 'c3-zoom-rect',
  5487. brush: 'c3-brush',
  5488. focused: 'c3-focused',
  5489. defocused: 'c3-defocused',
  5490. region: 'c3-region',
  5491. regions: 'c3-regions',
  5492. title: 'c3-title',
  5493. tooltipContainer: 'c3-tooltip-container',
  5494. tooltip: 'c3-tooltip',
  5495. tooltipName: 'c3-tooltip-name',
  5496. shape: 'c3-shape',
  5497. shapes: 'c3-shapes',
  5498. line: 'c3-line',
  5499. lines: 'c3-lines',
  5500. bar: 'c3-bar',
  5501. bars: 'c3-bars',
  5502. circle: 'c3-circle',
  5503. circles: 'c3-circles',
  5504. arc: 'c3-arc',
  5505. arcs: 'c3-arcs',
  5506. area: 'c3-area',
  5507. areas: 'c3-areas',
  5508. empty: 'c3-empty',
  5509. text: 'c3-text',
  5510. texts: 'c3-texts',
  5511. gaugeValue: 'c3-gauge-value',
  5512. grid: 'c3-grid',
  5513. gridLines: 'c3-grid-lines',
  5514. xgrid: 'c3-xgrid',
  5515. xgrids: 'c3-xgrids',
  5516. xgridLine: 'c3-xgrid-line',
  5517. xgridLines: 'c3-xgrid-lines',
  5518. xgridFocus: 'c3-xgrid-focus',
  5519. ygrid: 'c3-ygrid',
  5520. ygrids: 'c3-ygrids',
  5521. ygridLine: 'c3-ygrid-line',
  5522. ygridLines: 'c3-ygrid-lines',
  5523. axis: 'c3-axis',
  5524. axisX: 'c3-axis-x',
  5525. axisXLabel: 'c3-axis-x-label',
  5526. axisY: 'c3-axis-y',
  5527. axisYLabel: 'c3-axis-y-label',
  5528. axisY2: 'c3-axis-y2',
  5529. axisY2Label: 'c3-axis-y2-label',
  5530. legendBackground: 'c3-legend-background',
  5531. legendItem: 'c3-legend-item',
  5532. legendItemEvent: 'c3-legend-item-event',
  5533. legendItemTile: 'c3-legend-item-tile',
  5534. legendItemHidden: 'c3-legend-item-hidden',
  5535. legendItemFocused: 'c3-legend-item-focused',
  5536. dragarea: 'c3-dragarea',
  5537. EXPANDED: '_expanded_',
  5538. SELECTED: '_selected_',
  5539. INCLUDED: '_included_'
  5540. };
  5541. c3_chart_internal_fn.generateClass = function (prefix, targetId) {
  5542. return " " + prefix + " " + prefix + this.getTargetSelectorSuffix(targetId);
  5543. };
  5544. c3_chart_internal_fn.classText = function (d) {
  5545. return this.generateClass(CLASS.text, d.index);
  5546. };
  5547. c3_chart_internal_fn.classTexts = function (d) {
  5548. return this.generateClass(CLASS.texts, d.id);
  5549. };
  5550. c3_chart_internal_fn.classShape = function (d) {
  5551. return this.generateClass(CLASS.shape, d.index);
  5552. };
  5553. c3_chart_internal_fn.classShapes = function (d) {
  5554. return this.generateClass(CLASS.shapes, d.id);
  5555. };
  5556. c3_chart_internal_fn.classLine = function (d) {
  5557. return this.classShape(d) + this.generateClass(CLASS.line, d.id);
  5558. };
  5559. c3_chart_internal_fn.classLines = function (d) {
  5560. return this.classShapes(d) + this.generateClass(CLASS.lines, d.id);
  5561. };
  5562. c3_chart_internal_fn.classCircle = function (d) {
  5563. return this.classShape(d) + this.generateClass(CLASS.circle, d.index);
  5564. };
  5565. c3_chart_internal_fn.classCircles = function (d) {
  5566. return this.classShapes(d) + this.generateClass(CLASS.circles, d.id);
  5567. };
  5568. c3_chart_internal_fn.classBar = function (d) {
  5569. return this.classShape(d) + this.generateClass(CLASS.bar, d.index);
  5570. };
  5571. c3_chart_internal_fn.classBars = function (d) {
  5572. return this.classShapes(d) + this.generateClass(CLASS.bars, d.id);
  5573. };
  5574. c3_chart_internal_fn.classArc = function (d) {
  5575. return this.classShape(d.data) + this.generateClass(CLASS.arc, d.data.id);
  5576. };
  5577. c3_chart_internal_fn.classArcs = function (d) {
  5578. return this.classShapes(d.data) + this.generateClass(CLASS.arcs, d.data.id);
  5579. };
  5580. c3_chart_internal_fn.classArea = function (d) {
  5581. return this.classShape(d) + this.generateClass(CLASS.area, d.id);
  5582. };
  5583. c3_chart_internal_fn.classAreas = function (d) {
  5584. return this.classShapes(d) + this.generateClass(CLASS.areas, d.id);
  5585. };
  5586. c3_chart_internal_fn.classRegion = function (d, i) {
  5587. return this.generateClass(CLASS.region, i) + ' ' + ('class' in d ? d['class'] : '');
  5588. };
  5589. c3_chart_internal_fn.classEvent = function (d) {
  5590. return this.generateClass(CLASS.eventRect, d.index);
  5591. };
  5592. c3_chart_internal_fn.classTarget = function (id) {
  5593. var $$ = this;
  5594. var additionalClassSuffix = $$.config.data_classes[id], additionalClass = '';
  5595. if (additionalClassSuffix) {
  5596. additionalClass = ' ' + CLASS.target + '-' + additionalClassSuffix;
  5597. }
  5598. return $$.generateClass(CLASS.target, id) + additionalClass;
  5599. };
  5600. c3_chart_internal_fn.classFocus = function (d) {
  5601. return this.classFocused(d) + this.classDefocused(d);
  5602. };
  5603. c3_chart_internal_fn.classFocused = function (d) {
  5604. return ' ' + (this.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : '');
  5605. };
  5606. c3_chart_internal_fn.classDefocused = function (d) {
  5607. return ' ' + (this.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : '');
  5608. };
  5609. c3_chart_internal_fn.classChartText = function (d) {
  5610. return CLASS.chartText + this.classTarget(d.id);
  5611. };
  5612. c3_chart_internal_fn.classChartLine = function (d) {
  5613. return CLASS.chartLine + this.classTarget(d.id);
  5614. };
  5615. c3_chart_internal_fn.classChartBar = function (d) {
  5616. return CLASS.chartBar + this.classTarget(d.id);
  5617. };
  5618. c3_chart_internal_fn.classChartArc = function (d) {
  5619. return CLASS.chartArc + this.classTarget(d.data.id);
  5620. };
  5621. c3_chart_internal_fn.getTargetSelectorSuffix = function (targetId) {
  5622. return targetId || targetId === 0 ? ('-' + targetId).replace(/[\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\]/g, '-') : '';
  5623. };
  5624. c3_chart_internal_fn.selectorTarget = function (id, prefix) {
  5625. return (prefix || '') + '.' + CLASS.target + this.getTargetSelectorSuffix(id);
  5626. };
  5627. c3_chart_internal_fn.selectorTargets = function (ids, prefix) {
  5628. var $$ = this;
  5629. ids = ids || [];
  5630. return ids.length ? ids.map(function (id) { return $$.selectorTarget(id, prefix); }) : null;
  5631. };
  5632. c3_chart_internal_fn.selectorLegend = function (id) {
  5633. return '.' + CLASS.legendItem + this.getTargetSelectorSuffix(id);
  5634. };
  5635. c3_chart_internal_fn.selectorLegends = function (ids) {
  5636. var $$ = this;
  5637. return ids && ids.length ? ids.map(function (id) { return $$.selectorLegend(id); }) : null;
  5638. };
  5639. var isValue = c3_chart_internal_fn.isValue = function (v) {
  5640. return v || v === 0;
  5641. },
  5642. isFunction = c3_chart_internal_fn.isFunction = function (o) {
  5643. return typeof o === 'function';
  5644. },
  5645. isString = c3_chart_internal_fn.isString = function (o) {
  5646. return typeof o === 'string';
  5647. },
  5648. isUndefined = c3_chart_internal_fn.isUndefined = function (v) {
  5649. return typeof v === 'undefined';
  5650. },
  5651. isDefined = c3_chart_internal_fn.isDefined = function (v) {
  5652. return typeof v !== 'undefined';
  5653. },
  5654. ceil10 = c3_chart_internal_fn.ceil10 = function (v) {
  5655. return Math.ceil(v / 10) * 10;
  5656. },
  5657. asHalfPixel = c3_chart_internal_fn.asHalfPixel = function (n) {
  5658. return Math.ceil(n) + 0.5;
  5659. },
  5660. diffDomain = c3_chart_internal_fn.diffDomain = function (d) {
  5661. return d[1] - d[0];
  5662. },
  5663. isEmpty = c3_chart_internal_fn.isEmpty = function (o) {
  5664. return typeof o === 'undefined' || o === null || (isString(o) && o.length === 0) || (typeof o === 'object' && Object.keys(o).length === 0);
  5665. },
  5666. notEmpty = c3_chart_internal_fn.notEmpty = function (o) {
  5667. return !c3_chart_internal_fn.isEmpty(o);
  5668. },
  5669. getOption = c3_chart_internal_fn.getOption = function (options, key, defaultValue) {
  5670. return isDefined(options[key]) ? options[key] : defaultValue;
  5671. },
  5672. hasValue = c3_chart_internal_fn.hasValue = function (dict, value) {
  5673. var found = false;
  5674. Object.keys(dict).forEach(function (key) {
  5675. if (dict[key] === value) { found = true; }
  5676. });
  5677. return found;
  5678. },
  5679. getPathBox = c3_chart_internal_fn.getPathBox = function (path) {
  5680. var box = path.getBoundingClientRect(),
  5681. items = [path.pathSegList.getItem(0), path.pathSegList.getItem(1)],
  5682. minX = items[0].x, minY = Math.min(items[0].y, items[1].y);
  5683. return {x: minX, y: minY, width: box.width, height: box.height};
  5684. };
  5685. c3_chart_fn.focus = function (targetIds) {
  5686. var $$ = this.internal, candidates;
  5687. targetIds = $$.mapToTargetIds(targetIds);
  5688. candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
  5689. this.revert();
  5690. this.defocus();
  5691. candidates.classed(CLASS.focused, true).classed(CLASS.defocused, false);
  5692. if ($$.hasArcType()) {
  5693. $$.expandArc(targetIds);
  5694. }
  5695. $$.toggleFocusLegend(targetIds, true);
  5696. $$.focusedTargetIds = targetIds;
  5697. $$.defocusedTargetIds = $$.defocusedTargetIds.filter(function (id) {
  5698. return targetIds.indexOf(id) < 0;
  5699. });
  5700. };
  5701. c3_chart_fn.defocus = function (targetIds) {
  5702. var $$ = this.internal, candidates;
  5703. targetIds = $$.mapToTargetIds(targetIds);
  5704. candidates = $$.svg.selectAll($$.selectorTargets(targetIds.filter($$.isTargetToShow, $$))),
  5705. candidates.classed(CLASS.focused, false).classed(CLASS.defocused, true);
  5706. if ($$.hasArcType()) {
  5707. $$.unexpandArc(targetIds);
  5708. }
  5709. $$.toggleFocusLegend(targetIds, false);
  5710. $$.focusedTargetIds = $$.focusedTargetIds.filter(function (id) {
  5711. return targetIds.indexOf(id) < 0;
  5712. });
  5713. $$.defocusedTargetIds = targetIds;
  5714. };
  5715. c3_chart_fn.revert = function (targetIds) {
  5716. var $$ = this.internal, candidates;
  5717. targetIds = $$.mapToTargetIds(targetIds);
  5718. candidates = $$.svg.selectAll($$.selectorTargets(targetIds)); // should be for all targets
  5719. candidates.classed(CLASS.focused, false).classed(CLASS.defocused, false);
  5720. if ($$.hasArcType()) {
  5721. $$.unexpandArc(targetIds);
  5722. }
  5723. if ($$.config.legend_show) {
  5724. $$.showLegend(targetIds.filter($$.isLegendToShow.bind($$)));
  5725. $$.legend.selectAll($$.selectorLegends(targetIds))
  5726. .filter(function () {
  5727. return $$.d3.select(this).classed(CLASS.legendItemFocused);
  5728. })
  5729. .classed(CLASS.legendItemFocused, false);
  5730. }
  5731. $$.focusedTargetIds = [];
  5732. $$.defocusedTargetIds = [];
  5733. };
  5734. c3_chart_fn.show = function (targetIds, options) {
  5735. var $$ = this.internal, targets;
  5736. targetIds = $$.mapToTargetIds(targetIds);
  5737. options = options || {};
  5738. $$.removeHiddenTargetIds(targetIds);
  5739. targets = $$.svg.selectAll($$.selectorTargets(targetIds));
  5740. targets.transition()
  5741. .style('opacity', 1, 'important')
  5742. .call($$.endall, function () {
  5743. targets.style('opacity', null).style('opacity', 1);
  5744. });
  5745. if (options.withLegend) {
  5746. $$.showLegend(targetIds);
  5747. }
  5748. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
  5749. };
  5750. c3_chart_fn.hide = function (targetIds, options) {
  5751. var $$ = this.internal, targets;
  5752. targetIds = $$.mapToTargetIds(targetIds);
  5753. options = options || {};
  5754. $$.addHiddenTargetIds(targetIds);
  5755. targets = $$.svg.selectAll($$.selectorTargets(targetIds));
  5756. targets.transition()
  5757. .style('opacity', 0, 'important')
  5758. .call($$.endall, function () {
  5759. targets.style('opacity', null).style('opacity', 0);
  5760. });
  5761. if (options.withLegend) {
  5762. $$.hideLegend(targetIds);
  5763. }
  5764. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
  5765. };
  5766. c3_chart_fn.toggle = function (targetIds, options) {
  5767. var that = this, $$ = this.internal;
  5768. $$.mapToTargetIds(targetIds).forEach(function (targetId) {
  5769. $$.isTargetToShow(targetId) ? that.hide(targetId, options) : that.show(targetId, options);
  5770. });
  5771. };
  5772. c3_chart_fn.zoom = function (domain) {
  5773. var $$ = this.internal;
  5774. if (domain) {
  5775. if ($$.isTimeSeries()) {
  5776. domain = domain.map(function (x) { return $$.parseDate(x); });
  5777. }
  5778. $$.brush.extent(domain);
  5779. $$.redraw({withUpdateXDomain: true, withY: $$.config.zoom_rescale});
  5780. $$.config.zoom_onzoom.call(this, $$.x.orgDomain());
  5781. }
  5782. return $$.brush.extent();
  5783. };
  5784. c3_chart_fn.zoom.enable = function (enabled) {
  5785. var $$ = this.internal;
  5786. $$.config.zoom_enabled = enabled;
  5787. $$.updateAndRedraw();
  5788. };
  5789. c3_chart_fn.unzoom = function () {
  5790. var $$ = this.internal;
  5791. $$.brush.clear().update();
  5792. $$.redraw({withUpdateXDomain: true});
  5793. };
  5794. c3_chart_fn.zoom.max = function (max) {
  5795. var $$ = this.internal, config = $$.config, d3 = $$.d3;
  5796. if (max === 0 || max) {
  5797. config.zoom_x_max = d3.max([$$.orgXDomain[1], max]);
  5798. }
  5799. else {
  5800. return config.zoom_x_max;
  5801. }
  5802. };
  5803. c3_chart_fn.zoom.min = function (min) {
  5804. var $$ = this.internal, config = $$.config, d3 = $$.d3;
  5805. if (min === 0 || min) {
  5806. config.zoom_x_min = d3.min([$$.orgXDomain[0], min]);
  5807. }
  5808. else {
  5809. return config.zoom_x_min;
  5810. }
  5811. };
  5812. c3_chart_fn.zoom.range = function (range) {
  5813. if (arguments.length) {
  5814. if (isDefined(range.max)) { this.domain.max(range.max); }
  5815. if (isDefined(range.min)) { this.domain.min(range.min); }
  5816. } else {
  5817. return {
  5818. max: this.domain.max(),
  5819. min: this.domain.min()
  5820. };
  5821. }
  5822. };
  5823. c3_chart_fn.load = function (args) {
  5824. var $$ = this.internal, config = $$.config;
  5825. // update xs if specified
  5826. if (args.xs) {
  5827. $$.addXs(args.xs);
  5828. }
  5829. // update names if exists
  5830. if ('names' in args) {
  5831. c3_chart_fn.data.names.bind(this)(args.names);
  5832. }
  5833. // update classes if exists
  5834. if ('classes' in args) {
  5835. Object.keys(args.classes).forEach(function (id) {
  5836. config.data_classes[id] = args.classes[id];
  5837. });
  5838. }
  5839. // update categories if exists
  5840. if ('categories' in args && $$.isCategorized()) {
  5841. config.axis_x_categories = args.categories;
  5842. }
  5843. // update axes if exists
  5844. if ('axes' in args) {
  5845. Object.keys(args.axes).forEach(function (id) {
  5846. config.data_axes[id] = args.axes[id];
  5847. });
  5848. }
  5849. // update colors if exists
  5850. if ('colors' in args) {
  5851. Object.keys(args.colors).forEach(function (id) {
  5852. config.data_colors[id] = args.colors[id];
  5853. });
  5854. }
  5855. // use cache if exists
  5856. if ('cacheIds' in args && $$.hasCaches(args.cacheIds)) {
  5857. $$.load($$.getCaches(args.cacheIds), args.done);
  5858. return;
  5859. }
  5860. // unload if needed
  5861. if ('unload' in args) {
  5862. // TODO: do not unload if target will load (included in url/rows/columns)
  5863. $$.unload($$.mapToTargetIds((typeof args.unload === 'boolean' && args.unload) ? null : args.unload), function () {
  5864. $$.loadFromArgs(args);
  5865. });
  5866. } else {
  5867. $$.loadFromArgs(args);
  5868. }
  5869. };
  5870. c3_chart_fn.unload = function (args) {
  5871. var $$ = this.internal;
  5872. args = args || {};
  5873. if (args instanceof Array) {
  5874. args = {ids: args};
  5875. } else if (typeof args === 'string') {
  5876. args = {ids: [args]};
  5877. }
  5878. $$.unload($$.mapToTargetIds(args.ids), function () {
  5879. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true, withLegend: true});
  5880. if (args.done) { args.done(); }
  5881. });
  5882. };
  5883. c3_chart_fn.flow = function (args) {
  5884. var $$ = this.internal,
  5885. targets, data, notfoundIds = [], orgDataCount = $$.getMaxDataCount(),
  5886. dataCount, domain, baseTarget, baseValue, length = 0, tail = 0, diff, to;
  5887. if (args.json) {
  5888. data = $$.convertJsonToData(args.json, args.keys);
  5889. }
  5890. else if (args.rows) {
  5891. data = $$.convertRowsToData(args.rows);
  5892. }
  5893. else if (args.columns) {
  5894. data = $$.convertColumnsToData(args.columns);
  5895. }
  5896. else {
  5897. return;
  5898. }
  5899. targets = $$.convertDataToTargets(data, true);
  5900. // Update/Add data
  5901. $$.data.targets.forEach(function (t) {
  5902. var found = false, i, j;
  5903. for (i = 0; i < targets.length; i++) {
  5904. if (t.id === targets[i].id) {
  5905. found = true;
  5906. if (t.values[t.values.length - 1]) {
  5907. tail = t.values[t.values.length - 1].index + 1;
  5908. }
  5909. length = targets[i].values.length;
  5910. for (j = 0; j < length; j++) {
  5911. targets[i].values[j].index = tail + j;
  5912. if (!$$.isTimeSeries()) {
  5913. targets[i].values[j].x = tail + j;
  5914. }
  5915. }
  5916. t.values = t.values.concat(targets[i].values);
  5917. targets.splice(i, 1);
  5918. break;
  5919. }
  5920. }
  5921. if (!found) { notfoundIds.push(t.id); }
  5922. });
  5923. // Append null for not found targets
  5924. $$.data.targets.forEach(function (t) {
  5925. var i, j;
  5926. for (i = 0; i < notfoundIds.length; i++) {
  5927. if (t.id === notfoundIds[i]) {
  5928. tail = t.values[t.values.length - 1].index + 1;
  5929. for (j = 0; j < length; j++) {
  5930. t.values.push({
  5931. id: t.id,
  5932. index: tail + j,
  5933. x: $$.isTimeSeries() ? $$.getOtherTargetX(tail + j) : tail + j,
  5934. value: null
  5935. });
  5936. }
  5937. }
  5938. }
  5939. });
  5940. // Generate null values for new target
  5941. if ($$.data.targets.length) {
  5942. targets.forEach(function (t) {
  5943. var i, missing = [];
  5944. for (i = $$.data.targets[0].values[0].index; i < tail; i++) {
  5945. missing.push({
  5946. id: t.id,
  5947. index: i,
  5948. x: $$.isTimeSeries() ? $$.getOtherTargetX(i) : i,
  5949. value: null
  5950. });
  5951. }
  5952. t.values.forEach(function (v) {
  5953. v.index += tail;
  5954. if (!$$.isTimeSeries()) {
  5955. v.x += tail;
  5956. }
  5957. });
  5958. t.values = missing.concat(t.values);
  5959. });
  5960. }
  5961. $$.data.targets = $$.data.targets.concat(targets); // add remained
  5962. // check data count because behavior needs to change when it's only one
  5963. dataCount = $$.getMaxDataCount();
  5964. baseTarget = $$.data.targets[0];
  5965. baseValue = baseTarget.values[0];
  5966. // Update length to flow if needed
  5967. if (isDefined(args.to)) {
  5968. length = 0;
  5969. to = $$.isTimeSeries() ? $$.parseDate(args.to) : args.to;
  5970. baseTarget.values.forEach(function (v) {
  5971. if (v.x < to) { length++; }
  5972. });
  5973. } else if (isDefined(args.length)) {
  5974. length = args.length;
  5975. }
  5976. // If only one data, update the domain to flow from left edge of the chart
  5977. if (!orgDataCount) {
  5978. if ($$.isTimeSeries()) {
  5979. if (baseTarget.values.length > 1) {
  5980. diff = baseTarget.values[baseTarget.values.length - 1].x - baseValue.x;
  5981. } else {
  5982. diff = baseValue.x - $$.getXDomain($$.data.targets)[0];
  5983. }
  5984. } else {
  5985. diff = 1;
  5986. }
  5987. domain = [baseValue.x - diff, baseValue.x];
  5988. $$.updateXDomain(null, true, true, false, domain);
  5989. } else if (orgDataCount === 1) {
  5990. if ($$.isTimeSeries()) {
  5991. diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
  5992. domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
  5993. $$.updateXDomain(null, true, true, false, domain);
  5994. }
  5995. }
  5996. // Set targets
  5997. $$.updateTargets($$.data.targets);
  5998. // Redraw with new targets
  5999. $$.redraw({
  6000. flow: {
  6001. index: baseValue.index,
  6002. length: length,
  6003. duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
  6004. done: args.done,
  6005. orgDataCount: orgDataCount,
  6006. },
  6007. withLegend: true,
  6008. withTransition: orgDataCount > 1,
  6009. withTrimXDomain: false,
  6010. withUpdateXAxis: true,
  6011. });
  6012. };
  6013. c3_chart_internal_fn.generateFlow = function (args) {
  6014. var $$ = this, config = $$.config, d3 = $$.d3;
  6015. return function () {
  6016. var targets = args.targets,
  6017. flow = args.flow,
  6018. drawBar = args.drawBar,
  6019. drawLine = args.drawLine,
  6020. drawArea = args.drawArea,
  6021. cx = args.cx,
  6022. cy = args.cy,
  6023. xv = args.xv,
  6024. xForText = args.xForText,
  6025. yForText = args.yForText,
  6026. duration = args.duration;
  6027. var translateX, scaleX = 1, transform,
  6028. flowIndex = flow.index,
  6029. flowLength = flow.length,
  6030. flowStart = $$.getValueOnIndex($$.data.targets[0].values, flowIndex),
  6031. flowEnd = $$.getValueOnIndex($$.data.targets[0].values, flowIndex + flowLength),
  6032. orgDomain = $$.x.domain(), domain,
  6033. durationForFlow = flow.duration || duration,
  6034. done = flow.done || function () {},
  6035. wait = $$.generateWait();
  6036. var xgrid = $$.xgrid || d3.selectAll([]),
  6037. xgridLines = $$.xgridLines || d3.selectAll([]),
  6038. mainRegion = $$.mainRegion || d3.selectAll([]),
  6039. mainText = $$.mainText || d3.selectAll([]),
  6040. mainBar = $$.mainBar || d3.selectAll([]),
  6041. mainLine = $$.mainLine || d3.selectAll([]),
  6042. mainArea = $$.mainArea || d3.selectAll([]),
  6043. mainCircle = $$.mainCircle || d3.selectAll([]);
  6044. // set flag
  6045. $$.flowing = true;
  6046. // remove head data after rendered
  6047. $$.data.targets.forEach(function (d) {
  6048. d.values.splice(0, flowLength);
  6049. });
  6050. // update x domain to generate axis elements for flow
  6051. domain = $$.updateXDomain(targets, true, true);
  6052. // update elements related to x scale
  6053. if ($$.updateXGrid) { $$.updateXGrid(true); }
  6054. // generate transform to flow
  6055. if (!flow.orgDataCount) { // if empty
  6056. if ($$.data.targets[0].values.length !== 1) {
  6057. translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
  6058. } else {
  6059. if ($$.isTimeSeries()) {
  6060. flowStart = $$.getValueOnIndex($$.data.targets[0].values, 0);
  6061. flowEnd = $$.getValueOnIndex($$.data.targets[0].values, $$.data.targets[0].values.length - 1);
  6062. translateX = $$.x(flowStart.x) - $$.x(flowEnd.x);
  6063. } else {
  6064. translateX = diffDomain(domain) / 2;
  6065. }
  6066. }
  6067. } else if (flow.orgDataCount === 1 || flowStart.x === flowEnd.x) {
  6068. translateX = $$.x(orgDomain[0]) - $$.x(domain[0]);
  6069. } else {
  6070. if ($$.isTimeSeries()) {
  6071. translateX = ($$.x(orgDomain[0]) - $$.x(domain[0]));
  6072. } else {
  6073. translateX = ($$.x(flowStart.x) - $$.x(flowEnd.x));
  6074. }
  6075. }
  6076. scaleX = (diffDomain(orgDomain) / diffDomain(domain));
  6077. transform = 'translate(' + translateX + ',0) scale(' + scaleX + ',1)';
  6078. $$.hideXGridFocus();
  6079. d3.transition().ease('linear').duration(durationForFlow).each(function () {
  6080. wait.add($$.axes.x.transition().call($$.xAxis));
  6081. wait.add(mainBar.transition().attr('transform', transform));
  6082. wait.add(mainLine.transition().attr('transform', transform));
  6083. wait.add(mainArea.transition().attr('transform', transform));
  6084. wait.add(mainCircle.transition().attr('transform', transform));
  6085. wait.add(mainText.transition().attr('transform', transform));
  6086. wait.add(mainRegion.filter($$.isRegionOnX).transition().attr('transform', transform));
  6087. wait.add(xgrid.transition().attr('transform', transform));
  6088. wait.add(xgridLines.transition().attr('transform', transform));
  6089. })
  6090. .call(wait, function () {
  6091. var i, shapes = [], texts = [], eventRects = [];
  6092. // remove flowed elements
  6093. if (flowLength) {
  6094. for (i = 0; i < flowLength; i++) {
  6095. shapes.push('.' + CLASS.shape + '-' + (flowIndex + i));
  6096. texts.push('.' + CLASS.text + '-' + (flowIndex + i));
  6097. eventRects.push('.' + CLASS.eventRect + '-' + (flowIndex + i));
  6098. }
  6099. $$.svg.selectAll('.' + CLASS.shapes).selectAll(shapes).remove();
  6100. $$.svg.selectAll('.' + CLASS.texts).selectAll(texts).remove();
  6101. $$.svg.selectAll('.' + CLASS.eventRects).selectAll(eventRects).remove();
  6102. $$.svg.select('.' + CLASS.xgrid).remove();
  6103. }
  6104. // draw again for removing flowed elements and reverting attr
  6105. xgrid
  6106. .attr('transform', null)
  6107. .attr($$.xgridAttr);
  6108. xgridLines
  6109. .attr('transform', null);
  6110. xgridLines.select('line')
  6111. .attr("x1", config.axis_rotated ? 0 : xv)
  6112. .attr("x2", config.axis_rotated ? $$.width : xv);
  6113. xgridLines.select('text')
  6114. .attr("x", config.axis_rotated ? $$.width : 0)
  6115. .attr("y", xv);
  6116. mainBar
  6117. .attr('transform', null)
  6118. .attr("d", drawBar);
  6119. mainLine
  6120. .attr('transform', null)
  6121. .attr("d", drawLine);
  6122. mainArea
  6123. .attr('transform', null)
  6124. .attr("d", drawArea);
  6125. mainCircle
  6126. .attr('transform', null)
  6127. .attr("cx", cx)
  6128. .attr("cy", cy);
  6129. mainText
  6130. .attr('transform', null)
  6131. .attr('x', xForText)
  6132. .attr('y', yForText)
  6133. .style('fill-opacity', $$.opacityForText.bind($$));
  6134. mainRegion
  6135. .attr('transform', null);
  6136. mainRegion.select('rect').filter($$.isRegionOnX)
  6137. .attr("x", $$.regionX.bind($$))
  6138. .attr("width", $$.regionWidth.bind($$));
  6139. if (config.interaction_enabled) {
  6140. $$.redrawEventRect();
  6141. }
  6142. // callback for end of flow
  6143. done();
  6144. $$.flowing = false;
  6145. });
  6146. };
  6147. };
  6148. c3_chart_fn.selected = function (targetId) {
  6149. var $$ = this.internal, d3 = $$.d3;
  6150. return d3.merge(
  6151. $$.main.selectAll('.' + CLASS.shapes + $$.getTargetSelectorSuffix(targetId)).selectAll('.' + CLASS.shape)
  6152. .filter(function () { return d3.select(this).classed(CLASS.SELECTED); })
  6153. .map(function (d) { return d.map(function (d) { var data = d.__data__; return data.data ? data.data : data; }); })
  6154. );
  6155. };
  6156. c3_chart_fn.select = function (ids, indices, resetOther) {
  6157. var $$ = this.internal, d3 = $$.d3, config = $$.config;
  6158. if (! config.data_selection_enabled) { return; }
  6159. $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
  6160. var shape = d3.select(this), id = d.data ? d.data.id : d.id,
  6161. toggle = $$.getToggle(this, d).bind($$),
  6162. isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
  6163. isTargetIndex = !indices || indices.indexOf(i) >= 0,
  6164. isSelected = shape.classed(CLASS.SELECTED);
  6165. // line/area selection not supported yet
  6166. if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
  6167. return;
  6168. }
  6169. if (isTargetId && isTargetIndex) {
  6170. if (config.data_selection_isselectable(d) && !isSelected) {
  6171. toggle(true, shape.classed(CLASS.SELECTED, true), d, i);
  6172. }
  6173. } else if (isDefined(resetOther) && resetOther) {
  6174. if (isSelected) {
  6175. toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
  6176. }
  6177. }
  6178. });
  6179. };
  6180. c3_chart_fn.unselect = function (ids, indices) {
  6181. var $$ = this.internal, d3 = $$.d3, config = $$.config;
  6182. if (! config.data_selection_enabled) { return; }
  6183. $$.main.selectAll('.' + CLASS.shapes).selectAll('.' + CLASS.shape).each(function (d, i) {
  6184. var shape = d3.select(this), id = d.data ? d.data.id : d.id,
  6185. toggle = $$.getToggle(this, d).bind($$),
  6186. isTargetId = config.data_selection_grouped || !ids || ids.indexOf(id) >= 0,
  6187. isTargetIndex = !indices || indices.indexOf(i) >= 0,
  6188. isSelected = shape.classed(CLASS.SELECTED);
  6189. // line/area selection not supported yet
  6190. if (shape.classed(CLASS.line) || shape.classed(CLASS.area)) {
  6191. return;
  6192. }
  6193. if (isTargetId && isTargetIndex) {
  6194. if (config.data_selection_isselectable(d)) {
  6195. if (isSelected) {
  6196. toggle(false, shape.classed(CLASS.SELECTED, false), d, i);
  6197. }
  6198. }
  6199. }
  6200. });
  6201. };
  6202. c3_chart_fn.transform = function (type, targetIds) {
  6203. var $$ = this.internal,
  6204. options = ['pie', 'donut'].indexOf(type) >= 0 ? {withTransform: true} : null;
  6205. $$.transformTo(targetIds, type, options);
  6206. };
  6207. c3_chart_internal_fn.transformTo = function (targetIds, type, optionsForRedraw) {
  6208. var $$ = this,
  6209. withTransitionForAxis = !$$.hasArcType(),
  6210. options = optionsForRedraw || {withTransitionForAxis: withTransitionForAxis};
  6211. options.withTransitionForTransform = false;
  6212. $$.transiting = false;
  6213. $$.setTargetType(targetIds, type);
  6214. $$.updateTargets($$.data.targets); // this is needed when transforming to arc
  6215. $$.updateAndRedraw(options);
  6216. };
  6217. c3_chart_fn.groups = function (groups) {
  6218. var $$ = this.internal, config = $$.config;
  6219. if (isUndefined(groups)) { return config.data_groups; }
  6220. config.data_groups = groups;
  6221. $$.redraw();
  6222. return config.data_groups;
  6223. };
  6224. c3_chart_fn.xgrids = function (grids) {
  6225. var $$ = this.internal, config = $$.config;
  6226. if (! grids) { return config.grid_x_lines; }
  6227. config.grid_x_lines = grids;
  6228. $$.redrawWithoutRescale();
  6229. return config.grid_x_lines;
  6230. };
  6231. c3_chart_fn.xgrids.add = function (grids) {
  6232. var $$ = this.internal;
  6233. return this.xgrids($$.config.grid_x_lines.concat(grids ? grids : []));
  6234. };
  6235. c3_chart_fn.xgrids.remove = function (params) { // TODO: multiple
  6236. var $$ = this.internal;
  6237. $$.removeGridLines(params, true);
  6238. };
  6239. c3_chart_fn.ygrids = function (grids) {
  6240. var $$ = this.internal, config = $$.config;
  6241. if (! grids) { return config.grid_y_lines; }
  6242. config.grid_y_lines = grids;
  6243. $$.redrawWithoutRescale();
  6244. return config.grid_y_lines;
  6245. };
  6246. c3_chart_fn.ygrids.add = function (grids) {
  6247. var $$ = this.internal;
  6248. return this.ygrids($$.config.grid_y_lines.concat(grids ? grids : []));
  6249. };
  6250. c3_chart_fn.ygrids.remove = function (params) { // TODO: multiple
  6251. var $$ = this.internal;
  6252. $$.removeGridLines(params, false);
  6253. };
  6254. c3_chart_fn.regions = function (regions) {
  6255. var $$ = this.internal, config = $$.config;
  6256. if (!regions) { return config.regions; }
  6257. config.regions = regions;
  6258. $$.redrawWithoutRescale();
  6259. return config.regions;
  6260. };
  6261. c3_chart_fn.regions.add = function (regions) {
  6262. var $$ = this.internal, config = $$.config;
  6263. if (!regions) { return config.regions; }
  6264. config.regions = config.regions.concat(regions);
  6265. $$.redrawWithoutRescale();
  6266. return config.regions;
  6267. };
  6268. c3_chart_fn.regions.remove = function (options) {
  6269. var $$ = this.internal, config = $$.config,
  6270. duration, classes, regions;
  6271. options = options || {};
  6272. duration = $$.getOption(options, "duration", config.transition_duration);
  6273. classes = $$.getOption(options, "classes", [CLASS.region]);
  6274. regions = $$.main.select('.' + CLASS.regions).selectAll(classes.map(function (c) { return '.' + c; }));
  6275. (duration ? regions.transition().duration(duration) : regions)
  6276. .style('opacity', 0)
  6277. .remove();
  6278. config.regions = config.regions.filter(function (region) {
  6279. var found = false;
  6280. if (!region['class']) {
  6281. return true;
  6282. }
  6283. region['class'].split(' ').forEach(function (c) {
  6284. if (classes.indexOf(c) >= 0) { found = true; }
  6285. });
  6286. return !found;
  6287. });
  6288. return config.regions;
  6289. };
  6290. c3_chart_fn.data = function (targetIds) {
  6291. var targets = this.internal.data.targets;
  6292. return typeof targetIds === 'undefined' ? targets : targets.filter(function (t) {
  6293. return [].concat(targetIds).indexOf(t.id) >= 0;
  6294. });
  6295. };
  6296. c3_chart_fn.data.shown = function (targetIds) {
  6297. return this.internal.filterTargetsToShow(this.data(targetIds));
  6298. };
  6299. c3_chart_fn.data.values = function (targetId) {
  6300. var targets, values = null;
  6301. if (targetId) {
  6302. targets = this.data(targetId);
  6303. values = targets[0] ? targets[0].values.map(function (d) { return d.value; }) : null;
  6304. }
  6305. return values;
  6306. };
  6307. c3_chart_fn.data.names = function (names) {
  6308. this.internal.clearLegendItemTextBoxCache();
  6309. return this.internal.updateDataAttributes('names', names);
  6310. };
  6311. c3_chart_fn.data.colors = function (colors) {
  6312. return this.internal.updateDataAttributes('colors', colors);
  6313. };
  6314. c3_chart_fn.data.axes = function (axes) {
  6315. return this.internal.updateDataAttributes('axes', axes);
  6316. };
  6317. c3_chart_fn.category = function (i, category) {
  6318. var $$ = this.internal, config = $$.config;
  6319. if (arguments.length > 1) {
  6320. config.axis_x_categories[i] = category;
  6321. $$.redraw();
  6322. }
  6323. return config.axis_x_categories[i];
  6324. };
  6325. c3_chart_fn.categories = function (categories) {
  6326. var $$ = this.internal, config = $$.config;
  6327. if (!arguments.length) { return config.axis_x_categories; }
  6328. config.axis_x_categories = categories;
  6329. $$.redraw();
  6330. return config.axis_x_categories;
  6331. };
  6332. // TODO: fix
  6333. c3_chart_fn.color = function (id) {
  6334. var $$ = this.internal;
  6335. return $$.color(id); // more patterns
  6336. };
  6337. c3_chart_fn.x = function (x) {
  6338. var $$ = this.internal;
  6339. if (arguments.length) {
  6340. $$.updateTargetX($$.data.targets, x);
  6341. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
  6342. }
  6343. return $$.data.xs;
  6344. };
  6345. c3_chart_fn.xs = function (xs) {
  6346. var $$ = this.internal;
  6347. if (arguments.length) {
  6348. $$.updateTargetXs($$.data.targets, xs);
  6349. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
  6350. }
  6351. return $$.data.xs;
  6352. };
  6353. c3_chart_fn.axis = function () {};
  6354. c3_chart_fn.axis.labels = function (labels) {
  6355. var $$ = this.internal;
  6356. if (arguments.length) {
  6357. Object.keys(labels).forEach(function (axisId) {
  6358. $$.axis.setLabelText(axisId, labels[axisId]);
  6359. });
  6360. $$.axis.updateLabels();
  6361. }
  6362. // TODO: return some values?
  6363. };
  6364. c3_chart_fn.axis.max = function (max) {
  6365. var $$ = this.internal, config = $$.config;
  6366. if (arguments.length) {
  6367. if (typeof max === 'object') {
  6368. if (isValue(max.x)) { config.axis_x_max = max.x; }
  6369. if (isValue(max.y)) { config.axis_y_max = max.y; }
  6370. if (isValue(max.y2)) { config.axis_y2_max = max.y2; }
  6371. } else {
  6372. config.axis_y_max = config.axis_y2_max = max;
  6373. }
  6374. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
  6375. } else {
  6376. return {
  6377. x: config.axis_x_max,
  6378. y: config.axis_y_max,
  6379. y2: config.axis_y2_max
  6380. };
  6381. }
  6382. };
  6383. c3_chart_fn.axis.min = function (min) {
  6384. var $$ = this.internal, config = $$.config;
  6385. if (arguments.length) {
  6386. if (typeof min === 'object') {
  6387. if (isValue(min.x)) { config.axis_x_min = min.x; }
  6388. if (isValue(min.y)) { config.axis_y_min = min.y; }
  6389. if (isValue(min.y2)) { config.axis_y2_min = min.y2; }
  6390. } else {
  6391. config.axis_y_min = config.axis_y2_min = min;
  6392. }
  6393. $$.redraw({withUpdateOrgXDomain: true, withUpdateXDomain: true});
  6394. } else {
  6395. return {
  6396. x: config.axis_x_min,
  6397. y: config.axis_y_min,
  6398. y2: config.axis_y2_min
  6399. };
  6400. }
  6401. };
  6402. c3_chart_fn.axis.range = function (range) {
  6403. if (arguments.length) {
  6404. if (isDefined(range.max)) { this.axis.max(range.max); }
  6405. if (isDefined(range.min)) { this.axis.min(range.min); }
  6406. } else {
  6407. return {
  6408. max: this.axis.max(),
  6409. min: this.axis.min()
  6410. };
  6411. }
  6412. };
  6413. c3_chart_fn.legend = function () {};
  6414. c3_chart_fn.legend.show = function (targetIds) {
  6415. var $$ = this.internal;
  6416. $$.showLegend($$.mapToTargetIds(targetIds));
  6417. $$.updateAndRedraw({withLegend: true});
  6418. };
  6419. c3_chart_fn.legend.hide = function (targetIds) {
  6420. var $$ = this.internal;
  6421. $$.hideLegend($$.mapToTargetIds(targetIds));
  6422. $$.updateAndRedraw({withLegend: true});
  6423. };
  6424. c3_chart_fn.resize = function (size) {
  6425. var $$ = this.internal, config = $$.config;
  6426. config.size_width = size ? size.width : null;
  6427. config.size_height = size ? size.height : null;
  6428. this.flush();
  6429. };
  6430. c3_chart_fn.flush = function () {
  6431. var $$ = this.internal;
  6432. $$.updateAndRedraw({withLegend: true, withTransition: false, withTransitionForTransform: false});
  6433. };
  6434. c3_chart_fn.destroy = function () {
  6435. var $$ = this.internal;
  6436. window.clearInterval($$.intervalForObserveInserted);
  6437. if ($$.resizeTimeout !== undefined) {
  6438. window.clearTimeout($$.resizeTimeout);
  6439. }
  6440. if (window.detachEvent) {
  6441. window.detachEvent('onresize', $$.resizeFunction);
  6442. } else if (window.removeEventListener) {
  6443. window.removeEventListener('resize', $$.resizeFunction);
  6444. } else {
  6445. var wrapper = window.onresize;
  6446. // check if no one else removed our wrapper and remove our resizeFunction from it
  6447. if (wrapper && wrapper.add && wrapper.remove) {
  6448. wrapper.remove($$.resizeFunction);
  6449. }
  6450. }
  6451. $$.selectChart.classed('c3', false).html("");
  6452. // MEMO: this is needed because the reference of some elements will not be released, then memory leak will happen.
  6453. Object.keys($$).forEach(function (key) {
  6454. $$[key] = null;
  6455. });
  6456. return null;
  6457. };
  6458. c3_chart_fn.tooltip = function () {};
  6459. c3_chart_fn.tooltip.show = function (args) {
  6460. var $$ = this.internal, index, mouse;
  6461. // determine mouse position on the chart
  6462. if (args.mouse) {
  6463. mouse = args.mouse;
  6464. }
  6465. // determine focus data
  6466. if (args.data) {
  6467. if ($$.isMultipleX()) {
  6468. // if multiple xs, target point will be determined by mouse
  6469. mouse = [$$.x(args.data.x), $$.getYScale(args.data.id)(args.data.value)];
  6470. index = null;
  6471. } else {
  6472. // TODO: when tooltip_grouped = false
  6473. index = isValue(args.data.index) ? args.data.index : $$.getIndexByX(args.data.x);
  6474. }
  6475. }
  6476. else if (typeof args.x !== 'undefined') {
  6477. index = $$.getIndexByX(args.x);
  6478. }
  6479. else if (typeof args.index !== 'undefined') {
  6480. index = args.index;
  6481. }
  6482. // emulate mouse events to show
  6483. $$.dispatchEvent('mouseover', index, mouse);
  6484. $$.dispatchEvent('mousemove', index, mouse);
  6485. $$.config.tooltip_onshow.call($$, args.data);
  6486. };
  6487. c3_chart_fn.tooltip.hide = function () {
  6488. // TODO: get target data by checking the state of focus
  6489. this.internal.dispatchEvent('mouseout', 0);
  6490. this.internal.config.tooltip_onhide.call(this);
  6491. };
  6492. // Features:
  6493. // 1. category axis
  6494. // 2. ceil values of translate/x/y to int for half pixel antialiasing
  6495. // 3. multiline tick text
  6496. var tickTextCharSize;
  6497. function c3_axis(d3, params) {
  6498. var scale = d3.scale.linear(), orient = "bottom", innerTickSize = 6, outerTickSize, tickPadding = 3, tickValues = null, tickFormat, tickArguments;
  6499. var tickOffset = 0, tickCulling = true, tickCentered;
  6500. params = params || {};
  6501. outerTickSize = params.withOuterTick ? 6 : 0;
  6502. function axisX(selection, x) {
  6503. selection.attr("transform", function (d) {
  6504. return "translate(" + Math.ceil(x(d) + tickOffset) + ", 0)";
  6505. });
  6506. }
  6507. function axisY(selection, y) {
  6508. selection.attr("transform", function (d) {
  6509. return "translate(0," + Math.ceil(y(d)) + ")";
  6510. });
  6511. }
  6512. function scaleExtent(domain) {
  6513. var start = domain[0], stop = domain[domain.length - 1];
  6514. return start < stop ? [ start, stop ] : [ stop, start ];
  6515. }
  6516. function generateTicks(scale) {
  6517. var i, domain, ticks = [];
  6518. if (scale.ticks) {
  6519. return scale.ticks.apply(scale, tickArguments);
  6520. }
  6521. domain = scale.domain();
  6522. for (i = Math.ceil(domain[0]); i < domain[1]; i++) {
  6523. ticks.push(i);
  6524. }
  6525. if (ticks.length > 0 && ticks[0] > 0) {
  6526. ticks.unshift(ticks[0] - (ticks[1] - ticks[0]));
  6527. }
  6528. return ticks;
  6529. }
  6530. function copyScale() {
  6531. var newScale = scale.copy(), domain;
  6532. if (params.isCategory) {
  6533. domain = scale.domain();
  6534. newScale.domain([domain[0], domain[1] - 1]);
  6535. }
  6536. return newScale;
  6537. }
  6538. function textFormatted(v) {
  6539. var formatted = tickFormat ? tickFormat(v) : v;
  6540. return typeof formatted !== 'undefined' ? formatted : '';
  6541. }
  6542. function getSizeFor1Char(tick) {
  6543. if (tickTextCharSize) {
  6544. return tickTextCharSize;
  6545. }
  6546. var size = {
  6547. h: 11.5,
  6548. w: 5.5
  6549. };
  6550. tick.select('text').text(textFormatted).each(function (d) {
  6551. var box = this.getBoundingClientRect(),
  6552. text = textFormatted(d),
  6553. h = box.height,
  6554. w = text ? (box.width / text.length) : undefined;
  6555. if (h && w) {
  6556. size.h = h;
  6557. size.w = w;
  6558. }
  6559. }).text('');
  6560. tickTextCharSize = size;
  6561. return size;
  6562. }
  6563. function transitionise(selection) {
  6564. return params.withoutTransition ? selection : d3.transition(selection);
  6565. }
  6566. function axis(g) {
  6567. g.each(function () {
  6568. var g = axis.g = d3.select(this);
  6569. var scale0 = this.__chart__ || scale, scale1 = this.__chart__ = copyScale();
  6570. var ticks = tickValues ? tickValues : generateTicks(scale1),
  6571. tick = g.selectAll(".tick").data(ticks, scale1),
  6572. tickEnter = tick.enter().insert("g", ".domain").attr("class", "tick").style("opacity", 1e-6),
  6573. // MEMO: No exit transition. The reason is this transition affects max tick width calculation because old tick will be included in the ticks.
  6574. tickExit = tick.exit().remove(),
  6575. tickUpdate = transitionise(tick).style("opacity", 1),
  6576. tickTransform, tickX, tickY;
  6577. var range = scale.rangeExtent ? scale.rangeExtent() : scaleExtent(scale.range()),
  6578. path = g.selectAll(".domain").data([ 0 ]),
  6579. pathUpdate = (path.enter().append("path").attr("class", "domain"), transitionise(path));
  6580. tickEnter.append("line");
  6581. tickEnter.append("text");
  6582. var lineEnter = tickEnter.select("line"),
  6583. lineUpdate = tickUpdate.select("line"),
  6584. textEnter = tickEnter.select("text"),
  6585. textUpdate = tickUpdate.select("text");
  6586. if (params.isCategory) {
  6587. tickOffset = Math.ceil((scale1(1) - scale1(0)) / 2);
  6588. tickX = tickCentered ? 0 : tickOffset;
  6589. tickY = tickCentered ? tickOffset : 0;
  6590. } else {
  6591. tickOffset = tickX = 0;
  6592. }
  6593. var text, tspan, sizeFor1Char = getSizeFor1Char(g.select('.tick')), counts = [];
  6594. var tickLength = Math.max(innerTickSize, 0) + tickPadding,
  6595. isVertical = orient === 'left' || orient === 'right';
  6596. // this should be called only when category axis
  6597. function splitTickText(d, maxWidth) {
  6598. var tickText = textFormatted(d),
  6599. subtext, spaceIndex, textWidth, splitted = [];
  6600. if (Object.prototype.toString.call(tickText) === "[object Array]") {
  6601. return tickText;
  6602. }
  6603. if (!maxWidth || maxWidth <= 0) {
  6604. maxWidth = isVertical ? 95 : params.isCategory ? (Math.ceil(scale1(ticks[1]) - scale1(ticks[0])) - 12) : 110;
  6605. }
  6606. function split(splitted, text) {
  6607. spaceIndex = undefined;
  6608. for (var i = 1; i < text.length; i++) {
  6609. if (text.charAt(i) === ' ') {
  6610. spaceIndex = i;
  6611. }
  6612. subtext = text.substr(0, i + 1);
  6613. textWidth = sizeFor1Char.w * subtext.length;
  6614. // if text width gets over tick width, split by space index or crrent index
  6615. if (maxWidth < textWidth) {
  6616. return split(
  6617. splitted.concat(text.substr(0, spaceIndex ? spaceIndex : i)),
  6618. text.slice(spaceIndex ? spaceIndex + 1 : i)
  6619. );
  6620. }
  6621. }
  6622. return splitted.concat(text);
  6623. }
  6624. return split(splitted, tickText + "");
  6625. }
  6626. function tspanDy(d, i) {
  6627. var dy = sizeFor1Char.h;
  6628. if (i === 0) {
  6629. if (orient === 'left' || orient === 'right') {
  6630. dy = -((counts[d.index] - 1) * (sizeFor1Char.h / 2) - 3);
  6631. } else {
  6632. dy = ".71em";
  6633. }
  6634. }
  6635. return dy;
  6636. }
  6637. function tickSize(d) {
  6638. var tickPosition = scale(d) + (tickCentered ? 0 : tickOffset);
  6639. return range[0] < tickPosition && tickPosition < range[1] ? innerTickSize : 0;
  6640. }
  6641. text = tick.select("text");
  6642. tspan = text.selectAll('tspan')
  6643. .data(function (d, i) {
  6644. var splitted = params.tickMultiline ? splitTickText(d, params.tickWidth) : [].concat(textFormatted(d));
  6645. counts[i] = splitted.length;
  6646. return splitted.map(function (s) {
  6647. return { index: i, splitted: s };
  6648. });
  6649. });
  6650. tspan.enter().append('tspan');
  6651. tspan.exit().remove();
  6652. tspan.text(function (d) { return d.splitted; });
  6653. var rotate = params.tickTextRotate;
  6654. function textAnchorForText(rotate) {
  6655. if (!rotate) {
  6656. return 'middle';
  6657. }
  6658. return rotate > 0 ? "start" : "end";
  6659. }
  6660. function textTransform(rotate) {
  6661. if (!rotate) {
  6662. return '';
  6663. }
  6664. return "rotate(" + rotate + ")";
  6665. }
  6666. function dxForText(rotate) {
  6667. if (!rotate) {
  6668. return 0;
  6669. }
  6670. return 8 * Math.sin(Math.PI * (rotate / 180));
  6671. }
  6672. function yForText(rotate) {
  6673. if (!rotate) {
  6674. return tickLength;
  6675. }
  6676. return 11.5 - 2.5 * (rotate / 15) * (rotate > 0 ? 1 : -1);
  6677. }
  6678. switch (orient) {
  6679. case "bottom":
  6680. {
  6681. tickTransform = axisX;
  6682. lineEnter.attr("y2", innerTickSize);
  6683. textEnter.attr("y", tickLength);
  6684. lineUpdate.attr("x1", tickX).attr("x2", tickX).attr("y2", tickSize);
  6685. textUpdate.attr("x", 0).attr("y", yForText(rotate))
  6686. .style("text-anchor", textAnchorForText(rotate))
  6687. .attr("transform", textTransform(rotate));
  6688. tspan.attr('x', 0).attr("dy", tspanDy).attr('dx', dxForText(rotate));
  6689. pathUpdate.attr("d", "M" + range[0] + "," + outerTickSize + "V0H" + range[1] + "V" + outerTickSize);
  6690. break;
  6691. }
  6692. case "top":
  6693. {
  6694. // TODO: rotated tick text
  6695. tickTransform = axisX;
  6696. lineEnter.attr("y2", -innerTickSize);
  6697. textEnter.attr("y", -tickLength);
  6698. lineUpdate.attr("x2", 0).attr("y2", -innerTickSize);
  6699. textUpdate.attr("x", 0).attr("y", -tickLength);
  6700. text.style("text-anchor", "middle");
  6701. tspan.attr('x', 0).attr("dy", "0em");
  6702. pathUpdate.attr("d", "M" + range[0] + "," + -outerTickSize + "V0H" + range[1] + "V" + -outerTickSize);
  6703. break;
  6704. }
  6705. case "left":
  6706. {
  6707. tickTransform = axisY;
  6708. lineEnter.attr("x2", -innerTickSize);
  6709. textEnter.attr("x", -tickLength);
  6710. lineUpdate.attr("x2", -innerTickSize).attr("y1", tickY).attr("y2", tickY);
  6711. textUpdate.attr("x", -tickLength).attr("y", tickOffset);
  6712. text.style("text-anchor", "end");
  6713. tspan.attr('x', -tickLength).attr("dy", tspanDy);
  6714. pathUpdate.attr("d", "M" + -outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + -outerTickSize);
  6715. break;
  6716. }
  6717. case "right":
  6718. {
  6719. tickTransform = axisY;
  6720. lineEnter.attr("x2", innerTickSize);
  6721. textEnter.attr("x", tickLength);
  6722. lineUpdate.attr("x2", innerTickSize).attr("y2", 0);
  6723. textUpdate.attr("x", tickLength).attr("y", 0);
  6724. text.style("text-anchor", "start");
  6725. tspan.attr('x', tickLength).attr("dy", tspanDy);
  6726. pathUpdate.attr("d", "M" + outerTickSize + "," + range[0] + "H0V" + range[1] + "H" + outerTickSize);
  6727. break;
  6728. }
  6729. }
  6730. if (scale1.rangeBand) {
  6731. var x = scale1, dx = x.rangeBand() / 2;
  6732. scale0 = scale1 = function (d) {
  6733. return x(d) + dx;
  6734. };
  6735. } else if (scale0.rangeBand) {
  6736. scale0 = scale1;
  6737. } else {
  6738. tickExit.call(tickTransform, scale1);
  6739. }
  6740. tickEnter.call(tickTransform, scale0);
  6741. tickUpdate.call(tickTransform, scale1);
  6742. });
  6743. }
  6744. axis.scale = function (x) {
  6745. if (!arguments.length) { return scale; }
  6746. scale = x;
  6747. return axis;
  6748. };
  6749. axis.orient = function (x) {
  6750. if (!arguments.length) { return orient; }
  6751. orient = x in {top: 1, right: 1, bottom: 1, left: 1} ? x + "" : "bottom";
  6752. return axis;
  6753. };
  6754. axis.tickFormat = function (format) {
  6755. if (!arguments.length) { return tickFormat; }
  6756. tickFormat = format;
  6757. return axis;
  6758. };
  6759. axis.tickCentered = function (isCentered) {
  6760. if (!arguments.length) { return tickCentered; }
  6761. tickCentered = isCentered;
  6762. return axis;
  6763. };
  6764. axis.tickOffset = function () {
  6765. return tickOffset;
  6766. };
  6767. axis.tickInterval = function () {
  6768. var interval, length;
  6769. if (params.isCategory) {
  6770. interval = tickOffset * 2;
  6771. }
  6772. else {
  6773. length = axis.g.select('path.domain').node().getTotalLength() - outerTickSize * 2;
  6774. interval = length / axis.g.selectAll('line').size();
  6775. }
  6776. return interval === Infinity ? 0 : interval;
  6777. };
  6778. axis.ticks = function () {
  6779. if (!arguments.length) { return tickArguments; }
  6780. tickArguments = arguments;
  6781. return axis;
  6782. };
  6783. axis.tickCulling = function (culling) {
  6784. if (!arguments.length) { return tickCulling; }
  6785. tickCulling = culling;
  6786. return axis;
  6787. };
  6788. axis.tickValues = function (x) {
  6789. if (typeof x === 'function') {
  6790. tickValues = function () {
  6791. return x(scale.domain());
  6792. };
  6793. }
  6794. else {
  6795. if (!arguments.length) { return tickValues; }
  6796. tickValues = x;
  6797. }
  6798. return axis;
  6799. };
  6800. return axis;
  6801. }
  6802. c3_chart_internal_fn.isSafari = function () {
  6803. var ua = window.navigator.userAgent;
  6804. return ua.indexOf('Safari') >= 0 && ua.indexOf('Chrome') < 0;
  6805. };
  6806. c3_chart_internal_fn.isChrome = function () {
  6807. var ua = window.navigator.userAgent;
  6808. return ua.indexOf('Chrome') >= 0;
  6809. };
  6810. // PhantomJS doesn't have support for Function.prototype.bind, which has caused confusion. Use
  6811. // this polyfill to avoid the confusion.
  6812. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Polyfill
  6813. if (!Function.prototype.bind) {
  6814. Function.prototype.bind = function(oThis) {
  6815. if (typeof this !== 'function') {
  6816. // closest thing possible to the ECMAScript 5
  6817. // internal IsCallable function
  6818. throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  6819. }
  6820. var aArgs = Array.prototype.slice.call(arguments, 1),
  6821. fToBind = this,
  6822. fNOP = function() {},
  6823. fBound = function() {
  6824. return fToBind.apply(this instanceof fNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
  6825. };
  6826. fNOP.prototype = this.prototype;
  6827. fBound.prototype = new fNOP();
  6828. return fBound;
  6829. };
  6830. }
  6831. if (typeof define === 'function' && define.amd) {
  6832. define("c3", ["d3"], function () { return c3; });
  6833. } else if ('undefined' !== typeof exports && 'undefined' !== typeof module) {
  6834. module.exports = c3;
  6835. } else {
  6836. window.c3 = c3;
  6837. }
  6838. })(window);