Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

charts.js 386KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('charts', function(Y) {
  9. /**
  10. * The Charts widget provides an api for displaying data
  11. * graphically.
  12. *
  13. * @module charts
  14. * @main charts
  15. */
  16. var DOCUMENT = Y.config.doc,
  17. Y_Lang = Y.Lang,
  18. LeftAxisLayout,
  19. RightAxisLayout,
  20. BottomAxisLayout,
  21. TopAxisLayout,
  22. _getClassName = Y.ClassNameManager.getClassName,
  23. SERIES_MARKER = _getClassName("seriesmarker");
  24. /**
  25. * The Renderer class is a base class for chart components that use the `styles`
  26. * attribute.
  27. *
  28. * @module charts
  29. * @class Renderer
  30. * @constructor
  31. */
  32. function Renderer(){}
  33. Renderer.ATTRS = {
  34. /**
  35. * Style properties for class
  36. *
  37. * @attribute styles
  38. * @type Object
  39. */
  40. styles:
  41. {
  42. getter: function()
  43. {
  44. this._styles = this._styles || this._getDefaultStyles();
  45. return this._styles;
  46. },
  47. setter: function(val)
  48. {
  49. this._styles = this._setStyles(val);
  50. }
  51. },
  52. /**
  53. * The graphic in which drawings will be rendered.
  54. *
  55. * @attribute graphic
  56. * @type Graphic
  57. */
  58. graphic: {}
  59. };
  60. Renderer.NAME = "renderer";
  61. Renderer.prototype = {
  62. /**
  63. * Storage for `styles` attribute.
  64. *
  65. * @property _styles
  66. * @type Object
  67. * @private
  68. */
  69. _styles: null,
  70. /**
  71. * Method used by `styles` setter.
  72. *
  73. * @method _setStyles
  74. * @param {Object} newStyles Hash of properties to update.
  75. * @return Object
  76. * @protected
  77. */
  78. _setStyles: function(newstyles)
  79. {
  80. var styles = this.get("styles");
  81. return this._mergeStyles(newstyles, styles);
  82. },
  83. /**
  84. * Merges to object literals so that only specified properties are
  85. * overwritten.
  86. *
  87. * @method _mergeStyles
  88. * @param {Object} a Hash of new styles
  89. * @param {Object} b Hash of original styles
  90. * @return Object
  91. * @protected
  92. */
  93. _mergeStyles: function(a, b)
  94. {
  95. if(!b)
  96. {
  97. b = {};
  98. }
  99. var newstyles = Y.merge(b, {});
  100. Y.Object.each(a, function(value, key, a)
  101. {
  102. if(b.hasOwnProperty(key) && Y_Lang.isObject(value) && !Y_Lang.isArray(value))
  103. {
  104. newstyles[key] = this._mergeStyles(value, b[key]);
  105. }
  106. else
  107. {
  108. newstyles[key] = value;
  109. }
  110. }, this);
  111. return newstyles;
  112. },
  113. /**
  114. * Gets the default value for the `styles` attribute.
  115. *
  116. * @method _getDefaultStyles
  117. * @return Object
  118. * @protected
  119. */
  120. _getDefaultStyles: function()
  121. {
  122. return {padding:{
  123. top:0,
  124. right: 0,
  125. bottom: 0,
  126. left: 0
  127. }};
  128. }
  129. };
  130. Y.augment(Renderer, Y.Attribute);
  131. Y.Renderer = Renderer;
  132. /**
  133. * Algorithmic strategy for rendering a left axis.
  134. *
  135. * @module charts
  136. * @class LeftAxisLayout
  137. * @constructor
  138. */
  139. LeftAxisLayout = function() {};
  140. LeftAxisLayout.prototype = {
  141. /**
  142. * Default margins for text fields.
  143. *
  144. * @private
  145. * @method _getDefaultMargins
  146. * @return Object
  147. */
  148. _getDefaultMargins: function()
  149. {
  150. return {
  151. top: 0,
  152. left: 0,
  153. right: 4,
  154. bottom: 0
  155. };
  156. },
  157. /**
  158. * Sets the length of the tick on either side of the axis line.
  159. *
  160. * @method setTickOffset
  161. * @protected
  162. */
  163. setTickOffsets: function()
  164. {
  165. var host = this,
  166. majorTicks = host.get("styles").majorTicks,
  167. tickLength = majorTicks.length,
  168. halfTick = tickLength * 0.5,
  169. display = majorTicks.display;
  170. host.set("topTickOffset", 0);
  171. host.set("bottomTickOffset", 0);
  172. switch(display)
  173. {
  174. case "inside" :
  175. host.set("rightTickOffset", tickLength);
  176. host.set("leftTickOffset", 0);
  177. break;
  178. case "outside" :
  179. host.set("rightTickOffset", 0);
  180. host.set("leftTickOffset", tickLength);
  181. break;
  182. case "cross":
  183. host.set("rightTickOffset", halfTick);
  184. host.set("leftTickOffset", halfTick);
  185. break;
  186. default:
  187. host.set("rightTickOffset", 0);
  188. host.set("leftTickOffset", 0);
  189. break;
  190. }
  191. },
  192. /**
  193. * Draws a tick
  194. *
  195. * @method drawTick
  196. * @param {Path} path reference to the path `Path` element in which to draw the tick.
  197. * @param {Object} pt Point on the axis in which the tick will intersect.
  198. * @param {Object} tickStyle Hash of properties to apply to the tick.
  199. * @protected
  200. */
  201. drawTick: function(path, pt, tickStyles)
  202. {
  203. var host = this,
  204. style = host.get("styles"),
  205. padding = style.padding,
  206. tickLength = tickStyles.length,
  207. start = {x:padding.left, y:pt.y},
  208. end = {x:tickLength + padding.left, y:pt.y};
  209. host.drawLine(path, start, end);
  210. },
  211. /**
  212. * Calculates the coordinates for the first point on an axis.
  213. *
  214. * @method getLineStart
  215. * @return {Object}
  216. * @protected
  217. */
  218. getLineStart: function()
  219. {
  220. var style = this.get("styles"),
  221. padding = style.padding,
  222. majorTicks = style.majorTicks,
  223. tickLength = majorTicks.length,
  224. display = majorTicks.display,
  225. pt = {x:padding.left, y:0};
  226. if(display === "outside")
  227. {
  228. pt.x += tickLength;
  229. }
  230. else if(display === "cross")
  231. {
  232. pt.x += tickLength/2;
  233. }
  234. return pt;
  235. },
  236. /**
  237. * Calculates the point for a label.
  238. *
  239. * @method getLabelPoint
  240. * @param {Object} point Point on the axis in which the tick will intersect.
  241. * @return {Object}
  242. * @protected
  243. */
  244. getLabelPoint: function(point)
  245. {
  246. return {x:point.x - this.get("leftTickOffset"), y:point.y};
  247. },
  248. /**
  249. * Updates the value for the `maxLabelSize` for use in calculating total size.
  250. *
  251. * @method updateMaxLabelSize
  252. * @param {HTMLElement} label to measure
  253. * @protected
  254. */
  255. updateMaxLabelSize: function(label)
  256. {
  257. var host = this,
  258. props = this._labelRotationProps,
  259. rot = props.rot,
  260. absRot = props.absRot,
  261. sinRadians = props.sinRadians,
  262. cosRadians = props.cosRadians,
  263. m11 = props.m11,
  264. m12 = props.m12,
  265. m21 = props.m21,
  266. m22 = props.m22,
  267. max;
  268. if(!DOCUMENT.createElementNS)
  269. {
  270. label.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
  271. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), label.offsetWidth));
  272. }
  273. else
  274. {
  275. label.style.msTransform = "rotate(0deg)";
  276. if(rot === 0)
  277. {
  278. max = label.offsetWidth;
  279. }
  280. else if(absRot === 90)
  281. {
  282. max = label.offsetHeight;
  283. }
  284. else
  285. {
  286. max = (cosRadians * label.offsetWidth) + (sinRadians * label.offsetHeight);
  287. }
  288. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), max));
  289. }
  290. },
  291. /**
  292. * Rotate and position title.
  293. *
  294. * @method positionTitle
  295. * @param {HTMLElement} label to rotate position
  296. * @protected
  297. */
  298. positionTitle: function(label)
  299. {
  300. var host = this,
  301. max,
  302. styles = host.get("styles").title,
  303. props = this._getTextRotationProps(styles),
  304. rot = props.rot,
  305. absRot = props.absRot,
  306. sinRadians = props.sinRadians,
  307. cosRadians = props.cosRadians,
  308. x = 0,
  309. y = this.get("height")/2,
  310. leftOffset = 0,
  311. topOffset = 0,
  312. labelWidth = label.offsetWidth,
  313. labelHeight = label.offsetHeight;
  314. if(Y.config.doc.createElementNS)
  315. {
  316. if(rot === 0)
  317. {
  318. max = labelWidth;
  319. topOffset -= labelHeight * 0.5;
  320. }
  321. else if(absRot === 90)
  322. {
  323. max = labelHeight;
  324. if(rot === 90)
  325. {
  326. leftOffset += labelHeight;
  327. topOffset -= labelWidth * 0.5;
  328. }
  329. else
  330. {
  331. topOffset += labelWidth * 0.5;
  332. }
  333. }
  334. else
  335. {
  336. max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
  337. if(rot > 0)
  338. {
  339. topOffset -= ((sinRadians * labelWidth) + (cosRadians * labelHeight))/2;
  340. leftOffset += Math.min(labelHeight, (sinRadians * labelHeight));
  341. }
  342. else
  343. {
  344. topOffset += (sinRadians * labelWidth)/2 - (cosRadians * labelHeight)/2;
  345. }
  346. }
  347. y += topOffset;
  348. x += leftOffset;
  349. props.x = Math.round(x);
  350. props.y = Math.round(y);
  351. }
  352. else
  353. {
  354. label.style.filter = null;
  355. labelWidth = Math.round(label.offsetWidth);
  356. labelHeight = Math.round(label.offsetHeight);
  357. if(rot === 0)
  358. {
  359. topOffset -= labelHeight * 0.5;
  360. max = labelWidth;
  361. }
  362. else if(rot === 90)
  363. {
  364. topOffset -= labelWidth * 0.5;
  365. max = labelHeight;
  366. }
  367. else if(rot === -90)
  368. {
  369. topOffset -= labelWidth * 0.5;
  370. max = labelHeight;
  371. }
  372. else
  373. {
  374. max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
  375. topOffset -= ((sinRadians * labelWidth) + (cosRadians * labelHeight))/2;
  376. }
  377. y += topOffset;
  378. x += leftOffset;
  379. label.style.left = Math.round(x) + "px";
  380. label.style.top = Math.round(y) + "px";
  381. }
  382. this._titleSize = max;
  383. this._rotate(label, props);
  384. },
  385. /**
  386. * Rotate and position labels.
  387. *
  388. * @method positionLabel
  389. * @param {HTMLElement} label to rotate position
  390. * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
  391. * against.
  392. * @protected
  393. */
  394. positionLabel: function(label, pt)
  395. {
  396. var host = this,
  397. tickOffset = host.get("leftTickOffset"),
  398. rightTickOffset = host.get("rightTickOffset"),
  399. style = host.get("styles").label,
  400. margin = 0,
  401. leftOffset = pt.x + this._titleSize,
  402. topOffset = pt.y,
  403. props = this._labelRotationProps,
  404. rot = props.rot,
  405. absRot = props.absRot,
  406. sinRadians = props.sinRadians,
  407. cosRadians = props.cosRadians,
  408. maxLabelSize = host.get("maxLabelSize"),
  409. labelWidth = Math.round(label.offsetWidth),
  410. labelHeight = Math.round(label.offsetHeight);
  411. if(style.margin && style.margin.right)
  412. {
  413. margin = style.margin.right;
  414. }
  415. if(!DOCUMENT.createElementNS)
  416. {
  417. label.style.filter = null;
  418. labelWidth = Math.round(label.offsetWidth);
  419. labelHeight = Math.round(label.offsetHeight);
  420. if(rot === 0)
  421. {
  422. leftOffset = labelWidth;
  423. topOffset -= labelHeight * 0.5;
  424. }
  425. else if(absRot === 90)
  426. {
  427. leftOffset = labelHeight;
  428. topOffset -= labelWidth * 0.5;
  429. }
  430. else if(rot > 0)
  431. {
  432. leftOffset = (cosRadians * labelWidth) + (labelHeight * rot/90);
  433. topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight * 0.5));
  434. }
  435. else
  436. {
  437. leftOffset = (cosRadians * labelWidth) + (absRot/90 * labelHeight);
  438. topOffset -= cosRadians * (labelHeight * 0.5);
  439. }
  440. leftOffset += tickOffset;
  441. label.style.left = Math.round((pt.x + this._titleSize + maxLabelSize) - leftOffset) + "px";
  442. label.style.top = Math.round(topOffset) + "px";
  443. this._rotate(label, this._labelRotationProps);
  444. return;
  445. }
  446. label.style.msTransform = "rotate(0deg)";
  447. labelWidth = Math.round(label.offsetWidth);
  448. labelHeight = Math.round(label.offsetHeight);
  449. if(rot === 0)
  450. {
  451. leftOffset -= labelWidth;
  452. topOffset -= labelHeight * 0.5;
  453. }
  454. else if(rot === 90)
  455. {
  456. topOffset -= labelWidth * 0.5;
  457. }
  458. else if(rot === -90)
  459. {
  460. leftOffset -= labelHeight;
  461. topOffset += labelWidth * 0.5;
  462. }
  463. else
  464. {
  465. if(rot < 0)
  466. {
  467. leftOffset -= (cosRadians * labelWidth) + (sinRadians * labelHeight);
  468. topOffset += (sinRadians * labelWidth) - (cosRadians * (labelHeight * 0.6));
  469. }
  470. else
  471. {
  472. leftOffset -= (cosRadians * labelWidth);
  473. topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight * 0.6));
  474. }
  475. }
  476. leftOffset += rightTickOffset;
  477. leftOffset -= margin;
  478. props.x = Math.round(host.get("maxLabelSize") + leftOffset);
  479. props.y = Math.round(topOffset);
  480. this._rotate(label, this._labelRotationProps);
  481. },
  482. /**
  483. * Calculates the size and positions the content elements.
  484. *
  485. * @method setSizeAndPosition
  486. * @protected
  487. */
  488. setSizeAndPosition: function()
  489. {
  490. var host = this,
  491. labelSize = host.get("maxLabelSize"),
  492. style = host.get("styles"),
  493. leftTickOffset = host.get("leftTickOffset"),
  494. sz = labelSize + leftTickOffset,
  495. graphic = host.get("graphic"),
  496. margin = style.label.margin;
  497. if(margin && margin.right)
  498. {
  499. sz += margin.right;
  500. }
  501. sz += this._titleSize;
  502. sz = Math.round(sz);
  503. host.set("width", sz);
  504. host.get("contentBox").setStyle("width", sz);
  505. graphic.set("x", sz - leftTickOffset);
  506. },
  507. /**
  508. * Adjust the position of the Axis widget's content box for internal axes.
  509. *
  510. * @method offsetNodeForTick
  511. * @param {Node} cb Content box of the Axis.
  512. * @protected
  513. */
  514. offsetNodeForTick: function(cb)
  515. {
  516. },
  517. /**
  518. * Sets the width of the axis based on its contents.
  519. *
  520. * @method setCalculatedSize
  521. * @protected
  522. */
  523. setCalculatedSize: function()
  524. {
  525. var host = this,
  526. style = host.get("styles"),
  527. label = style.label,
  528. tickOffset = host.get("leftTickOffset"),
  529. max = host.get("maxLabelSize"),
  530. ttl = Math.round(this._titleSize + tickOffset + max + label.margin.right);
  531. host.get("contentBox").setStyle("width", ttl);
  532. host.set("width", ttl);
  533. }
  534. };
  535. Y.LeftAxisLayout = LeftAxisLayout;
  536. /**
  537. * RightAxisLayout contains algorithms for rendering a right axis.
  538. *
  539. * @module charts
  540. * @class RightAxisLayout
  541. * @constructor
  542. */
  543. RightAxisLayout = function(){};
  544. RightAxisLayout.prototype = {
  545. /**
  546. * Default margins for text fields.
  547. *
  548. * @private
  549. * @method _getDefaultMargins
  550. * @return Object
  551. */
  552. _getDefaultMargins: function()
  553. {
  554. return {
  555. top: 0,
  556. left: 4,
  557. right: 0,
  558. bottom: 0
  559. };
  560. },
  561. /**
  562. * Sets the length of the tick on either side of the axis line.
  563. *
  564. * @method setTickOffset
  565. * @protected
  566. */
  567. setTickOffsets: function()
  568. {
  569. var host = this,
  570. majorTicks = host.get("styles").majorTicks,
  571. tickLength = majorTicks.length,
  572. halfTick = tickLength * 0.5,
  573. display = majorTicks.display;
  574. host.set("topTickOffset", 0);
  575. host.set("bottomTickOffset", 0);
  576. switch(display)
  577. {
  578. case "inside" :
  579. host.set("leftTickOffset", tickLength);
  580. host.set("rightTickOffset", 0);
  581. break;
  582. case "outside" :
  583. host.set("leftTickOffset", 0);
  584. host.set("rightTickOffset", tickLength);
  585. break;
  586. case "cross" :
  587. host.set("rightTickOffset", halfTick);
  588. host.set("leftTickOffset", halfTick);
  589. break;
  590. default:
  591. host.set("leftTickOffset", 0);
  592. host.set("rightTickOffset", 0);
  593. break;
  594. }
  595. },
  596. /**
  597. * Draws a tick
  598. *
  599. * @method drawTick
  600. * @param {Path} path reference to the path `Path` element in which to draw the tick.
  601. * @param {Object} pt Point on the axis in which the tick will intersect.
  602. * @param {Object) tickStyle Hash of properties to apply to the tick.
  603. * @protected
  604. */
  605. drawTick: function(path, pt, tickStyles)
  606. {
  607. var host = this,
  608. style = host.get("styles"),
  609. padding = style.padding,
  610. tickLength = tickStyles.length,
  611. start = {x:padding.left, y:pt.y},
  612. end = {x:padding.left + tickLength, y:pt.y};
  613. host.drawLine(path, start, end);
  614. },
  615. /**
  616. * Calculates the coordinates for the first point on an axis.
  617. *
  618. * @method getLineStart
  619. * @return {Object}
  620. * @protected
  621. */
  622. getLineStart: function()
  623. {
  624. var host = this,
  625. style = host.get("styles"),
  626. padding = style.padding,
  627. majorTicks = style.majorTicks,
  628. tickLength = majorTicks.length,
  629. display = majorTicks.display,
  630. pt = {x:padding.left, y:padding.top};
  631. if(display === "inside")
  632. {
  633. pt.x += tickLength;
  634. }
  635. else if(display === "cross")
  636. {
  637. pt.x += tickLength/2;
  638. }
  639. return pt;
  640. },
  641. /**
  642. * Calculates the point for a label.
  643. *
  644. * @method getLabelPoint
  645. * @param {Object} point Point on the axis in which the tick will intersect.
  646. * @return {Object}
  647. * @protected
  648. */
  649. getLabelPoint: function(point)
  650. {
  651. return {x:point.x + this.get("rightTickOffset"), y:point.y};
  652. },
  653. /**
  654. * Updates the value for the `maxLabelSize` for use in calculating total size.
  655. *
  656. * @method updateMaxLabelSize
  657. * @param {HTMLElement} label to measure
  658. * @protected
  659. */
  660. updateMaxLabelSize: function(label)
  661. {
  662. var host = this,
  663. props = this._labelRotationProps,
  664. rot = props.rot,
  665. absRot = props.absRot,
  666. sinRadians = props.sinRadians,
  667. cosRadians = props.cosRadians,
  668. m11 = props.m11,
  669. m12 = props.m12,
  670. m21 = props.m21,
  671. m22 = props.m22,
  672. max;
  673. if(!DOCUMENT.createElementNS)
  674. {
  675. label.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
  676. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), label.offsetWidth));
  677. }
  678. else
  679. {
  680. label.style.msTransform = "rotate(0deg)";
  681. if(rot === 0)
  682. {
  683. max = label.offsetWidth;
  684. }
  685. else if(absRot === 90)
  686. {
  687. max = label.offsetHeight;
  688. }
  689. else
  690. {
  691. max = (cosRadians * label.offsetWidth) + (sinRadians * label.offsetHeight);
  692. }
  693. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), max));
  694. }
  695. },
  696. /**
  697. * Rotate and position title.
  698. *
  699. * @method positionTitle
  700. * @param {HTMLElement} label to rotate position
  701. * @protected
  702. */
  703. positionTitle: function(label)
  704. {
  705. var host = this,
  706. max,
  707. styles = host.get("styles").title,
  708. margin = styles.margin,
  709. props = this._getTextRotationProps(styles),
  710. rot = props.rot,
  711. absRot = props.absRot,
  712. sinRadians = props.sinRadians,
  713. cosRadians = props.cosRadians,
  714. x = 0,
  715. y = this.get("height")/2,
  716. leftOffset = this.get("maxLabelSize") + margin.left + this.get("rightTickOffset") + this.get("styles").label.margin.left,
  717. topOffset = 0,
  718. labelWidth = label.offsetWidth,
  719. labelHeight = label.offsetHeight;
  720. if(Y.config.doc.createElementNS)
  721. {
  722. if(rot === 0)
  723. {
  724. max = labelWidth;
  725. topOffset -= labelHeight * 0.5;
  726. }
  727. else if(absRot === 90)
  728. {
  729. max = labelHeight;
  730. if(rot === 90)
  731. {
  732. topOffset -= labelWidth * 0.5;
  733. leftOffset += labelHeight;
  734. }
  735. else
  736. {
  737. topOffset += labelWidth * 0.5;
  738. }
  739. }
  740. else
  741. {
  742. max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
  743. if(rot > 0)
  744. {
  745. topOffset -= ((sinRadians * labelWidth) + (cosRadians * labelHeight))/2;
  746. leftOffset += Math.min(labelHeight, (sinRadians * labelHeight));
  747. }
  748. else
  749. {
  750. topOffset += (sinRadians * labelWidth)/2 - (cosRadians * labelHeight)/2;
  751. }
  752. }
  753. y += topOffset;
  754. x += leftOffset;
  755. props.x = Math.round(x);
  756. props.y = Math.round(y);
  757. }
  758. else
  759. {
  760. label.style.filter = null;
  761. labelWidth = Math.round(label.offsetWidth);
  762. labelHeight = Math.round(label.offsetHeight);
  763. if(rot === 0)
  764. {
  765. topOffset -= labelHeight * 0.5;
  766. max = labelWidth;
  767. }
  768. else if(rot === 90)
  769. {
  770. topOffset -= labelWidth * 0.5;
  771. max = labelHeight;
  772. }
  773. else if(rot === -90)
  774. {
  775. topOffset -= labelWidth * 0.5;
  776. max = labelHeight;
  777. }
  778. else
  779. {
  780. max = (cosRadians * labelWidth) + (sinRadians * labelHeight);
  781. topOffset -= ((sinRadians * labelWidth) + (cosRadians * labelHeight))/2;
  782. }
  783. y += topOffset;
  784. x += leftOffset;
  785. label.style.left = Math.round(x) + "px";
  786. label.style.top = Math.round(y) + "px";
  787. }
  788. this._titleSize = max;
  789. this._rotate(label, props);
  790. },
  791. /**
  792. * Rotate and position labels.
  793. *
  794. * @method positionLabel
  795. * @param {HTMLElement} label to rotate position
  796. * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
  797. * against.
  798. * @protected
  799. */
  800. positionLabel: function(label, pt)
  801. {
  802. var host = this,
  803. tickOffset = host.get("rightTickOffset"),
  804. style = host.get("styles").label,
  805. margin = 0,
  806. leftOffset = pt.x,
  807. topOffset = pt.y,
  808. props = this._labelRotationProps,
  809. rot = props.rot,
  810. absRot = props.absRot,
  811. sinRadians = props.sinRadians,
  812. cosRadians = props.cosRadians,
  813. labelWidth = Math.round(label.offsetWidth),
  814. labelHeight = Math.round(label.offsetHeight);
  815. if(style.margin && style.margin.left)
  816. {
  817. margin = style.margin.left;
  818. }
  819. if(!DOCUMENT.createElementNS)
  820. {
  821. label.style.filter = null;
  822. if(rot === 0)
  823. {
  824. topOffset -= labelHeight * 0.5;
  825. }
  826. else if(absRot === 90)
  827. {
  828. topOffset -= labelWidth * 0.5;
  829. }
  830. else if(rot > 0)
  831. {
  832. topOffset -= (cosRadians * (labelHeight * 0.5));
  833. }
  834. else
  835. {
  836. topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight * 0.5));
  837. }
  838. leftOffset += margin;
  839. leftOffset += tickOffset;
  840. label.style.left = Math.round(leftOffset) + "px";
  841. label.style.top = Math.round(topOffset) + "px";
  842. this._rotate(label, props);
  843. return;
  844. }
  845. label.style.msTransform = "rotate(0deg)";
  846. labelWidth = Math.round(label.offsetWidth);
  847. labelHeight = Math.round(label.offsetHeight);
  848. if(rot === 0)
  849. {
  850. topOffset -= labelHeight * 0.5;
  851. }
  852. else if(rot === 90)
  853. {
  854. leftOffset += labelHeight;
  855. topOffset -= labelWidth * 0.5;
  856. }
  857. else if(rot === -90)
  858. {
  859. topOffset += labelWidth * 0.5;
  860. }
  861. else if(rot < 0)
  862. {
  863. topOffset -= (cosRadians * (labelHeight * 0.6));
  864. }
  865. else
  866. {
  867. topOffset -= cosRadians * (labelHeight * 0.6);
  868. leftOffset += sinRadians * labelHeight;
  869. }
  870. leftOffset += margin;
  871. leftOffset += tickOffset;
  872. props.x = Math.round(leftOffset);
  873. props.y = Math.round(topOffset);
  874. this._rotate(label, props);
  875. },
  876. /**
  877. * Calculates the size and positions the content elements.
  878. *
  879. * @method setSizeAndPosition
  880. * @protected
  881. */
  882. setSizeAndPosition: function()
  883. {
  884. var host = this,
  885. label = host.get("styles").label,
  886. labelSize = host.get("maxLabelSize"),
  887. tickOffset = host.get("rightTickOffset"),
  888. sz = tickOffset + labelSize;
  889. if(label.margin && label.margin.left)
  890. {
  891. sz += label.margin.left;
  892. }
  893. sz += this._titleSize;
  894. host.set("width", sz);
  895. host.get("contentBox").setStyle("width", sz);
  896. },
  897. /**
  898. * Adjusts position for inner ticks.
  899. *
  900. * @method offsetNodeForTick
  901. * @param {Node} cb contentBox of the axis
  902. * @protected
  903. */
  904. offsetNodeForTick: function(cb)
  905. {
  906. var host = this,
  907. tickOffset = host.get("leftTickOffset"),
  908. offset = 0 - tickOffset;
  909. cb.setStyle("left", offset);
  910. },
  911. /**
  912. * Assigns a height based on the size of the contents.
  913. *
  914. * @method setCalculatedSize
  915. * @protected
  916. */
  917. setCalculatedSize: function()
  918. {
  919. var host = this,
  920. style = host.get("styles").label,
  921. ttl = Math.round(host.get("rightTickOffset") + host.get("maxLabelSize") + this._titleSize + host.get("styles").title.margin.left + style.margin.left);
  922. host.set("width", ttl);
  923. }
  924. };
  925. Y.RightAxisLayout = RightAxisLayout;
  926. /**
  927. * Contains algorithms for rendering a bottom axis.
  928. *
  929. * @module charts
  930. * @class BottomAxisLayout
  931. * @Constructor
  932. */
  933. BottomAxisLayout = function(){};
  934. BottomAxisLayout.prototype = {
  935. /**
  936. * Default margins for text fields.
  937. *
  938. * @private
  939. * @method _getDefaultMargins
  940. * @return Object
  941. */
  942. _getDefaultMargins: function()
  943. {
  944. return {
  945. top: 4,
  946. left: 0,
  947. right: 0,
  948. bottom: 0
  949. };
  950. },
  951. /**
  952. * Sets the length of the tick on either side of the axis line.
  953. *
  954. * @method setTickOffsets
  955. * @protected
  956. */
  957. setTickOffsets: function()
  958. {
  959. var host = this,
  960. majorTicks = host.get("styles").majorTicks,
  961. tickLength = majorTicks.length,
  962. halfTick = tickLength * 0.5,
  963. display = majorTicks.display;
  964. host.set("leftTickOffset", 0);
  965. host.set("rightTickOffset", 0);
  966. switch(display)
  967. {
  968. case "inside" :
  969. host.set("topTickOffset", tickLength);
  970. host.set("bottomTickOffset", 0);
  971. break;
  972. case "outside" :
  973. host.set("topTickOffset", 0);
  974. host.set("bottomTickOffset", tickLength);
  975. break;
  976. case "cross":
  977. host.set("topTickOffset", halfTick);
  978. host.set("bottomTickOffset", halfTick);
  979. break;
  980. default:
  981. host.set("topTickOffset", 0);
  982. host.set("bottomTickOffset", 0);
  983. break;
  984. }
  985. },
  986. /**
  987. * Calculates the coordinates for the first point on an axis.
  988. *
  989. * @method getLineStart
  990. * @protected
  991. */
  992. getLineStart: function()
  993. {
  994. var style = this.get("styles"),
  995. padding = style.padding,
  996. majorTicks = style.majorTicks,
  997. tickLength = majorTicks.length,
  998. display = majorTicks.display,
  999. pt = {x:0, y:padding.top};
  1000. if(display === "inside")
  1001. {
  1002. pt.y += tickLength;
  1003. }
  1004. else if(display === "cross")
  1005. {
  1006. pt.y += tickLength/2;
  1007. }
  1008. return pt;
  1009. },
  1010. /**
  1011. * Draws a tick
  1012. *
  1013. * @method drawTick
  1014. * @param {Path} path reference to the path `Path` element in which to draw the tick.
  1015. * @param {Object} pt hash containing x and y coordinates
  1016. * @param {Object} tickStyles hash of properties used to draw the tick
  1017. * @protected
  1018. */
  1019. drawTick: function(path, pt, tickStyles)
  1020. {
  1021. var host = this,
  1022. style = host.get("styles"),
  1023. padding = style.padding,
  1024. tickLength = tickStyles.length,
  1025. start = {x:pt.x, y:padding.top},
  1026. end = {x:pt.x, y:tickLength + padding.top};
  1027. host.drawLine(path, start, end);
  1028. },
  1029. /**
  1030. * Calculates the point for a label.
  1031. *
  1032. * @method getLabelPoint
  1033. * @param {Object} pt Object containing x and y coordinates
  1034. * @return Object
  1035. * @protected
  1036. */
  1037. getLabelPoint: function(point)
  1038. {
  1039. return {x:point.x, y:point.y + this.get("bottomTickOffset")};
  1040. },
  1041. /**
  1042. * Updates the value for the `maxLabelSize` for use in calculating total size.
  1043. *
  1044. * @method updateMaxLabelSize
  1045. * @param {HTMLElement} label to measure
  1046. * @protected
  1047. */
  1048. updateMaxLabelSize: function(label)
  1049. {
  1050. var host = this,
  1051. props = this._labelRotationProps,
  1052. rot = props.rot,
  1053. absRot = props.absRot,
  1054. sinRadians = props.sinRadians,
  1055. cosRadians = props.cosRadians,
  1056. m11 = props.m11,
  1057. m12 = props.m12,
  1058. m21 = props.m21,
  1059. m22 = props.m22,
  1060. max;
  1061. if(!DOCUMENT.createElementNS)
  1062. {
  1063. label.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
  1064. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), label.offsetHeight));
  1065. }
  1066. else
  1067. {
  1068. label.style.msTransform = "rotate(0deg)";
  1069. if(rot === 0)
  1070. {
  1071. max = label.offsetHeight;
  1072. }
  1073. else if(absRot === 90)
  1074. {
  1075. max = label.offsetWidth;
  1076. }
  1077. else
  1078. {
  1079. max = (sinRadians * label.offsetWidth) + (cosRadians * label.offsetHeight);
  1080. }
  1081. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), max));
  1082. }
  1083. },
  1084. /**
  1085. * Rotate and position title.
  1086. *
  1087. * @method positionTitle
  1088. * @param {HTMLElement} label to rotate position
  1089. * @protected
  1090. */
  1091. positionTitle: function(label)
  1092. {
  1093. var host = this,
  1094. max,
  1095. styles = host.get("styles").title,
  1096. props = this._getTextRotationProps(styles),
  1097. rot = props.rot,
  1098. absRot = props.absRot,
  1099. sinRadians = props.sinRadians,
  1100. cosRadians = props.cosRadians,
  1101. x = this.get("width")/2,
  1102. y = this.get("maxLabelSize") + this.get("styles").label.margin.top + styles.margin.top + this.get("bottomTickOffset"),
  1103. leftOffset = 0,
  1104. topOffset = 0,
  1105. labelWidth = label.offsetWidth,
  1106. labelHeight = label.offsetHeight;
  1107. if(Y.config.doc.createElementNS)
  1108. {
  1109. if(rot === 0)
  1110. {
  1111. max = labelHeight;
  1112. leftOffset -= labelWidth * 0.5;
  1113. }
  1114. else if(absRot === 90)
  1115. {
  1116. max = labelWidth;
  1117. if(rot === -90)
  1118. {
  1119. topOffset += labelWidth;
  1120. leftOffset -= labelHeight;
  1121. }
  1122. }
  1123. else
  1124. {
  1125. max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
  1126. if(rot > 0)
  1127. {
  1128. leftOffset -= (cosRadians * labelWidth)/2 - (sinRadians * labelHeight)/2;
  1129. }
  1130. else
  1131. {
  1132. topOffset += (sinRadians * labelWidth) - (cosRadians * labelHeight)/2;
  1133. leftOffset -= (cosRadians * labelWidth)/2 + (sinRadians * labelHeight)/2;
  1134. }
  1135. }
  1136. x += leftOffset;
  1137. y += topOffset;
  1138. props.x = Math.round(x);
  1139. props.y = Math.round(y);
  1140. }
  1141. else
  1142. {
  1143. label.style.filter = null;
  1144. labelWidth = Math.round(label.offsetWidth);
  1145. labelHeight = Math.round(label.offsetHeight);
  1146. if(rot === 0)
  1147. {
  1148. leftOffset -= labelWidth * 0.5;
  1149. max = labelHeight;
  1150. }
  1151. else if(rot === 90)
  1152. {
  1153. leftOffset -= labelHeight * 0.5;
  1154. max = labelWidth;
  1155. }
  1156. else if(rot === -90)
  1157. {
  1158. leftOffset -= labelHeight * 0.5;
  1159. max = labelWidth;
  1160. }
  1161. else
  1162. {
  1163. max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
  1164. leftOffset -= ((cosRadians * labelWidth) + (sinRadians * labelHeight))/2;
  1165. }
  1166. x += leftOffset;
  1167. y += topOffset;
  1168. label.style.left = Math.round(x) + "px";
  1169. label.style.top = Math.round(y) + "px";
  1170. }
  1171. this._titleSize = max;
  1172. this._rotate(label, props);
  1173. },
  1174. /**
  1175. * Rotate and position labels.
  1176. *
  1177. * @method positionLabel
  1178. * @param {HTMLElement} label to rotate position
  1179. * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
  1180. * against.
  1181. * @protected
  1182. */
  1183. positionLabel: function(label, pt)
  1184. {
  1185. var host = this,
  1186. tickOffset = host.get("bottomTickOffset"),
  1187. style = host.get("styles").label,
  1188. margin = 0,
  1189. props = this._labelRotationProps,
  1190. rot = props.rot,
  1191. absRot = props.absRot,
  1192. sinRadians = props.sinRadians,
  1193. cosRadians = props.cosRadians,
  1194. leftOffset = Math.round(pt.x),
  1195. topOffset = Math.round(pt.y),
  1196. labelWidth = Math.round(label.offsetWidth),
  1197. labelHeight = Math.round(label.offsetHeight);
  1198. if(style.margin && style.margin.top)
  1199. {
  1200. margin = style.margin.top;
  1201. }
  1202. if(!DOCUMENT.createElementNS)
  1203. {
  1204. label.style.filter = null;
  1205. labelWidth = Math.round(label.offsetWidth);
  1206. labelHeight = Math.round(label.offsetHeight);
  1207. if(absRot === 90)
  1208. {
  1209. leftOffset -= labelHeight * 0.5;
  1210. }
  1211. else if(rot < 0)
  1212. {
  1213. leftOffset -= cosRadians * labelWidth;
  1214. leftOffset -= sinRadians * (labelHeight * 0.5);
  1215. }
  1216. else if(rot > 0)
  1217. {
  1218. leftOffset -= sinRadians * (labelHeight * 0.5);
  1219. }
  1220. else
  1221. {
  1222. leftOffset -= labelWidth * 0.5;
  1223. }
  1224. topOffset += margin;
  1225. topOffset += tickOffset;
  1226. label.style.left = Math.round(leftOffset) + "px";
  1227. label.style.top = Math.round(topOffset) + "px";
  1228. this._rotate(label, props);
  1229. return;
  1230. }
  1231. label.style.msTransform = "rotate(0deg)";
  1232. labelWidth = Math.round(label.offsetWidth);
  1233. labelHeight = Math.round(label.offsetHeight);
  1234. if(rot === 0)
  1235. {
  1236. leftOffset -= labelWidth * 0.5;
  1237. }
  1238. else if(absRot === 90)
  1239. {
  1240. if(rot === 90)
  1241. {
  1242. leftOffset += labelHeight * 0.5;
  1243. }
  1244. else
  1245. {
  1246. topOffset += labelWidth;
  1247. leftOffset -= labelHeight * 0.5;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. if(rot < 0)
  1253. {
  1254. leftOffset -= (cosRadians * labelWidth) + (sinRadians * (labelHeight * 0.6));
  1255. topOffset += sinRadians * labelWidth;
  1256. }
  1257. else
  1258. {
  1259. leftOffset += Math.round(sinRadians * (labelHeight * 0.6));
  1260. }
  1261. }
  1262. topOffset += margin;
  1263. topOffset += tickOffset;
  1264. props.x = leftOffset;
  1265. props.y = topOffset;
  1266. this._rotate(label, props);
  1267. },
  1268. /**
  1269. * Calculates the size and positions the content elements.
  1270. *
  1271. * @method setSizeAndPosition
  1272. * @protected
  1273. */
  1274. setSizeAndPosition: function()
  1275. {
  1276. var host = this,
  1277. labelSize = host.get("maxLabelSize"),
  1278. tickLength = host.get("bottomTickLength"),
  1279. style = host.get("styles"),
  1280. sz = tickLength + labelSize,
  1281. margin = style.label.margin;
  1282. if(margin && margin.top)
  1283. {
  1284. sz += margin.top;
  1285. }
  1286. sz = Math.round(sz);
  1287. host.set("height", sz);
  1288. },
  1289. /**
  1290. * Adjusts position for inner ticks.
  1291. *
  1292. * @method offsetNodeForTick
  1293. * @param {Node} cb contentBox of the axis
  1294. * @protected
  1295. */
  1296. offsetNodeForTick: function(cb)
  1297. {
  1298. var host = this;
  1299. host.get("contentBox").setStyle("top", 0 - host.get("topTickOffset"));
  1300. },
  1301. /**
  1302. * Assigns a height based on the size of the contents.
  1303. *
  1304. * @method setCalculatedSize
  1305. * @protected
  1306. */
  1307. setCalculatedSize: function()
  1308. {
  1309. var host = this,
  1310. style = host.get("styles").label,
  1311. ttl = Math.round(host.get("bottomTickOffset") + host.get("maxLabelSize") + style.margin.top + this.get("styles").title.margin.top + this._titleSize);
  1312. host.set("height", ttl);
  1313. }
  1314. };
  1315. Y.BottomAxisLayout = BottomAxisLayout;
  1316. /**
  1317. * Contains algorithms for rendering a top axis.
  1318. *
  1319. * @module charts
  1320. * @class TopAxisLayout
  1321. * @constructor
  1322. */
  1323. TopAxisLayout = function(){};
  1324. TopAxisLayout.prototype = {
  1325. /**
  1326. * Default margins for text fields.
  1327. *
  1328. * @private
  1329. * @method _getDefaultMargins
  1330. * @return Object
  1331. */
  1332. _getDefaultMargins: function()
  1333. {
  1334. return {
  1335. top: 0,
  1336. left: 0,
  1337. right: 0,
  1338. bottom: 4
  1339. };
  1340. },
  1341. /**
  1342. * Sets the length of the tick on either side of the axis line.
  1343. *
  1344. * @method setTickOffsets
  1345. * @protected
  1346. */
  1347. setTickOffsets: function()
  1348. {
  1349. var host = this,
  1350. majorTicks = host.get("styles").majorTicks,
  1351. tickLength = majorTicks.length,
  1352. halfTick = tickLength * 0.5,
  1353. display = majorTicks.display;
  1354. host.set("leftTickOffset", 0);
  1355. host.set("rightTickOffset", 0);
  1356. switch(display)
  1357. {
  1358. case "inside" :
  1359. host.set("bottomTickOffset", tickLength);
  1360. host.set("topTickOffset", 0);
  1361. break;
  1362. case "outside" :
  1363. host.set("bottomTickOffset", 0);
  1364. host.set("topTickOffset", tickLength);
  1365. break;
  1366. case "cross" :
  1367. host.set("topTickOffset", halfTick);
  1368. host.set("bottomTickOffset", halfTick);
  1369. break;
  1370. default:
  1371. host.set("topTickOffset", 0);
  1372. host.set("bottomTickOffset", 0);
  1373. break;
  1374. }
  1375. },
  1376. /**
  1377. * Calculates the coordinates for the first point on an axis.
  1378. *
  1379. * @method getLineStart
  1380. * @protected
  1381. */
  1382. getLineStart: function()
  1383. {
  1384. var host = this,
  1385. style = host.get("styles"),
  1386. padding = style.padding,
  1387. majorTicks = style.majorTicks,
  1388. tickLength = majorTicks.length,
  1389. display = majorTicks.display,
  1390. pt = {x:0, y:padding.top};
  1391. if(display === "outside")
  1392. {
  1393. pt.y += tickLength;
  1394. }
  1395. else if(display === "cross")
  1396. {
  1397. pt.y += tickLength/2;
  1398. }
  1399. return pt;
  1400. },
  1401. /**
  1402. * Draws a tick
  1403. *
  1404. * @method drawTick
  1405. * @param {Path} path reference to the path `Path` element in which to draw the tick.
  1406. * @param {Object} pt hash containing x and y coordinates
  1407. * @param {Object} tickStyles hash of properties used to draw the tick
  1408. * @protected
  1409. */
  1410. drawTick: function(path, pt, tickStyles)
  1411. {
  1412. var host = this,
  1413. style = host.get("styles"),
  1414. padding = style.padding,
  1415. tickLength = tickStyles.length,
  1416. start = {x:pt.x, y:padding.top},
  1417. end = {x:pt.x, y:tickLength + padding.top};
  1418. host.drawLine(path, start, end);
  1419. },
  1420. /**
  1421. * Calculates the point for a label.
  1422. *
  1423. * @method getLabelPoint
  1424. * @param {Object} pt hash containing x and y coordinates
  1425. * @return Object
  1426. * @protected
  1427. */
  1428. getLabelPoint: function(pt)
  1429. {
  1430. return {x:pt.x, y:pt.y - this.get("topTickOffset")};
  1431. },
  1432. /**
  1433. * Updates the value for the `maxLabelSize` for use in calculating total size.
  1434. *
  1435. * @method updateMaxLabelSize
  1436. * @param {HTMLElement} label to measure
  1437. * @protected
  1438. */
  1439. updateMaxLabelSize: function(label)
  1440. {
  1441. var host = this,
  1442. props = this._labelRotationProps,
  1443. rot = props.rot,
  1444. absRot = props.absRot,
  1445. sinRadians = props.sinRadians,
  1446. cosRadians = props.cosRadians,
  1447. m11 = props.m11,
  1448. m12 = props.m12,
  1449. m21 = props.m21,
  1450. m22 = props.m22,
  1451. max;
  1452. if(!DOCUMENT.createElementNS)
  1453. {
  1454. label.style.filter = 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
  1455. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), label.offsetHeight));
  1456. }
  1457. else
  1458. {
  1459. label.style.msTransform = "rotate(0deg)";
  1460. if(rot === 0)
  1461. {
  1462. max = label.offsetHeight;
  1463. }
  1464. else if(absRot === 90)
  1465. {
  1466. max = label.offsetWidth;
  1467. }
  1468. else
  1469. {
  1470. max = (sinRadians * label.offsetWidth) + (cosRadians * label.offsetHeight);
  1471. }
  1472. host.set("maxLabelSize", Math.max(host.get("maxLabelSize"), max));
  1473. }
  1474. },
  1475. /**
  1476. * Rotate and position title.
  1477. *
  1478. * @method positionTitle
  1479. * @param {HTMLElement} label to rotate position
  1480. * @protected
  1481. */
  1482. positionTitle: function(label)
  1483. {
  1484. var host = this,
  1485. max,
  1486. styles = host.get("styles").title,
  1487. props = this._getTextRotationProps(styles),
  1488. rot = props.rot,
  1489. absRot = props.absRot,
  1490. sinRadians = props.sinRadians,
  1491. cosRadians = props.cosRadians,
  1492. x = this.get("width")/2,
  1493. y = styles.margin.top,
  1494. leftOffset = 0,
  1495. topOffset = 0,
  1496. labelWidth = label.offsetWidth,
  1497. labelHeight = label.offsetHeight;
  1498. if(Y.config.doc.createElementNS)
  1499. {
  1500. if(rot === 0)
  1501. {
  1502. max = labelHeight;
  1503. leftOffset -= labelWidth * 0.5;
  1504. }
  1505. else if(absRot === 90)
  1506. {
  1507. max = labelWidth;
  1508. if(rot === 90)
  1509. {
  1510. leftOffset += labelHeight/2;
  1511. }
  1512. else
  1513. {
  1514. topOffset += labelWidth;
  1515. leftOffset -= labelHeight/2;
  1516. }
  1517. }
  1518. else
  1519. {
  1520. max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
  1521. if(rot > 0)
  1522. {
  1523. leftOffset -= (cosRadians * labelWidth)/2 - (sinRadians * labelHeight)/2;
  1524. }
  1525. else
  1526. {
  1527. topOffset += (sinRadians * labelWidth);
  1528. leftOffset -= (cosRadians * labelWidth)/2 + (sinRadians * labelHeight)/2;
  1529. }
  1530. }
  1531. x += leftOffset;
  1532. y += topOffset;
  1533. props.x = Math.round(x);
  1534. props.y = Math.round(y);
  1535. }
  1536. else
  1537. {
  1538. label.style.filter = null;
  1539. labelWidth = Math.round(label.offsetWidth);
  1540. labelHeight = Math.round(label.offsetHeight);
  1541. if(rot === 0)
  1542. {
  1543. leftOffset -= labelWidth * 0.5;
  1544. max = labelHeight;
  1545. }
  1546. else if(rot === 90)
  1547. {
  1548. leftOffset -= labelHeight * 0.5;
  1549. max = labelWidth;
  1550. }
  1551. else if(rot === -90)
  1552. {
  1553. leftOffset -= labelHeight * 0.5;
  1554. max = labelWidth;
  1555. }
  1556. else
  1557. {
  1558. max = (sinRadians * labelWidth) + (cosRadians * labelHeight);
  1559. leftOffset -= ((cosRadians * labelWidth) + (sinRadians * labelHeight))/2;
  1560. }
  1561. x += leftOffset;
  1562. y += topOffset;
  1563. label.style.left = Math.round(x) + "px";
  1564. label.style.top = Math.round(y) + "px";
  1565. }
  1566. this._titleSize = max;
  1567. this._rotate(label, props);
  1568. },
  1569. /**
  1570. * Rotate and position labels.
  1571. *
  1572. * @method positionLabel
  1573. * @param {HTMLElement} label to rotate position
  1574. * @param {Object} pt hash containing the x and y coordinates in which the label will be positioned
  1575. * against.
  1576. * @protected
  1577. */
  1578. positionLabel: function(label, pt)
  1579. {
  1580. var host = this,
  1581. tickOffset = host.get("topTickOffset"),
  1582. bottomTickOffset = host.get("bottomTickOffset"),
  1583. style = host.get("styles").label,
  1584. titleStyles = host.get("styles").title,
  1585. totalTitleSize = this.get("title") ? this._titleSize + titleStyles.margin.top + titleStyles.margin.bottom : 0,
  1586. margin = 0,
  1587. leftOffset = pt.x,
  1588. topOffset = pt.y + totalTitleSize,
  1589. props = this._labelRotationProps,
  1590. rot = props.rot,
  1591. absRot = props.absRot,
  1592. sinRadians = props.sinRadians,
  1593. cosRadians = props.cosRadians,
  1594. maxLabelSize = host.get("maxLabelSize"),
  1595. labelWidth = Math.round(label.offsetWidth),
  1596. labelHeight = Math.round(label.offsetHeight);
  1597. if(style.margin && style.margin.bottom)
  1598. {
  1599. margin = style.margin.bottom;
  1600. }
  1601. if(!DOCUMENT.createElementNS)
  1602. {
  1603. label.style.filter = null;
  1604. labelWidth = Math.round(label.offsetWidth);
  1605. labelHeight = Math.round(label.offsetHeight);
  1606. if(rot === 0)
  1607. {
  1608. leftOffset -= labelWidth * 0.5;
  1609. }
  1610. else if(absRot === 90)
  1611. {
  1612. leftOffset -= labelHeight * 0.5;
  1613. }
  1614. else if(rot > 0)
  1615. {
  1616. leftOffset -= (cosRadians * labelWidth) + Math.min((sinRadians * labelHeight), (rot/180 * labelHeight));
  1617. topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight));
  1618. topOffset += maxLabelSize;
  1619. }
  1620. else
  1621. {
  1622. leftOffset -= sinRadians * (labelHeight * 0.5);
  1623. topOffset -= (sinRadians * labelWidth) + (cosRadians * (labelHeight));
  1624. topOffset += maxLabelSize;
  1625. }
  1626. topOffset -= tickOffset;
  1627. label.style.left = Math.round(leftOffset);
  1628. label.style.top = Math.round(topOffset);
  1629. this._rotate(label, props);
  1630. return;
  1631. }
  1632. label.style.msTransform = "rotate(0deg)";
  1633. labelWidth = Math.round(label.offsetWidth);
  1634. labelHeight = Math.round(label.offsetHeight);
  1635. if(rot === 0)
  1636. {
  1637. leftOffset -= labelWidth * 0.5;
  1638. topOffset -= labelHeight;
  1639. }
  1640. else if(rot === 90)
  1641. {
  1642. leftOffset += labelHeight * 0.5;
  1643. topOffset -= labelWidth;
  1644. }
  1645. else if(rot === -90)
  1646. {
  1647. leftOffset -= labelHeight * 0.5;
  1648. topOffset -= 0;
  1649. }
  1650. else if(rot < 0)
  1651. {
  1652. leftOffset -= (sinRadians * (labelHeight * 0.6));
  1653. topOffset -= (cosRadians * labelHeight);
  1654. }
  1655. else
  1656. {
  1657. leftOffset -= (cosRadians * labelWidth) - (sinRadians * (labelHeight * 0.6));
  1658. topOffset -= (sinRadians * labelWidth) + (cosRadians * labelHeight);
  1659. }
  1660. topOffset += bottomTickOffset;
  1661. topOffset -= margin;
  1662. props.x = Math.round(leftOffset);
  1663. props.y = Math.round(host.get("maxLabelSize") + topOffset);
  1664. this._rotate(label, props);
  1665. },
  1666. /**
  1667. * Calculates the size and positions the content elements.
  1668. *
  1669. * @method setSizeAndPosition
  1670. * @protected
  1671. */
  1672. setSizeAndPosition: function()
  1673. {
  1674. var host = this,
  1675. labelSize = host.get("maxLabelSize"),
  1676. tickOffset = host.get("topTickOffset"),
  1677. style = host.get("styles"),
  1678. margin = style.label.margin,
  1679. graphic = host.get("graphic"),
  1680. sz = tickOffset + labelSize,
  1681. titleMargin = style.title.margin;
  1682. if(margin && margin.bottom)
  1683. {
  1684. sz += margin.bottom;
  1685. }
  1686. if(this.get("title"))
  1687. {
  1688. sz += this._titleSize + titleMargin.top + titleMargin.bottom;
  1689. }
  1690. host.set("height", sz);
  1691. graphic.set("y", sz - tickOffset);
  1692. },
  1693. /**
  1694. * Adjusts position for inner ticks.
  1695. *
  1696. * @method offsetNodeForTick
  1697. * @param {Node} cb contentBox of the axis
  1698. * @protected
  1699. */
  1700. offsetNodeForTick: function(cb)
  1701. {
  1702. },
  1703. /**
  1704. * Assigns a height based on the size of the contents.
  1705. *
  1706. * @method setCalculatedSize
  1707. * @protected
  1708. */
  1709. setCalculatedSize: function()
  1710. {
  1711. var host = this,
  1712. graphic = host.get("graphic"),
  1713. styles = host.get("styles"),
  1714. labelMargin = styles.label.margin,
  1715. titleMargin = styles.title.margin,
  1716. totalLabelSize = labelMargin.top + labelMargin.bottom + host.get("maxLabelSize"),
  1717. totalTitleSize = host.get("title") ? titleMargin.top + titleMargin.bottom + host._titleSize : 0,
  1718. topTickOffset = this.get("topTickOffset"),
  1719. ttl = Math.round(topTickOffset + totalLabelSize + totalTitleSize);
  1720. host.set("height", ttl);
  1721. graphic.set("y", ttl - topTickOffset);
  1722. }
  1723. };
  1724. Y.TopAxisLayout = TopAxisLayout;
  1725. /**
  1726. * The Axis class. Generates axes for a chart.
  1727. *
  1728. * @module charts
  1729. * @class Axis
  1730. * @extends Widget
  1731. * @uses Renderer
  1732. * @constructor
  1733. * @param {Object} config (optional) Configuration parameters for the Chart.
  1734. */
  1735. Y.Axis = Y.Base.create("axis", Y.Widget, [Y.Renderer], {
  1736. /**
  1737. * Handles change to the dataProvider
  1738. *
  1739. * @method _dataChangeHandler
  1740. * @param {Object} e Event object
  1741. * @private
  1742. */
  1743. _dataChangeHandler: function(e)
  1744. {
  1745. if(this.get("rendered"))
  1746. {
  1747. this._drawAxis();
  1748. }
  1749. },
  1750. /**
  1751. * Handles changes to axis.
  1752. *
  1753. * @method _updateHandler
  1754. * @param {Object} e Event object
  1755. * @private
  1756. */
  1757. _updateHandler: function(e)
  1758. {
  1759. if(this.get("rendered"))
  1760. {
  1761. this._drawAxis();
  1762. }
  1763. },
  1764. /**
  1765. * @method renderUI
  1766. * @private
  1767. */
  1768. renderUI: function()
  1769. {
  1770. var pos = this.get("position"),
  1771. layoutClass = this._layoutClasses[pos];
  1772. if(pos && pos != "none")
  1773. {
  1774. this._layout = new layoutClass();
  1775. if(this._layout)
  1776. {
  1777. this._setCanvas();
  1778. }
  1779. }
  1780. },
  1781. /**
  1782. * @method syncUI
  1783. * @private
  1784. */
  1785. syncUI: function()
  1786. {
  1787. var layout = this._layout,
  1788. defaultMargins,
  1789. styles,
  1790. label,
  1791. title,
  1792. i;
  1793. if(layout)
  1794. {
  1795. defaultMargins = layout._getDefaultMargins();
  1796. styles = this.get("styles");
  1797. label = styles.label.margin;
  1798. title =styles.title.margin;
  1799. //need to defaultMargins method to the layout classes.
  1800. for(i in defaultMargins)
  1801. {
  1802. if(defaultMargins.hasOwnProperty(i))
  1803. {
  1804. label[i] = label[i] === undefined ? defaultMargins[i] : label[i];
  1805. title[i] = title[i] === undefined ? defaultMargins[i] : title[i];
  1806. }
  1807. }
  1808. }
  1809. this._drawAxis();
  1810. },
  1811. /**
  1812. * Creates a graphic instance to be used for the axis line and ticks.
  1813. *
  1814. * @method _setCanvas
  1815. * @private
  1816. */
  1817. _setCanvas: function()
  1818. {
  1819. var cb = this.get("contentBox"),
  1820. bb = this.get("boundingBox"),
  1821. p = this.get("position"),
  1822. pn = this._parentNode,
  1823. w = this.get("width"),
  1824. h = this.get("height");
  1825. bb.setStyle("position", "absolute");
  1826. bb.setStyle("zIndex", 2);
  1827. w = w ? w + "px" : pn.getStyle("width");
  1828. h = h ? h + "px" : pn.getStyle("height");
  1829. if(p === "top" || p === "bottom")
  1830. {
  1831. cb.setStyle("width", w);
  1832. }
  1833. else
  1834. {
  1835. cb.setStyle("height", h);
  1836. }
  1837. cb.setStyle("position", "relative");
  1838. cb.setStyle("left", "0px");
  1839. cb.setStyle("top", "0px");
  1840. this.set("graphic", new Y.Graphic());
  1841. this.get("graphic").render(cb);
  1842. },
  1843. /**
  1844. * Gets the default value for the `styles` attribute. Overrides
  1845. * base implementation.
  1846. *
  1847. * @method _getDefaultStyles
  1848. * @return Object
  1849. * @protected
  1850. */
  1851. _getDefaultStyles: function()
  1852. {
  1853. var axisstyles = {
  1854. majorTicks: {
  1855. display:"inside",
  1856. length:4,
  1857. color:"#dad8c9",
  1858. weight:1,
  1859. alpha:1
  1860. },
  1861. minorTicks: {
  1862. display:"none",
  1863. length:2,
  1864. color:"#dad8c9",
  1865. weight:1
  1866. },
  1867. line: {
  1868. weight:1,
  1869. color:"#dad8c9",
  1870. alpha:1
  1871. },
  1872. majorUnit: {
  1873. determinant:"count",
  1874. count:11,
  1875. distance:75
  1876. },
  1877. top: "0px",
  1878. left: "0px",
  1879. width: "100px",
  1880. height: "100px",
  1881. label: {
  1882. color:"#808080",
  1883. alpha: 1,
  1884. fontSize:"85%",
  1885. rotation: 0,
  1886. margin: {
  1887. top: undefined,
  1888. right: undefined,
  1889. bottom: undefined,
  1890. left: undefined
  1891. }
  1892. },
  1893. title: {
  1894. color:"#808080",
  1895. alpha: 1,
  1896. fontSize:"85%",
  1897. rotation: undefined,
  1898. margin: {
  1899. top: undefined,
  1900. right: undefined,
  1901. bottom: undefined,
  1902. left: undefined
  1903. }
  1904. },
  1905. hideOverlappingLabelTicks: false
  1906. };
  1907. return Y.merge(Y.Renderer.prototype._getDefaultStyles(), axisstyles);
  1908. },
  1909. /**
  1910. * Updates the axis when the size changes.
  1911. *
  1912. * @method _handleSizeChange
  1913. * @param {Object} e Event object.
  1914. * @private
  1915. */
  1916. _handleSizeChange: function(e)
  1917. {
  1918. var attrName = e.attrName,
  1919. pos = this.get("position"),
  1920. vert = pos == "left" || pos == "right",
  1921. cb = this.get("contentBox"),
  1922. hor = pos == "bottom" || pos == "top";
  1923. cb.setStyle("width", this.get("width"));
  1924. cb.setStyle("height", this.get("height"));
  1925. if((hor && attrName == "width") || (vert && attrName == "height"))
  1926. {
  1927. this._drawAxis();
  1928. }
  1929. },
  1930. /**
  1931. * Maps key values to classes containing layout algorithms
  1932. *
  1933. * @property _layoutClasses
  1934. * @type Object
  1935. * @private
  1936. */
  1937. _layoutClasses:
  1938. {
  1939. top : TopAxisLayout,
  1940. bottom: BottomAxisLayout,
  1941. left: LeftAxisLayout,
  1942. right : RightAxisLayout
  1943. },
  1944. /**
  1945. * Draws a line segment between 2 points
  1946. *
  1947. * @method drawLine
  1948. * @param {Object} startPoint x and y coordinates for the start point of the line segment
  1949. * @param {Object} endPoint x and y coordinates for the for the end point of the line segment
  1950. * @param {Object} line styles (weight, color and alpha to be applied to the line segment)
  1951. * @private
  1952. */
  1953. drawLine: function(path, startPoint, endPoint)
  1954. {
  1955. path.moveTo(startPoint.x, startPoint.y);
  1956. path.lineTo(endPoint.x, endPoint.y);
  1957. },
  1958. /**
  1959. * Generates the properties necessary for rotating and positioning a text field.
  1960. *
  1961. * @method _getTextRotationProps
  1962. * @param {Object} styles properties for the text field
  1963. * @return Object
  1964. * @private
  1965. */
  1966. _getTextRotationProps: function(styles)
  1967. {
  1968. if(styles.rotation === undefined)
  1969. {
  1970. switch(this.get("position"))
  1971. {
  1972. case "left" :
  1973. styles.rotation = -90;
  1974. break;
  1975. case "right" :
  1976. styles.rotation = 90;
  1977. break;
  1978. default :
  1979. styles.rotation = 0;
  1980. break;
  1981. }
  1982. }
  1983. var rot = Math.min(90, Math.max(-90, styles.rotation)),
  1984. absRot = Math.abs(rot),
  1985. radCon = Math.PI/180,
  1986. sinRadians = parseFloat(parseFloat(Math.sin(absRot * radCon)).toFixed(8)),
  1987. cosRadians = parseFloat(parseFloat(Math.cos(absRot * radCon)).toFixed(8)),
  1988. m11 = cosRadians,
  1989. m12 = rot > 0 ? -sinRadians : sinRadians,
  1990. m21 = -m12,
  1991. m22 = m11;
  1992. return {
  1993. rot: rot,
  1994. absRot: absRot,
  1995. radCon: radCon,
  1996. sinRadians: sinRadians,
  1997. cosRadians: cosRadians,
  1998. m11: m11,
  1999. m12: m12,
  2000. m21: m21,
  2001. m22: m22,
  2002. textAlpha: styles.alpha
  2003. };
  2004. },
  2005. /**
  2006. * Draws an axis.
  2007. *
  2008. * @method _drawAxis
  2009. * @private
  2010. */
  2011. _drawAxis: function ()
  2012. {
  2013. if(this._drawing)
  2014. {
  2015. this._callLater = true;
  2016. return;
  2017. }
  2018. this._drawing = true;
  2019. this._callLater = false;
  2020. if(this._layout)
  2021. {
  2022. var styles = this.get("styles"),
  2023. line = styles.line,
  2024. labelStyles = styles.label,
  2025. majorTickStyles = styles.majorTicks,
  2026. drawTicks = majorTickStyles.display != "none",
  2027. tickPoint,
  2028. majorUnit = styles.majorUnit,
  2029. len,
  2030. majorUnitDistance,
  2031. i = 0,
  2032. layout = this._layout,
  2033. layoutLength,
  2034. position,
  2035. lineStart,
  2036. label,
  2037. labelFunction = this.get("labelFunction"),
  2038. labelFunctionScope = this.get("labelFunctionScope"),
  2039. labelFormat = this.get("labelFormat"),
  2040. graphic = this.get("graphic"),
  2041. path = this.get("path"),
  2042. tickPath;
  2043. graphic.set("autoDraw", false);
  2044. path.clear();
  2045. path.set("stroke", {
  2046. weight: line.weight,
  2047. color: line.color,
  2048. opacity: line.alpha
  2049. });
  2050. this._labelRotationProps = this._getTextRotationProps(labelStyles);
  2051. layout.setTickOffsets.apply(this);
  2052. layoutLength = this.getLength();
  2053. lineStart = layout.getLineStart.apply(this);
  2054. len = this.getTotalMajorUnits(majorUnit);
  2055. majorUnitDistance = this.getMajorUnitDistance(len, layoutLength, majorUnit);
  2056. this.set("edgeOffset", this.getEdgeOffset(len, layoutLength) * 0.5);
  2057. tickPoint = this.getFirstPoint(lineStart);
  2058. this.drawLine(path, lineStart, this.getLineEnd(tickPoint));
  2059. if(drawTicks)
  2060. {
  2061. tickPath = this.get("tickPath");
  2062. tickPath.clear();
  2063. tickPath.set("stroke", {
  2064. weight: majorTickStyles.weight,
  2065. color: majorTickStyles.color,
  2066. opacity: majorTickStyles.alpha
  2067. });
  2068. layout.drawTick.apply(this, [tickPath, tickPoint, majorTickStyles]);
  2069. }
  2070. if(len < 1)
  2071. {
  2072. this._clearLabelCache();
  2073. return;
  2074. }
  2075. this._createLabelCache();
  2076. this._tickPoints = [];
  2077. this.set("maxLabelSize", 0);
  2078. this._titleSize = 0;
  2079. for(; i < len; ++i)
  2080. {
  2081. if(drawTicks)
  2082. {
  2083. layout.drawTick.apply(this, [tickPath, tickPoint, majorTickStyles]);
  2084. }
  2085. position = this.getPosition(tickPoint);
  2086. label = this.getLabel(tickPoint, labelStyles);
  2087. label.innerHTML = labelFunction.apply(labelFunctionScope, [this.getLabelByIndex(i, len), labelFormat]);
  2088. tickPoint = this.getNextPoint(tickPoint, majorUnitDistance);
  2089. }
  2090. this._clearLabelCache();
  2091. this._updateTitle();
  2092. layout.setSizeAndPosition.apply(this);
  2093. if(this.get("overlapGraph"))
  2094. {
  2095. layout.offsetNodeForTick.apply(this, [this.get("contentBox")]);
  2096. }
  2097. layout.setCalculatedSize.apply(this);
  2098. for(i = 0; i < len; ++i)
  2099. {
  2100. layout.positionLabel.apply(this, [this.get("labels")[i], this._tickPoints[i]]);
  2101. }
  2102. }
  2103. this._drawing = false;
  2104. if(this._callLater)
  2105. {
  2106. this._drawAxis();
  2107. }
  2108. else
  2109. {
  2110. this._updatePathElement();
  2111. this.fire("axisRendered");
  2112. }
  2113. },
  2114. /**
  2115. * Updates path.
  2116. *
  2117. * @method _updatePathElement
  2118. * @private
  2119. */
  2120. _updatePathElement: function()
  2121. {
  2122. var path = this._path,
  2123. tickPath = this._tickPath,
  2124. redrawGraphic = false,
  2125. graphic = this.get("graphic");
  2126. if(path)
  2127. {
  2128. redrawGraphic = true;
  2129. path.end();
  2130. }
  2131. if(tickPath)
  2132. {
  2133. redrawGraphic = true;
  2134. tickPath.end();
  2135. }
  2136. if(redrawGraphic)
  2137. {
  2138. graphic._redraw();
  2139. }
  2140. },
  2141. /**
  2142. * Updates the content and style properties for a title field.
  2143. *
  2144. * @method _updateTitle
  2145. * @private
  2146. */
  2147. _updateTitle: function()
  2148. {
  2149. var i,
  2150. styles,
  2151. customStyles,
  2152. title = this.get("title"),
  2153. titleTextField = this._titleTextField,
  2154. parentNode;
  2155. if(title !== null && title !== undefined)
  2156. {
  2157. customStyles = {
  2158. rotation: "rotation",
  2159. margin: "margin",
  2160. alpha: "alpha"
  2161. };
  2162. styles = this.get("styles").title;
  2163. if(!titleTextField)
  2164. {
  2165. titleTextField = DOCUMENT.createElement('span');
  2166. titleTextField.style.display = "block";
  2167. titleTextField.style.whiteSpace = "nowrap";
  2168. titleTextField.setAttribute("class", "axisTitle");
  2169. this.get("contentBox").appendChild(titleTextField);
  2170. }
  2171. titleTextField.style.position = "absolute";
  2172. for(i in styles)
  2173. {
  2174. if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
  2175. {
  2176. titleTextField.style[i] = styles[i];
  2177. }
  2178. }
  2179. titleTextField.innerHTML = title;
  2180. this._titleTextField = titleTextField;
  2181. this._layout.positionTitle.apply(this, [titleTextField]);
  2182. }
  2183. else if(titleTextField)
  2184. {
  2185. parentNode = titleTextField.parentNode;
  2186. if(parentNode)
  2187. {
  2188. parentNode.removeChild(titleTextField);
  2189. }
  2190. this._titleTextField = null;
  2191. }
  2192. },
  2193. /**
  2194. * Creates or updates an axis label.
  2195. *
  2196. * @method getLabel
  2197. * @param {Object} pt x and y coordinates for the label
  2198. * @param {Object} styles styles applied to label
  2199. * @return HTMLElement
  2200. * @private
  2201. */
  2202. getLabel: function(pt, styles)
  2203. {
  2204. var i,
  2205. label,
  2206. customStyles = {
  2207. rotation: "rotation",
  2208. margin: "margin",
  2209. alpha: "alpha"
  2210. },
  2211. cache = this._labelCache;
  2212. if(cache.length > 0)
  2213. {
  2214. label = cache.shift();
  2215. }
  2216. else
  2217. {
  2218. label = DOCUMENT.createElement("span");
  2219. label.style.display = "block";
  2220. label.style.whiteSpace = "nowrap";
  2221. Y.one(label).addClass("axisLabel");
  2222. this.get("contentBox").appendChild(label);
  2223. }
  2224. label.style.position = "absolute";
  2225. this._labels.push(label);
  2226. this._tickPoints.push({x:pt.x, y:pt.y});
  2227. this._layout.updateMaxLabelSize.apply(this, [label]);
  2228. for(i in styles)
  2229. {
  2230. if(styles.hasOwnProperty(i) && !customStyles.hasOwnProperty(i))
  2231. {
  2232. label.style[i] = styles[i];
  2233. }
  2234. }
  2235. return label;
  2236. },
  2237. /**
  2238. * Creates a cache of labels that can be re-used when the axis redraws.
  2239. *
  2240. * @method _createLabelCache
  2241. * @private
  2242. */
  2243. _createLabelCache: function()
  2244. {
  2245. if(this._labels)
  2246. {
  2247. if(this._labelCache)
  2248. {
  2249. this._labelCache = this._labels.concat(this._labelCache);
  2250. }
  2251. else
  2252. {
  2253. this._labelCache = this._labels.concat();
  2254. }
  2255. }
  2256. else
  2257. {
  2258. this._clearLabelCache();
  2259. }
  2260. this._labels = [];
  2261. },
  2262. /**
  2263. * Removes axis labels from the dom and clears the label cache.
  2264. *
  2265. * @method _clearLabelCache
  2266. * @private
  2267. */
  2268. _clearLabelCache: function()
  2269. {
  2270. if(this._labelCache)
  2271. {
  2272. var len = this._labelCache.length,
  2273. i = 0,
  2274. label,
  2275. labelCache = this._labelCache;
  2276. for(; i < len; ++i)
  2277. {
  2278. label = labelCache[i];
  2279. label.parentNode.removeChild(label);
  2280. }
  2281. }
  2282. this._labelCache = [];
  2283. },
  2284. /**
  2285. * Gets the end point of an axis.
  2286. *
  2287. * @method getLineEnd
  2288. * @return Object
  2289. * @private
  2290. */
  2291. getLineEnd: function(pt)
  2292. {
  2293. var w = this.get("width"),
  2294. h = this.get("height"),
  2295. pos = this.get("position");
  2296. if(pos === "top" || pos === "bottom")
  2297. {
  2298. return {x:w, y:pt.y};
  2299. }
  2300. else
  2301. {
  2302. return {x:pt.x, y:h};
  2303. }
  2304. },
  2305. /**
  2306. * Calcuates the width or height of an axis depending on its direction.
  2307. *
  2308. * @method getLength
  2309. * @return Number
  2310. * @private
  2311. */
  2312. getLength: function()
  2313. {
  2314. var l,
  2315. style = this.get("styles"),
  2316. padding = style.padding,
  2317. w = this.get("width"),
  2318. h = this.get("height"),
  2319. pos = this.get("position");
  2320. if(pos === "top" || pos === "bottom")
  2321. {
  2322. l = w - (padding.left + padding.right);
  2323. }
  2324. else
  2325. {
  2326. l = h - (padding.top + padding.bottom);
  2327. }
  2328. return l;
  2329. },
  2330. /**
  2331. * Gets the position of the first point on an axis.
  2332. *
  2333. * @method getFirstPoint
  2334. * @param {Object} pt Object containing x and y coordinates.
  2335. * @return Object
  2336. * @private
  2337. */
  2338. getFirstPoint:function(pt)
  2339. {
  2340. var style = this.get("styles"),
  2341. pos = this.get("position"),
  2342. padding = style.padding,
  2343. np = {x:pt.x, y:pt.y};
  2344. if(pos === "top" || pos === "bottom")
  2345. {
  2346. np.x += padding.left + this.get("edgeOffset");
  2347. }
  2348. else
  2349. {
  2350. np.y += this.get("height") - (padding.top + this.get("edgeOffset"));
  2351. }
  2352. return np;
  2353. },
  2354. /**
  2355. * Gets the position of the next point on an axis.
  2356. *
  2357. * @method getNextPoint
  2358. * @param {Object} point Object containing x and y coordinates.
  2359. * @param {Number} majorUnitDistance Distance in pixels between ticks.
  2360. * @return Object
  2361. * @private
  2362. */
  2363. getNextPoint: function(point, majorUnitDistance)
  2364. {
  2365. var pos = this.get("position");
  2366. if(pos === "top" || pos === "bottom")
  2367. {
  2368. point.x = point.x + majorUnitDistance;
  2369. }
  2370. else
  2371. {
  2372. point.y = point.y - majorUnitDistance;
  2373. }
  2374. return point;
  2375. },
  2376. /**
  2377. * Calculates the placement of last tick on an axis.
  2378. *
  2379. * @method getLastPoint
  2380. * @return Object
  2381. * @private
  2382. */
  2383. getLastPoint: function()
  2384. {
  2385. var style = this.get("styles"),
  2386. padding = style.padding,
  2387. w = this.get("width"),
  2388. pos = this.get("position");
  2389. if(pos === "top" || pos === "bottom")
  2390. {
  2391. return {x:w - padding.right, y:padding.top};
  2392. }
  2393. else
  2394. {
  2395. return {x:padding.left, y:padding.top};
  2396. }
  2397. },
  2398. /**
  2399. * Calculates position on the axis.
  2400. *
  2401. * @method getPosition
  2402. * @param {Object} point contains x and y values
  2403. * @private
  2404. */
  2405. getPosition: function(point)
  2406. {
  2407. var p,
  2408. h = this.get("height"),
  2409. style = this.get("styles"),
  2410. padding = style.padding,
  2411. pos = this.get("position"),
  2412. dataType = this.get("dataType");
  2413. if(pos === "left" || pos === "right")
  2414. {
  2415. //Numeric data on a vertical axis is displayed from bottom to top.
  2416. //Categorical and Timeline data is displayed from top to bottom.
  2417. if(dataType === "numeric")
  2418. {
  2419. p = (h - (padding.top + padding.bottom)) - (point.y - padding.top);
  2420. }
  2421. else
  2422. {
  2423. p = point.y - padding.top;
  2424. }
  2425. }
  2426. else
  2427. {
  2428. p = point.x - padding.left;
  2429. }
  2430. return p;
  2431. },
  2432. /**
  2433. * Rotates and positions a text field.
  2434. *
  2435. * @method _rotate
  2436. * @param {HTMLElement} label text field to rotate and position
  2437. * @param {Object} props properties to be applied to the text field.
  2438. * @private
  2439. */
  2440. _rotate: function(label, props)
  2441. {
  2442. var rot = props.rot,
  2443. x = props.x,
  2444. y = props.y,
  2445. absRot,
  2446. radCon,
  2447. sinRadians,
  2448. cosRadians,
  2449. m11,
  2450. m12,
  2451. m21,
  2452. m22,
  2453. filterString,
  2454. textAlpha;
  2455. if(Y.config.doc.createElementNS)
  2456. {
  2457. label.style.MozTransformOrigin = "0 0";
  2458. label.style.MozTransform = "translate(" + x + "px," + y + "px) rotate(" + rot + "deg)";
  2459. label.style.webkitTransformOrigin = "0 0";
  2460. label.style.webkitTransform = "translate(" + x + "px," + y + "px) rotate(" + rot + "deg)";
  2461. label.style.msTransformOrigin = "0 0";
  2462. label.style.msTransform = "translate(" + x + "px," + y + "px) rotate(" + rot + "deg)";
  2463. label.style.OTransformOrigin = "0 0";
  2464. label.style.OTransform = "translate(" + x + "px," + y + "px) rotate(" + rot + "deg)";
  2465. }
  2466. else
  2467. {
  2468. textAlpha = props.textAlpha;
  2469. absRot = props.absRot;
  2470. radCon = props.radCon;
  2471. sinRadians = props.sinRadians;
  2472. cosRadians = props.cosRadians;
  2473. m11 = props.m11;
  2474. m12 = props.m12;
  2475. m21 = props.m21;
  2476. m22 = props.m22;
  2477. if(Y_Lang.isNumber(textAlpha) && textAlpha < 1 && textAlpha > -1 && !isNaN(textAlpha))
  2478. {
  2479. filterString = "progid:DXImageTransform.Microsoft.Alpha(Opacity=" + Math.round(textAlpha * 100) + ")";
  2480. }
  2481. if(rot !== 0)
  2482. {
  2483. if(filterString)
  2484. {
  2485. filterString += " ";
  2486. }
  2487. else
  2488. {
  2489. filterString = "";
  2490. }
  2491. filterString += 'progid:DXImageTransform.Microsoft.Matrix(M11=' + m11 + ' M12=' + m12 + ' M21=' + m21 + ' M22=' + m22 + ' sizingMethod="auto expand")';
  2492. }
  2493. if(filterString)
  2494. {
  2495. label.style.filter = filterString;
  2496. }
  2497. }
  2498. }
  2499. }, {
  2500. ATTRS:
  2501. {
  2502. /**
  2503. * Difference betweend the first/last tick and edge of axis.
  2504. *
  2505. * @attribute edgeOffset
  2506. * @type Number
  2507. * @protected
  2508. */
  2509. edgeOffset:
  2510. {
  2511. value: 0
  2512. },
  2513. /**
  2514. * The graphic in which the axis line and ticks will be rendered.
  2515. *
  2516. * @attribute graphic
  2517. * @type Graphic
  2518. */
  2519. graphic: {},
  2520. /**
  2521. * @attribute path
  2522. * @type Shape
  2523. * @readOnly
  2524. * @private
  2525. */
  2526. path: {
  2527. readOnly: true,
  2528. getter: function()
  2529. {
  2530. if(!this._path)
  2531. {
  2532. var graphic = this.get("graphic");
  2533. if(graphic)
  2534. {
  2535. this._path = graphic.addShape({type:"path"});
  2536. }
  2537. }
  2538. return this._path;
  2539. }
  2540. },
  2541. /**
  2542. * @attribute tickPath
  2543. * @type Shape
  2544. * @readOnly
  2545. * @private
  2546. */
  2547. tickPath: {
  2548. readOnly: true,
  2549. getter: function()
  2550. {
  2551. if(!this._tickPath)
  2552. {
  2553. var graphic = this.get("graphic");
  2554. if(graphic)
  2555. {
  2556. this._tickPath = graphic.addShape({type:"path"});
  2557. }
  2558. }
  2559. return this._tickPath;
  2560. }
  2561. },
  2562. /**
  2563. * Contains the contents of the axis.
  2564. *
  2565. * @attribute node
  2566. * @type HTMLElement
  2567. */
  2568. node: {},
  2569. /**
  2570. * Direction of the axis.
  2571. *
  2572. * @attribute position
  2573. * @type String
  2574. */
  2575. position: {
  2576. setOnce: true,
  2577. setter: function(val)
  2578. {
  2579. if(val == "none")
  2580. {
  2581. this.bindUI();
  2582. }
  2583. return val;
  2584. }
  2585. },
  2586. /**
  2587. * Distance determined by the tick styles used to calculate the distance between the axis
  2588. * line in relation to the top of the axis.
  2589. *
  2590. * @attribute topTickOffset
  2591. * @type Number
  2592. */
  2593. topTickOffset: {
  2594. value: 0
  2595. },
  2596. /**
  2597. * Distance determined by the tick styles used to calculate the distance between the axis
  2598. * line in relation to the bottom of the axis.
  2599. *
  2600. * @attribute bottomTickOffset
  2601. * @type Number
  2602. */
  2603. bottomTickOffset: {
  2604. value: 0
  2605. },
  2606. /**
  2607. * Distance determined by the tick styles used to calculate the distance between the axis
  2608. * line in relation to the left of the axis.
  2609. *
  2610. * @attribute leftTickOffset
  2611. * @type Number
  2612. */
  2613. leftTickOffset: {
  2614. value: 0
  2615. },
  2616. /**
  2617. * Distance determined by the tick styles used to calculate the distance between the axis
  2618. * line in relation to the right side of the axis.
  2619. *
  2620. * @attribute rightTickOffset
  2621. * @type Number
  2622. */
  2623. rightTickOffset: {
  2624. value: 0
  2625. },
  2626. /**
  2627. * Collection of labels used to render the axis.
  2628. *
  2629. * @attribute labels
  2630. * @type Array
  2631. */
  2632. labels: {
  2633. readOnly: true,
  2634. getter: function()
  2635. {
  2636. return this._labels;
  2637. }
  2638. },
  2639. /**
  2640. * Collection of points used for placement of labels and ticks along the axis.
  2641. *
  2642. * @attribute tickPoints
  2643. * @type Array
  2644. */
  2645. tickPoints: {
  2646. readOnly: true,
  2647. getter: function()
  2648. {
  2649. if(this.get("position") == "none")
  2650. {
  2651. return this.get("styles").majorUnit.count;
  2652. }
  2653. return this._tickPoints;
  2654. }
  2655. },
  2656. /**
  2657. * Indicates whether the axis overlaps the graph. If an axis is the inner most axis on a given
  2658. * position and the tick position is inside or cross, the axis will need to overlap the graph.
  2659. *
  2660. * @attribute overlapGraph
  2661. * @type Boolean
  2662. */
  2663. overlapGraph: {
  2664. value:true,
  2665. validator: function(val)
  2666. {
  2667. return Y_Lang.isBoolean(val);
  2668. }
  2669. },
  2670. /**
  2671. * Object which should have by the labelFunction
  2672. *
  2673. * @attribute labelFunctionScope
  2674. * @type Object
  2675. */
  2676. labelFunctionScope: {},
  2677. /**
  2678. * Length in pixels of largest text bounding box. Used to calculate the height of the axis.
  2679. *
  2680. * @attribute maxLabelSize
  2681. * @type Number
  2682. * @protected
  2683. */
  2684. maxLabelSize: {
  2685. value: 0
  2686. },
  2687. /**
  2688. * Title for the axis. When specified, the title will display. The position of the title is determined by the axis position.
  2689. * <dl>
  2690. * <dt>top</dt><dd>Appears above the axis and it labels. The default rotation is 0.</dd>
  2691. * <dt>right</dt><dd>Appears to the right of the axis and its labels. The default rotation is 90.</dd>
  2692. * <dt>bottom</dt><dd>Appears below the axis and its labels. The default rotation is 0.</dd>
  2693. * <dt>left</dt><dd>Appears to the left of the axis and its labels. The default rotation is -90.</dd>
  2694. * </dl>
  2695. *
  2696. * @attribute title
  2697. * @type String
  2698. */
  2699. title: {}
  2700. /**
  2701. * Style properties used for drawing an axis. This attribute is inherited from `Renderer`. Below are the default values:
  2702. * <dl>
  2703. * <dt>majorTicks</dt><dd>Properties used for drawing ticks.
  2704. * <dl>
  2705. * <dt>display</dt><dd>Position of the tick. Possible values are `inside`, `outside`, `cross` and `none`. The
  2706. * default value is `inside`.</dd>
  2707. * <dt>length</dt><dd>The length (in pixels) of the tick. The default value is 4.</dd>
  2708. * <dt>color</dt><dd>The color of the tick. The default value is `#dad8c9`</dd>
  2709. * <dt>weight</dt><dd>Number indicating the width of the tick. The default value is 1.</dd>
  2710. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
  2711. * </dl>
  2712. * </dd>
  2713. * <dt>line</dt><dd>Properties used for drawing the axis line.
  2714. * <dl>
  2715. * <dt>weight</dt><dd>Number indicating the width of the axis line. The default value is 1.</dd>
  2716. * <dt>color</dt><dd>The color of the axis line. The default value is `#dad8c9`.</dd>
  2717. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the tick. The default value is 1.</dd>
  2718. * </dl>
  2719. * </dd>
  2720. * <dt>majorUnit</dt><dd>Properties used to calculate the `majorUnit` for the axis.
  2721. * <dl>
  2722. * <dt>determinant</dt><dd>The algorithm used for calculating distance between ticks. The possible options are `count` and `distance`. If
  2723. * the `determinant` is `count`, the axis ticks will spaced so that a specified number of ticks appear on the axis. If the `determinant`
  2724. * is `distance`, the axis ticks will spaced out according to the specified distance. The default value is `count`.</dd>
  2725. * <dt>count</dt><dd>Number of ticks to appear on the axis when the `determinant` is `count`. The default value is 11.</dd>
  2726. * <dt>distance</dt><dd>The distance (in pixels) between ticks when the `determinant` is `distance`. The default value is 75.</dd>
  2727. * </dl>
  2728. * </dd>
  2729. * <dt>label</dt><dd>Properties and styles applied to the axis labels.
  2730. * <dl>
  2731. * <dt>color</dt><dd>The color of the labels. The default value is `#808080`.</dd>
  2732. * <dt>alpha</dt><dd>Number between 0 and 1 indicating the opacity of the labels. The default value is 1.</dd>
  2733. * <dt>fontSize</dt><dd>The font-size of the labels. The default value is 85%</dd>
  2734. * <dt>rotation</dt><dd>The rotation, in degrees (between -90 and 90) of the labels. The default value is 0.</dd>
  2735. * <dt>margin</dt><dd>The distance between the label and the axis/tick. Depending on the position of the `Axis`, only one of the properties used.
  2736. * <dl>
  2737. * <dt>top</dt><dd>Pixel value used for an axis with a `position` of `bottom`. The default value is 4.</dd>
  2738. * <dt>right</dt><dd>Pixel value used for an axis with a `position` of `left`. The default value is 4.</dd>
  2739. * <dt>bottom</dt><dd>Pixel value used for an axis with a `position` of `top`. The default value is 4.</dd>
  2740. * <dt>left</dt><dd>Pixel value used for an axis with a `position` of `right`. The default value is 4.</dd>
  2741. * </dl>
  2742. * </dd>
  2743. * </dl>
  2744. * </dd>
  2745. * </dl>
  2746. *
  2747. * @attribute styles
  2748. * @type Object
  2749. */
  2750. }
  2751. });
  2752. /**
  2753. * AxisType is an abstract class that manages the data for an axis.
  2754. *
  2755. * @module charts
  2756. * @class AxisType
  2757. * @constructor
  2758. * @extends Axis
  2759. */
  2760. Y.AxisType = Y.Base.create("baseAxis", Y.Axis, [], {
  2761. /**
  2762. * @method bindUI
  2763. * @private
  2764. */
  2765. bindUI: function()
  2766. {
  2767. this.after("dataReady", Y.bind(this._dataChangeHandler, this));
  2768. this.after("dataUpdate", Y.bind(this._dataChangeHandler, this));
  2769. this.after("minimumChange", Y.bind(this._keyChangeHandler, this));
  2770. this.after("maximumChange", Y.bind(this._keyChangeHandler, this));
  2771. this.after("keysChange", this._keyChangeHandler);
  2772. this.after("dataProviderChange", this._dataProviderChangeHandler);
  2773. this.after("stylesChange", this._updateHandler);
  2774. this.after("positionChange", this._positionChangeHandler);
  2775. this.after("overlapGraphChange", this._updateHandler);
  2776. this.after("widthChange", this._handleSizeChange);
  2777. this.after("heightChange", this._handleSizeChange);
  2778. this.after("alwaysShowZeroChange", this._keyChangeHandler);
  2779. this.after("roundingMethodChange", this._keyChangeHandler);
  2780. },
  2781. /**
  2782. * Handles changes to `dataProvider`.
  2783. *
  2784. * @method _dataProviderChangeHandler
  2785. * @param {Object} e Event object.
  2786. * @private
  2787. */
  2788. _dataProviderChangeHandler: function(e)
  2789. {
  2790. var keyCollection = this.get("keyCollection").concat(),
  2791. keys = this.get("keys"),
  2792. i;
  2793. if(keys)
  2794. {
  2795. for(i in keys)
  2796. {
  2797. if(keys.hasOwnProperty(i))
  2798. {
  2799. delete keys[i];
  2800. }
  2801. }
  2802. }
  2803. if(keyCollection && keyCollection.length)
  2804. {
  2805. this.set("keys", keyCollection);
  2806. }
  2807. },
  2808. /**
  2809. * Constant used to generate unique id.
  2810. *
  2811. * @property GUID
  2812. * @type String
  2813. * @private
  2814. */
  2815. GUID: "yuibaseaxis",
  2816. /**
  2817. * Type of data used in `Axis`.
  2818. *
  2819. * @property _type
  2820. * @type String
  2821. * @readOnly
  2822. * @private
  2823. */
  2824. _type: null,
  2825. /**
  2826. * Storage for `setMaximum` attribute.
  2827. *
  2828. * @property _setMaximum
  2829. * @type Object
  2830. * @private
  2831. */
  2832. _setMaximum: null,
  2833. /**
  2834. * Storage for `dataMaximum` attribute.
  2835. *
  2836. * @property _dataMaximum
  2837. * @type Object
  2838. * @private
  2839. */
  2840. _dataMaximum: null,
  2841. /**
  2842. * Storage for `setMinimum` attribute.
  2843. *
  2844. * @property _setMinimum
  2845. * @type Object
  2846. * @private
  2847. */
  2848. _setMinimum: null,
  2849. /**
  2850. * Reference to data array.
  2851. *
  2852. * @property _data
  2853. * @type Array
  2854. * @private
  2855. */
  2856. _data: null,
  2857. /**
  2858. * Indicates whether the all data is up to date.
  2859. *
  2860. * @property _updateTotalDataFlag
  2861. * @type Boolean
  2862. * @private
  2863. */
  2864. _updateTotalDataFlag: true,
  2865. /**
  2866. * Storage for `dataReady` attribute.
  2867. *
  2868. * @property _dataReady
  2869. * @type Boolean
  2870. * @readOnly
  2871. * @private
  2872. */
  2873. _dataReady: false,
  2874. /**
  2875. * Adds an array to the key hash.
  2876. *
  2877. * @method addKey
  2878. * @param value Indicates what key to use in retrieving
  2879. * the array.
  2880. */
  2881. addKey: function (value)
  2882. {
  2883. this.set("keys", value);
  2884. },
  2885. /**
  2886. * Gets an array of values based on a key.
  2887. *
  2888. * @method _getKeyArray
  2889. * @param {String} key Value key associated with the data array.
  2890. * @param {Array} data Array in which the data resides.
  2891. * @return Array
  2892. * @private
  2893. */
  2894. _getKeyArray: function(key, data)
  2895. {
  2896. var i = 0,
  2897. obj,
  2898. keyArray = [],
  2899. len = data.length;
  2900. for(; i < len; ++i)
  2901. {
  2902. obj = data[i];
  2903. keyArray[i] = obj[key];
  2904. }
  2905. return keyArray;
  2906. },
  2907. /**
  2908. * Sets data by key
  2909. *
  2910. * @method _setDataByKey
  2911. * @param {String} key Key value to use.
  2912. * @param {Array} data Array to use.
  2913. * @private
  2914. */
  2915. _setDataByKey: function(key, data)
  2916. {
  2917. var i,
  2918. obj,
  2919. arr = [],
  2920. dv = this._dataClone.concat(),
  2921. len = dv.length;
  2922. for(i = 0; i < len; ++i)
  2923. {
  2924. obj = dv[i];
  2925. arr[i] = obj[key];
  2926. }
  2927. this.get("keys")[key] = arr;
  2928. this._updateTotalDataFlag = true;
  2929. },
  2930. /**
  2931. * Updates the total data array.
  2932. *
  2933. * @method _updateTotalData
  2934. * @private
  2935. */
  2936. _updateTotalData: function()
  2937. {
  2938. var keys = this.get("keys"),
  2939. i;
  2940. this._data = [];
  2941. for(i in keys)
  2942. {
  2943. if(keys.hasOwnProperty(i))
  2944. {
  2945. this._data = this._data.concat(keys[i]);
  2946. }
  2947. }
  2948. this._updateTotalDataFlag = false;
  2949. },
  2950. /**
  2951. * Removes an array from the key hash.
  2952. *
  2953. * @method removeKey
  2954. * @param {String} value Indicates what key to use in removing from
  2955. * the hash.
  2956. */
  2957. removeKey: function(value)
  2958. {
  2959. var keys = this.get("keys");
  2960. if(keys.hasOwnProperty(value))
  2961. {
  2962. delete keys[value];
  2963. this._keyChangeHandler();
  2964. }
  2965. },
  2966. /**
  2967. * Returns a value based of a key value and an index.
  2968. *
  2969. * @method getKeyValueAt
  2970. * @param {String} key value used to look up the correct array
  2971. * @param {Number} index within the array
  2972. * @return Object
  2973. */
  2974. getKeyValueAt: function(key, index)
  2975. {
  2976. var value = NaN,
  2977. keys = this.get("keys");
  2978. if(keys[key] && keys[key][index])
  2979. {
  2980. value = keys[key][index];
  2981. }
  2982. return value;
  2983. },
  2984. /**
  2985. * Returns an array of values based on an identifier key.
  2986. *
  2987. * @method getDataByKey
  2988. * @param {String} value value used to identify the array
  2989. * @return Object
  2990. */
  2991. getDataByKey: function (value)
  2992. {
  2993. var keys = this.get("keys");
  2994. if(keys[value])
  2995. {
  2996. return keys[value];
  2997. }
  2998. return null;
  2999. },
  3000. /**
  3001. * Calculates the maximum and minimum values for the `Axis`.
  3002. *
  3003. * @method _updateMinAndMax
  3004. * @private
  3005. */
  3006. _updateMinAndMax: function()
  3007. {
  3008. var data = this.get("data"),
  3009. max = 0,
  3010. min = 0,
  3011. len,
  3012. num,
  3013. i;
  3014. if(data && data.length && data.length > 0)
  3015. {
  3016. len = data.length;
  3017. max = min = data[0];
  3018. if(len > 1)
  3019. {
  3020. for(i = 1; i < len; i++)
  3021. {
  3022. num = data[i];
  3023. if(isNaN(num))
  3024. {
  3025. continue;
  3026. }
  3027. max = Math.max(num, max);
  3028. min = Math.min(num, min);
  3029. }
  3030. }
  3031. }
  3032. this._dataMaximum = max;
  3033. this._dataMinimum = min;
  3034. },
  3035. /**
  3036. * Returns the total number of majorUnits that will appear on an axis.
  3037. *
  3038. * @method getTotalMajorUnits
  3039. * @return Number
  3040. */
  3041. getTotalMajorUnits: function()
  3042. {
  3043. var units,
  3044. majorUnit = this.get("styles").majorUnit,
  3045. len = this.get("length");
  3046. if(majorUnit.determinant === "count")
  3047. {
  3048. units = majorUnit.count;
  3049. }
  3050. else if(majorUnit.determinant === "distance")
  3051. {
  3052. units = (len/majorUnit.distance) + 1;
  3053. }
  3054. return units;
  3055. },
  3056. /**
  3057. * Returns the distance between major units on an axis.
  3058. *
  3059. * @method getMajorUnitDistance
  3060. * @param {Number} len Number of ticks
  3061. * @param {Number} uiLen Size of the axis.
  3062. * @param {Object} majorUnit Hash of properties used to determine the majorUnit
  3063. * @return Number
  3064. */
  3065. getMajorUnitDistance: function(len, uiLen, majorUnit)
  3066. {
  3067. var dist;
  3068. if(majorUnit.determinant === "count")
  3069. {
  3070. dist = uiLen/(len - 1);
  3071. }
  3072. else if(majorUnit.determinant === "distance")
  3073. {
  3074. dist = majorUnit.distance;
  3075. }
  3076. return dist;
  3077. },
  3078. /**
  3079. * Gets the distance that the first and last ticks are offset from there respective
  3080. * edges.
  3081. *
  3082. * @method getEdgeOffset
  3083. * @param {Number} ct Number of ticks on the axis.
  3084. * @param {Number} l Length (in pixels) of the axis.
  3085. * @return Number
  3086. */
  3087. getEdgeOffset: function(ct, l)
  3088. {
  3089. return 0;
  3090. },
  3091. /**
  3092. * Calculates and returns a value based on the number of labels and the index of
  3093. * the current label.
  3094. *
  3095. * @method getLabelByIndex
  3096. * @param {Number} i Index of the label.
  3097. * @param {Number} l Total number of labels.
  3098. * @return String
  3099. */
  3100. getLabelByIndex: function(i, l)
  3101. {
  3102. var min = this.get("minimum"),
  3103. max = this.get("maximum"),
  3104. increm = (max - min)/(l-1),
  3105. label;
  3106. l -= 1;
  3107. label = min + (i * increm);
  3108. return label;
  3109. },
  3110. /**
  3111. * Updates the `Axis` after a change in keys.
  3112. *
  3113. * @method _keyChangeHandler
  3114. * @param {Object} e Event object.
  3115. * @private
  3116. */
  3117. _keyChangeHandler: function(e)
  3118. {
  3119. this._updateMinAndMax();
  3120. this.fire("dataUpdate");
  3121. },
  3122. /**
  3123. * Checks to see if data extends beyond the range of the axis. If so,
  3124. * that data will need to be hidden. This method is internal, temporary and subject
  3125. * to removal in the future.
  3126. *
  3127. * @method _hasDataOverflow
  3128. * @protected
  3129. * @return Boolean
  3130. */
  3131. _hasDataOverflow: function()
  3132. {
  3133. if(this.get("setMin") || this.get("setMax"))
  3134. {
  3135. return true;
  3136. }
  3137. return false;
  3138. }
  3139. }, {
  3140. ATTRS: {
  3141. /**
  3142. * Hash of array identifed by a string value.
  3143. *
  3144. * @attribute keys
  3145. * @type Object
  3146. */
  3147. keys: {
  3148. value: {},
  3149. setter: function(val)
  3150. {
  3151. var keys = {},
  3152. i,
  3153. len,
  3154. data = this.get("dataProvider");
  3155. if(Y_Lang.isArray(val))
  3156. {
  3157. len = val.length;
  3158. for(i = 0; i < len; ++i)
  3159. {
  3160. keys[val[i]] = this._getKeyArray(val[i], data);
  3161. }
  3162. }
  3163. else if(Y_Lang.isString(val))
  3164. {
  3165. keys = this.get("keys");
  3166. keys[val] = this._getKeyArray(val, data);
  3167. }
  3168. else
  3169. {
  3170. for(i in val)
  3171. {
  3172. if(val.hasOwnProperty(i))
  3173. {
  3174. keys[i] = this._getKeyArray(i, data);
  3175. }
  3176. }
  3177. }
  3178. this._updateTotalDataFlag = true;
  3179. return keys;
  3180. }
  3181. },
  3182. /**
  3183. *Indicates how to round unit values.
  3184. * <dl>
  3185. * <dt>niceNumber</dt><dd>Units will be smoothed based on the number of ticks and data range.</dd>
  3186. * <dt>auto</dt><dd>If the range is greater than 1, the units will be rounded.</dd>
  3187. * <dt>numeric value</dt><dd>Units will be equal to the numeric value.</dd>
  3188. * <dt>null</dt><dd>No rounding will occur.</dd>
  3189. * </dl>
  3190. *
  3191. * @attribute roundingMethod
  3192. * @type String
  3193. * @default niceNumber
  3194. */
  3195. roundingMethod: {
  3196. value: "niceNumber"
  3197. },
  3198. /**
  3199. *Returns the type of axis data
  3200. * <dl>
  3201. * <dt>time</dt><dd>Manages time data</dd>
  3202. * <dt>stacked</dt><dd>Manages stacked numeric data</dd>
  3203. * <dt>numeric</dt><dd>Manages numeric data</dd>
  3204. * <dt>category</dt><dd>Manages categorical data</dd>
  3205. * </dl>
  3206. *
  3207. * @attribute type
  3208. * @type String
  3209. */
  3210. type:
  3211. {
  3212. readOnly: true,
  3213. getter: function ()
  3214. {
  3215. return this._type;
  3216. }
  3217. },
  3218. /**
  3219. * Instance of `ChartDataProvider` that the class uses
  3220. * to build its own data.
  3221. *
  3222. * @attribute dataProvider
  3223. * @type Array
  3224. */
  3225. dataProvider:{
  3226. setter: function (value)
  3227. {
  3228. return value;
  3229. }
  3230. },
  3231. /**
  3232. * The maximum value contained in the `data` array. Used for
  3233. * `maximum` when `autoMax` is true.
  3234. *
  3235. * @attribute dataMaximum
  3236. * @type Number
  3237. */
  3238. dataMaximum: {
  3239. getter: function ()
  3240. {
  3241. if(!this._dataMaximum)
  3242. {
  3243. this._updateMinAndMax();
  3244. }
  3245. return this._dataMaximum;
  3246. }
  3247. },
  3248. /**
  3249. * The maximum value that will appear on an axis.
  3250. *
  3251. * @attribute maximum
  3252. * @type Number
  3253. */
  3254. maximum: {
  3255. lazyAdd: false,
  3256. getter: function ()
  3257. {
  3258. var max = this.get("dataMaximum"),
  3259. min = this.get("minimum");
  3260. //If all values are zero, force a range so that the Axis and related series
  3261. //will still render.
  3262. if(min === 0 && max === 0)
  3263. {
  3264. max = 10;
  3265. }
  3266. if(Y_Lang.isNumber(this._setMaximum))
  3267. {
  3268. max = this._setMaximum;
  3269. }
  3270. return max;
  3271. },
  3272. setter: function (value)
  3273. {
  3274. this._setMaximum = parseFloat(value);
  3275. return value;
  3276. }
  3277. },
  3278. /**
  3279. * The minimum value contained in the `data` array. Used for
  3280. * `minimum` when `autoMin` is true.
  3281. *
  3282. * @attribute dataMinimum
  3283. * @type Number
  3284. */
  3285. dataMinimum: {
  3286. getter: function ()
  3287. {
  3288. if(!this._dataMinimum)
  3289. {
  3290. this._updateMinAndMax();
  3291. }
  3292. return this._dataMinimum;
  3293. }
  3294. },
  3295. /**
  3296. * The minimum value that will appear on an axis.
  3297. *
  3298. * @attribute minimum
  3299. * @type Number
  3300. */
  3301. minimum: {
  3302. lazyAdd: false,
  3303. getter: function ()
  3304. {
  3305. var min = this.get("dataMinimum");
  3306. if(Y_Lang.isNumber(this._setMinimum))
  3307. {
  3308. min = this._setMinimum;
  3309. }
  3310. return min;
  3311. },
  3312. setter: function(val)
  3313. {
  3314. this._setMinimum = parseFloat(val);
  3315. return val;
  3316. }
  3317. },
  3318. /**
  3319. * Determines whether the maximum is calculated or explicitly
  3320. * set by the user.
  3321. *
  3322. * @attribute setMax
  3323. * @type Boolean
  3324. */
  3325. setMax: {
  3326. readOnly: true,
  3327. getter: function()
  3328. {
  3329. return Y_Lang.isNumber(this._setMaximum);
  3330. }
  3331. },
  3332. /**
  3333. * Determines whether the minimum is calculated or explicitly
  3334. * set by the user.
  3335. *
  3336. * @attribute setMin
  3337. * @type Boolean
  3338. */
  3339. setMin: {
  3340. readOnly: true,
  3341. getter: function()
  3342. {
  3343. return Y_Lang.isNumber(this._setMinimum);
  3344. }
  3345. },
  3346. /**
  3347. * Array of axis data
  3348. *
  3349. * @attribute data
  3350. * @type Array
  3351. */
  3352. data: {
  3353. getter: function ()
  3354. {
  3355. if(!this._data || this._updateTotalDataFlag)
  3356. {
  3357. this._updateTotalData();
  3358. }
  3359. return this._data;
  3360. }
  3361. },
  3362. /**
  3363. * Array containing all the keys in the axis.
  3364. * @attribute keyCollection
  3365. * @type Array
  3366. */
  3367. keyCollection: {
  3368. getter: function()
  3369. {
  3370. var keys = this.get("keys"),
  3371. i,
  3372. col = [];
  3373. for(i in keys)
  3374. {
  3375. if(keys.hasOwnProperty(i))
  3376. {
  3377. col.push(i);
  3378. }
  3379. }
  3380. return col;
  3381. },
  3382. readOnly: true
  3383. },
  3384. /**
  3385. * Method used for formatting a label. This attribute allows for the default label formatting method to overridden. The method use would need
  3386. * to implement the arguments below and return a `String`.
  3387. * <dl>
  3388. * <dt>val</dt><dd>Label to be formatted. (`String`)</dd>
  3389. * <dt>format</dt><dd>Template for formatting label. (optional)</dd>
  3390. * </dl>
  3391. *
  3392. * @attribute labelFunction
  3393. * @type Function
  3394. */
  3395. labelFunction: {
  3396. value: function(val, format)
  3397. {
  3398. return val;
  3399. }
  3400. }
  3401. }
  3402. });
  3403. /**
  3404. * NumericAxis manages numeric data on an axis.
  3405. *
  3406. * @module charts
  3407. * @class NumericAxis
  3408. * @constructor
  3409. * @param {Object} config (optional) Configuration parameters for the Chart.
  3410. * @extends AxisType
  3411. */
  3412. function NumericAxis(config)
  3413. {
  3414. NumericAxis.superclass.constructor.apply(this, arguments);
  3415. }
  3416. NumericAxis.NAME = "numericAxis";
  3417. NumericAxis.ATTRS = {
  3418. /**
  3419. * Indicates whether 0 should always be displayed.
  3420. *
  3421. * @attribute alwaysShowZero
  3422. * @type Boolean
  3423. */
  3424. alwaysShowZero: {
  3425. value: true
  3426. },
  3427. /**
  3428. * Method used for formatting a label. This attribute allows for the default label formatting method to overridden. The method use would need
  3429. * to implement the arguments below and return a `String`.
  3430. * <dl>
  3431. * <dt>val</dt><dd>Label to be formatted. (`String`)</dd>
  3432. * <dt>format</dt><dd>Object containing properties used to format the label. (optional)</dd>
  3433. * </dl>
  3434. *
  3435. * @attribute labelFunction
  3436. * @type Function
  3437. */
  3438. labelFunction: {
  3439. value: function(val, format)
  3440. {
  3441. if(format)
  3442. {
  3443. return Y.DataType.Number.format(val, format);
  3444. }
  3445. return val;
  3446. }
  3447. },
  3448. /**
  3449. * Object containing properties used by the `labelFunction` to format a
  3450. * label.
  3451. *
  3452. * @attribute labelFormat
  3453. * @type Object
  3454. */
  3455. labelFormat: {
  3456. value: {
  3457. prefix: "",
  3458. thousandsSeparator: "",
  3459. decimalSeparator: "",
  3460. decimalPlaces: "0",
  3461. suffix: ""
  3462. }
  3463. }
  3464. };
  3465. Y.extend(NumericAxis, Y.AxisType,
  3466. {
  3467. /**
  3468. * Type of data used in `Axis`.
  3469. *
  3470. * @property _type
  3471. * @readOnly
  3472. * @private
  3473. */
  3474. _type: "numeric",
  3475. /**
  3476. * Returns a value based of a key value and an index.
  3477. *
  3478. * @method getKeyValueAt
  3479. * @param {String} key value used to look up the correct array
  3480. * @param {Number} index within the array
  3481. * @return Object
  3482. */
  3483. getKeyValueAt: function(key, index)
  3484. {
  3485. var value = NaN,
  3486. keys = this.get("keys");
  3487. if(keys[key] && Y_Lang.isNumber(parseFloat(keys[key][index])))
  3488. {
  3489. value = keys[key][index];
  3490. }
  3491. return value;
  3492. },
  3493. /**
  3494. * Helper method for getting a `roundingUnit` when calculating the minimum and maximum values.
  3495. *
  3496. * @method _getMinimumUnit
  3497. * @param {Number} max Maximum number
  3498. * @param {Number} min Minimum number
  3499. * @param {Number} units Number of units on the axis
  3500. * @return Number
  3501. * @private
  3502. */
  3503. _getMinimumUnit:function(max, min, units)
  3504. {
  3505. return this._getNiceNumber(Math.ceil((max - min)/units));
  3506. },
  3507. /**
  3508. * Calculates a nice rounding unit based on the range.
  3509. *
  3510. * @method _getNiceNumber
  3511. * @param {Number} roundingUnit The calculated rounding unit.
  3512. * @return Number
  3513. * @private
  3514. */
  3515. _getNiceNumber: function(roundingUnit)
  3516. {
  3517. var tempMajorUnit = roundingUnit,
  3518. order = Math.ceil(Math.log(tempMajorUnit) * 0.4342944819032518),
  3519. roundedMajorUnit = Math.pow(10, order),
  3520. roundedDiff;
  3521. if (roundedMajorUnit / 2 >= tempMajorUnit)
  3522. {
  3523. roundedDiff = Math.floor((roundedMajorUnit / 2 - tempMajorUnit) / (Math.pow(10,order-1)/2));
  3524. tempMajorUnit = roundedMajorUnit/2 - roundedDiff*Math.pow(10,order-1)/2;
  3525. }
  3526. else
  3527. {
  3528. tempMajorUnit = roundedMajorUnit;
  3529. }
  3530. if(!isNaN(tempMajorUnit))
  3531. {
  3532. return tempMajorUnit;
  3533. }
  3534. return roundingUnit;
  3535. },
  3536. /**
  3537. * Calculates the maximum and minimum values for the `Axis`.
  3538. *
  3539. * @method _updateMinAndMax
  3540. * @private
  3541. */
  3542. _updateMinAndMax: function()
  3543. {
  3544. var data = this.get("data"),
  3545. max = 0,
  3546. min = 0,
  3547. len,
  3548. num,
  3549. i = 0,
  3550. key,
  3551. setMax = this.get("setMax"),
  3552. setMin = this.get("setMin");
  3553. if(!setMax || !setMin)
  3554. {
  3555. if(data && data.length && data.length > 0)
  3556. {
  3557. len = data.length;
  3558. for(; i < len; i++)
  3559. {
  3560. num = data[i];
  3561. if(isNaN(num))
  3562. {
  3563. if(Y_Lang.isObject(num))
  3564. {
  3565. min = max = 0;
  3566. //hloc values
  3567. for(key in num)
  3568. {
  3569. if(num.hasOwnProperty(key))
  3570. {
  3571. max = Math.max(num[key], max);
  3572. min = Math.min(num[key], min);
  3573. }
  3574. }
  3575. }
  3576. max = setMax ? this._setMaximum : max;
  3577. min = setMin ? this._setMinimum : min;
  3578. continue;
  3579. }
  3580. max = setMax ? this._setMaximum : Math.max(num, max);
  3581. min = setMin ? this._setMinimum : Math.min(num, min);
  3582. this._actualMaximum = max;
  3583. this._actualMinimum = min;
  3584. }
  3585. }
  3586. this._roundMinAndMax(min, max, setMin, setMax);
  3587. }
  3588. },
  3589. /**
  3590. * Rounds the mimimum and maximum values based on the `roundingUnit` attribute.
  3591. *
  3592. * @method _roundMinAndMax
  3593. * @param {Number} min Minimum value
  3594. * @param {Number} max Maximum value
  3595. * @private
  3596. */
  3597. _roundMinAndMax: function(min, max, setMin, setMax)
  3598. {
  3599. var roundingUnit,
  3600. minimumRange,
  3601. minGreaterThanZero = min >= 0,
  3602. maxGreaterThanZero = max > 0,
  3603. dataRangeGreater,
  3604. maxRound,
  3605. minRound,
  3606. topTicks,
  3607. botTicks,
  3608. tempMax,
  3609. tempMin,
  3610. units = this.getTotalMajorUnits() - 1,
  3611. alwaysShowZero = this.get("alwaysShowZero"),
  3612. roundingMethod = this.get("roundingMethod"),
  3613. useIntegers = (max - min)/units >= 1;
  3614. if(roundingMethod)
  3615. {
  3616. if(roundingMethod == "niceNumber")
  3617. {
  3618. roundingUnit = this._getMinimumUnit(max, min, units);
  3619. if(minGreaterThanZero && maxGreaterThanZero)
  3620. {
  3621. if((alwaysShowZero || min < roundingUnit) && !setMin)
  3622. {
  3623. min = 0;
  3624. roundingUnit = this._getMinimumUnit(max, min, units);
  3625. }
  3626. else
  3627. {
  3628. min = this._roundDownToNearest(min, roundingUnit);
  3629. }
  3630. if(setMax)
  3631. {
  3632. if(!alwaysShowZero)
  3633. {
  3634. min = max - (roundingUnit * units);
  3635. }
  3636. }
  3637. else if(setMin)
  3638. {
  3639. max = min + (roundingUnit * units);
  3640. }
  3641. else
  3642. {
  3643. max = this._roundUpToNearest(max, roundingUnit);
  3644. }
  3645. }
  3646. else if(maxGreaterThanZero && !minGreaterThanZero)
  3647. {
  3648. if(alwaysShowZero)
  3649. {
  3650. topTicks = Math.round(units/((-1 * min)/max + 1));
  3651. topTicks = Math.max(Math.min(topTicks, units - 1), 1);
  3652. botTicks = units - topTicks;
  3653. tempMax = Math.ceil( max/topTicks );
  3654. tempMin = Math.floor( min/botTicks ) * -1;
  3655. if(setMin)
  3656. {
  3657. while(tempMin < tempMax && botTicks >= 0)
  3658. {
  3659. botTicks--;
  3660. topTicks++;
  3661. tempMax = Math.ceil( max/topTicks );
  3662. tempMin = Math.floor( min/botTicks ) * -1;
  3663. }
  3664. //if there are any bottom ticks left calcualate the maximum by multiplying by the tempMin value
  3665. //if not, it's impossible to ensure that a zero is shown. skip it
  3666. if(botTicks > 0)
  3667. {
  3668. max = tempMin * topTicks;
  3669. }
  3670. else
  3671. {
  3672. max = min + (roundingUnit * units);
  3673. }
  3674. }
  3675. else if(setMax)
  3676. {
  3677. while(tempMax < tempMin && topTicks >= 0)
  3678. {
  3679. botTicks++;
  3680. topTicks--;
  3681. tempMin = Math.floor( min/botTicks ) * -1;
  3682. tempMax = Math.ceil( max/topTicks );
  3683. }
  3684. //if there are any top ticks left calcualate the minimum by multiplying by the tempMax value
  3685. //if not, it's impossible to ensure that a zero is shown. skip it
  3686. if(topTicks > 0)
  3687. {
  3688. min = tempMax * botTicks * -1;
  3689. }
  3690. else
  3691. {
  3692. min = max - (roundingUnit * units);
  3693. }
  3694. }
  3695. else
  3696. {
  3697. roundingUnit = Math.max(tempMax, tempMin);
  3698. roundingUnit = this._getNiceNumber(roundingUnit);
  3699. max = roundingUnit * topTicks;
  3700. min = roundingUnit * botTicks * -1;
  3701. }
  3702. }
  3703. else
  3704. {
  3705. if(setMax)
  3706. {
  3707. min = max - (roundingUnit * units);
  3708. }
  3709. else if(setMin)
  3710. {
  3711. max = min + (roundingUnit * units);
  3712. }
  3713. else
  3714. {
  3715. min = this._roundDownToNearest(min, roundingUnit);
  3716. max = this._roundUpToNearest(max, roundingUnit);
  3717. }
  3718. }
  3719. }
  3720. else
  3721. {
  3722. if(setMin)
  3723. {
  3724. if(alwaysShowZero)
  3725. {
  3726. max = 0;
  3727. }
  3728. else
  3729. {
  3730. max = min + (roundingUnit * units);
  3731. }
  3732. }
  3733. else if(!setMax)
  3734. {
  3735. if(alwaysShowZero || max === 0 || max + roundingUnit > 0)
  3736. {
  3737. max = 0;
  3738. roundingUnit = this._getMinimumUnit(max, min, units);
  3739. }
  3740. else
  3741. {
  3742. max = this._roundUpToNearest(max, roundingUnit);
  3743. }
  3744. min = max - (roundingUnit * units);
  3745. }
  3746. else
  3747. {
  3748. min = max - (roundingUnit * units);
  3749. }
  3750. }
  3751. }
  3752. else if(roundingMethod == "auto")
  3753. {
  3754. if(minGreaterThanZero && maxGreaterThanZero)
  3755. {
  3756. if((alwaysShowZero || min < (max-min)/units) && !setMin)
  3757. {
  3758. min = 0;
  3759. }
  3760. roundingUnit = (max - min)/units;
  3761. if(useIntegers)
  3762. {
  3763. roundingUnit = Math.ceil(roundingUnit);
  3764. }
  3765. max = min + (roundingUnit * units);
  3766. }
  3767. else if(maxGreaterThanZero && !minGreaterThanZero)
  3768. {
  3769. if(alwaysShowZero)
  3770. {
  3771. topTicks = Math.round( units / ( (-1 * min) /max + 1) );
  3772. topTicks = Math.max(Math.min(topTicks, units - 1), 1);
  3773. botTicks = units - topTicks;
  3774. if(useIntegers)
  3775. {
  3776. tempMax = Math.ceil( max/topTicks );
  3777. tempMin = Math.floor( min/botTicks ) * -1;
  3778. }
  3779. else
  3780. {
  3781. tempMax = max/topTicks;
  3782. tempMin = min/botTicks * -1;
  3783. }
  3784. roundingUnit = Math.max(tempMax, tempMin);
  3785. max = roundingUnit * topTicks;
  3786. min = roundingUnit * botTicks * -1;
  3787. }
  3788. else
  3789. {
  3790. roundingUnit = (max - min)/units;
  3791. if(useIntegers)
  3792. {
  3793. roundingUnit = Math.ceil(roundingUnit);
  3794. }
  3795. min = this._roundDownToNearest(min, roundingUnit);
  3796. max = this._roundUpToNearest(max, roundingUnit);
  3797. }
  3798. }
  3799. else
  3800. {
  3801. roundingUnit = (max - min)/units;
  3802. if(useIntegers)
  3803. {
  3804. roundingUnit = Math.ceil(roundingUnit);
  3805. }
  3806. if(alwaysShowZero || max === 0 || max + roundingUnit > 0)
  3807. {
  3808. max = 0;
  3809. roundingUnit = (max - min)/units;
  3810. if(useIntegers)
  3811. {
  3812. Math.ceil(roundingUnit);
  3813. }
  3814. }
  3815. else
  3816. {
  3817. max = this._roundUpToNearest(max, roundingUnit);
  3818. }
  3819. min = max - (roundingUnit * units);
  3820. }
  3821. }
  3822. else if(!isNaN(roundingMethod) && isFinite(roundingMethod))
  3823. {
  3824. roundingUnit = roundingMethod;
  3825. minimumRange = roundingUnit * units;
  3826. dataRangeGreater = (max - min) > minimumRange;
  3827. minRound = this._roundDownToNearest(min, roundingUnit);
  3828. maxRound = this._roundUpToNearest(max, roundingUnit);
  3829. if(setMax)
  3830. {
  3831. min = max - minimumRange;
  3832. }
  3833. else if(setMin)
  3834. {
  3835. max = min + minimumRange;
  3836. }
  3837. else if(minGreaterThanZero && maxGreaterThanZero)
  3838. {
  3839. if(alwaysShowZero || minRound <= 0)
  3840. {
  3841. min = 0;
  3842. }
  3843. else
  3844. {
  3845. min = minRound;
  3846. }
  3847. max = min + minimumRange;
  3848. }
  3849. else if(maxGreaterThanZero && !minGreaterThanZero)
  3850. {
  3851. min = minRound;
  3852. max = min + minimumRange;
  3853. }
  3854. else
  3855. {
  3856. if(alwaysShowZero || maxRound >= 0)
  3857. {
  3858. max = 0;
  3859. }
  3860. else
  3861. {
  3862. max = maxRound;
  3863. }
  3864. min = max - minimumRange;
  3865. }
  3866. }
  3867. }
  3868. this._dataMaximum = max;
  3869. this._dataMinimum = min;
  3870. },
  3871. /**
  3872. * Calculates and returns a value based on the number of labels and the index of
  3873. * the current label.
  3874. *
  3875. * @method getLabelByIndex
  3876. * @param {Number} i Index of the label.
  3877. * @param {Number} l Total number of labels.
  3878. * @return String
  3879. */
  3880. getLabelByIndex: function(i, l)
  3881. {
  3882. var min = this.get("minimum"),
  3883. max = this.get("maximum"),
  3884. increm = (max - min)/(l-1),
  3885. label,
  3886. roundingMethod = this.get("roundingMethod");
  3887. l -= 1;
  3888. //respect the min and max. calculate all other labels.
  3889. if(i === 0)
  3890. {
  3891. label = min;
  3892. }
  3893. else if(i === l)
  3894. {
  3895. label = max;
  3896. }
  3897. else
  3898. {
  3899. label = (i * increm);
  3900. if(this.get("roundingMethod") == "niceNumber")
  3901. {
  3902. label = this._roundToNearest(label, increm);
  3903. }
  3904. label += min;
  3905. }
  3906. return label;
  3907. },
  3908. /**
  3909. * Rounds a Number to the nearest multiple of an input. For example, by rounding
  3910. * 16 to the nearest 10, you will receive 20. Similar to the built-in function Math.round().
  3911. *
  3912. * @method _roundToNearest
  3913. * @param {Number} number Number to round
  3914. * @param {Number} nearest Multiple to round towards.
  3915. * @return Number
  3916. * @private
  3917. */
  3918. _roundToNearest: function(number, nearest)
  3919. {
  3920. nearest = nearest || 1;
  3921. if(nearest === 0)
  3922. {
  3923. return number;
  3924. }
  3925. var roundedNumber = Math.round(this._roundToPrecision(number / nearest, 10)) * nearest;
  3926. return this._roundToPrecision(roundedNumber, 10);
  3927. },
  3928. /**
  3929. * Rounds a Number up to the nearest multiple of an input. For example, by rounding
  3930. * 16 up to the nearest 10, you will receive 20. Similar to the built-in function Math.ceil().
  3931. *
  3932. * @method _roundUpToNearest
  3933. * @param {Number} number Number to round
  3934. * @param {Number} nearest Multiple to round towards.
  3935. * @return Number
  3936. * @private
  3937. */
  3938. _roundUpToNearest: function(number, nearest)
  3939. {
  3940. nearest = nearest || 1;
  3941. if(nearest === 0)
  3942. {
  3943. return number;
  3944. }
  3945. return Math.ceil(this._roundToPrecision(number / nearest, 10)) * nearest;
  3946. },
  3947. /**
  3948. * Rounds a Number down to the nearest multiple of an input. For example, by rounding
  3949. * 16 down to the nearest 10, you will receive 10. Similar to the built-in function Math.floor().
  3950. *
  3951. * @method _roundDownToNearest
  3952. * @param {Number} number Number to round
  3953. * @param {Number} nearest Multiple to round towards.
  3954. * @return Number
  3955. * @private
  3956. */
  3957. _roundDownToNearest: function(number, nearest)
  3958. {
  3959. nearest = nearest || 1;
  3960. if(nearest === 0)
  3961. {
  3962. return number;
  3963. }
  3964. return Math.floor(this._roundToPrecision(number / nearest, 10)) * nearest;
  3965. },
  3966. /**
  3967. * Rounds a number to a certain level of precision. Useful for limiting the number of
  3968. * decimal places on a fractional number.
  3969. *
  3970. * @method _roundToPrecision
  3971. * @param {Number} number Number to round
  3972. * @param {Number} precision Multiple to round towards.
  3973. * @return Number
  3974. * @private
  3975. */
  3976. _roundToPrecision: function(number, precision)
  3977. {
  3978. precision = precision || 0;
  3979. var decimalPlaces = Math.pow(10, precision);
  3980. return Math.round(decimalPlaces * number) / decimalPlaces;
  3981. },
  3982. /**
  3983. * Checks to see if data extends beyond the range of the axis. If so,
  3984. * that data will need to be hidden. This method is internal, temporary and subject
  3985. * to removal in the future.
  3986. *
  3987. * @method _hasDataOverflow
  3988. * @protected
  3989. * @return Boolean
  3990. */
  3991. _hasDataOverflow: function()
  3992. {
  3993. var roundingMethod,
  3994. min,
  3995. max;
  3996. if(this.get("setMin") || this.get("setMax"))
  3997. {
  3998. return true;
  3999. }
  4000. roundingMethod = this.get("roundingMethod");
  4001. min = this._actualMinimum;
  4002. max = this._actualMaximum;
  4003. if(Y_Lang.isNumber(roundingMethod) && ((Y_Lang.isNumber(max) && max > this._dataMaximum) || (Y_Lang.isNumber(min) && min < this._dataMinimum)))
  4004. {
  4005. return true;
  4006. }
  4007. return false;
  4008. }
  4009. });
  4010. Y.NumericAxis = NumericAxis;
  4011. /**
  4012. * StackedAxis manages stacked numeric data on an axis.
  4013. *
  4014. * @module charts
  4015. * @class StackedAxis
  4016. * @constructor
  4017. * @param {Object} config (optional) Configuration parameters for the Chart.
  4018. * @extends NumericAxis
  4019. */
  4020. function StackedAxis(config)
  4021. {
  4022. StackedAxis.superclass.constructor.apply(this, arguments);
  4023. }
  4024. StackedAxis.NAME = "stackedAxis";
  4025. Y.extend(StackedAxis, Y.NumericAxis,
  4026. {
  4027. /**
  4028. * Calculates the maximum and minimum values for the `Axis`.
  4029. *
  4030. * @method _updateMinAndMax
  4031. * @private
  4032. */
  4033. _updateMinAndMax: function()
  4034. {
  4035. var max = 0,
  4036. min = 0,
  4037. pos = 0,
  4038. neg = 0,
  4039. len = 0,
  4040. i = 0,
  4041. key,
  4042. num,
  4043. keys = this.get("keys"),
  4044. setMin = this.get("setMin"),
  4045. setMax = this.get("setMax");
  4046. for(key in keys)
  4047. {
  4048. if(keys.hasOwnProperty(key))
  4049. {
  4050. len = Math.max(len, keys[key].length);
  4051. }
  4052. }
  4053. for(; i < len; ++i)
  4054. {
  4055. pos = 0;
  4056. neg = 0;
  4057. for(key in keys)
  4058. {
  4059. if(keys.hasOwnProperty(key))
  4060. {
  4061. num = keys[key][i];
  4062. if(isNaN(num))
  4063. {
  4064. continue;
  4065. }
  4066. if(num >= 0)
  4067. {
  4068. pos += num;
  4069. }
  4070. else
  4071. {
  4072. neg += num;
  4073. }
  4074. }
  4075. }
  4076. if(pos > 0)
  4077. {
  4078. max = Math.max(max, pos);
  4079. }
  4080. else
  4081. {
  4082. max = Math.max(max, neg);
  4083. }
  4084. if(neg < 0)
  4085. {
  4086. min = Math.min(min, neg);
  4087. }
  4088. else
  4089. {
  4090. min = Math.min(min, pos);
  4091. }
  4092. }
  4093. this._actualMaximum = max;
  4094. this._actualMinimum = min;
  4095. if(setMax)
  4096. {
  4097. max = this._setMaximum;
  4098. }
  4099. if(setMin)
  4100. {
  4101. min = this._setMinimum;
  4102. }
  4103. this._roundMinAndMax(min, max, setMin, setMax);
  4104. }
  4105. });
  4106. Y.StackedAxis = StackedAxis;
  4107. /**
  4108. * TimeAxis manages time data on an axis.
  4109. *
  4110. * @module charts
  4111. * @class TimeAxis
  4112. * @constructor
  4113. * @param {Object} config (optional) Configuration parameters for the Chart.
  4114. * @extends AxisType
  4115. */
  4116. function TimeAxis(config)
  4117. {
  4118. TimeAxis.superclass.constructor.apply(this, arguments);
  4119. }
  4120. TimeAxis.NAME = "timeAxis";
  4121. TimeAxis.ATTRS =
  4122. {
  4123. /**
  4124. * Indicates whether the maximum is calculated or explicitly set.
  4125. *
  4126. * @attribute setMax
  4127. * @readOnly
  4128. * @type Boolean
  4129. * @private
  4130. */
  4131. setMax: {
  4132. readOnly: true,
  4133. getter: function()
  4134. {
  4135. var max = this._getNumber(this._setMaximum);
  4136. return (Y_Lang.isNumber(max));
  4137. }
  4138. },
  4139. /**
  4140. * Indicates whether the minimum is calculated or explicitly set.
  4141. *
  4142. * @attribute setMin
  4143. * @readOnly
  4144. * @type Boolean
  4145. * @private
  4146. */
  4147. setMin: {
  4148. readOnly: true,
  4149. getter: function()
  4150. {
  4151. var min = this._getNumber(this._setMinimum);
  4152. return (Y_Lang.isNumber(min));
  4153. }
  4154. },
  4155. /**
  4156. * The maximum value that will appear on an axis. Unless explicitly set, this value is calculated by the `Axis`.
  4157. *
  4158. * @attribute maximum
  4159. * @type Number
  4160. */
  4161. maximum: {
  4162. getter: function ()
  4163. {
  4164. var max = this._getNumber(this._setMaximum);
  4165. if(!Y_Lang.isNumber(max))
  4166. {
  4167. max = this._getNumber(this.get("dataMaximum"));
  4168. }
  4169. return max;
  4170. },
  4171. setter: function (value)
  4172. {
  4173. this._setMaximum = this._getNumber(value);
  4174. return value;
  4175. }
  4176. },
  4177. /**
  4178. * The minimum value that will appear on an axis. Unless explicitly set, this value is calculated by the `Axis`.
  4179. *
  4180. * @attribute minimum
  4181. * @type Number
  4182. */
  4183. minimum: {
  4184. getter: function ()
  4185. {
  4186. var min = this._getNumber(this._setMinimum);
  4187. if(!Y_Lang.isNumber(min))
  4188. {
  4189. min = this._getNumber(this.get("dataMinimum"));
  4190. }
  4191. return min;
  4192. },
  4193. setter: function (value)
  4194. {
  4195. this._setMinimum = this._getNumber(value);
  4196. return value;
  4197. }
  4198. },
  4199. /**
  4200. * Method used for formatting a label. This attribute allows for the default label formatting method to overridden. The method use would need
  4201. * to implement the arguments below and return a `String`.
  4202. * <dl>
  4203. * <dt>val</dt><dd>Label to be formatted. (`String`)</dd>
  4204. * <dt>format</dt><dd>STRFTime string used to format the label. (optional)</dd>
  4205. * </dl>
  4206. *
  4207. * @attribute labelFunction
  4208. * @type Function
  4209. */
  4210. labelFunction: {
  4211. value: function(val, format)
  4212. {
  4213. val = Y.DataType.Date.parse(val);
  4214. if(format)
  4215. {
  4216. return Y.DataType.Date.format(val, {format:format});
  4217. }
  4218. return val;
  4219. }
  4220. },
  4221. /**
  4222. * Pattern used by the `labelFunction` to format a label.
  4223. *
  4224. * @attribute labelFormat
  4225. * @type String
  4226. */
  4227. labelFormat: {
  4228. value: "%b %d, %y"
  4229. }
  4230. };
  4231. Y.extend(TimeAxis, Y.AxisType, {
  4232. /**
  4233. * Constant used to generate unique id.
  4234. *
  4235. * @property GUID
  4236. * @type String
  4237. * @private
  4238. */
  4239. GUID: "yuitimeaxis",
  4240. /**
  4241. * Type of data used in `Axis`.
  4242. *
  4243. * @property _dataType
  4244. * @readOnly
  4245. * @private
  4246. */
  4247. _dataType: "time",
  4248. /**
  4249. * Calculates and returns a value based on the number of labels and the index of
  4250. * the current label.
  4251. *
  4252. * @method getLabelByIndex
  4253. * @param {Number} i Index of the label.
  4254. * @param {Number} l Total number of labels.
  4255. * @return String
  4256. */
  4257. getLabelByIndex: function(i, l)
  4258. {
  4259. var min = this.get("minimum"),
  4260. max = this.get("maximum"),
  4261. position = this.get("position"),
  4262. increm,
  4263. label;
  4264. l -= 1;
  4265. increm = ((max - min)/l) * i;
  4266. if(position == "bottom" || position == "top")
  4267. {
  4268. label = min + increm;
  4269. }
  4270. else
  4271. {
  4272. label = max - increm;
  4273. }
  4274. return label;
  4275. },
  4276. /**
  4277. * Gets an array of values based on a key.
  4278. *
  4279. * @method _getKeyArray
  4280. * @param {String} key Value key associated with the data array.
  4281. * @param {Array} data Array in which the data resides.
  4282. * @return Array
  4283. * @private
  4284. */
  4285. _getKeyArray: function(key, data)
  4286. {
  4287. var obj,
  4288. keyArray = [],
  4289. i = 0,
  4290. val,
  4291. len = data.length;
  4292. for(; i < len; ++i)
  4293. {
  4294. obj = data[i][key];
  4295. if(Y_Lang.isDate(obj))
  4296. {
  4297. val = obj.valueOf();
  4298. }
  4299. else
  4300. {
  4301. val = new Date(obj);
  4302. if(Y_Lang.isDate(val))
  4303. {
  4304. val = val.valueOf();
  4305. }
  4306. else if(!Y_Lang.isNumber(obj))
  4307. {
  4308. if(Y_Lang.isNumber(parseFloat(obj)))
  4309. {
  4310. val = parseFloat(obj);
  4311. }
  4312. else
  4313. {
  4314. if(typeof obj != "string")
  4315. {
  4316. obj = obj.toString();
  4317. }
  4318. val = new Date(obj).valueOf();
  4319. }
  4320. }
  4321. else
  4322. {
  4323. val = obj;
  4324. }
  4325. }
  4326. keyArray[i] = val;
  4327. }
  4328. return keyArray;
  4329. },
  4330. /**
  4331. * Sets data by key
  4332. *
  4333. * @method _setDataByKey
  4334. * @param {String} key Key value to use.
  4335. * @param {Array} data Array to use.
  4336. * @private
  4337. */
  4338. _setDataByKey: function(key, data)
  4339. {
  4340. var obj,
  4341. arr = [],
  4342. dv = this._dataClone.concat(),
  4343. i,
  4344. val,
  4345. len = dv.length;
  4346. for(i = 0; i < len; ++i)
  4347. {
  4348. obj = dv[i][key];
  4349. if(Y_Lang.isDate(obj))
  4350. {
  4351. val = obj.valueOf();
  4352. }
  4353. else
  4354. {
  4355. val = new Date(obj);
  4356. if(Y_Lang.isDate(val))
  4357. {
  4358. val = val.valueOf();
  4359. }
  4360. else if(!Y_Lang.isNumber(obj))
  4361. {
  4362. if(Y_Lang.isNumber(parseFloat(obj)))
  4363. {
  4364. val = parseFloat(obj);
  4365. }
  4366. else
  4367. {
  4368. if(typeof obj != "string")
  4369. {
  4370. obj = obj.toString();
  4371. }
  4372. val = new Date(obj).valueOf();
  4373. }
  4374. }
  4375. else
  4376. {
  4377. val = obj;
  4378. }
  4379. }
  4380. arr[i] = val;
  4381. }
  4382. this.get("keys")[key] = arr;
  4383. this._updateTotalDataFlag = true;
  4384. },
  4385. /**
  4386. * Parses value into a number.
  4387. *
  4388. * @method _getNumber
  4389. * @param val {Object} Value to parse into a number
  4390. * @return Number
  4391. * @private
  4392. */
  4393. _getNumber: function(val)
  4394. {
  4395. if(Y_Lang.isDate(val))
  4396. {
  4397. val = val.valueOf();
  4398. }
  4399. else if(!Y_Lang.isNumber(val) && val)
  4400. {
  4401. val = new Date(val).valueOf();
  4402. }
  4403. return val;
  4404. }
  4405. });
  4406. Y.TimeAxis = TimeAxis;
  4407. /**
  4408. * CategoryAxis manages category data on an axis.
  4409. *
  4410. * @module charts
  4411. * @class CategoryAxis
  4412. * @constructor
  4413. * @param {Object} config (optional) Configuration parameters for the Chart.
  4414. * @extends AxisType
  4415. */
  4416. function CategoryAxis(config)
  4417. {
  4418. CategoryAxis.superclass.constructor.apply(this, arguments);
  4419. }
  4420. CategoryAxis.NAME = "categoryAxis";
  4421. Y.extend(CategoryAxis, Y.AxisType,
  4422. {
  4423. /**
  4424. * Object storing key data.
  4425. *
  4426. * @property _indices
  4427. * @private
  4428. */
  4429. _indices: null,
  4430. /**
  4431. * Constant used to generate unique id.
  4432. *
  4433. * @property GUID
  4434. * @type String
  4435. * @private
  4436. */
  4437. GUID: "yuicategoryaxis",
  4438. /**
  4439. * Type of data used in `Axis`.
  4440. *
  4441. * @property _dataType
  4442. * @readOnly
  4443. * @private
  4444. */
  4445. _type: "category",
  4446. /**
  4447. * Calculates the maximum and minimum values for the `Axis`.
  4448. *
  4449. * @method _updateMinAndMax
  4450. * @private
  4451. */
  4452. _updateMinAndMax: function()
  4453. {
  4454. this._dataMaximum = Math.max(this.get("data").length - 1, 0);
  4455. this._dataMinimum = 0;
  4456. },
  4457. /**
  4458. * Gets an array of values based on a key.
  4459. *
  4460. * @method _getKeyArray
  4461. * @param {String} key Value key associated with the data array.
  4462. * @param {Array} data Array in which the data resides.
  4463. * @return Array
  4464. * @private
  4465. */
  4466. _getKeyArray: function(key, data)
  4467. {
  4468. var i = 0,
  4469. obj,
  4470. keyArr = [],
  4471. labels = [],
  4472. len = data.length;
  4473. if(!this._indices)
  4474. {
  4475. this._indices = {};
  4476. }
  4477. for(; i < len; ++i)
  4478. {
  4479. obj = data[i];
  4480. keyArr[i] = i;
  4481. labels[i] = obj[key];
  4482. }
  4483. this._indices[key] = keyArr;
  4484. return labels;
  4485. },
  4486. /**
  4487. * Sets data by key
  4488. *
  4489. * @method _setDataByKey
  4490. * @param {String} key Key value to use.
  4491. * @param {Array} data Array to use.
  4492. * @private
  4493. */
  4494. _setDataByKey: function(key)
  4495. {
  4496. var i,
  4497. obj,
  4498. arr = [],
  4499. labels = [],
  4500. dv = this._dataClone.concat(),
  4501. len = dv.length;
  4502. if(!this._indices)
  4503. {
  4504. this._indices = {};
  4505. }
  4506. for(i = 0; i < len; ++i)
  4507. {
  4508. obj = dv[i];
  4509. arr[i] = i;
  4510. labels[i] = obj[key];
  4511. }
  4512. this._indices[key] = arr;
  4513. this.get("keys")[key] = labels.concat();
  4514. this._updateTotalDataFlag = true;
  4515. },
  4516. /**
  4517. * Returns an array of values based on an identifier key.
  4518. *
  4519. * @method getDataByKey
  4520. * @param {String} value value used to identify the array
  4521. * @return Array
  4522. */
  4523. getDataByKey: function (value)
  4524. {
  4525. if(!this._indices)
  4526. {
  4527. this.get("keys");
  4528. }
  4529. var keys = this._indices;
  4530. if(keys[value])
  4531. {
  4532. return keys[value];
  4533. }
  4534. return null;
  4535. },
  4536. /**
  4537. * Returns the total number of majorUnits that will appear on an axis.
  4538. *
  4539. * @method getTotalMajorUnits
  4540. * @param {Object} majorUnit Object containing properties related to the majorUnit.
  4541. * @param {Number} len Length of the axis.
  4542. * @return Number
  4543. */
  4544. getTotalMajorUnits: function(majorUnit, len)
  4545. {
  4546. return this.get("data").length;
  4547. },
  4548. /**
  4549. * Returns the distance between major units on an axis.
  4550. *
  4551. * @method getMajorUnitDistance
  4552. * @param {Number} len Number of ticks
  4553. * @param {Number} uiLen Size of the axis.
  4554. * @param {Object} majorUnit Hash of properties used to determine the majorUnit
  4555. * @return Number
  4556. */
  4557. getMajorUnitDistance: function(len, uiLen, majorUnit)
  4558. {
  4559. var dist;
  4560. if(majorUnit.determinant === "count")
  4561. {
  4562. dist = uiLen/len;
  4563. }
  4564. else if(majorUnit.determinant === "distance")
  4565. {
  4566. dist = majorUnit.distance;
  4567. }
  4568. return dist;
  4569. },
  4570. /**
  4571. * Gets the distance that the first and last ticks are offset from there respective
  4572. * edges.
  4573. *
  4574. * @method getEdgeOffset
  4575. * @param {Number} ct Number of ticks on the axis.
  4576. * @param {Number} l Length (in pixels) of the axis.
  4577. * @return Number
  4578. */
  4579. getEdgeOffset: function(ct, l)
  4580. {
  4581. return l/ct;
  4582. },
  4583. /**
  4584. * Calculates and returns a value based on the number of labels and the index of
  4585. * the current label.
  4586. *
  4587. * @method getLabelByIndex
  4588. * @param {Number} i Index of the label.
  4589. * @param {Number} l Total number of labels.
  4590. * @return String
  4591. */
  4592. getLabelByIndex: function(i, l)
  4593. {
  4594. var label,
  4595. data = this.get("data"),
  4596. position = this.get("position");
  4597. if(position == "bottom" || position == "top")
  4598. {
  4599. label = data[i];
  4600. }
  4601. else
  4602. {
  4603. label = data[l - (i + 1)];
  4604. }
  4605. return label;
  4606. }
  4607. });
  4608. Y.CategoryAxis = CategoryAxis;
  4609. /**
  4610. * Utility class used for calculating curve points.
  4611. *
  4612. * @module charts
  4613. * @class CurveUtil
  4614. * @constructor
  4615. */
  4616. function CurveUtil()
  4617. {
  4618. }
  4619. CurveUtil.prototype = {
  4620. /**
  4621. * Creates an array of start, end and control points for splines.
  4622. *
  4623. * @method getCurveControlPoints
  4624. * @param {Array} xcoords Collection of x-coordinates used for calculate the curves
  4625. * @param {Array} ycoords Collection of y-coordinates used for calculate the curves
  4626. * @return Object
  4627. * @protected
  4628. */
  4629. getCurveControlPoints: function(xcoords, ycoords)
  4630. {
  4631. var outpoints = [],
  4632. i = 1,
  4633. l = xcoords.length - 1,
  4634. xvals = [],
  4635. yvals = [];
  4636. // Too few points, need at least two
  4637. if (l < 1)
  4638. {
  4639. return null;
  4640. }
  4641. outpoints[0] = {
  4642. startx: xcoords[0],
  4643. starty: ycoords[0],
  4644. endx: xcoords[1],
  4645. endy: ycoords[1]
  4646. };
  4647. // Special case, the Bezier should be a straight line
  4648. if (l === 1)
  4649. {
  4650. outpoints[0].ctrlx1 = (2.0*xcoords[0] + xcoords[1])/3.0;
  4651. outpoints[0].ctrly2 = (2.0*ycoords[0] + ycoords[1])/3.0;
  4652. outpoints[0].ctrlx2 = 2.0*outpoints[0].ctrlx1 - xcoords[0];
  4653. outpoints[0].ctrly2 = 2.0*outpoints[0].ctrly1 - ycoords[0];
  4654. return outpoints;
  4655. }
  4656. for (; i < l; ++i)
  4657. {
  4658. outpoints.push({startx: Math.round(xcoords[i]), starty: Math.round(ycoords[i]), endx: Math.round(xcoords[i+1]), endy: Math.round(ycoords[i+1])});
  4659. xvals[i] = 4.0 * xcoords[i] + 2*xcoords[i+1];
  4660. yvals[i] = 4.0*ycoords[i] + 2*ycoords[i+1];
  4661. }
  4662. xvals[0] = xcoords[0] + (2.0 * xcoords[1]);
  4663. xvals[l-1] = (8.0 * xcoords[l-1] + xcoords[l]) / 2.0;
  4664. xvals = this.getControlPoints(xvals.concat());
  4665. yvals[0] = ycoords[0] + (2.0 * ycoords[1]);
  4666. yvals[l-1] = (8.0 * ycoords[l-1] + ycoords[l]) / 2.0;
  4667. yvals = this.getControlPoints(yvals.concat());
  4668. for (i = 0; i < l; ++i)
  4669. {
  4670. outpoints[i].ctrlx1 = Math.round(xvals[i]);
  4671. outpoints[i].ctrly1 = Math.round(yvals[i]);
  4672. if (i < l-1)
  4673. {
  4674. outpoints[i].ctrlx2 = Math.round(2*xcoords[i+1] - xvals[i+1]);
  4675. outpoints[i].ctrly2 = Math.round(2*ycoords[i+1] - yvals[i+1]);
  4676. }
  4677. else
  4678. {
  4679. outpoints[i].ctrlx2 = Math.round((xcoords[l] + xvals[l-1])/2);
  4680. outpoints[i].ctrly2 = Math.round((ycoords[l] + yvals[l-1])/2);
  4681. }
  4682. }
  4683. return outpoints;
  4684. },
  4685. /**
  4686. * Gets the control points for the curve.
  4687. *
  4688. * @method getControlPoints
  4689. * @param {Array} vals Collection of values coords used to generate control points.
  4690. * @return Array
  4691. * @private
  4692. */
  4693. getControlPoints: function(vals)
  4694. {
  4695. var l = vals.length,
  4696. x = [],
  4697. tmp = [],
  4698. b = 2.0,
  4699. i = 1;
  4700. x[0] = vals[0] / b;
  4701. for (; i < l; ++i)
  4702. {
  4703. tmp[i] = 1/b;
  4704. b = (i < l-1 ? 4.0 : 3.5) - tmp[i];
  4705. x[i] = (vals[i] - x[i-1]) / b;
  4706. }
  4707. for (i = 1; i < l; ++i)
  4708. {
  4709. x[l-i-1] -= tmp[l-i] * x[l-i];
  4710. }
  4711. return x;
  4712. }
  4713. };
  4714. Y.CurveUtil = CurveUtil;
  4715. /**
  4716. * Utility class used for creating stacked series.
  4717. *
  4718. * @module charts
  4719. * @class StackingUtil
  4720. * @constructor
  4721. */
  4722. function StackingUtil(){}
  4723. StackingUtil.prototype = {
  4724. /**
  4725. * @protected
  4726. *
  4727. * Adjusts coordinate values for stacked series.
  4728. *
  4729. * @method _stackCoordinates
  4730. */
  4731. _stackCoordinates: function()
  4732. {
  4733. var direction = this.get("direction"),
  4734. order = this.get("order"),
  4735. type = this.get("type"),
  4736. graph = this.get("graph"),
  4737. h = graph.get("height"),
  4738. seriesCollection = graph.seriesTypes[type],
  4739. i = 0,
  4740. len,
  4741. xcoords = this.get("xcoords"),
  4742. ycoords = this.get("ycoords"),
  4743. prevXCoords,
  4744. prevYCoords;
  4745. if(order === 0)
  4746. {
  4747. return;
  4748. }
  4749. prevXCoords = seriesCollection[order - 1].get("xcoords").concat();
  4750. prevYCoords = seriesCollection[order - 1].get("ycoords").concat();
  4751. if(direction === "vertical")
  4752. {
  4753. len = prevXCoords.length;
  4754. for(; i < len; ++i)
  4755. {
  4756. if(!isNaN(prevXCoords[i]) && !isNaN(xcoords[i]))
  4757. {
  4758. xcoords[i] += prevXCoords[i];
  4759. }
  4760. }
  4761. }
  4762. else
  4763. {
  4764. len = prevYCoords.length;
  4765. for(; i < len; ++i)
  4766. {
  4767. if(!isNaN(prevYCoords[i]) && !isNaN(ycoords[i]))
  4768. {
  4769. ycoords[i] = prevYCoords[i] - (h - ycoords[i]);
  4770. }
  4771. }
  4772. }
  4773. }
  4774. };
  4775. Y.StackingUtil = StackingUtil;
  4776. /**
  4777. * Utility class used for drawing lines.
  4778. *
  4779. * @module charts
  4780. * @class Lines
  4781. * @constructor
  4782. */
  4783. function Lines(){}
  4784. Lines.prototype = {
  4785. /**
  4786. * @property _lineDefaults
  4787. * @type Object
  4788. * @private
  4789. */
  4790. _lineDefaults: null,
  4791. /**
  4792. * Creates a graphic in which to draw a series.
  4793. *
  4794. * @method _getGraphic
  4795. * @return Graphic
  4796. * @private
  4797. */
  4798. _getGraphic: function()
  4799. {
  4800. var graphic = this.get("graphic") || this.get("graph").get("graphic");
  4801. if(!this._lineGraphic)
  4802. {
  4803. this._lineGraphic = graphic.addShape({type: "path"});
  4804. }
  4805. this._lineGraphic.clear();
  4806. return this._lineGraphic;
  4807. },
  4808. /**
  4809. * Toggles visibility
  4810. *
  4811. * @method _toggleVisible
  4812. * @param {Boolean} visible indicates visibilitye
  4813. * @private
  4814. */
  4815. _toggleVisible: function(visible)
  4816. {
  4817. if(this._lineGraphic)
  4818. {
  4819. this._lineGraphic.set("visible", visible);
  4820. }
  4821. },
  4822. /**
  4823. * Draws lines for the series.
  4824. *
  4825. * @method drawLines
  4826. * @protected
  4827. */
  4828. drawLines: function()
  4829. {
  4830. if(this.get("xcoords").length < 1)
  4831. {
  4832. return;
  4833. }
  4834. var isNumber = Y_Lang.isNumber,
  4835. xcoords = this.get("xcoords").concat(),
  4836. ycoords = this.get("ycoords").concat(),
  4837. direction = this.get("direction"),
  4838. len = direction === "vertical" ? ycoords.length : xcoords.length,
  4839. lastPointValid,
  4840. pointValid,
  4841. noPointsRendered = true,
  4842. lastValidX,
  4843. lastValidY,
  4844. nextX,
  4845. nextY,
  4846. i,
  4847. styles = this.get("styles").line,
  4848. lineType = styles.lineType,
  4849. lc = styles.color || this._getDefaultColor(this.get("graphOrder"), "line"),
  4850. lineAlpha = styles.alpha,
  4851. dashLength = styles.dashLength,
  4852. gapSpace = styles.gapSpace,
  4853. connectDiscontinuousPoints = styles.connectDiscontinuousPoints,
  4854. discontinuousType = styles.discontinuousType,
  4855. discontinuousDashLength = styles.discontinuousDashLength,
  4856. discontinuousGapSpace = styles.discontinuousGapSpace,
  4857. path = this._getGraphic();
  4858. path.set("stroke", {
  4859. weight: styles.weight,
  4860. color: lc,
  4861. opacity: lineAlpha
  4862. });
  4863. for(i = 0; i < len; i = ++i)
  4864. {
  4865. nextX = xcoords[i];
  4866. nextY = ycoords[i];
  4867. pointValid = isNumber(nextX) && isNumber(nextY);
  4868. if(!pointValid)
  4869. {
  4870. lastPointValid = pointValid;
  4871. continue;
  4872. }
  4873. if(noPointsRendered)
  4874. {
  4875. noPointsRendered = false;
  4876. path.moveTo(nextX, nextY);
  4877. }
  4878. else if(lastPointValid)
  4879. {
  4880. if(lineType != "dashed")
  4881. {
  4882. path.lineTo(nextX, nextY);
  4883. }
  4884. else
  4885. {
  4886. this.drawDashedLine(lastValidX, lastValidY, nextX, nextY,
  4887. dashLength,
  4888. gapSpace);
  4889. }
  4890. }
  4891. else if(!connectDiscontinuousPoints)
  4892. {
  4893. path.moveTo(nextX, nextY);
  4894. }
  4895. else
  4896. {
  4897. if(discontinuousType != "solid")
  4898. {
  4899. this.drawDashedLine(lastValidX, lastValidY, nextX, nextY,
  4900. discontinuousDashLength,
  4901. discontinuousGapSpace);
  4902. }
  4903. else
  4904. {
  4905. path.lineTo(nextX, nextY);
  4906. }
  4907. }
  4908. lastValidX = nextX;
  4909. lastValidY = nextY;
  4910. lastPointValid = true;
  4911. }
  4912. path.end();
  4913. },
  4914. /**
  4915. * Connects data points with a consistent curve for a series.
  4916. *
  4917. * @method drawSpline
  4918. * @protected
  4919. */
  4920. drawSpline: function()
  4921. {
  4922. if(this.get("xcoords").length < 1)
  4923. {
  4924. return;
  4925. }
  4926. var xcoords = this.get("xcoords"),
  4927. ycoords = this.get("ycoords"),
  4928. curvecoords = this.getCurveControlPoints(xcoords, ycoords),
  4929. len = curvecoords.length,
  4930. cx1,
  4931. cx2,
  4932. cy1,
  4933. cy2,
  4934. x,
  4935. y,
  4936. i = 0,
  4937. styles = this.get("styles").line,
  4938. path = this._getGraphic(),
  4939. lineAlpha = styles.alpha,
  4940. color = styles.color || this._getDefaultColor(this.get("graphOrder"), "line");
  4941. path.set("stroke", {
  4942. weight: styles.weight,
  4943. color: color,
  4944. opacity: lineAlpha
  4945. });
  4946. path.moveTo(xcoords[0], ycoords[0]);
  4947. for(; i < len; i = ++i)
  4948. {
  4949. x = curvecoords[i].endx;
  4950. y = curvecoords[i].endy;
  4951. cx1 = curvecoords[i].ctrlx1;
  4952. cx2 = curvecoords[i].ctrlx2;
  4953. cy1 = curvecoords[i].ctrly1;
  4954. cy2 = curvecoords[i].ctrly2;
  4955. path.curveTo(cx1, cy1, cx2, cy2, x, y);
  4956. }
  4957. path.end();
  4958. },
  4959. /**
  4960. * Draws a dashed line between two points.
  4961. *
  4962. * @method drawDashedLine
  4963. * @param {Number} xStart The x position of the start of the line
  4964. * @param {Number} yStart The y position of the start of the line
  4965. * @param {Number} xEnd The x position of the end of the line
  4966. * @param {Number} yEnd The y position of the end of the line
  4967. * @param {Number} dashSize the size of dashes, in pixels
  4968. * @param {Number} gapSize the size of gaps between dashes, in pixels
  4969. * @private
  4970. */
  4971. drawDashedLine: function(xStart, yStart, xEnd, yEnd, dashSize, gapSize)
  4972. {
  4973. dashSize = dashSize || 10;
  4974. gapSize = gapSize || 10;
  4975. var segmentLength = dashSize + gapSize,
  4976. xDelta = xEnd - xStart,
  4977. yDelta = yEnd - yStart,
  4978. delta = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(yDelta, 2)),
  4979. segmentCount = Math.floor(Math.abs(delta / segmentLength)),
  4980. radians = Math.atan2(yDelta, xDelta),
  4981. xCurrent = xStart,
  4982. yCurrent = yStart,
  4983. i,
  4984. path = this._getGraphic();
  4985. xDelta = Math.cos(radians) * segmentLength;
  4986. yDelta = Math.sin(radians) * segmentLength;
  4987. for(i = 0; i < segmentCount; ++i)
  4988. {
  4989. path.moveTo(xCurrent, yCurrent);
  4990. path.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize);
  4991. xCurrent += xDelta;
  4992. yCurrent += yDelta;
  4993. }
  4994. path.moveTo(xCurrent, yCurrent);
  4995. delta = Math.sqrt((xEnd - xCurrent) * (xEnd - xCurrent) + (yEnd - yCurrent) * (yEnd - yCurrent));
  4996. if(delta > dashSize)
  4997. {
  4998. path.lineTo(xCurrent + Math.cos(radians) * dashSize, yCurrent + Math.sin(radians) * dashSize);
  4999. }
  5000. else if(delta > 0)
  5001. {
  5002. path.lineTo(xCurrent + Math.cos(radians) * delta, yCurrent + Math.sin(radians) * delta);
  5003. }
  5004. path.moveTo(xEnd, yEnd);
  5005. },
  5006. /**
  5007. * Default values for `styles` attribute.
  5008. *
  5009. * @method _getLineDefaults
  5010. * @return Object
  5011. * @protected
  5012. */
  5013. _getLineDefaults: function()
  5014. {
  5015. return {
  5016. alpha: 1,
  5017. weight: 6,
  5018. lineType:"solid",
  5019. dashLength:10,
  5020. gapSpace:10,
  5021. connectDiscontinuousPoints:true,
  5022. discontinuousType:"solid",
  5023. discontinuousDashLength:10,
  5024. discontinuousGapSpace:10
  5025. };
  5026. }
  5027. };
  5028. Y.augment(Lines, Y.Attribute);
  5029. Y.Lines = Lines;
  5030. /**
  5031. * Utility class used for drawing area fills.
  5032. *
  5033. * @module charts
  5034. * @class Fills
  5035. * @constructor
  5036. */
  5037. function Fills(cfg)
  5038. {
  5039. var attrs = {
  5040. area: {
  5041. getter: function()
  5042. {
  5043. return this._defaults || this._getAreaDefaults();
  5044. },
  5045. setter: function(val)
  5046. {
  5047. var defaults = this._defaults || this._getAreaDefaults();
  5048. this._defaults = Y.merge(defaults, val);
  5049. }
  5050. }
  5051. };
  5052. this.addAttrs(attrs, cfg);
  5053. this.get("styles");
  5054. }
  5055. Fills.prototype = {
  5056. /**
  5057. * Returns a path shape used for drawing fills.
  5058. *
  5059. * @method _getPath
  5060. * @return Path
  5061. * @private
  5062. */
  5063. _getPath: function()
  5064. {
  5065. var path = this._path;
  5066. if(!path)
  5067. {
  5068. path = this.get("graph").get("graphic").addShape({type:"path"});
  5069. this._path = path;
  5070. }
  5071. return path;
  5072. },
  5073. /**
  5074. * Toggles visibility
  5075. *
  5076. * @method _toggleVisible
  5077. * @param {Boolean} visible indicates visibilitye
  5078. * @private
  5079. */
  5080. _toggleVisible: function(visible)
  5081. {
  5082. if(this._path)
  5083. {
  5084. this._path.set("visible", visible);
  5085. }
  5086. },
  5087. /**
  5088. * Draws fill
  5089. *
  5090. * @method drawFill
  5091. * @param {Array} xcoords The x-coordinates for the series.
  5092. * @param {Array} ycoords The y-coordinates for the series.
  5093. * @protected
  5094. */
  5095. drawFill: function(xcoords, ycoords)
  5096. {
  5097. if(xcoords.length < 1)
  5098. {
  5099. return;
  5100. }
  5101. var len = xcoords.length,
  5102. firstX = xcoords[0],
  5103. firstY = ycoords[0],
  5104. lastValidX = firstX,
  5105. lastValidY = firstY,
  5106. nextX,
  5107. nextY,
  5108. i = 1,
  5109. styles = this.get("styles").area,
  5110. path = this._getPath(),
  5111. color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
  5112. path.clear();
  5113. path.set("fill", {
  5114. color: color,
  5115. opacity: styles.alpha
  5116. });
  5117. path.set("stroke", {weight: 0});
  5118. path.moveTo(firstX, firstY);
  5119. for(; i < len; i = ++i)
  5120. {
  5121. nextX = xcoords[i];
  5122. nextY = ycoords[i];
  5123. if(isNaN(nextY))
  5124. {
  5125. lastValidX = nextX;
  5126. lastValidY = nextY;
  5127. continue;
  5128. }
  5129. path.lineTo(nextX, nextY);
  5130. lastValidX = nextX;
  5131. lastValidY = nextY;
  5132. }
  5133. path.end();
  5134. },
  5135. /**
  5136. * Draws a fill for a spline
  5137. *
  5138. * @method drawAreaSpline
  5139. * @protected
  5140. */
  5141. drawAreaSpline: function()
  5142. {
  5143. if(this.get("xcoords").length < 1)
  5144. {
  5145. return;
  5146. }
  5147. var xcoords = this.get("xcoords"),
  5148. ycoords = this.get("ycoords"),
  5149. curvecoords = this.getCurveControlPoints(xcoords, ycoords),
  5150. len = curvecoords.length,
  5151. cx1,
  5152. cx2,
  5153. cy1,
  5154. cy2,
  5155. x,
  5156. y,
  5157. i = 0,
  5158. firstX = xcoords[0],
  5159. firstY = ycoords[0],
  5160. styles = this.get("styles").area,
  5161. path = this._getPath(),
  5162. color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
  5163. path.set("fill", {
  5164. color: color,
  5165. opacity: styles.alpha
  5166. });
  5167. path.set("stroke", {weight: 0});
  5168. path.moveTo(firstX, firstY);
  5169. for(; i < len; i = ++i)
  5170. {
  5171. x = curvecoords[i].endx;
  5172. y = curvecoords[i].endy;
  5173. cx1 = curvecoords[i].ctrlx1;
  5174. cx2 = curvecoords[i].ctrlx2;
  5175. cy1 = curvecoords[i].ctrly1;
  5176. cy2 = curvecoords[i].ctrly2;
  5177. path.curveTo(cx1, cy1, cx2, cy2, x, y);
  5178. }
  5179. if(this.get("direction") === "vertical")
  5180. {
  5181. path.lineTo(this._leftOrigin, y);
  5182. path.lineTo(this._leftOrigin, firstY);
  5183. }
  5184. else
  5185. {
  5186. path.lineTo(x, this._bottomOrigin);
  5187. path.lineTo(firstX, this._bottomOrigin);
  5188. }
  5189. path.lineTo(firstX, firstY);
  5190. path.end();
  5191. },
  5192. /**
  5193. * Draws a a stacked area spline
  5194. *
  5195. * @method drawStackedAreaSpline
  5196. * @protected
  5197. */
  5198. drawStackedAreaSpline: function()
  5199. {
  5200. if(this.get("xcoords").length < 1)
  5201. {
  5202. return;
  5203. }
  5204. var xcoords = this.get("xcoords"),
  5205. ycoords = this.get("ycoords"),
  5206. curvecoords,
  5207. order = this.get("order"),
  5208. type = this.get("type"),
  5209. graph = this.get("graph"),
  5210. seriesCollection = graph.seriesTypes[type],
  5211. prevXCoords,
  5212. prevYCoords,
  5213. len,
  5214. cx1,
  5215. cx2,
  5216. cy1,
  5217. cy2,
  5218. x,
  5219. y,
  5220. i = 0,
  5221. firstX,
  5222. firstY,
  5223. styles = this.get("styles").area,
  5224. path = this._getPath(),
  5225. color = styles.color || this._getDefaultColor(this.get("graphOrder"), "slice");
  5226. firstX = xcoords[0];
  5227. firstY = ycoords[0];
  5228. curvecoords = this.getCurveControlPoints(xcoords, ycoords);
  5229. len = curvecoords.length;
  5230. path.set("fill", {
  5231. color: color,
  5232. opacity: styles.alpha
  5233. });
  5234. path.set("stroke", {weight: 0});
  5235. path.moveTo(firstX, firstY);
  5236. for(; i < len; i = ++i)
  5237. {
  5238. x = curvecoords[i].endx;
  5239. y = curvecoords[i].endy;
  5240. cx1 = curvecoords[i].ctrlx1;
  5241. cx2 = curvecoords[i].ctrlx2;
  5242. cy1 = curvecoords[i].ctrly1;
  5243. cy2 = curvecoords[i].ctrly2;
  5244. path.curveTo(cx1, cy1, cx2, cy2, x, y);
  5245. }
  5246. if(order > 0)
  5247. {
  5248. prevXCoords = seriesCollection[order - 1].get("xcoords").concat().reverse();
  5249. prevYCoords = seriesCollection[order - 1].get("ycoords").concat().reverse();
  5250. curvecoords = this.getCurveControlPoints(prevXCoords, prevYCoords);
  5251. i = 0;
  5252. len = curvecoords.length;
  5253. path.lineTo(prevXCoords[0], prevYCoords[0]);
  5254. for(; i < len; i = ++i)
  5255. {
  5256. x = curvecoords[i].endx;
  5257. y = curvecoords[i].endy;
  5258. cx1 = curvecoords[i].ctrlx1;
  5259. cx2 = curvecoords[i].ctrlx2;
  5260. cy1 = curvecoords[i].ctrly1;
  5261. cy2 = curvecoords[i].ctrly2;
  5262. path.curveTo(cx1, cy1, cx2, cy2, x, y);
  5263. }
  5264. }
  5265. else
  5266. {
  5267. if(this.get("direction") === "vertical")
  5268. {
  5269. path.lineTo(this._leftOrigin, ycoords[ycoords.length-1]);
  5270. path.lineTo(this._leftOrigin, firstY);
  5271. }
  5272. else
  5273. {
  5274. path.lineTo(xcoords[xcoords.length-1], this._bottomOrigin);
  5275. path.lineTo(firstX, this._bottomOrigin);
  5276. }
  5277. }
  5278. path.lineTo(firstX, firstY);
  5279. path.end();
  5280. },
  5281. /**
  5282. * Storage for default area styles.
  5283. *
  5284. * @property _defaults
  5285. * @type Object
  5286. * @private
  5287. */
  5288. _defaults: null,
  5289. /**
  5290. * Concatenates coordinate array with correct coordinates for closing an area fill.
  5291. *
  5292. * @method _getClosingPoints
  5293. * @return Array
  5294. * @protected
  5295. */
  5296. _getClosingPoints: function()
  5297. {
  5298. var xcoords = this.get("xcoords").concat(),
  5299. ycoords = this.get("ycoords").concat();
  5300. if(this.get("direction") === "vertical")
  5301. {
  5302. xcoords.push(this._leftOrigin);
  5303. xcoords.push(this._leftOrigin);
  5304. ycoords.push(ycoords[ycoords.length - 1]);
  5305. ycoords.push(ycoords[0]);
  5306. }
  5307. else
  5308. {
  5309. xcoords.push(xcoords[xcoords.length - 1]);
  5310. xcoords.push(xcoords[0]);
  5311. ycoords.push(this._bottomOrigin);
  5312. ycoords.push(this._bottomOrigin);
  5313. }
  5314. xcoords.push(xcoords[0]);
  5315. ycoords.push(ycoords[0]);
  5316. return [xcoords, ycoords];
  5317. },
  5318. /**
  5319. * Concatenates coordinate array with the correct coordinates for closing an area stack.
  5320. *
  5321. * @method _getStackedClosingPoints
  5322. * @return Array
  5323. * @protected
  5324. */
  5325. _getStackedClosingPoints: function()
  5326. {
  5327. var order = this.get("order"),
  5328. type = this.get("type"),
  5329. graph = this.get("graph"),
  5330. direction = this.get("direction"),
  5331. seriesCollection = graph.seriesTypes[type],
  5332. prevXCoords,
  5333. prevYCoords,
  5334. allXCoords = this.get("xcoords").concat(),
  5335. allYCoords = this.get("ycoords").concat(),
  5336. firstX = allXCoords[0],
  5337. firstY = allYCoords[0];
  5338. if(order > 0)
  5339. {
  5340. prevXCoords = seriesCollection[order - 1].get("xcoords").concat();
  5341. prevYCoords = seriesCollection[order - 1].get("ycoords").concat();
  5342. allXCoords = allXCoords.concat(prevXCoords.concat().reverse());
  5343. allYCoords = allYCoords.concat(prevYCoords.concat().reverse());
  5344. allXCoords.push(allXCoords[0]);
  5345. allYCoords.push(allYCoords[0]);
  5346. }
  5347. else
  5348. {
  5349. if(direction === "vertical")
  5350. {
  5351. allXCoords.push(this._leftOrigin);
  5352. allXCoords.push(this._leftOrigin);
  5353. allYCoords.push(allYCoords[allYCoords.length-1]);
  5354. allYCoords.push(firstY);
  5355. }
  5356. else
  5357. {
  5358. allXCoords.push(allXCoords[allXCoords.length-1]);
  5359. allXCoords.push(firstX);
  5360. allYCoords.push(this._bottomOrigin);
  5361. allYCoords.push(this._bottomOrigin);
  5362. }
  5363. }
  5364. return [allXCoords, allYCoords];
  5365. },
  5366. /**
  5367. * Returns default values for area styles.
  5368. *
  5369. * @method _getAreaDefaults
  5370. * @return Object
  5371. * @private
  5372. */
  5373. _getAreaDefaults: function()
  5374. {
  5375. return {
  5376. };
  5377. }
  5378. };
  5379. Y.augment(Fills, Y.Attribute);
  5380. Y.Fills = Fills;
  5381. /**
  5382. * Utility class used for drawing markers.
  5383. *
  5384. * @module charts
  5385. * @class Plots
  5386. * @constructor
  5387. */
  5388. function Plots(cfg)
  5389. {
  5390. var attrs = {
  5391. markers: {
  5392. getter: function()
  5393. {
  5394. return this._markers;
  5395. }
  5396. }
  5397. };
  5398. this.addAttrs(attrs, cfg);
  5399. }
  5400. Plots.prototype = {
  5401. /**
  5402. * Storage for default marker styles.
  5403. *
  5404. * @property _plotDefaults
  5405. * @type Object
  5406. * @private
  5407. */
  5408. _plotDefaults: null,
  5409. /**
  5410. * Draws the markers
  5411. *
  5412. * @method drawPlots
  5413. * @protected
  5414. */
  5415. drawPlots: function()
  5416. {
  5417. if(!this.get("xcoords") || this.get("xcoords").length < 1)
  5418. {
  5419. return;
  5420. }
  5421. var isNumber = Y_Lang.isNumber,
  5422. style = Y.clone(this.get("styles").marker),
  5423. w = style.width,
  5424. h = style.height,
  5425. xcoords = this.get("xcoords"),
  5426. ycoords = this.get("ycoords"),
  5427. i = 0,
  5428. len = xcoords.length,
  5429. top = ycoords[0],
  5430. left,
  5431. marker,
  5432. offsetWidth = w/2,
  5433. offsetHeight = h/2,
  5434. fillColors = null,
  5435. borderColors = null,
  5436. graphOrder = this.get("graphOrder");
  5437. if(Y_Lang.isArray(style.fill.color))
  5438. {
  5439. fillColors = style.fill.color.concat();
  5440. }
  5441. if(Y_Lang.isArray(style.border.color))
  5442. {
  5443. borderColors = style.border.colors.concat();
  5444. }
  5445. this._createMarkerCache();
  5446. for(; i < len; ++i)
  5447. {
  5448. top = parseFloat(ycoords[i] - offsetHeight);
  5449. left = parseFloat(xcoords[i] - offsetWidth);
  5450. if(!isNumber(left) || !isNumber(top))
  5451. {
  5452. this._markers.push(null);
  5453. continue;
  5454. }
  5455. if(fillColors)
  5456. {
  5457. style.fill.color = fillColors[i % fillColors.length];
  5458. }
  5459. if(borderColors)
  5460. {
  5461. style.border.colors = borderColors[i % borderColors.length];
  5462. }
  5463. style.x = left;
  5464. style.y = top;
  5465. marker = this.getMarker(style, graphOrder, i);
  5466. }
  5467. this._clearMarkerCache();
  5468. },
  5469. /**
  5470. * Gets the default values for series that use the utility. This method is used by
  5471. * the class' `styles` attribute's getter to get build default values.
  5472. *
  5473. * @method _getPlotDefaults
  5474. * @return Object
  5475. * @protected
  5476. */
  5477. _getPlotDefaults: function()
  5478. {
  5479. var defs = {
  5480. fill:{
  5481. type: "solid",
  5482. alpha: 1,
  5483. colors:null,
  5484. alphas: null,
  5485. ratios: null
  5486. },
  5487. border:{
  5488. weight: 1,
  5489. alpha: 1
  5490. },
  5491. width: 10,
  5492. height: 10,
  5493. shape: "circle"
  5494. };
  5495. defs.fill.color = this._getDefaultColor(this.get("graphOrder"), "fill");
  5496. defs.border.color = this._getDefaultColor(this.get("graphOrder"), "border");
  5497. return defs;
  5498. },
  5499. /**
  5500. * Collection of markers to be used in the series.
  5501. *
  5502. * @property _markers
  5503. * @type Array
  5504. * @private
  5505. */
  5506. _markers: null,
  5507. /**
  5508. * Collection of markers to be re-used on a series redraw.
  5509. *
  5510. * @property _markerCache
  5511. * @type Array
  5512. * @private
  5513. */
  5514. _markerCache: null,
  5515. /**
  5516. * Gets and styles a marker. If there is a marker in cache, it will use it. Otherwise
  5517. * it will create one.
  5518. *
  5519. * @method getMarker
  5520. * @param {Object} styles Hash of style properties.
  5521. * @param {Number} order Order of the series.
  5522. * @param {Number} index Index within the series associated with the marker.
  5523. * @return Shape
  5524. * @protected
  5525. */
  5526. getMarker: function(styles, order, index)
  5527. {
  5528. var marker,
  5529. border = styles.border;
  5530. styles.id = this.get("chart").get("id") + "_" + order + "_" + index;
  5531. //fix name differences between graphic layer
  5532. border.opacity = border.alpha;
  5533. styles.stroke = border;
  5534. styles.fill.opacity = styles.fill.alpha;
  5535. if(this._markerCache.length > 0)
  5536. {
  5537. while(!marker)
  5538. {
  5539. if(this._markerCache.length < 1)
  5540. {
  5541. marker = this._createMarker(styles, order, index);
  5542. break;
  5543. }
  5544. marker = this._markerCache.shift();
  5545. }
  5546. marker.set(styles);
  5547. }
  5548. else
  5549. {
  5550. marker = this._createMarker(styles, order, index);
  5551. }
  5552. this._markers.push(marker);
  5553. return marker;
  5554. },
  5555. /**
  5556. * Creates a shape to be used as a marker.
  5557. *
  5558. * @method _createMarker
  5559. * @param {Object} styles Hash of style properties.
  5560. * @param {Number} order Order of the series.
  5561. * @param {Number} index Index within the series associated with the marker.
  5562. * @return Shape
  5563. * @private
  5564. */
  5565. _createMarker: function(styles, order, index)
  5566. {
  5567. var graphic = this.get("graphic"),
  5568. marker,
  5569. cfg = Y.clone(styles);
  5570. graphic.set("autoDraw", false);
  5571. cfg.type = cfg.shape;
  5572. marker = graphic.addShape(cfg);
  5573. marker.addClass(SERIES_MARKER);
  5574. return marker;
  5575. },
  5576. /**
  5577. * Creates a cache of markers for reuse.
  5578. *
  5579. * @method _createMarkerCache
  5580. * @private
  5581. */
  5582. _createMarkerCache: function()
  5583. {
  5584. if(this._markers && this._markers.length > 0)
  5585. {
  5586. this._markerCache = this._markers.concat();
  5587. }
  5588. else
  5589. {
  5590. this._markerCache = [];
  5591. }
  5592. this._markers = [];
  5593. },
  5594. /**
  5595. * Toggles visibility
  5596. *
  5597. * @method _toggleVisible
  5598. * @param {Boolean} visible indicates visibilitye
  5599. * @private
  5600. */
  5601. _toggleVisible: function(visible)
  5602. {
  5603. var marker,
  5604. markers = this.get("markers"),
  5605. i = 0,
  5606. len;
  5607. if(markers)
  5608. {
  5609. len = markers.length;
  5610. for(; i < len; ++i)
  5611. {
  5612. marker = markers[i];
  5613. if(marker)
  5614. {
  5615. marker.set("visible", visible);
  5616. }
  5617. }
  5618. }
  5619. },
  5620. /**
  5621. * Removes unused markers from the marker cache
  5622. *
  5623. * @method _clearMarkerCache
  5624. * @private
  5625. */
  5626. _clearMarkerCache: function()
  5627. {
  5628. var marker;
  5629. while(this._markerCache.length > 0)
  5630. {
  5631. marker = this._markerCache.shift();
  5632. if(marker)
  5633. {
  5634. marker.destroy();
  5635. }
  5636. }
  5637. },
  5638. /**
  5639. * Resizes and positions markers based on a mouse interaction.
  5640. *
  5641. * @method updateMarkerState
  5642. * @param {String} type state of the marker
  5643. * @param {Number} i index of the marker
  5644. * @protected
  5645. */
  5646. updateMarkerState: function(type, i)
  5647. {
  5648. if(this._markers[i])
  5649. {
  5650. var w,
  5651. h,
  5652. styles = Y.clone(this.get("styles").marker),
  5653. state = this._getState(type),
  5654. xcoords = this.get("xcoords"),
  5655. ycoords = this.get("ycoords"),
  5656. marker = this._markers[i],
  5657. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  5658. markerStyles.fill.color = this._getItemColor(markerStyles.fill.color, i);
  5659. markerStyles.border.color = this._getItemColor(markerStyles.border.color, i);
  5660. markerStyles.stroke = markerStyles.border;
  5661. marker.set(markerStyles);
  5662. w = markerStyles.width;
  5663. h = markerStyles.height;
  5664. marker.set("x", (xcoords[i] - w/2));
  5665. marker.set("y", (ycoords[i] - h/2));
  5666. marker.set("visible", this.get("visible"));
  5667. }
  5668. },
  5669. /**
  5670. * Parses a color from an array.
  5671. *
  5672. * @method _getItemColor
  5673. * @param {Array} val collection of colors
  5674. * @param {Number} i index of the item
  5675. * @return String
  5676. * @protected
  5677. */
  5678. _getItemColor: function(val, i)
  5679. {
  5680. if(Y_Lang.isArray(val))
  5681. {
  5682. return val[i % val.length];
  5683. }
  5684. return val;
  5685. },
  5686. /**
  5687. * Method used by `styles` setter. Overrides base implementation.
  5688. *
  5689. * @method _setStyles
  5690. * @param {Object} newStyles Hash of properties to update.
  5691. * @return Object
  5692. * @protected
  5693. */
  5694. _setStyles: function(val)
  5695. {
  5696. val = this._parseMarkerStyles(val);
  5697. return Y.Renderer.prototype._setStyles.apply(this, [val]);
  5698. },
  5699. /**
  5700. * Combines new styles with existing styles.
  5701. *
  5702. * @method _parseMarkerStyles
  5703. * @param {Object} Object containing style properties for the marker.
  5704. * @return Object
  5705. * @private
  5706. */
  5707. _parseMarkerStyles: function(val)
  5708. {
  5709. if(val.marker)
  5710. {
  5711. var defs = this._getPlotDefaults();
  5712. val.marker = this._mergeStyles(val.marker, defs);
  5713. if(val.marker.over)
  5714. {
  5715. val.marker.over = this._mergeStyles(val.marker.over, val.marker);
  5716. }
  5717. if(val.marker.down)
  5718. {
  5719. val.marker.down = this._mergeStyles(val.marker.down, val.marker);
  5720. }
  5721. }
  5722. return val;
  5723. },
  5724. /**
  5725. * Returns marker state based on event type
  5726. *
  5727. * @method _getState
  5728. * @param {String} type event type
  5729. * @return String
  5730. * @protected
  5731. */
  5732. _getState: function(type)
  5733. {
  5734. var state;
  5735. switch(type)
  5736. {
  5737. case "mouseout" :
  5738. state = "off";
  5739. break;
  5740. case "mouseover" :
  5741. state = "over";
  5742. break;
  5743. case "mouseup" :
  5744. state = "over";
  5745. break;
  5746. case "mousedown" :
  5747. state = "down";
  5748. break;
  5749. }
  5750. return state;
  5751. },
  5752. /**
  5753. * @property _statSyles
  5754. * @type Object
  5755. * @private
  5756. */
  5757. _stateSyles: null
  5758. };
  5759. Y.augment(Plots, Y.Attribute);
  5760. Y.Plots = Plots;
  5761. /**
  5762. * Histogram is the base class for Column and Bar series.
  5763. *
  5764. * @module charts
  5765. * @class Histogram
  5766. * @constructor
  5767. */
  5768. function Histogram(){}
  5769. Histogram.prototype = {
  5770. /**
  5771. * Draws the series.
  5772. *
  5773. * @method drawSeries
  5774. * @protected
  5775. */
  5776. drawSeries: function()
  5777. {
  5778. if(this.get("xcoords").length < 1)
  5779. {
  5780. return;
  5781. }
  5782. var style = Y.clone(this.get("styles").marker),
  5783. setSize,
  5784. calculatedSize,
  5785. xcoords = this.get("xcoords"),
  5786. ycoords = this.get("ycoords"),
  5787. i = 0,
  5788. len = xcoords.length,
  5789. top = ycoords[0],
  5790. type = this.get("type"),
  5791. graph = this.get("graph"),
  5792. seriesCollection = graph.seriesTypes[type],
  5793. seriesLen = seriesCollection.length,
  5794. seriesSize = 0,
  5795. totalSize = 0,
  5796. offset = 0,
  5797. ratio,
  5798. renderer,
  5799. order = this.get("order"),
  5800. graphOrder = this.get("graphOrder"),
  5801. left,
  5802. marker,
  5803. setSizeKey,
  5804. calculatedSizeKey,
  5805. config,
  5806. fillColors = null,
  5807. borderColors = null;
  5808. if(Y_Lang.isArray(style.fill.color))
  5809. {
  5810. fillColors = style.fill.color.concat();
  5811. }
  5812. if(Y_Lang.isArray(style.border.color))
  5813. {
  5814. borderColors = style.border.colors.concat();
  5815. }
  5816. if(this.get("direction") == "vertical")
  5817. {
  5818. setSizeKey = "height";
  5819. calculatedSizeKey = "width";
  5820. }
  5821. else
  5822. {
  5823. setSizeKey = "width";
  5824. calculatedSizeKey = "height";
  5825. }
  5826. setSize = style[setSizeKey];
  5827. calculatedSize = style[calculatedSizeKey];
  5828. this._createMarkerCache();
  5829. for(; i < seriesLen; ++i)
  5830. {
  5831. renderer = seriesCollection[i];
  5832. seriesSize += renderer.get("styles").marker[setSizeKey];
  5833. if(order > i)
  5834. {
  5835. offset = seriesSize;
  5836. }
  5837. }
  5838. totalSize = len * seriesSize;
  5839. if(totalSize > graph.get(setSizeKey))
  5840. {
  5841. ratio = graph.get(setSizeKey)/totalSize;
  5842. seriesSize *= ratio;
  5843. offset *= ratio;
  5844. setSize *= ratio;
  5845. setSize = Math.max(setSize, 1);
  5846. }
  5847. offset -= seriesSize/2;
  5848. for(i = 0; i < len; ++i)
  5849. {
  5850. if(isNaN(xcoords[i]) || isNaN(ycoords[i]))
  5851. {
  5852. this._markers.push(null);
  5853. continue;
  5854. }
  5855. config = this._getMarkerDimensions(xcoords[i], ycoords[i], calculatedSize, offset);
  5856. if(!isNaN(config.calculatedSize) && config.calculatedSize > 0)
  5857. {
  5858. top = config.top;
  5859. left = config.left;
  5860. style[setSizeKey] = setSize;
  5861. style[calculatedSizeKey] = config.calculatedSize;
  5862. style.x = left;
  5863. style.y = top;
  5864. if(fillColors)
  5865. {
  5866. style.fill.color = fillColors[i % fillColors.length];
  5867. }
  5868. if(borderColors)
  5869. {
  5870. style.border.colors = borderColors[i % borderColors.length];
  5871. }
  5872. marker = this.getMarker(style, graphOrder, i);
  5873. }
  5874. else
  5875. {
  5876. this._markers.push(null);
  5877. }
  5878. }
  5879. this._clearMarkerCache();
  5880. },
  5881. /**
  5882. * Collection of default colors used for marker fills in a series when not specified by user.
  5883. *
  5884. * @property _defaultFillColors
  5885. * @type Array
  5886. * @protected
  5887. */
  5888. _defaultFillColors: ["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"],
  5889. /**
  5890. * Gets the default style values for the markers.
  5891. *
  5892. * @method _getPlotDefaults
  5893. * @return Object
  5894. * @private
  5895. */
  5896. _getPlotDefaults: function()
  5897. {
  5898. var defs = {
  5899. fill:{
  5900. type: "solid",
  5901. alpha: 1,
  5902. colors:null,
  5903. alphas: null,
  5904. ratios: null
  5905. },
  5906. border:{
  5907. weight: 0,
  5908. alpha: 1
  5909. },
  5910. width: 12,
  5911. height: 12,
  5912. shape: "rect",
  5913. padding:{
  5914. top: 0,
  5915. left: 0,
  5916. right: 0,
  5917. bottom: 0
  5918. }
  5919. };
  5920. defs.fill.color = this._getDefaultColor(this.get("graphOrder"), "fill");
  5921. defs.border.color = this._getDefaultColor(this.get("graphOrder"), "border");
  5922. return defs;
  5923. }
  5924. };
  5925. Y.Histogram = Histogram;
  5926. /**
  5927. * The CartesianSeries class creates a chart with horizontal and vertical axes.
  5928. *
  5929. * @module charts
  5930. * @class CartesianSeries
  5931. * @extends Base
  5932. * @uses Renderer
  5933. * @constructor
  5934. */
  5935. Y.CartesianSeries = Y.Base.create("cartesianSeries", Y.Base, [Y.Renderer], {
  5936. /**
  5937. * Storage for `xDisplayName` attribute.
  5938. *
  5939. * @property _xDisplayName
  5940. * @type String
  5941. * @private
  5942. */
  5943. _xDisplayName: null,
  5944. /**
  5945. * Storage for `yDisplayName` attribute.
  5946. *
  5947. * @property _yDisplayName
  5948. * @type String
  5949. * @private
  5950. */
  5951. _yDisplayName: null,
  5952. /**
  5953. * Th x-coordinate for the left edge of the series.
  5954. *
  5955. * @property _leftOrigin
  5956. * @type String
  5957. * @private
  5958. */
  5959. _leftOrigin: null,
  5960. /**
  5961. * The y-coordinate for the bottom edge of the series.
  5962. *
  5963. * @property _bottomOrigin
  5964. * @type String
  5965. * @private
  5966. */
  5967. _bottomOrigin: null,
  5968. /**
  5969. * @method render
  5970. * @private
  5971. */
  5972. render: function()
  5973. {
  5974. this._setCanvas();
  5975. this.addListeners();
  5976. this.set("rendered", true);
  5977. this.validate();
  5978. },
  5979. /**
  5980. * Adds event listeners.
  5981. *
  5982. * @method addListeners
  5983. * @private
  5984. */
  5985. addListeners: function()
  5986. {
  5987. var xAxis = this.get("xAxis"),
  5988. yAxis = this.get("yAxis");
  5989. if(xAxis)
  5990. {
  5991. xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this));
  5992. xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this));
  5993. }
  5994. if(yAxis)
  5995. {
  5996. yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this));
  5997. yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this));
  5998. }
  5999. this.after("xAxisChange", this._xAxisChangeHandler);
  6000. this.after("yAxisChange", this._yAxisChangeHandler);
  6001. this.after("stylesChange", function(e) {
  6002. var axesReady = this._updateAxisData();
  6003. if(axesReady)
  6004. {
  6005. this.draw();
  6006. }
  6007. });
  6008. this.after("widthChange", function(e) {
  6009. var axesReady = this._updateAxisData();
  6010. if(axesReady)
  6011. {
  6012. this.draw();
  6013. }
  6014. });
  6015. this.after("heightChange", function(e) {
  6016. var axesReady = this._updateAxisData();
  6017. if(axesReady)
  6018. {
  6019. this.draw();
  6020. }
  6021. });
  6022. this.after("visibleChange", this._handleVisibleChange);
  6023. },
  6024. /**
  6025. * Event handler for the xAxisChange event.
  6026. *
  6027. * @method _xAxisChangeHandler
  6028. * @param {Object} e Event object.
  6029. * @private
  6030. */
  6031. _xAxisChangeHandler: function(e)
  6032. {
  6033. var xAxis = this.get("xAxis");
  6034. xAxis.after("dataReady", Y.bind(this._xDataChangeHandler, this));
  6035. xAxis.after("dataUpdate", Y.bind(this._xDataChangeHandler, this));
  6036. },
  6037. /**
  6038. * Event handler the yAxisChange event.
  6039. *
  6040. * @method _yAxisChangeHandler
  6041. * @param {Object} e Event object.
  6042. * @private
  6043. */
  6044. _yAxisChangeHandler: function(e)
  6045. {
  6046. var yAxis = this.get("yAxis");
  6047. yAxis.after("dataReady", Y.bind(this._yDataChangeHandler, this));
  6048. yAxis.after("dataUpdate", Y.bind(this._yDataChangeHandler, this));
  6049. },
  6050. /**
  6051. * Constant used to generate unique id.
  6052. *
  6053. * @property GUID
  6054. * @type String
  6055. * @private
  6056. */
  6057. GUID: "yuicartesianseries",
  6058. /**
  6059. * Event handler for xDataChange event.
  6060. *
  6061. * @method _xDataChangeHandler
  6062. * @param {Object} event Event object.
  6063. * @private
  6064. */
  6065. _xDataChangeHandler: function(event)
  6066. {
  6067. var axesReady = this._updateAxisData();
  6068. if(axesReady)
  6069. {
  6070. this.draw();
  6071. }
  6072. },
  6073. /**
  6074. * Event handler for yDataChange event.
  6075. *
  6076. * @method _yDataChangeHandler
  6077. * @param {Object} event Event object.
  6078. * @private
  6079. */
  6080. _yDataChangeHandler: function(event)
  6081. {
  6082. var axesReady = this._updateAxisData();
  6083. if(axesReady)
  6084. {
  6085. this.draw();
  6086. }
  6087. },
  6088. /**
  6089. * Checks to ensure that both xAxis and yAxis data are available. If so, set the `xData` and `yData` attributes and return `true`. Otherwise, return `false`.
  6090. *
  6091. * @method _updateAxisData
  6092. * @return Boolean
  6093. * @private
  6094. */
  6095. _updateAxisData: function()
  6096. {
  6097. var xAxis = this.get("xAxis"),
  6098. yAxis = this.get("yAxis"),
  6099. xKey = this.get("xKey"),
  6100. yKey = this.get("yKey"),
  6101. yData,
  6102. xData;
  6103. if(!xAxis || !yAxis || !xKey || !yKey)
  6104. {
  6105. return false;
  6106. }
  6107. xData = xAxis.getDataByKey(xKey);
  6108. yData = yAxis.getDataByKey(yKey);
  6109. if(!xData || !yData)
  6110. {
  6111. return false;
  6112. }
  6113. this.set("xData", xData.concat());
  6114. this.set("yData", yData.concat());
  6115. return true;
  6116. },
  6117. /**
  6118. * Draws the series is the xAxis and yAxis data are both available.
  6119. *
  6120. * @method validate
  6121. * @private
  6122. */
  6123. validate: function()
  6124. {
  6125. if((this.get("xData") && this.get("yData")) || this._updateAxisData())
  6126. {
  6127. this.draw();
  6128. }
  6129. else
  6130. {
  6131. this.fire("drawingComplete");
  6132. }
  6133. },
  6134. /**
  6135. * Creates a `Graphic` instance.
  6136. *
  6137. * @method _setCanvas
  6138. * @protected
  6139. */
  6140. _setCanvas: function()
  6141. {
  6142. var graph = this.get("graph"),
  6143. graphic = graph.get("graphic");
  6144. this.set("graphic", graphic);
  6145. },
  6146. /**
  6147. * Calculates the coordinates for the series.
  6148. *
  6149. * @method setAreaData
  6150. * @protected
  6151. */
  6152. setAreaData: function()
  6153. {
  6154. var isNumber = Y_Lang.isNumber,
  6155. nextX, nextY,
  6156. graph = this.get("graph"),
  6157. w = graph.get("width"),
  6158. h = graph.get("height"),
  6159. xAxis = this.get("xAxis"),
  6160. yAxis = this.get("yAxis"),
  6161. xData = this.get("xData").concat(),
  6162. yData = this.get("yData").concat(),
  6163. xValue,
  6164. yValue,
  6165. xOffset = xAxis.getEdgeOffset(xData.length, w),
  6166. yOffset = yAxis.getEdgeOffset(yData.length, h),
  6167. padding = this.get("styles").padding,
  6168. leftPadding = padding.left,
  6169. topPadding = padding.top,
  6170. dataWidth = w - (leftPadding + padding.right + xOffset),
  6171. dataHeight = h - (topPadding + padding.bottom + yOffset),
  6172. xcoords = [],
  6173. ycoords = [],
  6174. xMax = xAxis.get("maximum"),
  6175. xMin = xAxis.get("minimum"),
  6176. yMax = yAxis.get("maximum"),
  6177. yMin = yAxis.get("minimum"),
  6178. xScaleFactor = dataWidth / (xMax - xMin),
  6179. yScaleFactor = dataHeight / (yMax - yMin),
  6180. dataLength,
  6181. direction = this.get("direction"),
  6182. i = 0,
  6183. xMarkerPlane = [],
  6184. yMarkerPlane = [],
  6185. xMarkerPlaneOffset = this.get("xMarkerPlaneOffset"),
  6186. yMarkerPlaneOffset = this.get("yMarkerPlaneOffset"),
  6187. graphic = this.get("graphic");
  6188. graphic.set("width", w);
  6189. graphic.set("height", h);
  6190. dataLength = xData.length;
  6191. xOffset *= 0.5;
  6192. yOffset *= 0.5;
  6193. //Assuming a vertical graph has a range/category for its vertical axis.
  6194. if(direction === "vertical")
  6195. {
  6196. yData = yData.reverse();
  6197. }
  6198. this._leftOrigin = Math.round(((0 - xMin) * xScaleFactor) + leftPadding + xOffset);
  6199. this._bottomOrigin = Math.round((dataHeight + topPadding + yOffset) - (0 - yMin) * yScaleFactor);
  6200. for (; i < dataLength; ++i)
  6201. {
  6202. xValue = parseFloat(xData[i]);
  6203. yValue = parseFloat(yData[i]);
  6204. if(isNumber(xValue))
  6205. {
  6206. nextX = Math.round((((xValue - xMin) * xScaleFactor) + leftPadding + xOffset));
  6207. }
  6208. else
  6209. {
  6210. nextX = NaN;
  6211. }
  6212. if(isNumber(yValue))
  6213. {
  6214. nextY = Math.round(((dataHeight + topPadding + yOffset) - (yValue - yMin) * yScaleFactor));
  6215. }
  6216. else
  6217. {
  6218. nextY = NaN;
  6219. }
  6220. xcoords.push(nextX);
  6221. ycoords.push(nextY);
  6222. xMarkerPlane.push({start:nextX - xMarkerPlaneOffset, end: nextX + xMarkerPlaneOffset});
  6223. yMarkerPlane.push({start:nextY - yMarkerPlaneOffset, end: nextY + yMarkerPlaneOffset});
  6224. }
  6225. this.set("xcoords", xcoords);
  6226. this.set("ycoords", ycoords);
  6227. this.set("xMarkerPlane", xMarkerPlane);
  6228. this.set("yMarkerPlane", yMarkerPlane);
  6229. },
  6230. /**
  6231. * Draws the series.
  6232. *
  6233. * @method draw
  6234. * @protected
  6235. */
  6236. draw: function()
  6237. {
  6238. var graph = this.get("graph"),
  6239. w = graph.get("width"),
  6240. h = graph.get("height");
  6241. if(this.get("rendered"))
  6242. {
  6243. if((isFinite(w) && isFinite(h) && w > 0 && h > 0) && ((this.get("xData") && this.get("yData")) || this._updateAxisData()))
  6244. {
  6245. if(this._drawing)
  6246. {
  6247. this._callLater = true;
  6248. return;
  6249. }
  6250. this._drawing = true;
  6251. this._callLater = false;
  6252. this.setAreaData();
  6253. if(this.get("xcoords") && this.get("ycoords"))
  6254. {
  6255. this.drawSeries();
  6256. }
  6257. this._drawing = false;
  6258. if(this._callLater)
  6259. {
  6260. this.draw();
  6261. }
  6262. else
  6263. {
  6264. this._toggleVisible(this.get("visible"));
  6265. this.fire("drawingComplete");
  6266. }
  6267. }
  6268. }
  6269. },
  6270. /**
  6271. * Default value for plane offsets when the parent chart's `interactiveType` is `planar`.
  6272. *
  6273. * @property _defaultPlaneOffset
  6274. * @type Number
  6275. * @private
  6276. */
  6277. _defaultPlaneOffset: 4,
  6278. /**
  6279. * Gets the default value for the `styles` attribute. Overrides
  6280. * base implementation.
  6281. *
  6282. * @method _getDefaultStyles
  6283. * @return Object
  6284. * @protected
  6285. */
  6286. _getDefaultStyles: function()
  6287. {
  6288. return {padding:{
  6289. top: 0,
  6290. left: 0,
  6291. right: 0,
  6292. bottom: 0
  6293. }};
  6294. },
  6295. /**
  6296. * Collection of default colors used for lines in a series when not specified by user.
  6297. *
  6298. * @property _defaultLineColors
  6299. * @type Array
  6300. * @protected
  6301. */
  6302. _defaultLineColors:["#426ab3", "#d09b2c", "#000000", "#b82837", "#b384b5", "#ff7200", "#779de3", "#cbc8ba", "#7ed7a6", "#007a6c"],
  6303. /**
  6304. * Collection of default colors used for marker fills in a series when not specified by user.
  6305. *
  6306. * @property _defaultFillColors
  6307. * @type Array
  6308. * @protected
  6309. */
  6310. _defaultFillColors:["#6084d0", "#eeb647", "#6c6b5f", "#d6484f", "#ce9ed1", "#ff9f3b", "#93b7ff", "#e0ddd0", "#94ecba", "#309687"],
  6311. /**
  6312. * Collection of default colors used for marker borders in a series when not specified by user.
  6313. *
  6314. * @property _defaultBorderColors
  6315. * @type Array
  6316. * @protected
  6317. */
  6318. _defaultBorderColors:["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"],
  6319. /**
  6320. * Collection of default colors used for area fills, histogram fills and pie fills in a series when not specified by user.
  6321. *
  6322. * @property _defaultSliceColors
  6323. * @type Array
  6324. * @protected
  6325. */
  6326. _defaultSliceColors: ["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"],
  6327. /**
  6328. * Parses a color based on a series order and type.
  6329. *
  6330. * @method _getDefaultColor
  6331. * @param {Number} index Index indicating the series order.
  6332. * @param {String} type Indicates which type of object needs the color.
  6333. * @return String
  6334. * @protected
  6335. */
  6336. _getDefaultColor: function(index, type)
  6337. {
  6338. var colors = {
  6339. line: this._defaultLineColors,
  6340. fill: this._defaultFillColors,
  6341. border: this._defaultBorderColors,
  6342. slice: this._defaultSliceColors
  6343. },
  6344. col = colors[type],
  6345. l = col.length;
  6346. index = index || 0;
  6347. if(index >= l)
  6348. {
  6349. index = index % l;
  6350. }
  6351. type = type || "fill";
  6352. return colors[type][index];
  6353. },
  6354. /**
  6355. * Shows/hides contents of the series.
  6356. *
  6357. * @method _handleVisibleChange
  6358. * @param {Object} e Event object.
  6359. * @protected
  6360. */
  6361. _handleVisibleChange: function(e)
  6362. {
  6363. this._toggleVisible(this.get("visible"));
  6364. }
  6365. }, {
  6366. ATTRS: {
  6367. /**
  6368. * Name used for for displaying data related to the x-coordinate.
  6369. *
  6370. * @attribute xDisplayName
  6371. * @type String
  6372. */
  6373. xDisplayName: {
  6374. getter: function()
  6375. {
  6376. return this._xDisplayName || this.get("xKey");
  6377. },
  6378. setter: function(val)
  6379. {
  6380. this._xDisplayName = val;
  6381. return val;
  6382. }
  6383. },
  6384. /**
  6385. * Name used for for displaying data related to the y-coordinate.
  6386. *
  6387. * @attribute yDisplayName
  6388. * @type String
  6389. */
  6390. yDisplayName: {
  6391. getter: function()
  6392. {
  6393. return this._yDisplayName || this.get("yKey");
  6394. },
  6395. setter: function(val)
  6396. {
  6397. this._yDisplayName = val;
  6398. return val;
  6399. }
  6400. },
  6401. /**
  6402. * Name used for for displaying category data
  6403. *
  6404. * @attribute categoryDisplayName
  6405. * @type String
  6406. * @readOnly
  6407. */
  6408. categoryDisplayName: {
  6409. readOnly: true,
  6410. getter: function()
  6411. {
  6412. return this.get("direction") == "vertical" ? this.get("yDisplayName") : this.get("xDisplayName");
  6413. }
  6414. },
  6415. /**
  6416. * Name used for for displaying value data
  6417. *
  6418. * @attribute valueDisplayName
  6419. * @type String
  6420. * @readOnly
  6421. */
  6422. valueDisplayName: {
  6423. readOnly: true,
  6424. getter: function()
  6425. {
  6426. return this.get("direction") == "vertical" ? this.get("xDisplayName") : this.get("yDisplayName");
  6427. }
  6428. },
  6429. /**
  6430. * Read-only attribute indicating the type of series.
  6431. *
  6432. * @attribute type
  6433. * @type String
  6434. * @default cartesian
  6435. */
  6436. type: {
  6437. value: "cartesian"
  6438. },
  6439. /**
  6440. * Order of this instance of this `type`.
  6441. *
  6442. * @attribute order
  6443. * @type Number
  6444. */
  6445. order: {},
  6446. /**
  6447. * Order of the instance
  6448. *
  6449. * @attribute graphOrder
  6450. * @type Number
  6451. */
  6452. graphOrder: {},
  6453. /**
  6454. * x coordinates for the series.
  6455. *
  6456. * @attribute xcoords
  6457. * @type Array
  6458. */
  6459. xcoords: {},
  6460. /**
  6461. * y coordinates for the series
  6462. *
  6463. * @attribute ycoords
  6464. * @type Array
  6465. */
  6466. ycoords: {},
  6467. /**
  6468. * Reference to the `Chart` application.
  6469. *
  6470. * @attribute chart
  6471. * @type ChartBase
  6472. * @readOnly
  6473. */
  6474. chart: {
  6475. readOnly: true,
  6476. getter: function()
  6477. {
  6478. return this.get("graph").get("chart");
  6479. }
  6480. },
  6481. /**
  6482. * Reference to the `Graph` in which the series is drawn into.
  6483. *
  6484. * @attribute graph
  6485. * @type Graph
  6486. */
  6487. graph: {},
  6488. /**
  6489. * Reference to the `Axis` instance used for assigning
  6490. * x-values to the graph.
  6491. *
  6492. * @attribute xAxis
  6493. * @type Axis
  6494. */
  6495. xAxis: {},
  6496. /**
  6497. * Reference to the `Axis` instance used for assigning
  6498. * y-values to the graph.
  6499. *
  6500. * @attribute yAxis
  6501. * @type Axis
  6502. */
  6503. yAxis: {},
  6504. /**
  6505. * Indicates which array to from the hash of value arrays in
  6506. * the x-axis `Axis` instance.
  6507. *
  6508. * @attribute xKey
  6509. * @type String
  6510. */
  6511. xKey: {},
  6512. /**
  6513. * Indicates which array to from the hash of value arrays in
  6514. * the y-axis `Axis` instance.
  6515. *
  6516. * @attribute yKey
  6517. * @type String
  6518. */
  6519. yKey: {},
  6520. /**
  6521. * Array of x values for the series.
  6522. *
  6523. * @attribute xData
  6524. * @type Array
  6525. */
  6526. xData: {},
  6527. /**
  6528. * Array of y values for the series.
  6529. *
  6530. * @attribute yData
  6531. * @type Array
  6532. */
  6533. yData: {},
  6534. /**
  6535. * Indicates whether the Series has been through its initial set up.
  6536. *
  6537. * @attribute rendered
  6538. * @type Boolean
  6539. */
  6540. rendered: {
  6541. value: false
  6542. },
  6543. /*
  6544. * Returns the width of the parent graph
  6545. *
  6546. * @attribute width
  6547. * @type Number
  6548. */
  6549. width: {
  6550. readOnly: true,
  6551. getter: function()
  6552. {
  6553. this.get("graph").get("width");
  6554. }
  6555. },
  6556. /**
  6557. * Returns the height of the parent graph
  6558. *
  6559. * @attribute height
  6560. * @type Number
  6561. */
  6562. height: {
  6563. readOnly: true,
  6564. getter: function()
  6565. {
  6566. this.get("graph").get("height");
  6567. }
  6568. },
  6569. /**
  6570. * Indicates whether to show the series
  6571. *
  6572. * @attribute visible
  6573. * @type Boolean
  6574. * @default true
  6575. */
  6576. visible: {
  6577. value: true
  6578. },
  6579. /**
  6580. * Collection of area maps along the xAxis. Used to determine mouseover for multiple
  6581. * series.
  6582. *
  6583. * @attribute xMarkerPlane
  6584. * @type Array
  6585. */
  6586. xMarkerPlane: {},
  6587. /**
  6588. * Collection of area maps along the yAxis. Used to determine mouseover for multiple
  6589. * series.
  6590. *
  6591. * @attribute yMarkerPlane
  6592. * @type Array
  6593. */
  6594. yMarkerPlane: {},
  6595. /**
  6596. * Distance from a data coordinate to the left/right for setting a hotspot.
  6597. *
  6598. * @attribute xMarkerPlaneOffset
  6599. * @type Number
  6600. */
  6601. xMarkerPlaneOffset: {
  6602. getter: function() {
  6603. var marker = this.get("styles").marker;
  6604. if(marker && marker.width && isFinite(marker.width))
  6605. {
  6606. return marker.width * 0.5;
  6607. }
  6608. return this._defaultPlaneOffset;
  6609. }
  6610. },
  6611. /**
  6612. * Distance from a data coordinate to the top/bottom for setting a hotspot.
  6613. *
  6614. * @attribute yMarkerPlaneOffset
  6615. * @type Number
  6616. */
  6617. yMarkerPlaneOffset: {
  6618. getter: function() {
  6619. var marker = this.get("styles").marker;
  6620. if(marker && marker.height && isFinite(marker.height))
  6621. {
  6622. return marker.height * 0.5;
  6623. }
  6624. return this._defaultPlaneOffset;
  6625. }
  6626. },
  6627. /**
  6628. * Direction of the series
  6629. *
  6630. * @attribute direction
  6631. * @type String
  6632. */
  6633. direction: {
  6634. value: "horizontal"
  6635. }
  6636. }
  6637. });
  6638. /**
  6639. * The MarkerSeries class renders quantitative data by plotting relevant data points
  6640. * on a graph.
  6641. *
  6642. * @module charts
  6643. * @class MarkerSeries
  6644. * @extends CartesianSeries
  6645. * @uses Plots
  6646. * @constructor
  6647. */
  6648. Y.MarkerSeries = Y.Base.create("markerSeries", Y.CartesianSeries, [Y.Plots], {
  6649. /**
  6650. * @protected
  6651. *
  6652. * Draws the series.
  6653. *
  6654. * @method drawSeries
  6655. */
  6656. drawSeries: function()
  6657. {
  6658. this.drawPlots();
  6659. },
  6660. /**
  6661. * @protected
  6662. *
  6663. * Method used by `styles` setter. Overrides base implementation.
  6664. *
  6665. * @method _setStyles
  6666. * @param {Object} newStyles Hash of properties to update.
  6667. * @return Object
  6668. */
  6669. _setStyles: function(val)
  6670. {
  6671. if(!val.marker)
  6672. {
  6673. val = {marker:val};
  6674. }
  6675. val = this._parseMarkerStyles(val);
  6676. return Y.MarkerSeries.superclass._mergeStyles.apply(this, [val, this._getDefaultStyles()]);
  6677. },
  6678. /**
  6679. * @protected
  6680. *
  6681. * Gets the default value for the `styles` attribute. Overrides
  6682. * base implementation.
  6683. *
  6684. * @method _getDefaultStyles
  6685. * @return Object
  6686. */
  6687. _getDefaultStyles: function()
  6688. {
  6689. var styles = this._mergeStyles({marker:this._getPlotDefaults()}, Y.MarkerSeries.superclass._getDefaultStyles());
  6690. return styles;
  6691. }
  6692. },{
  6693. ATTRS : {
  6694. /**
  6695. * Read-only attribute indicating the type of series.
  6696. *
  6697. * @attribute type
  6698. * @type String
  6699. * @default marker
  6700. */
  6701. type: {
  6702. value:"marker"
  6703. }
  6704. /**
  6705. * Style properties used for drawing markers. This attribute is inherited from `Renderer`. Below are the default values:
  6706. * <dl>
  6707. * <dt>fill</dt><dd>A hash containing the following values:
  6708. * <dl>
  6709. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  6710. * will be retrieved from the below array:<br/>
  6711. * `["#6084d0", "#eeb647", "#6c6b5f", "#d6484f", "#ce9ed1", "#ff9f3b", "#93b7ff", "#e0ddd0", "#94ecba", "#309687"]`
  6712. * </dd>
  6713. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  6714. * </dl>
  6715. * </dd>
  6716. * <dt>border</dt><dd>A hash containing the following values:
  6717. * <dl>
  6718. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  6719. * will be retrieved from the below array:<br/>
  6720. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  6721. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  6722. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  6723. * </dl>
  6724. * </dd>
  6725. * <dt>width</dt><dd>indicates the width of the marker. The default value is 10.</dd>
  6726. * <dt>height</dt><dd>indicates the height of the marker The default value is 10.</dd>
  6727. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  6728. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  6729. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  6730. * </dl>
  6731. *
  6732. * @attribute styles
  6733. * @type Object
  6734. */
  6735. }
  6736. });
  6737. /**
  6738. * The LineSeries class renders quantitative data on a graph by connecting relevant data points.
  6739. *
  6740. * @module charts
  6741. * @class LineSeries
  6742. * @extends CartesianSeries
  6743. * @uses Lines
  6744. * @constructor
  6745. */
  6746. Y.LineSeries = Y.Base.create("lineSeries", Y.CartesianSeries, [Y.Lines], {
  6747. /**
  6748. * @protected
  6749. *
  6750. * @method drawSeries
  6751. */
  6752. drawSeries: function()
  6753. {
  6754. this.drawLines();
  6755. },
  6756. /**
  6757. * @protected
  6758. *
  6759. * Method used by `styles` setter. Overrides base implementation.
  6760. *
  6761. * @method _setStyles
  6762. * @param {Object} newStyles Hash of properties to update.
  6763. * @return Object
  6764. */
  6765. _setStyles: function(val)
  6766. {
  6767. if(!val.line)
  6768. {
  6769. val = {line:val};
  6770. }
  6771. return Y.LineSeries.superclass._setStyles.apply(this, [val]);
  6772. },
  6773. /**
  6774. * @protected
  6775. *
  6776. * Gets the default value for the `styles` attribute. Overrides
  6777. * base implementation.
  6778. *
  6779. * @method _getDefaultStyles
  6780. * @return Object
  6781. */
  6782. _getDefaultStyles: function()
  6783. {
  6784. var styles = this._mergeStyles({line:this._getLineDefaults()}, Y.LineSeries.superclass._getDefaultStyles());
  6785. return styles;
  6786. }
  6787. },
  6788. {
  6789. ATTRS: {
  6790. /**
  6791. * Read-only attribute indicating the type of series.
  6792. *
  6793. * @attribute type
  6794. * @type String
  6795. * @default line
  6796. */
  6797. type: {
  6798. value:"line"
  6799. }
  6800. /**
  6801. * Style properties used for drawing lines. This attribute is inherited from `Renderer`. Below are the default values:
  6802. * <dl>
  6803. * <dt>color</dt><dd>The color of the line. The default value is determined by the order of the series on the graph. The color will be
  6804. * retrieved from the following array:
  6805. * `["#426ab3", "#d09b2c", "#000000", "#b82837", "#b384b5", "#ff7200", "#779de3", "#cbc8ba", "#7ed7a6", "#007a6c"]`
  6806. * <dt>weight</dt><dd>Number that indicates the width of the line. The default value is 6.</dd>
  6807. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the line. The default value is 1.</dd>
  6808. * <dt>lineType</dt><dd>Indicates whether the line is solid or dashed. The default value is solid.</dd>
  6809. * <dt>dashLength</dt><dd>When the `lineType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  6810. * <dt>gapSpace</dt><dd>When the `lineType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  6811. * <dt>connectDiscontinuousPoints</dt><dd>Indicates whether or not to connect lines when there is a missing or null value between points. The default value is true.</dd>
  6812. * <dt>discontinuousType</dt><dd>Indicates whether the line between discontinuous points is solid or dashed. The default value is solid.</dd>
  6813. * <dt>discontinuousDashLength</dt><dd>When the `discontinuousType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  6814. * <dt>discontinuousGapSpace</dt><dd>When the `discontinuousType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  6815. * </dl>
  6816. *
  6817. * @attribute styles
  6818. * @type Object
  6819. */
  6820. }
  6821. });
  6822. /**
  6823. * SplineSeries renders a graph with data points connected by a curve.
  6824. *
  6825. * @module charts
  6826. * @class SplineSeries
  6827. * @constructor
  6828. * @extends CartesianSeries
  6829. * @uses CurveUtil
  6830. * @uses Lines
  6831. */
  6832. Y.SplineSeries = Y.Base.create("splineSeries", Y.LineSeries, [Y.CurveUtil, Y.Lines], {
  6833. /**
  6834. * @protected
  6835. *
  6836. * Draws the series.
  6837. *
  6838. * @method drawSeries
  6839. */
  6840. drawSeries: function()
  6841. {
  6842. this.drawSpline();
  6843. }
  6844. }, {
  6845. ATTRS : {
  6846. /**
  6847. * Read-only attribute indicating the type of series.
  6848. *
  6849. * @attribute type
  6850. * @type String
  6851. * @default spline
  6852. */
  6853. type : {
  6854. value:"spline"
  6855. }
  6856. /**
  6857. * Style properties used for drawing lines. This attribute is inherited from `Renderer`. Below are the default values:
  6858. * <dl>
  6859. * <dt>color</dt><dd>The color of the line. The default value is determined by the order of the series on the graph. The color will be
  6860. * retrieved from the following array:
  6861. * `["#426ab3", "#d09b2c", "#000000", "#b82837", "#b384b5", "#ff7200", "#779de3", "#cbc8ba", "#7ed7a6", "#007a6c"]`
  6862. * <dt>weight</dt><dd>Number that indicates the width of the line. The default value is 6.</dd>
  6863. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the line. The default value is 1.</dd>
  6864. * <dt>lineType</dt><dd>Indicates whether the line is solid or dashed. The default value is solid.</dd>
  6865. * <dt>dashLength</dt><dd>When the `lineType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  6866. * <dt>gapSpace</dt><dd>When the `lineType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  6867. * <dt>connectDiscontinuousPoints</dt><dd>Indicates whether or not to connect lines when there is a missing or null value between points. The default value is true.</dd>
  6868. * <dt>discontinuousType</dt><dd>Indicates whether the line between discontinuous points is solid or dashed. The default value is solid.</dd>
  6869. * <dt>discontinuousDashLength</dt><dd>When the `discontinuousType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  6870. * <dt>discontinuousGapSpace</dt><dd>When the `discontinuousType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  6871. * </dl>
  6872. *
  6873. * @attribute styles
  6874. * @type Object
  6875. */
  6876. }
  6877. });
  6878. /**
  6879. * AreaSplineSeries renders an area graph with data points connected by a curve.
  6880. *
  6881. * @module charts
  6882. * @class AreaSplineSeries
  6883. * @constructor
  6884. * @extends CartesianSeries
  6885. * @uses Fills
  6886. * @uses CurveUtil
  6887. */
  6888. Y.AreaSplineSeries = Y.Base.create("areaSplineSeries", Y.CartesianSeries, [Y.Fills, Y.CurveUtil], {
  6889. /**
  6890. * @protected
  6891. *
  6892. * Draws the series.
  6893. *
  6894. * @method drawSeries
  6895. */
  6896. drawSeries: function()
  6897. {
  6898. this.drawAreaSpline();
  6899. }
  6900. }, {
  6901. ATTRS : {
  6902. /**
  6903. * Read-only attribute indicating the type of series.
  6904. *
  6905. * @attribute type
  6906. * @type String
  6907. * @default areaSpline
  6908. */
  6909. type: {
  6910. value:"areaSpline"
  6911. }
  6912. /**
  6913. * Style properties used for drawing area fills. This attribute is inherited from `Renderer`. Below are the default values:
  6914. *
  6915. * <dl>
  6916. * <dt>color</dt><dd>The color of the fill. The default value is determined by the order of the series on the graph. The color will be
  6917. * retrieved from the following array:
  6918. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  6919. * </dd>
  6920. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1</dd>
  6921. * </dl>
  6922. *
  6923. * @attribute styles
  6924. * @type Object
  6925. */
  6926. }
  6927. });
  6928. /**
  6929. * StackedSplineSeries creates spline graphs in which the different series are stacked along a value axis
  6930. * to indicate their contribution to a cumulative total.
  6931. *
  6932. * @module charts
  6933. * @class StackedSplineSeries
  6934. * @constructor
  6935. * @extends SplineSeries
  6936. * @extends StackingUtil
  6937. */
  6938. Y.StackedSplineSeries = Y.Base.create("stackedSplineSeries", Y.SplineSeries, [Y.StackingUtil], {
  6939. /**
  6940. * @protected
  6941. *
  6942. * Calculates the coordinates for the series. Overrides base implementation.
  6943. *
  6944. * @method setAreaData
  6945. */
  6946. setAreaData: function()
  6947. {
  6948. Y.StackedSplineSeries.superclass.setAreaData.apply(this);
  6949. this._stackCoordinates.apply(this);
  6950. }
  6951. }, {
  6952. ATTRS: {
  6953. /**
  6954. * Read-only attribute indicating the type of series.
  6955. *
  6956. * @attribute type
  6957. * @type String
  6958. * @default stackedSpline
  6959. */
  6960. type: {
  6961. value:"stackedSpline"
  6962. }
  6963. }
  6964. });
  6965. /**
  6966. * StackedMarkerSeries plots markers with different series stacked along the value axis to indicate each
  6967. * series' contribution to a cumulative total.
  6968. *
  6969. * @module charts
  6970. * @class StackedMarkerSeries
  6971. * @constructor
  6972. * @extends MarkerSeries
  6973. * @extends StackingUtil
  6974. */
  6975. Y.StackedMarkerSeries = Y.Base.create("stackedMarkerSeries", Y.MarkerSeries, [Y.StackingUtil], {
  6976. /**
  6977. * @protected
  6978. *
  6979. * Calculates the coordinates for the series. Overrides base implementation.
  6980. *
  6981. * @method setAreaData
  6982. */
  6983. setAreaData: function()
  6984. {
  6985. Y.StackedMarkerSeries.superclass.setAreaData.apply(this);
  6986. this._stackCoordinates.apply(this);
  6987. }
  6988. }, {
  6989. ATTRS: {
  6990. /**
  6991. * Read-only attribute indicating the type of series.
  6992. *
  6993. * @attribute type
  6994. * @type String
  6995. * @default stackedMarker
  6996. */
  6997. type: {
  6998. value:"stackedMarker"
  6999. }
  7000. }
  7001. });
  7002. /**
  7003. * The ColumnSeries class renders columns positioned horizontally along a category or time axis. The columns'
  7004. * lengths are proportional to the values they represent along a vertical axis.
  7005. * and the relevant data points.
  7006. *
  7007. * @module charts
  7008. * @class ColumnSeries
  7009. * @extends MarkerSeries
  7010. * @uses Histogram
  7011. * @constructor
  7012. */
  7013. Y.ColumnSeries = Y.Base.create("columnSeries", Y.MarkerSeries, [Y.Histogram], {
  7014. /**
  7015. * Helper method for calculating the size of markers.
  7016. *
  7017. * @method _getMarkerDimensions
  7018. * @param {Number} xcoord The x-coordinate representing the data point for the marker.
  7019. * @param {Number} ycoord The y-coordinate representing the data point for the marker.
  7020. * @param {Number} calculatedSize The calculated size for the marker. For a `BarSeries` is it the width. For a `ColumnSeries` it is the height.
  7021. * @param {Number} offset Distance of position offset dictated by other marker series in the same graph.
  7022. * @return Object
  7023. * @private
  7024. */
  7025. _getMarkerDimensions: function(xcoord, ycoord, calculatedSize, offset)
  7026. {
  7027. var config = {
  7028. left: xcoord + offset
  7029. };
  7030. if(this._bottomOrigin >= ycoord)
  7031. {
  7032. config.top = ycoord;
  7033. config.calculatedSize = this._bottomOrigin - config.top;
  7034. }
  7035. else
  7036. {
  7037. config.top = this._bottomOrigin;
  7038. config.calculatedSize = ycoord - this._bottomOrigin;
  7039. }
  7040. return config;
  7041. },
  7042. /**
  7043. * Resizes and positions markers based on a mouse interaction.
  7044. *
  7045. * @method updateMarkerState
  7046. * @param {String} type state of the marker
  7047. * @param {Number} i index of the marker
  7048. * @protected
  7049. */
  7050. updateMarkerState: function(type, i)
  7051. {
  7052. if(this._markers[i])
  7053. {
  7054. var styles = Y.clone(this.get("styles").marker),
  7055. markerStyles,
  7056. state = this._getState(type),
  7057. xcoords = this.get("xcoords"),
  7058. ycoords = this.get("ycoords"),
  7059. marker = this._markers[i],
  7060. graph = this.get("graph"),
  7061. seriesStyles,
  7062. seriesCollection = graph.seriesTypes[this.get("type")],
  7063. seriesLen = seriesCollection.length,
  7064. seriesSize = 0,
  7065. offset = 0,
  7066. renderer,
  7067. n = 0,
  7068. xs = [],
  7069. order = this.get("order"),
  7070. config;
  7071. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  7072. markerStyles.fill.color = this._getItemColor(markerStyles.fill.color, i);
  7073. markerStyles.border.color = this._getItemColor(markerStyles.border.color, i);
  7074. config = this._getMarkerDimensions(xcoords[i], ycoords[i], styles.width, offset);
  7075. markerStyles.height = config.calculatedSize;
  7076. marker.set(markerStyles);
  7077. for(; n < seriesLen; ++n)
  7078. {
  7079. xs[n] = xcoords[i] + seriesSize;
  7080. seriesStyles = seriesCollection[n].get("styles").marker;
  7081. seriesSize += seriesStyles.width;
  7082. if(order > n)
  7083. {
  7084. offset = seriesSize;
  7085. }
  7086. offset -= seriesSize/2;
  7087. }
  7088. for(n = 0; n < seriesLen; ++n)
  7089. {
  7090. renderer = seriesCollection[n].get("markers")[i];
  7091. if(renderer && renderer !== undefined)
  7092. {
  7093. renderer.set("x", (xs[n] - seriesSize/2));
  7094. }
  7095. }
  7096. }
  7097. }
  7098. }, {
  7099. ATTRS: {
  7100. /**
  7101. * Read-only attribute indicating the type of series.
  7102. *
  7103. * @attribute type
  7104. * @type String
  7105. * @readOnly
  7106. * @default column
  7107. */
  7108. type: {
  7109. value: "column"
  7110. }
  7111. /**
  7112. * Style properties used for drawing markers. This attribute is inherited from `MarkerSeries`. Below are the default values:
  7113. * <dl>
  7114. * <dt>fill</dt><dd>A hash containing the following values:
  7115. * <dl>
  7116. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  7117. * will be retrieved from the below array:<br/>
  7118. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  7119. * </dd>
  7120. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  7121. * </dl>
  7122. * </dd>
  7123. * <dt>border</dt><dd>A hash containing the following values:
  7124. * <dl>
  7125. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  7126. * will be retrieved from the below array:<br/>
  7127. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  7128. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  7129. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  7130. * </dl>
  7131. * </dd>
  7132. * <dt>width</dt><dd>indicates the width of the marker. The default value is 12.</dd>
  7133. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  7134. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  7135. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  7136. * </dl>
  7137. *
  7138. * @attribute styles
  7139. * @type Object
  7140. */
  7141. }
  7142. });
  7143. /**
  7144. * The BarSeries class renders bars positioned vertically along a category or time axis. The bars'
  7145. * lengths are proportional to the values they represent along a horizontal axis.
  7146. * and the relevant data points.
  7147. *
  7148. * @module charts
  7149. * @class BarSeries
  7150. * @extends MarkerSeries
  7151. * @uses Histogram
  7152. * @constructor
  7153. */
  7154. Y.BarSeries = Y.Base.create("barSeries", Y.MarkerSeries, [Y.Histogram], {
  7155. /**
  7156. * Helper method for calculating the size of markers.
  7157. *
  7158. * @method _getMarkerDimensions
  7159. * @param {Number} xcoord The x-coordinate representing the data point for the marker.
  7160. * @param {Number} ycoord The y-coordinate representing the data point for the marker.
  7161. * @param {Number} calculatedSize The calculated size for the marker. For a `BarSeries` is it the width. For a `ColumnSeries` it is the height.
  7162. * @param {Number} offset Distance of position offset dictated by other marker series in the same graph.
  7163. * @return Object
  7164. * @private
  7165. */
  7166. _getMarkerDimensions: function(xcoord, ycoord, calculatedSize, offset)
  7167. {
  7168. var config = {
  7169. top: ycoord + offset
  7170. };
  7171. if(xcoord >= this._leftOrigin)
  7172. {
  7173. config.left = this._leftOrigin;
  7174. config.calculatedSize = xcoord - config.left;
  7175. }
  7176. else
  7177. {
  7178. config.left = xcoord;
  7179. config.calculatedSize = this._leftOrigin - xcoord;
  7180. }
  7181. return config;
  7182. },
  7183. /**
  7184. * Resizes and positions markers based on a mouse interaction.
  7185. *
  7186. * @method updateMarkerState
  7187. * @param {String} type state of the marker
  7188. * @param {Number} i index of the marker
  7189. * @protected
  7190. */
  7191. updateMarkerState: function(type, i)
  7192. {
  7193. if(this._markers[i])
  7194. {
  7195. var styles = Y.clone(this.get("styles").marker),
  7196. markerStyles,
  7197. state = this._getState(type),
  7198. xcoords = this.get("xcoords"),
  7199. ycoords = this.get("ycoords"),
  7200. marker = this._markers[i],
  7201. graph = this.get("graph"),
  7202. seriesCollection = graph.seriesTypes[this.get("type")],
  7203. seriesLen = seriesCollection.length,
  7204. seriesStyles,
  7205. seriesSize = 0,
  7206. offset = 0,
  7207. renderer,
  7208. n = 0,
  7209. ys = [],
  7210. order = this.get("order"),
  7211. config;
  7212. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  7213. markerStyles.fill.color = this._getItemColor(markerStyles.fill.color, i);
  7214. markerStyles.border.color = this._getItemColor(markerStyles.border.color, i);
  7215. config = this._getMarkerDimensions(xcoords[i], ycoords[i], styles.height, offset);
  7216. markerStyles.width = config.calculatedSize;
  7217. marker.set(markerStyles);
  7218. for(; n < seriesLen; ++n)
  7219. {
  7220. ys[n] = ycoords[i] + seriesSize;
  7221. seriesStyles = seriesCollection[n].get("styles").marker;
  7222. seriesSize += seriesStyles.height;
  7223. if(order > n)
  7224. {
  7225. offset = seriesSize;
  7226. }
  7227. offset -= seriesSize/2;
  7228. }
  7229. for(n = 0; n < seriesLen; ++n)
  7230. {
  7231. renderer = seriesCollection[n].get("markers")[i];
  7232. if(renderer && renderer !== undefined)
  7233. {
  7234. renderer.set("y", (ys[n] - seriesSize/2));
  7235. }
  7236. }
  7237. }
  7238. }
  7239. }, {
  7240. ATTRS: {
  7241. /**
  7242. * Read-only attribute indicating the type of series.
  7243. *
  7244. * @attribute type
  7245. * @type String
  7246. * @default bar
  7247. */
  7248. type: {
  7249. value: "bar"
  7250. },
  7251. /**
  7252. * Indicates the direction of the category axis that the bars are plotted against.
  7253. *
  7254. * @attribute direction
  7255. * @type String
  7256. */
  7257. direction: {
  7258. value: "vertical"
  7259. }
  7260. /**
  7261. * Style properties used for drawing markers. This attribute is inherited from `MarkerSeries`. Below are the default values:
  7262. * <dl>
  7263. * <dt>fill</dt><dd>A hash containing the following values:
  7264. * <dl>
  7265. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  7266. * will be retrieved from the below array:<br/>
  7267. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  7268. * </dd>
  7269. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  7270. * </dl>
  7271. * </dd>
  7272. * <dt>border</dt><dd>A hash containing the following values:
  7273. * <dl>
  7274. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  7275. * will be retrieved from the below array:<br/>
  7276. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  7277. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  7278. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  7279. * </dl>
  7280. * </dd>
  7281. * <dt>height</dt><dd>indicates the width of the marker. The default value is 12.</dd>
  7282. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  7283. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  7284. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  7285. * </dl>
  7286. *
  7287. * @attribute styles
  7288. * @type Object
  7289. */
  7290. }
  7291. });
  7292. /**
  7293. * The AreaSeries class renders quantitative data on a graph by creating a fill between 0
  7294. * and the relevant data points.
  7295. *
  7296. * @module charts
  7297. * @class AreaSeries
  7298. * @extends CartesianSeries
  7299. * @uses Fills
  7300. * @constructor
  7301. */
  7302. Y.AreaSeries = Y.Base.create("areaSeries", Y.CartesianSeries, [Y.Fills], {
  7303. /**
  7304. * @protected
  7305. *
  7306. * Renders the series.
  7307. *
  7308. * @method drawSeries
  7309. */
  7310. drawSeries: function()
  7311. {
  7312. this.drawFill.apply(this, this._getClosingPoints());
  7313. },
  7314. /**
  7315. * @protected
  7316. *
  7317. * Method used by `styles` setter. Overrides base implementation.
  7318. *
  7319. * @method _setStyles
  7320. * @param {Object} newStyles Hash of properties to update.
  7321. * @return Object
  7322. */
  7323. _setStyles: function(val)
  7324. {
  7325. if(!val.area)
  7326. {
  7327. val = {area:val};
  7328. }
  7329. return Y.AreaSeries.superclass._setStyles.apply(this, [val]);
  7330. },
  7331. /**
  7332. * @protected
  7333. *
  7334. * Gets the default value for the `styles` attribute. Overrides
  7335. * base implementation.
  7336. *
  7337. * @method _getDefaultStyles
  7338. * @return Object
  7339. */
  7340. _getDefaultStyles: function()
  7341. {
  7342. var styles = this._mergeStyles({area:this._getAreaDefaults()}, Y.AreaSeries.superclass._getDefaultStyles());
  7343. return styles;
  7344. }
  7345. },
  7346. {
  7347. ATTRS: {
  7348. /**
  7349. * Read-only attribute indicating the type of series.
  7350. *
  7351. * @attribute type
  7352. * @type String
  7353. * @default area
  7354. */
  7355. type: {
  7356. value:"area"
  7357. }
  7358. /**
  7359. * Style properties used for drawing area fills. This attribute is inherited from `Renderer`. Below are the default values:
  7360. *
  7361. * <dl>
  7362. * <dt>color</dt><dd>The color of the fill. The default value is determined by the order of the series on the graph. The color will be
  7363. * retrieved from the following array:
  7364. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  7365. * </dd>
  7366. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1</dd>
  7367. * </dl>
  7368. *
  7369. * @attribute styles
  7370. * @type Object
  7371. */
  7372. }
  7373. });
  7374. /**
  7375. * StackedAreaSplineSeries creates a stacked area chart with points data points connected by a curve.
  7376. *
  7377. * @module charts
  7378. * @class StackedAreaSplineSeries
  7379. * @constructor
  7380. * @extends AreaSeries
  7381. * @uses CurveUtil
  7382. * @uses StackingUtil
  7383. */
  7384. Y.StackedAreaSplineSeries = Y.Base.create("stackedAreaSplineSeries", Y.AreaSeries, [Y.CurveUtil, Y.StackingUtil], {
  7385. /**
  7386. * @protected
  7387. *
  7388. * Draws the series.
  7389. *
  7390. * @method drawSeries
  7391. */
  7392. drawSeries: function()
  7393. {
  7394. this._stackCoordinates();
  7395. this.drawStackedAreaSpline();
  7396. }
  7397. }, {
  7398. ATTRS : {
  7399. /**
  7400. * Read-only attribute indicating the type of series.
  7401. *
  7402. * @attribute type
  7403. * @type String
  7404. * @default stackedAreaSpline
  7405. */
  7406. type: {
  7407. value:"stackedAreaSpline"
  7408. }
  7409. }
  7410. });
  7411. /**
  7412. * The ComboSeries class renders a combination of lines, plots and area fills in a single series. Each
  7413. * series type has a corresponding boolean attribute indicating if it is rendered. By default, lines and plots
  7414. * are rendered and area is not.
  7415. *
  7416. * @module charts
  7417. * @class ComboSeries
  7418. * @extends CartesianSeries
  7419. * @uses Fills
  7420. * @uses Lines
  7421. * @uses Plots
  7422. * @constructor
  7423. */
  7424. Y.ComboSeries = Y.Base.create("comboSeries", Y.CartesianSeries, [Y.Fills, Y.Lines, Y.Plots], {
  7425. /**
  7426. * @protected
  7427. *
  7428. * Draws the series.
  7429. *
  7430. * @method drawSeries
  7431. */
  7432. drawSeries: function()
  7433. {
  7434. if(this.get("showAreaFill"))
  7435. {
  7436. this.drawFill.apply(this, this._getClosingPoints());
  7437. }
  7438. if(this.get("showLines"))
  7439. {
  7440. this.drawLines();
  7441. }
  7442. if(this.get("showMarkers"))
  7443. {
  7444. this.drawPlots();
  7445. }
  7446. },
  7447. /**
  7448. * Toggles visibility
  7449. *
  7450. * @method _toggleVisible
  7451. * @param {Boolean} visible indicates visibilitye
  7452. * @private
  7453. */
  7454. _toggleVisible: function(visible)
  7455. {
  7456. var markers,
  7457. marker,
  7458. len,
  7459. i;
  7460. if(this.get("showAreaFill") && this._path)
  7461. {
  7462. this._path.set("visible", visible);
  7463. }
  7464. if(this.get("showLines"))
  7465. {
  7466. this._lineGraphic.set("visible", visible);
  7467. }
  7468. if(this.get("showMarkers"))
  7469. {
  7470. markers = this.get("markers");
  7471. if(markers)
  7472. {
  7473. i = 0;
  7474. len = markers.length;
  7475. for(; i < len; ++i)
  7476. {
  7477. marker = markers[i];
  7478. if(marker)
  7479. {
  7480. marker.set("visible", visible);
  7481. }
  7482. }
  7483. }
  7484. }
  7485. },
  7486. /**
  7487. * @protected
  7488. *
  7489. * Returns the default hash for the `styles` attribute.
  7490. *
  7491. * @method _getDefaultStyles
  7492. * @return Object
  7493. */
  7494. _getDefaultStyles: function()
  7495. {
  7496. var styles = Y.ComboSeries.superclass._getDefaultStyles();
  7497. styles.line = this._getLineDefaults();
  7498. styles.marker = this._getPlotDefaults();
  7499. styles.area = this._getAreaDefaults();
  7500. return styles;
  7501. }
  7502. },
  7503. {
  7504. ATTRS: {
  7505. /**
  7506. * Read-only attribute indicating the type of series.
  7507. *
  7508. * @attribute type
  7509. * @type String
  7510. * @default combo
  7511. */
  7512. type: {
  7513. value:"combo"
  7514. },
  7515. /**
  7516. * Indicates whether a fill is displayed.
  7517. *
  7518. * @attribute showAreaFill
  7519. * @type Boolean
  7520. * @default false
  7521. */
  7522. showAreaFill: {
  7523. value: false
  7524. },
  7525. /**
  7526. * Indicates whether lines are displayed.
  7527. *
  7528. * @attribute showLines
  7529. * @type Boolean
  7530. * @default true
  7531. */
  7532. showLines: {
  7533. value: true
  7534. },
  7535. /**
  7536. * Indicates whether markers are displayed.
  7537. *
  7538. * @attribute showMarkers
  7539. * @type Boolean
  7540. * @default true
  7541. */
  7542. showMarkers: {
  7543. value: true
  7544. },
  7545. /**
  7546. * Reference to the styles of the markers. These styles can also
  7547. * be accessed through the `styles` attribute. Below are default
  7548. * values:
  7549. * <dl>
  7550. * <dt>fill</dt><dd>A hash containing the following values:
  7551. * <dl>
  7552. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  7553. * will be retrieved from the below array:<br/>
  7554. * `["#6084d0", "#eeb647", "#6c6b5f", "#d6484f", "#ce9ed1", "#ff9f3b", "#93b7ff", "#e0ddd0", "#94ecba", "#309687"]`
  7555. * </dd>
  7556. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  7557. * </dl>
  7558. * </dd>
  7559. * <dt>border</dt><dd>A hash containing the following values:
  7560. * <dl>
  7561. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  7562. * will be retrieved from the below array:<br/>
  7563. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  7564. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  7565. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  7566. * </dl>
  7567. * </dd>
  7568. * <dt>width</dt><dd>indicates the width of the marker. The default value is 10.</dd>
  7569. * <dt>height</dt><dd>indicates the height of the marker The default value is 10.</dd>
  7570. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  7571. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  7572. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  7573. * </dl>
  7574. *
  7575. * @attribute marker
  7576. * @type Object
  7577. */
  7578. marker: {
  7579. lazyAdd: false,
  7580. getter: function()
  7581. {
  7582. return this.get("styles").marker;
  7583. },
  7584. setter: function(val)
  7585. {
  7586. this.set("styles", {marker:val});
  7587. }
  7588. },
  7589. /**
  7590. * Reference to the styles of the lines. These styles can also be accessed through the `styles` attribute.
  7591. * Below are the default values:
  7592. * <dl>
  7593. * <dt>color</dt><dd>The color of the line. The default value is determined by the order of the series on the graph. The color will be
  7594. * retrieved from the following array:
  7595. * `["#426ab3", "#d09b2c", "#000000", "#b82837", "#b384b5", "#ff7200", "#779de3", "#cbc8ba", "#7ed7a6", "#007a6c"]`
  7596. * <dt>weight</dt><dd>Number that indicates the width of the line. The default value is 6.</dd>
  7597. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the line. The default value is 1.</dd>
  7598. * <dt>lineType</dt><dd>Indicates whether the line is solid or dashed. The default value is solid.</dd>
  7599. * <dt>dashLength</dt><dd>When the `lineType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  7600. * <dt>gapSpace</dt><dd>When the `lineType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  7601. * <dt>connectDiscontinuousPoints</dt><dd>Indicates whether or not to connect lines when there is a missing or null value between points. The default value is true.</dd>
  7602. * <dt>discontinuousType</dt><dd>Indicates whether the line between discontinuous points is solid or dashed. The default value is solid.</dd>
  7603. * <dt>discontinuousDashLength</dt><dd>When the `discontinuousType` is dashed, indicates the length of the dash. The default value is 10.</dd>
  7604. * <dt>discontinuousGapSpace</dt><dd>When the `discontinuousType` is dashed, indicates the distance between dashes. The default value is 10.</dd>
  7605. * </dl>
  7606. *
  7607. * @attribute line
  7608. * @type Object
  7609. */
  7610. line: {
  7611. lazyAdd: false,
  7612. getter: function()
  7613. {
  7614. return this.get("styles").line;
  7615. },
  7616. setter: function(val)
  7617. {
  7618. this.set("styles", {line:val});
  7619. }
  7620. },
  7621. /**
  7622. * Reference to the styles of the area fills. These styles can also be accessed through the `styles` attribute.
  7623. * Below are the default values:
  7624. *
  7625. * <dl>
  7626. * <dt>color</dt><dd>The color of the fill. The default value is determined by the order of the series on the graph. The color will be
  7627. * retrieved from the following array:
  7628. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  7629. * </dd>
  7630. * <dt>alpha</dt><dd>Number between 0 and 1 that indicates the opacity of the fill. The default value is 1</dd>
  7631. * </dl>
  7632. *
  7633. * @attribute area
  7634. * @type Object
  7635. */
  7636. area: {
  7637. lazyAdd: false,
  7638. getter: function()
  7639. {
  7640. return this.get("styles").area;
  7641. },
  7642. setter: function(val)
  7643. {
  7644. this.set("styles", {area:val});
  7645. }
  7646. }
  7647. /**
  7648. * Style properties for the series. Contains a key indexed hash of the following:
  7649. * <dl>
  7650. * <dt>marker</dt><dd>Style properties for the markers in the series. Specific style attributes are listed
  7651. * <a href="#attr_marker">here</a>.</dd>
  7652. * <dt>line</dt><dd>Style properties for the lines in the series. Specific
  7653. * style attributes are listed <a href="#attr_line">here</a>.</dd>
  7654. * <dt>area</dt><dd>Style properties for the area fills in the series. Specific style attributes are listed
  7655. * <a href="#attr_area">here</a>.</dd>
  7656. * </dl>
  7657. *
  7658. * @attribute styles
  7659. * @type Object
  7660. */
  7661. }
  7662. });
  7663. /**
  7664. * The StackedComboSeries class renders a combination of lines, plots and area fills in a single series. Series
  7665. * are stacked along the value axis to indicate each series contribution to a cumulative total. Each
  7666. * series type has a corresponding boolean attribute indicating if it is rendered. By default, all three types are
  7667. * rendered.
  7668. *
  7669. * @module charts
  7670. * @class StackedComboSeries
  7671. * @extends ComboSeries
  7672. * @uses StackingUtil
  7673. * @constructor
  7674. */
  7675. Y.StackedComboSeries = Y.Base.create("stackedComboSeries", Y.ComboSeries, [Y.StackingUtil], {
  7676. /**
  7677. * @protected
  7678. *
  7679. * Calculates the coordinates for the series. Overrides base implementation.
  7680. *
  7681. * @method setAreaData
  7682. */
  7683. setAreaData: function()
  7684. {
  7685. Y.StackedComboSeries.superclass.setAreaData.apply(this);
  7686. this._stackCoordinates.apply(this);
  7687. },
  7688. /**
  7689. * @protected
  7690. *
  7691. * Draws the series.
  7692. *
  7693. * @method drawSeries
  7694. */
  7695. drawSeries: function()
  7696. {
  7697. if(this.get("showAreaFill"))
  7698. {
  7699. this.drawFill.apply(this, this._getStackedClosingPoints());
  7700. }
  7701. if(this.get("showLines"))
  7702. {
  7703. this.drawLines();
  7704. }
  7705. if(this.get("showMarkers"))
  7706. {
  7707. this.drawPlots();
  7708. }
  7709. }
  7710. }, {
  7711. ATTRS : {
  7712. /**
  7713. * Read-only attribute indicating the type of series.
  7714. *
  7715. * @attribute type
  7716. * @type String
  7717. * @default stackedCombo
  7718. */
  7719. type: {
  7720. value: "stackedCombo"
  7721. },
  7722. /**
  7723. * Indicates whether a fill is displayed.
  7724. *
  7725. * @attribute showAreaFill
  7726. * @type Boolean
  7727. * @default true
  7728. */
  7729. showAreaFill: {
  7730. value: true
  7731. }
  7732. }
  7733. });
  7734. /**
  7735. * The ComboSplineSeries class renders a combination of splines, plots and areaspline fills in a single series. Each
  7736. * series type has a corresponding boolean attribute indicating if it is rendered. By default, splines and plots
  7737. * are rendered and areaspline is not.
  7738. *
  7739. * @module charts
  7740. * @class ComboSplineSeries
  7741. * @extends ComboSeries
  7742. * @extends CurveUtil
  7743. * @constructor
  7744. */
  7745. Y.ComboSplineSeries = Y.Base.create("comboSplineSeries", Y.ComboSeries, [Y.CurveUtil], {
  7746. /**
  7747. * @protected
  7748. *
  7749. * Draws the series.
  7750. *
  7751. * @method drawSeries
  7752. */
  7753. drawSeries: function()
  7754. {
  7755. if(this.get("showAreaFill"))
  7756. {
  7757. this.drawAreaSpline();
  7758. }
  7759. if(this.get("showLines"))
  7760. {
  7761. this.drawSpline();
  7762. }
  7763. if(this.get("showMarkers"))
  7764. {
  7765. this.drawPlots();
  7766. }
  7767. }
  7768. }, {
  7769. ATTRS: {
  7770. /**
  7771. * Read-only attribute indicating the type of series.
  7772. *
  7773. * @attribute type
  7774. * @type String
  7775. * @default comboSpline
  7776. */
  7777. type: {
  7778. value : "comboSpline"
  7779. }
  7780. }
  7781. });
  7782. /**
  7783. * The StackedComboSplineSeries class renders a combination of splines, plots and areaspline fills in a single series. Series
  7784. * are stacked along the value axis to indicate each series contribution to a cumulative total. Each
  7785. * series type has a corresponding boolean attribute indicating if it is rendered. By default, all three types are
  7786. * rendered.
  7787. *
  7788. * @module charts
  7789. * @class StackedComboSplineSeries
  7790. * @extends StackedComboSeries
  7791. * @uses CurveUtil
  7792. * @constructor
  7793. */
  7794. Y.StackedComboSplineSeries = Y.Base.create("stackedComboSplineSeries", Y.StackedComboSeries, [Y.CurveUtil], {
  7795. /**
  7796. * @protected
  7797. *
  7798. * Draws the series.
  7799. *
  7800. * @method drawSeries
  7801. */
  7802. drawSeries: function()
  7803. {
  7804. if(this.get("showAreaFill"))
  7805. {
  7806. this.drawStackedAreaSpline();
  7807. }
  7808. if(this.get("showLines"))
  7809. {
  7810. this.drawSpline();
  7811. }
  7812. if(this.get("showMarkers"))
  7813. {
  7814. this.drawPlots();
  7815. }
  7816. }
  7817. }, {
  7818. ATTRS: {
  7819. /**
  7820. * Read-only attribute indicating the type of series.
  7821. *
  7822. * @attribute type
  7823. * @type String
  7824. * @default stackedComboSpline
  7825. */
  7826. type : {
  7827. value : "stackedComboSpline"
  7828. },
  7829. /**
  7830. * Indicates whether a fill is displayed.
  7831. *
  7832. * @attribute showAreaFill
  7833. * @type Boolean
  7834. * @default true
  7835. */
  7836. showAreaFill: {
  7837. value: true
  7838. }
  7839. }
  7840. });
  7841. /**
  7842. * StackedLineSeries creates line graphs in which the different series are stacked along a value axis
  7843. * to indicate their contribution to a cumulative total.
  7844. *
  7845. * @module charts
  7846. * @class StackedLineSeries
  7847. * @constructor
  7848. * @extends LineSeries
  7849. * @uses StackingUtil
  7850. */
  7851. Y.StackedLineSeries = Y.Base.create("stackedLineSeries", Y.LineSeries, [Y.StackingUtil], {
  7852. /**
  7853. * @protected
  7854. *
  7855. * Calculates the coordinates for the series. Overrides base implementation.
  7856. *
  7857. * @method setAreaData
  7858. */
  7859. setAreaData: function()
  7860. {
  7861. Y.StackedLineSeries.superclass.setAreaData.apply(this);
  7862. this._stackCoordinates.apply(this);
  7863. }
  7864. }, {
  7865. ATTRS: {
  7866. /**
  7867. * Read-only attribute indicating the type of series.
  7868. *
  7869. * @attribute type
  7870. * @type String
  7871. * @default stackedLine
  7872. */
  7873. type: {
  7874. value:"stackedLine"
  7875. }
  7876. }
  7877. });
  7878. /**
  7879. * StackedAreaSeries area fills to display data showing its contribution to a whole.
  7880. *
  7881. * @module charts
  7882. * @class StackedAreaSeries
  7883. * @constructor
  7884. * @param {Object} config (optional) Configuration parameters for the Chart.
  7885. * @extends AreaSeries
  7886. * @uses StackingUtil
  7887. */
  7888. Y.StackedAreaSeries = Y.Base.create("stackedAreaSeries", Y.AreaSeries, [Y.StackingUtil], {
  7889. /**
  7890. * @protected
  7891. *
  7892. * Calculates the coordinates for the series. Overrides base implementation.
  7893. *
  7894. * @method setAreaData
  7895. */
  7896. setAreaData: function()
  7897. {
  7898. Y.StackedAreaSeries.superclass.setAreaData.apply(this);
  7899. this._stackCoordinates.apply(this);
  7900. },
  7901. /**
  7902. * @protected
  7903. *
  7904. * Draws the series
  7905. *
  7906. * @method drawSeries
  7907. */
  7908. drawSeries: function()
  7909. {
  7910. this.drawFill.apply(this, this._getStackedClosingPoints());
  7911. }
  7912. }, {
  7913. ATTRS: {
  7914. /**
  7915. * Read-only attribute indicating the type of series.
  7916. *
  7917. * @attribute type
  7918. * @type String
  7919. * @default stackedArea
  7920. */
  7921. type: {
  7922. value:"stackedArea"
  7923. }
  7924. }
  7925. });
  7926. /**
  7927. * The StackedColumnSeries renders column chart in which series are stacked vertically to show
  7928. * their contribution to the cumulative total.
  7929. *
  7930. * @module charts
  7931. * @class StackedColumnSeries
  7932. * @extends ColumnSeries
  7933. * @uses StackingUtil
  7934. * @constructor
  7935. */
  7936. Y.StackedColumnSeries = Y.Base.create("stackedColumnSeries", Y.ColumnSeries, [Y.StackingUtil], {
  7937. /**
  7938. * Draws the series.
  7939. *
  7940. * @method drawSeries
  7941. * @protected
  7942. */
  7943. drawSeries: function()
  7944. {
  7945. if(this.get("xcoords").length < 1)
  7946. {
  7947. return;
  7948. }
  7949. var isNumber = Y_Lang.isNumber,
  7950. style = this.get("styles").marker,
  7951. w = style.width,
  7952. h = style.height,
  7953. xcoords = this.get("xcoords"),
  7954. ycoords = this.get("ycoords"),
  7955. i = 0,
  7956. len = xcoords.length,
  7957. top = ycoords[0],
  7958. type = this.get("type"),
  7959. graph = this.get("graph"),
  7960. seriesCollection = graph.seriesTypes[type],
  7961. ratio,
  7962. order = this.get("order"),
  7963. graphOrder = this.get("graphOrder"),
  7964. left,
  7965. marker,
  7966. lastCollection,
  7967. negativeBaseValues,
  7968. positiveBaseValues,
  7969. useOrigin = order === 0,
  7970. totalWidth = len * w;
  7971. this._createMarkerCache();
  7972. if(totalWidth > this.get("width"))
  7973. {
  7974. ratio = this.width/totalWidth;
  7975. w *= ratio;
  7976. w = Math.max(w, 1);
  7977. }
  7978. if(!useOrigin)
  7979. {
  7980. lastCollection = seriesCollection[order - 1];
  7981. negativeBaseValues = lastCollection.get("negativeBaseValues");
  7982. positiveBaseValues = lastCollection.get("positiveBaseValues");
  7983. if(!negativeBaseValues || !positiveBaseValues)
  7984. {
  7985. useOrigin = true;
  7986. positiveBaseValues = [];
  7987. negativeBaseValues = [];
  7988. }
  7989. }
  7990. else
  7991. {
  7992. negativeBaseValues = [];
  7993. positiveBaseValues = [];
  7994. }
  7995. this.set("negativeBaseValues", negativeBaseValues);
  7996. this.set("positiveBaseValues", positiveBaseValues);
  7997. for(i = 0; i < len; ++i)
  7998. {
  7999. left = xcoords[i];
  8000. top = ycoords[i];
  8001. if(!isNumber(top) || !isNumber(left))
  8002. {
  8003. if(useOrigin)
  8004. {
  8005. negativeBaseValues[i] = this._bottomOrigin;
  8006. positiveBaseValues[i] = this._bottomOrigin;
  8007. }
  8008. this._markers.push(null);
  8009. continue;
  8010. }
  8011. if(useOrigin)
  8012. {
  8013. h = Math.abs(this._bottomOrigin - top);
  8014. if(top < this._bottomOrigin)
  8015. {
  8016. positiveBaseValues[i] = top;
  8017. negativeBaseValues[i] = this._bottomOrigin;
  8018. }
  8019. else if(top > this._bottomOrigin)
  8020. {
  8021. positiveBaseValues[i] = this._bottomOrigin;
  8022. negativeBaseValues[i] = top;
  8023. top -= h;
  8024. }
  8025. else
  8026. {
  8027. positiveBaseValues[i] = top;
  8028. negativeBaseValues[i] = top;
  8029. }
  8030. }
  8031. else
  8032. {
  8033. if(top > this._bottomOrigin)
  8034. {
  8035. top += (negativeBaseValues[i] - this._bottomOrigin);
  8036. h = top - negativeBaseValues[i];
  8037. negativeBaseValues[i] = top;
  8038. top -= h;
  8039. }
  8040. else if(top <= this._bottomOrigin)
  8041. {
  8042. top = positiveBaseValues[i] - (this._bottomOrigin - top);
  8043. h = positiveBaseValues[i] - top;
  8044. positiveBaseValues[i] = top;
  8045. }
  8046. }
  8047. if(!isNaN(h) && h > 0)
  8048. {
  8049. left -= w/2;
  8050. style.width = w;
  8051. style.height = h;
  8052. style.x = left;
  8053. style.y = top;
  8054. marker = this.getMarker(style, graphOrder, i);
  8055. }
  8056. else
  8057. {
  8058. this._markers.push(null);
  8059. }
  8060. }
  8061. this._clearMarkerCache();
  8062. },
  8063. /**
  8064. * Resizes and positions markers based on a mouse interaction.
  8065. *
  8066. * @method updateMarkerState
  8067. * @param {String} type state of the marker
  8068. * @param {Number} i index of the marker
  8069. * @protected
  8070. */
  8071. updateMarkerState: function(type, i)
  8072. {
  8073. if(this._markers[i])
  8074. {
  8075. var styles,
  8076. markerStyles,
  8077. state = this._getState(type),
  8078. xcoords = this.get("xcoords"),
  8079. marker = this._markers[i],
  8080. offset = 0;
  8081. styles = this.get("styles").marker;
  8082. offset = styles.width * 0.5;
  8083. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  8084. markerStyles.height = marker.get("height");
  8085. markerStyles.x = (xcoords[i] - offset);
  8086. markerStyles.y = marker.get("y");
  8087. markerStyles.id = marker.get("id");
  8088. marker.set(markerStyles);
  8089. }
  8090. },
  8091. /**
  8092. * Gets the default values for the markers.
  8093. *
  8094. * @method _getPlotDefaults
  8095. * @return Object
  8096. * @protected
  8097. */
  8098. _getPlotDefaults: function()
  8099. {
  8100. var defs = {
  8101. fill:{
  8102. type: "solid",
  8103. alpha: 1,
  8104. colors:null,
  8105. alphas: null,
  8106. ratios: null
  8107. },
  8108. border:{
  8109. weight: 0,
  8110. alpha: 1
  8111. },
  8112. width: 24,
  8113. height: 24,
  8114. shape: "rect",
  8115. padding:{
  8116. top: 0,
  8117. left: 0,
  8118. right: 0,
  8119. bottom: 0
  8120. }
  8121. };
  8122. defs.fill.color = this._getDefaultColor(this.get("graphOrder"), "fill");
  8123. defs.border.color = this._getDefaultColor(this.get("graphOrder"), "border");
  8124. return defs;
  8125. }
  8126. }, {
  8127. ATTRS: {
  8128. /**
  8129. * Read-only attribute indicating the type of series.
  8130. *
  8131. * @attribute type
  8132. * @type String
  8133. * @default stackedColumn
  8134. */
  8135. type: {
  8136. value: "stackedColumn"
  8137. },
  8138. /**
  8139. * @attribute negativeBaseValues
  8140. * @type Array
  8141. * @default null
  8142. * @private
  8143. */
  8144. negativeBaseValues: {
  8145. value: null
  8146. },
  8147. /**
  8148. * @attribute positiveBaseValues
  8149. * @type Array
  8150. * @default null
  8151. * @private
  8152. */
  8153. positiveBaseValues: {
  8154. value: null
  8155. }
  8156. /**
  8157. * Style properties used for drawing markers. This attribute is inherited from `ColumnSeries`. Below are the default values:
  8158. * <dl>
  8159. * <dt>fill</dt><dd>A hash containing the following values:
  8160. * <dl>
  8161. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  8162. * will be retrieved from the below array:<br/>
  8163. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  8164. * </dd>
  8165. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  8166. * </dl>
  8167. * </dd>
  8168. * <dt>border</dt><dd>A hash containing the following values:
  8169. * <dl>
  8170. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  8171. * will be retrieved from the below array:<br/>
  8172. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  8173. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  8174. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  8175. * </dl>
  8176. * </dd>
  8177. * <dt>width</dt><dd>indicates the width of the marker. The default value is 24.</dd>
  8178. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  8179. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  8180. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  8181. * </dl>
  8182. *
  8183. * @attribute styles
  8184. * @type Object
  8185. */
  8186. }
  8187. });
  8188. /**
  8189. * The StackedBarSeries renders bar chart in which series are stacked horizontally to show
  8190. * their contribution to the cumulative total.
  8191. *
  8192. * @module charts
  8193. * @class StackedBarSeries
  8194. * @extends BarSeries
  8195. * @uses StackingUtil
  8196. * @constructor
  8197. */
  8198. Y.StackedBarSeries = Y.Base.create("stackedBarSeries", Y.BarSeries, [Y.StackingUtil], {
  8199. /**
  8200. * @protected
  8201. *
  8202. * Draws the series.
  8203. *
  8204. * @method drawSeries
  8205. */
  8206. drawSeries: function()
  8207. {
  8208. if(this.get("xcoords").length < 1)
  8209. {
  8210. return;
  8211. }
  8212. var isNumber = Y_Lang.isNumber,
  8213. style = this.get("styles").marker,
  8214. w = style.width,
  8215. h = style.height,
  8216. xcoords = this.get("xcoords"),
  8217. ycoords = this.get("ycoords"),
  8218. i = 0,
  8219. len = xcoords.length,
  8220. top = ycoords[0],
  8221. type = this.get("type"),
  8222. graph = this.get("graph"),
  8223. seriesCollection = graph.seriesTypes[type],
  8224. ratio,
  8225. order = this.get("order"),
  8226. graphOrder = this.get("graphOrder"),
  8227. left,
  8228. marker,
  8229. lastCollection,
  8230. negativeBaseValues,
  8231. positiveBaseValues,
  8232. useOrigin = order === 0,
  8233. totalHeight = len * h;
  8234. this._createMarkerCache();
  8235. if(totalHeight > this.get("height"))
  8236. {
  8237. ratio = this.height/totalHeight;
  8238. h *= ratio;
  8239. h = Math.max(h, 1);
  8240. }
  8241. if(!useOrigin)
  8242. {
  8243. lastCollection = seriesCollection[order - 1];
  8244. negativeBaseValues = lastCollection.get("negativeBaseValues");
  8245. positiveBaseValues = lastCollection.get("positiveBaseValues");
  8246. if(!negativeBaseValues || !positiveBaseValues)
  8247. {
  8248. useOrigin = true;
  8249. positiveBaseValues = [];
  8250. negativeBaseValues = [];
  8251. }
  8252. }
  8253. else
  8254. {
  8255. negativeBaseValues = [];
  8256. positiveBaseValues = [];
  8257. }
  8258. this.set("negativeBaseValues", negativeBaseValues);
  8259. this.set("positiveBaseValues", positiveBaseValues);
  8260. for(i = 0; i < len; ++i)
  8261. {
  8262. top = ycoords[i];
  8263. left = xcoords[i];
  8264. if(!isNumber(top) || !isNumber(left))
  8265. {
  8266. if(useOrigin)
  8267. {
  8268. positiveBaseValues[i] = this._leftOrigin;
  8269. negativeBaseValues[i] = this._leftOrigin;
  8270. }
  8271. this._markers.push(null);
  8272. continue;
  8273. }
  8274. if(useOrigin)
  8275. {
  8276. w = Math.abs(left - this._leftOrigin);
  8277. if(left > this._leftOrigin)
  8278. {
  8279. positiveBaseValues[i] = left;
  8280. negativeBaseValues[i] = this._leftOrigin;
  8281. left -= w;
  8282. }
  8283. else if(left < this._leftOrigin)
  8284. {
  8285. positiveBaseValues[i] = this._leftOrigin;
  8286. negativeBaseValues[i] = left;
  8287. }
  8288. else
  8289. {
  8290. positiveBaseValues[i] = left;
  8291. negativeBaseValues[i] = this._leftOrigin;
  8292. }
  8293. }
  8294. else
  8295. {
  8296. if(left < this._leftOrigin)
  8297. {
  8298. left = negativeBaseValues[i] - (this._leftOrigin - xcoords[i]);
  8299. w = negativeBaseValues[i] - left;
  8300. negativeBaseValues[i] = left;
  8301. }
  8302. else if(left >= this._leftOrigin)
  8303. {
  8304. left += (positiveBaseValues[i] - this._leftOrigin);
  8305. w = left - positiveBaseValues[i];
  8306. positiveBaseValues[i] = left;
  8307. left -= w;
  8308. }
  8309. }
  8310. if(!isNaN(w) && w > 0)
  8311. {
  8312. top -= h/2;
  8313. style.width = w;
  8314. style.height = h;
  8315. style.x = left;
  8316. style.y = top;
  8317. marker = this.getMarker(style, graphOrder, i);
  8318. }
  8319. else
  8320. {
  8321. this._markers.push(null);
  8322. }
  8323. }
  8324. this._clearMarkerCache();
  8325. },
  8326. /**
  8327. * @protected
  8328. *
  8329. * Resizes and positions markers based on a mouse interaction.
  8330. *
  8331. * @method updateMarkerState
  8332. * @param {String} type state of the marker
  8333. * @param {Number} i index of the marker
  8334. */
  8335. updateMarkerState: function(type, i)
  8336. {
  8337. if(this._markers[i])
  8338. {
  8339. var state = this._getState(type),
  8340. ycoords = this.get("ycoords"),
  8341. marker = this._markers[i],
  8342. styles = this.get("styles").marker,
  8343. h = styles.height,
  8344. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  8345. markerStyles.y = (ycoords[i] - h/2);
  8346. markerStyles.x = marker.get("x");
  8347. markerStyles.width = marker.get("width");
  8348. markerStyles.id = marker.get("id");
  8349. marker.set(markerStyles);
  8350. }
  8351. },
  8352. /**
  8353. * @protected
  8354. *
  8355. * Returns default values for the `styles` attribute.
  8356. *
  8357. * @method _getPlotDefaults
  8358. * @return Object
  8359. */
  8360. _getPlotDefaults: function()
  8361. {
  8362. var defs = {
  8363. fill:{
  8364. type: "solid",
  8365. alpha: 1,
  8366. colors:null,
  8367. alphas: null,
  8368. ratios: null
  8369. },
  8370. border:{
  8371. weight: 0,
  8372. alpha: 1
  8373. },
  8374. width: 24,
  8375. height: 24,
  8376. shape: "rect",
  8377. padding:{
  8378. top: 0,
  8379. left: 0,
  8380. right: 0,
  8381. bottom: 0
  8382. }
  8383. };
  8384. defs.fill.color = this._getDefaultColor(this.get("graphOrder"), "fill");
  8385. defs.border.color = this._getDefaultColor(this.get("graphOrder"), "border");
  8386. return defs;
  8387. }
  8388. }, {
  8389. ATTRS: {
  8390. /**
  8391. * Read-only attribute indicating the type of series.
  8392. *
  8393. * @attribute type
  8394. * @type String
  8395. * @default stackedBar
  8396. */
  8397. type: {
  8398. value: "stackedBar"
  8399. },
  8400. /**
  8401. * Direction of the series
  8402. *
  8403. * @attribute direction
  8404. * @type String
  8405. * @default vertical
  8406. */
  8407. direction: {
  8408. value: "vertical"
  8409. },
  8410. /**
  8411. * @private
  8412. *
  8413. * @attribute negativeBaseValues
  8414. * @type Array
  8415. * @default null
  8416. */
  8417. negativeBaseValues: {
  8418. value: null
  8419. },
  8420. /**
  8421. * @private
  8422. *
  8423. * @attribute positiveBaseValues
  8424. * @type Array
  8425. * @default null
  8426. */
  8427. positiveBaseValues: {
  8428. value: null
  8429. }
  8430. /**
  8431. * Style properties used for drawing markers. This attribute is inherited from `BarSeries`. Below are the default values:
  8432. * <dl>
  8433. * <dt>fill</dt><dd>A hash containing the following values:
  8434. * <dl>
  8435. * <dt>color</dt><dd>Color of the fill. The default value is determined by the order of the series on the graph. The color
  8436. * will be retrieved from the below array:<br/>
  8437. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  8438. * </dd>
  8439. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker fill. The default value is 1.</dd>
  8440. * </dl>
  8441. * </dd>
  8442. * <dt>border</dt><dd>A hash containing the following values:
  8443. * <dl>
  8444. * <dt>color</dt><dd>Color of the border. The default value is determined by the order of the series on the graph. The color
  8445. * will be retrieved from the below array:<br/>
  8446. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  8447. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  8448. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  8449. * </dl>
  8450. * </dd>
  8451. * <dt>height</dt><dd>indicates the width of the marker. The default value is 24.</dd>
  8452. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  8453. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  8454. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  8455. * </dl>
  8456. *
  8457. * @attribute styles
  8458. * @type Object
  8459. */
  8460. }
  8461. });
  8462. /**
  8463. * PieSeries visualizes data as a circular chart divided into wedges which represent data as a
  8464. * percentage of a whole.
  8465. *
  8466. * @module charts
  8467. * @class PieSeries
  8468. * @constructor
  8469. * @extends MarkerSeries
  8470. */
  8471. Y.PieSeries = Y.Base.create("pieSeries", Y.MarkerSeries, [], {
  8472. /**
  8473. * Image map used for interactivity when rendered with canvas.
  8474. *
  8475. * @property _map
  8476. * @type HTMLElement
  8477. * @private
  8478. */
  8479. _map: null,
  8480. /**
  8481. * Image used for image map when rendered with canvas.
  8482. *
  8483. * @property _image
  8484. * @type HTMLElement
  8485. * @private
  8486. */
  8487. _image: null,
  8488. /**
  8489. * Creates or updates the image map when rendered with canvas.
  8490. *
  8491. * @method _setMap
  8492. * @private
  8493. */
  8494. _setMap: function()
  8495. {
  8496. var id = "pieHotSpotMapi_" + Math.round(100000 * Math.random()),
  8497. cb = this.get("graph").get("contentBox"),
  8498. areaNode;
  8499. if(this._image)
  8500. {
  8501. cb.removeChild(this._image);
  8502. while(this._areaNodes && this._areaNodes.length > 0)
  8503. {
  8504. areaNode = this._areaNodes.shift();
  8505. this._map.removeChild(areaNode);
  8506. }
  8507. cb.removeChild(this._map);
  8508. }
  8509. this._image = DOCUMENT.createElement("img");
  8510. this._image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAABCAYAAAD9yd/wAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABJJREFUeNpiZGBgSGPAAgACDAAIkABoFyloZQAAAABJRU5ErkJggg==";
  8511. cb.appendChild(this._image);
  8512. this._image.setAttribute("usemap", "#" + id);
  8513. this._image.style.zIndex = 3;
  8514. this._image.style.opacity = 0;
  8515. this._image.setAttribute("alt", "imagemap");
  8516. this._map = DOCUMENT.createElement("map");
  8517. this._map.style.zIndex = 5;
  8518. cb.appendChild(this._map);
  8519. this._map.setAttribute("name", id);
  8520. this._map.setAttribute("id", id);
  8521. this._areaNodes = [];
  8522. },
  8523. /**
  8524. * Storage for `categoryDisplayName` attribute.
  8525. *
  8526. * @property _categoryDisplayName
  8527. * @private
  8528. */
  8529. _categoryDisplayName: null,
  8530. /**
  8531. * Storage for `valueDisplayName` attribute.
  8532. *
  8533. * @property _valueDisplayName
  8534. * @private
  8535. */
  8536. _valueDisplayName: null,
  8537. /**
  8538. * Adds event listeners.
  8539. *
  8540. * @method addListeners
  8541. * @private
  8542. */
  8543. addListeners: function()
  8544. {
  8545. var categoryAxis = this.get("categoryAxis"),
  8546. valueAxis = this.get("valueAxis");
  8547. if(categoryAxis)
  8548. {
  8549. categoryAxis.after("dataReady", Y.bind(this._categoryDataChangeHandler, this));
  8550. categoryAxis.after("dataUpdate", Y.bind(this._categoryDataChangeHandler, this));
  8551. }
  8552. if(valueAxis)
  8553. {
  8554. valueAxis.after("dataReady", Y.bind(this._valueDataChangeHandler, this));
  8555. valueAxis.after("dataUpdate", Y.bind(this._valueDataChangeHandler, this));
  8556. }
  8557. this.after("categoryAxisChange", this.categoryAxisChangeHandler);
  8558. this.after("valueAxisChange", this.valueAxisChangeHandler);
  8559. this.after("stylesChange", this._updateHandler);
  8560. },
  8561. /**
  8562. * Draws the series.
  8563. *
  8564. * @method validate
  8565. * @private
  8566. */
  8567. validate: function()
  8568. {
  8569. this.draw();
  8570. this._renderered = true;
  8571. },
  8572. /**
  8573. * Event handler for the categoryAxisChange event.
  8574. *
  8575. * @method _categoryAxisChangeHandler
  8576. * @param {Object} e Event object.
  8577. * @private
  8578. */
  8579. _categoryAxisChangeHandler: function(e)
  8580. {
  8581. var categoryAxis = this.get("categoryAxis");
  8582. categoryAxis.after("dataReady", Y.bind(this._categoryDataChangeHandler, this));
  8583. categoryAxis.after("dataUpdate", Y.bind(this._categoryDataChangeHandler, this));
  8584. },
  8585. /**
  8586. * Event handler for the valueAxisChange event.
  8587. *
  8588. * @method _valueAxisChangeHandler
  8589. * @param {Object} e Event object.
  8590. * @private
  8591. */
  8592. _valueAxisChangeHandler: function(e)
  8593. {
  8594. var valueAxis = this.get("valueAxis");
  8595. valueAxis.after("dataReady", Y.bind(this._valueDataChangeHandler, this));
  8596. valueAxis.after("dataUpdate", Y.bind(this._valueDataChangeHandler, this));
  8597. },
  8598. /**
  8599. * Constant used to generate unique id.
  8600. *
  8601. * @property GUID
  8602. * @type String
  8603. * @private
  8604. */
  8605. GUID: "pieseries",
  8606. /**
  8607. * Event handler for categoryDataChange event.
  8608. *
  8609. * @method _categoryDataChangeHandler
  8610. * @param {Object} event Event object.
  8611. * @private
  8612. */
  8613. _categoryDataChangeHandler: function(event)
  8614. {
  8615. if(this._rendered && this.get("categoryKey") && this.get("valueKey"))
  8616. {
  8617. this.draw();
  8618. }
  8619. },
  8620. /**
  8621. * Event handler for valueDataChange event.
  8622. *
  8623. * @method _valueDataChangeHandler
  8624. * @param {Object} event Event object.
  8625. * @private
  8626. */
  8627. _valueDataChangeHandler: function(event)
  8628. {
  8629. if(this._rendered && this.get("categoryKey") && this.get("valueKey"))
  8630. {
  8631. this.draw();
  8632. }
  8633. },
  8634. /**
  8635. * Draws the series. Overrides the base implementation.
  8636. *
  8637. * @method draw
  8638. * @protected
  8639. */
  8640. draw: function()
  8641. {
  8642. var graph = this.get("graph"),
  8643. w = graph.get("width"),
  8644. h = graph.get("height");
  8645. if(isFinite(w) && isFinite(h) && w > 0 && h > 0)
  8646. {
  8647. this._rendered = true;
  8648. if(this._drawing)
  8649. {
  8650. this._callLater = true;
  8651. return;
  8652. }
  8653. this._drawing = true;
  8654. this._callLater = false;
  8655. this.drawSeries();
  8656. this._drawing = false;
  8657. if(this._callLater)
  8658. {
  8659. this.draw();
  8660. }
  8661. else
  8662. {
  8663. this.fire("drawingComplete");
  8664. }
  8665. }
  8666. },
  8667. /**
  8668. * Draws the markers
  8669. *
  8670. * @method drawPlots
  8671. * @protected
  8672. */
  8673. drawPlots: function()
  8674. {
  8675. var values = this.get("valueAxis").getDataByKey(this.get("valueKey")).concat(),
  8676. catValues = this.get("categoryAxis").getDataByKey(this.get("categoryKey")).concat(),
  8677. totalValue = 0,
  8678. itemCount = values.length,
  8679. styles = this.get("styles").marker,
  8680. fillColors = styles.fill.colors,
  8681. fillAlphas = styles.fill.alphas || ["1"],
  8682. borderColors = styles.border.colors,
  8683. borderWeights = [styles.border.weight],
  8684. borderAlphas = [styles.border.alpha],
  8685. tbw = borderWeights.concat(),
  8686. tbc = borderColors.concat(),
  8687. tba = borderAlphas.concat(),
  8688. tfc,
  8689. tfa,
  8690. padding = styles.padding,
  8691. graph = this.get("graph"),
  8692. minDimension = Math.min(graph.get("width"), graph.get("height")),
  8693. w = minDimension - (padding.left + padding.right),
  8694. h = minDimension - (padding.top + padding.bottom),
  8695. startAngle = -90,
  8696. halfWidth = w / 2,
  8697. halfHeight = h / 2,
  8698. radius = Math.min(halfWidth, halfHeight),
  8699. i = 0,
  8700. value,
  8701. angle = 0,
  8702. lc,
  8703. la,
  8704. lw,
  8705. wedgeStyle,
  8706. marker,
  8707. graphOrder = this.get("graphOrder"),
  8708. isCanvas = Y.Graphic.NAME == "canvasGraphic";
  8709. for(; i < itemCount; ++i)
  8710. {
  8711. value = values[i];
  8712. values.push(value);
  8713. if(!isNaN(value))
  8714. {
  8715. totalValue += value;
  8716. }
  8717. }
  8718. tfc = fillColors ? fillColors.concat() : null;
  8719. tfa = fillAlphas ? fillAlphas.concat() : null;
  8720. this._createMarkerCache();
  8721. if(isCanvas)
  8722. {
  8723. this._setMap();
  8724. this._image.width = w;
  8725. this._image.height = h;
  8726. }
  8727. for(i = 0; i < itemCount; i++)
  8728. {
  8729. value = values[i];
  8730. if(totalValue === 0)
  8731. {
  8732. angle = 360 / values.length;
  8733. }
  8734. else
  8735. {
  8736. angle = 360 * (value / totalValue);
  8737. }
  8738. angle = Math.round(angle);
  8739. if(tfc && tfc.length < 1)
  8740. {
  8741. tfc = fillColors.concat();
  8742. }
  8743. if(tfa && tfa.length < 1)
  8744. {
  8745. tfa = fillAlphas.concat();
  8746. }
  8747. if(tbw && tbw.length < 1)
  8748. {
  8749. tbw = borderWeights.concat();
  8750. }
  8751. if(tbw && tbc.length < 1)
  8752. {
  8753. tbc = borderColors.concat();
  8754. }
  8755. if(tba && tba.length < 1)
  8756. {
  8757. tba = borderAlphas.concat();
  8758. }
  8759. lw = tbw ? tbw.shift() : null;
  8760. lc = tbc ? tbc.shift() : null;
  8761. la = tba ? tba.shift() : null;
  8762. startAngle += angle;
  8763. wedgeStyle = {
  8764. border: {
  8765. color:lc,
  8766. weight:lw,
  8767. alpha:la
  8768. },
  8769. fill: {
  8770. color:tfc ? tfc.shift() : this._getDefaultColor(i, "slice"),
  8771. alpha:tfa ? tfa.shift() : null
  8772. },
  8773. type: "pieslice",
  8774. arc: angle,
  8775. radius: radius,
  8776. startAngle: startAngle,
  8777. cx: halfWidth,
  8778. cy: halfHeight,
  8779. width: w,
  8780. height: h
  8781. };
  8782. marker = this.getMarker(wedgeStyle, graphOrder, i);
  8783. if(isCanvas)
  8784. {
  8785. this._addHotspot(wedgeStyle, graphOrder, i);
  8786. }
  8787. }
  8788. this._clearMarkerCache();
  8789. },
  8790. /**
  8791. * Adds an interactive map when rendering in canvas.
  8792. *
  8793. * @method _addHotspot
  8794. * @param {Object} cfg Object containing data used to draw the hotspot
  8795. * @param {Number} seriesIndex Index of series in the `seriesCollection`.
  8796. * @param {Number} index Index of the marker using the hotspot.
  8797. * @private
  8798. */
  8799. _addHotspot: function(cfg, seriesIndex, index)
  8800. {
  8801. var areaNode = DOCUMENT.createElement("area"),
  8802. i = 1,
  8803. x = cfg.cx,
  8804. y = cfg.cy,
  8805. arc = cfg.arc,
  8806. startAngle = cfg.startAngle - arc,
  8807. endAngle = cfg.startAngle,
  8808. radius = cfg.radius,
  8809. ax = x + Math.cos(startAngle / 180 * Math.PI) * radius,
  8810. ay = y + Math.sin(startAngle / 180 * Math.PI) * radius,
  8811. bx = x + Math.cos(endAngle / 180 * Math.PI) * radius,
  8812. by = y + Math.sin(endAngle / 180 * Math.PI) * radius,
  8813. numPoints = Math.floor(arc/10) - 1,
  8814. divAngle = (arc/(Math.floor(arc/10)) / 180) * Math.PI,
  8815. angleCoord = Math.atan((ay - y)/(ax - x)),
  8816. pts = x + ", " + y + ", " + ax + ", " + ay,
  8817. cosAng,
  8818. sinAng,
  8819. multDivAng;
  8820. for(i = 1; i <= numPoints; ++i)
  8821. {
  8822. multDivAng = divAngle * i;
  8823. cosAng = Math.cos(angleCoord + multDivAng);
  8824. sinAng = Math.sin(angleCoord + multDivAng);
  8825. if(startAngle <= 90)
  8826. {
  8827. pts += ", " + (x + (radius * Math.cos(angleCoord + (divAngle * i))));
  8828. pts += ", " + (y + (radius * Math.sin(angleCoord + (divAngle * i))));
  8829. }
  8830. else
  8831. {
  8832. pts += ", " + (x - (radius * Math.cos(angleCoord + (divAngle * i))));
  8833. pts += ", " + (y - (radius * Math.sin(angleCoord + (divAngle * i))));
  8834. }
  8835. }
  8836. pts += ", " + bx + ", " + by;
  8837. pts += ", " + x + ", " + y;
  8838. this._map.appendChild(areaNode);
  8839. areaNode.setAttribute("class", SERIES_MARKER);
  8840. areaNode.setAttribute("id", "hotSpot_" + seriesIndex + "_" + index);
  8841. areaNode.setAttribute("shape", "polygon");
  8842. areaNode.setAttribute("coords", pts);
  8843. this._areaNodes.push(areaNode);
  8844. },
  8845. /**
  8846. * Resizes and positions markers based on a mouse interaction.
  8847. *
  8848. * @method updateMarkerState
  8849. * @param {String} type state of the marker
  8850. * @param {Number} i index of the marker
  8851. * @protected
  8852. */
  8853. updateMarkerState: function(type, i)
  8854. {
  8855. if(this._markers[i])
  8856. {
  8857. var state = this._getState(type),
  8858. markerStyles,
  8859. indexStyles,
  8860. marker = this._markers[i],
  8861. styles = this.get("styles").marker;
  8862. markerStyles = state == "off" || !styles[state] ? styles : styles[state];
  8863. indexStyles = this._mergeStyles(markerStyles, {});
  8864. indexStyles.fill.color = indexStyles.fill.colors[i % indexStyles.fill.colors.length];
  8865. indexStyles.fill.alpha = indexStyles.fill.alphas[i % indexStyles.fill.alphas.length];
  8866. marker.set(indexStyles);
  8867. }
  8868. },
  8869. /**
  8870. * Creates a shape to be used as a marker.
  8871. *
  8872. * @method _createMarker
  8873. * @param {Object} styles Hash of style properties.
  8874. * @param {Number} order Order of the series.
  8875. * @param {Number} index Index within the series associated with the marker.
  8876. * @return Shape
  8877. * @private
  8878. */
  8879. _createMarker: function(styles, order, index)
  8880. {
  8881. var graphic = this.get("graphic"),
  8882. marker,
  8883. cfg = Y.clone(styles);
  8884. graphic.set("autoDraw", false);
  8885. marker = graphic.addShape(cfg);
  8886. marker.addClass(SERIES_MARKER);
  8887. return marker;
  8888. },
  8889. /**
  8890. * Creates a cache of markers for reuse.
  8891. *
  8892. * @method _createMarkerCache
  8893. * @private
  8894. */
  8895. _clearMarkerCache: function()
  8896. {
  8897. var len = this._markerCache.length,
  8898. i = 0,
  8899. marker;
  8900. for(; i < len; ++i)
  8901. {
  8902. marker = this._markerCache[i];
  8903. if(marker)
  8904. {
  8905. marker.destroy();
  8906. }
  8907. }
  8908. this._markerCache = [];
  8909. },
  8910. /**
  8911. * Gets the default style values for the markers.
  8912. *
  8913. * @method _getPlotDefaults
  8914. * @return Object
  8915. * @private
  8916. */
  8917. _getPlotDefaults: function()
  8918. {
  8919. var defs = {
  8920. padding:{
  8921. top: 0,
  8922. left: 0,
  8923. right: 0,
  8924. bottom: 0
  8925. },
  8926. fill:{
  8927. alphas:["1"]
  8928. },
  8929. border: {
  8930. weight: 0,
  8931. alpha: 1
  8932. }
  8933. };
  8934. defs.fill.colors = this._defaultSliceColors;
  8935. defs.border.colors = this._defaultBorderColors;
  8936. return defs;
  8937. },
  8938. /**
  8939. * Collection of default colors used for lines in a series when not specified by user.
  8940. *
  8941. * @property _defaultLineColors
  8942. * @type Array
  8943. * @protected
  8944. */
  8945. _defaultLineColors:["#426ab3", "#d09b2c", "#000000", "#b82837", "#b384b5", "#ff7200", "#779de3", "#cbc8ba", "#7ed7a6", "#007a6c"],
  8946. /**
  8947. * Collection of default colors used for marker fills in a series when not specified by user.
  8948. *
  8949. * @property _defaultFillColors
  8950. * @type Array
  8951. * @protected
  8952. */
  8953. _defaultFillColors:["#6084d0", "#eeb647", "#6c6b5f", "#d6484f", "#ce9ed1", "#ff9f3b", "#93b7ff", "#e0ddd0", "#94ecba", "#309687"],
  8954. /**
  8955. * Collection of default colors used for marker borders in a series when not specified by user.
  8956. *
  8957. * @property _defaultBorderColors
  8958. * @type Array
  8959. * @protected
  8960. */
  8961. _defaultBorderColors:["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"],
  8962. /**
  8963. * Collection of default colors used for area fills, histogram fills and pie fills in a series when not specified by user.
  8964. *
  8965. * @property _defaultSliceColors
  8966. * @type Array
  8967. * @protected
  8968. */
  8969. _defaultSliceColors: ["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"],
  8970. /**
  8971. * Colors used if style colors are not specified
  8972. *
  8973. * @method _getDefaultColor
  8974. * @param {Number} index Index indicating the series order.
  8975. * @param {String} type Indicates which type of object needs the color.
  8976. * @return String
  8977. * @protected
  8978. */
  8979. _getDefaultColor: function(index, type)
  8980. {
  8981. var colors = {
  8982. line: this._defaultLineColors,
  8983. fill: this._defaultFillColors,
  8984. border: this._defaultBorderColors,
  8985. slice: this._defaultSliceColors
  8986. },
  8987. col = colors[type],
  8988. l = col.length;
  8989. index = index || 0;
  8990. if(index >= l)
  8991. {
  8992. index = index % l;
  8993. }
  8994. type = type || "fill";
  8995. return colors[type][index];
  8996. }
  8997. }, {
  8998. ATTRS: {
  8999. /**
  9000. * Read-only attribute indicating the type of series.
  9001. *
  9002. * @attribute type
  9003. * @type String
  9004. * @default pie
  9005. */
  9006. type: {
  9007. value: "pie"
  9008. },
  9009. /**
  9010. * Order of this instance of this `type`.
  9011. *
  9012. * @attribute order
  9013. * @type Number
  9014. */
  9015. order: {},
  9016. /**
  9017. * Reference to the `Graph` in which the series is drawn into.
  9018. *
  9019. * @attribute graph
  9020. * @type Graph
  9021. */
  9022. graph: {},
  9023. /**
  9024. * Reference to the `Axis` instance used for assigning
  9025. * category values to the graph.
  9026. *
  9027. * @attribute categoryAxis
  9028. * @type Axis
  9029. */
  9030. categoryAxis: {
  9031. value: null,
  9032. validator: function(value)
  9033. {
  9034. return value !== this.get("categoryAxis");
  9035. }
  9036. },
  9037. /**
  9038. * Reference to the `Axis` instance used for assigning
  9039. * series values to the graph.
  9040. *
  9041. * @attribute categoryAxis
  9042. * @type Axis
  9043. */
  9044. valueAxis: {
  9045. value: null,
  9046. validator: function(value)
  9047. {
  9048. return value !== this.get("valueAxis");
  9049. }
  9050. },
  9051. /**
  9052. * Indicates which array to from the hash of value arrays in
  9053. * the category `Axis` instance.
  9054. *
  9055. * @attribute categoryKey
  9056. * @type String
  9057. */
  9058. categoryKey: {
  9059. value: null,
  9060. validator: function(value)
  9061. {
  9062. return value !== this.get("categoryKey");
  9063. }
  9064. },
  9065. /**
  9066. * Indicates which array to from the hash of value arrays in
  9067. * the value `Axis` instance.
  9068. *
  9069. * @attribute valueKey
  9070. * @type String
  9071. */
  9072. valueKey: {
  9073. value: null,
  9074. validator: function(value)
  9075. {
  9076. return value !== this.get("valueKey");
  9077. }
  9078. },
  9079. /**
  9080. * Name used for for displaying category data
  9081. *
  9082. * @attribute categoryDisplayName
  9083. * @type String
  9084. */
  9085. categoryDisplayName: {
  9086. setter: function(val)
  9087. {
  9088. this._categoryDisplayName = val;
  9089. return val;
  9090. },
  9091. getter: function()
  9092. {
  9093. return this._categoryDisplayName || this.get("categoryKey");
  9094. }
  9095. },
  9096. /**
  9097. * Name used for for displaying value data
  9098. *
  9099. * @attribute valueDisplayName
  9100. * @type String
  9101. */
  9102. valueDisplayName: {
  9103. setter: function(val)
  9104. {
  9105. this._valueDisplayName = val;
  9106. return val;
  9107. },
  9108. getter: function()
  9109. {
  9110. return this._valueDisplayName || this.get("valueKey");
  9111. }
  9112. },
  9113. /**
  9114. * @attribute slices
  9115. * @type Array
  9116. * @private
  9117. */
  9118. slices: null
  9119. /**
  9120. * Style properties used for drawing markers. This attribute is inherited from `MarkerSeries`. Below are the default values:
  9121. * <dl>
  9122. * <dt>fill</dt><dd>A hash containing the following values:
  9123. * <dl>
  9124. * <dt>colors</dt><dd>An array of colors to be used for the marker fills. The color for each marker is retrieved from the
  9125. * array below:<br/>
  9126. * `["#66007f", "#a86f41", "#295454", "#996ab2", "#e8cdb7", "#90bdbd","#000000","#c3b8ca", "#968373", "#678585"]`
  9127. * </dd>
  9128. * <dt>alphas</dt><dd>An array of alpha references (Number from 0 to 1) indicating the opacity of each marker fill. The default value is [1].</dd>
  9129. * </dl>
  9130. * </dd>
  9131. * <dt>border</dt><dd>A hash containing the following values:
  9132. * <dl>
  9133. * <dt>color</dt><dd>An array of colors to be used for the marker borders. The color for each marker is retrieved from the
  9134. * array below:<br/>
  9135. * `["#205096", "#b38206", "#000000", "#94001e", "#9d6fa0", "#e55b00", "#5e85c9", "#adab9e", "#6ac291", "#006457"]`
  9136. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the marker border. The default value is 1.</dd>
  9137. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  9138. * </dl>
  9139. * </dd>
  9140. * <dt>over</dt><dd>hash containing styles for markers when highlighted by a `mouseover` event. The default
  9141. * values for each style is null. When an over style is not set, the non-over value will be used. For example,
  9142. * the default value for `marker.over.fill.color` is equivalent to `marker.fill.color`.</dd>
  9143. * </dl>
  9144. *
  9145. * @attribute styles
  9146. * @type Object
  9147. */
  9148. }
  9149. });
  9150. /**
  9151. * Gridlines draws gridlines on a Graph.
  9152. *
  9153. * @module charts
  9154. * @class Gridlines
  9155. * @constructor
  9156. * @extends Base
  9157. * @uses Renderer
  9158. */
  9159. Y.Gridlines = Y.Base.create("gridlines", Y.Base, [Y.Renderer], {
  9160. /**
  9161. * Reference to the `Path` element used for drawing Gridlines.
  9162. *
  9163. * @property _path
  9164. * @type Path
  9165. * @private
  9166. */
  9167. _path: null,
  9168. /**
  9169. * Removes the Gridlines.
  9170. *
  9171. * @method remove
  9172. * @private
  9173. */
  9174. remove: function()
  9175. {
  9176. var path = this._path;
  9177. if(path)
  9178. {
  9179. path.destroy();
  9180. }
  9181. },
  9182. /**
  9183. * Draws the gridlines
  9184. *
  9185. * @method draw
  9186. * @protected
  9187. */
  9188. draw: function()
  9189. {
  9190. if(this.get("axis") && this.get("graph"))
  9191. {
  9192. this._drawGridlines();
  9193. }
  9194. },
  9195. /**
  9196. * Algorithm for drawing gridlines
  9197. *
  9198. * @method _drawGridlines
  9199. * @private
  9200. */
  9201. _drawGridlines: function()
  9202. {
  9203. var path,
  9204. axis = this.get("axis"),
  9205. axisPosition = axis.get("position"),
  9206. points,
  9207. i = 0,
  9208. l,
  9209. direction = this.get("direction"),
  9210. graph = this.get("graph"),
  9211. w = graph.get("width"),
  9212. h = graph.get("height"),
  9213. line = this.get("styles").line,
  9214. color = line.color,
  9215. weight = line.weight,
  9216. alpha = line.alpha,
  9217. lineFunction = direction == "vertical" ? this._verticalLine : this._horizontalLine;
  9218. if(axisPosition == "none")
  9219. {
  9220. points = [];
  9221. l = axis.get("styles").majorUnit.count;
  9222. for(; i < l; ++i)
  9223. {
  9224. points[i] = {
  9225. x: w * (i/(l-1)),
  9226. y: h * (i/(l-1))
  9227. };
  9228. }
  9229. i = 0;
  9230. }
  9231. else
  9232. {
  9233. points = axis.get("tickPoints");
  9234. l = points.length;
  9235. }
  9236. path = graph.get("gridlines");
  9237. path.set("width", w);
  9238. path.set("height", h);
  9239. path.set("stroke", {
  9240. weight: weight,
  9241. color: color,
  9242. opacity: alpha
  9243. });
  9244. for(; i < l; ++i)
  9245. {
  9246. lineFunction(path, points[i], w, h);
  9247. }
  9248. path.end();
  9249. },
  9250. /**
  9251. * Algorithm for horizontal lines.
  9252. *
  9253. * @method _horizontalLine
  9254. * @param {Path} path Reference to path element
  9255. * @param {Object} pt Coordinates corresponding to a major unit of an axis.
  9256. * @param {Number} w Width of the Graph
  9257. * @param {Number} h Height of the Graph
  9258. * @private
  9259. */
  9260. _horizontalLine: function(path, pt, w, h)
  9261. {
  9262. path.moveTo(0, pt.y);
  9263. path.lineTo(w, pt.y);
  9264. },
  9265. /**
  9266. * Algorithm for vertical lines.
  9267. *
  9268. * @method _verticalLine
  9269. * @param {Path} path Reference to path element
  9270. * @param {Object} pt Coordinates corresponding to a major unit of an axis.
  9271. * @param {Number} w Width of the Graph
  9272. * @param {Number} h Height of the Graph
  9273. * @private
  9274. */
  9275. _verticalLine: function(path, pt, w, h)
  9276. {
  9277. path.moveTo(pt.x, 0);
  9278. path.lineTo(pt.x, h);
  9279. },
  9280. /**
  9281. * Gets the default value for the `styles` attribute. Overrides
  9282. * base implementation.
  9283. *
  9284. * @method _getDefaultStyles
  9285. * @return Object
  9286. * @protected
  9287. */
  9288. _getDefaultStyles: function()
  9289. {
  9290. var defs = {
  9291. line: {
  9292. color:"#f0efe9",
  9293. weight: 1,
  9294. alpha: 1
  9295. }
  9296. };
  9297. return defs;
  9298. }
  9299. },
  9300. {
  9301. ATTRS: {
  9302. /**
  9303. * Indicates the direction of the gridline.
  9304. *
  9305. * @attribute direction
  9306. * @type String
  9307. */
  9308. direction: {},
  9309. /**
  9310. * Indicate the `Axis` in which to bind
  9311. * the gridlines.
  9312. *
  9313. * @attribute axis
  9314. * @type Axis
  9315. */
  9316. axis: {},
  9317. /**
  9318. * Indicates the `Graph` in which the gridlines
  9319. * are drawn.
  9320. *
  9321. * @attribute graph
  9322. * @type Graph
  9323. */
  9324. graph: {}
  9325. }
  9326. });
  9327. /**
  9328. * Graph manages and contains series instances for a `CartesianChart`
  9329. * instance.
  9330. *
  9331. * @module charts
  9332. * @class Graph
  9333. * @constructor
  9334. * @extends Widget
  9335. * @uses Renderer
  9336. */
  9337. Y.Graph = Y.Base.create("graph", Y.Widget, [Y.Renderer], {
  9338. /**
  9339. * @method bindUI
  9340. * @private
  9341. */
  9342. bindUI: function()
  9343. {
  9344. var bb = this.get("boundingBox");
  9345. bb.setStyle("position", "absolute");
  9346. this.after("widthChange", this._sizeChangeHandler);
  9347. this.after("heightChange", this._sizeChangeHandler);
  9348. this.after("stylesChange", this._updateStyles);
  9349. },
  9350. /**
  9351. * @method syncUI
  9352. * @private
  9353. */
  9354. syncUI: function()
  9355. {
  9356. var background,
  9357. cb,
  9358. bg,
  9359. sc = this.get("seriesCollection"),
  9360. series,
  9361. i = 0,
  9362. len = sc.length,
  9363. hgl = this.get("horizontalGridlines"),
  9364. vgl = this.get("verticalGridlines");
  9365. if(this.get("showBackground"))
  9366. {
  9367. background = this.get("background");
  9368. cb = this.get("contentBox");
  9369. bg = this.get("styles").background;
  9370. bg.stroke = bg.border;
  9371. bg.stroke.opacity = bg.stroke.alpha;
  9372. bg.fill.opacity = bg.fill.alpha;
  9373. bg.width = this.get("width");
  9374. bg.height = this.get("height");
  9375. bg.type = bg.shape;
  9376. background.set(bg);
  9377. }
  9378. for(; i < len; ++i)
  9379. {
  9380. series = sc[i];
  9381. if(series instanceof Y.CartesianSeries)
  9382. {
  9383. series.render();
  9384. }
  9385. }
  9386. if(hgl && hgl instanceof Y.Gridlines)
  9387. {
  9388. hgl.draw();
  9389. }
  9390. if(vgl && vgl instanceof Y.Gridlines)
  9391. {
  9392. vgl.draw();
  9393. }
  9394. },
  9395. /**
  9396. * Object of arrays containing series mapped to a series type.
  9397. *
  9398. * @property seriesTypes
  9399. * @type Object
  9400. * @private
  9401. */
  9402. seriesTypes: null,
  9403. /**
  9404. * Returns a series instance based on an index.
  9405. *
  9406. * @method getSeriesByIndex
  9407. * @param {Number} val index of the series
  9408. * @return CartesianSeries
  9409. */
  9410. getSeriesByIndex: function(val)
  9411. {
  9412. var col = this.get("seriesCollection"),
  9413. series;
  9414. if(col && col.length > val)
  9415. {
  9416. series = col[val];
  9417. }
  9418. return series;
  9419. },
  9420. /**
  9421. * Returns a series instance based on a key value.
  9422. *
  9423. * @method getSeriesByKey
  9424. * @param {String} val key value of the series
  9425. * @return CartesianSeries
  9426. */
  9427. getSeriesByKey: function(val)
  9428. {
  9429. var obj = this._seriesDictionary,
  9430. series;
  9431. if(obj && obj.hasOwnProperty(val))
  9432. {
  9433. series = obj[val];
  9434. }
  9435. return series;
  9436. },
  9437. /**
  9438. * Adds dispatcher to a `_dispatcher` used to
  9439. * to ensure all series have redrawn before for firing event.
  9440. *
  9441. * @method addDispatcher
  9442. * @param {CartesianSeries} val series instance to add
  9443. * @protected
  9444. */
  9445. addDispatcher: function(val)
  9446. {
  9447. if(!this._dispatchers)
  9448. {
  9449. this._dispatchers = [];
  9450. }
  9451. this._dispatchers.push(val);
  9452. },
  9453. /**
  9454. * Collection of series to be displayed in the graph.
  9455. *
  9456. * @property _seriesCollection
  9457. * @type Array
  9458. * @private
  9459. */
  9460. _seriesCollection: null,
  9461. /**
  9462. * Object containing key value pairs of `CartesianSeries` instances.
  9463. *
  9464. * @property _seriesDictionary
  9465. * @type Object
  9466. * @private
  9467. */
  9468. _seriesDictionary: null,
  9469. /**
  9470. * Parses series instances to be displayed in the graph.
  9471. *
  9472. * @method _parseSeriesCollection
  9473. * @param {Array} Collection of `CartesianSeries` instances or objects container `CartesianSeries` attributes values.
  9474. * @private
  9475. */
  9476. _parseSeriesCollection: function(val)
  9477. {
  9478. if(!val)
  9479. {
  9480. return;
  9481. }
  9482. var len = val.length,
  9483. i = 0,
  9484. series,
  9485. seriesKey;
  9486. if(!this.get("seriesCollection"))
  9487. {
  9488. this._seriesCollection = [];
  9489. }
  9490. if(!this._seriesDictionary)
  9491. {
  9492. this._seriesDictionary = {};
  9493. }
  9494. if(!this.seriesTypes)
  9495. {
  9496. this.seriesTypes = [];
  9497. }
  9498. for(; i < len; ++i)
  9499. {
  9500. series = val[i];
  9501. if(!(series instanceof Y.CartesianSeries) && !(series instanceof Y.PieSeries))
  9502. {
  9503. this._createSeries(series);
  9504. continue;
  9505. }
  9506. this._addSeries(series);
  9507. }
  9508. len = this.get("seriesCollection").length;
  9509. for(i = 0; i < len; ++i)
  9510. {
  9511. series = this.get("seriesCollection")[i];
  9512. seriesKey = series.get("direction") == "horizontal" ? "yKey" : "xKey";
  9513. this._seriesDictionary[series.get(seriesKey)] = series;
  9514. }
  9515. },
  9516. /**
  9517. * Adds a series to the graph.
  9518. *
  9519. * @method _addSeries
  9520. * @param {CartesianSeries} series Series to add to the graph.
  9521. * @private
  9522. */
  9523. _addSeries: function(series)
  9524. {
  9525. var type = series.get("type"),
  9526. seriesCollection = this.get("seriesCollection"),
  9527. graphSeriesLength = seriesCollection.length,
  9528. seriesTypes = this.seriesTypes,
  9529. typeSeriesCollection;
  9530. if(!series.get("graph"))
  9531. {
  9532. series.set("graph", this);
  9533. }
  9534. seriesCollection.push(series);
  9535. if(!seriesTypes.hasOwnProperty(type))
  9536. {
  9537. this.seriesTypes[type] = [];
  9538. }
  9539. typeSeriesCollection = this.seriesTypes[type];
  9540. series.set("graphOrder", graphSeriesLength);
  9541. series.set("order", typeSeriesCollection.length);
  9542. typeSeriesCollection.push(series);
  9543. this.addDispatcher(series);
  9544. series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
  9545. this.fire("seriesAdded", series);
  9546. },
  9547. /**
  9548. * Creates a `CartesianSeries` instance from an object containing attribute key value pairs. The key value pairs include attributes for the specific series and a type value which defines the type of
  9549. * series to be used.
  9550. *
  9551. * @method createSeries
  9552. * @param {Object} seriesData Series attribute key value pairs.
  9553. * @private
  9554. */
  9555. _createSeries: function(seriesData)
  9556. {
  9557. var type = seriesData.type,
  9558. seriesCollection = this.get("seriesCollection"),
  9559. seriesTypes = this.seriesTypes,
  9560. typeSeriesCollection,
  9561. seriesType,
  9562. series;
  9563. seriesData.graph = this;
  9564. if(!seriesTypes.hasOwnProperty(type))
  9565. {
  9566. seriesTypes[type] = [];
  9567. }
  9568. typeSeriesCollection = seriesTypes[type];
  9569. seriesData.graph = this;
  9570. seriesData.order = typeSeriesCollection.length;
  9571. seriesData.graphOrder = seriesCollection.length;
  9572. seriesType = this._getSeries(seriesData.type);
  9573. series = new seriesType(seriesData);
  9574. this.addDispatcher(series);
  9575. series.after("drawingComplete", Y.bind(this._drawingCompleteHandler, this));
  9576. typeSeriesCollection.push(series);
  9577. seriesCollection.push(series);
  9578. },
  9579. /**
  9580. * String reference for pre-defined `Series` classes.
  9581. *
  9582. * @property _seriesMap
  9583. * @type Object
  9584. * @private
  9585. */
  9586. _seriesMap: {
  9587. line : Y.LineSeries,
  9588. column : Y.ColumnSeries,
  9589. bar : Y.BarSeries,
  9590. area : Y.AreaSeries,
  9591. candlestick : Y.CandlestickSeries,
  9592. ohlc : Y.OHLCSeries,
  9593. stackedarea : Y.StackedAreaSeries,
  9594. stackedline : Y.StackedLineSeries,
  9595. stackedcolumn : Y.StackedColumnSeries,
  9596. stackedbar : Y.StackedBarSeries,
  9597. markerseries : Y.MarkerSeries,
  9598. spline : Y.SplineSeries,
  9599. areaspline : Y.AreaSplineSeries,
  9600. stackedspline : Y.StackedSplineSeries,
  9601. stackedareaspline : Y.StackedAreaSplineSeries,
  9602. stackedmarkerseries : Y.StackedMarkerSeries,
  9603. pie : Y.PieSeries,
  9604. combo : Y.ComboSeries,
  9605. stackedcombo : Y.StackedComboSeries,
  9606. combospline : Y.ComboSplineSeries,
  9607. stackedcombospline : Y.StackedComboSplineSeries
  9608. },
  9609. /**
  9610. * Returns a specific `CartesianSeries` class based on key value from a look up table of a direct reference to a class. When specifying a key value, the following options
  9611. * are available:
  9612. *
  9613. * <table>
  9614. * <tr><th>Key Value</th><th>Class</th></tr>
  9615. * <tr><td>line</td><td>Y.LineSeries</td></tr>
  9616. * <tr><td>column</td><td>Y.ColumnSeries</td></tr>
  9617. * <tr><td>bar</td><td>Y.BarSeries</td></tr>
  9618. * <tr><td>area</td><td>Y.AreaSeries</td></tr>
  9619. * <tr><td>stackedarea</td><td>Y.StackedAreaSeries</td></tr>
  9620. * <tr><td>stackedline</td><td>Y.StackedLineSeries</td></tr>
  9621. * <tr><td>stackedcolumn</td><td>Y.StackedColumnSeries</td></tr>
  9622. * <tr><td>stackedbar</td><td>Y.StackedBarSeries</td></tr>
  9623. * <tr><td>markerseries</td><td>Y.MarkerSeries</td></tr>
  9624. * <tr><td>spline</td><td>Y.SplineSeries</td></tr>
  9625. * <tr><td>areaspline</td><td>Y.AreaSplineSeries</td></tr>
  9626. * <tr><td>stackedspline</td><td>Y.StackedSplineSeries</td></tr>
  9627. * <tr><td>stackedareaspline</td><td>Y.StackedAreaSplineSeries</td></tr>
  9628. * <tr><td>stackedmarkerseries</td><td>Y.StackedMarkerSeries</td></tr>
  9629. * <tr><td>pie</td><td>Y.PieSeries</td></tr>
  9630. * <tr><td>combo</td><td>Y.ComboSeries</td></tr>
  9631. * <tr><td>stackedcombo</td><td>Y.StackedComboSeries</td></tr>
  9632. * <tr><td>combospline</td><td>Y.ComboSplineSeries</td></tr>
  9633. * <tr><td>stackedcombospline</td><td>Y.StackedComboSplineSeries</td></tr>
  9634. * </table>
  9635. *
  9636. * When referencing a class directly, you can specify any of the above classes or any custom class that extends `CartesianSeries` or `PieSeries`.
  9637. *
  9638. * @method _getSeries
  9639. * @param {String | Object} type Series type.
  9640. * @return CartesianSeries
  9641. * @private
  9642. */
  9643. _getSeries: function(type)
  9644. {
  9645. var seriesClass;
  9646. if(Y_Lang.isString(type))
  9647. {
  9648. seriesClass = this._seriesMap[type];
  9649. }
  9650. else
  9651. {
  9652. seriesClass = type;
  9653. }
  9654. return seriesClass;
  9655. },
  9656. /**
  9657. * Event handler for marker events.
  9658. *
  9659. * @method _markerEventHandler
  9660. * @param {Object} e Event object.
  9661. * @private
  9662. */
  9663. _markerEventHandler: function(e)
  9664. {
  9665. var type = e.type,
  9666. markerNode = e.currentTarget,
  9667. strArr = markerNode.getAttribute("id").split("_"),
  9668. series = this.getSeriesByIndex(strArr[1]),
  9669. index = strArr[2];
  9670. series.updateMarkerState(type, index);
  9671. },
  9672. /**
  9673. * Collection of `CartesianSeries` instances to be redrawn.
  9674. *
  9675. * @property _dispatchers
  9676. * @type Array
  9677. * @private
  9678. */
  9679. _dispatchers: null,
  9680. /**
  9681. * Updates the `Graph` styles.
  9682. *
  9683. * @method _updateStyles
  9684. * @private
  9685. */
  9686. _updateStyles: function()
  9687. {
  9688. var styles = this.get("styles").background,
  9689. border = styles.border;
  9690. border.opacity = border.alpha;
  9691. styles.stroke = border;
  9692. styles.fill.opacity = styles.fill.alpha;
  9693. this.get("background").set(styles);
  9694. this._sizeChangeHandler();
  9695. },
  9696. /**
  9697. * Event handler for size changes.
  9698. *
  9699. * @method _sizeChangeHandler
  9700. * @param {Object} e Event object.
  9701. * @private
  9702. */
  9703. _sizeChangeHandler: function(e)
  9704. {
  9705. var hgl = this.get("horizontalGridlines"),
  9706. vgl = this.get("verticalGridlines"),
  9707. w = this.get("width"),
  9708. h = this.get("height"),
  9709. bg = this.get("styles").background,
  9710. weight,
  9711. background;
  9712. if(bg && bg.border)
  9713. {
  9714. weight = bg.border.weight || 0;
  9715. }
  9716. if(this.get("showBackground"))
  9717. {
  9718. background = this.get("background");
  9719. if(w && h)
  9720. {
  9721. background.set("width", w);
  9722. background.set("height", h);
  9723. }
  9724. }
  9725. if(this._gridlines)
  9726. {
  9727. this._gridlines.clear();
  9728. }
  9729. if(hgl && hgl instanceof Y.Gridlines)
  9730. {
  9731. hgl.draw();
  9732. }
  9733. if(vgl && vgl instanceof Y.Gridlines)
  9734. {
  9735. vgl.draw();
  9736. }
  9737. this._drawSeries();
  9738. },
  9739. /**
  9740. * Draws each series.
  9741. *
  9742. * @method _drawSeries
  9743. * @private
  9744. */
  9745. _drawSeries: function()
  9746. {
  9747. if(this._drawing)
  9748. {
  9749. this._callLater = true;
  9750. return;
  9751. }
  9752. var sc,
  9753. i,
  9754. len,
  9755. graphic = this.get("graphic");
  9756. graphic.set("autoDraw", false);
  9757. this._callLater = false;
  9758. this._drawing = true;
  9759. sc = this.get("seriesCollection");
  9760. i = 0;
  9761. len = sc.length;
  9762. for(; i < len; ++i)
  9763. {
  9764. sc[i].draw();
  9765. if((!sc[i].get("xcoords") || !sc[i].get("ycoords")) && !sc[i] instanceof Y.PieSeries)
  9766. {
  9767. this._callLater = true;
  9768. break;
  9769. }
  9770. }
  9771. this._drawing = false;
  9772. if(this._callLater)
  9773. {
  9774. this._drawSeries();
  9775. }
  9776. },
  9777. /**
  9778. * Event handler for series drawingComplete event.
  9779. *
  9780. * @method _drawingCompleteHandler
  9781. * @param {Object} e Event object.
  9782. * @private
  9783. */
  9784. _drawingCompleteHandler: function(e)
  9785. {
  9786. var series = e.currentTarget,
  9787. graphic,
  9788. index = Y.Array.indexOf(this._dispatchers, series);
  9789. if(index > -1)
  9790. {
  9791. this._dispatchers.splice(index, 1);
  9792. }
  9793. if(this._dispatchers.length < 1)
  9794. {
  9795. graphic = this.get("graphic");
  9796. if(!graphic.get("autoDraw"))
  9797. {
  9798. graphic._redraw();
  9799. }
  9800. this.fire("chartRendered");
  9801. }
  9802. },
  9803. /**
  9804. * Gets the default value for the `styles` attribute. Overrides
  9805. * base implementation.
  9806. *
  9807. * @method _getDefaultStyles
  9808. * @return Object
  9809. * @protected
  9810. */
  9811. _getDefaultStyles: function()
  9812. {
  9813. var defs = {
  9814. background: {
  9815. shape: "rect",
  9816. fill:{
  9817. color:"#faf9f2"
  9818. },
  9819. border: {
  9820. color:"#dad8c9",
  9821. weight: 1
  9822. }
  9823. }
  9824. };
  9825. return defs;
  9826. }
  9827. }, {
  9828. ATTRS: {
  9829. /**
  9830. * Reference to the chart instance using the graph.
  9831. *
  9832. * @attribute chart
  9833. * @type ChartBase
  9834. * @readOnly
  9835. */
  9836. chart: {},
  9837. /**
  9838. * Collection of series. When setting the `seriesCollection` the array can contain a combination of either
  9839. * `CartesianSeries` instances or object literals with properties that will define a series.
  9840. *
  9841. * @attribute seriesCollection
  9842. * @type CartesianSeries
  9843. */
  9844. seriesCollection: {
  9845. getter: function()
  9846. {
  9847. return this._seriesCollection;
  9848. },
  9849. setter: function(val)
  9850. {
  9851. this._parseSeriesCollection(val);
  9852. return this._seriesCollection;
  9853. }
  9854. },
  9855. /**
  9856. * Indicates whether the `Graph` has a background.
  9857. *
  9858. * @attribute showBackground
  9859. * @type Boolean
  9860. * @default true
  9861. */
  9862. showBackground: {
  9863. value: true
  9864. },
  9865. /**
  9866. * Read-only hash lookup for all series on in the `Graph`.
  9867. *
  9868. * @attribute seriesDictionary
  9869. * @type Object
  9870. * @readOnly
  9871. */
  9872. seriesDictionary: {
  9873. readOnly: true,
  9874. getter: function()
  9875. {
  9876. return this._seriesDictionary;
  9877. }
  9878. },
  9879. /**
  9880. * Reference to the horizontal `Gridlines` instance.
  9881. *
  9882. * @attribute horizontalGridlines
  9883. * @type Gridlines
  9884. * @default null
  9885. */
  9886. horizontalGridlines: {
  9887. value: null,
  9888. setter: function(val)
  9889. {
  9890. var gl = this.get("horizontalGridlines");
  9891. if(gl && gl instanceof Y.Gridlines)
  9892. {
  9893. gl.remove();
  9894. }
  9895. if(val instanceof Y.Gridlines)
  9896. {
  9897. gl = val;
  9898. val.set("graph", this);
  9899. return val;
  9900. }
  9901. else if(val && val.axis)
  9902. {
  9903. gl = new Y.Gridlines({direction:"horizontal", axis:val.axis, graph:this, styles:val.styles});
  9904. return gl;
  9905. }
  9906. }
  9907. },
  9908. /**
  9909. * Reference to the vertical `Gridlines` instance.
  9910. *
  9911. * @attribute verticalGridlines
  9912. * @type Gridlines
  9913. * @default null
  9914. */
  9915. verticalGridlines: {
  9916. value: null,
  9917. setter: function(val)
  9918. {
  9919. var gl = this.get("verticalGridlines");
  9920. if(gl && gl instanceof Y.Gridlines)
  9921. {
  9922. gl.remove();
  9923. }
  9924. if(val instanceof Y.Gridlines)
  9925. {
  9926. gl = val;
  9927. val.set("graph", this);
  9928. return val;
  9929. }
  9930. else if(val && val.axis)
  9931. {
  9932. gl = new Y.Gridlines({direction:"vertical", axis:val.axis, graph:this, styles:val.styles});
  9933. return gl;
  9934. }
  9935. }
  9936. },
  9937. /**
  9938. * Reference to graphic instance used for the background.
  9939. *
  9940. * @attribute background
  9941. * @type Graphic
  9942. * @readOnly
  9943. */
  9944. background: {
  9945. getter: function()
  9946. {
  9947. if(!this._background)
  9948. {
  9949. this._backgroundGraphic = new Y.Graphic({render:this.get("contentBox")});
  9950. Y.one(this._backgroundGraphic.get("node")).setStyle("zIndex", 0);
  9951. this._background = this._backgroundGraphic.addShape({type: "rect"});
  9952. }
  9953. return this._background;
  9954. }
  9955. },
  9956. /**
  9957. * Reference to graphic instance used for gridlines.
  9958. *
  9959. * @attribute gridlines
  9960. * @type Graphic
  9961. * @readOnly
  9962. */
  9963. gridlines: {
  9964. readOnly: true,
  9965. getter: function()
  9966. {
  9967. if(!this._gridlines)
  9968. {
  9969. this._gridlinesGraphic = new Y.Graphic({render:this.get("contentBox")});
  9970. Y.one(this._gridlinesGraphic.get("node")).setStyle("zIndex", 1);
  9971. this._gridlines = this._gridlinesGraphic.addShape({type: "path"});
  9972. }
  9973. return this._gridlines;
  9974. }
  9975. },
  9976. /**
  9977. * Reference to graphic instance used for series.
  9978. *
  9979. * @attribute graphic
  9980. * @type Graphic
  9981. * @readOnly
  9982. */
  9983. graphic: {
  9984. readOnly: true,
  9985. getter: function()
  9986. {
  9987. if(!this._graphic)
  9988. {
  9989. this._graphic = new Y.Graphic({render:this.get("contentBox")});
  9990. Y.one(this._graphic.get("node")).setStyle("zIndex", 2);
  9991. this._graphic.set("autoDraw", false);
  9992. }
  9993. return this._graphic;
  9994. }
  9995. }
  9996. /**
  9997. * Style properties used for drawing a background. Below are the default values:
  9998. * <dl>
  9999. * <dt>background</dt><dd>An object containing the following values:
  10000. * <dl>
  10001. * <dt>fill</dt><dd>Defines the style properties for the fill. Contains the following values:
  10002. * <dl>
  10003. * <dt>color</dt><dd>Color of the fill. The default value is #faf9f2.</dd>
  10004. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background fill. The default value is 1.</dd>
  10005. * </dl>
  10006. * </dd>
  10007. * <dt>border</dt><dd>Defines the style properties for the border. Contains the following values:
  10008. * <dl>
  10009. * <dt>color</dt><dd>Color of the border. The default value is #dad8c9.</dd>
  10010. * <dt>alpha</dt><dd>Number from 0 to 1 indicating the opacity of the background border. The default value is 1.</dd>
  10011. * <dt>weight</dt><dd>Number indicating the width of the border. The default value is 1.</dd>
  10012. * </dl>
  10013. * </dd>
  10014. * </dl>
  10015. * </dd>
  10016. * </dl>
  10017. *
  10018. * @attribute styles
  10019. * @type Object
  10020. */
  10021. }
  10022. });
  10023. /**
  10024. * The ChartBase class is an abstract class used to create charts.
  10025. *
  10026. * @module charts
  10027. * @class ChartBase
  10028. * @constructor
  10029. */
  10030. function ChartBase() {}
  10031. ChartBase.ATTRS = {
  10032. /**
  10033. * Reference to the default tooltip available for the chart.
  10034. * <p>Contains the following properties:</p>
  10035. * <dl>
  10036. * <dt>node</dt><dd>Reference to the actual dom node</dd>
  10037. * <dt>showEvent</dt><dd>Event that should trigger the tooltip</dd>
  10038. * <dt>hideEvent</dt><dd>Event that should trigger the removal of a tooltip (can be an event or an array of events)</dd>
  10039. * <dt>styles</dt><dd>A hash of style properties that will be applied to the tooltip node</dd>
  10040. * <dt>show</dt><dd>Indicates whether or not to show the tooltip</dd>
  10041. * <dt>markerEventHandler</dt><dd>Displays and hides tooltip based on marker events</dd>
  10042. * <dt>planarEventHandler</dt><dd>Displays and hides tooltip based on planar events</dd>
  10043. * <dt>markerLabelFunction</dt><dd>Reference to the function used to format a marker event triggered tooltip's text</dd>
  10044. * <dt>planarLabelFunction</dt><dd>Reference to the function used to format a planar event triggered tooltip's text</dd>
  10045. * </dl>
  10046. * @attribute tooltip
  10047. * @type Object
  10048. */
  10049. tooltip: {
  10050. valueFn: "_getTooltip",
  10051. setter: function(val)
  10052. {
  10053. return this._updateTooltip(val);
  10054. }
  10055. },
  10056. /**
  10057. * The key value used for the chart's category axis.
  10058. *
  10059. * @attribute categoryKey
  10060. * @type String
  10061. * @default category
  10062. */
  10063. categoryKey: {
  10064. value: "category"
  10065. },
  10066. /**
  10067. * Indicates the type of axis to use for the category axis.
  10068. *
  10069. * <dl>
  10070. * <dt>category</dt><dd>Specifies a `CategoryAxis`.</dd>
  10071. * <dt>time</dt><dd>Specifies a `TimeAxis</dd>
  10072. * </dl>
  10073. *
  10074. * @attribute categoryType
  10075. * @type String
  10076. * @default category
  10077. */
  10078. categoryType:{
  10079. value:"category"
  10080. },
  10081. /**
  10082. * Indicates the the type of interactions that will fire events.
  10083. *
  10084. * <dl>
  10085. * <dt>marker</dt><dd>Events will be broadcasted when the mouse interacts with individual markers.</dd>
  10086. * <dt>planar</dt><dd>Events will be broadcasted when the mouse intersects the plane of any markers on the chart.</dd>
  10087. * <dt>none</dt><dd>No events will be broadcasted.</dd>
  10088. * </dl>
  10089. *
  10090. * @attribute interactionType
  10091. * @type String
  10092. * @default marker
  10093. */
  10094. interactionType: {
  10095. value: "marker"
  10096. },
  10097. /**
  10098. * Data used to generate the chart.
  10099. *
  10100. * @attribute dataProvider
  10101. * @type Array
  10102. */
  10103. dataProvider: {
  10104. setter: function(val)
  10105. {
  10106. return this._setDataValues(val);
  10107. }
  10108. },
  10109. /**
  10110. * A collection of keys that map to the series axes. If no keys are set,
  10111. * they will be generated automatically depending on the data structure passed into
  10112. * the chart.
  10113. *
  10114. * @attribute seriesKeys
  10115. * @type Array
  10116. */
  10117. seriesKeys: {},
  10118. /**
  10119. * Reference to all the axes in the chart.
  10120. *
  10121. * @attribute axesCollection
  10122. * @type Array
  10123. */
  10124. axesCollection: {},
  10125. /**
  10126. * Reference to graph instance.
  10127. *
  10128. * @attribute graph
  10129. * @type Graph
  10130. */
  10131. graph: {
  10132. valueFn: "_getGraph"
  10133. }
  10134. };
  10135. ChartBase.prototype = {
  10136. /**
  10137. * Default value function for the `Graph` attribute.
  10138. *
  10139. * @method _getGraph
  10140. * @return Graph
  10141. * @private
  10142. */
  10143. _getGraph: function()
  10144. {
  10145. var graph = new Y.Graph({chart:this});
  10146. graph.after("chartRendered", Y.bind(function(e) {
  10147. this.fire("chartRendered");
  10148. }, this));
  10149. return graph;
  10150. },
  10151. /**
  10152. * Returns a series instance by index or key value.
  10153. *
  10154. * @method getSeries
  10155. * @param val
  10156. * @return CartesianSeries
  10157. */
  10158. getSeries: function(val)
  10159. {
  10160. var series = null,
  10161. graph = this.get("graph");
  10162. if(graph)
  10163. {
  10164. if(Y_Lang.isNumber(val))
  10165. {
  10166. series = graph.getSeriesByIndex(val);
  10167. }
  10168. else
  10169. {
  10170. series = graph.getSeriesByKey(val);
  10171. }
  10172. }
  10173. return series;
  10174. },
  10175. /**
  10176. * Returns an `Axis` instance by key reference. If the axis was explicitly set through the `axes` attribute,
  10177. * the key will be the same as the key used in the `axes` object. For default axes, the key for
  10178. * the category axis is the value of the `categoryKey` (`category`). For the value axis, the default
  10179. * key is `values`.
  10180. *
  10181. * @method getAxisByKey
  10182. * @param {String} val Key reference used to look up the axis.
  10183. * @return Axis
  10184. */
  10185. getAxisByKey: function(val)
  10186. {
  10187. var axis,
  10188. axes = this.get("axes");
  10189. if(axes.hasOwnProperty(val))
  10190. {
  10191. axis = axes[val];
  10192. }
  10193. return axis;
  10194. },
  10195. /**
  10196. * Returns the category axis for the chart.
  10197. *
  10198. * @method getCategoryAxis
  10199. * @return Axis
  10200. */
  10201. getCategoryAxis: function()
  10202. {
  10203. var axis,
  10204. key = this.get("categoryKey"),
  10205. axes = this.get("axes");
  10206. if(axes.hasOwnProperty(key))
  10207. {
  10208. axis = axes[key];
  10209. }
  10210. return axis;
  10211. },
  10212. /**
  10213. * Default direction of the chart.
  10214. *
  10215. * @property _direction
  10216. * @type String
  10217. * @default horizontal
  10218. * @private
  10219. */
  10220. _direction: "horizontal",
  10221. /**
  10222. * Storage for the `dataProvider` attribute.
  10223. *
  10224. * @property _dataProvider
  10225. * @type Array
  10226. * @private
  10227. */
  10228. _dataProvider: null,
  10229. /**
  10230. * Setter method for `dataProvider` attribute.
  10231. *
  10232. * @method _setDataValues
  10233. * @param {Array} val Array to be set as `dataProvider`.
  10234. * @return Array
  10235. * @private
  10236. */
  10237. _setDataValues: function(val)
  10238. {
  10239. if(Y_Lang.isArray(val[0]))
  10240. {
  10241. var hash,
  10242. dp = [],
  10243. cats = val[0],
  10244. i = 0,
  10245. l = cats.length,
  10246. n,
  10247. sl = val.length;
  10248. for(; i < l; ++i)
  10249. {
  10250. hash = {category:cats[i]};
  10251. for(n = 1; n < sl; ++n)
  10252. {
  10253. hash["series" + n] = val[n][i];
  10254. }
  10255. dp[i] = hash;
  10256. }
  10257. return dp;
  10258. }
  10259. return val;
  10260. },
  10261. /**
  10262. * Storage for `seriesCollection` attribute.
  10263. *
  10264. * @property _seriesCollection
  10265. * @type Array
  10266. * @private
  10267. */
  10268. _seriesCollection: null,
  10269. /**
  10270. * Setter method for `seriesCollection` attribute.
  10271. *
  10272. * @property _setSeriesCollection
  10273. * @param {Array} val Array of either `CartesianSeries` instances or objects containing series attribute key value pairs.
  10274. * @private
  10275. */
  10276. _setSeriesCollection: function(val)
  10277. {
  10278. this._seriesCollection = val;
  10279. },
  10280. /**
  10281. * Helper method that returns the axis class that a key references.
  10282. *
  10283. * @method _getAxisClass
  10284. * @param {String} t The type of axis.
  10285. * @return Axis
  10286. * @private
  10287. */
  10288. _getAxisClass: function(t)
  10289. {
  10290. return this._axisClass[t];
  10291. },
  10292. /**
  10293. * Key value pairs of axis types.
  10294. *
  10295. * @property _axisClass
  10296. * @type Object
  10297. * @private
  10298. */
  10299. _axisClass: {
  10300. stacked: Y.StackedAxis,
  10301. numeric: Y.NumericAxis,
  10302. category: Y.CategoryAxis,
  10303. time: Y.TimeAxis
  10304. },
  10305. /**
  10306. * Collection of axes.
  10307. *
  10308. * @property _axes
  10309. * @type Array
  10310. * @private
  10311. */
  10312. _axes: null,
  10313. /**
  10314. * @method renderUI
  10315. * @private
  10316. */
  10317. renderUI: function()
  10318. {
  10319. var tt = this.get("tooltip");
  10320. //move the position = absolute logic to a class file
  10321. this.get("boundingBox").setStyle("position", "absolute");
  10322. this.get("contentBox").setStyle("position", "absolute");
  10323. this._addAxes();
  10324. this._addSeries();
  10325. if(tt && tt.show)
  10326. {
  10327. this._addTooltip();
  10328. }
  10329. this._redraw();
  10330. },
  10331. /**
  10332. * @property bindUI
  10333. * @private
  10334. */
  10335. bindUI: function()
  10336. {
  10337. this.after("tooltipChange", Y.bind(this._tooltipChangeHandler, this));
  10338. this.after("widthChange", this._sizeChanged);
  10339. this.after("heightChange", this._sizeChanged);
  10340. this.after("dataProviderChange", this._dataProviderChangeHandler);
  10341. var tt = this.get("tooltip"),
  10342. hideEvent = "mouseout",
  10343. showEvent = "mouseover",
  10344. cb = this.get("contentBox"),
  10345. interactionType = this.get("interactionType"),
  10346. i = 0,
  10347. len,
  10348. markerClassName = "." + SERIES_MARKER;
  10349. if(interactionType == "marker")
  10350. {
  10351. hideEvent = tt.hideEvent;
  10352. showEvent = tt.showEvent;
  10353. Y.delegate("mouseenter", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
  10354. Y.delegate("mousedown", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
  10355. Y.delegate("mouseup", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
  10356. Y.delegate("mouseleave", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
  10357. Y.delegate("click", Y.bind(this._markerEventDispatcher, this), cb, markerClassName);
  10358. Y.delegate("mousemove", Y.bind(this._positionTooltip, this), cb, markerClassName);
  10359. }
  10360. else if(interactionType == "planar")
  10361. {
  10362. this._overlay.on("mousemove", Y.bind(this._planarEventDispatcher, this));
  10363. this.on("mouseout", this.hideTooltip);
  10364. }
  10365. if(tt)
  10366. {
  10367. if(hideEvent && showEvent && hideEvent == showEvent)
  10368. {
  10369. this.on(interactionType + "Event:" + hideEvent, this.toggleTooltip);
  10370. }
  10371. else
  10372. {
  10373. if(showEvent)
  10374. {
  10375. this.on(interactionType + "Event:" + showEvent, tt[interactionType + "EventHandler"]);
  10376. }
  10377. if(hideEvent)
  10378. {
  10379. if(Y_Lang.isArray(hideEvent))
  10380. {
  10381. len = hideEvent.length;
  10382. for(; i < len; ++i)
  10383. {
  10384. this.on(interactionType + "Event:" + hideEvent[i], this.hideTooltip);
  10385. }
  10386. }
  10387. this.on(interactionType + "Event:" + hideEvent, this.hideTooltip);
  10388. }
  10389. }
  10390. }
  10391. },
  10392. /**
  10393. * Event handler for marker events.
  10394. *
  10395. * @method _markerEventDispatcher
  10396. * @param {Object} e Event object.
  10397. * @private
  10398. */
  10399. _markerEventDispatcher: function(e)
  10400. {
  10401. var type = e.type,
  10402. cb = this.get("contentBox"),
  10403. markerNode = e.currentTarget,
  10404. strArr = markerNode.getAttribute("id").split("_"),
  10405. index = strArr.pop(),
  10406. seriesIndex = strArr.pop(),
  10407. series = this.getSeries(parseInt(seriesIndex, 10)),
  10408. items = this.getSeriesItems(series, index),
  10409. pageX = e.pageX,
  10410. pageY = e.pageY,
  10411. x = pageX - cb.getX(),
  10412. y = pageY - cb.getY();
  10413. if(type == "mouseenter")
  10414. {
  10415. type = "mouseover";
  10416. }
  10417. else if(type == "mouseleave")
  10418. {
  10419. type = "mouseout";
  10420. }
  10421. series.updateMarkerState(type, index);
  10422. e.halt();
  10423. /**
  10424. * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseover event.
  10425. *
  10426. *
  10427. * @event markerEvent:mouseover
  10428. * @preventable false
  10429. * @param {EventFacade} e Event facade with the following additional
  10430. * properties:
  10431. * <dl>
  10432. * <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
  10433. * <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
  10434. * <dt>node</dt><dd>The dom node of the marker.</dd>
  10435. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10436. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  10437. * <dt>series</dt><dd>Reference to the series of the marker.</dd>
  10438. * <dt>index</dt><dd>Index of the marker in the series.</dd>
  10439. * <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
  10440. * </dl>
  10441. */
  10442. /**
  10443. * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseout event.
  10444. *
  10445. * @event markerEvent:mouseout
  10446. * @preventable false
  10447. * @param {EventFacade} e Event facade with the following additional
  10448. * properties:
  10449. * <dl>
  10450. * <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
  10451. * <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
  10452. * <dt>node</dt><dd>The dom node of the marker.</dd>
  10453. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10454. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  10455. * <dt>series</dt><dd>Reference to the series of the marker.</dd>
  10456. * <dt>index</dt><dd>Index of the marker in the series.</dd>
  10457. * <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
  10458. * </dl>
  10459. */
  10460. /**
  10461. * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mousedown event.
  10462. *
  10463. * @event markerEvent:mousedown
  10464. * @preventable false
  10465. * @param {EventFacade} e Event facade with the following additional
  10466. * properties:
  10467. * <dl>
  10468. * <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
  10469. * <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
  10470. * <dt>node</dt><dd>The dom node of the marker.</dd>
  10471. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10472. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  10473. * <dt>series</dt><dd>Reference to the series of the marker.</dd>
  10474. * <dt>index</dt><dd>Index of the marker in the series.</dd>
  10475. * <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
  10476. * </dl>
  10477. */
  10478. /**
  10479. * Broadcasts when `interactionType` is set to `marker` and a series marker has received a mouseup event.
  10480. *
  10481. * @event markerEvent:mouseup
  10482. * @preventable false
  10483. * @param {EventFacade} e Event facade with the following additional
  10484. * properties:
  10485. * <dl>
  10486. * <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
  10487. * <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
  10488. * <dt>node</dt><dd>The dom node of the marker.</dd>
  10489. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10490. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  10491. * <dt>series</dt><dd>Reference to the series of the marker.</dd>
  10492. * <dt>index</dt><dd>Index of the marker in the series.</dd>
  10493. * <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
  10494. * </dl>
  10495. */
  10496. /**
  10497. * Broadcasts when `interactionType` is set to `marker` and a series marker has received a click event.
  10498. *
  10499. * @event markerEvent:click
  10500. * @preventable false
  10501. * @param {EventFacade} e Event facade with the following additional
  10502. * properties:
  10503. * <dl>
  10504. * <dt>categoryItem</dt><dd>Hash containing information about the category `Axis`.</dd>
  10505. * <dt>valueItem</dt><dd>Hash containing information about the value `Axis`.</dd>
  10506. * <dt>node</dt><dd>The dom node of the marker.</dd>
  10507. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10508. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  10509. * <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd>
  10510. * <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd>
  10511. * <dt>series</dt><dd>Reference to the series of the marker.</dd>
  10512. * <dt>index</dt><dd>Index of the marker in the series.</dd>
  10513. * <dt>seriesIndex</dt><dd>The `order` of the marker's series.</dd>
  10514. * <dt>originEvent</dt><dd>Underlying dom event.</dd>
  10515. * </dl>
  10516. */
  10517. this.fire("markerEvent:" + type, {
  10518. originEvent: e,
  10519. pageX:pageX,
  10520. pageY:pageY,
  10521. categoryItem:items.category,
  10522. valueItem:items.value,
  10523. node:markerNode,
  10524. x:x,
  10525. y:y,
  10526. series:series,
  10527. index:index,
  10528. seriesIndex:seriesIndex
  10529. });
  10530. },
  10531. /**
  10532. * Event handler for dataProviderChange.
  10533. *
  10534. * @method _dataProviderChangeHandler
  10535. * @param {Object} e Event object.
  10536. * @private
  10537. */
  10538. _dataProviderChangeHandler: function(e)
  10539. {
  10540. var dataProvider = this.get("dataProvider"),
  10541. axes = this.get("axes"),
  10542. i,
  10543. axis;
  10544. for(i in axes)
  10545. {
  10546. if(axes.hasOwnProperty(i))
  10547. {
  10548. axis = axes[i];
  10549. if(axis instanceof Y.Axis)
  10550. {
  10551. axis.set("dataProvider", dataProvider);
  10552. }
  10553. }
  10554. }
  10555. },
  10556. /**
  10557. * Event listener for toggling the tooltip. If a tooltip is visible, hide it. If not, it
  10558. * will create and show a tooltip based on the event object.
  10559. *
  10560. * @method toggleTooltip
  10561. * @param {Object} e Event object.
  10562. */
  10563. toggleTooltip: function(e)
  10564. {
  10565. var tt = this.get("tooltip");
  10566. if(tt.visible)
  10567. {
  10568. this.hideTooltip();
  10569. }
  10570. else
  10571. {
  10572. tt.markerEventHandler.apply(this, [e]);
  10573. }
  10574. },
  10575. /**
  10576. * Shows a tooltip
  10577. *
  10578. * @method _showTooltip
  10579. * @param {String} msg Message to dispaly in the tooltip.
  10580. * @param {Number} x x-coordinate
  10581. * @param {Number} y y-coordinate
  10582. * @private
  10583. */
  10584. _showTooltip: function(msg, x, y)
  10585. {
  10586. var tt = this.get("tooltip"),
  10587. node = tt.node;
  10588. if(msg)
  10589. {
  10590. tt.visible = true;
  10591. node.set("innerHTML", msg);
  10592. node.setStyle("top", y + "px");
  10593. node.setStyle("left", x + "px");
  10594. node.setStyle("visibility", "visible");
  10595. }
  10596. },
  10597. /**
  10598. * Positions the tooltip
  10599. *
  10600. * @method _positionTooltip
  10601. * @param {Object} e Event object.
  10602. * @private
  10603. */
  10604. _positionTooltip: function(e)
  10605. {
  10606. var tt = this.get("tooltip"),
  10607. node = tt.node,
  10608. cb = this.get("contentBox"),
  10609. x = (e.pageX + 10) - cb.getX(),
  10610. y = (e.pageY + 10) - cb.getY();
  10611. if(node)
  10612. {
  10613. node.setStyle("left", x + "px");
  10614. node.setStyle("top", y + "px");
  10615. }
  10616. },
  10617. /**
  10618. * Hides the default tooltip
  10619. *
  10620. * @method hideTooltip
  10621. */
  10622. hideTooltip: function()
  10623. {
  10624. var tt = this.get("tooltip"),
  10625. node = tt.node;
  10626. tt.visible = false;
  10627. node.set("innerHTML", "");
  10628. node.setStyle("left", -10000);
  10629. node.setStyle("top", -10000);
  10630. node.setStyle("visibility", "hidden");
  10631. },
  10632. /**
  10633. * Adds a tooltip to the dom.
  10634. *
  10635. * @method _addTooltip
  10636. * @private
  10637. */
  10638. _addTooltip: function()
  10639. {
  10640. var tt = this.get("tooltip"),
  10641. id = this.get("id") + "_tooltip",
  10642. cb = this.get("contentBox"),
  10643. oldNode = DOCUMENT.getElementById(id);
  10644. if(oldNode)
  10645. {
  10646. cb.removeChild(oldNode);
  10647. }
  10648. tt.node.setAttribute("id", id);
  10649. tt.node.setStyle("visibility", "hidden");
  10650. cb.appendChild(tt.node);
  10651. },
  10652. /**
  10653. * Updates the tooltip attribute.
  10654. *
  10655. * @method _updateTooltip
  10656. * @param {Object} val Object containing properties for the tooltip.
  10657. * @return Object
  10658. * @private
  10659. */
  10660. _updateTooltip: function(val)
  10661. {
  10662. var tt = this._tooltip,
  10663. i,
  10664. styles,
  10665. node,
  10666. props = {
  10667. markerLabelFunction:"markerLabelFunction",
  10668. planarLabelFunction:"planarLabelFunction",
  10669. showEvent:"showEvent",
  10670. hideEvent:"hideEvent",
  10671. markerEventHandler:"markerEventHandler",
  10672. planarEventHandler:"planarEventHandler",
  10673. show:"show"
  10674. };
  10675. if(Y_Lang.isObject(val))
  10676. {
  10677. styles = val.styles;
  10678. node = Y.one(val.node) || tt.node;
  10679. if(styles)
  10680. {
  10681. for(i in styles)
  10682. {
  10683. if(styles.hasOwnProperty(i))
  10684. {
  10685. node.setStyle(i, styles[i]);
  10686. }
  10687. }
  10688. }
  10689. for(i in props)
  10690. {
  10691. if(val.hasOwnProperty(i))
  10692. {
  10693. tt[i] = val[i];
  10694. }
  10695. }
  10696. tt.node = node;
  10697. }
  10698. return tt;
  10699. },
  10700. /**
  10701. * Default getter for `tooltip` attribute.
  10702. *
  10703. * @method _getTooltip
  10704. * @return Object
  10705. * @private
  10706. */
  10707. _getTooltip: function()
  10708. {
  10709. var node = DOCUMENT.createElement("div"),
  10710. tt = {
  10711. markerLabelFunction: this._tooltipLabelFunction,
  10712. planarLabelFunction: this._planarLabelFunction,
  10713. show: true,
  10714. hideEvent: "mouseout",
  10715. showEvent: "mouseover",
  10716. markerEventHandler: function(e)
  10717. {
  10718. var tt = this.get("tooltip"),
  10719. msg = tt.markerLabelFunction.apply(this, [e.categoryItem, e.valueItem, e.index, e.series, e.seriesIndex]);
  10720. this._showTooltip(msg, e.x + 10, e.y + 10);
  10721. },
  10722. planarEventHandler: function(e)
  10723. {
  10724. var tt = this.get("tooltip"),
  10725. msg ,
  10726. categoryAxis = this.get("categoryAxis");
  10727. msg = tt.planarLabelFunction.apply(this, [categoryAxis, e.valueItem, e.index, e.items, e.seriesIndex]);
  10728. this._showTooltip(msg, e.x + 10, e.y + 10);
  10729. }
  10730. };
  10731. node.setAttribute("id", this.get("id") + "_tooltip");
  10732. node = Y.one(node);
  10733. node.setStyle("fontSize", "85%");
  10734. node.setStyle("opacity", "0.83");
  10735. node.setStyle("position", "absolute");
  10736. node.setStyle("paddingTop", "2px");
  10737. node.setStyle("paddingRight", "5px");
  10738. node.setStyle("paddingBottom", "4px");
  10739. node.setStyle("paddingLeft", "2px");
  10740. node.setStyle("backgroundColor", "#fff");
  10741. node.setStyle("border", "1px solid #dbdccc");
  10742. node.setStyle("pointerEvents", "none");
  10743. node.setStyle("zIndex", 3);
  10744. node.setStyle("whiteSpace", "noWrap");
  10745. node.setStyle("visibility", "hidden");
  10746. tt.node = Y.one(node);
  10747. this._tooltip = tt;
  10748. return tt;
  10749. },
  10750. /**
  10751. * Formats tooltip text when `interactionType` is `planar`.
  10752. *
  10753. * @method _planarLabelFunction
  10754. * @param {Axis} categoryAxis Reference to the categoryAxis of the chart.
  10755. * @param {Array} valueItems Array of objects for each series that has a data point in the coordinate plane of the event. Each object contains the following data:
  10756. * <dl>
  10757. * <dt>axis</dt><dd>The value axis of the series.</dd>
  10758. * <dt>key</dt><dd>The key for the series.</dd>
  10759. * <dt>value</dt><dd>The value for the series item.</dd>
  10760. * <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
  10761. * </dl>
  10762. * @param {Number} index The index of the item within its series.
  10763. * @param {Array} seriesArray Array of series instances for each value item.
  10764. * @param {Number} seriesIndex The index of the series in the `seriesCollection`.
  10765. * @private
  10766. */
  10767. _planarLabelFunction: function(categoryAxis, valueItems, index, seriesArray, seriesIndex)
  10768. {
  10769. var msg = "",
  10770. valueItem,
  10771. i = 0,
  10772. len = seriesArray.length,
  10773. axis,
  10774. series;
  10775. if(categoryAxis)
  10776. {
  10777. msg += categoryAxis.get("labelFunction").apply(this, [categoryAxis.getKeyValueAt(this.get("categoryKey"), index), categoryAxis.get("labelFormat")]);
  10778. }
  10779. for(; i < len; ++i)
  10780. {
  10781. series = seriesArray[i];
  10782. if(series.get("visible"))
  10783. {
  10784. valueItem = valueItems[i];
  10785. axis = valueItem.axis;
  10786. msg += "<br/><span>" + valueItem.displayName + ": " + axis.get("labelFunction").apply(this, [axis.getKeyValueAt(valueItem.key, index), axis.get("labelFormat")]) + "</span>";
  10787. }
  10788. }
  10789. return msg;
  10790. },
  10791. /**
  10792. * Formats tooltip text when `interactionType` is `marker`.
  10793. *
  10794. * @method _tooltipLabelFunction
  10795. * @param {Object} categoryItem An object containing the following:
  10796. * <dl>
  10797. * <dt>axis</dt><dd>The axis to which the category is bound.</dd>
  10798. * <dt>displayName</dt><dd>The display name set to the category (defaults to key if not provided)</dd>
  10799. * <dt>key</dt><dd>The key of the category.</dd>
  10800. * <dt>value</dt><dd>The value of the category</dd>
  10801. * </dl>
  10802. * @param {Object} valueItem An object containing the following:
  10803. * <dl>
  10804. * <dt>axis</dt><dd>The axis to which the item's series is bound.</dd>
  10805. * <dt>displayName</dt><dd>The display name of the series. (defaults to key if not provided)</dd>
  10806. * <dt>key</dt><dd>The key for the series.</dd>
  10807. * <dt>value</dt><dd>The value for the series item.</dd>
  10808. * </dl>
  10809. * @param {Number} itemIndex The index of the item within the series.
  10810. * @param {CartesianSeries} series The `CartesianSeries` instance of the item.
  10811. * @param {Number} seriesIndex The index of the series in the `seriesCollection`.
  10812. * @private
  10813. */
  10814. _tooltipLabelFunction: function(categoryItem, valueItem, itemIndex, series, seriesIndex)
  10815. {
  10816. var msg = categoryItem.displayName +
  10817. ":&nbsp;" + categoryItem.axis.get("labelFunction").apply(this, [categoryItem.value, categoryItem.axis.get("labelFormat")]) +
  10818. "<br/>" + valueItem.displayName +
  10819. ":&nbsp;" + valueItem.axis.get("labelFunction").apply(this, [valueItem.value, valueItem.axis.get("labelFormat")]);
  10820. return msg;
  10821. },
  10822. /**
  10823. * Event handler for the tooltipChange.
  10824. *
  10825. * @method _tooltipChangeHandler
  10826. * @param {Object} e Event object.
  10827. * @private
  10828. */
  10829. _tooltipChangeHandler: function(e)
  10830. {
  10831. if(this.get("tooltip"))
  10832. {
  10833. var tt = this.get("tooltip"),
  10834. node = tt.node,
  10835. show = tt.show,
  10836. cb = this.get("contentBox");
  10837. if(node && show)
  10838. {
  10839. if(!cb.contains(node))
  10840. {
  10841. this._addTooltip();
  10842. }
  10843. }
  10844. }
  10845. }
  10846. };
  10847. Y.ChartBase = ChartBase;
  10848. /**
  10849. * The CartesianChart class creates a chart with horizontal and vertical axes.
  10850. *
  10851. * @module charts
  10852. * @class CartesianChart
  10853. * @extends ChartBase
  10854. * @constructor
  10855. */
  10856. Y.CartesianChart = Y.Base.create("cartesianChart", Y.Widget, [Y.ChartBase], {
  10857. /**
  10858. * @method renderUI
  10859. * @private
  10860. */
  10861. renderUI: function()
  10862. {
  10863. var tt = this.get("tooltip"),
  10864. overlay,
  10865. overlayClass = _getClassName("overlay");
  10866. //move the position = absolute logic to a class file
  10867. this.get("boundingBox").setStyle("position", "absolute");
  10868. this.get("contentBox").setStyle("position", "absolute");
  10869. this._addAxes();
  10870. this._addGridlines();
  10871. this._addSeries();
  10872. if(tt && tt.show)
  10873. {
  10874. this._addTooltip();
  10875. }
  10876. //If there is a style definition. Force them to set.
  10877. this.get("styles");
  10878. if(this.get("interactionType") == "planar")
  10879. {
  10880. overlay = DOCUMENT.createElement("div");
  10881. this.get("contentBox").appendChild(overlay);
  10882. this._overlay = Y.one(overlay);
  10883. this._overlay.setStyle("position", "absolute");
  10884. this._overlay.setStyle("background", "#fff");
  10885. this._overlay.setStyle("opacity", 0);
  10886. this._overlay.addClass(overlayClass);
  10887. this._overlay.setStyle("zIndex", 4);
  10888. }
  10889. this._redraw();
  10890. },
  10891. /**
  10892. * When `interactionType` is set to `planar`, listens for mouse move events and fires `planarEvent:mouseover` or `planarEvent:mouseout` depending on the position of the mouse in relation to
  10893. * data points on the `Chart`.
  10894. *
  10895. * @method _planarEventDispatcher
  10896. * @param {Object} e Event object.
  10897. * @private
  10898. */
  10899. _planarEventDispatcher: function(e)
  10900. {
  10901. var graph = this.get("graph"),
  10902. bb = this.get("boundingBox"),
  10903. cb = graph.get("contentBox"),
  10904. pageX = e.pageX,
  10905. pageY = e.pageY,
  10906. posX = pageX - bb.getX(),
  10907. posY = pageY - bb.getY(),
  10908. offset = {
  10909. x: pageX - cb.getX(),
  10910. y: pageY - cb.getY()
  10911. },
  10912. sc = graph.get("seriesCollection"),
  10913. series,
  10914. i = 0,
  10915. index,
  10916. oldIndex = this._selectedIndex,
  10917. item,
  10918. items = [],
  10919. categoryItems = [],
  10920. valueItems = [],
  10921. direction = this.get("direction"),
  10922. hasMarkers,
  10923. catAxis,
  10924. valAxis,
  10925. coord,
  10926. //data columns and area data could be created on a graph level
  10927. markerPlane,
  10928. len,
  10929. coords;
  10930. if(direction == "horizontal")
  10931. {
  10932. catAxis = "x";
  10933. valAxis = "y";
  10934. }
  10935. else
  10936. {
  10937. valAxis = "x";
  10938. catAxis = "y";
  10939. }
  10940. coord = offset[catAxis];
  10941. if(sc)
  10942. {
  10943. len = sc.length;
  10944. while(i < len && !markerPlane)
  10945. {
  10946. if(sc[i])
  10947. {
  10948. markerPlane = sc[i].get(catAxis + "MarkerPlane");
  10949. }
  10950. i++;
  10951. }
  10952. }
  10953. if(markerPlane)
  10954. {
  10955. len = markerPlane.length;
  10956. for(i = 0; i < len; ++i)
  10957. {
  10958. if(coord <= markerPlane[i].end && coord >= markerPlane[i].start)
  10959. {
  10960. index = i;
  10961. break;
  10962. }
  10963. }
  10964. len = sc.length;
  10965. for(i = 0; i < len; ++i)
  10966. {
  10967. series = sc[i];
  10968. coords = series.get(valAxis + "coords");
  10969. hasMarkers = series.get("markers");
  10970. if(hasMarkers && !isNaN(oldIndex) && oldIndex > -1)
  10971. {
  10972. series.updateMarkerState("mouseout", oldIndex);
  10973. }
  10974. if(coords && coords[index] > -1)
  10975. {
  10976. if(hasMarkers && !isNaN(index) && index > -1)
  10977. {
  10978. series.updateMarkerState("mouseover", index);
  10979. }
  10980. item = this.getSeriesItems(series, index);
  10981. categoryItems.push(item.category);
  10982. valueItems.push(item.value);
  10983. items.push(series);
  10984. }
  10985. }
  10986. this._selectedIndex = index;
  10987. /**
  10988. * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseover event.
  10989. *
  10990. *
  10991. * @event planarEvent:mouseover
  10992. * @preventable false
  10993. * @param {EventFacade} e Event facade with the following additional
  10994. * properties:
  10995. * <dl>
  10996. * <dt>categoryItem</dt><dd>An array of hashes, each containing information about the category `Axis` of each marker whose plane has been intersected.</dd>
  10997. * <dt>valueItem</dt><dd>An array of hashes, each containing information about the value `Axis` of each marker whose plane has been intersected.</dd>
  10998. * <dt>x</dt><dd>The x-coordinate of the mouse in relation to the Chart.</dd>
  10999. * <dt>y</dt><dd>The y-coordinate of the mouse in relation to the Chart.</dd>
  11000. * <dt>pageX</dt><dd>The x location of the event on the page (including scroll)</dd>
  11001. * <dt>pageY</dt><dd>The y location of the event on the page (including scroll)</dd>
  11002. * <dt>items</dt><dd>An array including all the series which contain a marker whose plane has been intersected.</dd>
  11003. * <dt>index</dt><dd>Index of the markers in their respective series.</dd>
  11004. * <dt>originEvent</dt><dd>Underlying dom event.</dd>
  11005. * </dl>
  11006. */
  11007. /**
  11008. * Broadcasts when `interactionType` is set to `planar` and a series' marker plane has received a mouseout event.
  11009. *
  11010. * @event planarEvent:mouseout
  11011. * @preventable false
  11012. * @param {EventFacade} e
  11013. */
  11014. if(index > -1)
  11015. {
  11016. this.fire("planarEvent:mouseover", {
  11017. categoryItem:categoryItems,
  11018. valueItem:valueItems,
  11019. x:posX,
  11020. y:posY,
  11021. pageX:pageX,
  11022. pageY:pageY,
  11023. items:items,
  11024. index:index,
  11025. originEvent:e
  11026. });
  11027. }
  11028. else
  11029. {
  11030. this.fire("planarEvent:mouseout");
  11031. }
  11032. }
  11033. },
  11034. /**
  11035. * Indicates the default series type for the chart.
  11036. *
  11037. * @property _type
  11038. * @type {String}
  11039. * @private
  11040. */
  11041. _type: "combo",
  11042. /**
  11043. * Queue of axes instances that will be updated. This method is used internally to determine when all axes have been updated.
  11044. *
  11045. * @property _axesRenderQueue
  11046. * @type Array
  11047. * @private
  11048. */
  11049. _axesRenderQueue: null,
  11050. /**
  11051. * Adds an `Axis` instance to the `_axesRenderQueue`.
  11052. *
  11053. * @method _addToAxesRenderQueue
  11054. * @param {Axis} axis An `Axis` instance.
  11055. * @private
  11056. */
  11057. _addToAxesRenderQueue: function(axis)
  11058. {
  11059. if(!this._axesRenderQueue)
  11060. {
  11061. this._axesRenderQueue = [];
  11062. }
  11063. if(Y.Array.indexOf(this._axesRenderQueue, axis) < 0)
  11064. {
  11065. this._axesRenderQueue.push(axis);
  11066. }
  11067. },
  11068. /**
  11069. * Returns the default value for the `seriesCollection` attribute.
  11070. *
  11071. * @method _getDefaultSeriesCollection
  11072. * @param {Array} val Array containing either `CartesianSeries` instances or objects containing data to construct series instances.
  11073. * @return Array
  11074. * @private
  11075. */
  11076. _getDefaultSeriesCollection: function(val)
  11077. {
  11078. var dir = this.get("direction"),
  11079. sc = val || [],
  11080. catAxis,
  11081. valAxis,
  11082. tempKeys = [],
  11083. series,
  11084. seriesKeys = this.get("seriesKeys").concat(),
  11085. i,
  11086. index,
  11087. l,
  11088. type = this.get("type"),
  11089. key,
  11090. catKey,
  11091. seriesKey,
  11092. graph,
  11093. categoryKey = this.get("categoryKey"),
  11094. showMarkers = this.get("showMarkers"),
  11095. showAreaFill = this.get("showAreaFill"),
  11096. showLines = this.get("showLines");
  11097. if(dir == "vertical")
  11098. {
  11099. catAxis = "yAxis";
  11100. catKey = "yKey";
  11101. valAxis = "xAxis";
  11102. seriesKey = "xKey";
  11103. }
  11104. else
  11105. {
  11106. catAxis = "xAxis";
  11107. catKey = "xKey";
  11108. valAxis = "yAxis";
  11109. seriesKey = "yKey";
  11110. }
  11111. l = sc.length;
  11112. for(i = 0; i < l; ++i)
  11113. {
  11114. key = this._getBaseAttribute(sc[i], seriesKey);
  11115. if(key)
  11116. {
  11117. index = Y.Array.indexOf(seriesKeys, key);
  11118. if(index > -1)
  11119. {
  11120. seriesKeys.splice(index, 1);
  11121. }
  11122. tempKeys.push(key);
  11123. }
  11124. }
  11125. if(seriesKeys.length > 0)
  11126. {
  11127. tempKeys = tempKeys.concat(seriesKeys);
  11128. }
  11129. l = tempKeys.length;
  11130. for(i = 0; i < l; ++i)
  11131. {
  11132. series = sc[i] || {type:type};
  11133. if(series instanceof Y.CartesianSeries)
  11134. {
  11135. this._parseSeriesAxes(series);
  11136. continue;
  11137. }
  11138. series[catKey] = series[catKey] || categoryKey;
  11139. series[seriesKey] = series[seriesKey] || seriesKeys.shift();
  11140. series[catAxis] = this._getCategoryAxis();
  11141. series[valAxis] = this._getSeriesAxis(series[seriesKey]);
  11142. series.type = series.type || type;
  11143. if((series.type == "combo" || series.type == "stackedcombo" || series.type == "combospline" || series.type == "stackedcombospline"))
  11144. {
  11145. if(showAreaFill !== null)
  11146. {
  11147. series.showAreaFill = (series.showAreaFill !== null && series.showAreaFill !== undefined) ? series.showAreaFill : showAreaFill;
  11148. }
  11149. if(showMarkers !== null)
  11150. {
  11151. series.showMarkers = (series.showMarkers !== null && series.showMarkers !== undefined) ? series.showMarkers : showMarkers;
  11152. }
  11153. if(showLines !== null)
  11154. {
  11155. series.showLines = (series.showLines !== null && series.showLines !== undefined) ? series.showLines : showLines;
  11156. }
  11157. }
  11158. sc[i] = series;
  11159. }
  11160. if(val)
  11161. {
  11162. graph = this.get("graph");
  11163. graph.set("seriesCollection", sc);
  11164. sc = graph.get("seriesCollection");
  11165. }
  11166. return sc;
  11167. },
  11168. /**
  11169. * Parse and sets the axes for a series instance.
  11170. *
  11171. * @method _parseSeriesAxes
  11172. * @param {CartesianSeries} series A `CartesianSeries` instance.
  11173. * @private
  11174. */
  11175. _parseSeriesAxes: function(series)
  11176. {
  11177. var axes = this.get("axes"),
  11178. xAxis = series.get("xAxis"),
  11179. yAxis = series.get("yAxis"),
  11180. YAxis = Y.Axis,
  11181. axis;
  11182. if(xAxis && !(xAxis instanceof YAxis) && Y_Lang.isString(xAxis) && axes.hasOwnProperty(xAxis))
  11183. {
  11184. axis = axes[xAxis];
  11185. if(axis instanceof YAxis)
  11186. {
  11187. series.set("xAxis", axis);
  11188. }
  11189. }
  11190. if(yAxis && !(yAxis instanceof YAxis) && Y_Lang.isString(yAxis) && axes.hasOwnProperty(yAxis))
  11191. {
  11192. axis = axes[yAxis];
  11193. if(axis instanceof YAxis)
  11194. {
  11195. series.set("yAxis", axis);
  11196. }
  11197. }
  11198. },
  11199. /**
  11200. * Returns the category axis instance for the chart.
  11201. *
  11202. * @method _getCategoryAxis
  11203. * @return Axis
  11204. * @private
  11205. */
  11206. _getCategoryAxis: function()
  11207. {
  11208. var axis,
  11209. axes = this.get("axes"),
  11210. categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey");
  11211. axis = axes[categoryAxisName];
  11212. return axis;
  11213. },
  11214. /**
  11215. * Returns the value axis for a series.
  11216. *
  11217. * @method _getSeriesAxis
  11218. * @param {String} key The key value used to determine the axis instance.
  11219. * @return Axis
  11220. * @private
  11221. */
  11222. _getSeriesAxis:function(key, axisName)
  11223. {
  11224. var axes = this.get("axes"),
  11225. i,
  11226. keys,
  11227. axis;
  11228. if(axes)
  11229. {
  11230. if(axisName && axes.hasOwnProperty(axisName))
  11231. {
  11232. axis = axes[axisName];
  11233. }
  11234. else
  11235. {
  11236. for(i in axes)
  11237. {
  11238. if(axes.hasOwnProperty(i))
  11239. {
  11240. keys = axes[i].get("keys");
  11241. if(keys && keys.hasOwnProperty(key))
  11242. {
  11243. axis = axes[i];
  11244. break;
  11245. }
  11246. }
  11247. }
  11248. }
  11249. }
  11250. return axis;
  11251. },
  11252. /**
  11253. * Gets an attribute from an object, using a getter for Base objects and a property for object
  11254. * literals. Used for determining attributes from series/axis references which can be an actual class instance
  11255. * or a hash of properties that will be used to create a class instance.
  11256. *
  11257. * @method _getBaseAttribute
  11258. * @param {Object} item Object or instance in which the attribute resides.
  11259. * @param {String} key Attribute whose value will be returned.
  11260. * @return Object
  11261. * @private
  11262. */
  11263. _getBaseAttribute: function(item, key)
  11264. {
  11265. if(item instanceof Y.Base)
  11266. {
  11267. return item.get(key);
  11268. }
  11269. if(item.hasOwnProperty(key))
  11270. {
  11271. return item[key];
  11272. }
  11273. return null;
  11274. },
  11275. /**
  11276. * Sets an attribute on an object, using a setter of Base objects and a property for object
  11277. * literals. Used for setting attributes on a Base class, either directly or to be stored in an object literal
  11278. * for use at instantiation.
  11279. *
  11280. * @method _setBaseAttribute
  11281. * @param {Object} item Object or instance in which the attribute resides.
  11282. * @param {String} key Attribute whose value will be assigned.
  11283. * @param {Object} value Value to be assigned to the attribute.
  11284. * @private
  11285. */
  11286. _setBaseAttribute: function(item, key, value)
  11287. {
  11288. if(item instanceof Y.Base)
  11289. {
  11290. item.set(key, value);
  11291. }
  11292. else
  11293. {
  11294. item[key] = value;
  11295. }
  11296. },
  11297. /**
  11298. * Creates `Axis` instances.
  11299. *
  11300. * @method _parseAxes
  11301. * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
  11302. * @return Object
  11303. * @private
  11304. */
  11305. _parseAxes: function(val)
  11306. {
  11307. var hash = this._getDefaultAxes(val),
  11308. axes = {},
  11309. axesAttrs = {
  11310. edgeOffset: "edgeOffset",
  11311. position: "position",
  11312. overlapGraph:"overlapGraph",
  11313. labelFunction:"labelFunction",
  11314. labelFunctionScope:"labelFunctionScope",
  11315. labelFormat:"labelFormat",
  11316. maximum:"maximum",
  11317. minimum:"minimum",
  11318. roundingMethod:"roundingMethod",
  11319. alwaysShowZero:"alwaysShowZero",
  11320. title:"title"
  11321. },
  11322. dp = this.get("dataProvider"),
  11323. ai,
  11324. i,
  11325. pos,
  11326. axis,
  11327. dh,
  11328. axisClass,
  11329. config,
  11330. axesCollection;
  11331. for(i in hash)
  11332. {
  11333. if(hash.hasOwnProperty(i))
  11334. {
  11335. dh = hash[i];
  11336. if(dh instanceof Y.Axis)
  11337. {
  11338. axis = dh;
  11339. }
  11340. else
  11341. {
  11342. axisClass = this._getAxisClass(dh.type);
  11343. config = {};
  11344. config.dataProvider = dh.dataProvider || dp;
  11345. config.keys = dh.keys;
  11346. if(dh.hasOwnProperty("roundingUnit"))
  11347. {
  11348. config.roundingUnit = dh.roundingUnit;
  11349. }
  11350. pos = dh.position;
  11351. if(dh.styles)
  11352. {
  11353. config.styles = dh.styles;
  11354. }
  11355. config.position = dh.position;
  11356. for(ai in axesAttrs)
  11357. {
  11358. if(axesAttrs.hasOwnProperty(ai) && dh.hasOwnProperty(ai))
  11359. {
  11360. config[ai] = dh[ai];
  11361. }
  11362. }
  11363. axis = new axisClass(config);
  11364. }
  11365. if(axis)
  11366. {
  11367. axesCollection = this.get(pos + "AxesCollection");
  11368. if(axesCollection && Y.Array.indexOf(axesCollection, axis) > 0)
  11369. {
  11370. axis.set("overlapGraph", false);
  11371. }
  11372. axis.after("axisRendered", Y.bind(this._axisRendered, this));
  11373. axes[i] = axis;
  11374. }
  11375. }
  11376. }
  11377. return axes;
  11378. },
  11379. /**
  11380. * Adds axes to the chart.
  11381. *
  11382. * @method _addAxes
  11383. * @private
  11384. */
  11385. _addAxes: function()
  11386. {
  11387. var axes = this.get("axes"),
  11388. i,
  11389. axis,
  11390. pos,
  11391. w = this.get("width"),
  11392. h = this.get("height"),
  11393. node = Y.Node.one(this._parentNode);
  11394. if(!this._axesCollection)
  11395. {
  11396. this._axesCollection = [];
  11397. }
  11398. for(i in axes)
  11399. {
  11400. if(axes.hasOwnProperty(i))
  11401. {
  11402. axis = axes[i];
  11403. if(axis instanceof Y.Axis)
  11404. {
  11405. if(!w)
  11406. {
  11407. this.set("width", node.get("offsetWidth"));
  11408. w = this.get("width");
  11409. }
  11410. if(!h)
  11411. {
  11412. this.set("height", node.get("offsetHeight"));
  11413. h = this.get("height");
  11414. }
  11415. axis.set("width", w);
  11416. axis.set("height", h);
  11417. this._addToAxesRenderQueue(axis);
  11418. pos = axis.get("position");
  11419. if(!this.get(pos + "AxesCollection"))
  11420. {
  11421. this.set(pos + "AxesCollection", [axis]);
  11422. }
  11423. else
  11424. {
  11425. this.get(pos + "AxesCollection").push(axis);
  11426. }
  11427. this._axesCollection.push(axis);
  11428. if(axis.get("keys").hasOwnProperty(this.get("categoryKey")))
  11429. {
  11430. this.set("categoryAxis", axis);
  11431. }
  11432. axis.render(this.get("contentBox"));
  11433. }
  11434. }
  11435. }
  11436. },
  11437. /**
  11438. * Renders the Graph.
  11439. *
  11440. * @method _addSeries
  11441. * @private
  11442. */
  11443. _addSeries: function()
  11444. {
  11445. var graph = this.get("graph"),
  11446. sc = this.get("seriesCollection");
  11447. graph.render(this.get("contentBox"));
  11448. },
  11449. /**
  11450. * Adds gridlines to the chart.
  11451. *
  11452. * @method _addGridlines
  11453. * @private
  11454. */
  11455. _addGridlines: function()
  11456. {
  11457. var graph = this.get("graph"),
  11458. hgl = this.get("horizontalGridlines"),
  11459. vgl = this.get("verticalGridlines"),
  11460. direction = this.get("direction"),
  11461. leftAxesCollection = this.get("leftAxesCollection"),
  11462. rightAxesCollection = this.get("rightAxesCollection"),
  11463. bottomAxesCollection = this.get("bottomAxesCollection"),
  11464. topAxesCollection = this.get("topAxesCollection"),
  11465. seriesAxesCollection,
  11466. catAxis = this.get("categoryAxis"),
  11467. hAxis,
  11468. vAxis;
  11469. if(this._axesCollection)
  11470. {
  11471. seriesAxesCollection = this._axesCollection.concat();
  11472. seriesAxesCollection.splice(Y.Array.indexOf(seriesAxesCollection, catAxis), 1);
  11473. }
  11474. if(hgl)
  11475. {
  11476. if(leftAxesCollection && leftAxesCollection[0])
  11477. {
  11478. hAxis = leftAxesCollection[0];
  11479. }
  11480. else if(rightAxesCollection && rightAxesCollection[0])
  11481. {
  11482. hAxis = rightAxesCollection[0];
  11483. }
  11484. else
  11485. {
  11486. hAxis = direction == "horizontal" ? catAxis : seriesAxesCollection[0];
  11487. }
  11488. if(!this._getBaseAttribute(hgl, "axis") && hAxis)
  11489. {
  11490. this._setBaseAttribute(hgl, "axis", hAxis);
  11491. }
  11492. if(this._getBaseAttribute(hgl, "axis"))
  11493. {
  11494. graph.set("horizontalGridlines", hgl);
  11495. }
  11496. }
  11497. if(vgl)
  11498. {
  11499. if(bottomAxesCollection && bottomAxesCollection[0])
  11500. {
  11501. vAxis = bottomAxesCollection[0];
  11502. }
  11503. else if (topAxesCollection && topAxesCollection[0])
  11504. {
  11505. vAxis = topAxesCollection[0];
  11506. }
  11507. else
  11508. {
  11509. vAxis = direction == "vertical" ? catAxis : seriesAxesCollection[0];
  11510. }
  11511. if(!this._getBaseAttribute(vgl, "axis") && vAxis)
  11512. {
  11513. this._setBaseAttribute(vgl, "axis", vAxis);
  11514. }
  11515. if(this._getBaseAttribute(vgl, "axis"))
  11516. {
  11517. graph.set("verticalGridlines", vgl);
  11518. }
  11519. }
  11520. },
  11521. /**
  11522. * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
  11523. *
  11524. * @method _getDefaultAxes
  11525. * @param {Object} axes Object containing `Axis` instances or `Axis` attributes.
  11526. * @return Object
  11527. * @private
  11528. */
  11529. _getDefaultAxes: function(axes)
  11530. {
  11531. var catKey = this.get("categoryKey"),
  11532. axis,
  11533. attr,
  11534. keys,
  11535. newAxes = {},
  11536. claimedKeys = [],
  11537. categoryAxisName = this.get("categoryAxisName") || this.get("categoryKey"),
  11538. valueAxisName = this.get("valueAxisName"),
  11539. seriesKeys = this.get("seriesKeys") || [],
  11540. i,
  11541. l,
  11542. ii,
  11543. ll,
  11544. cIndex,
  11545. dv,
  11546. dp = this.get("dataProvider"),
  11547. direction = this.get("direction"),
  11548. seriesPosition,
  11549. categoryPosition,
  11550. valueAxes = [],
  11551. seriesAxis = this.get("stacked") ? "stacked" : "numeric";
  11552. dv = dp[0];
  11553. if(direction == "vertical")
  11554. {
  11555. seriesPosition = "bottom";
  11556. categoryPosition = "left";
  11557. }
  11558. else
  11559. {
  11560. seriesPosition = "left";
  11561. categoryPosition = "bottom";
  11562. }
  11563. if(axes)
  11564. {
  11565. for(i in axes)
  11566. {
  11567. if(axes.hasOwnProperty(i))
  11568. {
  11569. axis = axes[i];
  11570. keys = this._getBaseAttribute(axis, "keys");
  11571. attr = this._getBaseAttribute(axis, "type");
  11572. if(attr == "time" || attr == "category")
  11573. {
  11574. categoryAxisName = i;
  11575. this.set("categoryAxisName", i);
  11576. if(Y_Lang.isArray(keys) && keys.length > 0)
  11577. {
  11578. catKey = keys[0];
  11579. this.set("categoryKey", catKey);
  11580. }
  11581. newAxes[i] = axis;
  11582. }
  11583. else if(i == categoryAxisName)
  11584. {
  11585. newAxes[i] = axis;
  11586. }
  11587. else
  11588. {
  11589. newAxes[i] = axis;
  11590. if(i != valueAxisName && keys && Y_Lang.isArray(keys))
  11591. {
  11592. ll = keys.length;
  11593. for(ii = 0; ii < ll; ++ii)
  11594. {
  11595. claimedKeys.push(keys[ii]);
  11596. }
  11597. valueAxes.push(newAxes[i]);
  11598. }
  11599. if(!(this._getBaseAttribute(newAxes[i], "type")))
  11600. {
  11601. this._setBaseAttribute(newAxes[i], "type", seriesAxis);
  11602. }
  11603. if(!(this._getBaseAttribute(newAxes[i], "position")))
  11604. {
  11605. this._setBaseAttribute(newAxes[i], "position", this._getDefaultAxisPosition(newAxes[i], valueAxes, seriesPosition));
  11606. }
  11607. }
  11608. }
  11609. }
  11610. }
  11611. if(seriesKeys.length < 1)
  11612. {
  11613. for(i in dv)
  11614. {
  11615. if(dv.hasOwnProperty(i) && i != catKey && Y.Array.indexOf(claimedKeys, i) == -1)
  11616. {
  11617. seriesKeys.push(i);
  11618. }
  11619. }
  11620. }
  11621. cIndex = Y.Array.indexOf(seriesKeys, catKey);
  11622. if(cIndex > -1)
  11623. {
  11624. seriesKeys.splice(cIndex, 1);
  11625. }
  11626. l = claimedKeys.length;
  11627. for(i = 0; i < l; ++i)
  11628. {
  11629. cIndex = Y.Array.indexOf(seriesKeys, claimedKeys[i]);
  11630. if(cIndex > -1)
  11631. {
  11632. seriesKeys.splice(cIndex, 1);
  11633. }
  11634. }
  11635. if(!newAxes.hasOwnProperty(categoryAxisName))
  11636. {
  11637. newAxes[categoryAxisName] = {};
  11638. }
  11639. if(!(this._getBaseAttribute(newAxes[categoryAxisName], "keys")))
  11640. {
  11641. this._setBaseAttribute(newAxes[categoryAxisName], "keys", [catKey]);
  11642. }
  11643. if(!(this._getBaseAttribute(newAxes[categoryAxisName], "position")))
  11644. {
  11645. this._setBaseAttribute(newAxes[categoryAxisName], "position", categoryPosition);
  11646. }
  11647. if(!(this._getBaseAttribute(newAxes[categoryAxisName], "type")))
  11648. {
  11649. this._setBaseAttribute(newAxes[categoryAxisName], "type", this.get("categoryType"));
  11650. }
  11651. if(!newAxes.hasOwnProperty(valueAxisName) && seriesKeys && seriesKeys.length > 0)
  11652. {
  11653. newAxes[valueAxisName] = {keys:seriesKeys};
  11654. valueAxes.push(newAxes[valueAxisName]);
  11655. }
  11656. if(claimedKeys.length > 0)
  11657. {
  11658. if(seriesKeys.length > 0)
  11659. {
  11660. seriesKeys = claimedKeys.concat(seriesKeys);
  11661. }
  11662. else
  11663. {
  11664. seriesKeys = claimedKeys;
  11665. }
  11666. }
  11667. if(newAxes.hasOwnProperty(valueAxisName))
  11668. {
  11669. if(!(this._getBaseAttribute(newAxes[valueAxisName], "position")))
  11670. {
  11671. this._setBaseAttribute(newAxes[valueAxisName], "position", this._getDefaultAxisPosition(newAxes[valueAxisName], valueAxes, seriesPosition));
  11672. }
  11673. if(!(this._getBaseAttribute(newAxes[valueAxisName], "type")))
  11674. {
  11675. this._setBaseAttribute(newAxes[valueAxisName], "type", seriesAxis);
  11676. }
  11677. if(!(this._getBaseAttribute(newAxes[valueAxisName], "keys")))
  11678. {
  11679. this._setBaseAttribute(newAxes[valueAxisName], "keys", seriesKeys);
  11680. }
  11681. }
  11682. this.set("seriesKeys", seriesKeys);
  11683. return newAxes;
  11684. },
  11685. /**
  11686. * Determines the position of an axis when one is not specified.
  11687. *
  11688. * @method _getDefaultAxisPosition
  11689. * @param {Axis} axis `Axis` instance.
  11690. * @param {Array} valueAxes Array of `Axis` instances.
  11691. * @param {String} position Default position depending on the direction of the chart and type of axis.
  11692. * @return String
  11693. * @private
  11694. */
  11695. _getDefaultAxisPosition: function(axis, valueAxes, position)
  11696. {
  11697. var direction = this.get("direction"),
  11698. i = Y.Array.indexOf(valueAxes, axis);
  11699. if(valueAxes[i - 1] && valueAxes[i - 1].position)
  11700. {
  11701. if(direction == "horizontal")
  11702. {
  11703. if(valueAxes[i - 1].position == "left")
  11704. {
  11705. position = "right";
  11706. }
  11707. else if(valueAxes[i - 1].position == "right")
  11708. {
  11709. position = "left";
  11710. }
  11711. }
  11712. else
  11713. {
  11714. if (valueAxes[i -1].position == "bottom")
  11715. {
  11716. position = "top";
  11717. }
  11718. else
  11719. {
  11720. position = "bottom";
  11721. }
  11722. }
  11723. }
  11724. return position;
  11725. },
  11726. /**
  11727. * Returns an object literal containing a categoryItem and a valueItem for a given series index.
  11728. *
  11729. * @method getSeriesItem
  11730. * @param {CartesianSeries} series Reference to a series.
  11731. * @param {Number} index Index of the specified item within a series.
  11732. * @return Object
  11733. */
  11734. getSeriesItems: function(series, index)
  11735. {
  11736. var xAxis = series.get("xAxis"),
  11737. yAxis = series.get("yAxis"),
  11738. xKey = series.get("xKey"),
  11739. yKey = series.get("yKey"),
  11740. categoryItem,
  11741. valueItem;
  11742. if(this.get("direction") == "vertical")
  11743. {
  11744. categoryItem = {
  11745. axis:yAxis,
  11746. key:yKey,
  11747. value:yAxis.getKeyValueAt(yKey, index)
  11748. };
  11749. valueItem = {
  11750. axis:xAxis,
  11751. key:xKey,
  11752. value: xAxis.getKeyValueAt(xKey, index)
  11753. };
  11754. }
  11755. else
  11756. {
  11757. valueItem = {
  11758. axis:yAxis,
  11759. key:yKey,
  11760. value:yAxis.getKeyValueAt(yKey, index)
  11761. };
  11762. categoryItem = {
  11763. axis:xAxis,
  11764. key:xKey,
  11765. value: xAxis.getKeyValueAt(xKey, index)
  11766. };
  11767. }
  11768. categoryItem.displayName = series.get("categoryDisplayName");
  11769. valueItem.displayName = series.get("valueDisplayName");
  11770. categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index);
  11771. valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index);
  11772. return {category:categoryItem, value:valueItem};
  11773. },
  11774. /**
  11775. * Handler for axisRendered event.
  11776. *
  11777. * @method _axisRendered
  11778. * @param {Object} e Event object.
  11779. * @private
  11780. */
  11781. _axisRendered: function(e)
  11782. {
  11783. this._axesRenderQueue = this._axesRenderQueue.splice(1 + Y.Array.indexOf(this._axesRenderQueue, e.currentTarget), 1);
  11784. if(this._axesRenderQueue.length < 1)
  11785. {
  11786. this._redraw();
  11787. }
  11788. },
  11789. /**
  11790. * Handler for sizeChanged event.
  11791. *
  11792. * @method _sizeChanged
  11793. * @param {Object} e Event object.
  11794. * @private
  11795. */
  11796. _sizeChanged: function(e)
  11797. {
  11798. if(this._axesCollection)
  11799. {
  11800. var ac = this._axesCollection,
  11801. i = 0,
  11802. l = ac.length;
  11803. for(; i < l; ++i)
  11804. {
  11805. this._addToAxesRenderQueue(ac[i]);
  11806. }
  11807. this._redraw();
  11808. }
  11809. },
  11810. /**
  11811. * Redraws and position all the components of the chart instance.
  11812. *
  11813. * @method _redraw
  11814. * @private
  11815. */
  11816. _redraw: function()
  11817. {
  11818. if(this._drawing)
  11819. {
  11820. this._callLater = true;
  11821. return;
  11822. }
  11823. this._drawing = true;
  11824. this._callLater = false;
  11825. var w = this.get("width"),
  11826. h = this.get("height"),
  11827. lw = 0,
  11828. rw = 0,
  11829. th = 0,
  11830. bh = 0,
  11831. lc = this.get("leftAxesCollection"),
  11832. rc = this.get("rightAxesCollection"),
  11833. tc = this.get("topAxesCollection"),
  11834. bc = this.get("bottomAxesCollection"),
  11835. i = 0,
  11836. l,
  11837. axis,
  11838. pos,
  11839. pts = [],
  11840. graphOverflow = "visible",
  11841. graph = this.get("graph");
  11842. if(lc)
  11843. {
  11844. l = lc.length;
  11845. for(i = l - 1; i > -1; --i)
  11846. {
  11847. pts[Y.Array.indexOf(this._axesCollection, lc[i])] = {x:lw + "px"};
  11848. lw += lc[i].get("width");
  11849. }
  11850. }
  11851. if(rc)
  11852. {
  11853. l = rc.length;
  11854. i = 0;
  11855. for(i = l - 1; i > -1; --i)
  11856. {
  11857. rw += rc[i].get("width");
  11858. pts[Y.Array.indexOf(this._axesCollection, rc[i])] = {x:(w - rw) + "px"};
  11859. }
  11860. }
  11861. if(tc)
  11862. {
  11863. l = tc.length;
  11864. for(i = l - 1; i > -1; --i)
  11865. {
  11866. pts[Y.Array.indexOf(this._axesCollection, tc[i])] = {y:th + "px"};
  11867. th += tc[i].get("height");
  11868. }
  11869. }
  11870. if(bc)
  11871. {
  11872. l = bc.length;
  11873. for(i = l - 1; i > -1; --i)
  11874. {
  11875. bh += bc[i].get("height");
  11876. pts[Y.Array.indexOf(this._axesCollection, bc[i])] = {y:(h - bh) + "px"};
  11877. }
  11878. }
  11879. l = this._axesCollection.length;
  11880. i = 0;
  11881. for(; i < l; ++i)
  11882. {
  11883. axis = this._axesCollection[i];
  11884. pos = axis.get("position");
  11885. if(pos == "left" || pos === "right")
  11886. {
  11887. axis.get("boundingBox").setStyle("top", th + "px");
  11888. axis.get("boundingBox").setStyle("left", pts[i].x);
  11889. if(axis.get("height") !== h - (bh + th))
  11890. {
  11891. axis.set("height", h - (bh + th));
  11892. }
  11893. }
  11894. else if(pos == "bottom" || pos == "top")
  11895. {
  11896. if(axis.get("width") !== w - (lw + rw))
  11897. {
  11898. axis.set("width", w - (lw + rw));
  11899. }
  11900. axis.get("boundingBox").setStyle("left", lw + "px");
  11901. axis.get("boundingBox").setStyle("top", pts[i].y);
  11902. }
  11903. if(axis._hasDataOverflow())
  11904. {
  11905. graphOverflow = "hidden";
  11906. }
  11907. }
  11908. this._drawing = false;
  11909. if(this._callLater)
  11910. {
  11911. this._redraw();
  11912. return;
  11913. }
  11914. if(graph)
  11915. {
  11916. graph.get("boundingBox").setStyle("left", lw + "px");
  11917. graph.get("boundingBox").setStyle("top", th + "px");
  11918. graph.set("width", w - (lw + rw));
  11919. graph.set("height", h - (th + bh));
  11920. graph.get("boundingBox").setStyle("overflow", graphOverflow);
  11921. }
  11922. if(this._overlay)
  11923. {
  11924. this._overlay.setStyle("left", lw + "px");
  11925. this._overlay.setStyle("top", th + "px");
  11926. this._overlay.setStyle("width", (w - (lw + rw)) + "px");
  11927. this._overlay.setStyle("height", (h - (th + bh)) + "px");
  11928. }
  11929. }
  11930. }, {
  11931. ATTRS: {
  11932. /**
  11933. * Style object for the axes.
  11934. *
  11935. * @attribute axesStyles
  11936. * @type Object
  11937. * @private
  11938. */
  11939. axesStyles: {
  11940. getter: function()
  11941. {
  11942. var axes = this.get("axes"),
  11943. i,
  11944. styles = this._axesStyles;
  11945. if(axes)
  11946. {
  11947. for(i in axes)
  11948. {
  11949. if(axes.hasOwnProperty(i) && axes[i] instanceof Y.Axis)
  11950. {
  11951. if(!styles)
  11952. {
  11953. styles = {};
  11954. }
  11955. styles[i] = axes[i].get("styles");
  11956. }
  11957. }
  11958. }
  11959. return styles;
  11960. },
  11961. setter: function(val)
  11962. {
  11963. var axes = this.get("axes"),
  11964. i;
  11965. for(i in val)
  11966. {
  11967. if(val.hasOwnProperty(i) && axes.hasOwnProperty(i))
  11968. {
  11969. this._setBaseAttribute(axes[i], "styles", val[i]);
  11970. }
  11971. }
  11972. }
  11973. },
  11974. /**
  11975. * Style object for the series
  11976. *
  11977. * @attribute seriesStyles
  11978. * @type Object
  11979. * @private
  11980. */
  11981. seriesStyles: {
  11982. getter: function()
  11983. {
  11984. var styles = this._seriesStyles,
  11985. graph = this.get("graph"),
  11986. dict,
  11987. i;
  11988. if(graph)
  11989. {
  11990. dict = graph.get("seriesDictionary");
  11991. if(dict)
  11992. {
  11993. styles = {};
  11994. for(i in dict)
  11995. {
  11996. if(dict.hasOwnProperty(i))
  11997. {
  11998. styles[i] = dict[i].get("styles");
  11999. }
  12000. }
  12001. }
  12002. }
  12003. return styles;
  12004. },
  12005. setter: function(val)
  12006. {
  12007. var i,
  12008. l,
  12009. s;
  12010. if(Y_Lang.isArray(val))
  12011. {
  12012. s = this.get("seriesCollection");
  12013. i = 0;
  12014. l = val.length;
  12015. for(; i < l; ++i)
  12016. {
  12017. this._setBaseAttribute(s[i], "styles", val[i]);
  12018. }
  12019. }
  12020. else
  12021. {
  12022. for(i in val)
  12023. {
  12024. if(val.hasOwnProperty(i))
  12025. {
  12026. s = this.getSeries(i);
  12027. this._setBaseAttribute(s, "styles", val[i]);
  12028. }
  12029. }
  12030. }
  12031. }
  12032. },
  12033. /**
  12034. * Styles for the graph.
  12035. *
  12036. * @attribute graphStyles
  12037. * @type Object
  12038. * @private
  12039. */
  12040. graphStyles: {
  12041. getter: function()
  12042. {
  12043. var graph = this.get("graph");
  12044. if(graph)
  12045. {
  12046. return(graph.get("styles"));
  12047. }
  12048. return this._graphStyles;
  12049. },
  12050. setter: function(val)
  12051. {
  12052. var graph = this.get("graph");
  12053. this._setBaseAttribute(graph, "styles", val);
  12054. }
  12055. },
  12056. /**
  12057. * Style properties for the chart. Contains a key indexed hash of the following:
  12058. * <dl>
  12059. * <dt>series</dt><dd>A key indexed hash containing references to the `styles` attribute for each series in the chart.
  12060. * Specific style attributes vary depending on the series:
  12061. * <ul>
  12062. * <li><a href="AreaSeries.html#attr_styles">AreaSeries</a></li>
  12063. * <li><a href="BarSeries.html#attr_styles">BarSeries</a></li>
  12064. * <li><a href="ColumnSeries.html#attr_styles">ColumnSeries</a></li>
  12065. * <li><a href="ComboSeries.html#attr_styles">ComboSeries</a></li>
  12066. * <li><a href="LineSeries.html#attr_styles">LineSeries</a></li>
  12067. * <li><a href="MarkerSeries.html#attr_styles">MarkerSeries</a></li>
  12068. * <li><a href="SplineSeries.html#attr_styles">SplineSeries</a></li>
  12069. * </ul>
  12070. * </dd>
  12071. * <dt>axes</dt><dd>A key indexed hash containing references to the `styles` attribute for each axes in the chart. Specific
  12072. * style attributes can be found in the <a href="Axis.html#attr_styles">Axis</a> class.</dd>
  12073. * <dt>graph</dt><dd>A reference to the `styles` attribute in the chart. Specific style attributes can be found in the
  12074. * <a href="Graph.html#attr_styles">Graph</a> class.</dd>
  12075. * </dl>
  12076. *
  12077. * @attribute styles
  12078. * @type Object
  12079. */
  12080. styles: {
  12081. getter: function()
  12082. {
  12083. var styles = {
  12084. axes: this.get("axesStyles"),
  12085. series: this.get("seriesStyles"),
  12086. graph: this.get("graphStyles")
  12087. };
  12088. return styles;
  12089. },
  12090. setter: function(val)
  12091. {
  12092. if(val.hasOwnProperty("axes"))
  12093. {
  12094. if(this.get("axesStyles"))
  12095. {
  12096. this.set("axesStyles", val.axes);
  12097. }
  12098. else
  12099. {
  12100. this._axesStyles = val.axes;
  12101. }
  12102. }
  12103. if(val.hasOwnProperty("series"))
  12104. {
  12105. if(this.get("seriesStyles"))
  12106. {
  12107. this.set("seriesStyles", val.series);
  12108. }
  12109. else
  12110. {
  12111. this._seriesStyles = val.series;
  12112. }
  12113. }
  12114. if(val.hasOwnProperty("graph"))
  12115. {
  12116. this.set("graphStyles", val.graph);
  12117. }
  12118. }
  12119. },
  12120. /**
  12121. * Axes to appear in the chart. This can be a key indexed hash of axis instances or object literals
  12122. * used to construct the appropriate axes.
  12123. *
  12124. * @attribute axes
  12125. * @type Object
  12126. */
  12127. axes: {
  12128. valueFn: "_parseAxes",
  12129. setter: function(val)
  12130. {
  12131. return this._parseAxes(val);
  12132. }
  12133. },
  12134. /**
  12135. * Collection of series to appear on the chart. This can be an array of Series instances or object literals
  12136. * used to construct the appropriate series.
  12137. *
  12138. * @attribute seriesCollection
  12139. * @type Array
  12140. */
  12141. seriesCollection: {
  12142. valueFn: "_getDefaultSeriesCollection",
  12143. setter: function(val)
  12144. {
  12145. return this._getDefaultSeriesCollection(val);
  12146. }
  12147. },
  12148. /**
  12149. * Reference to the left-aligned axes for the chart.
  12150. *
  12151. * @attribute leftAxesCollection
  12152. * @type Array
  12153. * @private
  12154. */
  12155. leftAxesCollection: {},
  12156. /**
  12157. * Reference to the bottom-aligned axes for the chart.
  12158. *
  12159. * @attribute bottomAxesCollection
  12160. * @type Array
  12161. * @private
  12162. */
  12163. bottomAxesCollection: {},
  12164. /**
  12165. * Reference to the right-aligned axes for the chart.
  12166. *
  12167. * @attribute rightAxesCollection
  12168. * @type Array
  12169. * @private
  12170. */
  12171. rightAxesCollection: {},
  12172. /**
  12173. * Reference to the top-aligned axes for the chart.
  12174. *
  12175. * @attribute topAxesCollection
  12176. * @type Array
  12177. * @private
  12178. */
  12179. topAxesCollection: {},
  12180. /**
  12181. * Indicates whether or not the chart is stacked.
  12182. *
  12183. * @attribute stacked
  12184. * @type Boolean
  12185. */
  12186. stacked: {
  12187. value: false
  12188. },
  12189. /**
  12190. * Direction of chart's category axis when there is no series collection specified. Charts can
  12191. * be horizontal or vertical. When the chart type is column, the chart is horizontal.
  12192. * When the chart type is bar, the chart is vertical.
  12193. *
  12194. * @attribute direction
  12195. * @type String
  12196. */
  12197. direction: {
  12198. getter: function()
  12199. {
  12200. var type = this.get("type");
  12201. if(type == "bar")
  12202. {
  12203. return "vertical";
  12204. }
  12205. else if(type == "column")
  12206. {
  12207. return "horizontal";
  12208. }
  12209. return this._direction;
  12210. },
  12211. setter: function(val)
  12212. {
  12213. this._direction = val;
  12214. return this._direction;
  12215. }
  12216. },
  12217. /**
  12218. * Indicates whether or not an area is filled in a combo chart.
  12219. *
  12220. * @attribute showAreaFill
  12221. * @type Boolean
  12222. */
  12223. showAreaFill: {},
  12224. /**
  12225. * Indicates whether to display markers in a combo chart.
  12226. *
  12227. * @attribute showMarkers
  12228. * @type Boolean
  12229. */
  12230. showMarkers:{},
  12231. /**
  12232. * Indicates whether to display lines in a combo chart.
  12233. *
  12234. * @attribute showLines
  12235. * @type Boolean
  12236. */
  12237. showLines:{},
  12238. /**
  12239. * Indicates the key value used to identify a category axis in the `axes` hash. If
  12240. * not specified, the categoryKey attribute value will be used.
  12241. *
  12242. * @attribute categoryAxisName
  12243. * @type String
  12244. */
  12245. categoryAxisName: {
  12246. },
  12247. /**
  12248. * Indicates the key value used to identify a the series axis when an axis not generated.
  12249. *
  12250. * @attribute valueAxisName
  12251. * @type String
  12252. */
  12253. valueAxisName: {
  12254. value: "values"
  12255. },
  12256. /**
  12257. * Reference to the horizontalGridlines for the chart.
  12258. *
  12259. * @attribute horizontalGridlines
  12260. * @type Gridlines
  12261. */
  12262. horizontalGridlines: {
  12263. getter: function()
  12264. {
  12265. var graph = this.get("graph");
  12266. if(graph)
  12267. {
  12268. return graph.get("horizontalGridlines");
  12269. }
  12270. return this._horizontalGridlines;
  12271. },
  12272. setter: function(val)
  12273. {
  12274. var graph = this.get("graph");
  12275. if(val && !Y_Lang.isObject(val))
  12276. {
  12277. val = {};
  12278. }
  12279. if(graph)
  12280. {
  12281. graph.set("horizontalGridlines", val);
  12282. }
  12283. else
  12284. {
  12285. this._horizontalGridlines = val;
  12286. }
  12287. }
  12288. },
  12289. /**
  12290. * Reference to the verticalGridlines for the chart.
  12291. *
  12292. * @attribute verticalGridlines
  12293. * @type Gridlines
  12294. */
  12295. verticalGridlines: {
  12296. getter: function()
  12297. {
  12298. var graph = this.get("graph");
  12299. if(graph)
  12300. {
  12301. return graph.get("verticalGridlines");
  12302. }
  12303. return this._verticalGridlines;
  12304. },
  12305. setter: function(val)
  12306. {
  12307. var graph = this.get("graph");
  12308. if(val && !Y_Lang.isObject(val))
  12309. {
  12310. val = {};
  12311. }
  12312. if(graph)
  12313. {
  12314. graph.set("verticalGridlines", val);
  12315. }
  12316. else
  12317. {
  12318. this._verticalGridlines = val;
  12319. }
  12320. }
  12321. },
  12322. /**
  12323. * Type of chart when there is no series collection specified.
  12324. *
  12325. * @attribute type
  12326. * @type String
  12327. */
  12328. type: {
  12329. getter: function()
  12330. {
  12331. if(this.get("stacked"))
  12332. {
  12333. return "stacked" + this._type;
  12334. }
  12335. return this._type;
  12336. },
  12337. setter: function(val)
  12338. {
  12339. if(this._type == "bar")
  12340. {
  12341. if(val != "bar")
  12342. {
  12343. this.set("direction", "horizontal");
  12344. }
  12345. }
  12346. else
  12347. {
  12348. if(val == "bar")
  12349. {
  12350. this.set("direction", "vertical");
  12351. }
  12352. }
  12353. this._type = val;
  12354. return this._type;
  12355. }
  12356. },
  12357. /**
  12358. * Reference to the category axis used by the chart.
  12359. *
  12360. * @attribute categoryAxis
  12361. * @type Axis
  12362. */
  12363. categoryAxis:{}
  12364. }
  12365. });
  12366. /**
  12367. * The PieChart class creates a pie chart
  12368. *
  12369. * @module charts
  12370. * @class PieChart
  12371. * @extends ChartBase
  12372. * @constructor
  12373. */
  12374. Y.PieChart = Y.Base.create("pieChart", Y.Widget, [Y.ChartBase], {
  12375. /**
  12376. * Calculates and returns a `seriesCollection`.
  12377. *
  12378. * @method _getSeriesCollection
  12379. * @return Array
  12380. * @private
  12381. */
  12382. _getSeriesCollection: function()
  12383. {
  12384. if(this._seriesCollection)
  12385. {
  12386. return this._seriesCollection;
  12387. }
  12388. var axes = this.get("axes"),
  12389. sc = [],
  12390. seriesKeys,
  12391. i = 0,
  12392. l,
  12393. type = this.get("type"),
  12394. key,
  12395. catAxis = "categoryAxis",
  12396. catKey = "categoryKey",
  12397. valAxis = "valueAxis",
  12398. seriesKey = "valueKey";
  12399. if(axes)
  12400. {
  12401. seriesKeys = axes.values.get("keyCollection");
  12402. key = axes.category.get("keyCollection")[0];
  12403. l = seriesKeys.length;
  12404. for(; i < l; ++i)
  12405. {
  12406. sc[i] = {type:type};
  12407. sc[i][catAxis] = "category";
  12408. sc[i][valAxis] = "values";
  12409. sc[i][catKey] = key;
  12410. sc[i][seriesKey] = seriesKeys[i];
  12411. }
  12412. }
  12413. this._seriesCollection = sc;
  12414. return sc;
  12415. },
  12416. /**
  12417. * Creates `Axis` instances.
  12418. *
  12419. * @method _parseAxes
  12420. * @param {Object} val Object containing `Axis` instances or objects in which to construct `Axis` instances.
  12421. * @return Object
  12422. * @private
  12423. */
  12424. _parseAxes: function(hash)
  12425. {
  12426. if(!this._axes)
  12427. {
  12428. this._axes = {};
  12429. }
  12430. var i, pos, axis, dh, config, axisClass,
  12431. type = this.get("type"),
  12432. w = this.get("width"),
  12433. h = this.get("height"),
  12434. node = Y.Node.one(this._parentNode);
  12435. if(!w)
  12436. {
  12437. this.set("width", node.get("offsetWidth"));
  12438. w = this.get("width");
  12439. }
  12440. if(!h)
  12441. {
  12442. this.set("height", node.get("offsetHeight"));
  12443. h = this.get("height");
  12444. }
  12445. for(i in hash)
  12446. {
  12447. if(hash.hasOwnProperty(i))
  12448. {
  12449. dh = hash[i];
  12450. pos = type == "pie" ? "none" : dh.position;
  12451. axisClass = this._getAxisClass(dh.type);
  12452. config = {dataProvider:this.get("dataProvider")};
  12453. if(dh.hasOwnProperty("roundingUnit"))
  12454. {
  12455. config.roundingUnit = dh.roundingUnit;
  12456. }
  12457. config.keys = dh.keys;
  12458. config.width = w;
  12459. config.height = h;
  12460. config.position = pos;
  12461. config.styles = dh.styles;
  12462. axis = new axisClass(config);
  12463. axis.on("axisRendered", Y.bind(this._axisRendered, this));
  12464. this._axes[i] = axis;
  12465. }
  12466. }
  12467. },
  12468. /**
  12469. * Adds axes to the chart.
  12470. *
  12471. * @method _addAxes
  12472. * @private
  12473. */
  12474. _addAxes: function()
  12475. {
  12476. var axes = this.get("axes"),
  12477. i,
  12478. axis,
  12479. p;
  12480. if(!axes)
  12481. {
  12482. this.set("axes", this._getDefaultAxes());
  12483. axes = this.get("axes");
  12484. }
  12485. if(!this._axesCollection)
  12486. {
  12487. this._axesCollection = [];
  12488. }
  12489. for(i in axes)
  12490. {
  12491. if(axes.hasOwnProperty(i))
  12492. {
  12493. axis = axes[i];
  12494. p = axis.get("position");
  12495. if(!this.get(p + "AxesCollection"))
  12496. {
  12497. this.set(p + "AxesCollection", [axis]);
  12498. }
  12499. else
  12500. {
  12501. this.get(p + "AxesCollection").push(axis);
  12502. }
  12503. this._axesCollection.push(axis);
  12504. }
  12505. }
  12506. },
  12507. /**
  12508. * Renders the Graph.
  12509. *
  12510. * @method _addSeries
  12511. * @private
  12512. */
  12513. _addSeries: function()
  12514. {
  12515. var graph = this.get("graph"),
  12516. seriesCollection = this.get("seriesCollection");
  12517. this._parseSeriesAxes(seriesCollection);
  12518. graph.set("showBackground", false);
  12519. graph.set("width", this.get("width"));
  12520. graph.set("height", this.get("height"));
  12521. graph.set("seriesCollection", seriesCollection);
  12522. this._seriesCollection = graph.get("seriesCollection");
  12523. graph.render(this.get("contentBox"));
  12524. },
  12525. /**
  12526. * Parse and sets the axes for the chart.
  12527. *
  12528. * @method _parseSeriesAxes
  12529. * @param {Array} c A collection `PieSeries` instance.
  12530. * @private
  12531. */
  12532. _parseSeriesAxes: function(c)
  12533. {
  12534. var i = 0,
  12535. len = c.length,
  12536. s,
  12537. axes = this.get("axes"),
  12538. axis;
  12539. for(; i < len; ++i)
  12540. {
  12541. s = c[i];
  12542. if(s)
  12543. {
  12544. //If series is an actual series instance,
  12545. //replace axes attribute string ids with axes
  12546. if(s instanceof Y.PieSeries)
  12547. {
  12548. axis = s.get("categoryAxis");
  12549. if(axis && !(axis instanceof Y.Axis))
  12550. {
  12551. s.set("categoryAxis", axes[axis]);
  12552. }
  12553. axis = s.get("valueAxis");
  12554. if(axis && !(axis instanceof Y.Axis))
  12555. {
  12556. s.set("valueAxis", axes[axis]);
  12557. }
  12558. continue;
  12559. }
  12560. s.categoryAxis = axes.category;
  12561. s.valueAxis = axes.values;
  12562. if(!s.type)
  12563. {
  12564. s.type = this.get("type");
  12565. }
  12566. }
  12567. }
  12568. },
  12569. /**
  12570. * Generates and returns a key-indexed object containing `Axis` instances or objects used to create `Axis` instances.
  12571. *
  12572. * @method _getDefaultAxes
  12573. * @return Object
  12574. * @private
  12575. */
  12576. _getDefaultAxes: function()
  12577. {
  12578. var catKey = this.get("categoryKey"),
  12579. seriesKeys = this.get("seriesKeys") || [],
  12580. seriesAxis = "numeric",
  12581. i,
  12582. dv = this.get("dataProvider")[0];
  12583. if(seriesKeys.length < 1)
  12584. {
  12585. for(i in dv)
  12586. {
  12587. if(i != catKey)
  12588. {
  12589. seriesKeys.push(i);
  12590. }
  12591. }
  12592. if(seriesKeys.length > 0)
  12593. {
  12594. this.set("seriesKeys", seriesKeys);
  12595. }
  12596. }
  12597. return {
  12598. values:{
  12599. keys:seriesKeys,
  12600. type:seriesAxis
  12601. },
  12602. category:{
  12603. keys:[catKey],
  12604. type:this.get("categoryType")
  12605. }
  12606. };
  12607. },
  12608. /**
  12609. * Returns an object literal containing a categoryItem and a valueItem for a given series index.
  12610. *
  12611. * @method getSeriesItem
  12612. * @param series Reference to a series.
  12613. * @param index Index of the specified item within a series.
  12614. * @return Object
  12615. */
  12616. getSeriesItems: function(series, index)
  12617. {
  12618. var categoryItem = {
  12619. axis: series.get("categoryAxis"),
  12620. key: series.get("categoryKey"),
  12621. displayName: series.get("categoryDisplayName")
  12622. },
  12623. valueItem = {
  12624. axis: series.get("valueAxis"),
  12625. key: series.get("valueKey"),
  12626. displayName: series.get("valueDisplayName")
  12627. };
  12628. categoryItem.value = categoryItem.axis.getKeyValueAt(categoryItem.key, index);
  12629. valueItem.value = valueItem.axis.getKeyValueAt(valueItem.key, index);
  12630. return {category:categoryItem, value:valueItem};
  12631. },
  12632. /**
  12633. * Handler for sizeChanged event.
  12634. *
  12635. * @method _sizeChanged
  12636. * @param {Object} e Event object.
  12637. * @private
  12638. */
  12639. _sizeChanged: function(e)
  12640. {
  12641. var graph = this.get("graph");
  12642. if(graph)
  12643. {
  12644. graph.set(e.attrName, e.newVal);
  12645. }
  12646. },
  12647. /**
  12648. * Redraws the chart instance.
  12649. *
  12650. * @method _redraw
  12651. * @private
  12652. */
  12653. _redraw: function()
  12654. {
  12655. var graph = this.get("graph");
  12656. if(graph)
  12657. {
  12658. graph.set("width", this.get("width"));
  12659. graph.set("height", this.get("height"));
  12660. }
  12661. }
  12662. }, {
  12663. ATTRS: {
  12664. /**
  12665. * Axes to appear in the chart.
  12666. *
  12667. * @attribute axes
  12668. * @type Object
  12669. */
  12670. axes: {
  12671. getter: function()
  12672. {
  12673. return this._axes;
  12674. },
  12675. setter: function(val)
  12676. {
  12677. this._parseAxes(val);
  12678. }
  12679. },
  12680. /**
  12681. * Collection of series to appear on the chart. This can be an array of Series instances or object literals
  12682. * used to describe a Series instance.
  12683. *
  12684. * @attribute seriesCollection
  12685. * @type Array
  12686. */
  12687. seriesCollection: {
  12688. getter: function()
  12689. {
  12690. return this._getSeriesCollection();
  12691. },
  12692. setter: function(val)
  12693. {
  12694. return this._setSeriesCollection(val);
  12695. }
  12696. },
  12697. /**
  12698. * Type of chart when there is no series collection specified.
  12699. *
  12700. * @attribute type
  12701. * @type String
  12702. */
  12703. type: {
  12704. value: "pie"
  12705. }
  12706. }
  12707. });
  12708. /**
  12709. * The Chart class is the basic application used to create a chart.
  12710. *
  12711. * @module charts
  12712. * @class Chart
  12713. * @constructor
  12714. */
  12715. function Chart(cfg)
  12716. {
  12717. if(cfg.type != "pie")
  12718. {
  12719. return new Y.CartesianChart(cfg);
  12720. }
  12721. else
  12722. {
  12723. return new Y.PieChart(cfg);
  12724. }
  12725. }
  12726. Y.Chart = Chart;
  12727. }, '3.4.0' ,{requires:['dom', 'datatype-number', 'datatype-date', 'event-custom', 'event-mouseenter', 'widget', 'widget-position', 'widget-stack', 'graphics']});