Chart.bundle.js 437 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946
  1. /*!
  2. * Chart.js
  3. * http://chartjs.org/
  4. * Version: 2.1.4
  5. *
  6. * Copyright 2016 Nick Downie
  7. * Released under the MIT license
  8. * https://github.com/chartjs/Chart.js/blob/master/LICENSE.md
  9. */
  10. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  11. /* MIT license */
  12. var colorNames = require('color-name');
  13. module.exports = {
  14. getRgba: getRgba,
  15. getHsla: getHsla,
  16. getRgb: getRgb,
  17. getHsl: getHsl,
  18. getHwb: getHwb,
  19. getAlpha: getAlpha,
  20. hexString: hexString,
  21. rgbString: rgbString,
  22. rgbaString: rgbaString,
  23. percentString: percentString,
  24. percentaString: percentaString,
  25. hslString: hslString,
  26. hslaString: hslaString,
  27. hwbString: hwbString,
  28. keyword: keyword
  29. }
  30. function getRgba(string) {
  31. if (!string) {
  32. return;
  33. }
  34. var abbr = /^#([a-fA-F0-9]{3})$/,
  35. hex = /^#([a-fA-F0-9]{6})$/,
  36. rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
  37. per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/,
  38. keyword = /(\w+)/;
  39. var rgb = [0, 0, 0],
  40. a = 1,
  41. match = string.match(abbr);
  42. if (match) {
  43. match = match[1];
  44. for (var i = 0; i < rgb.length; i++) {
  45. rgb[i] = parseInt(match[i] + match[i], 16);
  46. }
  47. }
  48. else if (match = string.match(hex)) {
  49. match = match[1];
  50. for (var i = 0; i < rgb.length; i++) {
  51. rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);
  52. }
  53. }
  54. else if (match = string.match(rgba)) {
  55. for (var i = 0; i < rgb.length; i++) {
  56. rgb[i] = parseInt(match[i + 1]);
  57. }
  58. a = parseFloat(match[4]);
  59. }
  60. else if (match = string.match(per)) {
  61. for (var i = 0; i < rgb.length; i++) {
  62. rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
  63. }
  64. a = parseFloat(match[4]);
  65. }
  66. else if (match = string.match(keyword)) {
  67. if (match[1] == "transparent") {
  68. return [0, 0, 0, 0];
  69. }
  70. rgb = colorNames[match[1]];
  71. if (!rgb) {
  72. return;
  73. }
  74. }
  75. for (var i = 0; i < rgb.length; i++) {
  76. rgb[i] = scale(rgb[i], 0, 255);
  77. }
  78. if (!a && a != 0) {
  79. a = 1;
  80. }
  81. else {
  82. a = scale(a, 0, 1);
  83. }
  84. rgb[3] = a;
  85. return rgb;
  86. }
  87. function getHsla(string) {
  88. if (!string) {
  89. return;
  90. }
  91. var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
  92. var match = string.match(hsl);
  93. if (match) {
  94. var alpha = parseFloat(match[4]);
  95. var h = scale(parseInt(match[1]), 0, 360),
  96. s = scale(parseFloat(match[2]), 0, 100),
  97. l = scale(parseFloat(match[3]), 0, 100),
  98. a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
  99. return [h, s, l, a];
  100. }
  101. }
  102. function getHwb(string) {
  103. if (!string) {
  104. return;
  105. }
  106. var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;
  107. var match = string.match(hwb);
  108. if (match) {
  109. var alpha = parseFloat(match[4]);
  110. var h = scale(parseInt(match[1]), 0, 360),
  111. w = scale(parseFloat(match[2]), 0, 100),
  112. b = scale(parseFloat(match[3]), 0, 100),
  113. a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);
  114. return [h, w, b, a];
  115. }
  116. }
  117. function getRgb(string) {
  118. var rgba = getRgba(string);
  119. return rgba && rgba.slice(0, 3);
  120. }
  121. function getHsl(string) {
  122. var hsla = getHsla(string);
  123. return hsla && hsla.slice(0, 3);
  124. }
  125. function getAlpha(string) {
  126. var vals = getRgba(string);
  127. if (vals) {
  128. return vals[3];
  129. }
  130. else if (vals = getHsla(string)) {
  131. return vals[3];
  132. }
  133. else if (vals = getHwb(string)) {
  134. return vals[3];
  135. }
  136. }
  137. // generators
  138. function hexString(rgb) {
  139. return "#" + hexDouble(rgb[0]) + hexDouble(rgb[1])
  140. + hexDouble(rgb[2]);
  141. }
  142. function rgbString(rgba, alpha) {
  143. if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
  144. return rgbaString(rgba, alpha);
  145. }
  146. return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";
  147. }
  148. function rgbaString(rgba, alpha) {
  149. if (alpha === undefined) {
  150. alpha = (rgba[3] !== undefined ? rgba[3] : 1);
  151. }
  152. return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]
  153. + ", " + alpha + ")";
  154. }
  155. function percentString(rgba, alpha) {
  156. if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {
  157. return percentaString(rgba, alpha);
  158. }
  159. var r = Math.round(rgba[0]/255 * 100),
  160. g = Math.round(rgba[1]/255 * 100),
  161. b = Math.round(rgba[2]/255 * 100);
  162. return "rgb(" + r + "%, " + g + "%, " + b + "%)";
  163. }
  164. function percentaString(rgba, alpha) {
  165. var r = Math.round(rgba[0]/255 * 100),
  166. g = Math.round(rgba[1]/255 * 100),
  167. b = Math.round(rgba[2]/255 * 100);
  168. return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";
  169. }
  170. function hslString(hsla, alpha) {
  171. if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {
  172. return hslaString(hsla, alpha);
  173. }
  174. return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";
  175. }
  176. function hslaString(hsla, alpha) {
  177. if (alpha === undefined) {
  178. alpha = (hsla[3] !== undefined ? hsla[3] : 1);
  179. }
  180. return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "
  181. + alpha + ")";
  182. }
  183. // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
  184. // (hwb have alpha optional & 1 is default value)
  185. function hwbString(hwb, alpha) {
  186. if (alpha === undefined) {
  187. alpha = (hwb[3] !== undefined ? hwb[3] : 1);
  188. }
  189. return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"
  190. + (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";
  191. }
  192. function keyword(rgb) {
  193. return reverseNames[rgb.slice(0, 3)];
  194. }
  195. // helpers
  196. function scale(num, min, max) {
  197. return Math.min(Math.max(min, num), max);
  198. }
  199. function hexDouble(num) {
  200. var str = num.toString(16).toUpperCase();
  201. return (str.length < 2) ? "0" + str : str;
  202. }
  203. //create a list of reverse color names
  204. var reverseNames = {};
  205. for (var name in colorNames) {
  206. reverseNames[colorNames[name]] = name;
  207. }
  208. },{"color-name":5}],2:[function(require,module,exports){
  209. /* MIT license */
  210. var convert = require('color-convert');
  211. var string = require('chartjs-color-string');
  212. var Color = function (obj) {
  213. if (obj instanceof Color) {
  214. return obj;
  215. }
  216. if (!(this instanceof Color)) {
  217. return new Color(obj);
  218. }
  219. this.values = {
  220. rgb: [0, 0, 0],
  221. hsl: [0, 0, 0],
  222. hsv: [0, 0, 0],
  223. hwb: [0, 0, 0],
  224. cmyk: [0, 0, 0, 0],
  225. alpha: 1
  226. };
  227. // parse Color() argument
  228. var vals;
  229. if (typeof obj === 'string') {
  230. vals = string.getRgba(obj);
  231. if (vals) {
  232. this.setValues('rgb', vals);
  233. } else if (vals = string.getHsla(obj)) {
  234. this.setValues('hsl', vals);
  235. } else if (vals = string.getHwb(obj)) {
  236. this.setValues('hwb', vals);
  237. } else {
  238. throw new Error('Unable to parse color from string "' + obj + '"');
  239. }
  240. } else if (typeof obj === 'object') {
  241. vals = obj;
  242. if (vals.r !== undefined || vals.red !== undefined) {
  243. this.setValues('rgb', vals);
  244. } else if (vals.l !== undefined || vals.lightness !== undefined) {
  245. this.setValues('hsl', vals);
  246. } else if (vals.v !== undefined || vals.value !== undefined) {
  247. this.setValues('hsv', vals);
  248. } else if (vals.w !== undefined || vals.whiteness !== undefined) {
  249. this.setValues('hwb', vals);
  250. } else if (vals.c !== undefined || vals.cyan !== undefined) {
  251. this.setValues('cmyk', vals);
  252. } else {
  253. throw new Error('Unable to parse color from object ' + JSON.stringify(obj));
  254. }
  255. }
  256. };
  257. Color.prototype = {
  258. rgb: function () {
  259. return this.setSpace('rgb', arguments);
  260. },
  261. hsl: function () {
  262. return this.setSpace('hsl', arguments);
  263. },
  264. hsv: function () {
  265. return this.setSpace('hsv', arguments);
  266. },
  267. hwb: function () {
  268. return this.setSpace('hwb', arguments);
  269. },
  270. cmyk: function () {
  271. return this.setSpace('cmyk', arguments);
  272. },
  273. rgbArray: function () {
  274. return this.values.rgb;
  275. },
  276. hslArray: function () {
  277. return this.values.hsl;
  278. },
  279. hsvArray: function () {
  280. return this.values.hsv;
  281. },
  282. hwbArray: function () {
  283. var values = this.values;
  284. if (values.alpha !== 1) {
  285. return values.hwb.concat([values.alpha]);
  286. }
  287. return values.hwb;
  288. },
  289. cmykArray: function () {
  290. return this.values.cmyk;
  291. },
  292. rgbaArray: function () {
  293. var values = this.values;
  294. return values.rgb.concat([values.alpha]);
  295. },
  296. hslaArray: function () {
  297. var values = this.values;
  298. return values.hsl.concat([values.alpha]);
  299. },
  300. alpha: function (val) {
  301. if (val === undefined) {
  302. return this.values.alpha;
  303. }
  304. this.setValues('alpha', val);
  305. return this;
  306. },
  307. red: function (val) {
  308. return this.setChannel('rgb', 0, val);
  309. },
  310. green: function (val) {
  311. return this.setChannel('rgb', 1, val);
  312. },
  313. blue: function (val) {
  314. return this.setChannel('rgb', 2, val);
  315. },
  316. hue: function (val) {
  317. if (val) {
  318. val %= 360;
  319. val = val < 0 ? 360 + val : val;
  320. }
  321. return this.setChannel('hsl', 0, val);
  322. },
  323. saturation: function (val) {
  324. return this.setChannel('hsl', 1, val);
  325. },
  326. lightness: function (val) {
  327. return this.setChannel('hsl', 2, val);
  328. },
  329. saturationv: function (val) {
  330. return this.setChannel('hsv', 1, val);
  331. },
  332. whiteness: function (val) {
  333. return this.setChannel('hwb', 1, val);
  334. },
  335. blackness: function (val) {
  336. return this.setChannel('hwb', 2, val);
  337. },
  338. value: function (val) {
  339. return this.setChannel('hsv', 2, val);
  340. },
  341. cyan: function (val) {
  342. return this.setChannel('cmyk', 0, val);
  343. },
  344. magenta: function (val) {
  345. return this.setChannel('cmyk', 1, val);
  346. },
  347. yellow: function (val) {
  348. return this.setChannel('cmyk', 2, val);
  349. },
  350. black: function (val) {
  351. return this.setChannel('cmyk', 3, val);
  352. },
  353. hexString: function () {
  354. return string.hexString(this.values.rgb);
  355. },
  356. rgbString: function () {
  357. return string.rgbString(this.values.rgb, this.values.alpha);
  358. },
  359. rgbaString: function () {
  360. return string.rgbaString(this.values.rgb, this.values.alpha);
  361. },
  362. percentString: function () {
  363. return string.percentString(this.values.rgb, this.values.alpha);
  364. },
  365. hslString: function () {
  366. return string.hslString(this.values.hsl, this.values.alpha);
  367. },
  368. hslaString: function () {
  369. return string.hslaString(this.values.hsl, this.values.alpha);
  370. },
  371. hwbString: function () {
  372. return string.hwbString(this.values.hwb, this.values.alpha);
  373. },
  374. keyword: function () {
  375. return string.keyword(this.values.rgb, this.values.alpha);
  376. },
  377. rgbNumber: function () {
  378. var rgb = this.values.rgb;
  379. return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
  380. },
  381. luminosity: function () {
  382. // http://www.w3.org/TR/WCAG20/#relativeluminancedef
  383. var rgb = this.values.rgb;
  384. var lum = [];
  385. for (var i = 0; i < rgb.length; i++) {
  386. var chan = rgb[i] / 255;
  387. lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);
  388. }
  389. return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
  390. },
  391. contrast: function (color2) {
  392. // http://www.w3.org/TR/WCAG20/#contrast-ratiodef
  393. var lum1 = this.luminosity();
  394. var lum2 = color2.luminosity();
  395. if (lum1 > lum2) {
  396. return (lum1 + 0.05) / (lum2 + 0.05);
  397. }
  398. return (lum2 + 0.05) / (lum1 + 0.05);
  399. },
  400. level: function (color2) {
  401. var contrastRatio = this.contrast(color2);
  402. if (contrastRatio >= 7.1) {
  403. return 'AAA';
  404. }
  405. return (contrastRatio >= 4.5) ? 'AA' : '';
  406. },
  407. dark: function () {
  408. // YIQ equation from http://24ways.org/2010/calculating-color-contrast
  409. var rgb = this.values.rgb;
  410. var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;
  411. return yiq < 128;
  412. },
  413. light: function () {
  414. return !this.dark();
  415. },
  416. negate: function () {
  417. var rgb = [];
  418. for (var i = 0; i < 3; i++) {
  419. rgb[i] = 255 - this.values.rgb[i];
  420. }
  421. this.setValues('rgb', rgb);
  422. return this;
  423. },
  424. lighten: function (ratio) {
  425. var hsl = this.values.hsl;
  426. hsl[2] += hsl[2] * ratio;
  427. this.setValues('hsl', hsl);
  428. return this;
  429. },
  430. darken: function (ratio) {
  431. var hsl = this.values.hsl;
  432. hsl[2] -= hsl[2] * ratio;
  433. this.setValues('hsl', hsl);
  434. return this;
  435. },
  436. saturate: function (ratio) {
  437. var hsl = this.values.hsl;
  438. hsl[1] += hsl[1] * ratio;
  439. this.setValues('hsl', hsl);
  440. return this;
  441. },
  442. desaturate: function (ratio) {
  443. var hsl = this.values.hsl;
  444. hsl[1] -= hsl[1] * ratio;
  445. this.setValues('hsl', hsl);
  446. return this;
  447. },
  448. whiten: function (ratio) {
  449. var hwb = this.values.hwb;
  450. hwb[1] += hwb[1] * ratio;
  451. this.setValues('hwb', hwb);
  452. return this;
  453. },
  454. blacken: function (ratio) {
  455. var hwb = this.values.hwb;
  456. hwb[2] += hwb[2] * ratio;
  457. this.setValues('hwb', hwb);
  458. return this;
  459. },
  460. greyscale: function () {
  461. var rgb = this.values.rgb;
  462. // http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
  463. var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
  464. this.setValues('rgb', [val, val, val]);
  465. return this;
  466. },
  467. clearer: function (ratio) {
  468. var alpha = this.values.alpha;
  469. this.setValues('alpha', alpha - (alpha * ratio));
  470. return this;
  471. },
  472. opaquer: function (ratio) {
  473. var alpha = this.values.alpha;
  474. this.setValues('alpha', alpha + (alpha * ratio));
  475. return this;
  476. },
  477. rotate: function (degrees) {
  478. var hsl = this.values.hsl;
  479. var hue = (hsl[0] + degrees) % 360;
  480. hsl[0] = hue < 0 ? 360 + hue : hue;
  481. this.setValues('hsl', hsl);
  482. return this;
  483. },
  484. /**
  485. * Ported from sass implementation in C
  486. * https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
  487. */
  488. mix: function (mixinColor, weight) {
  489. var color1 = this;
  490. var color2 = mixinColor;
  491. var p = weight === undefined ? 0.5 : weight;
  492. var w = 2 * p - 1;
  493. var a = color1.alpha() - color2.alpha();
  494. var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
  495. var w2 = 1 - w1;
  496. return this
  497. .rgb(
  498. w1 * color1.red() + w2 * color2.red(),
  499. w1 * color1.green() + w2 * color2.green(),
  500. w1 * color1.blue() + w2 * color2.blue()
  501. )
  502. .alpha(color1.alpha() * p + color2.alpha() * (1 - p));
  503. },
  504. toJSON: function () {
  505. return this.rgb();
  506. },
  507. clone: function () {
  508. // NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,
  509. // making the final build way to big to embed in Chart.js. So let's do it manually,
  510. // assuming that values to clone are 1 dimension arrays containing only numbers,
  511. // except 'alpha' which is a number.
  512. var result = new Color();
  513. var source = this.values;
  514. var target = result.values;
  515. var value, type;
  516. for (var prop in source) {
  517. if (source.hasOwnProperty(prop)) {
  518. value = source[prop];
  519. type = ({}).toString.call(value);
  520. if (type === '[object Array]') {
  521. target[prop] = value.slice(0);
  522. } else if (type === '[object Number]') {
  523. target[prop] = value;
  524. } else {
  525. console.error('unexpected color value:', value);
  526. }
  527. }
  528. }
  529. return result;
  530. }
  531. };
  532. Color.prototype.spaces = {
  533. rgb: ['red', 'green', 'blue'],
  534. hsl: ['hue', 'saturation', 'lightness'],
  535. hsv: ['hue', 'saturation', 'value'],
  536. hwb: ['hue', 'whiteness', 'blackness'],
  537. cmyk: ['cyan', 'magenta', 'yellow', 'black']
  538. };
  539. Color.prototype.maxes = {
  540. rgb: [255, 255, 255],
  541. hsl: [360, 100, 100],
  542. hsv: [360, 100, 100],
  543. hwb: [360, 100, 100],
  544. cmyk: [100, 100, 100, 100]
  545. };
  546. Color.prototype.getValues = function (space) {
  547. var values = this.values;
  548. var vals = {};
  549. for (var i = 0; i < space.length; i++) {
  550. vals[space.charAt(i)] = values[space][i];
  551. }
  552. if (values.alpha !== 1) {
  553. vals.a = values.alpha;
  554. }
  555. // {r: 255, g: 255, b: 255, a: 0.4}
  556. return vals;
  557. };
  558. Color.prototype.setValues = function (space, vals) {
  559. var values = this.values;
  560. var spaces = this.spaces;
  561. var maxes = this.maxes;
  562. var alpha = 1;
  563. var i;
  564. if (space === 'alpha') {
  565. alpha = vals;
  566. } else if (vals.length) {
  567. // [10, 10, 10]
  568. values[space] = vals.slice(0, space.length);
  569. alpha = vals[space.length];
  570. } else if (vals[space.charAt(0)] !== undefined) {
  571. // {r: 10, g: 10, b: 10}
  572. for (i = 0; i < space.length; i++) {
  573. values[space][i] = vals[space.charAt(i)];
  574. }
  575. alpha = vals.a;
  576. } else if (vals[spaces[space][0]] !== undefined) {
  577. // {red: 10, green: 10, blue: 10}
  578. var chans = spaces[space];
  579. for (i = 0; i < space.length; i++) {
  580. values[space][i] = vals[chans[i]];
  581. }
  582. alpha = vals.alpha;
  583. }
  584. values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));
  585. if (space === 'alpha') {
  586. return false;
  587. }
  588. var capped;
  589. // cap values of the space prior converting all values
  590. for (i = 0; i < space.length; i++) {
  591. capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));
  592. values[space][i] = Math.round(capped);
  593. }
  594. // convert to all the other color spaces
  595. for (var sname in spaces) {
  596. if (sname !== space) {
  597. values[sname] = convert[space][sname](values[space]);
  598. }
  599. }
  600. return true;
  601. };
  602. Color.prototype.setSpace = function (space, args) {
  603. var vals = args[0];
  604. if (vals === undefined) {
  605. // color.rgb()
  606. return this.getValues(space);
  607. }
  608. // color.rgb(10, 10, 10)
  609. if (typeof vals === 'number') {
  610. vals = Array.prototype.slice.call(args);
  611. }
  612. this.setValues(space, vals);
  613. return this;
  614. };
  615. Color.prototype.setChannel = function (space, index, val) {
  616. var svalues = this.values[space];
  617. if (val === undefined) {
  618. // color.red()
  619. return svalues[index];
  620. } else if (val === svalues[index]) {
  621. // color.red(color.red())
  622. return this;
  623. }
  624. // color.red(100)
  625. svalues[index] = val;
  626. this.setValues(space, svalues);
  627. return this;
  628. };
  629. if (typeof window !== 'undefined') {
  630. window.Color = Color;
  631. }
  632. module.exports = Color;
  633. },{"chartjs-color-string":1,"color-convert":4}],3:[function(require,module,exports){
  634. /* MIT license */
  635. module.exports = {
  636. rgb2hsl: rgb2hsl,
  637. rgb2hsv: rgb2hsv,
  638. rgb2hwb: rgb2hwb,
  639. rgb2cmyk: rgb2cmyk,
  640. rgb2keyword: rgb2keyword,
  641. rgb2xyz: rgb2xyz,
  642. rgb2lab: rgb2lab,
  643. rgb2lch: rgb2lch,
  644. hsl2rgb: hsl2rgb,
  645. hsl2hsv: hsl2hsv,
  646. hsl2hwb: hsl2hwb,
  647. hsl2cmyk: hsl2cmyk,
  648. hsl2keyword: hsl2keyword,
  649. hsv2rgb: hsv2rgb,
  650. hsv2hsl: hsv2hsl,
  651. hsv2hwb: hsv2hwb,
  652. hsv2cmyk: hsv2cmyk,
  653. hsv2keyword: hsv2keyword,
  654. hwb2rgb: hwb2rgb,
  655. hwb2hsl: hwb2hsl,
  656. hwb2hsv: hwb2hsv,
  657. hwb2cmyk: hwb2cmyk,
  658. hwb2keyword: hwb2keyword,
  659. cmyk2rgb: cmyk2rgb,
  660. cmyk2hsl: cmyk2hsl,
  661. cmyk2hsv: cmyk2hsv,
  662. cmyk2hwb: cmyk2hwb,
  663. cmyk2keyword: cmyk2keyword,
  664. keyword2rgb: keyword2rgb,
  665. keyword2hsl: keyword2hsl,
  666. keyword2hsv: keyword2hsv,
  667. keyword2hwb: keyword2hwb,
  668. keyword2cmyk: keyword2cmyk,
  669. keyword2lab: keyword2lab,
  670. keyword2xyz: keyword2xyz,
  671. xyz2rgb: xyz2rgb,
  672. xyz2lab: xyz2lab,
  673. xyz2lch: xyz2lch,
  674. lab2xyz: lab2xyz,
  675. lab2rgb: lab2rgb,
  676. lab2lch: lab2lch,
  677. lch2lab: lch2lab,
  678. lch2xyz: lch2xyz,
  679. lch2rgb: lch2rgb
  680. }
  681. function rgb2hsl(rgb) {
  682. var r = rgb[0]/255,
  683. g = rgb[1]/255,
  684. b = rgb[2]/255,
  685. min = Math.min(r, g, b),
  686. max = Math.max(r, g, b),
  687. delta = max - min,
  688. h, s, l;
  689. if (max == min)
  690. h = 0;
  691. else if (r == max)
  692. h = (g - b) / delta;
  693. else if (g == max)
  694. h = 2 + (b - r) / delta;
  695. else if (b == max)
  696. h = 4 + (r - g)/ delta;
  697. h = Math.min(h * 60, 360);
  698. if (h < 0)
  699. h += 360;
  700. l = (min + max) / 2;
  701. if (max == min)
  702. s = 0;
  703. else if (l <= 0.5)
  704. s = delta / (max + min);
  705. else
  706. s = delta / (2 - max - min);
  707. return [h, s * 100, l * 100];
  708. }
  709. function rgb2hsv(rgb) {
  710. var r = rgb[0],
  711. g = rgb[1],
  712. b = rgb[2],
  713. min = Math.min(r, g, b),
  714. max = Math.max(r, g, b),
  715. delta = max - min,
  716. h, s, v;
  717. if (max == 0)
  718. s = 0;
  719. else
  720. s = (delta/max * 1000)/10;
  721. if (max == min)
  722. h = 0;
  723. else if (r == max)
  724. h = (g - b) / delta;
  725. else if (g == max)
  726. h = 2 + (b - r) / delta;
  727. else if (b == max)
  728. h = 4 + (r - g) / delta;
  729. h = Math.min(h * 60, 360);
  730. if (h < 0)
  731. h += 360;
  732. v = ((max / 255) * 1000) / 10;
  733. return [h, s, v];
  734. }
  735. function rgb2hwb(rgb) {
  736. var r = rgb[0],
  737. g = rgb[1],
  738. b = rgb[2],
  739. h = rgb2hsl(rgb)[0],
  740. w = 1/255 * Math.min(r, Math.min(g, b)),
  741. b = 1 - 1/255 * Math.max(r, Math.max(g, b));
  742. return [h, w * 100, b * 100];
  743. }
  744. function rgb2cmyk(rgb) {
  745. var r = rgb[0] / 255,
  746. g = rgb[1] / 255,
  747. b = rgb[2] / 255,
  748. c, m, y, k;
  749. k = Math.min(1 - r, 1 - g, 1 - b);
  750. c = (1 - r - k) / (1 - k) || 0;
  751. m = (1 - g - k) / (1 - k) || 0;
  752. y = (1 - b - k) / (1 - k) || 0;
  753. return [c * 100, m * 100, y * 100, k * 100];
  754. }
  755. function rgb2keyword(rgb) {
  756. return reverseKeywords[JSON.stringify(rgb)];
  757. }
  758. function rgb2xyz(rgb) {
  759. var r = rgb[0] / 255,
  760. g = rgb[1] / 255,
  761. b = rgb[2] / 255;
  762. // assume sRGB
  763. r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);
  764. g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);
  765. b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);
  766. var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
  767. var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
  768. var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
  769. return [x * 100, y *100, z * 100];
  770. }
  771. function rgb2lab(rgb) {
  772. var xyz = rgb2xyz(rgb),
  773. x = xyz[0],
  774. y = xyz[1],
  775. z = xyz[2],
  776. l, a, b;
  777. x /= 95.047;
  778. y /= 100;
  779. z /= 108.883;
  780. x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
  781. y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
  782. z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
  783. l = (116 * y) - 16;
  784. a = 500 * (x - y);
  785. b = 200 * (y - z);
  786. return [l, a, b];
  787. }
  788. function rgb2lch(args) {
  789. return lab2lch(rgb2lab(args));
  790. }
  791. function hsl2rgb(hsl) {
  792. var h = hsl[0] / 360,
  793. s = hsl[1] / 100,
  794. l = hsl[2] / 100,
  795. t1, t2, t3, rgb, val;
  796. if (s == 0) {
  797. val = l * 255;
  798. return [val, val, val];
  799. }
  800. if (l < 0.5)
  801. t2 = l * (1 + s);
  802. else
  803. t2 = l + s - l * s;
  804. t1 = 2 * l - t2;
  805. rgb = [0, 0, 0];
  806. for (var i = 0; i < 3; i++) {
  807. t3 = h + 1 / 3 * - (i - 1);
  808. t3 < 0 && t3++;
  809. t3 > 1 && t3--;
  810. if (6 * t3 < 1)
  811. val = t1 + (t2 - t1) * 6 * t3;
  812. else if (2 * t3 < 1)
  813. val = t2;
  814. else if (3 * t3 < 2)
  815. val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
  816. else
  817. val = t1;
  818. rgb[i] = val * 255;
  819. }
  820. return rgb;
  821. }
  822. function hsl2hsv(hsl) {
  823. var h = hsl[0],
  824. s = hsl[1] / 100,
  825. l = hsl[2] / 100,
  826. sv, v;
  827. if(l === 0) {
  828. // no need to do calc on black
  829. // also avoids divide by 0 error
  830. return [0, 0, 0];
  831. }
  832. l *= 2;
  833. s *= (l <= 1) ? l : 2 - l;
  834. v = (l + s) / 2;
  835. sv = (2 * s) / (l + s);
  836. return [h, sv * 100, v * 100];
  837. }
  838. function hsl2hwb(args) {
  839. return rgb2hwb(hsl2rgb(args));
  840. }
  841. function hsl2cmyk(args) {
  842. return rgb2cmyk(hsl2rgb(args));
  843. }
  844. function hsl2keyword(args) {
  845. return rgb2keyword(hsl2rgb(args));
  846. }
  847. function hsv2rgb(hsv) {
  848. var h = hsv[0] / 60,
  849. s = hsv[1] / 100,
  850. v = hsv[2] / 100,
  851. hi = Math.floor(h) % 6;
  852. var f = h - Math.floor(h),
  853. p = 255 * v * (1 - s),
  854. q = 255 * v * (1 - (s * f)),
  855. t = 255 * v * (1 - (s * (1 - f))),
  856. v = 255 * v;
  857. switch(hi) {
  858. case 0:
  859. return [v, t, p];
  860. case 1:
  861. return [q, v, p];
  862. case 2:
  863. return [p, v, t];
  864. case 3:
  865. return [p, q, v];
  866. case 4:
  867. return [t, p, v];
  868. case 5:
  869. return [v, p, q];
  870. }
  871. }
  872. function hsv2hsl(hsv) {
  873. var h = hsv[0],
  874. s = hsv[1] / 100,
  875. v = hsv[2] / 100,
  876. sl, l;
  877. l = (2 - s) * v;
  878. sl = s * v;
  879. sl /= (l <= 1) ? l : 2 - l;
  880. sl = sl || 0;
  881. l /= 2;
  882. return [h, sl * 100, l * 100];
  883. }
  884. function hsv2hwb(args) {
  885. return rgb2hwb(hsv2rgb(args))
  886. }
  887. function hsv2cmyk(args) {
  888. return rgb2cmyk(hsv2rgb(args));
  889. }
  890. function hsv2keyword(args) {
  891. return rgb2keyword(hsv2rgb(args));
  892. }
  893. // http://dev.w3.org/csswg/css-color/#hwb-to-rgb
  894. function hwb2rgb(hwb) {
  895. var h = hwb[0] / 360,
  896. wh = hwb[1] / 100,
  897. bl = hwb[2] / 100,
  898. ratio = wh + bl,
  899. i, v, f, n;
  900. // wh + bl cant be > 1
  901. if (ratio > 1) {
  902. wh /= ratio;
  903. bl /= ratio;
  904. }
  905. i = Math.floor(6 * h);
  906. v = 1 - bl;
  907. f = 6 * h - i;
  908. if ((i & 0x01) != 0) {
  909. f = 1 - f;
  910. }
  911. n = wh + f * (v - wh); // linear interpolation
  912. switch (i) {
  913. default:
  914. case 6:
  915. case 0: r = v; g = n; b = wh; break;
  916. case 1: r = n; g = v; b = wh; break;
  917. case 2: r = wh; g = v; b = n; break;
  918. case 3: r = wh; g = n; b = v; break;
  919. case 4: r = n; g = wh; b = v; break;
  920. case 5: r = v; g = wh; b = n; break;
  921. }
  922. return [r * 255, g * 255, b * 255];
  923. }
  924. function hwb2hsl(args) {
  925. return rgb2hsl(hwb2rgb(args));
  926. }
  927. function hwb2hsv(args) {
  928. return rgb2hsv(hwb2rgb(args));
  929. }
  930. function hwb2cmyk(args) {
  931. return rgb2cmyk(hwb2rgb(args));
  932. }
  933. function hwb2keyword(args) {
  934. return rgb2keyword(hwb2rgb(args));
  935. }
  936. function cmyk2rgb(cmyk) {
  937. var c = cmyk[0] / 100,
  938. m = cmyk[1] / 100,
  939. y = cmyk[2] / 100,
  940. k = cmyk[3] / 100,
  941. r, g, b;
  942. r = 1 - Math.min(1, c * (1 - k) + k);
  943. g = 1 - Math.min(1, m * (1 - k) + k);
  944. b = 1 - Math.min(1, y * (1 - k) + k);
  945. return [r * 255, g * 255, b * 255];
  946. }
  947. function cmyk2hsl(args) {
  948. return rgb2hsl(cmyk2rgb(args));
  949. }
  950. function cmyk2hsv(args) {
  951. return rgb2hsv(cmyk2rgb(args));
  952. }
  953. function cmyk2hwb(args) {
  954. return rgb2hwb(cmyk2rgb(args));
  955. }
  956. function cmyk2keyword(args) {
  957. return rgb2keyword(cmyk2rgb(args));
  958. }
  959. function xyz2rgb(xyz) {
  960. var x = xyz[0] / 100,
  961. y = xyz[1] / 100,
  962. z = xyz[2] / 100,
  963. r, g, b;
  964. r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
  965. g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
  966. b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
  967. // assume sRGB
  968. r = r > 0.0031308 ? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)
  969. : r = (r * 12.92);
  970. g = g > 0.0031308 ? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)
  971. : g = (g * 12.92);
  972. b = b > 0.0031308 ? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)
  973. : b = (b * 12.92);
  974. r = Math.min(Math.max(0, r), 1);
  975. g = Math.min(Math.max(0, g), 1);
  976. b = Math.min(Math.max(0, b), 1);
  977. return [r * 255, g * 255, b * 255];
  978. }
  979. function xyz2lab(xyz) {
  980. var x = xyz[0],
  981. y = xyz[1],
  982. z = xyz[2],
  983. l, a, b;
  984. x /= 95.047;
  985. y /= 100;
  986. z /= 108.883;
  987. x = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x) + (16 / 116);
  988. y = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y) + (16 / 116);
  989. z = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z) + (16 / 116);
  990. l = (116 * y) - 16;
  991. a = 500 * (x - y);
  992. b = 200 * (y - z);
  993. return [l, a, b];
  994. }
  995. function xyz2lch(args) {
  996. return lab2lch(xyz2lab(args));
  997. }
  998. function lab2xyz(lab) {
  999. var l = lab[0],
  1000. a = lab[1],
  1001. b = lab[2],
  1002. x, y, z, y2;
  1003. if (l <= 8) {
  1004. y = (l * 100) / 903.3;
  1005. y2 = (7.787 * (y / 100)) + (16 / 116);
  1006. } else {
  1007. y = 100 * Math.pow((l + 16) / 116, 3);
  1008. y2 = Math.pow(y / 100, 1/3);
  1009. }
  1010. x = x / 95.047 <= 0.008856 ? x = (95.047 * ((a / 500) + y2 - (16 / 116))) / 7.787 : 95.047 * Math.pow((a / 500) + y2, 3);
  1011. z = z / 108.883 <= 0.008859 ? z = (108.883 * (y2 - (b / 200) - (16 / 116))) / 7.787 : 108.883 * Math.pow(y2 - (b / 200), 3);
  1012. return [x, y, z];
  1013. }
  1014. function lab2lch(lab) {
  1015. var l = lab[0],
  1016. a = lab[1],
  1017. b = lab[2],
  1018. hr, h, c;
  1019. hr = Math.atan2(b, a);
  1020. h = hr * 360 / 2 / Math.PI;
  1021. if (h < 0) {
  1022. h += 360;
  1023. }
  1024. c = Math.sqrt(a * a + b * b);
  1025. return [l, c, h];
  1026. }
  1027. function lab2rgb(args) {
  1028. return xyz2rgb(lab2xyz(args));
  1029. }
  1030. function lch2lab(lch) {
  1031. var l = lch[0],
  1032. c = lch[1],
  1033. h = lch[2],
  1034. a, b, hr;
  1035. hr = h / 360 * 2 * Math.PI;
  1036. a = c * Math.cos(hr);
  1037. b = c * Math.sin(hr);
  1038. return [l, a, b];
  1039. }
  1040. function lch2xyz(args) {
  1041. return lab2xyz(lch2lab(args));
  1042. }
  1043. function lch2rgb(args) {
  1044. return lab2rgb(lch2lab(args));
  1045. }
  1046. function keyword2rgb(keyword) {
  1047. return cssKeywords[keyword];
  1048. }
  1049. function keyword2hsl(args) {
  1050. return rgb2hsl(keyword2rgb(args));
  1051. }
  1052. function keyword2hsv(args) {
  1053. return rgb2hsv(keyword2rgb(args));
  1054. }
  1055. function keyword2hwb(args) {
  1056. return rgb2hwb(keyword2rgb(args));
  1057. }
  1058. function keyword2cmyk(args) {
  1059. return rgb2cmyk(keyword2rgb(args));
  1060. }
  1061. function keyword2lab(args) {
  1062. return rgb2lab(keyword2rgb(args));
  1063. }
  1064. function keyword2xyz(args) {
  1065. return rgb2xyz(keyword2rgb(args));
  1066. }
  1067. var cssKeywords = {
  1068. aliceblue: [240,248,255],
  1069. antiquewhite: [250,235,215],
  1070. aqua: [0,255,255],
  1071. aquamarine: [127,255,212],
  1072. azure: [240,255,255],
  1073. beige: [245,245,220],
  1074. bisque: [255,228,196],
  1075. black: [0,0,0],
  1076. blanchedalmond: [255,235,205],
  1077. blue: [0,0,255],
  1078. blueviolet: [138,43,226],
  1079. brown: [165,42,42],
  1080. burlywood: [222,184,135],
  1081. cadetblue: [95,158,160],
  1082. chartreuse: [127,255,0],
  1083. chocolate: [210,105,30],
  1084. coral: [255,127,80],
  1085. cornflowerblue: [100,149,237],
  1086. cornsilk: [255,248,220],
  1087. crimson: [220,20,60],
  1088. cyan: [0,255,255],
  1089. darkblue: [0,0,139],
  1090. darkcyan: [0,139,139],
  1091. darkgoldenrod: [184,134,11],
  1092. darkgray: [169,169,169],
  1093. darkgreen: [0,100,0],
  1094. darkgrey: [169,169,169],
  1095. darkkhaki: [189,183,107],
  1096. darkmagenta: [139,0,139],
  1097. darkolivegreen: [85,107,47],
  1098. darkorange: [255,140,0],
  1099. darkorchid: [153,50,204],
  1100. darkred: [139,0,0],
  1101. darksalmon: [233,150,122],
  1102. darkseagreen: [143,188,143],
  1103. darkslateblue: [72,61,139],
  1104. darkslategray: [47,79,79],
  1105. darkslategrey: [47,79,79],
  1106. darkturquoise: [0,206,209],
  1107. darkviolet: [148,0,211],
  1108. deeppink: [255,20,147],
  1109. deepskyblue: [0,191,255],
  1110. dimgray: [105,105,105],
  1111. dimgrey: [105,105,105],
  1112. dodgerblue: [30,144,255],
  1113. firebrick: [178,34,34],
  1114. floralwhite: [255,250,240],
  1115. forestgreen: [34,139,34],
  1116. fuchsia: [255,0,255],
  1117. gainsboro: [220,220,220],
  1118. ghostwhite: [248,248,255],
  1119. gold: [255,215,0],
  1120. goldenrod: [218,165,32],
  1121. gray: [128,128,128],
  1122. green: [0,128,0],
  1123. greenyellow: [173,255,47],
  1124. grey: [128,128,128],
  1125. honeydew: [240,255,240],
  1126. hotpink: [255,105,180],
  1127. indianred: [205,92,92],
  1128. indigo: [75,0,130],
  1129. ivory: [255,255,240],
  1130. khaki: [240,230,140],
  1131. lavender: [230,230,250],
  1132. lavenderblush: [255,240,245],
  1133. lawngreen: [124,252,0],
  1134. lemonchiffon: [255,250,205],
  1135. lightblue: [173,216,230],
  1136. lightcoral: [240,128,128],
  1137. lightcyan: [224,255,255],
  1138. lightgoldenrodyellow: [250,250,210],
  1139. lightgray: [211,211,211],
  1140. lightgreen: [144,238,144],
  1141. lightgrey: [211,211,211],
  1142. lightpink: [255,182,193],
  1143. lightsalmon: [255,160,122],
  1144. lightseagreen: [32,178,170],
  1145. lightskyblue: [135,206,250],
  1146. lightslategray: [119,136,153],
  1147. lightslategrey: [119,136,153],
  1148. lightsteelblue: [176,196,222],
  1149. lightyellow: [255,255,224],
  1150. lime: [0,255,0],
  1151. limegreen: [50,205,50],
  1152. linen: [250,240,230],
  1153. magenta: [255,0,255],
  1154. maroon: [128,0,0],
  1155. mediumaquamarine: [102,205,170],
  1156. mediumblue: [0,0,205],
  1157. mediumorchid: [186,85,211],
  1158. mediumpurple: [147,112,219],
  1159. mediumseagreen: [60,179,113],
  1160. mediumslateblue: [123,104,238],
  1161. mediumspringgreen: [0,250,154],
  1162. mediumturquoise: [72,209,204],
  1163. mediumvioletred: [199,21,133],
  1164. midnightblue: [25,25,112],
  1165. mintcream: [245,255,250],
  1166. mistyrose: [255,228,225],
  1167. moccasin: [255,228,181],
  1168. navajowhite: [255,222,173],
  1169. navy: [0,0,128],
  1170. oldlace: [253,245,230],
  1171. olive: [128,128,0],
  1172. olivedrab: [107,142,35],
  1173. orange: [255,165,0],
  1174. orangered: [255,69,0],
  1175. orchid: [218,112,214],
  1176. palegoldenrod: [238,232,170],
  1177. palegreen: [152,251,152],
  1178. paleturquoise: [175,238,238],
  1179. palevioletred: [219,112,147],
  1180. papayawhip: [255,239,213],
  1181. peachpuff: [255,218,185],
  1182. peru: [205,133,63],
  1183. pink: [255,192,203],
  1184. plum: [221,160,221],
  1185. powderblue: [176,224,230],
  1186. purple: [128,0,128],
  1187. rebeccapurple: [102, 51, 153],
  1188. red: [255,0,0],
  1189. rosybrown: [188,143,143],
  1190. royalblue: [65,105,225],
  1191. saddlebrown: [139,69,19],
  1192. salmon: [250,128,114],
  1193. sandybrown: [244,164,96],
  1194. seagreen: [46,139,87],
  1195. seashell: [255,245,238],
  1196. sienna: [160,82,45],
  1197. silver: [192,192,192],
  1198. skyblue: [135,206,235],
  1199. slateblue: [106,90,205],
  1200. slategray: [112,128,144],
  1201. slategrey: [112,128,144],
  1202. snow: [255,250,250],
  1203. springgreen: [0,255,127],
  1204. steelblue: [70,130,180],
  1205. tan: [210,180,140],
  1206. teal: [0,128,128],
  1207. thistle: [216,191,216],
  1208. tomato: [255,99,71],
  1209. turquoise: [64,224,208],
  1210. violet: [238,130,238],
  1211. wheat: [245,222,179],
  1212. white: [255,255,255],
  1213. whitesmoke: [245,245,245],
  1214. yellow: [255,255,0],
  1215. yellowgreen: [154,205,50]
  1216. };
  1217. var reverseKeywords = {};
  1218. for (var key in cssKeywords) {
  1219. reverseKeywords[JSON.stringify(cssKeywords[key])] = key;
  1220. }
  1221. },{}],4:[function(require,module,exports){
  1222. var conversions = require("./conversions");
  1223. var convert = function() {
  1224. return new Converter();
  1225. }
  1226. for (var func in conversions) {
  1227. // export Raw versions
  1228. convert[func + "Raw"] = (function(func) {
  1229. // accept array or plain args
  1230. return function(arg) {
  1231. if (typeof arg == "number")
  1232. arg = Array.prototype.slice.call(arguments);
  1233. return conversions[func](arg);
  1234. }
  1235. })(func);
  1236. var pair = /(\w+)2(\w+)/.exec(func),
  1237. from = pair[1],
  1238. to = pair[2];
  1239. // export rgb2hsl and ["rgb"]["hsl"]
  1240. convert[from] = convert[from] || {};
  1241. convert[from][to] = convert[func] = (function(func) {
  1242. return function(arg) {
  1243. if (typeof arg == "number")
  1244. arg = Array.prototype.slice.call(arguments);
  1245. var val = conversions[func](arg);
  1246. if (typeof val == "string" || val === undefined)
  1247. return val; // keyword
  1248. for (var i = 0; i < val.length; i++)
  1249. val[i] = Math.round(val[i]);
  1250. return val;
  1251. }
  1252. })(func);
  1253. }
  1254. /* Converter does lazy conversion and caching */
  1255. var Converter = function() {
  1256. this.convs = {};
  1257. };
  1258. /* Either get the values for a space or
  1259. set the values for a space, depending on args */
  1260. Converter.prototype.routeSpace = function(space, args) {
  1261. var values = args[0];
  1262. if (values === undefined) {
  1263. // color.rgb()
  1264. return this.getValues(space);
  1265. }
  1266. // color.rgb(10, 10, 10)
  1267. if (typeof values == "number") {
  1268. values = Array.prototype.slice.call(args);
  1269. }
  1270. return this.setValues(space, values);
  1271. };
  1272. /* Set the values for a space, invalidating cache */
  1273. Converter.prototype.setValues = function(space, values) {
  1274. this.space = space;
  1275. this.convs = {};
  1276. this.convs[space] = values;
  1277. return this;
  1278. };
  1279. /* Get the values for a space. If there's already
  1280. a conversion for the space, fetch it, otherwise
  1281. compute it */
  1282. Converter.prototype.getValues = function(space) {
  1283. var vals = this.convs[space];
  1284. if (!vals) {
  1285. var fspace = this.space,
  1286. from = this.convs[fspace];
  1287. vals = convert[fspace][space](from);
  1288. this.convs[space] = vals;
  1289. }
  1290. return vals;
  1291. };
  1292. ["rgb", "hsl", "hsv", "cmyk", "keyword"].forEach(function(space) {
  1293. Converter.prototype[space] = function(vals) {
  1294. return this.routeSpace(space, arguments);
  1295. }
  1296. });
  1297. module.exports = convert;
  1298. },{"./conversions":3}],5:[function(require,module,exports){
  1299. module.exports = {
  1300. "aliceblue": [240, 248, 255],
  1301. "antiquewhite": [250, 235, 215],
  1302. "aqua": [0, 255, 255],
  1303. "aquamarine": [127, 255, 212],
  1304. "azure": [240, 255, 255],
  1305. "beige": [245, 245, 220],
  1306. "bisque": [255, 228, 196],
  1307. "black": [0, 0, 0],
  1308. "blanchedalmond": [255, 235, 205],
  1309. "blue": [0, 0, 255],
  1310. "blueviolet": [138, 43, 226],
  1311. "brown": [165, 42, 42],
  1312. "burlywood": [222, 184, 135],
  1313. "cadetblue": [95, 158, 160],
  1314. "chartreuse": [127, 255, 0],
  1315. "chocolate": [210, 105, 30],
  1316. "coral": [255, 127, 80],
  1317. "cornflowerblue": [100, 149, 237],
  1318. "cornsilk": [255, 248, 220],
  1319. "crimson": [220, 20, 60],
  1320. "cyan": [0, 255, 255],
  1321. "darkblue": [0, 0, 139],
  1322. "darkcyan": [0, 139, 139],
  1323. "darkgoldenrod": [184, 134, 11],
  1324. "darkgray": [169, 169, 169],
  1325. "darkgreen": [0, 100, 0],
  1326. "darkgrey": [169, 169, 169],
  1327. "darkkhaki": [189, 183, 107],
  1328. "darkmagenta": [139, 0, 139],
  1329. "darkolivegreen": [85, 107, 47],
  1330. "darkorange": [255, 140, 0],
  1331. "darkorchid": [153, 50, 204],
  1332. "darkred": [139, 0, 0],
  1333. "darksalmon": [233, 150, 122],
  1334. "darkseagreen": [143, 188, 143],
  1335. "darkslateblue": [72, 61, 139],
  1336. "darkslategray": [47, 79, 79],
  1337. "darkslategrey": [47, 79, 79],
  1338. "darkturquoise": [0, 206, 209],
  1339. "darkviolet": [148, 0, 211],
  1340. "deeppink": [255, 20, 147],
  1341. "deepskyblue": [0, 191, 255],
  1342. "dimgray": [105, 105, 105],
  1343. "dimgrey": [105, 105, 105],
  1344. "dodgerblue": [30, 144, 255],
  1345. "firebrick": [178, 34, 34],
  1346. "floralwhite": [255, 250, 240],
  1347. "forestgreen": [34, 139, 34],
  1348. "fuchsia": [255, 0, 255],
  1349. "gainsboro": [220, 220, 220],
  1350. "ghostwhite": [248, 248, 255],
  1351. "gold": [255, 215, 0],
  1352. "goldenrod": [218, 165, 32],
  1353. "gray": [128, 128, 128],
  1354. "green": [0, 128, 0],
  1355. "greenyellow": [173, 255, 47],
  1356. "grey": [128, 128, 128],
  1357. "honeydew": [240, 255, 240],
  1358. "hotpink": [255, 105, 180],
  1359. "indianred": [205, 92, 92],
  1360. "indigo": [75, 0, 130],
  1361. "ivory": [255, 255, 240],
  1362. "khaki": [240, 230, 140],
  1363. "lavender": [230, 230, 250],
  1364. "lavenderblush": [255, 240, 245],
  1365. "lawngreen": [124, 252, 0],
  1366. "lemonchiffon": [255, 250, 205],
  1367. "lightblue": [173, 216, 230],
  1368. "lightcoral": [240, 128, 128],
  1369. "lightcyan": [224, 255, 255],
  1370. "lightgoldenrodyellow": [250, 250, 210],
  1371. "lightgray": [211, 211, 211],
  1372. "lightgreen": [144, 238, 144],
  1373. "lightgrey": [211, 211, 211],
  1374. "lightpink": [255, 182, 193],
  1375. "lightsalmon": [255, 160, 122],
  1376. "lightseagreen": [32, 178, 170],
  1377. "lightskyblue": [135, 206, 250],
  1378. "lightslategray": [119, 136, 153],
  1379. "lightslategrey": [119, 136, 153],
  1380. "lightsteelblue": [176, 196, 222],
  1381. "lightyellow": [255, 255, 224],
  1382. "lime": [0, 255, 0],
  1383. "limegreen": [50, 205, 50],
  1384. "linen": [250, 240, 230],
  1385. "magenta": [255, 0, 255],
  1386. "maroon": [128, 0, 0],
  1387. "mediumaquamarine": [102, 205, 170],
  1388. "mediumblue": [0, 0, 205],
  1389. "mediumorchid": [186, 85, 211],
  1390. "mediumpurple": [147, 112, 219],
  1391. "mediumseagreen": [60, 179, 113],
  1392. "mediumslateblue": [123, 104, 238],
  1393. "mediumspringgreen": [0, 250, 154],
  1394. "mediumturquoise": [72, 209, 204],
  1395. "mediumvioletred": [199, 21, 133],
  1396. "midnightblue": [25, 25, 112],
  1397. "mintcream": [245, 255, 250],
  1398. "mistyrose": [255, 228, 225],
  1399. "moccasin": [255, 228, 181],
  1400. "navajowhite": [255, 222, 173],
  1401. "navy": [0, 0, 128],
  1402. "oldlace": [253, 245, 230],
  1403. "olive": [128, 128, 0],
  1404. "olivedrab": [107, 142, 35],
  1405. "orange": [255, 165, 0],
  1406. "orangered": [255, 69, 0],
  1407. "orchid": [218, 112, 214],
  1408. "palegoldenrod": [238, 232, 170],
  1409. "palegreen": [152, 251, 152],
  1410. "paleturquoise": [175, 238, 238],
  1411. "palevioletred": [219, 112, 147],
  1412. "papayawhip": [255, 239, 213],
  1413. "peachpuff": [255, 218, 185],
  1414. "peru": [205, 133, 63],
  1415. "pink": [255, 192, 203],
  1416. "plum": [221, 160, 221],
  1417. "powderblue": [176, 224, 230],
  1418. "purple": [128, 0, 128],
  1419. "rebeccapurple": [102, 51, 153],
  1420. "red": [255, 0, 0],
  1421. "rosybrown": [188, 143, 143],
  1422. "royalblue": [65, 105, 225],
  1423. "saddlebrown": [139, 69, 19],
  1424. "salmon": [250, 128, 114],
  1425. "sandybrown": [244, 164, 96],
  1426. "seagreen": [46, 139, 87],
  1427. "seashell": [255, 245, 238],
  1428. "sienna": [160, 82, 45],
  1429. "silver": [192, 192, 192],
  1430. "skyblue": [135, 206, 235],
  1431. "slateblue": [106, 90, 205],
  1432. "slategray": [112, 128, 144],
  1433. "slategrey": [112, 128, 144],
  1434. "snow": [255, 250, 250],
  1435. "springgreen": [0, 255, 127],
  1436. "steelblue": [70, 130, 180],
  1437. "tan": [210, 180, 140],
  1438. "teal": [0, 128, 128],
  1439. "thistle": [216, 191, 216],
  1440. "tomato": [255, 99, 71],
  1441. "turquoise": [64, 224, 208],
  1442. "violet": [238, 130, 238],
  1443. "wheat": [245, 222, 179],
  1444. "white": [255, 255, 255],
  1445. "whitesmoke": [245, 245, 245],
  1446. "yellow": [255, 255, 0],
  1447. "yellowgreen": [154, 205, 50]
  1448. };
  1449. },{}],6:[function(require,module,exports){
  1450. //! moment.js
  1451. //! version : 2.13.0
  1452. //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
  1453. //! license : MIT
  1454. //! momentjs.com
  1455. ;(function (global, factory) {
  1456. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  1457. typeof define === 'function' && define.amd ? define(factory) :
  1458. global.moment = factory()
  1459. }(this, function () { 'use strict';
  1460. var hookCallback;
  1461. function utils_hooks__hooks () {
  1462. return hookCallback.apply(null, arguments);
  1463. }
  1464. // This is done to register the method called with moment()
  1465. // without creating circular dependencies.
  1466. function setHookCallback (callback) {
  1467. hookCallback = callback;
  1468. }
  1469. function isArray(input) {
  1470. return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';
  1471. }
  1472. function isDate(input) {
  1473. return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';
  1474. }
  1475. function map(arr, fn) {
  1476. var res = [], i;
  1477. for (i = 0; i < arr.length; ++i) {
  1478. res.push(fn(arr[i], i));
  1479. }
  1480. return res;
  1481. }
  1482. function hasOwnProp(a, b) {
  1483. return Object.prototype.hasOwnProperty.call(a, b);
  1484. }
  1485. function extend(a, b) {
  1486. for (var i in b) {
  1487. if (hasOwnProp(b, i)) {
  1488. a[i] = b[i];
  1489. }
  1490. }
  1491. if (hasOwnProp(b, 'toString')) {
  1492. a.toString = b.toString;
  1493. }
  1494. if (hasOwnProp(b, 'valueOf')) {
  1495. a.valueOf = b.valueOf;
  1496. }
  1497. return a;
  1498. }
  1499. function create_utc__createUTC (input, format, locale, strict) {
  1500. return createLocalOrUTC(input, format, locale, strict, true).utc();
  1501. }
  1502. function defaultParsingFlags() {
  1503. // We need to deep clone this object.
  1504. return {
  1505. empty : false,
  1506. unusedTokens : [],
  1507. unusedInput : [],
  1508. overflow : -2,
  1509. charsLeftOver : 0,
  1510. nullInput : false,
  1511. invalidMonth : null,
  1512. invalidFormat : false,
  1513. userInvalidated : false,
  1514. iso : false,
  1515. parsedDateParts : [],
  1516. meridiem : null
  1517. };
  1518. }
  1519. function getParsingFlags(m) {
  1520. if (m._pf == null) {
  1521. m._pf = defaultParsingFlags();
  1522. }
  1523. return m._pf;
  1524. }
  1525. var some;
  1526. if (Array.prototype.some) {
  1527. some = Array.prototype.some;
  1528. } else {
  1529. some = function (fun) {
  1530. var t = Object(this);
  1531. var len = t.length >>> 0;
  1532. for (var i = 0; i < len; i++) {
  1533. if (i in t && fun.call(this, t[i], i, t)) {
  1534. return true;
  1535. }
  1536. }
  1537. return false;
  1538. };
  1539. }
  1540. function valid__isValid(m) {
  1541. if (m._isValid == null) {
  1542. var flags = getParsingFlags(m);
  1543. var parsedParts = some.call(flags.parsedDateParts, function (i) {
  1544. return i != null;
  1545. });
  1546. m._isValid = !isNaN(m._d.getTime()) &&
  1547. flags.overflow < 0 &&
  1548. !flags.empty &&
  1549. !flags.invalidMonth &&
  1550. !flags.invalidWeekday &&
  1551. !flags.nullInput &&
  1552. !flags.invalidFormat &&
  1553. !flags.userInvalidated &&
  1554. (!flags.meridiem || (flags.meridiem && parsedParts));
  1555. if (m._strict) {
  1556. m._isValid = m._isValid &&
  1557. flags.charsLeftOver === 0 &&
  1558. flags.unusedTokens.length === 0 &&
  1559. flags.bigHour === undefined;
  1560. }
  1561. }
  1562. return m._isValid;
  1563. }
  1564. function valid__createInvalid (flags) {
  1565. var m = create_utc__createUTC(NaN);
  1566. if (flags != null) {
  1567. extend(getParsingFlags(m), flags);
  1568. }
  1569. else {
  1570. getParsingFlags(m).userInvalidated = true;
  1571. }
  1572. return m;
  1573. }
  1574. function isUndefined(input) {
  1575. return input === void 0;
  1576. }
  1577. // Plugins that add properties should also add the key here (null value),
  1578. // so we can properly clone ourselves.
  1579. var momentProperties = utils_hooks__hooks.momentProperties = [];
  1580. function copyConfig(to, from) {
  1581. var i, prop, val;
  1582. if (!isUndefined(from._isAMomentObject)) {
  1583. to._isAMomentObject = from._isAMomentObject;
  1584. }
  1585. if (!isUndefined(from._i)) {
  1586. to._i = from._i;
  1587. }
  1588. if (!isUndefined(from._f)) {
  1589. to._f = from._f;
  1590. }
  1591. if (!isUndefined(from._l)) {
  1592. to._l = from._l;
  1593. }
  1594. if (!isUndefined(from._strict)) {
  1595. to._strict = from._strict;
  1596. }
  1597. if (!isUndefined(from._tzm)) {
  1598. to._tzm = from._tzm;
  1599. }
  1600. if (!isUndefined(from._isUTC)) {
  1601. to._isUTC = from._isUTC;
  1602. }
  1603. if (!isUndefined(from._offset)) {
  1604. to._offset = from._offset;
  1605. }
  1606. if (!isUndefined(from._pf)) {
  1607. to._pf = getParsingFlags(from);
  1608. }
  1609. if (!isUndefined(from._locale)) {
  1610. to._locale = from._locale;
  1611. }
  1612. if (momentProperties.length > 0) {
  1613. for (i in momentProperties) {
  1614. prop = momentProperties[i];
  1615. val = from[prop];
  1616. if (!isUndefined(val)) {
  1617. to[prop] = val;
  1618. }
  1619. }
  1620. }
  1621. return to;
  1622. }
  1623. var updateInProgress = false;
  1624. // Moment prototype object
  1625. function Moment(config) {
  1626. copyConfig(this, config);
  1627. this._d = new Date(config._d != null ? config._d.getTime() : NaN);
  1628. // Prevent infinite loop in case updateOffset creates new moment
  1629. // objects.
  1630. if (updateInProgress === false) {
  1631. updateInProgress = true;
  1632. utils_hooks__hooks.updateOffset(this);
  1633. updateInProgress = false;
  1634. }
  1635. }
  1636. function isMoment (obj) {
  1637. return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);
  1638. }
  1639. function absFloor (number) {
  1640. if (number < 0) {
  1641. return Math.ceil(number);
  1642. } else {
  1643. return Math.floor(number);
  1644. }
  1645. }
  1646. function toInt(argumentForCoercion) {
  1647. var coercedNumber = +argumentForCoercion,
  1648. value = 0;
  1649. if (coercedNumber !== 0 && isFinite(coercedNumber)) {
  1650. value = absFloor(coercedNumber);
  1651. }
  1652. return value;
  1653. }
  1654. // compare two arrays, return the number of differences
  1655. function compareArrays(array1, array2, dontConvert) {
  1656. var len = Math.min(array1.length, array2.length),
  1657. lengthDiff = Math.abs(array1.length - array2.length),
  1658. diffs = 0,
  1659. i;
  1660. for (i = 0; i < len; i++) {
  1661. if ((dontConvert && array1[i] !== array2[i]) ||
  1662. (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
  1663. diffs++;
  1664. }
  1665. }
  1666. return diffs + lengthDiff;
  1667. }
  1668. function warn(msg) {
  1669. if (utils_hooks__hooks.suppressDeprecationWarnings === false &&
  1670. (typeof console !== 'undefined') && console.warn) {
  1671. console.warn('Deprecation warning: ' + msg);
  1672. }
  1673. }
  1674. function deprecate(msg, fn) {
  1675. var firstTime = true;
  1676. return extend(function () {
  1677. if (utils_hooks__hooks.deprecationHandler != null) {
  1678. utils_hooks__hooks.deprecationHandler(null, msg);
  1679. }
  1680. if (firstTime) {
  1681. warn(msg + '\nArguments: ' + Array.prototype.slice.call(arguments).join(', ') + '\n' + (new Error()).stack);
  1682. firstTime = false;
  1683. }
  1684. return fn.apply(this, arguments);
  1685. }, fn);
  1686. }
  1687. var deprecations = {};
  1688. function deprecateSimple(name, msg) {
  1689. if (utils_hooks__hooks.deprecationHandler != null) {
  1690. utils_hooks__hooks.deprecationHandler(name, msg);
  1691. }
  1692. if (!deprecations[name]) {
  1693. warn(msg);
  1694. deprecations[name] = true;
  1695. }
  1696. }
  1697. utils_hooks__hooks.suppressDeprecationWarnings = false;
  1698. utils_hooks__hooks.deprecationHandler = null;
  1699. function isFunction(input) {
  1700. return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';
  1701. }
  1702. function isObject(input) {
  1703. return Object.prototype.toString.call(input) === '[object Object]';
  1704. }
  1705. function locale_set__set (config) {
  1706. var prop, i;
  1707. for (i in config) {
  1708. prop = config[i];
  1709. if (isFunction(prop)) {
  1710. this[i] = prop;
  1711. } else {
  1712. this['_' + i] = prop;
  1713. }
  1714. }
  1715. this._config = config;
  1716. // Lenient ordinal parsing accepts just a number in addition to
  1717. // number + (possibly) stuff coming from _ordinalParseLenient.
  1718. this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + (/\d{1,2}/).source);
  1719. }
  1720. function mergeConfigs(parentConfig, childConfig) {
  1721. var res = extend({}, parentConfig), prop;
  1722. for (prop in childConfig) {
  1723. if (hasOwnProp(childConfig, prop)) {
  1724. if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {
  1725. res[prop] = {};
  1726. extend(res[prop], parentConfig[prop]);
  1727. extend(res[prop], childConfig[prop]);
  1728. } else if (childConfig[prop] != null) {
  1729. res[prop] = childConfig[prop];
  1730. } else {
  1731. delete res[prop];
  1732. }
  1733. }
  1734. }
  1735. return res;
  1736. }
  1737. function Locale(config) {
  1738. if (config != null) {
  1739. this.set(config);
  1740. }
  1741. }
  1742. var keys;
  1743. if (Object.keys) {
  1744. keys = Object.keys;
  1745. } else {
  1746. keys = function (obj) {
  1747. var i, res = [];
  1748. for (i in obj) {
  1749. if (hasOwnProp(obj, i)) {
  1750. res.push(i);
  1751. }
  1752. }
  1753. return res;
  1754. };
  1755. }
  1756. // internal storage for locale config files
  1757. var locales = {};
  1758. var globalLocale;
  1759. function normalizeLocale(key) {
  1760. return key ? key.toLowerCase().replace('_', '-') : key;
  1761. }
  1762. // pick the locale from the array
  1763. // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
  1764. // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
  1765. function chooseLocale(names) {
  1766. var i = 0, j, next, locale, split;
  1767. while (i < names.length) {
  1768. split = normalizeLocale(names[i]).split('-');
  1769. j = split.length;
  1770. next = normalizeLocale(names[i + 1]);
  1771. next = next ? next.split('-') : null;
  1772. while (j > 0) {
  1773. locale = loadLocale(split.slice(0, j).join('-'));
  1774. if (locale) {
  1775. return locale;
  1776. }
  1777. if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
  1778. //the next array item is better than a shallower substring of this one
  1779. break;
  1780. }
  1781. j--;
  1782. }
  1783. i++;
  1784. }
  1785. return null;
  1786. }
  1787. function loadLocale(name) {
  1788. var oldLocale = null;
  1789. // TODO: Find a better way to register and load all the locales in Node
  1790. if (!locales[name] && (typeof module !== 'undefined') &&
  1791. module && module.exports) {
  1792. try {
  1793. oldLocale = globalLocale._abbr;
  1794. require('./locale/' + name);
  1795. // because defineLocale currently also sets the global locale, we
  1796. // want to undo that for lazy loaded locales
  1797. locale_locales__getSetGlobalLocale(oldLocale);
  1798. } catch (e) { }
  1799. }
  1800. return locales[name];
  1801. }
  1802. // This function will load locale and then set the global locale. If
  1803. // no arguments are passed in, it will simply return the current global
  1804. // locale key.
  1805. function locale_locales__getSetGlobalLocale (key, values) {
  1806. var data;
  1807. if (key) {
  1808. if (isUndefined(values)) {
  1809. data = locale_locales__getLocale(key);
  1810. }
  1811. else {
  1812. data = defineLocale(key, values);
  1813. }
  1814. if (data) {
  1815. // moment.duration._locale = moment._locale = data;
  1816. globalLocale = data;
  1817. }
  1818. }
  1819. return globalLocale._abbr;
  1820. }
  1821. function defineLocale (name, config) {
  1822. if (config !== null) {
  1823. config.abbr = name;
  1824. if (locales[name] != null) {
  1825. deprecateSimple('defineLocaleOverride',
  1826. 'use moment.updateLocale(localeName, config) to change ' +
  1827. 'an existing locale. moment.defineLocale(localeName, ' +
  1828. 'config) should only be used for creating a new locale');
  1829. config = mergeConfigs(locales[name]._config, config);
  1830. } else if (config.parentLocale != null) {
  1831. if (locales[config.parentLocale] != null) {
  1832. config = mergeConfigs(locales[config.parentLocale]._config, config);
  1833. } else {
  1834. // treat as if there is no base config
  1835. deprecateSimple('parentLocaleUndefined',
  1836. 'specified parentLocale is not defined yet');
  1837. }
  1838. }
  1839. locales[name] = new Locale(config);
  1840. // backwards compat for now: also set the locale
  1841. locale_locales__getSetGlobalLocale(name);
  1842. return locales[name];
  1843. } else {
  1844. // useful for testing
  1845. delete locales[name];
  1846. return null;
  1847. }
  1848. }
  1849. function updateLocale(name, config) {
  1850. if (config != null) {
  1851. var locale;
  1852. if (locales[name] != null) {
  1853. config = mergeConfigs(locales[name]._config, config);
  1854. }
  1855. locale = new Locale(config);
  1856. locale.parentLocale = locales[name];
  1857. locales[name] = locale;
  1858. // backwards compat for now: also set the locale
  1859. locale_locales__getSetGlobalLocale(name);
  1860. } else {
  1861. // pass null for config to unupdate, useful for tests
  1862. if (locales[name] != null) {
  1863. if (locales[name].parentLocale != null) {
  1864. locales[name] = locales[name].parentLocale;
  1865. } else if (locales[name] != null) {
  1866. delete locales[name];
  1867. }
  1868. }
  1869. }
  1870. return locales[name];
  1871. }
  1872. // returns locale data
  1873. function locale_locales__getLocale (key) {
  1874. var locale;
  1875. if (key && key._locale && key._locale._abbr) {
  1876. key = key._locale._abbr;
  1877. }
  1878. if (!key) {
  1879. return globalLocale;
  1880. }
  1881. if (!isArray(key)) {
  1882. //short-circuit everything else
  1883. locale = loadLocale(key);
  1884. if (locale) {
  1885. return locale;
  1886. }
  1887. key = [key];
  1888. }
  1889. return chooseLocale(key);
  1890. }
  1891. function locale_locales__listLocales() {
  1892. return keys(locales);
  1893. }
  1894. var aliases = {};
  1895. function addUnitAlias (unit, shorthand) {
  1896. var lowerCase = unit.toLowerCase();
  1897. aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;
  1898. }
  1899. function normalizeUnits(units) {
  1900. return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;
  1901. }
  1902. function normalizeObjectUnits(inputObject) {
  1903. var normalizedInput = {},
  1904. normalizedProp,
  1905. prop;
  1906. for (prop in inputObject) {
  1907. if (hasOwnProp(inputObject, prop)) {
  1908. normalizedProp = normalizeUnits(prop);
  1909. if (normalizedProp) {
  1910. normalizedInput[normalizedProp] = inputObject[prop];
  1911. }
  1912. }
  1913. }
  1914. return normalizedInput;
  1915. }
  1916. function makeGetSet (unit, keepTime) {
  1917. return function (value) {
  1918. if (value != null) {
  1919. get_set__set(this, unit, value);
  1920. utils_hooks__hooks.updateOffset(this, keepTime);
  1921. return this;
  1922. } else {
  1923. return get_set__get(this, unit);
  1924. }
  1925. };
  1926. }
  1927. function get_set__get (mom, unit) {
  1928. return mom.isValid() ?
  1929. mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;
  1930. }
  1931. function get_set__set (mom, unit, value) {
  1932. if (mom.isValid()) {
  1933. mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);
  1934. }
  1935. }
  1936. // MOMENTS
  1937. function getSet (units, value) {
  1938. var unit;
  1939. if (typeof units === 'object') {
  1940. for (unit in units) {
  1941. this.set(unit, units[unit]);
  1942. }
  1943. } else {
  1944. units = normalizeUnits(units);
  1945. if (isFunction(this[units])) {
  1946. return this[units](value);
  1947. }
  1948. }
  1949. return this;
  1950. }
  1951. function zeroFill(number, targetLength, forceSign) {
  1952. var absNumber = '' + Math.abs(number),
  1953. zerosToFill = targetLength - absNumber.length,
  1954. sign = number >= 0;
  1955. return (sign ? (forceSign ? '+' : '') : '-') +
  1956. Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;
  1957. }
  1958. var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g;
  1959. var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;
  1960. var formatFunctions = {};
  1961. var formatTokenFunctions = {};
  1962. // token: 'M'
  1963. // padded: ['MM', 2]
  1964. // ordinal: 'Mo'
  1965. // callback: function () { this.month() + 1 }
  1966. function addFormatToken (token, padded, ordinal, callback) {
  1967. var func = callback;
  1968. if (typeof callback === 'string') {
  1969. func = function () {
  1970. return this[callback]();
  1971. };
  1972. }
  1973. if (token) {
  1974. formatTokenFunctions[token] = func;
  1975. }
  1976. if (padded) {
  1977. formatTokenFunctions[padded[0]] = function () {
  1978. return zeroFill(func.apply(this, arguments), padded[1], padded[2]);
  1979. };
  1980. }
  1981. if (ordinal) {
  1982. formatTokenFunctions[ordinal] = function () {
  1983. return this.localeData().ordinal(func.apply(this, arguments), token);
  1984. };
  1985. }
  1986. }
  1987. function removeFormattingTokens(input) {
  1988. if (input.match(/\[[\s\S]/)) {
  1989. return input.replace(/^\[|\]$/g, '');
  1990. }
  1991. return input.replace(/\\/g, '');
  1992. }
  1993. function makeFormatFunction(format) {
  1994. var array = format.match(formattingTokens), i, length;
  1995. for (i = 0, length = array.length; i < length; i++) {
  1996. if (formatTokenFunctions[array[i]]) {
  1997. array[i] = formatTokenFunctions[array[i]];
  1998. } else {
  1999. array[i] = removeFormattingTokens(array[i]);
  2000. }
  2001. }
  2002. return function (mom) {
  2003. var output = '', i;
  2004. for (i = 0; i < length; i++) {
  2005. output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
  2006. }
  2007. return output;
  2008. };
  2009. }
  2010. // format date using native date object
  2011. function formatMoment(m, format) {
  2012. if (!m.isValid()) {
  2013. return m.localeData().invalidDate();
  2014. }
  2015. format = expandFormat(format, m.localeData());
  2016. formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);
  2017. return formatFunctions[format](m);
  2018. }
  2019. function expandFormat(format, locale) {
  2020. var i = 5;
  2021. function replaceLongDateFormatTokens(input) {
  2022. return locale.longDateFormat(input) || input;
  2023. }
  2024. localFormattingTokens.lastIndex = 0;
  2025. while (i >= 0 && localFormattingTokens.test(format)) {
  2026. format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
  2027. localFormattingTokens.lastIndex = 0;
  2028. i -= 1;
  2029. }
  2030. return format;
  2031. }
  2032. var match1 = /\d/; // 0 - 9
  2033. var match2 = /\d\d/; // 00 - 99
  2034. var match3 = /\d{3}/; // 000 - 999
  2035. var match4 = /\d{4}/; // 0000 - 9999
  2036. var match6 = /[+-]?\d{6}/; // -999999 - 999999
  2037. var match1to2 = /\d\d?/; // 0 - 99
  2038. var match3to4 = /\d\d\d\d?/; // 999 - 9999
  2039. var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 999999
  2040. var match1to3 = /\d{1,3}/; // 0 - 999
  2041. var match1to4 = /\d{1,4}/; // 0 - 9999
  2042. var match1to6 = /[+-]?\d{1,6}/; // -999999 - 999999
  2043. var matchUnsigned = /\d+/; // 0 - inf
  2044. var matchSigned = /[+-]?\d+/; // -inf - inf
  2045. var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z
  2046. var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z
  2047. var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.123
  2048. // any word (or two) characters or numbers including two/three word month in arabic.
  2049. // includes scottish gaelic two word and hyphenated months
  2050. var matchWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i;
  2051. var regexes = {};
  2052. function addRegexToken (token, regex, strictRegex) {
  2053. regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {
  2054. return (isStrict && strictRegex) ? strictRegex : regex;
  2055. };
  2056. }
  2057. function getParseRegexForToken (token, config) {
  2058. if (!hasOwnProp(regexes, token)) {
  2059. return new RegExp(unescapeFormat(token));
  2060. }
  2061. return regexes[token](config._strict, config._locale);
  2062. }
  2063. // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
  2064. function unescapeFormat(s) {
  2065. return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
  2066. return p1 || p2 || p3 || p4;
  2067. }));
  2068. }
  2069. function regexEscape(s) {
  2070. return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
  2071. }
  2072. var tokens = {};
  2073. function addParseToken (token, callback) {
  2074. var i, func = callback;
  2075. if (typeof token === 'string') {
  2076. token = [token];
  2077. }
  2078. if (typeof callback === 'number') {
  2079. func = function (input, array) {
  2080. array[callback] = toInt(input);
  2081. };
  2082. }
  2083. for (i = 0; i < token.length; i++) {
  2084. tokens[token[i]] = func;
  2085. }
  2086. }
  2087. function addWeekParseToken (token, callback) {
  2088. addParseToken(token, function (input, array, config, token) {
  2089. config._w = config._w || {};
  2090. callback(input, config._w, config, token);
  2091. });
  2092. }
  2093. function addTimeToArrayFromToken(token, input, config) {
  2094. if (input != null && hasOwnProp(tokens, token)) {
  2095. tokens[token](input, config._a, config, token);
  2096. }
  2097. }
  2098. var YEAR = 0;
  2099. var MONTH = 1;
  2100. var DATE = 2;
  2101. var HOUR = 3;
  2102. var MINUTE = 4;
  2103. var SECOND = 5;
  2104. var MILLISECOND = 6;
  2105. var WEEK = 7;
  2106. var WEEKDAY = 8;
  2107. var indexOf;
  2108. if (Array.prototype.indexOf) {
  2109. indexOf = Array.prototype.indexOf;
  2110. } else {
  2111. indexOf = function (o) {
  2112. // I know
  2113. var i;
  2114. for (i = 0; i < this.length; ++i) {
  2115. if (this[i] === o) {
  2116. return i;
  2117. }
  2118. }
  2119. return -1;
  2120. };
  2121. }
  2122. function daysInMonth(year, month) {
  2123. return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
  2124. }
  2125. // FORMATTING
  2126. addFormatToken('M', ['MM', 2], 'Mo', function () {
  2127. return this.month() + 1;
  2128. });
  2129. addFormatToken('MMM', 0, 0, function (format) {
  2130. return this.localeData().monthsShort(this, format);
  2131. });
  2132. addFormatToken('MMMM', 0, 0, function (format) {
  2133. return this.localeData().months(this, format);
  2134. });
  2135. // ALIASES
  2136. addUnitAlias('month', 'M');
  2137. // PARSING
  2138. addRegexToken('M', match1to2);
  2139. addRegexToken('MM', match1to2, match2);
  2140. addRegexToken('MMM', function (isStrict, locale) {
  2141. return locale.monthsShortRegex(isStrict);
  2142. });
  2143. addRegexToken('MMMM', function (isStrict, locale) {
  2144. return locale.monthsRegex(isStrict);
  2145. });
  2146. addParseToken(['M', 'MM'], function (input, array) {
  2147. array[MONTH] = toInt(input) - 1;
  2148. });
  2149. addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {
  2150. var month = config._locale.monthsParse(input, token, config._strict);
  2151. // if we didn't find a month name, mark the date as invalid.
  2152. if (month != null) {
  2153. array[MONTH] = month;
  2154. } else {
  2155. getParsingFlags(config).invalidMonth = input;
  2156. }
  2157. });
  2158. // LOCALES
  2159. var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/;
  2160. var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');
  2161. function localeMonths (m, format) {
  2162. return isArray(this._months) ? this._months[m.month()] :
  2163. this._months[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
  2164. }
  2165. var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');
  2166. function localeMonthsShort (m, format) {
  2167. return isArray(this._monthsShort) ? this._monthsShort[m.month()] :
  2168. this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];
  2169. }
  2170. function units_month__handleStrictParse(monthName, format, strict) {
  2171. var i, ii, mom, llc = monthName.toLocaleLowerCase();
  2172. if (!this._monthsParse) {
  2173. // this is not used
  2174. this._monthsParse = [];
  2175. this._longMonthsParse = [];
  2176. this._shortMonthsParse = [];
  2177. for (i = 0; i < 12; ++i) {
  2178. mom = create_utc__createUTC([2000, i]);
  2179. this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();
  2180. this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();
  2181. }
  2182. }
  2183. if (strict) {
  2184. if (format === 'MMM') {
  2185. ii = indexOf.call(this._shortMonthsParse, llc);
  2186. return ii !== -1 ? ii : null;
  2187. } else {
  2188. ii = indexOf.call(this._longMonthsParse, llc);
  2189. return ii !== -1 ? ii : null;
  2190. }
  2191. } else {
  2192. if (format === 'MMM') {
  2193. ii = indexOf.call(this._shortMonthsParse, llc);
  2194. if (ii !== -1) {
  2195. return ii;
  2196. }
  2197. ii = indexOf.call(this._longMonthsParse, llc);
  2198. return ii !== -1 ? ii : null;
  2199. } else {
  2200. ii = indexOf.call(this._longMonthsParse, llc);
  2201. if (ii !== -1) {
  2202. return ii;
  2203. }
  2204. ii = indexOf.call(this._shortMonthsParse, llc);
  2205. return ii !== -1 ? ii : null;
  2206. }
  2207. }
  2208. }
  2209. function localeMonthsParse (monthName, format, strict) {
  2210. var i, mom, regex;
  2211. if (this._monthsParseExact) {
  2212. return units_month__handleStrictParse.call(this, monthName, format, strict);
  2213. }
  2214. if (!this._monthsParse) {
  2215. this._monthsParse = [];
  2216. this._longMonthsParse = [];
  2217. this._shortMonthsParse = [];
  2218. }
  2219. // TODO: add sorting
  2220. // Sorting makes sure if one month (or abbr) is a prefix of another
  2221. // see sorting in computeMonthsParse
  2222. for (i = 0; i < 12; i++) {
  2223. // make the regex if we don't have it already
  2224. mom = create_utc__createUTC([2000, i]);
  2225. if (strict && !this._longMonthsParse[i]) {
  2226. this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
  2227. this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
  2228. }
  2229. if (!strict && !this._monthsParse[i]) {
  2230. regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
  2231. this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
  2232. }
  2233. // test the regex
  2234. if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
  2235. return i;
  2236. } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
  2237. return i;
  2238. } else if (!strict && this._monthsParse[i].test(monthName)) {
  2239. return i;
  2240. }
  2241. }
  2242. }
  2243. // MOMENTS
  2244. function setMonth (mom, value) {
  2245. var dayOfMonth;
  2246. if (!mom.isValid()) {
  2247. // No op
  2248. return mom;
  2249. }
  2250. if (typeof value === 'string') {
  2251. if (/^\d+$/.test(value)) {
  2252. value = toInt(value);
  2253. } else {
  2254. value = mom.localeData().monthsParse(value);
  2255. // TODO: Another silent failure?
  2256. if (typeof value !== 'number') {
  2257. return mom;
  2258. }
  2259. }
  2260. }
  2261. dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));
  2262. mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);
  2263. return mom;
  2264. }
  2265. function getSetMonth (value) {
  2266. if (value != null) {
  2267. setMonth(this, value);
  2268. utils_hooks__hooks.updateOffset(this, true);
  2269. return this;
  2270. } else {
  2271. return get_set__get(this, 'Month');
  2272. }
  2273. }
  2274. function getDaysInMonth () {
  2275. return daysInMonth(this.year(), this.month());
  2276. }
  2277. var defaultMonthsShortRegex = matchWord;
  2278. function monthsShortRegex (isStrict) {
  2279. if (this._monthsParseExact) {
  2280. if (!hasOwnProp(this, '_monthsRegex')) {
  2281. computeMonthsParse.call(this);
  2282. }
  2283. if (isStrict) {
  2284. return this._monthsShortStrictRegex;
  2285. } else {
  2286. return this._monthsShortRegex;
  2287. }
  2288. } else {
  2289. return this._monthsShortStrictRegex && isStrict ?
  2290. this._monthsShortStrictRegex : this._monthsShortRegex;
  2291. }
  2292. }
  2293. var defaultMonthsRegex = matchWord;
  2294. function monthsRegex (isStrict) {
  2295. if (this._monthsParseExact) {
  2296. if (!hasOwnProp(this, '_monthsRegex')) {
  2297. computeMonthsParse.call(this);
  2298. }
  2299. if (isStrict) {
  2300. return this._monthsStrictRegex;
  2301. } else {
  2302. return this._monthsRegex;
  2303. }
  2304. } else {
  2305. return this._monthsStrictRegex && isStrict ?
  2306. this._monthsStrictRegex : this._monthsRegex;
  2307. }
  2308. }
  2309. function computeMonthsParse () {
  2310. function cmpLenRev(a, b) {
  2311. return b.length - a.length;
  2312. }
  2313. var shortPieces = [], longPieces = [], mixedPieces = [],
  2314. i, mom;
  2315. for (i = 0; i < 12; i++) {
  2316. // make the regex if we don't have it already
  2317. mom = create_utc__createUTC([2000, i]);
  2318. shortPieces.push(this.monthsShort(mom, ''));
  2319. longPieces.push(this.months(mom, ''));
  2320. mixedPieces.push(this.months(mom, ''));
  2321. mixedPieces.push(this.monthsShort(mom, ''));
  2322. }
  2323. // Sorting makes sure if one month (or abbr) is a prefix of another it
  2324. // will match the longer piece.
  2325. shortPieces.sort(cmpLenRev);
  2326. longPieces.sort(cmpLenRev);
  2327. mixedPieces.sort(cmpLenRev);
  2328. for (i = 0; i < 12; i++) {
  2329. shortPieces[i] = regexEscape(shortPieces[i]);
  2330. longPieces[i] = regexEscape(longPieces[i]);
  2331. mixedPieces[i] = regexEscape(mixedPieces[i]);
  2332. }
  2333. this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
  2334. this._monthsShortRegex = this._monthsRegex;
  2335. this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
  2336. this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
  2337. }
  2338. function checkOverflow (m) {
  2339. var overflow;
  2340. var a = m._a;
  2341. if (a && getParsingFlags(m).overflow === -2) {
  2342. overflow =
  2343. a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :
  2344. a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :
  2345. a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :
  2346. a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :
  2347. a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :
  2348. a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :
  2349. -1;
  2350. if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
  2351. overflow = DATE;
  2352. }
  2353. if (getParsingFlags(m)._overflowWeeks && overflow === -1) {
  2354. overflow = WEEK;
  2355. }
  2356. if (getParsingFlags(m)._overflowWeekday && overflow === -1) {
  2357. overflow = WEEKDAY;
  2358. }
  2359. getParsingFlags(m).overflow = overflow;
  2360. }
  2361. return m;
  2362. }
  2363. // iso 8601 regex
  2364. // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
  2365. var extendedIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
  2366. var basicIsoRegex = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/;
  2367. var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;
  2368. var isoDates = [
  2369. ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
  2370. ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
  2371. ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
  2372. ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
  2373. ['YYYY-DDD', /\d{4}-\d{3}/],
  2374. ['YYYY-MM', /\d{4}-\d\d/, false],
  2375. ['YYYYYYMMDD', /[+-]\d{10}/],
  2376. ['YYYYMMDD', /\d{8}/],
  2377. // YYYYMM is NOT allowed by the standard
  2378. ['GGGG[W]WWE', /\d{4}W\d{3}/],
  2379. ['GGGG[W]WW', /\d{4}W\d{2}/, false],
  2380. ['YYYYDDD', /\d{7}/]
  2381. ];
  2382. // iso time formats and regexes
  2383. var isoTimes = [
  2384. ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
  2385. ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
  2386. ['HH:mm:ss', /\d\d:\d\d:\d\d/],
  2387. ['HH:mm', /\d\d:\d\d/],
  2388. ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
  2389. ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
  2390. ['HHmmss', /\d\d\d\d\d\d/],
  2391. ['HHmm', /\d\d\d\d/],
  2392. ['HH', /\d\d/]
  2393. ];
  2394. var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;
  2395. // date from iso format
  2396. function configFromISO(config) {
  2397. var i, l,
  2398. string = config._i,
  2399. match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
  2400. allowTime, dateFormat, timeFormat, tzFormat;
  2401. if (match) {
  2402. getParsingFlags(config).iso = true;
  2403. for (i = 0, l = isoDates.length; i < l; i++) {
  2404. if (isoDates[i][1].exec(match[1])) {
  2405. dateFormat = isoDates[i][0];
  2406. allowTime = isoDates[i][2] !== false;
  2407. break;
  2408. }
  2409. }
  2410. if (dateFormat == null) {
  2411. config._isValid = false;
  2412. return;
  2413. }
  2414. if (match[3]) {
  2415. for (i = 0, l = isoTimes.length; i < l; i++) {
  2416. if (isoTimes[i][1].exec(match[3])) {
  2417. // match[2] should be 'T' or space
  2418. timeFormat = (match[2] || ' ') + isoTimes[i][0];
  2419. break;
  2420. }
  2421. }
  2422. if (timeFormat == null) {
  2423. config._isValid = false;
  2424. return;
  2425. }
  2426. }
  2427. if (!allowTime && timeFormat != null) {
  2428. config._isValid = false;
  2429. return;
  2430. }
  2431. if (match[4]) {
  2432. if (tzRegex.exec(match[4])) {
  2433. tzFormat = 'Z';
  2434. } else {
  2435. config._isValid = false;
  2436. return;
  2437. }
  2438. }
  2439. config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
  2440. configFromStringAndFormat(config);
  2441. } else {
  2442. config._isValid = false;
  2443. }
  2444. }
  2445. // date from iso format or fallback
  2446. function configFromString(config) {
  2447. var matched = aspNetJsonRegex.exec(config._i);
  2448. if (matched !== null) {
  2449. config._d = new Date(+matched[1]);
  2450. return;
  2451. }
  2452. configFromISO(config);
  2453. if (config._isValid === false) {
  2454. delete config._isValid;
  2455. utils_hooks__hooks.createFromInputFallback(config);
  2456. }
  2457. }
  2458. utils_hooks__hooks.createFromInputFallback = deprecate(
  2459. 'moment construction falls back to js Date. This is ' +
  2460. 'discouraged and will be removed in upcoming major ' +
  2461. 'release. Please refer to ' +
  2462. 'https://github.com/moment/moment/issues/1407 for more info.',
  2463. function (config) {
  2464. config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
  2465. }
  2466. );
  2467. function createDate (y, m, d, h, M, s, ms) {
  2468. //can't just apply() to create a date:
  2469. //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
  2470. var date = new Date(y, m, d, h, M, s, ms);
  2471. //the date constructor remaps years 0-99 to 1900-1999
  2472. if (y < 100 && y >= 0 && isFinite(date.getFullYear())) {
  2473. date.setFullYear(y);
  2474. }
  2475. return date;
  2476. }
  2477. function createUTCDate (y) {
  2478. var date = new Date(Date.UTC.apply(null, arguments));
  2479. //the Date.UTC function remaps years 0-99 to 1900-1999
  2480. if (y < 100 && y >= 0 && isFinite(date.getUTCFullYear())) {
  2481. date.setUTCFullYear(y);
  2482. }
  2483. return date;
  2484. }
  2485. // FORMATTING
  2486. addFormatToken('Y', 0, 0, function () {
  2487. var y = this.year();
  2488. return y <= 9999 ? '' + y : '+' + y;
  2489. });
  2490. addFormatToken(0, ['YY', 2], 0, function () {
  2491. return this.year() % 100;
  2492. });
  2493. addFormatToken(0, ['YYYY', 4], 0, 'year');
  2494. addFormatToken(0, ['YYYYY', 5], 0, 'year');
  2495. addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');
  2496. // ALIASES
  2497. addUnitAlias('year', 'y');
  2498. // PARSING
  2499. addRegexToken('Y', matchSigned);
  2500. addRegexToken('YY', match1to2, match2);
  2501. addRegexToken('YYYY', match1to4, match4);
  2502. addRegexToken('YYYYY', match1to6, match6);
  2503. addRegexToken('YYYYYY', match1to6, match6);
  2504. addParseToken(['YYYYY', 'YYYYYY'], YEAR);
  2505. addParseToken('YYYY', function (input, array) {
  2506. array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input);
  2507. });
  2508. addParseToken('YY', function (input, array) {
  2509. array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input);
  2510. });
  2511. addParseToken('Y', function (input, array) {
  2512. array[YEAR] = parseInt(input, 10);
  2513. });
  2514. // HELPERS
  2515. function daysInYear(year) {
  2516. return isLeapYear(year) ? 366 : 365;
  2517. }
  2518. function isLeapYear(year) {
  2519. return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
  2520. }
  2521. // HOOKS
  2522. utils_hooks__hooks.parseTwoDigitYear = function (input) {
  2523. return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
  2524. };
  2525. // MOMENTS
  2526. var getSetYear = makeGetSet('FullYear', true);
  2527. function getIsLeapYear () {
  2528. return isLeapYear(this.year());
  2529. }
  2530. // start-of-first-week - start-of-year
  2531. function firstWeekOffset(year, dow, doy) {
  2532. var // first-week day -- which january is always in the first week (4 for iso, 1 for other)
  2533. fwd = 7 + dow - doy,
  2534. // first-week day local weekday -- which local weekday is fwd
  2535. fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
  2536. return -fwdlw + fwd - 1;
  2537. }
  2538. //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
  2539. function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
  2540. var localWeekday = (7 + weekday - dow) % 7,
  2541. weekOffset = firstWeekOffset(year, dow, doy),
  2542. dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,
  2543. resYear, resDayOfYear;
  2544. if (dayOfYear <= 0) {
  2545. resYear = year - 1;
  2546. resDayOfYear = daysInYear(resYear) + dayOfYear;
  2547. } else if (dayOfYear > daysInYear(year)) {
  2548. resYear = year + 1;
  2549. resDayOfYear = dayOfYear - daysInYear(year);
  2550. } else {
  2551. resYear = year;
  2552. resDayOfYear = dayOfYear;
  2553. }
  2554. return {
  2555. year: resYear,
  2556. dayOfYear: resDayOfYear
  2557. };
  2558. }
  2559. function weekOfYear(mom, dow, doy) {
  2560. var weekOffset = firstWeekOffset(mom.year(), dow, doy),
  2561. week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,
  2562. resWeek, resYear;
  2563. if (week < 1) {
  2564. resYear = mom.year() - 1;
  2565. resWeek = week + weeksInYear(resYear, dow, doy);
  2566. } else if (week > weeksInYear(mom.year(), dow, doy)) {
  2567. resWeek = week - weeksInYear(mom.year(), dow, doy);
  2568. resYear = mom.year() + 1;
  2569. } else {
  2570. resYear = mom.year();
  2571. resWeek = week;
  2572. }
  2573. return {
  2574. week: resWeek,
  2575. year: resYear
  2576. };
  2577. }
  2578. function weeksInYear(year, dow, doy) {
  2579. var weekOffset = firstWeekOffset(year, dow, doy),
  2580. weekOffsetNext = firstWeekOffset(year + 1, dow, doy);
  2581. return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;
  2582. }
  2583. // Pick the first defined of two or three arguments.
  2584. function defaults(a, b, c) {
  2585. if (a != null) {
  2586. return a;
  2587. }
  2588. if (b != null) {
  2589. return b;
  2590. }
  2591. return c;
  2592. }
  2593. function currentDateArray(config) {
  2594. // hooks is actually the exported moment object
  2595. var nowValue = new Date(utils_hooks__hooks.now());
  2596. if (config._useUTC) {
  2597. return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];
  2598. }
  2599. return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];
  2600. }
  2601. // convert an array to a date.
  2602. // the array should mirror the parameters below
  2603. // note: all values past the year are optional and will default to the lowest possible value.
  2604. // [year, month, day , hour, minute, second, millisecond]
  2605. function configFromArray (config) {
  2606. var i, date, input = [], currentDate, yearToUse;
  2607. if (config._d) {
  2608. return;
  2609. }
  2610. currentDate = currentDateArray(config);
  2611. //compute day of the year from weeks and weekdays
  2612. if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
  2613. dayOfYearFromWeekInfo(config);
  2614. }
  2615. //if the day of the year is set, figure out what it is
  2616. if (config._dayOfYear) {
  2617. yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);
  2618. if (config._dayOfYear > daysInYear(yearToUse)) {
  2619. getParsingFlags(config)._overflowDayOfYear = true;
  2620. }
  2621. date = createUTCDate(yearToUse, 0, config._dayOfYear);
  2622. config._a[MONTH] = date.getUTCMonth();
  2623. config._a[DATE] = date.getUTCDate();
  2624. }
  2625. // Default to current date.
  2626. // * if no year, month, day of month are given, default to today
  2627. // * if day of month is given, default month and year
  2628. // * if month is given, default only year
  2629. // * if year is given, don't default anything
  2630. for (i = 0; i < 3 && config._a[i] == null; ++i) {
  2631. config._a[i] = input[i] = currentDate[i];
  2632. }
  2633. // Zero out whatever was not defaulted, including time
  2634. for (; i < 7; i++) {
  2635. config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
  2636. }
  2637. // Check for 24:00:00.000
  2638. if (config._a[HOUR] === 24 &&
  2639. config._a[MINUTE] === 0 &&
  2640. config._a[SECOND] === 0 &&
  2641. config._a[MILLISECOND] === 0) {
  2642. config._nextDay = true;
  2643. config._a[HOUR] = 0;
  2644. }
  2645. config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);
  2646. // Apply timezone offset from input. The actual utcOffset can be changed
  2647. // with parseZone.
  2648. if (config._tzm != null) {
  2649. config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
  2650. }
  2651. if (config._nextDay) {
  2652. config._a[HOUR] = 24;
  2653. }
  2654. }
  2655. function dayOfYearFromWeekInfo(config) {
  2656. var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;
  2657. w = config._w;
  2658. if (w.GG != null || w.W != null || w.E != null) {
  2659. dow = 1;
  2660. doy = 4;
  2661. // TODO: We need to take the current isoWeekYear, but that depends on
  2662. // how we interpret now (local, utc, fixed offset). So create
  2663. // a now version of current config (take local/utc/offset flags, and
  2664. // create now).
  2665. weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(local__createLocal(), 1, 4).year);
  2666. week = defaults(w.W, 1);
  2667. weekday = defaults(w.E, 1);
  2668. if (weekday < 1 || weekday > 7) {
  2669. weekdayOverflow = true;
  2670. }
  2671. } else {
  2672. dow = config._locale._week.dow;
  2673. doy = config._locale._week.doy;
  2674. weekYear = defaults(w.gg, config._a[YEAR], weekOfYear(local__createLocal(), dow, doy).year);
  2675. week = defaults(w.w, 1);
  2676. if (w.d != null) {
  2677. // weekday -- low day numbers are considered next week
  2678. weekday = w.d;
  2679. if (weekday < 0 || weekday > 6) {
  2680. weekdayOverflow = true;
  2681. }
  2682. } else if (w.e != null) {
  2683. // local weekday -- counting starts from begining of week
  2684. weekday = w.e + dow;
  2685. if (w.e < 0 || w.e > 6) {
  2686. weekdayOverflow = true;
  2687. }
  2688. } else {
  2689. // default to begining of week
  2690. weekday = dow;
  2691. }
  2692. }
  2693. if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {
  2694. getParsingFlags(config)._overflowWeeks = true;
  2695. } else if (weekdayOverflow != null) {
  2696. getParsingFlags(config)._overflowWeekday = true;
  2697. } else {
  2698. temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);
  2699. config._a[YEAR] = temp.year;
  2700. config._dayOfYear = temp.dayOfYear;
  2701. }
  2702. }
  2703. // constant that refers to the ISO standard
  2704. utils_hooks__hooks.ISO_8601 = function () {};
  2705. // date from string and format string
  2706. function configFromStringAndFormat(config) {
  2707. // TODO: Move this to another part of the creation flow to prevent circular deps
  2708. if (config._f === utils_hooks__hooks.ISO_8601) {
  2709. configFromISO(config);
  2710. return;
  2711. }
  2712. config._a = [];
  2713. getParsingFlags(config).empty = true;
  2714. // This array is used to make a Date, either with `new Date` or `Date.UTC`
  2715. var string = '' + config._i,
  2716. i, parsedInput, tokens, token, skipped,
  2717. stringLength = string.length,
  2718. totalParsedInputLength = 0;
  2719. tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];
  2720. for (i = 0; i < tokens.length; i++) {
  2721. token = tokens[i];
  2722. parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
  2723. // console.log('token', token, 'parsedInput', parsedInput,
  2724. // 'regex', getParseRegexForToken(token, config));
  2725. if (parsedInput) {
  2726. skipped = string.substr(0, string.indexOf(parsedInput));
  2727. if (skipped.length > 0) {
  2728. getParsingFlags(config).unusedInput.push(skipped);
  2729. }
  2730. string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
  2731. totalParsedInputLength += parsedInput.length;
  2732. }
  2733. // don't parse if it's not a known token
  2734. if (formatTokenFunctions[token]) {
  2735. if (parsedInput) {
  2736. getParsingFlags(config).empty = false;
  2737. }
  2738. else {
  2739. getParsingFlags(config).unusedTokens.push(token);
  2740. }
  2741. addTimeToArrayFromToken(token, parsedInput, config);
  2742. }
  2743. else if (config._strict && !parsedInput) {
  2744. getParsingFlags(config).unusedTokens.push(token);
  2745. }
  2746. }
  2747. // add remaining unparsed input length to the string
  2748. getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;
  2749. if (string.length > 0) {
  2750. getParsingFlags(config).unusedInput.push(string);
  2751. }
  2752. // clear _12h flag if hour is <= 12
  2753. if (getParsingFlags(config).bigHour === true &&
  2754. config._a[HOUR] <= 12 &&
  2755. config._a[HOUR] > 0) {
  2756. getParsingFlags(config).bigHour = undefined;
  2757. }
  2758. getParsingFlags(config).parsedDateParts = config._a.slice(0);
  2759. getParsingFlags(config).meridiem = config._meridiem;
  2760. // handle meridiem
  2761. config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);
  2762. configFromArray(config);
  2763. checkOverflow(config);
  2764. }
  2765. function meridiemFixWrap (locale, hour, meridiem) {
  2766. var isPm;
  2767. if (meridiem == null) {
  2768. // nothing to do
  2769. return hour;
  2770. }
  2771. if (locale.meridiemHour != null) {
  2772. return locale.meridiemHour(hour, meridiem);
  2773. } else if (locale.isPM != null) {
  2774. // Fallback
  2775. isPm = locale.isPM(meridiem);
  2776. if (isPm && hour < 12) {
  2777. hour += 12;
  2778. }
  2779. if (!isPm && hour === 12) {
  2780. hour = 0;
  2781. }
  2782. return hour;
  2783. } else {
  2784. // this is not supposed to happen
  2785. return hour;
  2786. }
  2787. }
  2788. // date from string and array of format strings
  2789. function configFromStringAndArray(config) {
  2790. var tempConfig,
  2791. bestMoment,
  2792. scoreToBeat,
  2793. i,
  2794. currentScore;
  2795. if (config._f.length === 0) {
  2796. getParsingFlags(config).invalidFormat = true;
  2797. config._d = new Date(NaN);
  2798. return;
  2799. }
  2800. for (i = 0; i < config._f.length; i++) {
  2801. currentScore = 0;
  2802. tempConfig = copyConfig({}, config);
  2803. if (config._useUTC != null) {
  2804. tempConfig._useUTC = config._useUTC;
  2805. }
  2806. tempConfig._f = config._f[i];
  2807. configFromStringAndFormat(tempConfig);
  2808. if (!valid__isValid(tempConfig)) {
  2809. continue;
  2810. }
  2811. // if there is any input that was not parsed add a penalty for that format
  2812. currentScore += getParsingFlags(tempConfig).charsLeftOver;
  2813. //or tokens
  2814. currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;
  2815. getParsingFlags(tempConfig).score = currentScore;
  2816. if (scoreToBeat == null || currentScore < scoreToBeat) {
  2817. scoreToBeat = currentScore;
  2818. bestMoment = tempConfig;
  2819. }
  2820. }
  2821. extend(config, bestMoment || tempConfig);
  2822. }
  2823. function configFromObject(config) {
  2824. if (config._d) {
  2825. return;
  2826. }
  2827. var i = normalizeObjectUnits(config._i);
  2828. config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {
  2829. return obj && parseInt(obj, 10);
  2830. });
  2831. configFromArray(config);
  2832. }
  2833. function createFromConfig (config) {
  2834. var res = new Moment(checkOverflow(prepareConfig(config)));
  2835. if (res._nextDay) {
  2836. // Adding is smart enough around DST
  2837. res.add(1, 'd');
  2838. res._nextDay = undefined;
  2839. }
  2840. return res;
  2841. }
  2842. function prepareConfig (config) {
  2843. var input = config._i,
  2844. format = config._f;
  2845. config._locale = config._locale || locale_locales__getLocale(config._l);
  2846. if (input === null || (format === undefined && input === '')) {
  2847. return valid__createInvalid({nullInput: true});
  2848. }
  2849. if (typeof input === 'string') {
  2850. config._i = input = config._locale.preparse(input);
  2851. }
  2852. if (isMoment(input)) {
  2853. return new Moment(checkOverflow(input));
  2854. } else if (isArray(format)) {
  2855. configFromStringAndArray(config);
  2856. } else if (format) {
  2857. configFromStringAndFormat(config);
  2858. } else if (isDate(input)) {
  2859. config._d = input;
  2860. } else {
  2861. configFromInput(config);
  2862. }
  2863. if (!valid__isValid(config)) {
  2864. config._d = null;
  2865. }
  2866. return config;
  2867. }
  2868. function configFromInput(config) {
  2869. var input = config._i;
  2870. if (input === undefined) {
  2871. config._d = new Date(utils_hooks__hooks.now());
  2872. } else if (isDate(input)) {
  2873. config._d = new Date(input.valueOf());
  2874. } else if (typeof input === 'string') {
  2875. configFromString(config);
  2876. } else if (isArray(input)) {
  2877. config._a = map(input.slice(0), function (obj) {
  2878. return parseInt(obj, 10);
  2879. });
  2880. configFromArray(config);
  2881. } else if (typeof(input) === 'object') {
  2882. configFromObject(config);
  2883. } else if (typeof(input) === 'number') {
  2884. // from milliseconds
  2885. config._d = new Date(input);
  2886. } else {
  2887. utils_hooks__hooks.createFromInputFallback(config);
  2888. }
  2889. }
  2890. function createLocalOrUTC (input, format, locale, strict, isUTC) {
  2891. var c = {};
  2892. if (typeof(locale) === 'boolean') {
  2893. strict = locale;
  2894. locale = undefined;
  2895. }
  2896. // object construction must be done this way.
  2897. // https://github.com/moment/moment/issues/1423
  2898. c._isAMomentObject = true;
  2899. c._useUTC = c._isUTC = isUTC;
  2900. c._l = locale;
  2901. c._i = input;
  2902. c._f = format;
  2903. c._strict = strict;
  2904. return createFromConfig(c);
  2905. }
  2906. function local__createLocal (input, format, locale, strict) {
  2907. return createLocalOrUTC(input, format, locale, strict, false);
  2908. }
  2909. var prototypeMin = deprecate(
  2910. 'moment().min is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548',
  2911. function () {
  2912. var other = local__createLocal.apply(null, arguments);
  2913. if (this.isValid() && other.isValid()) {
  2914. return other < this ? this : other;
  2915. } else {
  2916. return valid__createInvalid();
  2917. }
  2918. }
  2919. );
  2920. var prototypeMax = deprecate(
  2921. 'moment().max is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548',
  2922. function () {
  2923. var other = local__createLocal.apply(null, arguments);
  2924. if (this.isValid() && other.isValid()) {
  2925. return other > this ? this : other;
  2926. } else {
  2927. return valid__createInvalid();
  2928. }
  2929. }
  2930. );
  2931. // Pick a moment m from moments so that m[fn](other) is true for all
  2932. // other. This relies on the function fn to be transitive.
  2933. //
  2934. // moments should either be an array of moment objects or an array, whose
  2935. // first element is an array of moment objects.
  2936. function pickBy(fn, moments) {
  2937. var res, i;
  2938. if (moments.length === 1 && isArray(moments[0])) {
  2939. moments = moments[0];
  2940. }
  2941. if (!moments.length) {
  2942. return local__createLocal();
  2943. }
  2944. res = moments[0];
  2945. for (i = 1; i < moments.length; ++i) {
  2946. if (!moments[i].isValid() || moments[i][fn](res)) {
  2947. res = moments[i];
  2948. }
  2949. }
  2950. return res;
  2951. }
  2952. // TODO: Use [].sort instead?
  2953. function min () {
  2954. var args = [].slice.call(arguments, 0);
  2955. return pickBy('isBefore', args);
  2956. }
  2957. function max () {
  2958. var args = [].slice.call(arguments, 0);
  2959. return pickBy('isAfter', args);
  2960. }
  2961. var now = function () {
  2962. return Date.now ? Date.now() : +(new Date());
  2963. };
  2964. function Duration (duration) {
  2965. var normalizedInput = normalizeObjectUnits(duration),
  2966. years = normalizedInput.year || 0,
  2967. quarters = normalizedInput.quarter || 0,
  2968. months = normalizedInput.month || 0,
  2969. weeks = normalizedInput.week || 0,
  2970. days = normalizedInput.day || 0,
  2971. hours = normalizedInput.hour || 0,
  2972. minutes = normalizedInput.minute || 0,
  2973. seconds = normalizedInput.second || 0,
  2974. milliseconds = normalizedInput.millisecond || 0;
  2975. // representation for dateAddRemove
  2976. this._milliseconds = +milliseconds +
  2977. seconds * 1e3 + // 1000
  2978. minutes * 6e4 + // 1000 * 60
  2979. hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978
  2980. // Because of dateAddRemove treats 24 hours as different from a
  2981. // day when working around DST, we need to store them separately
  2982. this._days = +days +
  2983. weeks * 7;
  2984. // It is impossible translate months into days without knowing
  2985. // which months you are are talking about, so we have to store
  2986. // it separately.
  2987. this._months = +months +
  2988. quarters * 3 +
  2989. years * 12;
  2990. this._data = {};
  2991. this._locale = locale_locales__getLocale();
  2992. this._bubble();
  2993. }
  2994. function isDuration (obj) {
  2995. return obj instanceof Duration;
  2996. }
  2997. // FORMATTING
  2998. function offset (token, separator) {
  2999. addFormatToken(token, 0, 0, function () {
  3000. var offset = this.utcOffset();
  3001. var sign = '+';
  3002. if (offset < 0) {
  3003. offset = -offset;
  3004. sign = '-';
  3005. }
  3006. return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);
  3007. });
  3008. }
  3009. offset('Z', ':');
  3010. offset('ZZ', '');
  3011. // PARSING
  3012. addRegexToken('Z', matchShortOffset);
  3013. addRegexToken('ZZ', matchShortOffset);
  3014. addParseToken(['Z', 'ZZ'], function (input, array, config) {
  3015. config._useUTC = true;
  3016. config._tzm = offsetFromString(matchShortOffset, input);
  3017. });
  3018. // HELPERS
  3019. // timezone chunker
  3020. // '+10:00' > ['10', '00']
  3021. // '-1530' > ['-15', '30']
  3022. var chunkOffset = /([\+\-]|\d\d)/gi;
  3023. function offsetFromString(matcher, string) {
  3024. var matches = ((string || '').match(matcher) || []);
  3025. var chunk = matches[matches.length - 1] || [];
  3026. var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];
  3027. var minutes = +(parts[1] * 60) + toInt(parts[2]);
  3028. return parts[0] === '+' ? minutes : -minutes;
  3029. }
  3030. // Return a moment from input, that is local/utc/zone equivalent to model.
  3031. function cloneWithOffset(input, model) {
  3032. var res, diff;
  3033. if (model._isUTC) {
  3034. res = model.clone();
  3035. diff = (isMoment(input) || isDate(input) ? input.valueOf() : local__createLocal(input).valueOf()) - res.valueOf();
  3036. // Use low-level api, because this fn is low-level api.
  3037. res._d.setTime(res._d.valueOf() + diff);
  3038. utils_hooks__hooks.updateOffset(res, false);
  3039. return res;
  3040. } else {
  3041. return local__createLocal(input).local();
  3042. }
  3043. }
  3044. function getDateOffset (m) {
  3045. // On Firefox.24 Date#getTimezoneOffset returns a floating point.
  3046. // https://github.com/moment/moment/pull/1871
  3047. return -Math.round(m._d.getTimezoneOffset() / 15) * 15;
  3048. }
  3049. // HOOKS
  3050. // This function will be called whenever a moment is mutated.
  3051. // It is intended to keep the offset in sync with the timezone.
  3052. utils_hooks__hooks.updateOffset = function () {};
  3053. // MOMENTS
  3054. // keepLocalTime = true means only change the timezone, without
  3055. // affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->
  3056. // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset
  3057. // +0200, so we adjust the time as needed, to be valid.
  3058. //
  3059. // Keeping the time actually adds/subtracts (one hour)
  3060. // from the actual represented time. That is why we call updateOffset
  3061. // a second time. In case it wants us to change the offset again
  3062. // _changeInProgress == true case, then we have to adjust, because
  3063. // there is no such time in the given timezone.
  3064. function getSetOffset (input, keepLocalTime) {
  3065. var offset = this._offset || 0,
  3066. localAdjust;
  3067. if (!this.isValid()) {
  3068. return input != null ? this : NaN;
  3069. }
  3070. if (input != null) {
  3071. if (typeof input === 'string') {
  3072. input = offsetFromString(matchShortOffset, input);
  3073. } else if (Math.abs(input) < 16) {
  3074. input = input * 60;
  3075. }
  3076. if (!this._isUTC && keepLocalTime) {
  3077. localAdjust = getDateOffset(this);
  3078. }
  3079. this._offset = input;
  3080. this._isUTC = true;
  3081. if (localAdjust != null) {
  3082. this.add(localAdjust, 'm');
  3083. }
  3084. if (offset !== input) {
  3085. if (!keepLocalTime || this._changeInProgress) {
  3086. add_subtract__addSubtract(this, create__createDuration(input - offset, 'm'), 1, false);
  3087. } else if (!this._changeInProgress) {
  3088. this._changeInProgress = true;
  3089. utils_hooks__hooks.updateOffset(this, true);
  3090. this._changeInProgress = null;
  3091. }
  3092. }
  3093. return this;
  3094. } else {
  3095. return this._isUTC ? offset : getDateOffset(this);
  3096. }
  3097. }
  3098. function getSetZone (input, keepLocalTime) {
  3099. if (input != null) {
  3100. if (typeof input !== 'string') {
  3101. input = -input;
  3102. }
  3103. this.utcOffset(input, keepLocalTime);
  3104. return this;
  3105. } else {
  3106. return -this.utcOffset();
  3107. }
  3108. }
  3109. function setOffsetToUTC (keepLocalTime) {
  3110. return this.utcOffset(0, keepLocalTime);
  3111. }
  3112. function setOffsetToLocal (keepLocalTime) {
  3113. if (this._isUTC) {
  3114. this.utcOffset(0, keepLocalTime);
  3115. this._isUTC = false;
  3116. if (keepLocalTime) {
  3117. this.subtract(getDateOffset(this), 'm');
  3118. }
  3119. }
  3120. return this;
  3121. }
  3122. function setOffsetToParsedOffset () {
  3123. if (this._tzm) {
  3124. this.utcOffset(this._tzm);
  3125. } else if (typeof this._i === 'string') {
  3126. this.utcOffset(offsetFromString(matchOffset, this._i));
  3127. }
  3128. return this;
  3129. }
  3130. function hasAlignedHourOffset (input) {
  3131. if (!this.isValid()) {
  3132. return false;
  3133. }
  3134. input = input ? local__createLocal(input).utcOffset() : 0;
  3135. return (this.utcOffset() - input) % 60 === 0;
  3136. }
  3137. function isDaylightSavingTime () {
  3138. return (
  3139. this.utcOffset() > this.clone().month(0).utcOffset() ||
  3140. this.utcOffset() > this.clone().month(5).utcOffset()
  3141. );
  3142. }
  3143. function isDaylightSavingTimeShifted () {
  3144. if (!isUndefined(this._isDSTShifted)) {
  3145. return this._isDSTShifted;
  3146. }
  3147. var c = {};
  3148. copyConfig(c, this);
  3149. c = prepareConfig(c);
  3150. if (c._a) {
  3151. var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a);
  3152. this._isDSTShifted = this.isValid() &&
  3153. compareArrays(c._a, other.toArray()) > 0;
  3154. } else {
  3155. this._isDSTShifted = false;
  3156. }
  3157. return this._isDSTShifted;
  3158. }
  3159. function isLocal () {
  3160. return this.isValid() ? !this._isUTC : false;
  3161. }
  3162. function isUtcOffset () {
  3163. return this.isValid() ? this._isUTC : false;
  3164. }
  3165. function isUtc () {
  3166. return this.isValid() ? this._isUTC && this._offset === 0 : false;
  3167. }
  3168. // ASP.NET json date format regex
  3169. var aspNetRegex = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/;
  3170. // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
  3171. // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
  3172. // and further modified to allow for strings containing both week and day
  3173. var isoRegex = /^(-)?P(?:(-?[0-9,.]*)Y)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)W)?(?:(-?[0-9,.]*)D)?(?:T(?:(-?[0-9,.]*)H)?(?:(-?[0-9,.]*)M)?(?:(-?[0-9,.]*)S)?)?$/;
  3174. function create__createDuration (input, key) {
  3175. var duration = input,
  3176. // matching against regexp is expensive, do it on demand
  3177. match = null,
  3178. sign,
  3179. ret,
  3180. diffRes;
  3181. if (isDuration(input)) {
  3182. duration = {
  3183. ms : input._milliseconds,
  3184. d : input._days,
  3185. M : input._months
  3186. };
  3187. } else if (typeof input === 'number') {
  3188. duration = {};
  3189. if (key) {
  3190. duration[key] = input;
  3191. } else {
  3192. duration.milliseconds = input;
  3193. }
  3194. } else if (!!(match = aspNetRegex.exec(input))) {
  3195. sign = (match[1] === '-') ? -1 : 1;
  3196. duration = {
  3197. y : 0,
  3198. d : toInt(match[DATE]) * sign,
  3199. h : toInt(match[HOUR]) * sign,
  3200. m : toInt(match[MINUTE]) * sign,
  3201. s : toInt(match[SECOND]) * sign,
  3202. ms : toInt(match[MILLISECOND]) * sign
  3203. };
  3204. } else if (!!(match = isoRegex.exec(input))) {
  3205. sign = (match[1] === '-') ? -1 : 1;
  3206. duration = {
  3207. y : parseIso(match[2], sign),
  3208. M : parseIso(match[3], sign),
  3209. w : parseIso(match[4], sign),
  3210. d : parseIso(match[5], sign),
  3211. h : parseIso(match[6], sign),
  3212. m : parseIso(match[7], sign),
  3213. s : parseIso(match[8], sign)
  3214. };
  3215. } else if (duration == null) {// checks for null or undefined
  3216. duration = {};
  3217. } else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {
  3218. diffRes = momentsDifference(local__createLocal(duration.from), local__createLocal(duration.to));
  3219. duration = {};
  3220. duration.ms = diffRes.milliseconds;
  3221. duration.M = diffRes.months;
  3222. }
  3223. ret = new Duration(duration);
  3224. if (isDuration(input) && hasOwnProp(input, '_locale')) {
  3225. ret._locale = input._locale;
  3226. }
  3227. return ret;
  3228. }
  3229. create__createDuration.fn = Duration.prototype;
  3230. function parseIso (inp, sign) {
  3231. // We'd normally use ~~inp for this, but unfortunately it also
  3232. // converts floats to ints.
  3233. // inp may be undefined, so careful calling replace on it.
  3234. var res = inp && parseFloat(inp.replace(',', '.'));
  3235. // apply sign while we're at it
  3236. return (isNaN(res) ? 0 : res) * sign;
  3237. }
  3238. function positiveMomentsDifference(base, other) {
  3239. var res = {milliseconds: 0, months: 0};
  3240. res.months = other.month() - base.month() +
  3241. (other.year() - base.year()) * 12;
  3242. if (base.clone().add(res.months, 'M').isAfter(other)) {
  3243. --res.months;
  3244. }
  3245. res.milliseconds = +other - +(base.clone().add(res.months, 'M'));
  3246. return res;
  3247. }
  3248. function momentsDifference(base, other) {
  3249. var res;
  3250. if (!(base.isValid() && other.isValid())) {
  3251. return {milliseconds: 0, months: 0};
  3252. }
  3253. other = cloneWithOffset(other, base);
  3254. if (base.isBefore(other)) {
  3255. res = positiveMomentsDifference(base, other);
  3256. } else {
  3257. res = positiveMomentsDifference(other, base);
  3258. res.milliseconds = -res.milliseconds;
  3259. res.months = -res.months;
  3260. }
  3261. return res;
  3262. }
  3263. function absRound (number) {
  3264. if (number < 0) {
  3265. return Math.round(-1 * number) * -1;
  3266. } else {
  3267. return Math.round(number);
  3268. }
  3269. }
  3270. // TODO: remove 'name' arg after deprecation is removed
  3271. function createAdder(direction, name) {
  3272. return function (val, period) {
  3273. var dur, tmp;
  3274. //invert the arguments, but complain about it
  3275. if (period !== null && !isNaN(+period)) {
  3276. deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).');
  3277. tmp = val; val = period; period = tmp;
  3278. }
  3279. val = typeof val === 'string' ? +val : val;
  3280. dur = create__createDuration(val, period);
  3281. add_subtract__addSubtract(this, dur, direction);
  3282. return this;
  3283. };
  3284. }
  3285. function add_subtract__addSubtract (mom, duration, isAdding, updateOffset) {
  3286. var milliseconds = duration._milliseconds,
  3287. days = absRound(duration._days),
  3288. months = absRound(duration._months);
  3289. if (!mom.isValid()) {
  3290. // No op
  3291. return;
  3292. }
  3293. updateOffset = updateOffset == null ? true : updateOffset;
  3294. if (milliseconds) {
  3295. mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);
  3296. }
  3297. if (days) {
  3298. get_set__set(mom, 'Date', get_set__get(mom, 'Date') + days * isAdding);
  3299. }
  3300. if (months) {
  3301. setMonth(mom, get_set__get(mom, 'Month') + months * isAdding);
  3302. }
  3303. if (updateOffset) {
  3304. utils_hooks__hooks.updateOffset(mom, days || months);
  3305. }
  3306. }
  3307. var add_subtract__add = createAdder(1, 'add');
  3308. var add_subtract__subtract = createAdder(-1, 'subtract');
  3309. function moment_calendar__calendar (time, formats) {
  3310. // We want to compare the start of today, vs this.
  3311. // Getting start-of-today depends on whether we're local/utc/offset or not.
  3312. var now = time || local__createLocal(),
  3313. sod = cloneWithOffset(now, this).startOf('day'),
  3314. diff = this.diff(sod, 'days', true),
  3315. format = diff < -6 ? 'sameElse' :
  3316. diff < -1 ? 'lastWeek' :
  3317. diff < 0 ? 'lastDay' :
  3318. diff < 1 ? 'sameDay' :
  3319. diff < 2 ? 'nextDay' :
  3320. diff < 7 ? 'nextWeek' : 'sameElse';
  3321. var output = formats && (isFunction(formats[format]) ? formats[format]() : formats[format]);
  3322. return this.format(output || this.localeData().calendar(format, this, local__createLocal(now)));
  3323. }
  3324. function clone () {
  3325. return new Moment(this);
  3326. }
  3327. function isAfter (input, units) {
  3328. var localInput = isMoment(input) ? input : local__createLocal(input);
  3329. if (!(this.isValid() && localInput.isValid())) {
  3330. return false;
  3331. }
  3332. units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
  3333. if (units === 'millisecond') {
  3334. return this.valueOf() > localInput.valueOf();
  3335. } else {
  3336. return localInput.valueOf() < this.clone().startOf(units).valueOf();
  3337. }
  3338. }
  3339. function isBefore (input, units) {
  3340. var localInput = isMoment(input) ? input : local__createLocal(input);
  3341. if (!(this.isValid() && localInput.isValid())) {
  3342. return false;
  3343. }
  3344. units = normalizeUnits(!isUndefined(units) ? units : 'millisecond');
  3345. if (units === 'millisecond') {
  3346. return this.valueOf() < localInput.valueOf();
  3347. } else {
  3348. return this.clone().endOf(units).valueOf() < localInput.valueOf();
  3349. }
  3350. }
  3351. function isBetween (from, to, units, inclusivity) {
  3352. inclusivity = inclusivity || '()';
  3353. return (inclusivity[0] === '(' ? this.isAfter(from, units) : !this.isBefore(from, units)) &&
  3354. (inclusivity[1] === ')' ? this.isBefore(to, units) : !this.isAfter(to, units));
  3355. }
  3356. function isSame (input, units) {
  3357. var localInput = isMoment(input) ? input : local__createLocal(input),
  3358. inputMs;
  3359. if (!(this.isValid() && localInput.isValid())) {
  3360. return false;
  3361. }
  3362. units = normalizeUnits(units || 'millisecond');
  3363. if (units === 'millisecond') {
  3364. return this.valueOf() === localInput.valueOf();
  3365. } else {
  3366. inputMs = localInput.valueOf();
  3367. return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();
  3368. }
  3369. }
  3370. function isSameOrAfter (input, units) {
  3371. return this.isSame(input, units) || this.isAfter(input,units);
  3372. }
  3373. function isSameOrBefore (input, units) {
  3374. return this.isSame(input, units) || this.isBefore(input,units);
  3375. }
  3376. function diff (input, units, asFloat) {
  3377. var that,
  3378. zoneDelta,
  3379. delta, output;
  3380. if (!this.isValid()) {
  3381. return NaN;
  3382. }
  3383. that = cloneWithOffset(input, this);
  3384. if (!that.isValid()) {
  3385. return NaN;
  3386. }
  3387. zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;
  3388. units = normalizeUnits(units);
  3389. if (units === 'year' || units === 'month' || units === 'quarter') {
  3390. output = monthDiff(this, that);
  3391. if (units === 'quarter') {
  3392. output = output / 3;
  3393. } else if (units === 'year') {
  3394. output = output / 12;
  3395. }
  3396. } else {
  3397. delta = this - that;
  3398. output = units === 'second' ? delta / 1e3 : // 1000
  3399. units === 'minute' ? delta / 6e4 : // 1000 * 60
  3400. units === 'hour' ? delta / 36e5 : // 1000 * 60 * 60
  3401. units === 'day' ? (delta - zoneDelta) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
  3402. units === 'week' ? (delta - zoneDelta) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
  3403. delta;
  3404. }
  3405. return asFloat ? output : absFloor(output);
  3406. }
  3407. function monthDiff (a, b) {
  3408. // difference in months
  3409. var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),
  3410. // b is in (anchor - 1 month, anchor + 1 month)
  3411. anchor = a.clone().add(wholeMonthDiff, 'months'),
  3412. anchor2, adjust;
  3413. if (b - anchor < 0) {
  3414. anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');
  3415. // linear across the month
  3416. adjust = (b - anchor) / (anchor - anchor2);
  3417. } else {
  3418. anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');
  3419. // linear across the month
  3420. adjust = (b - anchor) / (anchor2 - anchor);
  3421. }
  3422. //check for negative zero, return zero if negative zero
  3423. return -(wholeMonthDiff + adjust) || 0;
  3424. }
  3425. utils_hooks__hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';
  3426. utils_hooks__hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';
  3427. function toString () {
  3428. return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');
  3429. }
  3430. function moment_format__toISOString () {
  3431. var m = this.clone().utc();
  3432. if (0 < m.year() && m.year() <= 9999) {
  3433. if (isFunction(Date.prototype.toISOString)) {
  3434. // native implementation is ~50x faster, use it when we can
  3435. return this.toDate().toISOString();
  3436. } else {
  3437. return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
  3438. }
  3439. } else {
  3440. return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
  3441. }
  3442. }
  3443. function format (inputString) {
  3444. if (!inputString) {
  3445. inputString = this.isUtc() ? utils_hooks__hooks.defaultFormatUtc : utils_hooks__hooks.defaultFormat;
  3446. }
  3447. var output = formatMoment(this, inputString);
  3448. return this.localeData().postformat(output);
  3449. }
  3450. function from (time, withoutSuffix) {
  3451. if (this.isValid() &&
  3452. ((isMoment(time) && time.isValid()) ||
  3453. local__createLocal(time).isValid())) {
  3454. return create__createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);
  3455. } else {
  3456. return this.localeData().invalidDate();
  3457. }
  3458. }
  3459. function fromNow (withoutSuffix) {
  3460. return this.from(local__createLocal(), withoutSuffix);
  3461. }
  3462. function to (time, withoutSuffix) {
  3463. if (this.isValid() &&
  3464. ((isMoment(time) && time.isValid()) ||
  3465. local__createLocal(time).isValid())) {
  3466. return create__createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);
  3467. } else {
  3468. return this.localeData().invalidDate();
  3469. }
  3470. }
  3471. function toNow (withoutSuffix) {
  3472. return this.to(local__createLocal(), withoutSuffix);
  3473. }
  3474. // If passed a locale key, it will set the locale for this
  3475. // instance. Otherwise, it will return the locale configuration
  3476. // variables for this instance.
  3477. function locale (key) {
  3478. var newLocaleData;
  3479. if (key === undefined) {
  3480. return this._locale._abbr;
  3481. } else {
  3482. newLocaleData = locale_locales__getLocale(key);
  3483. if (newLocaleData != null) {
  3484. this._locale = newLocaleData;
  3485. }
  3486. return this;
  3487. }
  3488. }
  3489. var lang = deprecate(
  3490. 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
  3491. function (key) {
  3492. if (key === undefined) {
  3493. return this.localeData();
  3494. } else {
  3495. return this.locale(key);
  3496. }
  3497. }
  3498. );
  3499. function localeData () {
  3500. return this._locale;
  3501. }
  3502. function startOf (units) {
  3503. units = normalizeUnits(units);
  3504. // the following switch intentionally omits break keywords
  3505. // to utilize falling through the cases.
  3506. switch (units) {
  3507. case 'year':
  3508. this.month(0);
  3509. /* falls through */
  3510. case 'quarter':
  3511. case 'month':
  3512. this.date(1);
  3513. /* falls through */
  3514. case 'week':
  3515. case 'isoWeek':
  3516. case 'day':
  3517. case 'date':
  3518. this.hours(0);
  3519. /* falls through */
  3520. case 'hour':
  3521. this.minutes(0);
  3522. /* falls through */
  3523. case 'minute':
  3524. this.seconds(0);
  3525. /* falls through */
  3526. case 'second':
  3527. this.milliseconds(0);
  3528. }
  3529. // weeks are a special case
  3530. if (units === 'week') {
  3531. this.weekday(0);
  3532. }
  3533. if (units === 'isoWeek') {
  3534. this.isoWeekday(1);
  3535. }
  3536. // quarters are also special
  3537. if (units === 'quarter') {
  3538. this.month(Math.floor(this.month() / 3) * 3);
  3539. }
  3540. return this;
  3541. }
  3542. function endOf (units) {
  3543. units = normalizeUnits(units);
  3544. if (units === undefined || units === 'millisecond') {
  3545. return this;
  3546. }
  3547. // 'date' is an alias for 'day', so it should be considered as such.
  3548. if (units === 'date') {
  3549. units = 'day';
  3550. }
  3551. return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
  3552. }
  3553. function to_type__valueOf () {
  3554. return this._d.valueOf() - ((this._offset || 0) * 60000);
  3555. }
  3556. function unix () {
  3557. return Math.floor(this.valueOf() / 1000);
  3558. }
  3559. function toDate () {
  3560. return this._offset ? new Date(this.valueOf()) : this._d;
  3561. }
  3562. function toArray () {
  3563. var m = this;
  3564. return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];
  3565. }
  3566. function toObject () {
  3567. var m = this;
  3568. return {
  3569. years: m.year(),
  3570. months: m.month(),
  3571. date: m.date(),
  3572. hours: m.hours(),
  3573. minutes: m.minutes(),
  3574. seconds: m.seconds(),
  3575. milliseconds: m.milliseconds()
  3576. };
  3577. }
  3578. function toJSON () {
  3579. // new Date(NaN).toJSON() === null
  3580. return this.isValid() ? this.toISOString() : null;
  3581. }
  3582. function moment_valid__isValid () {
  3583. return valid__isValid(this);
  3584. }
  3585. function parsingFlags () {
  3586. return extend({}, getParsingFlags(this));
  3587. }
  3588. function invalidAt () {
  3589. return getParsingFlags(this).overflow;
  3590. }
  3591. function creationData() {
  3592. return {
  3593. input: this._i,
  3594. format: this._f,
  3595. locale: this._locale,
  3596. isUTC: this._isUTC,
  3597. strict: this._strict
  3598. };
  3599. }
  3600. // FORMATTING
  3601. addFormatToken(0, ['gg', 2], 0, function () {
  3602. return this.weekYear() % 100;
  3603. });
  3604. addFormatToken(0, ['GG', 2], 0, function () {
  3605. return this.isoWeekYear() % 100;
  3606. });
  3607. function addWeekYearFormatToken (token, getter) {
  3608. addFormatToken(0, [token, token.length], 0, getter);
  3609. }
  3610. addWeekYearFormatToken('gggg', 'weekYear');
  3611. addWeekYearFormatToken('ggggg', 'weekYear');
  3612. addWeekYearFormatToken('GGGG', 'isoWeekYear');
  3613. addWeekYearFormatToken('GGGGG', 'isoWeekYear');
  3614. // ALIASES
  3615. addUnitAlias('weekYear', 'gg');
  3616. addUnitAlias('isoWeekYear', 'GG');
  3617. // PARSING
  3618. addRegexToken('G', matchSigned);
  3619. addRegexToken('g', matchSigned);
  3620. addRegexToken('GG', match1to2, match2);
  3621. addRegexToken('gg', match1to2, match2);
  3622. addRegexToken('GGGG', match1to4, match4);
  3623. addRegexToken('gggg', match1to4, match4);
  3624. addRegexToken('GGGGG', match1to6, match6);
  3625. addRegexToken('ggggg', match1to6, match6);
  3626. addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {
  3627. week[token.substr(0, 2)] = toInt(input);
  3628. });
  3629. addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {
  3630. week[token] = utils_hooks__hooks.parseTwoDigitYear(input);
  3631. });
  3632. // MOMENTS
  3633. function getSetWeekYear (input) {
  3634. return getSetWeekYearHelper.call(this,
  3635. input,
  3636. this.week(),
  3637. this.weekday(),
  3638. this.localeData()._week.dow,
  3639. this.localeData()._week.doy);
  3640. }
  3641. function getSetISOWeekYear (input) {
  3642. return getSetWeekYearHelper.call(this,
  3643. input, this.isoWeek(), this.isoWeekday(), 1, 4);
  3644. }
  3645. function getISOWeeksInYear () {
  3646. return weeksInYear(this.year(), 1, 4);
  3647. }
  3648. function getWeeksInYear () {
  3649. var weekInfo = this.localeData()._week;
  3650. return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);
  3651. }
  3652. function getSetWeekYearHelper(input, week, weekday, dow, doy) {
  3653. var weeksTarget;
  3654. if (input == null) {
  3655. return weekOfYear(this, dow, doy).year;
  3656. } else {
  3657. weeksTarget = weeksInYear(input, dow, doy);
  3658. if (week > weeksTarget) {
  3659. week = weeksTarget;
  3660. }
  3661. return setWeekAll.call(this, input, week, weekday, dow, doy);
  3662. }
  3663. }
  3664. function setWeekAll(weekYear, week, weekday, dow, doy) {
  3665. var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),
  3666. date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);
  3667. this.year(date.getUTCFullYear());
  3668. this.month(date.getUTCMonth());
  3669. this.date(date.getUTCDate());
  3670. return this;
  3671. }
  3672. // FORMATTING
  3673. addFormatToken('Q', 0, 'Qo', 'quarter');
  3674. // ALIASES
  3675. addUnitAlias('quarter', 'Q');
  3676. // PARSING
  3677. addRegexToken('Q', match1);
  3678. addParseToken('Q', function (input, array) {
  3679. array[MONTH] = (toInt(input) - 1) * 3;
  3680. });
  3681. // MOMENTS
  3682. function getSetQuarter (input) {
  3683. return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);
  3684. }
  3685. // FORMATTING
  3686. addFormatToken('w', ['ww', 2], 'wo', 'week');
  3687. addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');
  3688. // ALIASES
  3689. addUnitAlias('week', 'w');
  3690. addUnitAlias('isoWeek', 'W');
  3691. // PARSING
  3692. addRegexToken('w', match1to2);
  3693. addRegexToken('ww', match1to2, match2);
  3694. addRegexToken('W', match1to2);
  3695. addRegexToken('WW', match1to2, match2);
  3696. addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {
  3697. week[token.substr(0, 1)] = toInt(input);
  3698. });
  3699. // HELPERS
  3700. // LOCALES
  3701. function localeWeek (mom) {
  3702. return weekOfYear(mom, this._week.dow, this._week.doy).week;
  3703. }
  3704. var defaultLocaleWeek = {
  3705. dow : 0, // Sunday is the first day of the week.
  3706. doy : 6 // The week that contains Jan 1st is the first week of the year.
  3707. };
  3708. function localeFirstDayOfWeek () {
  3709. return this._week.dow;
  3710. }
  3711. function localeFirstDayOfYear () {
  3712. return this._week.doy;
  3713. }
  3714. // MOMENTS
  3715. function getSetWeek (input) {
  3716. var week = this.localeData().week(this);
  3717. return input == null ? week : this.add((input - week) * 7, 'd');
  3718. }
  3719. function getSetISOWeek (input) {
  3720. var week = weekOfYear(this, 1, 4).week;
  3721. return input == null ? week : this.add((input - week) * 7, 'd');
  3722. }
  3723. // FORMATTING
  3724. addFormatToken('D', ['DD', 2], 'Do', 'date');
  3725. // ALIASES
  3726. addUnitAlias('date', 'D');
  3727. // PARSING
  3728. addRegexToken('D', match1to2);
  3729. addRegexToken('DD', match1to2, match2);
  3730. addRegexToken('Do', function (isStrict, locale) {
  3731. return isStrict ? locale._ordinalParse : locale._ordinalParseLenient;
  3732. });
  3733. addParseToken(['D', 'DD'], DATE);
  3734. addParseToken('Do', function (input, array) {
  3735. array[DATE] = toInt(input.match(match1to2)[0], 10);
  3736. });
  3737. // MOMENTS
  3738. var getSetDayOfMonth = makeGetSet('Date', true);
  3739. // FORMATTING
  3740. addFormatToken('d', 0, 'do', 'day');
  3741. addFormatToken('dd', 0, 0, function (format) {
  3742. return this.localeData().weekdaysMin(this, format);
  3743. });
  3744. addFormatToken('ddd', 0, 0, function (format) {
  3745. return this.localeData().weekdaysShort(this, format);
  3746. });
  3747. addFormatToken('dddd', 0, 0, function (format) {
  3748. return this.localeData().weekdays(this, format);
  3749. });
  3750. addFormatToken('e', 0, 0, 'weekday');
  3751. addFormatToken('E', 0, 0, 'isoWeekday');
  3752. // ALIASES
  3753. addUnitAlias('day', 'd');
  3754. addUnitAlias('weekday', 'e');
  3755. addUnitAlias('isoWeekday', 'E');
  3756. // PARSING
  3757. addRegexToken('d', match1to2);
  3758. addRegexToken('e', match1to2);
  3759. addRegexToken('E', match1to2);
  3760. addRegexToken('dd', function (isStrict, locale) {
  3761. return locale.weekdaysMinRegex(isStrict);
  3762. });
  3763. addRegexToken('ddd', function (isStrict, locale) {
  3764. return locale.weekdaysShortRegex(isStrict);
  3765. });
  3766. addRegexToken('dddd', function (isStrict, locale) {
  3767. return locale.weekdaysRegex(isStrict);
  3768. });
  3769. addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {
  3770. var weekday = config._locale.weekdaysParse(input, token, config._strict);
  3771. // if we didn't get a weekday name, mark the date as invalid
  3772. if (weekday != null) {
  3773. week.d = weekday;
  3774. } else {
  3775. getParsingFlags(config).invalidWeekday = input;
  3776. }
  3777. });
  3778. addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {
  3779. week[token] = toInt(input);
  3780. });
  3781. // HELPERS
  3782. function parseWeekday(input, locale) {
  3783. if (typeof input !== 'string') {
  3784. return input;
  3785. }
  3786. if (!isNaN(input)) {
  3787. return parseInt(input, 10);
  3788. }
  3789. input = locale.weekdaysParse(input);
  3790. if (typeof input === 'number') {
  3791. return input;
  3792. }
  3793. return null;
  3794. }
  3795. // LOCALES
  3796. var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');
  3797. function localeWeekdays (m, format) {
  3798. return isArray(this._weekdays) ? this._weekdays[m.day()] :
  3799. this._weekdays[this._weekdays.isFormat.test(format) ? 'format' : 'standalone'][m.day()];
  3800. }
  3801. var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');
  3802. function localeWeekdaysShort (m) {
  3803. return this._weekdaysShort[m.day()];
  3804. }
  3805. var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');
  3806. function localeWeekdaysMin (m) {
  3807. return this._weekdaysMin[m.day()];
  3808. }
  3809. function day_of_week__handleStrictParse(weekdayName, format, strict) {
  3810. var i, ii, mom, llc = weekdayName.toLocaleLowerCase();
  3811. if (!this._weekdaysParse) {
  3812. this._weekdaysParse = [];
  3813. this._shortWeekdaysParse = [];
  3814. this._minWeekdaysParse = [];
  3815. for (i = 0; i < 7; ++i) {
  3816. mom = create_utc__createUTC([2000, 1]).day(i);
  3817. this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();
  3818. this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();
  3819. this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();
  3820. }
  3821. }
  3822. if (strict) {
  3823. if (format === 'dddd') {
  3824. ii = indexOf.call(this._weekdaysParse, llc);
  3825. return ii !== -1 ? ii : null;
  3826. } else if (format === 'ddd') {
  3827. ii = indexOf.call(this._shortWeekdaysParse, llc);
  3828. return ii !== -1 ? ii : null;
  3829. } else {
  3830. ii = indexOf.call(this._minWeekdaysParse, llc);
  3831. return ii !== -1 ? ii : null;
  3832. }
  3833. } else {
  3834. if (format === 'dddd') {
  3835. ii = indexOf.call(this._weekdaysParse, llc);
  3836. if (ii !== -1) {
  3837. return ii;
  3838. }
  3839. ii = indexOf.call(this._shortWeekdaysParse, llc);
  3840. if (ii !== -1) {
  3841. return ii;
  3842. }
  3843. ii = indexOf.call(this._minWeekdaysParse, llc);
  3844. return ii !== -1 ? ii : null;
  3845. } else if (format === 'ddd') {
  3846. ii = indexOf.call(this._shortWeekdaysParse, llc);
  3847. if (ii !== -1) {
  3848. return ii;
  3849. }
  3850. ii = indexOf.call(this._weekdaysParse, llc);
  3851. if (ii !== -1) {
  3852. return ii;
  3853. }
  3854. ii = indexOf.call(this._minWeekdaysParse, llc);
  3855. return ii !== -1 ? ii : null;
  3856. } else {
  3857. ii = indexOf.call(this._minWeekdaysParse, llc);
  3858. if (ii !== -1) {
  3859. return ii;
  3860. }
  3861. ii = indexOf.call(this._weekdaysParse, llc);
  3862. if (ii !== -1) {
  3863. return ii;
  3864. }
  3865. ii = indexOf.call(this._shortWeekdaysParse, llc);
  3866. return ii !== -1 ? ii : null;
  3867. }
  3868. }
  3869. }
  3870. function localeWeekdaysParse (weekdayName, format, strict) {
  3871. var i, mom, regex;
  3872. if (this._weekdaysParseExact) {
  3873. return day_of_week__handleStrictParse.call(this, weekdayName, format, strict);
  3874. }
  3875. if (!this._weekdaysParse) {
  3876. this._weekdaysParse = [];
  3877. this._minWeekdaysParse = [];
  3878. this._shortWeekdaysParse = [];
  3879. this._fullWeekdaysParse = [];
  3880. }
  3881. for (i = 0; i < 7; i++) {
  3882. // make the regex if we don't have it already
  3883. mom = create_utc__createUTC([2000, 1]).day(i);
  3884. if (strict && !this._fullWeekdaysParse[i]) {
  3885. this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\.?') + '$', 'i');
  3886. this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\.?') + '$', 'i');
  3887. this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\.?') + '$', 'i');
  3888. }
  3889. if (!this._weekdaysParse[i]) {
  3890. regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
  3891. this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
  3892. }
  3893. // test the regex
  3894. if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {
  3895. return i;
  3896. } else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {
  3897. return i;
  3898. } else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {
  3899. return i;
  3900. } else if (!strict && this._weekdaysParse[i].test(weekdayName)) {
  3901. return i;
  3902. }
  3903. }
  3904. }
  3905. // MOMENTS
  3906. function getSetDayOfWeek (input) {
  3907. if (!this.isValid()) {
  3908. return input != null ? this : NaN;
  3909. }
  3910. var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
  3911. if (input != null) {
  3912. input = parseWeekday(input, this.localeData());
  3913. return this.add(input - day, 'd');
  3914. } else {
  3915. return day;
  3916. }
  3917. }
  3918. function getSetLocaleDayOfWeek (input) {
  3919. if (!this.isValid()) {
  3920. return input != null ? this : NaN;
  3921. }
  3922. var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;
  3923. return input == null ? weekday : this.add(input - weekday, 'd');
  3924. }
  3925. function getSetISODayOfWeek (input) {
  3926. if (!this.isValid()) {
  3927. return input != null ? this : NaN;
  3928. }
  3929. // behaves the same as moment#day except
  3930. // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
  3931. // as a setter, sunday should belong to the previous week.
  3932. return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
  3933. }
  3934. var defaultWeekdaysRegex = matchWord;
  3935. function weekdaysRegex (isStrict) {
  3936. if (this._weekdaysParseExact) {
  3937. if (!hasOwnProp(this, '_weekdaysRegex')) {
  3938. computeWeekdaysParse.call(this);
  3939. }
  3940. if (isStrict) {
  3941. return this._weekdaysStrictRegex;
  3942. } else {
  3943. return this._weekdaysRegex;
  3944. }
  3945. } else {
  3946. return this._weekdaysStrictRegex && isStrict ?
  3947. this._weekdaysStrictRegex : this._weekdaysRegex;
  3948. }
  3949. }
  3950. var defaultWeekdaysShortRegex = matchWord;
  3951. function weekdaysShortRegex (isStrict) {
  3952. if (this._weekdaysParseExact) {
  3953. if (!hasOwnProp(this, '_weekdaysRegex')) {
  3954. computeWeekdaysParse.call(this);
  3955. }
  3956. if (isStrict) {
  3957. return this._weekdaysShortStrictRegex;
  3958. } else {
  3959. return this._weekdaysShortRegex;
  3960. }
  3961. } else {
  3962. return this._weekdaysShortStrictRegex && isStrict ?
  3963. this._weekdaysShortStrictRegex : this._weekdaysShortRegex;
  3964. }
  3965. }
  3966. var defaultWeekdaysMinRegex = matchWord;
  3967. function weekdaysMinRegex (isStrict) {
  3968. if (this._weekdaysParseExact) {
  3969. if (!hasOwnProp(this, '_weekdaysRegex')) {
  3970. computeWeekdaysParse.call(this);
  3971. }
  3972. if (isStrict) {
  3973. return this._weekdaysMinStrictRegex;
  3974. } else {
  3975. return this._weekdaysMinRegex;
  3976. }
  3977. } else {
  3978. return this._weekdaysMinStrictRegex && isStrict ?
  3979. this._weekdaysMinStrictRegex : this._weekdaysMinRegex;
  3980. }
  3981. }
  3982. function computeWeekdaysParse () {
  3983. function cmpLenRev(a, b) {
  3984. return b.length - a.length;
  3985. }
  3986. var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],
  3987. i, mom, minp, shortp, longp;
  3988. for (i = 0; i < 7; i++) {
  3989. // make the regex if we don't have it already
  3990. mom = create_utc__createUTC([2000, 1]).day(i);
  3991. minp = this.weekdaysMin(mom, '');
  3992. shortp = this.weekdaysShort(mom, '');
  3993. longp = this.weekdays(mom, '');
  3994. minPieces.push(minp);
  3995. shortPieces.push(shortp);
  3996. longPieces.push(longp);
  3997. mixedPieces.push(minp);
  3998. mixedPieces.push(shortp);
  3999. mixedPieces.push(longp);
  4000. }
  4001. // Sorting makes sure if one weekday (or abbr) is a prefix of another it
  4002. // will match the longer piece.
  4003. minPieces.sort(cmpLenRev);
  4004. shortPieces.sort(cmpLenRev);
  4005. longPieces.sort(cmpLenRev);
  4006. mixedPieces.sort(cmpLenRev);
  4007. for (i = 0; i < 7; i++) {
  4008. shortPieces[i] = regexEscape(shortPieces[i]);
  4009. longPieces[i] = regexEscape(longPieces[i]);
  4010. mixedPieces[i] = regexEscape(mixedPieces[i]);
  4011. }
  4012. this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
  4013. this._weekdaysShortRegex = this._weekdaysRegex;
  4014. this._weekdaysMinRegex = this._weekdaysRegex;
  4015. this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');
  4016. this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');
  4017. this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');
  4018. }
  4019. // FORMATTING
  4020. addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');
  4021. // ALIASES
  4022. addUnitAlias('dayOfYear', 'DDD');
  4023. // PARSING
  4024. addRegexToken('DDD', match1to3);
  4025. addRegexToken('DDDD', match3);
  4026. addParseToken(['DDD', 'DDDD'], function (input, array, config) {
  4027. config._dayOfYear = toInt(input);
  4028. });
  4029. // HELPERS
  4030. // MOMENTS
  4031. function getSetDayOfYear (input) {
  4032. var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;
  4033. return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');
  4034. }
  4035. // FORMATTING
  4036. function hFormat() {
  4037. return this.hours() % 12 || 12;
  4038. }
  4039. function kFormat() {
  4040. return this.hours() || 24;
  4041. }
  4042. addFormatToken('H', ['HH', 2], 0, 'hour');
  4043. addFormatToken('h', ['hh', 2], 0, hFormat);
  4044. addFormatToken('k', ['kk', 2], 0, kFormat);
  4045. addFormatToken('hmm', 0, 0, function () {
  4046. return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);
  4047. });
  4048. addFormatToken('hmmss', 0, 0, function () {
  4049. return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +
  4050. zeroFill(this.seconds(), 2);
  4051. });
  4052. addFormatToken('Hmm', 0, 0, function () {
  4053. return '' + this.hours() + zeroFill(this.minutes(), 2);
  4054. });
  4055. addFormatToken('Hmmss', 0, 0, function () {
  4056. return '' + this.hours() + zeroFill(this.minutes(), 2) +
  4057. zeroFill(this.seconds(), 2);
  4058. });
  4059. function meridiem (token, lowercase) {
  4060. addFormatToken(token, 0, 0, function () {
  4061. return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);
  4062. });
  4063. }
  4064. meridiem('a', true);
  4065. meridiem('A', false);
  4066. // ALIASES
  4067. addUnitAlias('hour', 'h');
  4068. // PARSING
  4069. function matchMeridiem (isStrict, locale) {
  4070. return locale._meridiemParse;
  4071. }
  4072. addRegexToken('a', matchMeridiem);
  4073. addRegexToken('A', matchMeridiem);
  4074. addRegexToken('H', match1to2);
  4075. addRegexToken('h', match1to2);
  4076. addRegexToken('HH', match1to2, match2);
  4077. addRegexToken('hh', match1to2, match2);
  4078. addRegexToken('hmm', match3to4);
  4079. addRegexToken('hmmss', match5to6);
  4080. addRegexToken('Hmm', match3to4);
  4081. addRegexToken('Hmmss', match5to6);
  4082. addParseToken(['H', 'HH'], HOUR);
  4083. addParseToken(['a', 'A'], function (input, array, config) {
  4084. config._isPm = config._locale.isPM(input);
  4085. config._meridiem = input;
  4086. });
  4087. addParseToken(['h', 'hh'], function (input, array, config) {
  4088. array[HOUR] = toInt(input);
  4089. getParsingFlags(config).bigHour = true;
  4090. });
  4091. addParseToken('hmm', function (input, array, config) {
  4092. var pos = input.length - 2;
  4093. array[HOUR] = toInt(input.substr(0, pos));
  4094. array[MINUTE] = toInt(input.substr(pos));
  4095. getParsingFlags(config).bigHour = true;
  4096. });
  4097. addParseToken('hmmss', function (input, array, config) {
  4098. var pos1 = input.length - 4;
  4099. var pos2 = input.length - 2;
  4100. array[HOUR] = toInt(input.substr(0, pos1));
  4101. array[MINUTE] = toInt(input.substr(pos1, 2));
  4102. array[SECOND] = toInt(input.substr(pos2));
  4103. getParsingFlags(config).bigHour = true;
  4104. });
  4105. addParseToken('Hmm', function (input, array, config) {
  4106. var pos = input.length - 2;
  4107. array[HOUR] = toInt(input.substr(0, pos));
  4108. array[MINUTE] = toInt(input.substr(pos));
  4109. });
  4110. addParseToken('Hmmss', function (input, array, config) {
  4111. var pos1 = input.length - 4;
  4112. var pos2 = input.length - 2;
  4113. array[HOUR] = toInt(input.substr(0, pos1));
  4114. array[MINUTE] = toInt(input.substr(pos1, 2));
  4115. array[SECOND] = toInt(input.substr(pos2));
  4116. });
  4117. // LOCALES
  4118. function localeIsPM (input) {
  4119. // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
  4120. // Using charAt should be more compatible.
  4121. return ((input + '').toLowerCase().charAt(0) === 'p');
  4122. }
  4123. var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;
  4124. function localeMeridiem (hours, minutes, isLower) {
  4125. if (hours > 11) {
  4126. return isLower ? 'pm' : 'PM';
  4127. } else {
  4128. return isLower ? 'am' : 'AM';
  4129. }
  4130. }
  4131. // MOMENTS
  4132. // Setting the hour should keep the time, because the user explicitly
  4133. // specified which hour he wants. So trying to maintain the same hour (in
  4134. // a new timezone) makes sense. Adding/subtracting hours does not follow
  4135. // this rule.
  4136. var getSetHour = makeGetSet('Hours', true);
  4137. // FORMATTING
  4138. addFormatToken('m', ['mm', 2], 0, 'minute');
  4139. // ALIASES
  4140. addUnitAlias('minute', 'm');
  4141. // PARSING
  4142. addRegexToken('m', match1to2);
  4143. addRegexToken('mm', match1to2, match2);
  4144. addParseToken(['m', 'mm'], MINUTE);
  4145. // MOMENTS
  4146. var getSetMinute = makeGetSet('Minutes', false);
  4147. // FORMATTING
  4148. addFormatToken('s', ['ss', 2], 0, 'second');
  4149. // ALIASES
  4150. addUnitAlias('second', 's');
  4151. // PARSING
  4152. addRegexToken('s', match1to2);
  4153. addRegexToken('ss', match1to2, match2);
  4154. addParseToken(['s', 'ss'], SECOND);
  4155. // MOMENTS
  4156. var getSetSecond = makeGetSet('Seconds', false);
  4157. // FORMATTING
  4158. addFormatToken('S', 0, 0, function () {
  4159. return ~~(this.millisecond() / 100);
  4160. });
  4161. addFormatToken(0, ['SS', 2], 0, function () {
  4162. return ~~(this.millisecond() / 10);
  4163. });
  4164. addFormatToken(0, ['SSS', 3], 0, 'millisecond');
  4165. addFormatToken(0, ['SSSS', 4], 0, function () {
  4166. return this.millisecond() * 10;
  4167. });
  4168. addFormatToken(0, ['SSSSS', 5], 0, function () {
  4169. return this.millisecond() * 100;
  4170. });
  4171. addFormatToken(0, ['SSSSSS', 6], 0, function () {
  4172. return this.millisecond() * 1000;
  4173. });
  4174. addFormatToken(0, ['SSSSSSS', 7], 0, function () {
  4175. return this.millisecond() * 10000;
  4176. });
  4177. addFormatToken(0, ['SSSSSSSS', 8], 0, function () {
  4178. return this.millisecond() * 100000;
  4179. });
  4180. addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {
  4181. return this.millisecond() * 1000000;
  4182. });
  4183. // ALIASES
  4184. addUnitAlias('millisecond', 'ms');
  4185. // PARSING
  4186. addRegexToken('S', match1to3, match1);
  4187. addRegexToken('SS', match1to3, match2);
  4188. addRegexToken('SSS', match1to3, match3);
  4189. var token;
  4190. for (token = 'SSSS'; token.length <= 9; token += 'S') {
  4191. addRegexToken(token, matchUnsigned);
  4192. }
  4193. function parseMs(input, array) {
  4194. array[MILLISECOND] = toInt(('0.' + input) * 1000);
  4195. }
  4196. for (token = 'S'; token.length <= 9; token += 'S') {
  4197. addParseToken(token, parseMs);
  4198. }
  4199. // MOMENTS
  4200. var getSetMillisecond = makeGetSet('Milliseconds', false);
  4201. // FORMATTING
  4202. addFormatToken('z', 0, 0, 'zoneAbbr');
  4203. addFormatToken('zz', 0, 0, 'zoneName');
  4204. // MOMENTS
  4205. function getZoneAbbr () {
  4206. return this._isUTC ? 'UTC' : '';
  4207. }
  4208. function getZoneName () {
  4209. return this._isUTC ? 'Coordinated Universal Time' : '';
  4210. }
  4211. var momentPrototype__proto = Moment.prototype;
  4212. momentPrototype__proto.add = add_subtract__add;
  4213. momentPrototype__proto.calendar = moment_calendar__calendar;
  4214. momentPrototype__proto.clone = clone;
  4215. momentPrototype__proto.diff = diff;
  4216. momentPrototype__proto.endOf = endOf;
  4217. momentPrototype__proto.format = format;
  4218. momentPrototype__proto.from = from;
  4219. momentPrototype__proto.fromNow = fromNow;
  4220. momentPrototype__proto.to = to;
  4221. momentPrototype__proto.toNow = toNow;
  4222. momentPrototype__proto.get = getSet;
  4223. momentPrototype__proto.invalidAt = invalidAt;
  4224. momentPrototype__proto.isAfter = isAfter;
  4225. momentPrototype__proto.isBefore = isBefore;
  4226. momentPrototype__proto.isBetween = isBetween;
  4227. momentPrototype__proto.isSame = isSame;
  4228. momentPrototype__proto.isSameOrAfter = isSameOrAfter;
  4229. momentPrototype__proto.isSameOrBefore = isSameOrBefore;
  4230. momentPrototype__proto.isValid = moment_valid__isValid;
  4231. momentPrototype__proto.lang = lang;
  4232. momentPrototype__proto.locale = locale;
  4233. momentPrototype__proto.localeData = localeData;
  4234. momentPrototype__proto.max = prototypeMax;
  4235. momentPrototype__proto.min = prototypeMin;
  4236. momentPrototype__proto.parsingFlags = parsingFlags;
  4237. momentPrototype__proto.set = getSet;
  4238. momentPrototype__proto.startOf = startOf;
  4239. momentPrototype__proto.subtract = add_subtract__subtract;
  4240. momentPrototype__proto.toArray = toArray;
  4241. momentPrototype__proto.toObject = toObject;
  4242. momentPrototype__proto.toDate = toDate;
  4243. momentPrototype__proto.toISOString = moment_format__toISOString;
  4244. momentPrototype__proto.toJSON = toJSON;
  4245. momentPrototype__proto.toString = toString;
  4246. momentPrototype__proto.unix = unix;
  4247. momentPrototype__proto.valueOf = to_type__valueOf;
  4248. momentPrototype__proto.creationData = creationData;
  4249. // Year
  4250. momentPrototype__proto.year = getSetYear;
  4251. momentPrototype__proto.isLeapYear = getIsLeapYear;
  4252. // Week Year
  4253. momentPrototype__proto.weekYear = getSetWeekYear;
  4254. momentPrototype__proto.isoWeekYear = getSetISOWeekYear;
  4255. // Quarter
  4256. momentPrototype__proto.quarter = momentPrototype__proto.quarters = getSetQuarter;
  4257. // Month
  4258. momentPrototype__proto.month = getSetMonth;
  4259. momentPrototype__proto.daysInMonth = getDaysInMonth;
  4260. // Week
  4261. momentPrototype__proto.week = momentPrototype__proto.weeks = getSetWeek;
  4262. momentPrototype__proto.isoWeek = momentPrototype__proto.isoWeeks = getSetISOWeek;
  4263. momentPrototype__proto.weeksInYear = getWeeksInYear;
  4264. momentPrototype__proto.isoWeeksInYear = getISOWeeksInYear;
  4265. // Day
  4266. momentPrototype__proto.date = getSetDayOfMonth;
  4267. momentPrototype__proto.day = momentPrototype__proto.days = getSetDayOfWeek;
  4268. momentPrototype__proto.weekday = getSetLocaleDayOfWeek;
  4269. momentPrototype__proto.isoWeekday = getSetISODayOfWeek;
  4270. momentPrototype__proto.dayOfYear = getSetDayOfYear;
  4271. // Hour
  4272. momentPrototype__proto.hour = momentPrototype__proto.hours = getSetHour;
  4273. // Minute
  4274. momentPrototype__proto.minute = momentPrototype__proto.minutes = getSetMinute;
  4275. // Second
  4276. momentPrototype__proto.second = momentPrototype__proto.seconds = getSetSecond;
  4277. // Millisecond
  4278. momentPrototype__proto.millisecond = momentPrototype__proto.milliseconds = getSetMillisecond;
  4279. // Offset
  4280. momentPrototype__proto.utcOffset = getSetOffset;
  4281. momentPrototype__proto.utc = setOffsetToUTC;
  4282. momentPrototype__proto.local = setOffsetToLocal;
  4283. momentPrototype__proto.parseZone = setOffsetToParsedOffset;
  4284. momentPrototype__proto.hasAlignedHourOffset = hasAlignedHourOffset;
  4285. momentPrototype__proto.isDST = isDaylightSavingTime;
  4286. momentPrototype__proto.isDSTShifted = isDaylightSavingTimeShifted;
  4287. momentPrototype__proto.isLocal = isLocal;
  4288. momentPrototype__proto.isUtcOffset = isUtcOffset;
  4289. momentPrototype__proto.isUtc = isUtc;
  4290. momentPrototype__proto.isUTC = isUtc;
  4291. // Timezone
  4292. momentPrototype__proto.zoneAbbr = getZoneAbbr;
  4293. momentPrototype__proto.zoneName = getZoneName;
  4294. // Deprecations
  4295. momentPrototype__proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);
  4296. momentPrototype__proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);
  4297. momentPrototype__proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);
  4298. momentPrototype__proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779', getSetZone);
  4299. var momentPrototype = momentPrototype__proto;
  4300. function moment__createUnix (input) {
  4301. return local__createLocal(input * 1000);
  4302. }
  4303. function moment__createInZone () {
  4304. return local__createLocal.apply(null, arguments).parseZone();
  4305. }
  4306. var defaultCalendar = {
  4307. sameDay : '[Today at] LT',
  4308. nextDay : '[Tomorrow at] LT',
  4309. nextWeek : 'dddd [at] LT',
  4310. lastDay : '[Yesterday at] LT',
  4311. lastWeek : '[Last] dddd [at] LT',
  4312. sameElse : 'L'
  4313. };
  4314. function locale_calendar__calendar (key, mom, now) {
  4315. var output = this._calendar[key];
  4316. return isFunction(output) ? output.call(mom, now) : output;
  4317. }
  4318. var defaultLongDateFormat = {
  4319. LTS : 'h:mm:ss A',
  4320. LT : 'h:mm A',
  4321. L : 'MM/DD/YYYY',
  4322. LL : 'MMMM D, YYYY',
  4323. LLL : 'MMMM D, YYYY h:mm A',
  4324. LLLL : 'dddd, MMMM D, YYYY h:mm A'
  4325. };
  4326. function longDateFormat (key) {
  4327. var format = this._longDateFormat[key],
  4328. formatUpper = this._longDateFormat[key.toUpperCase()];
  4329. if (format || !formatUpper) {
  4330. return format;
  4331. }
  4332. this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {
  4333. return val.slice(1);
  4334. });
  4335. return this._longDateFormat[key];
  4336. }
  4337. var defaultInvalidDate = 'Invalid date';
  4338. function invalidDate () {
  4339. return this._invalidDate;
  4340. }
  4341. var defaultOrdinal = '%d';
  4342. var defaultOrdinalParse = /\d{1,2}/;
  4343. function ordinal (number) {
  4344. return this._ordinal.replace('%d', number);
  4345. }
  4346. function preParsePostFormat (string) {
  4347. return string;
  4348. }
  4349. var defaultRelativeTime = {
  4350. future : 'in %s',
  4351. past : '%s ago',
  4352. s : 'a few seconds',
  4353. m : 'a minute',
  4354. mm : '%d minutes',
  4355. h : 'an hour',
  4356. hh : '%d hours',
  4357. d : 'a day',
  4358. dd : '%d days',
  4359. M : 'a month',
  4360. MM : '%d months',
  4361. y : 'a year',
  4362. yy : '%d years'
  4363. };
  4364. function relative__relativeTime (number, withoutSuffix, string, isFuture) {
  4365. var output = this._relativeTime[string];
  4366. return (isFunction(output)) ?
  4367. output(number, withoutSuffix, string, isFuture) :
  4368. output.replace(/%d/i, number);
  4369. }
  4370. function pastFuture (diff, output) {
  4371. var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
  4372. return isFunction(format) ? format(output) : format.replace(/%s/i, output);
  4373. }
  4374. var prototype__proto = Locale.prototype;
  4375. prototype__proto._calendar = defaultCalendar;
  4376. prototype__proto.calendar = locale_calendar__calendar;
  4377. prototype__proto._longDateFormat = defaultLongDateFormat;
  4378. prototype__proto.longDateFormat = longDateFormat;
  4379. prototype__proto._invalidDate = defaultInvalidDate;
  4380. prototype__proto.invalidDate = invalidDate;
  4381. prototype__proto._ordinal = defaultOrdinal;
  4382. prototype__proto.ordinal = ordinal;
  4383. prototype__proto._ordinalParse = defaultOrdinalParse;
  4384. prototype__proto.preparse = preParsePostFormat;
  4385. prototype__proto.postformat = preParsePostFormat;
  4386. prototype__proto._relativeTime = defaultRelativeTime;
  4387. prototype__proto.relativeTime = relative__relativeTime;
  4388. prototype__proto.pastFuture = pastFuture;
  4389. prototype__proto.set = locale_set__set;
  4390. // Month
  4391. prototype__proto.months = localeMonths;
  4392. prototype__proto._months = defaultLocaleMonths;
  4393. prototype__proto.monthsShort = localeMonthsShort;
  4394. prototype__proto._monthsShort = defaultLocaleMonthsShort;
  4395. prototype__proto.monthsParse = localeMonthsParse;
  4396. prototype__proto._monthsRegex = defaultMonthsRegex;
  4397. prototype__proto.monthsRegex = monthsRegex;
  4398. prototype__proto._monthsShortRegex = defaultMonthsShortRegex;
  4399. prototype__proto.monthsShortRegex = monthsShortRegex;
  4400. // Week
  4401. prototype__proto.week = localeWeek;
  4402. prototype__proto._week = defaultLocaleWeek;
  4403. prototype__proto.firstDayOfYear = localeFirstDayOfYear;
  4404. prototype__proto.firstDayOfWeek = localeFirstDayOfWeek;
  4405. // Day of Week
  4406. prototype__proto.weekdays = localeWeekdays;
  4407. prototype__proto._weekdays = defaultLocaleWeekdays;
  4408. prototype__proto.weekdaysMin = localeWeekdaysMin;
  4409. prototype__proto._weekdaysMin = defaultLocaleWeekdaysMin;
  4410. prototype__proto.weekdaysShort = localeWeekdaysShort;
  4411. prototype__proto._weekdaysShort = defaultLocaleWeekdaysShort;
  4412. prototype__proto.weekdaysParse = localeWeekdaysParse;
  4413. prototype__proto._weekdaysRegex = defaultWeekdaysRegex;
  4414. prototype__proto.weekdaysRegex = weekdaysRegex;
  4415. prototype__proto._weekdaysShortRegex = defaultWeekdaysShortRegex;
  4416. prototype__proto.weekdaysShortRegex = weekdaysShortRegex;
  4417. prototype__proto._weekdaysMinRegex = defaultWeekdaysMinRegex;
  4418. prototype__proto.weekdaysMinRegex = weekdaysMinRegex;
  4419. // Hours
  4420. prototype__proto.isPM = localeIsPM;
  4421. prototype__proto._meridiemParse = defaultLocaleMeridiemParse;
  4422. prototype__proto.meridiem = localeMeridiem;
  4423. function lists__get (format, index, field, setter) {
  4424. var locale = locale_locales__getLocale();
  4425. var utc = create_utc__createUTC().set(setter, index);
  4426. return locale[field](utc, format);
  4427. }
  4428. function listMonthsImpl (format, index, field) {
  4429. if (typeof format === 'number') {
  4430. index = format;
  4431. format = undefined;
  4432. }
  4433. format = format || '';
  4434. if (index != null) {
  4435. return lists__get(format, index, field, 'month');
  4436. }
  4437. var i;
  4438. var out = [];
  4439. for (i = 0; i < 12; i++) {
  4440. out[i] = lists__get(format, i, field, 'month');
  4441. }
  4442. return out;
  4443. }
  4444. // ()
  4445. // (5)
  4446. // (fmt, 5)
  4447. // (fmt)
  4448. // (true)
  4449. // (true, 5)
  4450. // (true, fmt, 5)
  4451. // (true, fmt)
  4452. function listWeekdaysImpl (localeSorted, format, index, field) {
  4453. if (typeof localeSorted === 'boolean') {
  4454. if (typeof format === 'number') {
  4455. index = format;
  4456. format = undefined;
  4457. }
  4458. format = format || '';
  4459. } else {
  4460. format = localeSorted;
  4461. index = format;
  4462. localeSorted = false;
  4463. if (typeof format === 'number') {
  4464. index = format;
  4465. format = undefined;
  4466. }
  4467. format = format || '';
  4468. }
  4469. var locale = locale_locales__getLocale(),
  4470. shift = localeSorted ? locale._week.dow : 0;
  4471. if (index != null) {
  4472. return lists__get(format, (index + shift) % 7, field, 'day');
  4473. }
  4474. var i;
  4475. var out = [];
  4476. for (i = 0; i < 7; i++) {
  4477. out[i] = lists__get(format, (i + shift) % 7, field, 'day');
  4478. }
  4479. return out;
  4480. }
  4481. function lists__listMonths (format, index) {
  4482. return listMonthsImpl(format, index, 'months');
  4483. }
  4484. function lists__listMonthsShort (format, index) {
  4485. return listMonthsImpl(format, index, 'monthsShort');
  4486. }
  4487. function lists__listWeekdays (localeSorted, format, index) {
  4488. return listWeekdaysImpl(localeSorted, format, index, 'weekdays');
  4489. }
  4490. function lists__listWeekdaysShort (localeSorted, format, index) {
  4491. return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');
  4492. }
  4493. function lists__listWeekdaysMin (localeSorted, format, index) {
  4494. return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');
  4495. }
  4496. locale_locales__getSetGlobalLocale('en', {
  4497. ordinalParse: /\d{1,2}(th|st|nd|rd)/,
  4498. ordinal : function (number) {
  4499. var b = number % 10,
  4500. output = (toInt(number % 100 / 10) === 1) ? 'th' :
  4501. (b === 1) ? 'st' :
  4502. (b === 2) ? 'nd' :
  4503. (b === 3) ? 'rd' : 'th';
  4504. return number + output;
  4505. }
  4506. });
  4507. // Side effect imports
  4508. utils_hooks__hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', locale_locales__getSetGlobalLocale);
  4509. utils_hooks__hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', locale_locales__getLocale);
  4510. var mathAbs = Math.abs;
  4511. function duration_abs__abs () {
  4512. var data = this._data;
  4513. this._milliseconds = mathAbs(this._milliseconds);
  4514. this._days = mathAbs(this._days);
  4515. this._months = mathAbs(this._months);
  4516. data.milliseconds = mathAbs(data.milliseconds);
  4517. data.seconds = mathAbs(data.seconds);
  4518. data.minutes = mathAbs(data.minutes);
  4519. data.hours = mathAbs(data.hours);
  4520. data.months = mathAbs(data.months);
  4521. data.years = mathAbs(data.years);
  4522. return this;
  4523. }
  4524. function duration_add_subtract__addSubtract (duration, input, value, direction) {
  4525. var other = create__createDuration(input, value);
  4526. duration._milliseconds += direction * other._milliseconds;
  4527. duration._days += direction * other._days;
  4528. duration._months += direction * other._months;
  4529. return duration._bubble();
  4530. }
  4531. // supports only 2.0-style add(1, 's') or add(duration)
  4532. function duration_add_subtract__add (input, value) {
  4533. return duration_add_subtract__addSubtract(this, input, value, 1);
  4534. }
  4535. // supports only 2.0-style subtract(1, 's') or subtract(duration)
  4536. function duration_add_subtract__subtract (input, value) {
  4537. return duration_add_subtract__addSubtract(this, input, value, -1);
  4538. }
  4539. function absCeil (number) {
  4540. if (number < 0) {
  4541. return Math.floor(number);
  4542. } else {
  4543. return Math.ceil(number);
  4544. }
  4545. }
  4546. function bubble () {
  4547. var milliseconds = this._milliseconds;
  4548. var days = this._days;
  4549. var months = this._months;
  4550. var data = this._data;
  4551. var seconds, minutes, hours, years, monthsFromDays;
  4552. // if we have a mix of positive and negative values, bubble down first
  4553. // check: https://github.com/moment/moment/issues/2166
  4554. if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||
  4555. (milliseconds <= 0 && days <= 0 && months <= 0))) {
  4556. milliseconds += absCeil(monthsToDays(months) + days) * 864e5;
  4557. days = 0;
  4558. months = 0;
  4559. }
  4560. // The following code bubbles up values, see the tests for
  4561. // examples of what that means.
  4562. data.milliseconds = milliseconds % 1000;
  4563. seconds = absFloor(milliseconds / 1000);
  4564. data.seconds = seconds % 60;
  4565. minutes = absFloor(seconds / 60);
  4566. data.minutes = minutes % 60;
  4567. hours = absFloor(minutes / 60);
  4568. data.hours = hours % 24;
  4569. days += absFloor(hours / 24);
  4570. // convert days to months
  4571. monthsFromDays = absFloor(daysToMonths(days));
  4572. months += monthsFromDays;
  4573. days -= absCeil(monthsToDays(monthsFromDays));
  4574. // 12 months -> 1 year
  4575. years = absFloor(months / 12);
  4576. months %= 12;
  4577. data.days = days;
  4578. data.months = months;
  4579. data.years = years;
  4580. return this;
  4581. }
  4582. function daysToMonths (days) {
  4583. // 400 years have 146097 days (taking into account leap year rules)
  4584. // 400 years have 12 months === 4800
  4585. return days * 4800 / 146097;
  4586. }
  4587. function monthsToDays (months) {
  4588. // the reverse of daysToMonths
  4589. return months * 146097 / 4800;
  4590. }
  4591. function as (units) {
  4592. var days;
  4593. var months;
  4594. var milliseconds = this._milliseconds;
  4595. units = normalizeUnits(units);
  4596. if (units === 'month' || units === 'year') {
  4597. days = this._days + milliseconds / 864e5;
  4598. months = this._months + daysToMonths(days);
  4599. return units === 'month' ? months : months / 12;
  4600. } else {
  4601. // handle milliseconds separately because of floating point math errors (issue #1867)
  4602. days = this._days + Math.round(monthsToDays(this._months));
  4603. switch (units) {
  4604. case 'week' : return days / 7 + milliseconds / 6048e5;
  4605. case 'day' : return days + milliseconds / 864e5;
  4606. case 'hour' : return days * 24 + milliseconds / 36e5;
  4607. case 'minute' : return days * 1440 + milliseconds / 6e4;
  4608. case 'second' : return days * 86400 + milliseconds / 1000;
  4609. // Math.floor prevents floating point math errors here
  4610. case 'millisecond': return Math.floor(days * 864e5) + milliseconds;
  4611. default: throw new Error('Unknown unit ' + units);
  4612. }
  4613. }
  4614. }
  4615. // TODO: Use this.as('ms')?
  4616. function duration_as__valueOf () {
  4617. return (
  4618. this._milliseconds +
  4619. this._days * 864e5 +
  4620. (this._months % 12) * 2592e6 +
  4621. toInt(this._months / 12) * 31536e6
  4622. );
  4623. }
  4624. function makeAs (alias) {
  4625. return function () {
  4626. return this.as(alias);
  4627. };
  4628. }
  4629. var asMilliseconds = makeAs('ms');
  4630. var asSeconds = makeAs('s');
  4631. var asMinutes = makeAs('m');
  4632. var asHours = makeAs('h');
  4633. var asDays = makeAs('d');
  4634. var asWeeks = makeAs('w');
  4635. var asMonths = makeAs('M');
  4636. var asYears = makeAs('y');
  4637. function duration_get__get (units) {
  4638. units = normalizeUnits(units);
  4639. return this[units + 's']();
  4640. }
  4641. function makeGetter(name) {
  4642. return function () {
  4643. return this._data[name];
  4644. };
  4645. }
  4646. var milliseconds = makeGetter('milliseconds');
  4647. var seconds = makeGetter('seconds');
  4648. var minutes = makeGetter('minutes');
  4649. var hours = makeGetter('hours');
  4650. var days = makeGetter('days');
  4651. var months = makeGetter('months');
  4652. var years = makeGetter('years');
  4653. function weeks () {
  4654. return absFloor(this.days() / 7);
  4655. }
  4656. var round = Math.round;
  4657. var thresholds = {
  4658. s: 45, // seconds to minute
  4659. m: 45, // minutes to hour
  4660. h: 22, // hours to day
  4661. d: 26, // days to month
  4662. M: 11 // months to year
  4663. };
  4664. // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
  4665. function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {
  4666. return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
  4667. }
  4668. function duration_humanize__relativeTime (posNegDuration, withoutSuffix, locale) {
  4669. var duration = create__createDuration(posNegDuration).abs();
  4670. var seconds = round(duration.as('s'));
  4671. var minutes = round(duration.as('m'));
  4672. var hours = round(duration.as('h'));
  4673. var days = round(duration.as('d'));
  4674. var months = round(duration.as('M'));
  4675. var years = round(duration.as('y'));
  4676. var a = seconds < thresholds.s && ['s', seconds] ||
  4677. minutes <= 1 && ['m'] ||
  4678. minutes < thresholds.m && ['mm', minutes] ||
  4679. hours <= 1 && ['h'] ||
  4680. hours < thresholds.h && ['hh', hours] ||
  4681. days <= 1 && ['d'] ||
  4682. days < thresholds.d && ['dd', days] ||
  4683. months <= 1 && ['M'] ||
  4684. months < thresholds.M && ['MM', months] ||
  4685. years <= 1 && ['y'] || ['yy', years];
  4686. a[2] = withoutSuffix;
  4687. a[3] = +posNegDuration > 0;
  4688. a[4] = locale;
  4689. return substituteTimeAgo.apply(null, a);
  4690. }
  4691. // This function allows you to set a threshold for relative time strings
  4692. function duration_humanize__getSetRelativeTimeThreshold (threshold, limit) {
  4693. if (thresholds[threshold] === undefined) {
  4694. return false;
  4695. }
  4696. if (limit === undefined) {
  4697. return thresholds[threshold];
  4698. }
  4699. thresholds[threshold] = limit;
  4700. return true;
  4701. }
  4702. function humanize (withSuffix) {
  4703. var locale = this.localeData();
  4704. var output = duration_humanize__relativeTime(this, !withSuffix, locale);
  4705. if (withSuffix) {
  4706. output = locale.pastFuture(+this, output);
  4707. }
  4708. return locale.postformat(output);
  4709. }
  4710. var iso_string__abs = Math.abs;
  4711. function iso_string__toISOString() {
  4712. // for ISO strings we do not use the normal bubbling rules:
  4713. // * milliseconds bubble up until they become hours
  4714. // * days do not bubble at all
  4715. // * months bubble up until they become years
  4716. // This is because there is no context-free conversion between hours and days
  4717. // (think of clock changes)
  4718. // and also not between days and months (28-31 days per month)
  4719. var seconds = iso_string__abs(this._milliseconds) / 1000;
  4720. var days = iso_string__abs(this._days);
  4721. var months = iso_string__abs(this._months);
  4722. var minutes, hours, years;
  4723. // 3600 seconds -> 60 minutes -> 1 hour
  4724. minutes = absFloor(seconds / 60);
  4725. hours = absFloor(minutes / 60);
  4726. seconds %= 60;
  4727. minutes %= 60;
  4728. // 12 months -> 1 year
  4729. years = absFloor(months / 12);
  4730. months %= 12;
  4731. // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
  4732. var Y = years;
  4733. var M = months;
  4734. var D = days;
  4735. var h = hours;
  4736. var m = minutes;
  4737. var s = seconds;
  4738. var total = this.asSeconds();
  4739. if (!total) {
  4740. // this is the same as C#'s (Noda) and python (isodate)...
  4741. // but not other JS (goog.date)
  4742. return 'P0D';
  4743. }
  4744. return (total < 0 ? '-' : '') +
  4745. 'P' +
  4746. (Y ? Y + 'Y' : '') +
  4747. (M ? M + 'M' : '') +
  4748. (D ? D + 'D' : '') +
  4749. ((h || m || s) ? 'T' : '') +
  4750. (h ? h + 'H' : '') +
  4751. (m ? m + 'M' : '') +
  4752. (s ? s + 'S' : '');
  4753. }
  4754. var duration_prototype__proto = Duration.prototype;
  4755. duration_prototype__proto.abs = duration_abs__abs;
  4756. duration_prototype__proto.add = duration_add_subtract__add;
  4757. duration_prototype__proto.subtract = duration_add_subtract__subtract;
  4758. duration_prototype__proto.as = as;
  4759. duration_prototype__proto.asMilliseconds = asMilliseconds;
  4760. duration_prototype__proto.asSeconds = asSeconds;
  4761. duration_prototype__proto.asMinutes = asMinutes;
  4762. duration_prototype__proto.asHours = asHours;
  4763. duration_prototype__proto.asDays = asDays;
  4764. duration_prototype__proto.asWeeks = asWeeks;
  4765. duration_prototype__proto.asMonths = asMonths;
  4766. duration_prototype__proto.asYears = asYears;
  4767. duration_prototype__proto.valueOf = duration_as__valueOf;
  4768. duration_prototype__proto._bubble = bubble;
  4769. duration_prototype__proto.get = duration_get__get;
  4770. duration_prototype__proto.milliseconds = milliseconds;
  4771. duration_prototype__proto.seconds = seconds;
  4772. duration_prototype__proto.minutes = minutes;
  4773. duration_prototype__proto.hours = hours;
  4774. duration_prototype__proto.days = days;
  4775. duration_prototype__proto.weeks = weeks;
  4776. duration_prototype__proto.months = months;
  4777. duration_prototype__proto.years = years;
  4778. duration_prototype__proto.humanize = humanize;
  4779. duration_prototype__proto.toISOString = iso_string__toISOString;
  4780. duration_prototype__proto.toString = iso_string__toISOString;
  4781. duration_prototype__proto.toJSON = iso_string__toISOString;
  4782. duration_prototype__proto.locale = locale;
  4783. duration_prototype__proto.localeData = localeData;
  4784. // Deprecations
  4785. duration_prototype__proto.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', iso_string__toISOString);
  4786. duration_prototype__proto.lang = lang;
  4787. // Side effect imports
  4788. // FORMATTING
  4789. addFormatToken('X', 0, 0, 'unix');
  4790. addFormatToken('x', 0, 0, 'valueOf');
  4791. // PARSING
  4792. addRegexToken('x', matchSigned);
  4793. addRegexToken('X', matchTimestamp);
  4794. addParseToken('X', function (input, array, config) {
  4795. config._d = new Date(parseFloat(input, 10) * 1000);
  4796. });
  4797. addParseToken('x', function (input, array, config) {
  4798. config._d = new Date(toInt(input));
  4799. });
  4800. // Side effect imports
  4801. utils_hooks__hooks.version = '2.13.0';
  4802. setHookCallback(local__createLocal);
  4803. utils_hooks__hooks.fn = momentPrototype;
  4804. utils_hooks__hooks.min = min;
  4805. utils_hooks__hooks.max = max;
  4806. utils_hooks__hooks.now = now;
  4807. utils_hooks__hooks.utc = create_utc__createUTC;
  4808. utils_hooks__hooks.unix = moment__createUnix;
  4809. utils_hooks__hooks.months = lists__listMonths;
  4810. utils_hooks__hooks.isDate = isDate;
  4811. utils_hooks__hooks.locale = locale_locales__getSetGlobalLocale;
  4812. utils_hooks__hooks.invalid = valid__createInvalid;
  4813. utils_hooks__hooks.duration = create__createDuration;
  4814. utils_hooks__hooks.isMoment = isMoment;
  4815. utils_hooks__hooks.weekdays = lists__listWeekdays;
  4816. utils_hooks__hooks.parseZone = moment__createInZone;
  4817. utils_hooks__hooks.localeData = locale_locales__getLocale;
  4818. utils_hooks__hooks.isDuration = isDuration;
  4819. utils_hooks__hooks.monthsShort = lists__listMonthsShort;
  4820. utils_hooks__hooks.weekdaysMin = lists__listWeekdaysMin;
  4821. utils_hooks__hooks.defineLocale = defineLocale;
  4822. utils_hooks__hooks.updateLocale = updateLocale;
  4823. utils_hooks__hooks.locales = locale_locales__listLocales;
  4824. utils_hooks__hooks.weekdaysShort = lists__listWeekdaysShort;
  4825. utils_hooks__hooks.normalizeUnits = normalizeUnits;
  4826. utils_hooks__hooks.relativeTimeThreshold = duration_humanize__getSetRelativeTimeThreshold;
  4827. utils_hooks__hooks.prototype = momentPrototype;
  4828. var _moment = utils_hooks__hooks;
  4829. return _moment;
  4830. }));
  4831. },{}],7:[function(require,module,exports){
  4832. var Chart = require('./core/core.js')();
  4833. require('./core/core.helpers')(Chart);
  4834. require('./core/core.element')(Chart);
  4835. require('./core/core.animation')(Chart);
  4836. require('./core/core.controller')(Chart);
  4837. require('./core/core.datasetController')(Chart);
  4838. require('./core/core.layoutService')(Chart);
  4839. require('./core/core.legend')(Chart);
  4840. require('./core/core.plugin.js')(Chart);
  4841. require('./core/core.scale')(Chart);
  4842. require('./core/core.scaleService')(Chart);
  4843. require('./core/core.title')(Chart);
  4844. require('./core/core.tooltip')(Chart);
  4845. require('./elements/element.arc')(Chart);
  4846. require('./elements/element.line')(Chart);
  4847. require('./elements/element.point')(Chart);
  4848. require('./elements/element.rectangle')(Chart);
  4849. require('./scales/scale.category')(Chart);
  4850. require('./scales/scale.linear')(Chart);
  4851. require('./scales/scale.logarithmic')(Chart);
  4852. require('./scales/scale.radialLinear')(Chart);
  4853. require('./scales/scale.time')(Chart);
  4854. // Controllers must be loaded after elements
  4855. // See Chart.core.datasetController.dataElementType
  4856. require('./controllers/controller.bar')(Chart);
  4857. require('./controllers/controller.bubble')(Chart);
  4858. require('./controllers/controller.doughnut')(Chart);
  4859. require('./controllers/controller.line')(Chart);
  4860. require('./controllers/controller.polarArea')(Chart);
  4861. require('./controllers/controller.radar')(Chart);
  4862. require('./charts/Chart.Bar')(Chart);
  4863. require('./charts/Chart.Bubble')(Chart);
  4864. require('./charts/Chart.Doughnut')(Chart);
  4865. require('./charts/Chart.Line')(Chart);
  4866. require('./charts/Chart.PolarArea')(Chart);
  4867. require('./charts/Chart.Radar')(Chart);
  4868. require('./charts/Chart.Scatter')(Chart);
  4869. window.Chart = module.exports = Chart;
  4870. },{"./charts/Chart.Bar":8,"./charts/Chart.Bubble":9,"./charts/Chart.Doughnut":10,"./charts/Chart.Line":11,"./charts/Chart.PolarArea":12,"./charts/Chart.Radar":13,"./charts/Chart.Scatter":14,"./controllers/controller.bar":15,"./controllers/controller.bubble":16,"./controllers/controller.doughnut":17,"./controllers/controller.line":18,"./controllers/controller.polarArea":19,"./controllers/controller.radar":20,"./core/core.animation":21,"./core/core.controller":22,"./core/core.datasetController":23,"./core/core.element":24,"./core/core.helpers":25,"./core/core.js":26,"./core/core.layoutService":27,"./core/core.legend":28,"./core/core.plugin.js":29,"./core/core.scale":30,"./core/core.scaleService":31,"./core/core.title":32,"./core/core.tooltip":33,"./elements/element.arc":34,"./elements/element.line":35,"./elements/element.point":36,"./elements/element.rectangle":37,"./scales/scale.category":38,"./scales/scale.linear":39,"./scales/scale.logarithmic":40,"./scales/scale.radialLinear":41,"./scales/scale.time":42}],8:[function(require,module,exports){
  4871. "use strict";
  4872. module.exports = function(Chart) {
  4873. Chart.Bar = function(context, config) {
  4874. config.type = 'bar';
  4875. return new Chart(context, config);
  4876. };
  4877. };
  4878. },{}],9:[function(require,module,exports){
  4879. "use strict";
  4880. module.exports = function(Chart) {
  4881. Chart.Bubble = function(context, config) {
  4882. config.type = 'bubble';
  4883. return new Chart(context, config);
  4884. };
  4885. };
  4886. },{}],10:[function(require,module,exports){
  4887. "use strict";
  4888. module.exports = function(Chart) {
  4889. Chart.Doughnut = function(context, config) {
  4890. config.type = 'doughnut';
  4891. return new Chart(context, config);
  4892. };
  4893. };
  4894. },{}],11:[function(require,module,exports){
  4895. "use strict";
  4896. module.exports = function(Chart) {
  4897. Chart.Line = function(context, config) {
  4898. config.type = 'line';
  4899. return new Chart(context, config);
  4900. };
  4901. };
  4902. },{}],12:[function(require,module,exports){
  4903. "use strict";
  4904. module.exports = function(Chart) {
  4905. Chart.PolarArea = function(context, config) {
  4906. config.type = 'polarArea';
  4907. return new Chart(context, config);
  4908. };
  4909. };
  4910. },{}],13:[function(require,module,exports){
  4911. "use strict";
  4912. module.exports = function(Chart) {
  4913. Chart.Radar = function(context, config) {
  4914. config.options = Chart.helpers.configMerge({ aspectRatio: 1 }, config.options);
  4915. config.type = 'radar';
  4916. return new Chart(context, config);
  4917. };
  4918. };
  4919. },{}],14:[function(require,module,exports){
  4920. "use strict";
  4921. module.exports = function(Chart) {
  4922. var defaultConfig = {
  4923. hover: {
  4924. mode: 'single'
  4925. },
  4926. scales: {
  4927. xAxes: [{
  4928. type: "linear", // scatter should not use a category axis
  4929. position: "bottom",
  4930. id: "x-axis-1" // need an ID so datasets can reference the scale
  4931. }],
  4932. yAxes: [{
  4933. type: "linear",
  4934. position: "left",
  4935. id: "y-axis-1"
  4936. }]
  4937. },
  4938. tooltips: {
  4939. callbacks: {
  4940. title: function(tooltipItems, data) {
  4941. // Title doesn't make sense for scatter since we format the data as a point
  4942. return '';
  4943. },
  4944. label: function(tooltipItem, data) {
  4945. return '(' + tooltipItem.xLabel + ', ' + tooltipItem.yLabel + ')';
  4946. }
  4947. }
  4948. }
  4949. };
  4950. // Register the default config for this type
  4951. Chart.defaults.scatter = defaultConfig;
  4952. // Scatter charts use line controllers
  4953. Chart.controllers.scatter = Chart.controllers.line;
  4954. Chart.Scatter = function(context, config) {
  4955. config.type = 'scatter';
  4956. return new Chart(context, config);
  4957. };
  4958. };
  4959. },{}],15:[function(require,module,exports){
  4960. "use strict";
  4961. module.exports = function(Chart) {
  4962. var helpers = Chart.helpers;
  4963. Chart.defaults.bar = {
  4964. hover: {
  4965. mode: "label"
  4966. },
  4967. scales: {
  4968. xAxes: [{
  4969. type: "category",
  4970. // Specific to Bar Controller
  4971. categoryPercentage: 0.8,
  4972. barPercentage: 0.9,
  4973. // grid line settings
  4974. gridLines: {
  4975. offsetGridLines: true
  4976. }
  4977. }],
  4978. yAxes: [{
  4979. type: "linear"
  4980. }]
  4981. }
  4982. };
  4983. Chart.controllers.bar = Chart.DatasetController.extend({
  4984. dataElementType: Chart.elements.Rectangle,
  4985. initialize: function(chart, datasetIndex) {
  4986. Chart.DatasetController.prototype.initialize.call(this, chart, datasetIndex);
  4987. // Use this to indicate that this is a bar dataset.
  4988. this.getMeta().bar = true;
  4989. },
  4990. // Get the number of datasets that display bars. We use this to correctly calculate the bar width
  4991. getBarCount: function getBarCount() {
  4992. var barCount = 0;
  4993. helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
  4994. var meta = this.chart.getDatasetMeta(datasetIndex);
  4995. if (meta.bar && this.chart.isDatasetVisible(datasetIndex)) {
  4996. ++barCount;
  4997. }
  4998. }, this);
  4999. return barCount;
  5000. },
  5001. update: function update(reset) {
  5002. helpers.each(this.getMeta().data, function(rectangle, index) {
  5003. this.updateElement(rectangle, index, reset);
  5004. }, this);
  5005. },
  5006. updateElement: function updateElement(rectangle, index, reset) {
  5007. var meta = this.getMeta();
  5008. var xScale = this.getScaleForId(meta.xAxisID);
  5009. var yScale = this.getScaleForId(meta.yAxisID);
  5010. var scaleBase = yScale.getBasePixel();
  5011. var rectangleElementOptions = this.chart.options.elements.rectangle;
  5012. var custom = rectangle.custom || {};
  5013. var dataset = this.getDataset();
  5014. helpers.extend(rectangle, {
  5015. // Utility
  5016. _xScale: xScale,
  5017. _yScale: yScale,
  5018. _datasetIndex: this.index,
  5019. _index: index,
  5020. // Desired view properties
  5021. _model: {
  5022. x: this.calculateBarX(index, this.index),
  5023. y: reset ? scaleBase : this.calculateBarY(index, this.index),
  5024. // Tooltip
  5025. label: this.chart.data.labels[index],
  5026. datasetLabel: dataset.label,
  5027. // Appearance
  5028. base: reset ? scaleBase : this.calculateBarBase(this.index, index),
  5029. width: this.calculateBarWidth(index),
  5030. backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
  5031. borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped,
  5032. borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor),
  5033. borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth)
  5034. }
  5035. });
  5036. rectangle.pivot();
  5037. },
  5038. calculateBarBase: function(datasetIndex, index) {
  5039. var meta = this.getMeta();
  5040. var yScale = this.getScaleForId(meta.yAxisID);
  5041. var base = 0;
  5042. if (yScale.options.stacked) {
  5043. var chart = this.chart;
  5044. var datasets = chart.data.datasets;
  5045. var value = datasets[datasetIndex].data[index];
  5046. if (value < 0) {
  5047. for (var i = 0; i < datasetIndex; i++) {
  5048. var negDS = datasets[i];
  5049. var negDSMeta = chart.getDatasetMeta(i);
  5050. if (negDSMeta.bar && negDSMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
  5051. base += negDS.data[index] < 0 ? negDS.data[index] : 0;
  5052. }
  5053. }
  5054. } else {
  5055. for (var j = 0; j < datasetIndex; j++) {
  5056. var posDS = datasets[j];
  5057. var posDSMeta = chart.getDatasetMeta(j);
  5058. if (posDSMeta.bar && posDSMeta.yAxisID === yScale.id && chart.isDatasetVisible(j)) {
  5059. base += posDS.data[index] > 0 ? posDS.data[index] : 0;
  5060. }
  5061. }
  5062. }
  5063. return yScale.getPixelForValue(base);
  5064. }
  5065. return yScale.getBasePixel();
  5066. },
  5067. getRuler: function(index) {
  5068. var meta = this.getMeta();
  5069. var xScale = this.getScaleForId(meta.xAxisID);
  5070. var datasetCount = this.getBarCount();
  5071. var tickWidth;
  5072. if (xScale.options.type === 'category') {
  5073. tickWidth = xScale.getPixelForTick(index + 1) - xScale.getPixelForTick(index);
  5074. } else {
  5075. // Average width
  5076. tickWidth = xScale.width / xScale.ticks.length;
  5077. }
  5078. var categoryWidth = tickWidth * xScale.options.categoryPercentage;
  5079. var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2;
  5080. var fullBarWidth = categoryWidth / datasetCount;
  5081. if (xScale.ticks.length !== this.chart.data.labels.length) {
  5082. var perc = xScale.ticks.length / this.chart.data.labels.length;
  5083. fullBarWidth = fullBarWidth * perc;
  5084. }
  5085. var barWidth = fullBarWidth * xScale.options.barPercentage;
  5086. var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage);
  5087. return {
  5088. datasetCount: datasetCount,
  5089. tickWidth: tickWidth,
  5090. categoryWidth: categoryWidth,
  5091. categorySpacing: categorySpacing,
  5092. fullBarWidth: fullBarWidth,
  5093. barWidth: barWidth,
  5094. barSpacing: barSpacing
  5095. };
  5096. },
  5097. calculateBarWidth: function(index) {
  5098. var xScale = this.getScaleForId(this.getMeta().xAxisID);
  5099. var ruler = this.getRuler(index);
  5100. return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth;
  5101. },
  5102. // Get bar index from the given dataset index accounting for the fact that not all bars are visible
  5103. getBarIndex: function(datasetIndex) {
  5104. var barIndex = 0;
  5105. var meta, j;
  5106. for (j = 0; j < datasetIndex; ++j) {
  5107. meta = this.chart.getDatasetMeta(j);
  5108. if (meta.bar && this.chart.isDatasetVisible(j)) {
  5109. ++barIndex;
  5110. }
  5111. }
  5112. return barIndex;
  5113. },
  5114. calculateBarX: function(index, datasetIndex) {
  5115. var meta = this.getMeta();
  5116. var xScale = this.getScaleForId(meta.xAxisID);
  5117. var barIndex = this.getBarIndex(datasetIndex);
  5118. var ruler = this.getRuler(index);
  5119. var leftTick = xScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
  5120. leftTick -= this.chart.isCombo ? (ruler.tickWidth / 2) : 0;
  5121. if (xScale.options.stacked) {
  5122. return leftTick + (ruler.categoryWidth / 2) + ruler.categorySpacing;
  5123. }
  5124. return leftTick +
  5125. (ruler.barWidth / 2) +
  5126. ruler.categorySpacing +
  5127. (ruler.barWidth * barIndex) +
  5128. (ruler.barSpacing / 2) +
  5129. (ruler.barSpacing * barIndex);
  5130. },
  5131. calculateBarY: function(index, datasetIndex) {
  5132. var meta = this.getMeta();
  5133. var yScale = this.getScaleForId(meta.yAxisID);
  5134. var value = this.getDataset().data[index];
  5135. if (yScale.options.stacked) {
  5136. var sumPos = 0,
  5137. sumNeg = 0;
  5138. for (var i = 0; i < datasetIndex; i++) {
  5139. var ds = this.chart.data.datasets[i];
  5140. var dsMeta = this.chart.getDatasetMeta(i);
  5141. if (dsMeta.bar && dsMeta.yAxisID === yScale.id && this.chart.isDatasetVisible(i)) {
  5142. if (ds.data[index] < 0) {
  5143. sumNeg += ds.data[index] || 0;
  5144. } else {
  5145. sumPos += ds.data[index] || 0;
  5146. }
  5147. }
  5148. }
  5149. if (value < 0) {
  5150. return yScale.getPixelForValue(sumNeg + value);
  5151. } else {
  5152. return yScale.getPixelForValue(sumPos + value);
  5153. }
  5154. }
  5155. return yScale.getPixelForValue(value);
  5156. },
  5157. draw: function(ease) {
  5158. var easingDecimal = ease || 1;
  5159. helpers.each(this.getMeta().data, function(rectangle, index) {
  5160. var d = this.getDataset().data[index];
  5161. if (d !== null && d !== undefined && !isNaN(d)) {
  5162. rectangle.transition(easingDecimal).draw();
  5163. }
  5164. }, this);
  5165. },
  5166. setHoverStyle: function(rectangle) {
  5167. var dataset = this.chart.data.datasets[rectangle._datasetIndex];
  5168. var index = rectangle._index;
  5169. var custom = rectangle.custom || {};
  5170. var model = rectangle._model;
  5171. model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  5172. model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  5173. model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
  5174. },
  5175. removeHoverStyle: function(rectangle) {
  5176. var dataset = this.chart.data.datasets[rectangle._datasetIndex];
  5177. var index = rectangle._index;
  5178. var custom = rectangle.custom || {};
  5179. var model = rectangle._model;
  5180. var rectangleElementOptions = this.chart.options.elements.rectangle;
  5181. model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor);
  5182. model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor);
  5183. model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth);
  5184. }
  5185. });
  5186. // including horizontalBar in the bar file, instead of a file of its own
  5187. // it extends bar (like pie extends doughnut)
  5188. Chart.defaults.horizontalBar = {
  5189. hover: {
  5190. mode: "label"
  5191. },
  5192. scales: {
  5193. xAxes: [{
  5194. type: "linear",
  5195. position: "bottom"
  5196. }],
  5197. yAxes: [{
  5198. position: "left",
  5199. type: "category",
  5200. // Specific to Horizontal Bar Controller
  5201. categoryPercentage: 0.8,
  5202. barPercentage: 0.9,
  5203. // grid line settings
  5204. gridLines: {
  5205. offsetGridLines: true
  5206. }
  5207. }]
  5208. },
  5209. elements: {
  5210. rectangle: {
  5211. borderSkipped: 'left'
  5212. }
  5213. },
  5214. tooltips: {
  5215. callbacks: {
  5216. title: function(tooltipItems, data) {
  5217. // Pick first xLabel for now
  5218. var title = '';
  5219. if (tooltipItems.length > 0) {
  5220. if (tooltipItems[0].yLabel) {
  5221. title = tooltipItems[0].yLabel;
  5222. } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
  5223. title = data.labels[tooltipItems[0].index];
  5224. }
  5225. }
  5226. return title;
  5227. },
  5228. label: function(tooltipItem, data) {
  5229. var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
  5230. return datasetLabel + ': ' + tooltipItem.xLabel;
  5231. }
  5232. }
  5233. }
  5234. };
  5235. Chart.controllers.horizontalBar = Chart.controllers.bar.extend({
  5236. updateElement: function updateElement(rectangle, index, reset, numBars) {
  5237. var meta = this.getMeta();
  5238. var xScale = this.getScaleForId(meta.xAxisID);
  5239. var yScale = this.getScaleForId(meta.yAxisID);
  5240. var scaleBase = xScale.getBasePixel();
  5241. var custom = rectangle.custom || {};
  5242. var dataset = this.getDataset();
  5243. var rectangleElementOptions = this.chart.options.elements.rectangle;
  5244. helpers.extend(rectangle, {
  5245. // Utility
  5246. _xScale: xScale,
  5247. _yScale: yScale,
  5248. _datasetIndex: this.index,
  5249. _index: index,
  5250. // Desired view properties
  5251. _model: {
  5252. x: reset ? scaleBase : this.calculateBarX(index, this.index),
  5253. y: this.calculateBarY(index, this.index),
  5254. // Tooltip
  5255. label: this.chart.data.labels[index],
  5256. datasetLabel: dataset.label,
  5257. // Appearance
  5258. base: reset ? scaleBase : this.calculateBarBase(this.index, index),
  5259. height: this.calculateBarHeight(index),
  5260. backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, rectangleElementOptions.backgroundColor),
  5261. borderSkipped: custom.borderSkipped ? custom.borderSkipped : rectangleElementOptions.borderSkipped,
  5262. borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, rectangleElementOptions.borderColor),
  5263. borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, rectangleElementOptions.borderWidth)
  5264. },
  5265. draw: function () {
  5266. var ctx = this._chart.ctx;
  5267. var vm = this._view;
  5268. var halfHeight = vm.height / 2,
  5269. topY = vm.y - halfHeight,
  5270. bottomY = vm.y + halfHeight,
  5271. right = vm.base - (vm.base - vm.x),
  5272. halfStroke = vm.borderWidth / 2;
  5273. // Canvas doesn't allow us to stroke inside the width so we can
  5274. // adjust the sizes to fit if we're setting a stroke on the line
  5275. if (vm.borderWidth) {
  5276. topY += halfStroke;
  5277. bottomY -= halfStroke;
  5278. right += halfStroke;
  5279. }
  5280. ctx.beginPath();
  5281. ctx.fillStyle = vm.backgroundColor;
  5282. ctx.strokeStyle = vm.borderColor;
  5283. ctx.lineWidth = vm.borderWidth;
  5284. // Corner points, from bottom-left to bottom-right clockwise
  5285. // | 1 2 |
  5286. // | 0 3 |
  5287. var corners = [
  5288. [vm.base, bottomY],
  5289. [vm.base, topY],
  5290. [right, topY],
  5291. [right, bottomY]
  5292. ];
  5293. // Find first (starting) corner with fallback to 'bottom'
  5294. var borders = ['bottom', 'left', 'top', 'right'];
  5295. var startCorner = borders.indexOf(vm.borderSkipped, 0);
  5296. if (startCorner === -1)
  5297. startCorner = 0;
  5298. function cornerAt(index) {
  5299. return corners[(startCorner + index) % 4];
  5300. }
  5301. // Draw rectangle from 'startCorner'
  5302. ctx.moveTo.apply(ctx, cornerAt(0));
  5303. for (var i = 1; i < 4; i++)
  5304. ctx.lineTo.apply(ctx, cornerAt(i));
  5305. ctx.fill();
  5306. if (vm.borderWidth) {
  5307. ctx.stroke();
  5308. }
  5309. },
  5310. inRange: function (mouseX, mouseY) {
  5311. var vm = this._view;
  5312. var inRange = false;
  5313. if (vm) {
  5314. if (vm.x < vm.base) {
  5315. inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.x && mouseX <= vm.base);
  5316. } else {
  5317. inRange = (mouseY >= vm.y - vm.height / 2 && mouseY <= vm.y + vm.height / 2) && (mouseX >= vm.base && mouseX <= vm.x);
  5318. }
  5319. }
  5320. return inRange;
  5321. }
  5322. });
  5323. rectangle.pivot();
  5324. },
  5325. calculateBarBase: function (datasetIndex, index) {
  5326. var meta = this.getMeta();
  5327. var xScale = this.getScaleForId(meta.xAxisID);
  5328. var base = 0;
  5329. if (xScale.options.stacked) {
  5330. var value = this.chart.data.datasets[datasetIndex].data[index];
  5331. if (value < 0) {
  5332. for (var i = 0; i < datasetIndex; i++) {
  5333. var negDS = this.chart.data.datasets[i];
  5334. var negDSMeta = this.chart.getDatasetMeta(i);
  5335. if (negDSMeta.bar && negDSMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(i)) {
  5336. base += negDS.data[index] < 0 ? negDS.data[index] : 0;
  5337. }
  5338. }
  5339. } else {
  5340. for (var j = 0; j < datasetIndex; j++) {
  5341. var posDS = this.chart.data.datasets[j];
  5342. var posDSMeta = this.chart.getDatasetMeta(j);
  5343. if (posDSMeta.bar && posDSMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(j)) {
  5344. base += posDS.data[index] > 0 ? posDS.data[index] : 0;
  5345. }
  5346. }
  5347. }
  5348. return xScale.getPixelForValue(base);
  5349. }
  5350. return xScale.getBasePixel();
  5351. },
  5352. getRuler: function (index) {
  5353. var meta = this.getMeta();
  5354. var yScale = this.getScaleForId(meta.yAxisID);
  5355. var datasetCount = this.getBarCount();
  5356. var tickHeight;
  5357. if (yScale.options.type === 'category') {
  5358. tickHeight = yScale.getPixelForTick(index + 1) - yScale.getPixelForTick(index);
  5359. } else {
  5360. // Average width
  5361. tickHeight = yScale.width / yScale.ticks.length;
  5362. }
  5363. var categoryHeight = tickHeight * yScale.options.categoryPercentage;
  5364. var categorySpacing = (tickHeight - (tickHeight * yScale.options.categoryPercentage)) / 2;
  5365. var fullBarHeight = categoryHeight / datasetCount;
  5366. if (yScale.ticks.length !== this.chart.data.labels.length) {
  5367. var perc = yScale.ticks.length / this.chart.data.labels.length;
  5368. fullBarHeight = fullBarHeight * perc;
  5369. }
  5370. var barHeight = fullBarHeight * yScale.options.barPercentage;
  5371. var barSpacing = fullBarHeight - (fullBarHeight * yScale.options.barPercentage);
  5372. return {
  5373. datasetCount: datasetCount,
  5374. tickHeight: tickHeight,
  5375. categoryHeight: categoryHeight,
  5376. categorySpacing: categorySpacing,
  5377. fullBarHeight: fullBarHeight,
  5378. barHeight: barHeight,
  5379. barSpacing: barSpacing,
  5380. };
  5381. },
  5382. calculateBarHeight: function (index) {
  5383. var yScale = this.getScaleForId(this.getMeta().yAxisID);
  5384. var ruler = this.getRuler(index);
  5385. return yScale.options.stacked ? ruler.categoryHeight : ruler.barHeight;
  5386. },
  5387. calculateBarX: function (index, datasetIndex) {
  5388. var meta = this.getMeta();
  5389. var xScale = this.getScaleForId(meta.xAxisID);
  5390. var value = this.getDataset().data[index];
  5391. if (xScale.options.stacked) {
  5392. var sumPos = 0,
  5393. sumNeg = 0;
  5394. for (var i = 0; i < datasetIndex; i++) {
  5395. var ds = this.chart.data.datasets[i];
  5396. var dsMeta = this.chart.getDatasetMeta(i);
  5397. if (dsMeta.bar && dsMeta.xAxisID === xScale.id && this.chart.isDatasetVisible(i)) {
  5398. if (ds.data[index] < 0) {
  5399. sumNeg += ds.data[index] || 0;
  5400. } else {
  5401. sumPos += ds.data[index] || 0;
  5402. }
  5403. }
  5404. }
  5405. if (value < 0) {
  5406. return xScale.getPixelForValue(sumNeg + value);
  5407. } else {
  5408. return xScale.getPixelForValue(sumPos + value);
  5409. }
  5410. }
  5411. return xScale.getPixelForValue(value);
  5412. },
  5413. calculateBarY: function (index, datasetIndex) {
  5414. var meta = this.getMeta();
  5415. var yScale = this.getScaleForId(meta.yAxisID);
  5416. var barIndex = this.getBarIndex(datasetIndex);
  5417. var ruler = this.getRuler(index);
  5418. var topTick = yScale.getPixelForValue(null, index, datasetIndex, this.chart.isCombo);
  5419. topTick -= this.chart.isCombo ? (ruler.tickHeight / 2) : 0;
  5420. if (yScale.options.stacked) {
  5421. return topTick + (ruler.categoryHeight / 2) + ruler.categorySpacing;
  5422. }
  5423. return topTick +
  5424. (ruler.barHeight / 2) +
  5425. ruler.categorySpacing +
  5426. (ruler.barHeight * barIndex) +
  5427. (ruler.barSpacing / 2) +
  5428. (ruler.barSpacing * barIndex);
  5429. }
  5430. });
  5431. };
  5432. },{}],16:[function(require,module,exports){
  5433. "use strict";
  5434. module.exports = function(Chart) {
  5435. var helpers = Chart.helpers;
  5436. Chart.defaults.bubble = {
  5437. hover: {
  5438. mode: "single"
  5439. },
  5440. scales: {
  5441. xAxes: [{
  5442. type: "linear", // bubble should probably use a linear scale by default
  5443. position: "bottom",
  5444. id: "x-axis-0" // need an ID so datasets can reference the scale
  5445. }],
  5446. yAxes: [{
  5447. type: "linear",
  5448. position: "left",
  5449. id: "y-axis-0"
  5450. }]
  5451. },
  5452. tooltips: {
  5453. callbacks: {
  5454. title: function(tooltipItems, data) {
  5455. // Title doesn't make sense for scatter since we format the data as a point
  5456. return '';
  5457. },
  5458. label: function(tooltipItem, data) {
  5459. var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
  5460. var dataPoint = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
  5461. return datasetLabel + ': (' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.r + ')';
  5462. }
  5463. }
  5464. }
  5465. };
  5466. Chart.controllers.bubble = Chart.DatasetController.extend({
  5467. dataElementType: Chart.elements.Point,
  5468. update: function update(reset) {
  5469. var meta = this.getMeta();
  5470. var points = meta.data;
  5471. // Update Points
  5472. helpers.each(points, function(point, index) {
  5473. this.updateElement(point, index, reset);
  5474. }, this);
  5475. },
  5476. updateElement: function(point, index, reset) {
  5477. var meta = this.getMeta();
  5478. var xScale = this.getScaleForId(meta.xAxisID);
  5479. var yScale = this.getScaleForId(meta.yAxisID);
  5480. var custom = point.custom || {};
  5481. var dataset = this.getDataset();
  5482. var data = dataset.data[index];
  5483. var pointElementOptions = this.chart.options.elements.point;
  5484. helpers.extend(point, {
  5485. // Utility
  5486. _xScale: xScale,
  5487. _yScale: yScale,
  5488. _datasetIndex: this.index,
  5489. _index: index,
  5490. // Desired view properties
  5491. _model: {
  5492. x: reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(data, index, this.index, this.chart.isCombo),
  5493. y: reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, this.index),
  5494. // Appearance
  5495. radius: reset ? 0 : custom.radius ? custom.radius : this.getRadius(data),
  5496. backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, pointElementOptions.backgroundColor),
  5497. borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, pointElementOptions.borderColor),
  5498. borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, pointElementOptions.borderWidth),
  5499. // Tooltip
  5500. hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
  5501. }
  5502. });
  5503. var model = point._model;
  5504. model.skip = custom.skip ? custom.skip : (isNaN(model.x) || isNaN(model.y));
  5505. point.pivot();
  5506. },
  5507. getRadius: function(value) {
  5508. return value.r || this.chart.options.elements.point.radius;
  5509. },
  5510. setHoverStyle: function(point) {
  5511. // Point
  5512. var dataset = this.chart.data.datasets[point._datasetIndex];
  5513. var index = point._index;
  5514. var custom = point.custom || {};
  5515. var model = point._model;
  5516. model.radius = custom.hoverRadius ? custom.hoverRadius : (helpers.getValueAtIndexOrDefault(dataset.hoverRadius, index, this.chart.options.elements.point.hoverRadius)) + this.getRadius(this.getDataset().data[point._index]);
  5517. model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  5518. model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  5519. model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
  5520. },
  5521. removeHoverStyle: function(point) {
  5522. var dataset = this.chart.data.datasets[point._datasetIndex];
  5523. var index = point._index;
  5524. var custom = point.custom || {};
  5525. var model = point._model;
  5526. var pointElementOptions = this.chart.options.elements.point;
  5527. model.radius = custom.radius ? custom.radius : this.getRadius(dataset.data[point._index]);
  5528. model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.backgroundColor, index, pointElementOptions.backgroundColor);
  5529. model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.borderColor, index, pointElementOptions.borderColor);
  5530. model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, pointElementOptions.borderWidth);
  5531. }
  5532. });
  5533. };
  5534. },{}],17:[function(require,module,exports){
  5535. "use strict";
  5536. module.exports = function(Chart) {
  5537. var helpers = Chart.helpers,
  5538. defaults = Chart.defaults;
  5539. defaults.doughnut = {
  5540. animation: {
  5541. //Boolean - Whether we animate the rotation of the Doughnut
  5542. animateRotate: true,
  5543. //Boolean - Whether we animate scaling the Doughnut from the centre
  5544. animateScale: false
  5545. },
  5546. aspectRatio: 1,
  5547. hover: {
  5548. mode: 'single'
  5549. },
  5550. legendCallback: function(chart) {
  5551. var text = [];
  5552. text.push('<ul class="' + chart.id + '-legend">');
  5553. var data = chart.data;
  5554. var datasets = data.datasets;
  5555. var labels = data.labels;
  5556. if (datasets.length) {
  5557. for (var i = 0; i < datasets[0].data.length; ++i) {
  5558. text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
  5559. if (labels[i]) {
  5560. text.push(labels[i]);
  5561. }
  5562. text.push('</li>');
  5563. }
  5564. }
  5565. text.push('</ul>');
  5566. return text.join("");
  5567. },
  5568. legend: {
  5569. labels: {
  5570. generateLabels: function(chart) {
  5571. var data = chart.data;
  5572. if (data.labels.length && data.datasets.length) {
  5573. return data.labels.map(function(label, i) {
  5574. var meta = chart.getDatasetMeta(0);
  5575. var ds = data.datasets[0];
  5576. var arc = meta.data[i];
  5577. var custom = arc.custom || {};
  5578. var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  5579. var arcOpts = chart.options.elements.arc;
  5580. var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
  5581. var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
  5582. var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
  5583. return {
  5584. text: label,
  5585. fillStyle: fill,
  5586. strokeStyle: stroke,
  5587. lineWidth: bw,
  5588. hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
  5589. // Extra data used for toggling the correct item
  5590. index: i
  5591. };
  5592. });
  5593. } else {
  5594. return [];
  5595. }
  5596. }
  5597. },
  5598. onClick: function(e, legendItem) {
  5599. var index = legendItem.index;
  5600. var chart = this.chart;
  5601. var i, ilen, meta;
  5602. for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  5603. meta = chart.getDatasetMeta(i);
  5604. meta.data[index].hidden = !meta.data[index].hidden;
  5605. }
  5606. chart.update();
  5607. }
  5608. },
  5609. //The percentage of the chart that we cut out of the middle.
  5610. cutoutPercentage: 50,
  5611. //The rotation of the chart, where the first data arc begins.
  5612. rotation: Math.PI * -0.5,
  5613. //The total circumference of the chart.
  5614. circumference: Math.PI * 2.0,
  5615. // Need to override these to give a nice default
  5616. tooltips: {
  5617. callbacks: {
  5618. title: function() {
  5619. return '';
  5620. },
  5621. label: function(tooltipItem, data) {
  5622. return data.labels[tooltipItem.index] + ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
  5623. }
  5624. }
  5625. }
  5626. };
  5627. defaults.pie = helpers.clone(defaults.doughnut);
  5628. helpers.extend(defaults.pie, {
  5629. cutoutPercentage: 0
  5630. });
  5631. Chart.controllers.doughnut = Chart.controllers.pie = Chart.DatasetController.extend({
  5632. dataElementType: Chart.elements.Arc,
  5633. linkScales: helpers.noop,
  5634. // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
  5635. getRingIndex: function getRingIndex(datasetIndex) {
  5636. var ringIndex = 0;
  5637. for (var j = 0; j < datasetIndex; ++j) {
  5638. if (this.chart.isDatasetVisible(j)) {
  5639. ++ringIndex;
  5640. }
  5641. }
  5642. return ringIndex;
  5643. },
  5644. update: function update(reset) {
  5645. var _this = this;
  5646. var chart = _this.chart,
  5647. chartArea = chart.chartArea,
  5648. opts = chart.options,
  5649. arcOpts = opts.elements.arc,
  5650. availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth,
  5651. availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth,
  5652. minSize = Math.min(availableWidth, availableHeight),
  5653. offset = {
  5654. x: 0,
  5655. y: 0
  5656. },
  5657. meta = _this.getMeta(),
  5658. cutoutPercentage = opts.cutoutPercentage,
  5659. circumference = opts.circumference;
  5660. // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
  5661. if (circumference < Math.PI * 2.0) {
  5662. var startAngle = opts.rotation % (Math.PI * 2.0);
  5663. startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
  5664. var endAngle = startAngle + circumference;
  5665. var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
  5666. var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
  5667. var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
  5668. var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
  5669. var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
  5670. var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
  5671. var cutout = cutoutPercentage / 100.0;
  5672. var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
  5673. var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
  5674. var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
  5675. minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
  5676. offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
  5677. }
  5678. chart.outerRadius = Math.max(minSize / 2, 0);
  5679. chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 1, 0);
  5680. chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
  5681. chart.offsetX = offset.x * chart.outerRadius;
  5682. chart.offsetY = offset.y * chart.outerRadius;
  5683. meta.total = _this.calculateTotal();
  5684. _this.outerRadius = chart.outerRadius - (chart.radiusLength * _this.getRingIndex(_this.index));
  5685. _this.innerRadius = _this.outerRadius - chart.radiusLength;
  5686. helpers.each(meta.data, function(arc, index) {
  5687. _this.updateElement(arc, index, reset);
  5688. });
  5689. },
  5690. updateElement: function(arc, index, reset) {
  5691. var _this = this;
  5692. var chart = _this.chart,
  5693. chartArea = chart.chartArea,
  5694. opts = chart.options,
  5695. animationOpts = opts.animation,
  5696. arcOpts = opts.elements.arc,
  5697. centerX = (chartArea.left + chartArea.right) / 2,
  5698. centerY = (chartArea.top + chartArea.bottom) / 2,
  5699. startAngle = opts.rotation, // non reset case handled later
  5700. endAngle = opts.rotation, // non reset case handled later
  5701. dataset = _this.getDataset(),
  5702. circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : _this.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI)),
  5703. innerRadius = reset && animationOpts.animateScale ? 0 : _this.innerRadius,
  5704. outerRadius = reset && animationOpts.animateScale ? 0 : _this.outerRadius,
  5705. custom = arc.custom || {},
  5706. valueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  5707. helpers.extend(arc, {
  5708. // Utility
  5709. _datasetIndex: _this.index,
  5710. _index: index,
  5711. // Desired view properties
  5712. _model: {
  5713. x: centerX + chart.offsetX,
  5714. y: centerY + chart.offsetY,
  5715. startAngle: startAngle,
  5716. endAngle: endAngle,
  5717. circumference: circumference,
  5718. outerRadius: outerRadius,
  5719. innerRadius: innerRadius,
  5720. label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
  5721. }
  5722. });
  5723. var model = arc._model;
  5724. model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor);
  5725. model.hoverBackgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueAtIndexOrDefault(dataset.hoverBackgroundColor, index, arcOpts.hoverBackgroundColor);
  5726. model.borderWidth = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth);
  5727. model.borderColor = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor);
  5728. // Set correct angles if not resetting
  5729. if (!reset || !animationOpts.animateRotate) {
  5730. if (index === 0) {
  5731. model.startAngle = opts.rotation;
  5732. } else {
  5733. model.startAngle = _this.getMeta().data[index - 1]._model.endAngle;
  5734. }
  5735. model.endAngle = model.startAngle + model.circumference;
  5736. }
  5737. arc.pivot();
  5738. },
  5739. removeHoverStyle: function(arc) {
  5740. Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
  5741. },
  5742. calculateTotal: function() {
  5743. var dataset = this.getDataset();
  5744. var meta = this.getMeta();
  5745. var total = 0;
  5746. var value;
  5747. helpers.each(meta.data, function(element, index) {
  5748. value = dataset.data[index];
  5749. if (!isNaN(value) && !element.hidden) {
  5750. total += Math.abs(value);
  5751. }
  5752. });
  5753. return total;
  5754. },
  5755. calculateCircumference: function(value) {
  5756. var total = this.getMeta().total;
  5757. if (total > 0 && !isNaN(value)) {
  5758. return (Math.PI * 2.0) * (value / total);
  5759. } else {
  5760. return 0;
  5761. }
  5762. }
  5763. });
  5764. };
  5765. },{}],18:[function(require,module,exports){
  5766. "use strict";
  5767. module.exports = function(Chart) {
  5768. var helpers = Chart.helpers;
  5769. Chart.defaults.line = {
  5770. showLines: true,
  5771. hover: {
  5772. mode: "label"
  5773. },
  5774. scales: {
  5775. xAxes: [{
  5776. type: "category",
  5777. id: 'x-axis-0'
  5778. }],
  5779. yAxes: [{
  5780. type: "linear",
  5781. id: 'y-axis-0'
  5782. }]
  5783. }
  5784. };
  5785. Chart.controllers.line = Chart.DatasetController.extend({
  5786. datasetElementType: Chart.elements.Line,
  5787. dataElementType: Chart.elements.Point,
  5788. addElementAndReset: function(index) {
  5789. var me = this;
  5790. var options = me.chart.options;
  5791. Chart.DatasetController.prototype.addElementAndReset.call(me, index);
  5792. // Make sure bezier control points are updated
  5793. if (options.showLines && options.elements.line.tension !== 0) {
  5794. me.updateBezierControlPoints();
  5795. }
  5796. },
  5797. update: function update(reset) {
  5798. var me = this;
  5799. var meta = me.getMeta();
  5800. var line = meta.dataset;
  5801. var points = meta.data || [];
  5802. var options = me.chart.options;
  5803. var lineElementOptions = options.elements.line;
  5804. var scale = me.getScaleForId(meta.yAxisID);
  5805. var i, ilen, dataset, custom;
  5806. // Update Line
  5807. if (options.showLines) {
  5808. dataset = me.getDataset();
  5809. custom = line.custom || {};
  5810. // Compatibility: If the properties are defined with only the old name, use those values
  5811. if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
  5812. dataset.lineTension = dataset.tension;
  5813. }
  5814. // Utility
  5815. line._scale = scale;
  5816. line._datasetIndex = me.index;
  5817. // Data
  5818. line._children = points;
  5819. // Model
  5820. line._model = {
  5821. // Appearance
  5822. tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
  5823. backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
  5824. borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
  5825. borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
  5826. borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
  5827. borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
  5828. borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
  5829. borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
  5830. fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
  5831. // Scale
  5832. scaleTop: scale.top,
  5833. scaleBottom: scale.bottom,
  5834. scaleZero: scale.getBasePixel()
  5835. };
  5836. line.pivot();
  5837. }
  5838. // Update Points
  5839. for (i=0, ilen=points.length; i<ilen; ++i) {
  5840. me.updateElement(points[i], i, reset);
  5841. }
  5842. if (options.showLines && lineElementOptions.tension !== 0) {
  5843. me.updateBezierControlPoints();
  5844. }
  5845. },
  5846. getPointBackgroundColor: function(point, index) {
  5847. var backgroundColor = this.chart.options.elements.point.backgroundColor;
  5848. var dataset = this.getDataset();
  5849. var custom = point.custom || {};
  5850. if (custom.backgroundColor) {
  5851. backgroundColor = custom.backgroundColor;
  5852. } else if (dataset.pointBackgroundColor) {
  5853. backgroundColor = helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, backgroundColor);
  5854. } else if (dataset.backgroundColor) {
  5855. backgroundColor = dataset.backgroundColor;
  5856. }
  5857. return backgroundColor;
  5858. },
  5859. getPointBorderColor: function(point, index) {
  5860. var borderColor = this.chart.options.elements.point.borderColor;
  5861. var dataset = this.getDataset();
  5862. var custom = point.custom || {};
  5863. if (custom.borderColor) {
  5864. borderColor = custom.borderColor;
  5865. } else if (dataset.pointBorderColor) {
  5866. borderColor = helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, borderColor);
  5867. } else if (dataset.borderColor) {
  5868. borderColor = dataset.borderColor;
  5869. }
  5870. return borderColor;
  5871. },
  5872. getPointBorderWidth: function(point, index) {
  5873. var borderWidth = this.chart.options.elements.point.borderWidth;
  5874. var dataset = this.getDataset();
  5875. var custom = point.custom || {};
  5876. if (custom.borderWidth) {
  5877. borderWidth = custom.borderWidth;
  5878. } else if (dataset.pointBorderWidth) {
  5879. borderWidth = helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, borderWidth);
  5880. } else if (dataset.borderWidth) {
  5881. borderWidth = dataset.borderWidth;
  5882. }
  5883. return borderWidth;
  5884. },
  5885. updateElement: function(point, index, reset) {
  5886. var me = this;
  5887. var meta = me.getMeta();
  5888. var custom = point.custom || {};
  5889. var dataset = me.getDataset();
  5890. var datasetIndex = me.index;
  5891. var value = dataset.data[index];
  5892. var yScale = me.getScaleForId(meta.yAxisID);
  5893. var xScale = me.getScaleForId(meta.xAxisID);
  5894. var pointOptions = me.chart.options.elements.point;
  5895. var x, y;
  5896. // Compatibility: If the properties are defined with only the old name, use those values
  5897. if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
  5898. dataset.pointRadius = dataset.radius;
  5899. }
  5900. if ((dataset.hitRadius !== undefined) && (dataset.pointHitRadius === undefined)) {
  5901. dataset.pointHitRadius = dataset.hitRadius;
  5902. }
  5903. x = xScale.getPixelForValue(value, index, datasetIndex, me.chart.isCombo);
  5904. y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex, me.chart.isCombo);
  5905. // Utility
  5906. point._xScale = xScale;
  5907. point._yScale = yScale;
  5908. point._datasetIndex = datasetIndex;
  5909. point._index = index;
  5910. // Desired view properties
  5911. point._model = {
  5912. x: x,
  5913. y: y,
  5914. skip: custom.skip || isNaN(x) || isNaN(y),
  5915. // Appearance
  5916. radius: custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointOptions.radius),
  5917. pointStyle: custom.pointStyle || helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointOptions.pointStyle),
  5918. backgroundColor: me.getPointBackgroundColor(point, index),
  5919. borderColor: me.getPointBorderColor(point, index),
  5920. borderWidth: me.getPointBorderWidth(point, index),
  5921. tension: meta.dataset._model ? meta.dataset._model.tension : 0,
  5922. // Tooltip
  5923. hitRadius: custom.hitRadius || helpers.getValueAtIndexOrDefault(dataset.pointHitRadius, index, pointOptions.hitRadius)
  5924. };
  5925. },
  5926. calculatePointY: function(value, index, datasetIndex, isCombo) {
  5927. var me = this;
  5928. var chart = me.chart;
  5929. var meta = me.getMeta();
  5930. var yScale = me.getScaleForId(meta.yAxisID);
  5931. var sumPos = 0;
  5932. var sumNeg = 0;
  5933. var i, ds, dsMeta;
  5934. if (yScale.options.stacked) {
  5935. for (i = 0; i < datasetIndex; i++) {
  5936. ds = chart.data.datasets[i];
  5937. dsMeta = chart.getDatasetMeta(i);
  5938. if (dsMeta.type === 'line' && chart.isDatasetVisible(i)) {
  5939. if (ds.data[index] < 0) {
  5940. sumNeg += ds.data[index] || 0;
  5941. } else {
  5942. sumPos += ds.data[index] || 0;
  5943. }
  5944. }
  5945. }
  5946. if (value < 0) {
  5947. return yScale.getPixelForValue(sumNeg + value);
  5948. } else {
  5949. return yScale.getPixelForValue(sumPos + value);
  5950. }
  5951. }
  5952. return yScale.getPixelForValue(value);
  5953. },
  5954. updateBezierControlPoints: function() {
  5955. var meta = this.getMeta();
  5956. var area = this.chart.chartArea;
  5957. var points = meta.data || [];
  5958. var i, ilen, point, model, controlPoints;
  5959. for (i=0, ilen=points.length; i<ilen; ++i) {
  5960. point = points[i];
  5961. model = point._model;
  5962. controlPoints = helpers.splineCurve(
  5963. helpers.previousItem(points, i)._model,
  5964. model,
  5965. helpers.nextItem(points, i)._model,
  5966. meta.dataset._model.tension
  5967. );
  5968. // Prevent the bezier going outside of the bounds of the graph
  5969. model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, area.right), area.left);
  5970. model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, area.bottom), area.top);
  5971. model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, area.right), area.left);
  5972. model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, area.bottom), area.top);
  5973. // Now pivot the point for animation
  5974. point.pivot();
  5975. }
  5976. },
  5977. draw: function(ease) {
  5978. var meta = this.getMeta();
  5979. var points = meta.data || [];
  5980. var easingDecimal = ease || 1;
  5981. var i, ilen;
  5982. // Transition Point Locations
  5983. for (i=0, ilen=points.length; i<ilen; ++i) {
  5984. points[i].transition(easingDecimal);
  5985. }
  5986. // Transition and Draw the line
  5987. if (this.chart.options.showLines) {
  5988. meta.dataset.transition(easingDecimal).draw();
  5989. }
  5990. // Draw the points
  5991. for (i=0, ilen=points.length; i<ilen; ++i) {
  5992. points[i].draw();
  5993. }
  5994. },
  5995. setHoverStyle: function(point) {
  5996. // Point
  5997. var dataset = this.chart.data.datasets[point._datasetIndex];
  5998. var index = point._index;
  5999. var custom = point.custom || {};
  6000. var model = point._model;
  6001. model.radius = custom.hoverRadius || helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
  6002. model.backgroundColor = custom.hoverBackgroundColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  6003. model.borderColor = custom.hoverBorderColor || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  6004. model.borderWidth = custom.hoverBorderWidth || helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
  6005. },
  6006. removeHoverStyle: function(point) {
  6007. var me = this;
  6008. var dataset = me.chart.data.datasets[point._datasetIndex];
  6009. var index = point._index;
  6010. var custom = point.custom || {};
  6011. var model = point._model;
  6012. // Compatibility: If the properties are defined with only the old name, use those values
  6013. if ((dataset.radius !== undefined) && (dataset.pointRadius === undefined)) {
  6014. dataset.pointRadius = dataset.radius;
  6015. }
  6016. model.radius = custom.radius || helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, me.chart.options.elements.point.radius);
  6017. model.backgroundColor = me.getPointBackgroundColor(point, index);
  6018. model.borderColor = me.getPointBorderColor(point, index);
  6019. model.borderWidth = me.getPointBorderWidth(point, index);
  6020. }
  6021. });
  6022. };
  6023. },{}],19:[function(require,module,exports){
  6024. "use strict";
  6025. module.exports = function(Chart) {
  6026. var helpers = Chart.helpers;
  6027. Chart.defaults.polarArea = {
  6028. scale: {
  6029. type: "radialLinear",
  6030. lineArc: true // so that lines are circular
  6031. },
  6032. //Boolean - Whether to animate the rotation of the chart
  6033. animation: {
  6034. animateRotate: true,
  6035. animateScale: true
  6036. },
  6037. aspectRatio: 1,
  6038. legendCallback: function(chart) {
  6039. var text = [];
  6040. text.push('<ul class="' + chart.id + '-legend">');
  6041. var data = chart.data;
  6042. var datasets = data.datasets;
  6043. var labels = data.labels;
  6044. if (datasets.length) {
  6045. for (var i = 0; i < datasets[0].data.length; ++i) {
  6046. text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '">');
  6047. if (labels[i]) {
  6048. text.push(labels[i]);
  6049. }
  6050. text.push('</span></li>');
  6051. }
  6052. }
  6053. text.push('</ul>');
  6054. return text.join("");
  6055. },
  6056. legend: {
  6057. labels: {
  6058. generateLabels: function(chart) {
  6059. var data = chart.data;
  6060. if (data.labels.length && data.datasets.length) {
  6061. return data.labels.map(function(label, i) {
  6062. var meta = chart.getDatasetMeta(0);
  6063. var ds = data.datasets[0];
  6064. var arc = meta.data[i];
  6065. var custom = arc.custom || {};
  6066. var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  6067. var arcOpts = chart.options.elements.arc;
  6068. var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
  6069. var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
  6070. var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
  6071. return {
  6072. text: label,
  6073. fillStyle: fill,
  6074. strokeStyle: stroke,
  6075. lineWidth: bw,
  6076. hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
  6077. // Extra data used for toggling the correct item
  6078. index: i
  6079. };
  6080. });
  6081. } else {
  6082. return [];
  6083. }
  6084. }
  6085. },
  6086. onClick: function(e, legendItem) {
  6087. var index = legendItem.index;
  6088. var chart = this.chart;
  6089. var i, ilen, meta;
  6090. for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  6091. meta = chart.getDatasetMeta(i);
  6092. meta.data[index].hidden = !meta.data[index].hidden;
  6093. }
  6094. chart.update();
  6095. }
  6096. },
  6097. // Need to override these to give a nice default
  6098. tooltips: {
  6099. callbacks: {
  6100. title: function() {
  6101. return '';
  6102. },
  6103. label: function(tooltipItem, data) {
  6104. return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
  6105. }
  6106. }
  6107. }
  6108. };
  6109. Chart.controllers.polarArea = Chart.DatasetController.extend({
  6110. dataElementType: Chart.elements.Arc,
  6111. linkScales: helpers.noop,
  6112. update: function update(reset) {
  6113. var _this = this;
  6114. var chart = _this.chart;
  6115. var chartArea = chart.chartArea;
  6116. var meta = this.getMeta();
  6117. var opts = chart.options;
  6118. var arcOpts = opts.elements.arc;
  6119. var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
  6120. chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
  6121. chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
  6122. chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
  6123. _this.outerRadius = chart.outerRadius - (chart.radiusLength * _this.index);
  6124. _this.innerRadius = _this.outerRadius - chart.radiusLength;
  6125. meta.count = _this.countVisibleElements();
  6126. helpers.each(meta.data, function(arc, index) {
  6127. _this.updateElement(arc, index, reset);
  6128. });
  6129. },
  6130. updateElement: function(arc, index, reset) {
  6131. var _this = this;
  6132. var chart = _this.chart;
  6133. var chartArea = chart.chartArea;
  6134. var dataset = _this.getDataset();
  6135. var opts = chart.options;
  6136. var animationOpts = opts.animation;
  6137. var arcOpts = opts.elements.arc;
  6138. var custom = arc.custom || {};
  6139. var scale = chart.scale;
  6140. var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  6141. var labels = chart.data.labels;
  6142. var circumference = _this.calculateCircumference(dataset.data[index]);
  6143. var centerX = (chartArea.left + chartArea.right) / 2;
  6144. var centerY = (chartArea.top + chartArea.bottom) / 2;
  6145. // If there is NaN data before us, we need to calculate the starting angle correctly.
  6146. // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
  6147. var visibleCount = 0;
  6148. var meta = _this.getMeta();
  6149. for (var i = 0; i < index; ++i) {
  6150. if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
  6151. ++visibleCount;
  6152. }
  6153. }
  6154. var distance = arc.hidden? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
  6155. var startAngle = (-0.5 * Math.PI) + (circumference * visibleCount);
  6156. var endAngle = startAngle + (arc.hidden? 0 : circumference);
  6157. var resetModel = {
  6158. x: centerX,
  6159. y: centerY,
  6160. innerRadius: 0,
  6161. outerRadius: animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]),
  6162. startAngle: animationOpts.animateRotate ? Math.PI * -0.5 : startAngle,
  6163. endAngle: animationOpts.animateRotate ? Math.PI * -0.5 : endAngle,
  6164. backgroundColor: custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor),
  6165. borderWidth: custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth),
  6166. borderColor: custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor),
  6167. label: getValueAtIndexOrDefault(labels, index, labels[index])
  6168. };
  6169. helpers.extend(arc, {
  6170. // Utility
  6171. _datasetIndex: _this.index,
  6172. _index: index,
  6173. _scale: scale,
  6174. // Desired view properties
  6175. _model: reset ? resetModel : {
  6176. x: centerX,
  6177. y: centerY,
  6178. innerRadius: 0,
  6179. outerRadius: distance,
  6180. startAngle: startAngle,
  6181. endAngle: endAngle,
  6182. backgroundColor: custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(dataset.backgroundColor, index, arcOpts.backgroundColor),
  6183. borderWidth: custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(dataset.borderWidth, index, arcOpts.borderWidth),
  6184. borderColor: custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(dataset.borderColor, index, arcOpts.borderColor),
  6185. label: getValueAtIndexOrDefault(labels, index, labels[index])
  6186. }
  6187. });
  6188. arc.pivot();
  6189. },
  6190. removeHoverStyle: function(arc) {
  6191. Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
  6192. },
  6193. countVisibleElements: function() {
  6194. var dataset = this.getDataset();
  6195. var meta = this.getMeta();
  6196. var count = 0;
  6197. helpers.each(meta.data, function(element, index) {
  6198. if (!isNaN(dataset.data[index]) && !element.hidden) {
  6199. count++;
  6200. }
  6201. });
  6202. return count;
  6203. },
  6204. calculateCircumference: function(value) {
  6205. var count = this.getMeta().count;
  6206. if (count > 0 && !isNaN(value)) {
  6207. return (2 * Math.PI) / count;
  6208. } else {
  6209. return 0;
  6210. }
  6211. }
  6212. });
  6213. };
  6214. },{}],20:[function(require,module,exports){
  6215. "use strict";
  6216. module.exports = function(Chart) {
  6217. var helpers = Chart.helpers;
  6218. Chart.defaults.radar = {
  6219. scale: {
  6220. type: "radialLinear"
  6221. },
  6222. elements: {
  6223. line: {
  6224. tension: 0 // no bezier in radar
  6225. }
  6226. }
  6227. };
  6228. Chart.controllers.radar = Chart.DatasetController.extend({
  6229. datasetElementType: Chart.elements.Line,
  6230. dataElementType: Chart.elements.Point,
  6231. linkScales: helpers.noop,
  6232. addElementAndReset: function(index) {
  6233. Chart.DatasetController.prototype.addElementAndReset.call(this, index);
  6234. // Make sure bezier control points are updated
  6235. this.updateBezierControlPoints();
  6236. },
  6237. update: function update(reset) {
  6238. var meta = this.getMeta();
  6239. var line = meta.dataset;
  6240. var points = meta.data;
  6241. var custom = line.custom || {};
  6242. var dataset = this.getDataset();
  6243. var lineElementOptions = this.chart.options.elements.line;
  6244. var scale = this.chart.scale;
  6245. // Compatibility: If the properties are defined with only the old name, use those values
  6246. if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
  6247. dataset.lineTension = dataset.tension;
  6248. }
  6249. helpers.extend(meta.dataset, {
  6250. // Utility
  6251. _datasetIndex: this.index,
  6252. // Data
  6253. _children: points,
  6254. _loop: true,
  6255. // Model
  6256. _model: {
  6257. // Appearance
  6258. tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.lineTension, lineElementOptions.tension),
  6259. backgroundColor: custom.backgroundColor ? custom.backgroundColor : (dataset.backgroundColor || lineElementOptions.backgroundColor),
  6260. borderWidth: custom.borderWidth ? custom.borderWidth : (dataset.borderWidth || lineElementOptions.borderWidth),
  6261. borderColor: custom.borderColor ? custom.borderColor : (dataset.borderColor || lineElementOptions.borderColor),
  6262. fill: custom.fill ? custom.fill : (dataset.fill !== undefined ? dataset.fill : lineElementOptions.fill),
  6263. borderCapStyle: custom.borderCapStyle ? custom.borderCapStyle : (dataset.borderCapStyle || lineElementOptions.borderCapStyle),
  6264. borderDash: custom.borderDash ? custom.borderDash : (dataset.borderDash || lineElementOptions.borderDash),
  6265. borderDashOffset: custom.borderDashOffset ? custom.borderDashOffset : (dataset.borderDashOffset || lineElementOptions.borderDashOffset),
  6266. borderJoinStyle: custom.borderJoinStyle ? custom.borderJoinStyle : (dataset.borderJoinStyle || lineElementOptions.borderJoinStyle),
  6267. // Scale
  6268. scaleTop: scale.top,
  6269. scaleBottom: scale.bottom,
  6270. scaleZero: scale.getBasePosition()
  6271. }
  6272. });
  6273. meta.dataset.pivot();
  6274. // Update Points
  6275. helpers.each(points, function(point, index) {
  6276. this.updateElement(point, index, reset);
  6277. }, this);
  6278. // Update bezier control points
  6279. this.updateBezierControlPoints();
  6280. },
  6281. updateElement: function(point, index, reset) {
  6282. var custom = point.custom || {};
  6283. var dataset = this.getDataset();
  6284. var scale = this.chart.scale;
  6285. var pointElementOptions = this.chart.options.elements.point;
  6286. var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
  6287. helpers.extend(point, {
  6288. // Utility
  6289. _datasetIndex: this.index,
  6290. _index: index,
  6291. _scale: scale,
  6292. // Desired view properties
  6293. _model: {
  6294. x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales
  6295. y: reset ? scale.yCenter : pointPosition.y,
  6296. // Appearance
  6297. tension: custom.tension ? custom.tension : helpers.getValueOrDefault(dataset.tension, this.chart.options.elements.line.tension),
  6298. radius: custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, pointElementOptions.radius),
  6299. backgroundColor: custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor),
  6300. borderColor: custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor),
  6301. borderWidth: custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth),
  6302. pointStyle: custom.pointStyle ? custom.pointStyle : helpers.getValueAtIndexOrDefault(dataset.pointStyle, index, pointElementOptions.pointStyle),
  6303. // Tooltip
  6304. hitRadius: custom.hitRadius ? custom.hitRadius : helpers.getValueAtIndexOrDefault(dataset.hitRadius, index, pointElementOptions.hitRadius)
  6305. }
  6306. });
  6307. point._model.skip = custom.skip ? custom.skip : (isNaN(point._model.x) || isNaN(point._model.y));
  6308. },
  6309. updateBezierControlPoints: function() {
  6310. var chartArea = this.chart.chartArea;
  6311. var meta = this.getMeta();
  6312. helpers.each(meta.data, function(point, index) {
  6313. var model = point._model;
  6314. var controlPoints = helpers.splineCurve(
  6315. helpers.previousItem(meta.data, index, true)._model,
  6316. model,
  6317. helpers.nextItem(meta.data, index, true)._model,
  6318. model.tension
  6319. );
  6320. // Prevent the bezier going outside of the bounds of the graph
  6321. model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, chartArea.right), chartArea.left);
  6322. model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, chartArea.bottom), chartArea.top);
  6323. model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, chartArea.right), chartArea.left);
  6324. model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, chartArea.bottom), chartArea.top);
  6325. // Now pivot the point for animation
  6326. point.pivot();
  6327. }, this);
  6328. },
  6329. draw: function(ease) {
  6330. var meta = this.getMeta();
  6331. var easingDecimal = ease || 1;
  6332. // Transition Point Locations
  6333. helpers.each(meta.data, function(point, index) {
  6334. point.transition(easingDecimal);
  6335. });
  6336. // Transition and Draw the line
  6337. meta.dataset.transition(easingDecimal).draw();
  6338. // Draw the points
  6339. helpers.each(meta.data, function(point) {
  6340. point.draw();
  6341. });
  6342. },
  6343. setHoverStyle: function(point) {
  6344. // Point
  6345. var dataset = this.chart.data.datasets[point._datasetIndex];
  6346. var custom = point.custom || {};
  6347. var index = point._index;
  6348. var model = point._model;
  6349. model.radius = custom.hoverRadius ? custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.chart.options.elements.point.hoverRadius);
  6350. model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.getHoverColor(model.backgroundColor));
  6351. model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.getHoverColor(model.borderColor));
  6352. model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderWidth, index, model.borderWidth);
  6353. },
  6354. removeHoverStyle: function(point) {
  6355. var dataset = this.chart.data.datasets[point._datasetIndex];
  6356. var custom = point.custom || {};
  6357. var index = point._index;
  6358. var model = point._model;
  6359. var pointElementOptions = this.chart.options.elements.point;
  6360. model.radius = custom.radius ? custom.radius : helpers.getValueAtIndexOrDefault(dataset.radius, index, pointElementOptions.radius);
  6361. model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, pointElementOptions.backgroundColor);
  6362. model.borderColor = custom.borderColor ? custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, pointElementOptions.borderColor);
  6363. model.borderWidth = custom.borderWidth ? custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, pointElementOptions.borderWidth);
  6364. }
  6365. });
  6366. };
  6367. },{}],21:[function(require,module,exports){
  6368. /*global window: false */
  6369. "use strict";
  6370. module.exports = function(Chart) {
  6371. var helpers = Chart.helpers;
  6372. Chart.defaults.global.animation = {
  6373. duration: 1000,
  6374. easing: "easeOutQuart",
  6375. onProgress: helpers.noop,
  6376. onComplete: helpers.noop
  6377. };
  6378. Chart.Animation = Chart.Element.extend({
  6379. currentStep: null, // the current animation step
  6380. numSteps: 60, // default number of steps
  6381. easing: "", // the easing to use for this animation
  6382. render: null, // render function used by the animation service
  6383. onAnimationProgress: null, // user specified callback to fire on each step of the animation
  6384. onAnimationComplete: null // user specified callback to fire when the animation finishes
  6385. });
  6386. Chart.animationService = {
  6387. frameDuration: 17,
  6388. animations: [],
  6389. dropFrames: 0,
  6390. request: null,
  6391. addAnimation: function(chartInstance, animationObject, duration, lazy) {
  6392. if (!lazy) {
  6393. chartInstance.animating = true;
  6394. }
  6395. for (var index = 0; index < this.animations.length; ++index) {
  6396. if (this.animations[index].chartInstance === chartInstance) {
  6397. // replacing an in progress animation
  6398. this.animations[index].animationObject = animationObject;
  6399. return;
  6400. }
  6401. }
  6402. this.animations.push({
  6403. chartInstance: chartInstance,
  6404. animationObject: animationObject
  6405. });
  6406. // If there are no animations queued, manually kickstart a digest, for lack of a better word
  6407. if (this.animations.length === 1) {
  6408. this.requestAnimationFrame();
  6409. }
  6410. },
  6411. // Cancel the animation for a given chart instance
  6412. cancelAnimation: function(chartInstance) {
  6413. var index = helpers.findIndex(this.animations, function(animationWrapper) {
  6414. return animationWrapper.chartInstance === chartInstance;
  6415. });
  6416. if (index !== -1) {
  6417. this.animations.splice(index, 1);
  6418. chartInstance.animating = false;
  6419. }
  6420. },
  6421. requestAnimationFrame: function() {
  6422. var me = this;
  6423. if (me.request === null) {
  6424. // Skip animation frame requests until the active one is executed.
  6425. // This can happen when processing mouse events, e.g. 'mousemove'
  6426. // and 'mouseout' events will trigger multiple renders.
  6427. me.request = helpers.requestAnimFrame.call(window, function() {
  6428. me.request = null;
  6429. me.startDigest();
  6430. });
  6431. }
  6432. },
  6433. startDigest: function() {
  6434. var startTime = Date.now();
  6435. var framesToDrop = 0;
  6436. if (this.dropFrames > 1) {
  6437. framesToDrop = Math.floor(this.dropFrames);
  6438. this.dropFrames = this.dropFrames % 1;
  6439. }
  6440. var i = 0;
  6441. while (i < this.animations.length) {
  6442. if (this.animations[i].animationObject.currentStep === null) {
  6443. this.animations[i].animationObject.currentStep = 0;
  6444. }
  6445. this.animations[i].animationObject.currentStep += 1 + framesToDrop;
  6446. if (this.animations[i].animationObject.currentStep > this.animations[i].animationObject.numSteps) {
  6447. this.animations[i].animationObject.currentStep = this.animations[i].animationObject.numSteps;
  6448. }
  6449. this.animations[i].animationObject.render(this.animations[i].chartInstance, this.animations[i].animationObject);
  6450. if (this.animations[i].animationObject.onAnimationProgress && this.animations[i].animationObject.onAnimationProgress.call) {
  6451. this.animations[i].animationObject.onAnimationProgress.call(this.animations[i].chartInstance, this.animations[i]);
  6452. }
  6453. if (this.animations[i].animationObject.currentStep === this.animations[i].animationObject.numSteps) {
  6454. if (this.animations[i].animationObject.onAnimationComplete && this.animations[i].animationObject.onAnimationComplete.call) {
  6455. this.animations[i].animationObject.onAnimationComplete.call(this.animations[i].chartInstance, this.animations[i]);
  6456. }
  6457. // executed the last frame. Remove the animation.
  6458. this.animations[i].chartInstance.animating = false;
  6459. this.animations.splice(i, 1);
  6460. } else {
  6461. ++i;
  6462. }
  6463. }
  6464. var endTime = Date.now();
  6465. var dropFrames = (endTime - startTime) / this.frameDuration;
  6466. this.dropFrames += dropFrames;
  6467. // Do we have more stuff to animate?
  6468. if (this.animations.length > 0) {
  6469. this.requestAnimationFrame();
  6470. }
  6471. }
  6472. };
  6473. };
  6474. },{}],22:[function(require,module,exports){
  6475. "use strict";
  6476. module.exports = function(Chart) {
  6477. var helpers = Chart.helpers;
  6478. //Create a dictionary of chart types, to allow for extension of existing types
  6479. Chart.types = {};
  6480. //Store a reference to each instance - allowing us to globally resize chart instances on window resize.
  6481. //Destroy method on the chart will remove the instance of the chart from this reference.
  6482. Chart.instances = {};
  6483. // Controllers available for dataset visualization eg. bar, line, slice, etc.
  6484. Chart.controllers = {};
  6485. // The main controller of a chart
  6486. Chart.Controller = function(instance) {
  6487. this.chart = instance;
  6488. this.config = instance.config;
  6489. this.options = this.config.options = helpers.configMerge(Chart.defaults.global, Chart.defaults[this.config.type], this.config.options || {});
  6490. this.id = helpers.uid();
  6491. Object.defineProperty(this, 'data', {
  6492. get: function() {
  6493. return this.config.data;
  6494. }
  6495. });
  6496. //Add the chart instance to the global namespace
  6497. Chart.instances[this.id] = this;
  6498. if (this.options.responsive) {
  6499. // Silent resize before chart draws
  6500. this.resize(true);
  6501. }
  6502. this.initialize();
  6503. return this;
  6504. };
  6505. helpers.extend(Chart.Controller.prototype, {
  6506. initialize: function initialize() {
  6507. // Before init plugin notification
  6508. Chart.pluginService.notifyPlugins('beforeInit', [this]);
  6509. this.bindEvents();
  6510. // Make sure controllers are built first so that each dataset is bound to an axis before the scales
  6511. // are built
  6512. this.ensureScalesHaveIDs();
  6513. this.buildOrUpdateControllers();
  6514. this.buildScales();
  6515. this.buildSurroundingItems();
  6516. this.updateLayout();
  6517. this.resetElements();
  6518. this.initToolTip();
  6519. this.update();
  6520. // After init plugin notification
  6521. Chart.pluginService.notifyPlugins('afterInit', [this]);
  6522. return this;
  6523. },
  6524. clear: function clear() {
  6525. helpers.clear(this.chart);
  6526. return this;
  6527. },
  6528. stop: function stop() {
  6529. // Stops any current animation loop occuring
  6530. Chart.animationService.cancelAnimation(this);
  6531. return this;
  6532. },
  6533. resize: function resize(silent) {
  6534. var canvas = this.chart.canvas;
  6535. var newWidth = helpers.getMaximumWidth(this.chart.canvas);
  6536. var newHeight = (this.options.maintainAspectRatio && isNaN(this.chart.aspectRatio) === false && isFinite(this.chart.aspectRatio) && this.chart.aspectRatio !== 0) ? newWidth / this.chart.aspectRatio : helpers.getMaximumHeight(this.chart.canvas);
  6537. var sizeChanged = this.chart.width !== newWidth || this.chart.height !== newHeight;
  6538. if (!sizeChanged)
  6539. return this;
  6540. canvas.width = this.chart.width = newWidth;
  6541. canvas.height = this.chart.height = newHeight;
  6542. helpers.retinaScale(this.chart);
  6543. if (!silent) {
  6544. this.stop();
  6545. this.update(this.options.responsiveAnimationDuration);
  6546. }
  6547. return this;
  6548. },
  6549. ensureScalesHaveIDs: function ensureScalesHaveIDs() {
  6550. var options = this.options;
  6551. var scalesOptions = options.scales || {};
  6552. var scaleOptions = options.scale;
  6553. helpers.each(scalesOptions.xAxes, function(xAxisOptions, index) {
  6554. xAxisOptions.id = xAxisOptions.id || ('x-axis-' + index);
  6555. });
  6556. helpers.each(scalesOptions.yAxes, function(yAxisOptions, index) {
  6557. yAxisOptions.id = yAxisOptions.id || ('y-axis-' + index);
  6558. });
  6559. if (scaleOptions) {
  6560. scaleOptions.id = scaleOptions.id || 'scale';
  6561. }
  6562. },
  6563. /**
  6564. * Builds a map of scale ID to scale object for future lookup.
  6565. */
  6566. buildScales: function buildScales() {
  6567. var me = this;
  6568. var options = me.options;
  6569. var scales = me.scales = {};
  6570. var items = [];
  6571. if (options.scales) {
  6572. items = items.concat(
  6573. (options.scales.xAxes || []).map(function(xAxisOptions) {
  6574. return { options: xAxisOptions, dtype: 'category' }; }),
  6575. (options.scales.yAxes || []).map(function(yAxisOptions) {
  6576. return { options: yAxisOptions, dtype: 'linear' }; }));
  6577. }
  6578. if (options.scale) {
  6579. items.push({ options: options.scale, dtype: 'radialLinear', isDefault: true });
  6580. }
  6581. helpers.each(items, function(item, index) {
  6582. var scaleOptions = item.options;
  6583. var scaleType = helpers.getValueOrDefault(scaleOptions.type, item.dtype);
  6584. var scaleClass = Chart.scaleService.getScaleConstructor(scaleType);
  6585. if (!scaleClass) {
  6586. return;
  6587. }
  6588. var scale = new scaleClass({
  6589. id: scaleOptions.id,
  6590. options: scaleOptions,
  6591. ctx: me.chart.ctx,
  6592. chart: me
  6593. });
  6594. scales[scale.id] = scale;
  6595. // TODO(SB): I think we should be able to remove this custom case (options.scale)
  6596. // and consider it as a regular scale part of the "scales"" map only! This would
  6597. // make the logic easier and remove some useless? custom code.
  6598. if (item.isDefault) {
  6599. me.scale = scale;
  6600. }
  6601. });
  6602. Chart.scaleService.addScalesToLayout(this);
  6603. },
  6604. buildSurroundingItems: function() {
  6605. if (this.options.title) {
  6606. this.titleBlock = new Chart.Title({
  6607. ctx: this.chart.ctx,
  6608. options: this.options.title,
  6609. chart: this
  6610. });
  6611. Chart.layoutService.addBox(this, this.titleBlock);
  6612. }
  6613. if (this.options.legend) {
  6614. this.legend = new Chart.Legend({
  6615. ctx: this.chart.ctx,
  6616. options: this.options.legend,
  6617. chart: this
  6618. });
  6619. Chart.layoutService.addBox(this, this.legend);
  6620. }
  6621. },
  6622. updateLayout: function() {
  6623. Chart.layoutService.update(this, this.chart.width, this.chart.height);
  6624. },
  6625. buildOrUpdateControllers: function buildOrUpdateControllers() {
  6626. var types = [];
  6627. var newControllers = [];
  6628. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6629. var meta = this.getDatasetMeta(datasetIndex);
  6630. if (!meta.type) {
  6631. meta.type = dataset.type || this.config.type;
  6632. }
  6633. types.push(meta.type);
  6634. if (meta.controller) {
  6635. meta.controller.updateIndex(datasetIndex);
  6636. } else {
  6637. meta.controller = new Chart.controllers[meta.type](this, datasetIndex);
  6638. newControllers.push(meta.controller);
  6639. }
  6640. }, this);
  6641. if (types.length > 1) {
  6642. for (var i = 1; i < types.length; i++) {
  6643. if (types[i] !== types[i - 1]) {
  6644. this.isCombo = true;
  6645. break;
  6646. }
  6647. }
  6648. }
  6649. return newControllers;
  6650. },
  6651. resetElements: function resetElements() {
  6652. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6653. this.getDatasetMeta(datasetIndex).controller.reset();
  6654. }, this);
  6655. },
  6656. update: function update(animationDuration, lazy) {
  6657. Chart.pluginService.notifyPlugins('beforeUpdate', [this]);
  6658. // In case the entire data object changed
  6659. this.tooltip._data = this.data;
  6660. // Make sure dataset controllers are updated and new controllers are reset
  6661. var newControllers = this.buildOrUpdateControllers();
  6662. // Make sure all dataset controllers have correct meta data counts
  6663. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6664. this.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements();
  6665. }, this);
  6666. Chart.layoutService.update(this, this.chart.width, this.chart.height);
  6667. // Apply changes to the dataets that require the scales to have been calculated i.e BorderColor chages
  6668. Chart.pluginService.notifyPlugins('afterScaleUpdate', [this]);
  6669. // Can only reset the new controllers after the scales have been updated
  6670. helpers.each(newControllers, function(controller) {
  6671. controller.reset();
  6672. });
  6673. // This will loop through any data and do the appropriate element update for the type
  6674. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6675. this.getDatasetMeta(datasetIndex).controller.update();
  6676. }, this);
  6677. // Do this before render so that any plugins that need final scale updates can use it
  6678. Chart.pluginService.notifyPlugins('afterUpdate', [this]);
  6679. this.render(animationDuration, lazy);
  6680. },
  6681. render: function render(duration, lazy) {
  6682. Chart.pluginService.notifyPlugins('beforeRender', [this]);
  6683. var animationOptions = this.options.animation;
  6684. if (animationOptions && ((typeof duration !== 'undefined' && duration !== 0) || (typeof duration === 'undefined' && animationOptions.duration !== 0))) {
  6685. var animation = new Chart.Animation();
  6686. animation.numSteps = (duration || animationOptions.duration) / 16.66; //60 fps
  6687. animation.easing = animationOptions.easing;
  6688. // render function
  6689. animation.render = function(chartInstance, animationObject) {
  6690. var easingFunction = helpers.easingEffects[animationObject.easing];
  6691. var stepDecimal = animationObject.currentStep / animationObject.numSteps;
  6692. var easeDecimal = easingFunction(stepDecimal);
  6693. chartInstance.draw(easeDecimal, stepDecimal, animationObject.currentStep);
  6694. };
  6695. // user events
  6696. animation.onAnimationProgress = animationOptions.onProgress;
  6697. animation.onAnimationComplete = animationOptions.onComplete;
  6698. Chart.animationService.addAnimation(this, animation, duration, lazy);
  6699. } else {
  6700. this.draw();
  6701. if (animationOptions && animationOptions.onComplete && animationOptions.onComplete.call) {
  6702. animationOptions.onComplete.call(this);
  6703. }
  6704. }
  6705. return this;
  6706. },
  6707. draw: function(ease) {
  6708. var easingDecimal = ease || 1;
  6709. this.clear();
  6710. Chart.pluginService.notifyPlugins('beforeDraw', [this, easingDecimal]);
  6711. // Draw all the scales
  6712. helpers.each(this.boxes, function(box) {
  6713. box.draw(this.chartArea);
  6714. }, this);
  6715. if (this.scale) {
  6716. this.scale.draw();
  6717. }
  6718. // Clip out the chart area so that anything outside does not draw. This is necessary for zoom and pan to function
  6719. var context = this.chart.ctx;
  6720. context.save();
  6721. context.beginPath();
  6722. context.rect(this.chartArea.left, this.chartArea.top, this.chartArea.right - this.chartArea.left, this.chartArea.bottom - this.chartArea.top);
  6723. context.clip();
  6724. // Draw each dataset via its respective controller (reversed to support proper line stacking)
  6725. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6726. if (this.isDatasetVisible(datasetIndex)) {
  6727. this.getDatasetMeta(datasetIndex).controller.draw(ease);
  6728. }
  6729. }, this, true);
  6730. // Restore from the clipping operation
  6731. context.restore();
  6732. // Finally draw the tooltip
  6733. this.tooltip.transition(easingDecimal).draw();
  6734. Chart.pluginService.notifyPlugins('afterDraw', [this, easingDecimal]);
  6735. },
  6736. // Get the single element that was clicked on
  6737. // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw
  6738. getElementAtEvent: function(e) {
  6739. var eventPosition = helpers.getRelativePosition(e, this.chart);
  6740. var elementsArray = [];
  6741. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6742. if (this.isDatasetVisible(datasetIndex)) {
  6743. var meta = this.getDatasetMeta(datasetIndex);
  6744. helpers.each(meta.data, function(element, index) {
  6745. if (element.inRange(eventPosition.x, eventPosition.y)) {
  6746. elementsArray.push(element);
  6747. return elementsArray;
  6748. }
  6749. });
  6750. }
  6751. }, this);
  6752. return elementsArray;
  6753. },
  6754. getElementsAtEvent: function(e) {
  6755. var eventPosition = helpers.getRelativePosition(e, this.chart);
  6756. var elementsArray = [];
  6757. var found = (function() {
  6758. if (this.data.datasets) {
  6759. for (var i = 0; i < this.data.datasets.length; i++) {
  6760. var meta = this.getDatasetMeta(i);
  6761. if (this.isDatasetVisible(i)) {
  6762. for (var j = 0; j < meta.data.length; j++) {
  6763. if (meta.data[j].inRange(eventPosition.x, eventPosition.y)) {
  6764. return meta.data[j];
  6765. }
  6766. }
  6767. }
  6768. }
  6769. }
  6770. }).call(this);
  6771. if (!found) {
  6772. return elementsArray;
  6773. }
  6774. helpers.each(this.data.datasets, function(dataset, datasetIndex) {
  6775. if (this.isDatasetVisible(datasetIndex)) {
  6776. var meta = this.getDatasetMeta(datasetIndex);
  6777. elementsArray.push(meta.data[found._index]);
  6778. }
  6779. }, this);
  6780. return elementsArray;
  6781. },
  6782. getElementsAtEventForMode: function(e, mode) {
  6783. var me = this;
  6784. switch (mode) {
  6785. case 'single':
  6786. return me.getElementAtEvent(e);
  6787. case 'label':
  6788. return me.getElementsAtEvent(e);
  6789. case 'dataset':
  6790. return me.getDatasetAtEvent(e);
  6791. default:
  6792. return e;
  6793. }
  6794. },
  6795. getDatasetAtEvent: function(e) {
  6796. var elementsArray = this.getElementAtEvent(e);
  6797. if (elementsArray.length > 0) {
  6798. elementsArray = this.getDatasetMeta(elementsArray[0]._datasetIndex).data;
  6799. }
  6800. return elementsArray;
  6801. },
  6802. getDatasetMeta: function(datasetIndex) {
  6803. var dataset = this.data.datasets[datasetIndex];
  6804. if (!dataset._meta) {
  6805. dataset._meta = {};
  6806. }
  6807. var meta = dataset._meta[this.id];
  6808. if (!meta) {
  6809. meta = dataset._meta[this.id] = {
  6810. type: null,
  6811. data: [],
  6812. dataset: null,
  6813. controller: null,
  6814. hidden: null, // See isDatasetVisible() comment
  6815. xAxisID: null,
  6816. yAxisID: null
  6817. };
  6818. }
  6819. return meta;
  6820. },
  6821. getVisibleDatasetCount: function() {
  6822. var count = 0;
  6823. for (var i = 0, ilen = this.data.datasets.length; i<ilen; ++i) {
  6824. if (this.isDatasetVisible(i)) {
  6825. count++;
  6826. }
  6827. }
  6828. return count;
  6829. },
  6830. isDatasetVisible: function(datasetIndex) {
  6831. var meta = this.getDatasetMeta(datasetIndex);
  6832. // meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,
  6833. // the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.
  6834. return typeof meta.hidden === 'boolean'? !meta.hidden : !this.data.datasets[datasetIndex].hidden;
  6835. },
  6836. generateLegend: function generateLegend() {
  6837. return this.options.legendCallback(this);
  6838. },
  6839. destroy: function destroy() {
  6840. this.clear();
  6841. helpers.unbindEvents(this, this.events);
  6842. helpers.removeResizeListener(this.chart.canvas.parentNode);
  6843. // Reset canvas height/width attributes
  6844. var canvas = this.chart.canvas;
  6845. canvas.width = this.chart.width;
  6846. canvas.height = this.chart.height;
  6847. // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here
  6848. if (this.chart.originalDevicePixelRatio !== undefined) {
  6849. this.chart.ctx.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio);
  6850. }
  6851. // Reset to the old style since it may have been changed by the device pixel ratio changes
  6852. canvas.style.width = this.chart.originalCanvasStyleWidth;
  6853. canvas.style.height = this.chart.originalCanvasStyleHeight;
  6854. Chart.pluginService.notifyPlugins('destroy', [this]);
  6855. delete Chart.instances[this.id];
  6856. },
  6857. toBase64Image: function toBase64Image() {
  6858. return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments);
  6859. },
  6860. initToolTip: function initToolTip() {
  6861. this.tooltip = new Chart.Tooltip({
  6862. _chart: this.chart,
  6863. _chartInstance: this,
  6864. _data: this.data,
  6865. _options: this.options
  6866. }, this);
  6867. },
  6868. bindEvents: function bindEvents() {
  6869. helpers.bindEvents(this, this.options.events, function(evt) {
  6870. this.eventHandler(evt);
  6871. });
  6872. },
  6873. updateHoverStyle: function(elements, mode, enabled) {
  6874. var method = enabled? 'setHoverStyle' : 'removeHoverStyle';
  6875. var element, i, ilen;
  6876. switch (mode) {
  6877. case 'single':
  6878. elements = [ elements[0] ];
  6879. break;
  6880. case 'label':
  6881. case 'dataset':
  6882. // elements = elements;
  6883. break;
  6884. default:
  6885. // unsupported mode
  6886. return;
  6887. }
  6888. for (i=0, ilen=elements.length; i<ilen; ++i) {
  6889. element = elements[i];
  6890. if (element) {
  6891. this.getDatasetMeta(element._datasetIndex).controller[method](element);
  6892. }
  6893. }
  6894. },
  6895. eventHandler: function eventHandler(e) {
  6896. var me = this;
  6897. var tooltip = me.tooltip;
  6898. var options = me.options || {};
  6899. var hoverOptions = options.hover;
  6900. var tooltipsOptions = options.tooltips;
  6901. me.lastActive = me.lastActive || [];
  6902. me.lastTooltipActive = me.lastTooltipActive || [];
  6903. // Find Active Elements for hover and tooltips
  6904. if (e.type === 'mouseout') {
  6905. me.active = [];
  6906. me.tooltipActive = [];
  6907. } else {
  6908. me.active = me.getElementsAtEventForMode(e, hoverOptions.mode);
  6909. me.tooltipActive = me.getElementsAtEventForMode(e, tooltipsOptions.mode);
  6910. }
  6911. // On Hover hook
  6912. if (hoverOptions.onHover) {
  6913. hoverOptions.onHover.call(me, me.active);
  6914. }
  6915. if (e.type === 'mouseup' || e.type === 'click') {
  6916. if (options.onClick) {
  6917. options.onClick.call(me, e, me.active);
  6918. }
  6919. if (me.legend && me.legend.handleEvent) {
  6920. me.legend.handleEvent(e);
  6921. }
  6922. }
  6923. // Remove styling for last active (even if it may still be active)
  6924. if (me.lastActive.length) {
  6925. me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);
  6926. }
  6927. // Built in hover styling
  6928. if (me.active.length && hoverOptions.mode) {
  6929. me.updateHoverStyle(me.active, hoverOptions.mode, true);
  6930. }
  6931. // Built in Tooltips
  6932. if (tooltipsOptions.enabled || tooltipsOptions.custom) {
  6933. tooltip.initialize();
  6934. tooltip._active = me.tooltipActive;
  6935. tooltip.update(true);
  6936. }
  6937. // Hover animations
  6938. tooltip.pivot();
  6939. if (!me.animating) {
  6940. // If entering, leaving, or changing elements, animate the change via pivot
  6941. if (!helpers.arrayEquals(me.active, me.lastActive) ||
  6942. !helpers.arrayEquals(me.tooltipActive, me.lastTooltipActive)) {
  6943. me.stop();
  6944. if (tooltipsOptions.enabled || tooltipsOptions.custom) {
  6945. tooltip.update(true);
  6946. }
  6947. // We only need to render at this point. Updating will cause scales to be
  6948. // recomputed generating flicker & using more memory than necessary.
  6949. me.render(hoverOptions.animationDuration, true);
  6950. }
  6951. }
  6952. // Remember Last Actives
  6953. me.lastActive = me.active;
  6954. me.lastTooltipActive = me.tooltipActive;
  6955. return me;
  6956. }
  6957. });
  6958. };
  6959. },{}],23:[function(require,module,exports){
  6960. "use strict";
  6961. module.exports = function(Chart) {
  6962. var helpers = Chart.helpers;
  6963. var noop = helpers.noop;
  6964. // Base class for all dataset controllers (line, bar, etc)
  6965. Chart.DatasetController = function(chart, datasetIndex) {
  6966. this.initialize.call(this, chart, datasetIndex);
  6967. };
  6968. helpers.extend(Chart.DatasetController.prototype, {
  6969. /**
  6970. * Element type used to generate a meta dataset (e.g. Chart.element.Line).
  6971. * @type {Chart.core.element}
  6972. */
  6973. datasetElementType: null,
  6974. /**
  6975. * Element type used to generate a meta data (e.g. Chart.element.Point).
  6976. * @type {Chart.core.element}
  6977. */
  6978. dataElementType: null,
  6979. initialize: function(chart, datasetIndex) {
  6980. this.chart = chart;
  6981. this.index = datasetIndex;
  6982. this.linkScales();
  6983. this.addElements();
  6984. },
  6985. updateIndex: function(datasetIndex) {
  6986. this.index = datasetIndex;
  6987. },
  6988. linkScales: function() {
  6989. var meta = this.getMeta();
  6990. var dataset = this.getDataset();
  6991. if (meta.xAxisID === null) {
  6992. meta.xAxisID = dataset.xAxisID || this.chart.options.scales.xAxes[0].id;
  6993. }
  6994. if (meta.yAxisID === null) {
  6995. meta.yAxisID = dataset.yAxisID || this.chart.options.scales.yAxes[0].id;
  6996. }
  6997. },
  6998. getDataset: function() {
  6999. return this.chart.data.datasets[this.index];
  7000. },
  7001. getMeta: function() {
  7002. return this.chart.getDatasetMeta(this.index);
  7003. },
  7004. getScaleForId: function(scaleID) {
  7005. return this.chart.scales[scaleID];
  7006. },
  7007. reset: function() {
  7008. this.update(true);
  7009. },
  7010. createMetaDataset: function() {
  7011. var me = this;
  7012. var type = me.datasetElementType;
  7013. return type && new type({
  7014. _chart: me.chart.chart,
  7015. _datasetIndex: me.index
  7016. });
  7017. },
  7018. createMetaData: function(index) {
  7019. var me = this;
  7020. var type = me.dataElementType;
  7021. return type && new type({
  7022. _chart: me.chart.chart,
  7023. _datasetIndex: me.index,
  7024. _index: index
  7025. });
  7026. },
  7027. addElements: function() {
  7028. var me = this;
  7029. var meta = me.getMeta();
  7030. var data = me.getDataset().data || [];
  7031. var metaData = meta.data;
  7032. var i, ilen;
  7033. for (i=0, ilen=data.length; i<ilen; ++i) {
  7034. metaData[i] = metaData[i] || me.createMetaData(meta, i);
  7035. }
  7036. meta.dataset = meta.dataset || me.createMetaDataset();
  7037. },
  7038. addElementAndReset: function(index) {
  7039. var me = this;
  7040. var element = me.createMetaData(index);
  7041. me.getMeta().data.splice(index, 0, element);
  7042. me.updateElement(element, index, true);
  7043. },
  7044. buildOrUpdateElements: function buildOrUpdateElements() {
  7045. // Handle the number of data points changing
  7046. var meta = this.getMeta(),
  7047. md = meta.data,
  7048. numData = this.getDataset().data.length,
  7049. numMetaData = md.length;
  7050. // Make sure that we handle number of datapoints changing
  7051. if (numData < numMetaData) {
  7052. // Remove excess bars for data points that have been removed
  7053. md.splice(numData, numMetaData - numData);
  7054. } else if (numData > numMetaData) {
  7055. // Add new elements
  7056. for (var index = numMetaData; index < numData; ++index) {
  7057. this.addElementAndReset(index);
  7058. }
  7059. }
  7060. },
  7061. update: noop,
  7062. draw: function(ease) {
  7063. var easingDecimal = ease || 1;
  7064. helpers.each(this.getMeta().data, function(element, index) {
  7065. element.transition(easingDecimal).draw();
  7066. });
  7067. },
  7068. removeHoverStyle: function(element, elementOpts) {
  7069. var dataset = this.chart.data.datasets[element._datasetIndex],
  7070. index = element._index,
  7071. custom = element.custom || {},
  7072. valueOrDefault = helpers.getValueAtIndexOrDefault,
  7073. color = helpers.color,
  7074. model = element._model;
  7075. model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
  7076. model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
  7077. model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
  7078. },
  7079. setHoverStyle: function(element) {
  7080. var dataset = this.chart.data.datasets[element._datasetIndex],
  7081. index = element._index,
  7082. custom = element.custom || {},
  7083. valueOrDefault = helpers.getValueAtIndexOrDefault,
  7084. color = helpers.color,
  7085. getHoverColor = helpers.getHoverColor,
  7086. model = element._model;
  7087. model.backgroundColor = custom.hoverBackgroundColor ? custom.hoverBackgroundColor : valueOrDefault(dataset.hoverBackgroundColor, index, getHoverColor(model.backgroundColor));
  7088. model.borderColor = custom.hoverBorderColor ? custom.hoverBorderColor : valueOrDefault(dataset.hoverBorderColor, index, getHoverColor(model.borderColor));
  7089. model.borderWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueOrDefault(dataset.hoverBorderWidth, index, model.borderWidth);
  7090. }
  7091. });
  7092. Chart.DatasetController.extend = helpers.inherits;
  7093. };
  7094. },{}],24:[function(require,module,exports){
  7095. "use strict";
  7096. module.exports = function(Chart) {
  7097. var helpers = Chart.helpers;
  7098. Chart.elements = {};
  7099. Chart.Element = function(configuration) {
  7100. helpers.extend(this, configuration);
  7101. this.initialize.apply(this, arguments);
  7102. };
  7103. helpers.extend(Chart.Element.prototype, {
  7104. initialize: function() {
  7105. this.hidden = false;
  7106. },
  7107. pivot: function() {
  7108. if (!this._view) {
  7109. this._view = helpers.clone(this._model);
  7110. }
  7111. this._start = helpers.clone(this._view);
  7112. return this;
  7113. },
  7114. transition: function(ease) {
  7115. if (!this._view) {
  7116. this._view = helpers.clone(this._model);
  7117. }
  7118. // No animation -> No Transition
  7119. if (ease === 1) {
  7120. this._view = this._model;
  7121. this._start = null;
  7122. return this;
  7123. }
  7124. if (!this._start) {
  7125. this.pivot();
  7126. }
  7127. helpers.each(this._model, function(value, key) {
  7128. if (key[0] === '_') {
  7129. // Only non-underscored properties
  7130. }
  7131. // Init if doesn't exist
  7132. else if (!this._view.hasOwnProperty(key)) {
  7133. if (typeof value === 'number' && !isNaN(this._view[key])) {
  7134. this._view[key] = value * ease;
  7135. } else {
  7136. this._view[key] = value;
  7137. }
  7138. }
  7139. // No unnecessary computations
  7140. else if (value === this._view[key]) {
  7141. // It's the same! Woohoo!
  7142. }
  7143. // Color transitions if possible
  7144. else if (typeof value === 'string') {
  7145. try {
  7146. var color = helpers.color(this._model[key]).mix(helpers.color(this._start[key]), ease);
  7147. this._view[key] = color.rgbString();
  7148. } catch (err) {
  7149. this._view[key] = value;
  7150. }
  7151. }
  7152. // Number transitions
  7153. else if (typeof value === 'number') {
  7154. var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0;
  7155. this._view[key] = ((this._model[key] - startVal) * ease) + startVal;
  7156. }
  7157. // Everything else
  7158. else {
  7159. this._view[key] = value;
  7160. }
  7161. }, this);
  7162. return this;
  7163. },
  7164. tooltipPosition: function() {
  7165. return {
  7166. x: this._model.x,
  7167. y: this._model.y
  7168. };
  7169. },
  7170. hasValue: function() {
  7171. return helpers.isNumber(this._model.x) && helpers.isNumber(this._model.y);
  7172. }
  7173. });
  7174. Chart.Element.extend = helpers.inherits;
  7175. };
  7176. },{}],25:[function(require,module,exports){
  7177. /*global window: false */
  7178. /*global document: false */
  7179. "use strict";
  7180. var color = require('chartjs-color');
  7181. module.exports = function(Chart) {
  7182. //Global Chart helpers object for utility methods and classes
  7183. var helpers = Chart.helpers = {};
  7184. //-- Basic js utility methods
  7185. helpers.each = function(loopable, callback, self, reverse) {
  7186. // Check to see if null or undefined firstly.
  7187. var i, len;
  7188. if (helpers.isArray(loopable)) {
  7189. len = loopable.length;
  7190. if (reverse) {
  7191. for (i = len - 1; i >= 0; i--) {
  7192. callback.call(self, loopable[i], i);
  7193. }
  7194. } else {
  7195. for (i = 0; i < len; i++) {
  7196. callback.call(self, loopable[i], i);
  7197. }
  7198. }
  7199. } else if (typeof loopable === 'object') {
  7200. var keys = Object.keys(loopable);
  7201. len = keys.length;
  7202. for (i = 0; i < len; i++) {
  7203. callback.call(self, loopable[keys[i]], keys[i]);
  7204. }
  7205. }
  7206. };
  7207. helpers.clone = function(obj) {
  7208. var objClone = {};
  7209. helpers.each(obj, function(value, key) {
  7210. if (helpers.isArray(value)) {
  7211. objClone[key] = value.slice(0);
  7212. } else if (typeof value === 'object' && value !== null) {
  7213. objClone[key] = helpers.clone(value);
  7214. } else {
  7215. objClone[key] = value;
  7216. }
  7217. });
  7218. return objClone;
  7219. };
  7220. helpers.extend = function(base) {
  7221. var len = arguments.length;
  7222. var additionalArgs = [];
  7223. for (var i = 1; i < len; i++) {
  7224. additionalArgs.push(arguments[i]);
  7225. }
  7226. helpers.each(additionalArgs, function(extensionObject) {
  7227. helpers.each(extensionObject, function(value, key) {
  7228. base[key] = value;
  7229. });
  7230. });
  7231. return base;
  7232. };
  7233. // Need a special merge function to chart configs since they are now grouped
  7234. helpers.configMerge = function(_base) {
  7235. var base = helpers.clone(_base);
  7236. helpers.each(Array.prototype.slice.call(arguments, 1), function(extension) {
  7237. helpers.each(extension, function(value, key) {
  7238. if (key === 'scales') {
  7239. // Scale config merging is complex. Add out own function here for that
  7240. base[key] = helpers.scaleMerge(base.hasOwnProperty(key) ? base[key] : {}, value);
  7241. } else if (key === 'scale') {
  7242. // Used in polar area & radar charts since there is only one scale
  7243. base[key] = helpers.configMerge(base.hasOwnProperty(key) ? base[key] : {}, Chart.scaleService.getScaleDefaults(value.type), value);
  7244. } else if (base.hasOwnProperty(key) && helpers.isArray(base[key]) && helpers.isArray(value)) {
  7245. // In this case we have an array of objects replacing another array. Rather than doing a strict replace,
  7246. // merge. This allows easy scale option merging
  7247. var baseArray = base[key];
  7248. helpers.each(value, function(valueObj, index) {
  7249. if (index < baseArray.length) {
  7250. if (typeof baseArray[index] === 'object' && baseArray[index] !== null && typeof valueObj === 'object' && valueObj !== null) {
  7251. // Two objects are coming together. Do a merge of them.
  7252. baseArray[index] = helpers.configMerge(baseArray[index], valueObj);
  7253. } else {
  7254. // Just overwrite in this case since there is nothing to merge
  7255. baseArray[index] = valueObj;
  7256. }
  7257. } else {
  7258. baseArray.push(valueObj); // nothing to merge
  7259. }
  7260. });
  7261. } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") {
  7262. // If we are overwriting an object with an object, do a merge of the properties.
  7263. base[key] = helpers.configMerge(base[key], value);
  7264. } else {
  7265. // can just overwrite the value in this case
  7266. base[key] = value;
  7267. }
  7268. });
  7269. });
  7270. return base;
  7271. };
  7272. helpers.extendDeep = function(_base) {
  7273. return _extendDeep.apply(this, arguments);
  7274. function _extendDeep(dst) {
  7275. helpers.each(arguments, function(obj) {
  7276. if (obj !== dst) {
  7277. helpers.each(obj, function(value, key) {
  7278. if (dst[key] && dst[key].constructor && dst[key].constructor === Object) {
  7279. _extendDeep(dst[key], value);
  7280. } else {
  7281. dst[key] = value;
  7282. }
  7283. });
  7284. }
  7285. });
  7286. return dst;
  7287. }
  7288. };
  7289. helpers.scaleMerge = function(_base, extension) {
  7290. var base = helpers.clone(_base);
  7291. helpers.each(extension, function(value, key) {
  7292. if (key === 'xAxes' || key === 'yAxes') {
  7293. // These properties are arrays of items
  7294. if (base.hasOwnProperty(key)) {
  7295. helpers.each(value, function(valueObj, index) {
  7296. var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
  7297. var axisDefaults = Chart.scaleService.getScaleDefaults(axisType);
  7298. if (index >= base[key].length || !base[key][index].type) {
  7299. base[key].push(helpers.configMerge(axisDefaults, valueObj));
  7300. } else if (valueObj.type && valueObj.type !== base[key][index].type) {
  7301. // Type changed. Bring in the new defaults before we bring in valueObj so that valueObj can override the correct scale defaults
  7302. base[key][index] = helpers.configMerge(base[key][index], axisDefaults, valueObj);
  7303. } else {
  7304. // Type is the same
  7305. base[key][index] = helpers.configMerge(base[key][index], valueObj);
  7306. }
  7307. });
  7308. } else {
  7309. base[key] = [];
  7310. helpers.each(value, function(valueObj) {
  7311. var axisType = helpers.getValueOrDefault(valueObj.type, key === 'xAxes' ? 'category' : 'linear');
  7312. base[key].push(helpers.configMerge(Chart.scaleService.getScaleDefaults(axisType), valueObj));
  7313. });
  7314. }
  7315. } else if (base.hasOwnProperty(key) && typeof base[key] === "object" && base[key] !== null && typeof value === "object") {
  7316. // If we are overwriting an object with an object, do a merge of the properties.
  7317. base[key] = helpers.configMerge(base[key], value);
  7318. } else {
  7319. // can just overwrite the value in this case
  7320. base[key] = value;
  7321. }
  7322. });
  7323. return base;
  7324. };
  7325. helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) {
  7326. if (value === undefined || value === null) {
  7327. return defaultValue;
  7328. }
  7329. if (helpers.isArray(value)) {
  7330. return index < value.length ? value[index] : defaultValue;
  7331. }
  7332. return value;
  7333. };
  7334. helpers.getValueOrDefault = function(value, defaultValue) {
  7335. return value === undefined ? defaultValue : value;
  7336. };
  7337. helpers.indexOf = function(arrayToSearch, item) {
  7338. if (Array.prototype.indexOf) {
  7339. return arrayToSearch.indexOf(item);
  7340. } else {
  7341. for (var i = 0; i < arrayToSearch.length; i++) {
  7342. if (arrayToSearch[i] === item)
  7343. return i;
  7344. }
  7345. return -1;
  7346. }
  7347. };
  7348. helpers.where = function(collection, filterCallback) {
  7349. if (helpers.isArray(collection) && Array.prototype.filter) {
  7350. return collection.filter(filterCallback);
  7351. } else {
  7352. var filtered = [];
  7353. helpers.each(collection, function(item) {
  7354. if (filterCallback(item)) {
  7355. filtered.push(item);
  7356. }
  7357. });
  7358. return filtered;
  7359. }
  7360. };
  7361. helpers.findIndex = function(arrayToSearch, callback, thisArg) {
  7362. var index = -1;
  7363. if (Array.prototype.findIndex) {
  7364. index = arrayToSearch.findIndex(callback, thisArg);
  7365. } else {
  7366. for (var i = 0; i < arrayToSearch.length; ++i) {
  7367. thisArg = thisArg !== undefined ? thisArg : arrayToSearch;
  7368. if (callback.call(thisArg, arrayToSearch[i], i, arrayToSearch)) {
  7369. index = i;
  7370. break;
  7371. }
  7372. }
  7373. }
  7374. return index;
  7375. };
  7376. helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {
  7377. // Default to start of the array
  7378. if (startIndex === undefined || startIndex === null) {
  7379. startIndex = -1;
  7380. }
  7381. for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
  7382. var currentItem = arrayToSearch[i];
  7383. if (filterCallback(currentItem)) {
  7384. return currentItem;
  7385. }
  7386. }
  7387. };
  7388. helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {
  7389. // Default to end of the array
  7390. if (startIndex === undefined || startIndex === null) {
  7391. startIndex = arrayToSearch.length;
  7392. }
  7393. for (var i = startIndex - 1; i >= 0; i--) {
  7394. var currentItem = arrayToSearch[i];
  7395. if (filterCallback(currentItem)) {
  7396. return currentItem;
  7397. }
  7398. }
  7399. };
  7400. helpers.inherits = function(extensions) {
  7401. //Basic javascript inheritance based on the model created in Backbone.js
  7402. var parent = this;
  7403. var ChartElement = (extensions && extensions.hasOwnProperty("constructor")) ? extensions.constructor : function() {
  7404. return parent.apply(this, arguments);
  7405. };
  7406. var Surrogate = function() {
  7407. this.constructor = ChartElement;
  7408. };
  7409. Surrogate.prototype = parent.prototype;
  7410. ChartElement.prototype = new Surrogate();
  7411. ChartElement.extend = helpers.inherits;
  7412. if (extensions) {
  7413. helpers.extend(ChartElement.prototype, extensions);
  7414. }
  7415. ChartElement.__super__ = parent.prototype;
  7416. return ChartElement;
  7417. };
  7418. helpers.noop = function() {};
  7419. helpers.uid = (function() {
  7420. var id = 0;
  7421. return function() {
  7422. return id++;
  7423. };
  7424. })();
  7425. helpers.warn = function(str) {
  7426. //Method for warning of errors
  7427. if (console && typeof console.warn === "function") {
  7428. console.warn(str);
  7429. }
  7430. };
  7431. //-- Math methods
  7432. helpers.isNumber = function(n) {
  7433. return !isNaN(parseFloat(n)) && isFinite(n);
  7434. };
  7435. helpers.almostEquals = function(x, y, epsilon) {
  7436. return Math.abs(x - y) < epsilon;
  7437. };
  7438. helpers.max = function(array) {
  7439. return array.reduce(function(max, value) {
  7440. if (!isNaN(value)) {
  7441. return Math.max(max, value);
  7442. } else {
  7443. return max;
  7444. }
  7445. }, Number.NEGATIVE_INFINITY);
  7446. };
  7447. helpers.min = function(array) {
  7448. return array.reduce(function(min, value) {
  7449. if (!isNaN(value)) {
  7450. return Math.min(min, value);
  7451. } else {
  7452. return min;
  7453. }
  7454. }, Number.POSITIVE_INFINITY);
  7455. };
  7456. helpers.sign = function(x) {
  7457. if (Math.sign) {
  7458. return Math.sign(x);
  7459. } else {
  7460. x = +x; // convert to a number
  7461. if (x === 0 || isNaN(x)) {
  7462. return x;
  7463. }
  7464. return x > 0 ? 1 : -1;
  7465. }
  7466. };
  7467. helpers.log10 = function(x) {
  7468. if (Math.log10) {
  7469. return Math.log10(x);
  7470. } else {
  7471. return Math.log(x) / Math.LN10;
  7472. }
  7473. };
  7474. helpers.toRadians = function(degrees) {
  7475. return degrees * (Math.PI / 180);
  7476. };
  7477. helpers.toDegrees = function(radians) {
  7478. return radians * (180 / Math.PI);
  7479. };
  7480. // Gets the angle from vertical upright to the point about a centre.
  7481. helpers.getAngleFromPoint = function(centrePoint, anglePoint) {
  7482. var distanceFromXCenter = anglePoint.x - centrePoint.x,
  7483. distanceFromYCenter = anglePoint.y - centrePoint.y,
  7484. radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
  7485. var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
  7486. if (angle < (-0.5 * Math.PI)) {
  7487. angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]
  7488. }
  7489. return {
  7490. angle: angle,
  7491. distance: radialDistanceFromCenter
  7492. };
  7493. };
  7494. helpers.aliasPixel = function(pixelWidth) {
  7495. return (pixelWidth % 2 === 0) ? 0 : 0.5;
  7496. };
  7497. helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {
  7498. //Props to Rob Spencer at scaled innovation for his post on splining between points
  7499. //http://scaledinnovation.com/analytics/splines/aboutSplines.html
  7500. // This function must also respect "skipped" points
  7501. var previous = firstPoint.skip ? middlePoint : firstPoint,
  7502. current = middlePoint,
  7503. next = afterPoint.skip ? middlePoint : afterPoint;
  7504. var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));
  7505. var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));
  7506. var s01 = d01 / (d01 + d12);
  7507. var s12 = d12 / (d01 + d12);
  7508. // If all points are the same, s01 & s02 will be inf
  7509. s01 = isNaN(s01) ? 0 : s01;
  7510. s12 = isNaN(s12) ? 0 : s12;
  7511. var fa = t * s01; // scaling factor for triangle Ta
  7512. var fb = t * s12;
  7513. return {
  7514. previous: {
  7515. x: current.x - fa * (next.x - previous.x),
  7516. y: current.y - fa * (next.y - previous.y)
  7517. },
  7518. next: {
  7519. x: current.x + fb * (next.x - previous.x),
  7520. y: current.y + fb * (next.y - previous.y)
  7521. }
  7522. };
  7523. };
  7524. helpers.nextItem = function(collection, index, loop) {
  7525. if (loop) {
  7526. return index >= collection.length - 1 ? collection[0] : collection[index + 1];
  7527. }
  7528. return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];
  7529. };
  7530. helpers.previousItem = function(collection, index, loop) {
  7531. if (loop) {
  7532. return index <= 0 ? collection[collection.length - 1] : collection[index - 1];
  7533. }
  7534. return index <= 0 ? collection[0] : collection[index - 1];
  7535. };
  7536. // Implementation of the nice number algorithm used in determining where axis labels will go
  7537. helpers.niceNum = function(range, round) {
  7538. var exponent = Math.floor(helpers.log10(range));
  7539. var fraction = range / Math.pow(10, exponent);
  7540. var niceFraction;
  7541. if (round) {
  7542. if (fraction < 1.5) {
  7543. niceFraction = 1;
  7544. } else if (fraction < 3) {
  7545. niceFraction = 2;
  7546. } else if (fraction < 7) {
  7547. niceFraction = 5;
  7548. } else {
  7549. niceFraction = 10;
  7550. }
  7551. } else {
  7552. if (fraction <= 1.0) {
  7553. niceFraction = 1;
  7554. } else if (fraction <= 2) {
  7555. niceFraction = 2;
  7556. } else if (fraction <= 5) {
  7557. niceFraction = 5;
  7558. } else {
  7559. niceFraction = 10;
  7560. }
  7561. }
  7562. return niceFraction * Math.pow(10, exponent);
  7563. };
  7564. //Easing functions adapted from Robert Penner's easing equations
  7565. //http://www.robertpenner.com/easing/
  7566. var easingEffects = helpers.easingEffects = {
  7567. linear: function(t) {
  7568. return t;
  7569. },
  7570. easeInQuad: function(t) {
  7571. return t * t;
  7572. },
  7573. easeOutQuad: function(t) {
  7574. return -1 * t * (t - 2);
  7575. },
  7576. easeInOutQuad: function(t) {
  7577. if ((t /= 1 / 2) < 1) {
  7578. return 1 / 2 * t * t;
  7579. }
  7580. return -1 / 2 * ((--t) * (t - 2) - 1);
  7581. },
  7582. easeInCubic: function(t) {
  7583. return t * t * t;
  7584. },
  7585. easeOutCubic: function(t) {
  7586. return 1 * ((t = t / 1 - 1) * t * t + 1);
  7587. },
  7588. easeInOutCubic: function(t) {
  7589. if ((t /= 1 / 2) < 1) {
  7590. return 1 / 2 * t * t * t;
  7591. }
  7592. return 1 / 2 * ((t -= 2) * t * t + 2);
  7593. },
  7594. easeInQuart: function(t) {
  7595. return t * t * t * t;
  7596. },
  7597. easeOutQuart: function(t) {
  7598. return -1 * ((t = t / 1 - 1) * t * t * t - 1);
  7599. },
  7600. easeInOutQuart: function(t) {
  7601. if ((t /= 1 / 2) < 1) {
  7602. return 1 / 2 * t * t * t * t;
  7603. }
  7604. return -1 / 2 * ((t -= 2) * t * t * t - 2);
  7605. },
  7606. easeInQuint: function(t) {
  7607. return 1 * (t /= 1) * t * t * t * t;
  7608. },
  7609. easeOutQuint: function(t) {
  7610. return 1 * ((t = t / 1 - 1) * t * t * t * t + 1);
  7611. },
  7612. easeInOutQuint: function(t) {
  7613. if ((t /= 1 / 2) < 1) {
  7614. return 1 / 2 * t * t * t * t * t;
  7615. }
  7616. return 1 / 2 * ((t -= 2) * t * t * t * t + 2);
  7617. },
  7618. easeInSine: function(t) {
  7619. return -1 * Math.cos(t / 1 * (Math.PI / 2)) + 1;
  7620. },
  7621. easeOutSine: function(t) {
  7622. return 1 * Math.sin(t / 1 * (Math.PI / 2));
  7623. },
  7624. easeInOutSine: function(t) {
  7625. return -1 / 2 * (Math.cos(Math.PI * t / 1) - 1);
  7626. },
  7627. easeInExpo: function(t) {
  7628. return (t === 0) ? 1 : 1 * Math.pow(2, 10 * (t / 1 - 1));
  7629. },
  7630. easeOutExpo: function(t) {
  7631. return (t === 1) ? 1 : 1 * (-Math.pow(2, -10 * t / 1) + 1);
  7632. },
  7633. easeInOutExpo: function(t) {
  7634. if (t === 0) {
  7635. return 0;
  7636. }
  7637. if (t === 1) {
  7638. return 1;
  7639. }
  7640. if ((t /= 1 / 2) < 1) {
  7641. return 1 / 2 * Math.pow(2, 10 * (t - 1));
  7642. }
  7643. return 1 / 2 * (-Math.pow(2, -10 * --t) + 2);
  7644. },
  7645. easeInCirc: function(t) {
  7646. if (t >= 1) {
  7647. return t;
  7648. }
  7649. return -1 * (Math.sqrt(1 - (t /= 1) * t) - 1);
  7650. },
  7651. easeOutCirc: function(t) {
  7652. return 1 * Math.sqrt(1 - (t = t / 1 - 1) * t);
  7653. },
  7654. easeInOutCirc: function(t) {
  7655. if ((t /= 1 / 2) < 1) {
  7656. return -1 / 2 * (Math.sqrt(1 - t * t) - 1);
  7657. }
  7658. return 1 / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1);
  7659. },
  7660. easeInElastic: function(t) {
  7661. var s = 1.70158;
  7662. var p = 0;
  7663. var a = 1;
  7664. if (t === 0) {
  7665. return 0;
  7666. }
  7667. if ((t /= 1) === 1) {
  7668. return 1;
  7669. }
  7670. if (!p) {
  7671. p = 1 * 0.3;
  7672. }
  7673. if (a < Math.abs(1)) {
  7674. a = 1;
  7675. s = p / 4;
  7676. } else {
  7677. s = p / (2 * Math.PI) * Math.asin(1 / a);
  7678. }
  7679. return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
  7680. },
  7681. easeOutElastic: function(t) {
  7682. var s = 1.70158;
  7683. var p = 0;
  7684. var a = 1;
  7685. if (t === 0) {
  7686. return 0;
  7687. }
  7688. if ((t /= 1) === 1) {
  7689. return 1;
  7690. }
  7691. if (!p) {
  7692. p = 1 * 0.3;
  7693. }
  7694. if (a < Math.abs(1)) {
  7695. a = 1;
  7696. s = p / 4;
  7697. } else {
  7698. s = p / (2 * Math.PI) * Math.asin(1 / a);
  7699. }
  7700. return a * Math.pow(2, -10 * t) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) + 1;
  7701. },
  7702. easeInOutElastic: function(t) {
  7703. var s = 1.70158;
  7704. var p = 0;
  7705. var a = 1;
  7706. if (t === 0) {
  7707. return 0;
  7708. }
  7709. if ((t /= 1 / 2) === 2) {
  7710. return 1;
  7711. }
  7712. if (!p) {
  7713. p = 1 * (0.3 * 1.5);
  7714. }
  7715. if (a < Math.abs(1)) {
  7716. a = 1;
  7717. s = p / 4;
  7718. } else {
  7719. s = p / (2 * Math.PI) * Math.asin(1 / a);
  7720. }
  7721. if (t < 1) {
  7722. return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p));
  7723. }
  7724. return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * 1 - s) * (2 * Math.PI) / p) * 0.5 + 1;
  7725. },
  7726. easeInBack: function(t) {
  7727. var s = 1.70158;
  7728. return 1 * (t /= 1) * t * ((s + 1) * t - s);
  7729. },
  7730. easeOutBack: function(t) {
  7731. var s = 1.70158;
  7732. return 1 * ((t = t / 1 - 1) * t * ((s + 1) * t + s) + 1);
  7733. },
  7734. easeInOutBack: function(t) {
  7735. var s = 1.70158;
  7736. if ((t /= 1 / 2) < 1) {
  7737. return 1 / 2 * (t * t * (((s *= (1.525)) + 1) * t - s));
  7738. }
  7739. return 1 / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
  7740. },
  7741. easeInBounce: function(t) {
  7742. return 1 - easingEffects.easeOutBounce(1 - t);
  7743. },
  7744. easeOutBounce: function(t) {
  7745. if ((t /= 1) < (1 / 2.75)) {
  7746. return 1 * (7.5625 * t * t);
  7747. } else if (t < (2 / 2.75)) {
  7748. return 1 * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75);
  7749. } else if (t < (2.5 / 2.75)) {
  7750. return 1 * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375);
  7751. } else {
  7752. return 1 * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375);
  7753. }
  7754. },
  7755. easeInOutBounce: function(t) {
  7756. if (t < 1 / 2) {
  7757. return easingEffects.easeInBounce(t * 2) * 0.5;
  7758. }
  7759. return easingEffects.easeOutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
  7760. }
  7761. };
  7762. //Request animation polyfill - http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
  7763. helpers.requestAnimFrame = (function() {
  7764. return window.requestAnimationFrame ||
  7765. window.webkitRequestAnimationFrame ||
  7766. window.mozRequestAnimationFrame ||
  7767. window.oRequestAnimationFrame ||
  7768. window.msRequestAnimationFrame ||
  7769. function(callback) {
  7770. return window.setTimeout(callback, 1000 / 60);
  7771. };
  7772. })();
  7773. helpers.cancelAnimFrame = (function() {
  7774. return window.cancelAnimationFrame ||
  7775. window.webkitCancelAnimationFrame ||
  7776. window.mozCancelAnimationFrame ||
  7777. window.oCancelAnimationFrame ||
  7778. window.msCancelAnimationFrame ||
  7779. function(callback) {
  7780. return window.clearTimeout(callback, 1000 / 60);
  7781. };
  7782. })();
  7783. //-- DOM methods
  7784. helpers.getRelativePosition = function(evt, chart) {
  7785. var mouseX, mouseY;
  7786. var e = evt.originalEvent || evt,
  7787. canvas = evt.currentTarget || evt.srcElement,
  7788. boundingRect = canvas.getBoundingClientRect();
  7789. var touches = e.touches;
  7790. if (touches && touches.length > 0) {
  7791. mouseX = touches[0].clientX;
  7792. mouseY = touches[0].clientY;
  7793. } else {
  7794. mouseX = e.clientX;
  7795. mouseY = e.clientY;
  7796. }
  7797. // Scale mouse coordinates into canvas coordinates
  7798. // by following the pattern laid out by 'jerryj' in the comments of
  7799. // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/
  7800. var paddingLeft = parseFloat(helpers.getStyle(canvas, 'padding-left'));
  7801. var paddingTop = parseFloat(helpers.getStyle(canvas, 'padding-top'));
  7802. var paddingRight = parseFloat(helpers.getStyle(canvas, 'padding-right'));
  7803. var paddingBottom = parseFloat(helpers.getStyle(canvas, 'padding-bottom'));
  7804. var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;
  7805. var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;
  7806. // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However
  7807. // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here
  7808. mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);
  7809. mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);
  7810. return {
  7811. x: mouseX,
  7812. y: mouseY
  7813. };
  7814. };
  7815. helpers.addEvent = function(node, eventType, method) {
  7816. if (node.addEventListener) {
  7817. node.addEventListener(eventType, method);
  7818. } else if (node.attachEvent) {
  7819. node.attachEvent("on" + eventType, method);
  7820. } else {
  7821. node["on" + eventType] = method;
  7822. }
  7823. };
  7824. helpers.removeEvent = function(node, eventType, handler) {
  7825. if (node.removeEventListener) {
  7826. node.removeEventListener(eventType, handler, false);
  7827. } else if (node.detachEvent) {
  7828. node.detachEvent("on" + eventType, handler);
  7829. } else {
  7830. node["on" + eventType] = helpers.noop;
  7831. }
  7832. };
  7833. helpers.bindEvents = function(chartInstance, arrayOfEvents, handler) {
  7834. // Create the events object if it's not already present
  7835. var events = chartInstance.events = chartInstance.events || {};
  7836. helpers.each(arrayOfEvents, function(eventName) {
  7837. events[eventName] = function() {
  7838. handler.apply(chartInstance, arguments);
  7839. };
  7840. helpers.addEvent(chartInstance.chart.canvas, eventName, events[eventName]);
  7841. });
  7842. };
  7843. helpers.unbindEvents = function(chartInstance, arrayOfEvents) {
  7844. var canvas = chartInstance.chart.canvas;
  7845. helpers.each(arrayOfEvents, function(handler, eventName) {
  7846. helpers.removeEvent(canvas, eventName, handler);
  7847. });
  7848. };
  7849. // Private helper function to convert max-width/max-height values that may be percentages into a number
  7850. function parseMaxStyle(styleValue, node, parentProperty) {
  7851. var valueInPixels;
  7852. if (typeof(styleValue) === 'string') {
  7853. valueInPixels = parseInt(styleValue, 10);
  7854. if (styleValue.indexOf('%') != -1) {
  7855. // percentage * size in dimension
  7856. valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
  7857. }
  7858. } else {
  7859. valueInPixels = styleValue;
  7860. }
  7861. return valueInPixels;
  7862. }
  7863. /**
  7864. * Returns if the given value contains an effective constraint.
  7865. * @private
  7866. */
  7867. function isConstrainedValue(value) {
  7868. return value !== undefined && value !== null && value !== 'none';
  7869. }
  7870. // Private helper to get a constraint dimension
  7871. // @param domNode : the node to check the constraint on
  7872. // @param maxStyle : the style that defines the maximum for the direction we are using (maxWidth / maxHeight)
  7873. // @param percentageProperty : property of parent to use when calculating width as a percentage
  7874. // @see http://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser
  7875. function getConstraintDimension(domNode, maxStyle, percentageProperty) {
  7876. var view = document.defaultView;
  7877. var parentNode = domNode.parentNode;
  7878. var constrainedNode = view.getComputedStyle(domNode)[maxStyle];
  7879. var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];
  7880. var hasCNode = isConstrainedValue(constrainedNode);
  7881. var hasCContainer = isConstrainedValue(constrainedContainer);
  7882. var infinity = Number.POSITIVE_INFINITY;
  7883. if (hasCNode || hasCContainer) {
  7884. return Math.min(
  7885. hasCNode? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,
  7886. hasCContainer? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);
  7887. }
  7888. return 'none';
  7889. }
  7890. // returns Number or undefined if no constraint
  7891. helpers.getConstraintWidth = function(domNode) {
  7892. return getConstraintDimension(domNode, 'max-width', 'clientWidth');
  7893. };
  7894. // returns Number or undefined if no constraint
  7895. helpers.getConstraintHeight = function(domNode) {
  7896. return getConstraintDimension(domNode, 'max-height', 'clientHeight');
  7897. };
  7898. helpers.getMaximumWidth = function(domNode) {
  7899. var container = domNode.parentNode;
  7900. var padding = parseInt(helpers.getStyle(container, 'padding-left')) + parseInt(helpers.getStyle(container, 'padding-right'));
  7901. var w = container.clientWidth - padding;
  7902. var cw = helpers.getConstraintWidth(domNode);
  7903. return isNaN(cw)? w : Math.min(w, cw);
  7904. };
  7905. helpers.getMaximumHeight = function(domNode) {
  7906. var container = domNode.parentNode;
  7907. var padding = parseInt(helpers.getStyle(container, 'padding-top')) + parseInt(helpers.getStyle(container, 'padding-bottom'));
  7908. var h = container.clientHeight - padding;
  7909. var ch = helpers.getConstraintHeight(domNode);
  7910. return isNaN(ch)? h : Math.min(h, ch);
  7911. };
  7912. helpers.getStyle = function(el, property) {
  7913. return el.currentStyle ?
  7914. el.currentStyle[property] :
  7915. document.defaultView.getComputedStyle(el, null).getPropertyValue(property);
  7916. };
  7917. helpers.retinaScale = function(chart) {
  7918. var ctx = chart.ctx;
  7919. var canvas = chart.canvas;
  7920. var width = canvas.width;
  7921. var height = canvas.height;
  7922. var pixelRatio = chart.currentDevicePixelRatio = window.devicePixelRatio || 1;
  7923. if (pixelRatio !== 1) {
  7924. canvas.height = height * pixelRatio;
  7925. canvas.width = width * pixelRatio;
  7926. ctx.scale(pixelRatio, pixelRatio);
  7927. // Store the device pixel ratio so that we can go backwards in `destroy`.
  7928. // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same
  7929. // when destroy is called
  7930. chart.originalDevicePixelRatio = chart.originalDevicePixelRatio || pixelRatio;
  7931. }
  7932. canvas.style.width = width + 'px';
  7933. canvas.style.height = height + 'px';
  7934. };
  7935. //-- Canvas methods
  7936. helpers.clear = function(chart) {
  7937. chart.ctx.clearRect(0, 0, chart.width, chart.height);
  7938. };
  7939. helpers.fontString = function(pixelSize, fontStyle, fontFamily) {
  7940. return fontStyle + " " + pixelSize + "px " + fontFamily;
  7941. };
  7942. helpers.longestText = function(ctx, font, arrayOfStrings, cache) {
  7943. cache = cache || {};
  7944. var data = cache.data = cache.data || {};
  7945. var gc = cache.garbageCollect = cache.garbageCollect || [];
  7946. if (cache.font !== font) {
  7947. data = cache.data = {};
  7948. gc = cache.garbageCollect = [];
  7949. cache.font = font;
  7950. }
  7951. ctx.font = font;
  7952. var longest = 0;
  7953. helpers.each(arrayOfStrings, function(string) {
  7954. // Undefined strings should not be measured
  7955. if (string !== undefined && string !== null) {
  7956. var textWidth = data[string];
  7957. if (!textWidth) {
  7958. textWidth = data[string] = ctx.measureText(string).width;
  7959. gc.push(string);
  7960. }
  7961. if (textWidth > longest) {
  7962. longest = textWidth;
  7963. }
  7964. }
  7965. });
  7966. var gcLen = gc.length / 2;
  7967. if (gcLen > arrayOfStrings.length) {
  7968. for (var i = 0; i < gcLen; i++) {
  7969. delete data[gc[i]];
  7970. }
  7971. gc.splice(0, gcLen);
  7972. }
  7973. return longest;
  7974. };
  7975. helpers.drawRoundedRectangle = function(ctx, x, y, width, height, radius) {
  7976. ctx.beginPath();
  7977. ctx.moveTo(x + radius, y);
  7978. ctx.lineTo(x + width - radius, y);
  7979. ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  7980. ctx.lineTo(x + width, y + height - radius);
  7981. ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  7982. ctx.lineTo(x + radius, y + height);
  7983. ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  7984. ctx.lineTo(x, y + radius);
  7985. ctx.quadraticCurveTo(x, y, x + radius, y);
  7986. ctx.closePath();
  7987. };
  7988. helpers.color = function(c) {
  7989. if (!color) {
  7990. console.log('Color.js not found!');
  7991. return c;
  7992. }
  7993. /* global CanvasGradient */
  7994. if (c instanceof CanvasGradient) {
  7995. return color(Chart.defaults.global.defaultColor);
  7996. }
  7997. return color(c);
  7998. };
  7999. helpers.addResizeListener = function(node, callback) {
  8000. // Hide an iframe before the node
  8001. var hiddenIframe = document.createElement('iframe');
  8002. var hiddenIframeClass = 'chartjs-hidden-iframe';
  8003. if (hiddenIframe.classlist) {
  8004. // can use classlist
  8005. hiddenIframe.classlist.add(hiddenIframeClass);
  8006. } else {
  8007. hiddenIframe.setAttribute('class', hiddenIframeClass);
  8008. }
  8009. // Set the style
  8010. var style = hiddenIframe.style;
  8011. style.width = '100%';
  8012. style.display = 'block';
  8013. style.border = 0;
  8014. style.height = 0;
  8015. style.margin = 0;
  8016. style.position = 'absolute';
  8017. style.left = 0;
  8018. style.right = 0;
  8019. style.top = 0;
  8020. style.bottom = 0;
  8021. // Insert the iframe so that contentWindow is available
  8022. node.insertBefore(hiddenIframe, node.firstChild);
  8023. (hiddenIframe.contentWindow || hiddenIframe).onresize = function() {
  8024. if (callback) {
  8025. callback();
  8026. }
  8027. };
  8028. };
  8029. helpers.removeResizeListener = function(node) {
  8030. var hiddenIframe = node.querySelector('.chartjs-hidden-iframe');
  8031. // Remove the resize detect iframe
  8032. if (hiddenIframe) {
  8033. hiddenIframe.parentNode.removeChild(hiddenIframe);
  8034. }
  8035. };
  8036. helpers.isArray = function(obj) {
  8037. if (!Array.isArray) {
  8038. return Object.prototype.toString.call(obj) === '[object Array]';
  8039. }
  8040. return Array.isArray(obj);
  8041. };
  8042. //! @see http://stackoverflow.com/a/14853974
  8043. helpers.arrayEquals = function(a0, a1) {
  8044. var i, ilen, v0, v1;
  8045. if (!a0 || !a1 || a0.length != a1.length) {
  8046. return false;
  8047. }
  8048. for (i = 0, ilen=a0.length; i < ilen; ++i) {
  8049. v0 = a0[i];
  8050. v1 = a1[i];
  8051. if (v0 instanceof Array && v1 instanceof Array) {
  8052. if (!helpers.arrayEquals(v0, v1)) {
  8053. return false;
  8054. }
  8055. } else if (v0 != v1) {
  8056. // NOTE: two different object instances will never be equal: {x:20} != {x:20}
  8057. return false;
  8058. }
  8059. }
  8060. return true;
  8061. };
  8062. helpers.pushAllIfDefined = function(element, array) {
  8063. if (typeof element === "undefined") {
  8064. return;
  8065. }
  8066. if (helpers.isArray(element)) {
  8067. array.push.apply(array, element);
  8068. } else {
  8069. array.push(element);
  8070. }
  8071. };
  8072. helpers.callCallback = function(fn, args, _tArg) {
  8073. if (fn && typeof fn.call === 'function') {
  8074. fn.apply(_tArg, args);
  8075. }
  8076. };
  8077. helpers.getHoverColor = function(color) {
  8078. /* global CanvasPattern */
  8079. return (color instanceof CanvasPattern) ?
  8080. color :
  8081. helpers.color(color).saturate(0.5).darken(0.1).rgbString();
  8082. };
  8083. };
  8084. },{"chartjs-color":2}],26:[function(require,module,exports){
  8085. "use strict";
  8086. module.exports = function() {
  8087. //Occupy the global variable of Chart, and create a simple base class
  8088. var Chart = function(context, config) {
  8089. this.config = config;
  8090. // Support a jQuery'd canvas element
  8091. if (context.length && context[0].getContext) {
  8092. context = context[0];
  8093. }
  8094. // Support a canvas domnode
  8095. if (context.getContext) {
  8096. context = context.getContext("2d");
  8097. }
  8098. this.ctx = context;
  8099. this.canvas = context.canvas;
  8100. // Figure out what the size of the chart will be.
  8101. // If the canvas has a specified width and height, we use those else
  8102. // we look to see if the canvas node has a CSS width and height.
  8103. // If there is still no height, fill the parent container
  8104. this.width = context.canvas.width || parseInt(Chart.helpers.getStyle(context.canvas, 'width')) || Chart.helpers.getMaximumWidth(context.canvas);
  8105. this.height = context.canvas.height || parseInt(Chart.helpers.getStyle(context.canvas, 'height')) || Chart.helpers.getMaximumHeight(context.canvas);
  8106. this.aspectRatio = this.width / this.height;
  8107. if (isNaN(this.aspectRatio) || isFinite(this.aspectRatio) === false) {
  8108. // If the canvas has no size, try and figure out what the aspect ratio will be.
  8109. // Some charts prefer square canvases (pie, radar, etc). If that is specified, use that
  8110. // else use the canvas default ratio of 2
  8111. this.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2;
  8112. }
  8113. // Store the original style of the element so we can set it back
  8114. this.originalCanvasStyleWidth = context.canvas.style.width;
  8115. this.originalCanvasStyleHeight = context.canvas.style.height;
  8116. // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale.
  8117. Chart.helpers.retinaScale(this);
  8118. if (config) {
  8119. this.controller = new Chart.Controller(this);
  8120. }
  8121. // Always bind this so that if the responsive state changes we still work
  8122. var _this = this;
  8123. Chart.helpers.addResizeListener(context.canvas.parentNode, function() {
  8124. if (_this.controller && _this.controller.config.options.responsive) {
  8125. _this.controller.resize();
  8126. }
  8127. });
  8128. return this.controller ? this.controller : this;
  8129. };
  8130. //Globally expose the defaults to allow for user updating/changing
  8131. Chart.defaults = {
  8132. global: {
  8133. responsive: true,
  8134. responsiveAnimationDuration: 0,
  8135. maintainAspectRatio: true,
  8136. events: ["mousemove", "mouseout", "click", "touchstart", "touchmove"],
  8137. hover: {
  8138. onHover: null,
  8139. mode: 'single',
  8140. animationDuration: 400
  8141. },
  8142. onClick: null,
  8143. defaultColor: 'rgba(0,0,0,0.1)',
  8144. defaultFontColor: '#666',
  8145. defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
  8146. defaultFontSize: 12,
  8147. defaultFontStyle: 'normal',
  8148. showLines: true,
  8149. // Element defaults defined in element extensions
  8150. elements: {},
  8151. // Legend callback string
  8152. legendCallback: function(chart) {
  8153. var text = [];
  8154. text.push('<ul class="' + chart.id + '-legend">');
  8155. for (var i = 0; i < chart.data.datasets.length; i++) {
  8156. text.push('<li><span style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span>');
  8157. if (chart.data.datasets[i].label) {
  8158. text.push(chart.data.datasets[i].label);
  8159. }
  8160. text.push('</li>');
  8161. }
  8162. text.push('</ul>');
  8163. return text.join("");
  8164. }
  8165. }
  8166. };
  8167. return Chart;
  8168. };
  8169. },{}],27:[function(require,module,exports){
  8170. "use strict";
  8171. module.exports = function(Chart) {
  8172. var helpers = Chart.helpers;
  8173. // The layout service is very self explanatory. It's responsible for the layout within a chart.
  8174. // Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need
  8175. // It is this service's responsibility of carrying out that layout.
  8176. Chart.layoutService = {
  8177. defaults: {},
  8178. // Register a box to a chartInstance. A box is simply a reference to an object that requires layout. eg. Scales, Legend, Plugins.
  8179. addBox: function(chartInstance, box) {
  8180. if (!chartInstance.boxes) {
  8181. chartInstance.boxes = [];
  8182. }
  8183. chartInstance.boxes.push(box);
  8184. },
  8185. removeBox: function(chartInstance, box) {
  8186. if (!chartInstance.boxes) {
  8187. return;
  8188. }
  8189. chartInstance.boxes.splice(chartInstance.boxes.indexOf(box), 1);
  8190. },
  8191. // The most important function
  8192. update: function(chartInstance, width, height) {
  8193. if (!chartInstance) {
  8194. return;
  8195. }
  8196. var xPadding = 0;
  8197. var yPadding = 0;
  8198. var leftBoxes = helpers.where(chartInstance.boxes, function(box) {
  8199. return box.options.position === "left";
  8200. });
  8201. var rightBoxes = helpers.where(chartInstance.boxes, function(box) {
  8202. return box.options.position === "right";
  8203. });
  8204. var topBoxes = helpers.where(chartInstance.boxes, function(box) {
  8205. return box.options.position === "top";
  8206. });
  8207. var bottomBoxes = helpers.where(chartInstance.boxes, function(box) {
  8208. return box.options.position === "bottom";
  8209. });
  8210. // Boxes that overlay the chartarea such as the radialLinear scale
  8211. var chartAreaBoxes = helpers.where(chartInstance.boxes, function(box) {
  8212. return box.options.position === "chartArea";
  8213. });
  8214. // Ensure that full width boxes are at the very top / bottom
  8215. topBoxes.sort(function(a, b) {
  8216. return (b.options.fullWidth ? 1 : 0) - (a.options.fullWidth ? 1 : 0);
  8217. });
  8218. bottomBoxes.sort(function(a, b) {
  8219. return (a.options.fullWidth ? 1 : 0) - (b.options.fullWidth ? 1 : 0);
  8220. });
  8221. // Essentially we now have any number of boxes on each of the 4 sides.
  8222. // Our canvas looks like the following.
  8223. // The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and
  8224. // B1 is the bottom axis
  8225. // There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays
  8226. // These locations are single-box locations only, when trying to register a chartArea location that is already taken,
  8227. // an error will be thrown.
  8228. //
  8229. // |----------------------------------------------------|
  8230. // | T1 (Full Width) |
  8231. // |----------------------------------------------------|
  8232. // | | | T2 | |
  8233. // | |----|-------------------------------------|----|
  8234. // | | | C1 | | C2 | |
  8235. // | | |----| |----| |
  8236. // | | | | |
  8237. // | L1 | L2 | ChartArea (C0) | R1 |
  8238. // | | | | |
  8239. // | | |----| |----| |
  8240. // | | | C3 | | C4 | |
  8241. // | |----|-------------------------------------|----|
  8242. // | | | B1 | |
  8243. // |----------------------------------------------------|
  8244. // | B2 (Full Width) |
  8245. // |----------------------------------------------------|
  8246. //
  8247. // What we do to find the best sizing, we do the following
  8248. // 1. Determine the minimum size of the chart area.
  8249. // 2. Split the remaining width equally between each vertical axis
  8250. // 3. Split the remaining height equally between each horizontal axis
  8251. // 4. Give each layout the maximum size it can be. The layout will return it's minimum size
  8252. // 5. Adjust the sizes of each axis based on it's minimum reported size.
  8253. // 6. Refit each axis
  8254. // 7. Position each axis in the final location
  8255. // 8. Tell the chart the final location of the chart area
  8256. // 9. Tell any axes that overlay the chart area the positions of the chart area
  8257. // Step 1
  8258. var chartWidth = width - (2 * xPadding);
  8259. var chartHeight = height - (2 * yPadding);
  8260. var chartAreaWidth = chartWidth / 2; // min 50%
  8261. var chartAreaHeight = chartHeight / 2; // min 50%
  8262. // Step 2
  8263. var verticalBoxWidth = (width - chartAreaWidth) / (leftBoxes.length + rightBoxes.length);
  8264. // Step 3
  8265. var horizontalBoxHeight = (height - chartAreaHeight) / (topBoxes.length + bottomBoxes.length);
  8266. // Step 4
  8267. var maxChartAreaWidth = chartWidth;
  8268. var maxChartAreaHeight = chartHeight;
  8269. var minBoxSizes = [];
  8270. helpers.each(leftBoxes.concat(rightBoxes, topBoxes, bottomBoxes), getMinimumBoxSize);
  8271. function getMinimumBoxSize(box) {
  8272. var minSize;
  8273. var isHorizontal = box.isHorizontal();
  8274. if (isHorizontal) {
  8275. minSize = box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, horizontalBoxHeight);
  8276. maxChartAreaHeight -= minSize.height;
  8277. } else {
  8278. minSize = box.update(verticalBoxWidth, chartAreaHeight);
  8279. maxChartAreaWidth -= minSize.width;
  8280. }
  8281. minBoxSizes.push({
  8282. horizontal: isHorizontal,
  8283. minSize: minSize,
  8284. box: box
  8285. });
  8286. }
  8287. // At this point, maxChartAreaHeight and maxChartAreaWidth are the size the chart area could
  8288. // be if the axes are drawn at their minimum sizes.
  8289. // Steps 5 & 6
  8290. var totalLeftBoxesWidth = xPadding;
  8291. var totalRightBoxesWidth = xPadding;
  8292. var totalTopBoxesHeight = yPadding;
  8293. var totalBottomBoxesHeight = yPadding;
  8294. // Update, and calculate the left and right margins for the horizontal boxes
  8295. helpers.each(leftBoxes.concat(rightBoxes), fitBox);
  8296. helpers.each(leftBoxes, function(box) {
  8297. totalLeftBoxesWidth += box.width;
  8298. });
  8299. helpers.each(rightBoxes, function(box) {
  8300. totalRightBoxesWidth += box.width;
  8301. });
  8302. // Set the Left and Right margins for the horizontal boxes
  8303. helpers.each(topBoxes.concat(bottomBoxes), fitBox);
  8304. // Function to fit a box
  8305. function fitBox(box) {
  8306. var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
  8307. return minBoxSize.box === box;
  8308. });
  8309. if (minBoxSize) {
  8310. if (box.isHorizontal()) {
  8311. var scaleMargin = {
  8312. left: totalLeftBoxesWidth,
  8313. right: totalRightBoxesWidth,
  8314. top: 0,
  8315. bottom: 0
  8316. };
  8317. // Don't use min size here because of label rotation. When the labels are rotated, their rotation highly depends
  8318. // on the margin. Sometimes they need to increase in size slightly
  8319. box.update(box.options.fullWidth ? chartWidth : maxChartAreaWidth, chartHeight / 2, scaleMargin);
  8320. } else {
  8321. box.update(minBoxSize.minSize.width, maxChartAreaHeight);
  8322. }
  8323. }
  8324. }
  8325. // Figure out how much margin is on the top and bottom of the vertical boxes
  8326. helpers.each(topBoxes, function(box) {
  8327. totalTopBoxesHeight += box.height;
  8328. });
  8329. helpers.each(bottomBoxes, function(box) {
  8330. totalBottomBoxesHeight += box.height;
  8331. });
  8332. // Let the left layout know the final margin
  8333. helpers.each(leftBoxes.concat(rightBoxes), finalFitVerticalBox);
  8334. function finalFitVerticalBox(box) {
  8335. var minBoxSize = helpers.findNextWhere(minBoxSizes, function(minBoxSize) {
  8336. return minBoxSize.box === box;
  8337. });
  8338. var scaleMargin = {
  8339. left: 0,
  8340. right: 0,
  8341. top: totalTopBoxesHeight,
  8342. bottom: totalBottomBoxesHeight
  8343. };
  8344. if (minBoxSize) {
  8345. box.update(minBoxSize.minSize.width, maxChartAreaHeight, scaleMargin);
  8346. }
  8347. }
  8348. // Recalculate because the size of each layout might have changed slightly due to the margins (label rotation for instance)
  8349. totalLeftBoxesWidth = xPadding;
  8350. totalRightBoxesWidth = xPadding;
  8351. totalTopBoxesHeight = yPadding;
  8352. totalBottomBoxesHeight = yPadding;
  8353. helpers.each(leftBoxes, function(box) {
  8354. totalLeftBoxesWidth += box.width;
  8355. });
  8356. helpers.each(rightBoxes, function(box) {
  8357. totalRightBoxesWidth += box.width;
  8358. });
  8359. helpers.each(topBoxes, function(box) {
  8360. totalTopBoxesHeight += box.height;
  8361. });
  8362. helpers.each(bottomBoxes, function(box) {
  8363. totalBottomBoxesHeight += box.height;
  8364. });
  8365. // Figure out if our chart area changed. This would occur if the dataset layout label rotation
  8366. // changed due to the application of the margins in step 6. Since we can only get bigger, this is safe to do
  8367. // without calling `fit` again
  8368. var newMaxChartAreaHeight = height - totalTopBoxesHeight - totalBottomBoxesHeight;
  8369. var newMaxChartAreaWidth = width - totalLeftBoxesWidth - totalRightBoxesWidth;
  8370. if (newMaxChartAreaWidth !== maxChartAreaWidth || newMaxChartAreaHeight !== maxChartAreaHeight) {
  8371. helpers.each(leftBoxes, function(box) {
  8372. box.height = newMaxChartAreaHeight;
  8373. });
  8374. helpers.each(rightBoxes, function(box) {
  8375. box.height = newMaxChartAreaHeight;
  8376. });
  8377. helpers.each(topBoxes, function(box) {
  8378. if (!box.options.fullWidth) {
  8379. box.width = newMaxChartAreaWidth;
  8380. }
  8381. });
  8382. helpers.each(bottomBoxes, function(box) {
  8383. if (!box.options.fullWidth) {
  8384. box.width = newMaxChartAreaWidth;
  8385. }
  8386. });
  8387. maxChartAreaHeight = newMaxChartAreaHeight;
  8388. maxChartAreaWidth = newMaxChartAreaWidth;
  8389. }
  8390. // Step 7 - Position the boxes
  8391. var left = xPadding;
  8392. var top = yPadding;
  8393. var right = 0;
  8394. var bottom = 0;
  8395. helpers.each(leftBoxes.concat(topBoxes), placeBox);
  8396. // Account for chart width and height
  8397. left += maxChartAreaWidth;
  8398. top += maxChartAreaHeight;
  8399. helpers.each(rightBoxes, placeBox);
  8400. helpers.each(bottomBoxes, placeBox);
  8401. function placeBox(box) {
  8402. if (box.isHorizontal()) {
  8403. box.left = box.options.fullWidth ? xPadding : totalLeftBoxesWidth;
  8404. box.right = box.options.fullWidth ? width - xPadding : totalLeftBoxesWidth + maxChartAreaWidth;
  8405. box.top = top;
  8406. box.bottom = top + box.height;
  8407. // Move to next point
  8408. top = box.bottom;
  8409. } else {
  8410. box.left = left;
  8411. box.right = left + box.width;
  8412. box.top = totalTopBoxesHeight;
  8413. box.bottom = totalTopBoxesHeight + maxChartAreaHeight;
  8414. // Move to next point
  8415. left = box.right;
  8416. }
  8417. }
  8418. // Step 8
  8419. chartInstance.chartArea = {
  8420. left: totalLeftBoxesWidth,
  8421. top: totalTopBoxesHeight,
  8422. right: totalLeftBoxesWidth + maxChartAreaWidth,
  8423. bottom: totalTopBoxesHeight + maxChartAreaHeight
  8424. };
  8425. // Step 9
  8426. helpers.each(chartAreaBoxes, function(box) {
  8427. box.left = chartInstance.chartArea.left;
  8428. box.top = chartInstance.chartArea.top;
  8429. box.right = chartInstance.chartArea.right;
  8430. box.bottom = chartInstance.chartArea.bottom;
  8431. box.update(maxChartAreaWidth, maxChartAreaHeight);
  8432. });
  8433. }
  8434. };
  8435. };
  8436. },{}],28:[function(require,module,exports){
  8437. "use strict";
  8438. module.exports = function(Chart) {
  8439. var helpers = Chart.helpers;
  8440. var noop = helpers.noop;
  8441. Chart.defaults.global.legend = {
  8442. display: true,
  8443. position: 'top',
  8444. fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
  8445. reverse: false,
  8446. // a callback that will handle
  8447. onClick: function(e, legendItem) {
  8448. var index = legendItem.datasetIndex;
  8449. var ci = this.chart;
  8450. var meta = ci.getDatasetMeta(index);
  8451. // See controller.isDatasetVisible comment
  8452. meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
  8453. // We hid a dataset ... rerender the chart
  8454. ci.update();
  8455. },
  8456. labels: {
  8457. boxWidth: 40,
  8458. padding: 10,
  8459. // Generates labels shown in the legend
  8460. // Valid properties to return:
  8461. // text : text to display
  8462. // fillStyle : fill of coloured box
  8463. // strokeStyle: stroke of coloured box
  8464. // hidden : if this legend item refers to a hidden item
  8465. // lineCap : cap style for line
  8466. // lineDash
  8467. // lineDashOffset :
  8468. // lineJoin :
  8469. // lineWidth :
  8470. generateLabels: function(chart) {
  8471. var data = chart.data;
  8472. return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
  8473. return {
  8474. text: dataset.label,
  8475. fillStyle: dataset.backgroundColor,
  8476. hidden: !chart.isDatasetVisible(i),
  8477. lineCap: dataset.borderCapStyle,
  8478. lineDash: dataset.borderDash,
  8479. lineDashOffset: dataset.borderDashOffset,
  8480. lineJoin: dataset.borderJoinStyle,
  8481. lineWidth: dataset.borderWidth,
  8482. strokeStyle: dataset.borderColor,
  8483. // Below is extra data used for toggling the datasets
  8484. datasetIndex: i
  8485. };
  8486. }, this) : [];
  8487. }
  8488. }
  8489. };
  8490. Chart.Legend = Chart.Element.extend({
  8491. initialize: function(config) {
  8492. helpers.extend(this, config);
  8493. // Contains hit boxes for each dataset (in dataset order)
  8494. this.legendHitBoxes = [];
  8495. // Are we in doughnut mode which has a different data type
  8496. this.doughnutMode = false;
  8497. },
  8498. // These methods are ordered by lifecyle. Utilities then follow.
  8499. // Any function defined here is inherited by all legend types.
  8500. // Any function can be extended by the legend type
  8501. beforeUpdate: noop,
  8502. update: function(maxWidth, maxHeight, margins) {
  8503. // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  8504. this.beforeUpdate();
  8505. // Absorb the master measurements
  8506. this.maxWidth = maxWidth;
  8507. this.maxHeight = maxHeight;
  8508. this.margins = margins;
  8509. // Dimensions
  8510. this.beforeSetDimensions();
  8511. this.setDimensions();
  8512. this.afterSetDimensions();
  8513. // Labels
  8514. this.beforeBuildLabels();
  8515. this.buildLabels();
  8516. this.afterBuildLabels();
  8517. // Fit
  8518. this.beforeFit();
  8519. this.fit();
  8520. this.afterFit();
  8521. //
  8522. this.afterUpdate();
  8523. return this.minSize;
  8524. },
  8525. afterUpdate: noop,
  8526. //
  8527. beforeSetDimensions: noop,
  8528. setDimensions: function() {
  8529. // Set the unconstrained dimension before label rotation
  8530. if (this.isHorizontal()) {
  8531. // Reset position before calculating rotation
  8532. this.width = this.maxWidth;
  8533. this.left = 0;
  8534. this.right = this.width;
  8535. } else {
  8536. this.height = this.maxHeight;
  8537. // Reset position before calculating rotation
  8538. this.top = 0;
  8539. this.bottom = this.height;
  8540. }
  8541. // Reset padding
  8542. this.paddingLeft = 0;
  8543. this.paddingTop = 0;
  8544. this.paddingRight = 0;
  8545. this.paddingBottom = 0;
  8546. // Reset minSize
  8547. this.minSize = {
  8548. width: 0,
  8549. height: 0
  8550. };
  8551. },
  8552. afterSetDimensions: noop,
  8553. //
  8554. beforeBuildLabels: noop,
  8555. buildLabels: function() {
  8556. this.legendItems = this.options.labels.generateLabels.call(this, this.chart);
  8557. if(this.options.reverse){
  8558. this.legendItems.reverse();
  8559. }
  8560. },
  8561. afterBuildLabels: noop,
  8562. //
  8563. beforeFit: noop,
  8564. fit: function() {
  8565. var opts = this.options;
  8566. var labelOpts = opts.labels;
  8567. var display = opts.display;
  8568. var ctx = this.ctx;
  8569. var globalDefault = Chart.defaults.global,
  8570. itemOrDefault = helpers.getValueOrDefault,
  8571. fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
  8572. fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
  8573. fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
  8574. labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
  8575. // Reset hit boxes
  8576. var hitboxes = this.legendHitBoxes = [];
  8577. var minSize = this.minSize;
  8578. var isHorizontal = this.isHorizontal();
  8579. if (isHorizontal) {
  8580. minSize.width = this.maxWidth; // fill all the width
  8581. minSize.height = display ? 10 : 0;
  8582. } else {
  8583. minSize.width = display ? 10 : 0;
  8584. minSize.height = this.maxHeight; // fill all the height
  8585. }
  8586. // Increase sizes here
  8587. if (display) {
  8588. if (isHorizontal) {
  8589. // Labels
  8590. // Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
  8591. var lineWidths = this.lineWidths = [0];
  8592. var totalHeight = this.legendItems.length ? fontSize + (labelOpts.padding) : 0;
  8593. ctx.textAlign = "left";
  8594. ctx.textBaseline = 'top';
  8595. ctx.font = labelFont;
  8596. helpers.each(this.legendItems, function(legendItem, i) {
  8597. var width = labelOpts.boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
  8598. if (lineWidths[lineWidths.length - 1] + width + labelOpts.padding >= this.width) {
  8599. totalHeight += fontSize + (labelOpts.padding);
  8600. lineWidths[lineWidths.length] = this.left;
  8601. }
  8602. // Store the hitbox width and height here. Final position will be updated in `draw`
  8603. hitboxes[i] = {
  8604. left: 0,
  8605. top: 0,
  8606. width: width,
  8607. height: fontSize
  8608. };
  8609. lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
  8610. }, this);
  8611. minSize.height += totalHeight;
  8612. } else {
  8613. // TODO vertical
  8614. }
  8615. }
  8616. this.width = minSize.width;
  8617. this.height = minSize.height;
  8618. },
  8619. afterFit: noop,
  8620. // Shared Methods
  8621. isHorizontal: function() {
  8622. return this.options.position === "top" || this.options.position === "bottom";
  8623. },
  8624. // Actualy draw the legend on the canvas
  8625. draw: function() {
  8626. var opts = this.options;
  8627. var labelOpts = opts.labels;
  8628. var globalDefault = Chart.defaults.global,
  8629. lineDefault = globalDefault.elements.line,
  8630. legendWidth = this.width,
  8631. lineWidths = this.lineWidths;
  8632. if (opts.display) {
  8633. var ctx = this.ctx,
  8634. cursor = {
  8635. x: this.left + ((legendWidth - lineWidths[0]) / 2),
  8636. y: this.top + labelOpts.padding,
  8637. line: 0
  8638. },
  8639. itemOrDefault = helpers.getValueOrDefault,
  8640. fontColor = itemOrDefault(labelOpts.fontColor, globalDefault.defaultFontColor),
  8641. fontSize = itemOrDefault(labelOpts.fontSize, globalDefault.defaultFontSize),
  8642. fontStyle = itemOrDefault(labelOpts.fontStyle, globalDefault.defaultFontStyle),
  8643. fontFamily = itemOrDefault(labelOpts.fontFamily, globalDefault.defaultFontFamily),
  8644. labelFont = helpers.fontString(fontSize, fontStyle, fontFamily);
  8645. // Horizontal
  8646. if (this.isHorizontal()) {
  8647. // Labels
  8648. ctx.textAlign = "left";
  8649. ctx.textBaseline = 'top';
  8650. ctx.lineWidth = 0.5;
  8651. ctx.strokeStyle = fontColor; // for strikethrough effect
  8652. ctx.fillStyle = fontColor; // render in correct colour
  8653. ctx.font = labelFont;
  8654. var boxWidth = labelOpts.boxWidth,
  8655. hitboxes = this.legendHitBoxes;
  8656. helpers.each(this.legendItems, function(legendItem, i) {
  8657. var textWidth = ctx.measureText(legendItem.text).width,
  8658. width = boxWidth + (fontSize / 2) + textWidth,
  8659. x = cursor.x,
  8660. y = cursor.y;
  8661. if (x + width >= legendWidth) {
  8662. y = cursor.y += fontSize + (labelOpts.padding);
  8663. cursor.line++;
  8664. x = cursor.x = this.left + ((legendWidth - lineWidths[cursor.line]) / 2);
  8665. }
  8666. // Set the ctx for the box
  8667. ctx.save();
  8668. ctx.fillStyle = itemOrDefault(legendItem.fillStyle, globalDefault.defaultColor);
  8669. ctx.lineCap = itemOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
  8670. ctx.lineDashOffset = itemOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
  8671. ctx.lineJoin = itemOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
  8672. ctx.lineWidth = itemOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
  8673. ctx.strokeStyle = itemOrDefault(legendItem.strokeStyle, globalDefault.defaultColor);
  8674. if (ctx.setLineDash) {
  8675. // IE 9 and 10 do not support line dash
  8676. ctx.setLineDash(itemOrDefault(legendItem.lineDash, lineDefault.borderDash));
  8677. }
  8678. // Draw the box
  8679. ctx.strokeRect(x, y, boxWidth, fontSize);
  8680. ctx.fillRect(x, y, boxWidth, fontSize);
  8681. ctx.restore();
  8682. hitboxes[i].left = x;
  8683. hitboxes[i].top = y;
  8684. // Fill the actual label
  8685. ctx.fillText(legendItem.text, boxWidth + (fontSize / 2) + x, y);
  8686. if (legendItem.hidden) {
  8687. // Strikethrough the text if hidden
  8688. ctx.beginPath();
  8689. ctx.lineWidth = 2;
  8690. ctx.moveTo(boxWidth + (fontSize / 2) + x, y + (fontSize / 2));
  8691. ctx.lineTo(boxWidth + (fontSize / 2) + x + textWidth, y + (fontSize / 2));
  8692. ctx.stroke();
  8693. }
  8694. cursor.x += width + (labelOpts.padding);
  8695. }, this);
  8696. } else {
  8697. }
  8698. }
  8699. },
  8700. // Handle an event
  8701. handleEvent: function(e) {
  8702. var position = helpers.getRelativePosition(e, this.chart.chart),
  8703. x = position.x,
  8704. y = position.y,
  8705. opts = this.options;
  8706. if (x >= this.left && x <= this.right && y >= this.top && y <= this.bottom) {
  8707. // See if we are touching one of the dataset boxes
  8708. var lh = this.legendHitBoxes;
  8709. for (var i = 0; i < lh.length; ++i) {
  8710. var hitBox = lh[i];
  8711. if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {
  8712. // Touching an element
  8713. if (opts.onClick) {
  8714. opts.onClick.call(this, e, this.legendItems[i]);
  8715. }
  8716. break;
  8717. }
  8718. }
  8719. }
  8720. }
  8721. });
  8722. };
  8723. },{}],29:[function(require,module,exports){
  8724. "use strict";
  8725. module.exports = function(Chart) {
  8726. var helpers = Chart.helpers;
  8727. // Plugins are stored here
  8728. Chart.plugins = [];
  8729. Chart.pluginService = {
  8730. // Register a new plugin
  8731. register: function(plugin) {
  8732. var p = Chart.plugins;
  8733. if (p.indexOf(plugin) === -1) {
  8734. p.push(plugin);
  8735. }
  8736. },
  8737. // Remove a registered plugin
  8738. remove: function(plugin) {
  8739. var p = Chart.plugins;
  8740. var idx = p.indexOf(plugin);
  8741. if (idx !== -1) {
  8742. p.splice(idx, 1);
  8743. }
  8744. },
  8745. // Iterate over all plugins
  8746. notifyPlugins: function(method, args, scope) {
  8747. helpers.each(Chart.plugins, function(plugin) {
  8748. if (plugin[method] && typeof plugin[method] === 'function') {
  8749. plugin[method].apply(scope, args);
  8750. }
  8751. }, scope);
  8752. }
  8753. };
  8754. var noop = helpers.noop;
  8755. Chart.PluginBase = Chart.Element.extend({
  8756. // Plugin methods. All functions are passed the chart instance
  8757. // Called at start of chart init
  8758. beforeInit: noop,
  8759. // Called at end of chart init
  8760. afterInit: noop,
  8761. // Called at start of update
  8762. beforeUpdate: noop,
  8763. // Called at end of update
  8764. afterUpdate: noop,
  8765. // Called at start of draw
  8766. beforeDraw: noop,
  8767. // Called at end of draw
  8768. afterDraw: noop,
  8769. // Called during destroy
  8770. destroy: noop
  8771. });
  8772. };
  8773. },{}],30:[function(require,module,exports){
  8774. "use strict";
  8775. module.exports = function(Chart) {
  8776. var helpers = Chart.helpers;
  8777. Chart.defaults.scale = {
  8778. display: true,
  8779. position: "left",
  8780. // grid line settings
  8781. gridLines: {
  8782. display: true,
  8783. color: "rgba(0, 0, 0, 0.1)",
  8784. lineWidth: 1,
  8785. drawBorder: true,
  8786. drawOnChartArea: true,
  8787. drawTicks: true,
  8788. tickMarkLength: 10,
  8789. zeroLineWidth: 1,
  8790. zeroLineColor: "rgba(0,0,0,0.25)",
  8791. offsetGridLines: false
  8792. },
  8793. // scale label
  8794. scaleLabel: {
  8795. // actual label
  8796. labelString: '',
  8797. // display property
  8798. display: false
  8799. },
  8800. // label settings
  8801. ticks: {
  8802. beginAtZero: false,
  8803. minRotation: 0,
  8804. maxRotation: 50,
  8805. mirror: false,
  8806. padding: 10,
  8807. reverse: false,
  8808. display: true,
  8809. autoSkip: true,
  8810. autoSkipPadding: 0,
  8811. labelOffset: 0,
  8812. callback: function(value) {
  8813. return '' + value;
  8814. }
  8815. }
  8816. };
  8817. Chart.Scale = Chart.Element.extend({
  8818. // These methods are ordered by lifecyle. Utilities then follow.
  8819. // Any function defined here is inherited by all scale types.
  8820. // Any function can be extended by the scale type
  8821. beforeUpdate: function() {
  8822. helpers.callCallback(this.options.beforeUpdate, [this]);
  8823. },
  8824. update: function(maxWidth, maxHeight, margins) {
  8825. // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  8826. this.beforeUpdate();
  8827. // Absorb the master measurements
  8828. this.maxWidth = maxWidth;
  8829. this.maxHeight = maxHeight;
  8830. this.margins = helpers.extend({
  8831. left: 0,
  8832. right: 0,
  8833. top: 0,
  8834. bottom: 0
  8835. }, margins);
  8836. // Dimensions
  8837. this.beforeSetDimensions();
  8838. this.setDimensions();
  8839. this.afterSetDimensions();
  8840. // Data min/max
  8841. this.beforeDataLimits();
  8842. this.determineDataLimits();
  8843. this.afterDataLimits();
  8844. // Ticks
  8845. this.beforeBuildTicks();
  8846. this.buildTicks();
  8847. this.afterBuildTicks();
  8848. this.beforeTickToLabelConversion();
  8849. this.convertTicksToLabels();
  8850. this.afterTickToLabelConversion();
  8851. // Tick Rotation
  8852. this.beforeCalculateTickRotation();
  8853. this.calculateTickRotation();
  8854. this.afterCalculateTickRotation();
  8855. // Fit
  8856. this.beforeFit();
  8857. this.fit();
  8858. this.afterFit();
  8859. //
  8860. this.afterUpdate();
  8861. return this.minSize;
  8862. },
  8863. afterUpdate: function() {
  8864. helpers.callCallback(this.options.afterUpdate, [this]);
  8865. },
  8866. //
  8867. beforeSetDimensions: function() {
  8868. helpers.callCallback(this.options.beforeSetDimensions, [this]);
  8869. },
  8870. setDimensions: function() {
  8871. // Set the unconstrained dimension before label rotation
  8872. if (this.isHorizontal()) {
  8873. // Reset position before calculating rotation
  8874. this.width = this.maxWidth;
  8875. this.left = 0;
  8876. this.right = this.width;
  8877. } else {
  8878. this.height = this.maxHeight;
  8879. // Reset position before calculating rotation
  8880. this.top = 0;
  8881. this.bottom = this.height;
  8882. }
  8883. // Reset padding
  8884. this.paddingLeft = 0;
  8885. this.paddingTop = 0;
  8886. this.paddingRight = 0;
  8887. this.paddingBottom = 0;
  8888. },
  8889. afterSetDimensions: function() {
  8890. helpers.callCallback(this.options.afterSetDimensions, [this]);
  8891. },
  8892. // Data limits
  8893. beforeDataLimits: function() {
  8894. helpers.callCallback(this.options.beforeDataLimits, [this]);
  8895. },
  8896. determineDataLimits: helpers.noop,
  8897. afterDataLimits: function() {
  8898. helpers.callCallback(this.options.afterDataLimits, [this]);
  8899. },
  8900. //
  8901. beforeBuildTicks: function() {
  8902. helpers.callCallback(this.options.beforeBuildTicks, [this]);
  8903. },
  8904. buildTicks: helpers.noop,
  8905. afterBuildTicks: function() {
  8906. helpers.callCallback(this.options.afterBuildTicks, [this]);
  8907. },
  8908. beforeTickToLabelConversion: function() {
  8909. helpers.callCallback(this.options.beforeTickToLabelConversion, [this]);
  8910. },
  8911. convertTicksToLabels: function() {
  8912. // Convert ticks to strings
  8913. this.ticks = this.ticks.map(function(numericalTick, index, ticks) {
  8914. if (this.options.ticks.userCallback) {
  8915. return this.options.ticks.userCallback(numericalTick, index, ticks);
  8916. }
  8917. return this.options.ticks.callback(numericalTick, index, ticks);
  8918. },
  8919. this);
  8920. },
  8921. afterTickToLabelConversion: function() {
  8922. helpers.callCallback(this.options.afterTickToLabelConversion, [this]);
  8923. },
  8924. //
  8925. beforeCalculateTickRotation: function() {
  8926. helpers.callCallback(this.options.beforeCalculateTickRotation, [this]);
  8927. },
  8928. calculateTickRotation: function() {
  8929. var context = this.ctx;
  8930. var globalDefaults = Chart.defaults.global;
  8931. var optionTicks = this.options.ticks;
  8932. //Get the width of each grid by calculating the difference
  8933. //between x offsets between 0 and 1.
  8934. var tickFontSize = helpers.getValueOrDefault(optionTicks.fontSize, globalDefaults.defaultFontSize);
  8935. var tickFontStyle = helpers.getValueOrDefault(optionTicks.fontStyle, globalDefaults.defaultFontStyle);
  8936. var tickFontFamily = helpers.getValueOrDefault(optionTicks.fontFamily, globalDefaults.defaultFontFamily);
  8937. var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  8938. context.font = tickLabelFont;
  8939. var firstWidth = context.measureText(this.ticks[0]).width;
  8940. var lastWidth = context.measureText(this.ticks[this.ticks.length - 1]).width;
  8941. var firstRotated;
  8942. this.labelRotation = optionTicks.minRotation || 0;
  8943. this.paddingRight = 0;
  8944. this.paddingLeft = 0;
  8945. if (this.options.display) {
  8946. if (this.isHorizontal()) {
  8947. this.paddingRight = lastWidth / 2 + 3;
  8948. this.paddingLeft = firstWidth / 2 + 3;
  8949. if (!this.longestTextCache) {
  8950. this.longestTextCache = {};
  8951. }
  8952. var originalLabelWidth = helpers.longestText(context, tickLabelFont, this.ticks, this.longestTextCache);
  8953. var labelWidth = originalLabelWidth;
  8954. var cosRotation;
  8955. var sinRotation;
  8956. // Allow 3 pixels x2 padding either side for label readability
  8957. // only the index matters for a dataset scale, but we want a consistent interface between scales
  8958. var tickWidth = this.getPixelForTick(1) - this.getPixelForTick(0) - 6;
  8959. //Max label rotation can be set or default to 90 - also act as a loop counter
  8960. while (labelWidth > tickWidth && this.labelRotation < optionTicks.maxRotation) {
  8961. cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
  8962. sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
  8963. firstRotated = cosRotation * firstWidth;
  8964. // We're right aligning the text now.
  8965. if (firstRotated + tickFontSize / 2 > this.yLabelWidth) {
  8966. this.paddingLeft = firstRotated + tickFontSize / 2;
  8967. }
  8968. this.paddingRight = tickFontSize / 2;
  8969. if (sinRotation * originalLabelWidth > this.maxHeight) {
  8970. // go back one step
  8971. this.labelRotation--;
  8972. break;
  8973. }
  8974. this.labelRotation++;
  8975. labelWidth = cosRotation * originalLabelWidth;
  8976. }
  8977. }
  8978. }
  8979. if (this.margins) {
  8980. this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0);
  8981. this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0);
  8982. }
  8983. },
  8984. afterCalculateTickRotation: function() {
  8985. helpers.callCallback(this.options.afterCalculateTickRotation, [this]);
  8986. },
  8987. //
  8988. beforeFit: function() {
  8989. helpers.callCallback(this.options.beforeFit, [this]);
  8990. },
  8991. fit: function() {
  8992. // Reset
  8993. var minSize = this.minSize = {
  8994. width: 0,
  8995. height: 0
  8996. };
  8997. var opts = this.options;
  8998. var globalDefaults = Chart.defaults.global;
  8999. var tickOpts = opts.ticks;
  9000. var scaleLabelOpts = opts.scaleLabel;
  9001. var display = opts.display;
  9002. var isHorizontal = this.isHorizontal();
  9003. var tickFontSize = helpers.getValueOrDefault(tickOpts.fontSize, globalDefaults.defaultFontSize);
  9004. var tickFontStyle = helpers.getValueOrDefault(tickOpts.fontStyle, globalDefaults.defaultFontStyle);
  9005. var tickFontFamily = helpers.getValueOrDefault(tickOpts.fontFamily, globalDefaults.defaultFontFamily);
  9006. var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  9007. var scaleLabelFontSize = helpers.getValueOrDefault(scaleLabelOpts.fontSize, globalDefaults.defaultFontSize);
  9008. var scaleLabelFontStyle = helpers.getValueOrDefault(scaleLabelOpts.fontStyle, globalDefaults.defaultFontStyle);
  9009. var scaleLabelFontFamily = helpers.getValueOrDefault(scaleLabelOpts.fontFamily, globalDefaults.defaultFontFamily);
  9010. var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
  9011. var tickMarkLength = opts.gridLines.tickMarkLength;
  9012. // Width
  9013. if (isHorizontal) {
  9014. // subtract the margins to line up with the chartArea if we are a full width scale
  9015. minSize.width = this.isFullWidth() ? this.maxWidth - this.margins.left - this.margins.right : this.maxWidth;
  9016. } else {
  9017. minSize.width = display ? tickMarkLength : 0;
  9018. }
  9019. // height
  9020. if (isHorizontal) {
  9021. minSize.height = display ? tickMarkLength : 0;
  9022. } else {
  9023. minSize.height = this.maxHeight; // fill all the height
  9024. }
  9025. // Are we showing a title for the scale?
  9026. if (scaleLabelOpts.display && display) {
  9027. if (isHorizontal) {
  9028. minSize.height += (scaleLabelFontSize * 1.5);
  9029. } else {
  9030. minSize.width += (scaleLabelFontSize * 1.5);
  9031. }
  9032. }
  9033. if (tickOpts.display && display) {
  9034. // Don't bother fitting the ticks if we are not showing them
  9035. if (!this.longestTextCache) {
  9036. this.longestTextCache = {};
  9037. }
  9038. var largestTextWidth = helpers.longestText(this.ctx, tickLabelFont, this.ticks, this.longestTextCache);
  9039. if (isHorizontal) {
  9040. // A horizontal axis is more constrained by the height.
  9041. this.longestLabelWidth = largestTextWidth;
  9042. // TODO - improve this calculation
  9043. var labelHeight = (Math.sin(helpers.toRadians(this.labelRotation)) * this.longestLabelWidth) + 1.5 * tickFontSize;
  9044. minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight);
  9045. this.ctx.font = tickLabelFont;
  9046. var firstLabelWidth = this.ctx.measureText(this.ticks[0]).width;
  9047. var lastLabelWidth = this.ctx.measureText(this.ticks[this.ticks.length - 1]).width;
  9048. // Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned which means that the right padding is dominated
  9049. // by the font height
  9050. var cosRotation = Math.cos(helpers.toRadians(this.labelRotation));
  9051. var sinRotation = Math.sin(helpers.toRadians(this.labelRotation));
  9052. this.paddingLeft = this.labelRotation !== 0 ? (cosRotation * firstLabelWidth) + 3 : firstLabelWidth / 2 + 3; // add 3 px to move away from canvas edges
  9053. this.paddingRight = this.labelRotation !== 0 ? (sinRotation * (tickFontSize / 2)) + 3 : lastLabelWidth / 2 + 3; // when rotated
  9054. } else {
  9055. // A vertical axis is more constrained by the width. Labels are the dominant factor here, so get that length first
  9056. var maxLabelWidth = this.maxWidth - minSize.width;
  9057. // Account for padding
  9058. var mirror = tickOpts.mirror;
  9059. if (!mirror) {
  9060. largestTextWidth += this.options.ticks.padding;
  9061. } else {
  9062. // If mirrored text is on the inside so don't expand
  9063. largestTextWidth = 0;
  9064. }
  9065. if (largestTextWidth < maxLabelWidth) {
  9066. // We don't need all the room
  9067. minSize.width += largestTextWidth;
  9068. } else {
  9069. // Expand to max size
  9070. minSize.width = this.maxWidth;
  9071. }
  9072. this.paddingTop = tickFontSize / 2;
  9073. this.paddingBottom = tickFontSize / 2;
  9074. }
  9075. }
  9076. if (this.margins) {
  9077. this.paddingLeft = Math.max(this.paddingLeft - this.margins.left, 0);
  9078. this.paddingTop = Math.max(this.paddingTop - this.margins.top, 0);
  9079. this.paddingRight = Math.max(this.paddingRight - this.margins.right, 0);
  9080. this.paddingBottom = Math.max(this.paddingBottom - this.margins.bottom, 0);
  9081. }
  9082. this.width = minSize.width;
  9083. this.height = minSize.height;
  9084. },
  9085. afterFit: function() {
  9086. helpers.callCallback(this.options.afterFit, [this]);
  9087. },
  9088. // Shared Methods
  9089. isHorizontal: function() {
  9090. return this.options.position === "top" || this.options.position === "bottom";
  9091. },
  9092. isFullWidth: function() {
  9093. return (this.options.fullWidth);
  9094. },
  9095. // Get the correct value. NaN bad inputs, If the value type is object get the x or y based on whether we are horizontal or not
  9096. getRightValue: function getRightValue(rawValue) {
  9097. // Null and undefined values first
  9098. if (rawValue === null || typeof(rawValue) === 'undefined') {
  9099. return NaN;
  9100. }
  9101. // isNaN(object) returns true, so make sure NaN is checking for a number
  9102. if (typeof(rawValue) === 'number' && isNaN(rawValue)) {
  9103. return NaN;
  9104. }
  9105. // If it is in fact an object, dive in one more level
  9106. if (typeof(rawValue) === "object") {
  9107. if ((rawValue instanceof Date) || (rawValue.isValid)) {
  9108. return rawValue;
  9109. } else {
  9110. return getRightValue(this.isHorizontal() ? rawValue.x : rawValue.y);
  9111. }
  9112. }
  9113. // Value is good, return it
  9114. return rawValue;
  9115. },
  9116. // Used to get the value to display in the tooltip for the data at the given index
  9117. // function getLabelForIndex(index, datasetIndex)
  9118. getLabelForIndex: helpers.noop,
  9119. // Used to get data value locations. Value can either be an index or a numerical value
  9120. getPixelForValue: helpers.noop,
  9121. // Used to get the data value from a given pixel. This is the inverse of getPixelForValue
  9122. getValueForPixel: helpers.noop,
  9123. // Used for tick location, should
  9124. getPixelForTick: function(index, includeOffset) {
  9125. if (this.isHorizontal()) {
  9126. var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
  9127. var tickWidth = innerWidth / Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
  9128. var pixel = (tickWidth * index) + this.paddingLeft;
  9129. if (includeOffset) {
  9130. pixel += tickWidth / 2;
  9131. }
  9132. var finalVal = this.left + Math.round(pixel);
  9133. finalVal += this.isFullWidth() ? this.margins.left : 0;
  9134. return finalVal;
  9135. } else {
  9136. var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
  9137. return this.top + (index * (innerHeight / (this.ticks.length - 1)));
  9138. }
  9139. },
  9140. // Utility for getting the pixel location of a percentage of scale
  9141. getPixelForDecimal: function(decimal /*, includeOffset*/ ) {
  9142. if (this.isHorizontal()) {
  9143. var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
  9144. var valueOffset = (innerWidth * decimal) + this.paddingLeft;
  9145. var finalVal = this.left + Math.round(valueOffset);
  9146. finalVal += this.isFullWidth() ? this.margins.left : 0;
  9147. return finalVal;
  9148. } else {
  9149. return this.top + (decimal * this.height);
  9150. }
  9151. },
  9152. getBasePixel: function() {
  9153. var me = this;
  9154. var min = me.min;
  9155. var max = me.max;
  9156. return me.getPixelForValue(
  9157. me.beginAtZero? 0:
  9158. min < 0 && max < 0? max :
  9159. min > 0 && max > 0? min :
  9160. 0);
  9161. },
  9162. // Actualy draw the scale on the canvas
  9163. // @param {rectangle} chartArea : the area of the chart to draw full grid lines on
  9164. draw: function(chartArea) {
  9165. var options = this.options;
  9166. if (!options.display) {
  9167. return;
  9168. }
  9169. var context = this.ctx;
  9170. var globalDefaults = Chart.defaults.global;
  9171. var optionTicks = options.ticks;
  9172. var gridLines = options.gridLines;
  9173. var scaleLabel = options.scaleLabel;
  9174. var setContextLineSettings;
  9175. var isRotated = this.labelRotation !== 0;
  9176. var skipRatio;
  9177. var scaleLabelX;
  9178. var scaleLabelY;
  9179. var useAutoskipper = optionTicks.autoSkip;
  9180. // figure out the maximum number of gridlines to show
  9181. var maxTicks;
  9182. if (optionTicks.maxTicksLimit) {
  9183. maxTicks = optionTicks.maxTicksLimit;
  9184. }
  9185. var tickFontColor = helpers.getValueOrDefault(optionTicks.fontColor, globalDefaults.defaultFontColor);
  9186. var tickFontSize = helpers.getValueOrDefault(optionTicks.fontSize, globalDefaults.defaultFontSize);
  9187. var tickFontStyle = helpers.getValueOrDefault(optionTicks.fontStyle, globalDefaults.defaultFontStyle);
  9188. var tickFontFamily = helpers.getValueOrDefault(optionTicks.fontFamily, globalDefaults.defaultFontFamily);
  9189. var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  9190. var tl = gridLines.tickMarkLength;
  9191. var scaleLabelFontColor = helpers.getValueOrDefault(scaleLabel.fontColor, globalDefaults.defaultFontColor);
  9192. var scaleLabelFontSize = helpers.getValueOrDefault(scaleLabel.fontSize, globalDefaults.defaultFontSize);
  9193. var scaleLabelFontStyle = helpers.getValueOrDefault(scaleLabel.fontStyle, globalDefaults.defaultFontStyle);
  9194. var scaleLabelFontFamily = helpers.getValueOrDefault(scaleLabel.fontFamily, globalDefaults.defaultFontFamily);
  9195. var scaleLabelFont = helpers.fontString(scaleLabelFontSize, scaleLabelFontStyle, scaleLabelFontFamily);
  9196. var labelRotationRadians = helpers.toRadians(this.labelRotation);
  9197. var cosRotation = Math.cos(labelRotationRadians);
  9198. var sinRotation = Math.sin(labelRotationRadians);
  9199. var longestRotatedLabel = this.longestLabelWidth * cosRotation;
  9200. var rotatedLabelHeight = tickFontSize * sinRotation;
  9201. // Make sure we draw text in the correct color and font
  9202. context.fillStyle = tickFontColor;
  9203. if (this.isHorizontal()) {
  9204. setContextLineSettings = true;
  9205. var yTickStart = options.position === "bottom" ? this.top : this.bottom - tl;
  9206. var yTickEnd = options.position === "bottom" ? this.top + tl : this.bottom;
  9207. skipRatio = false;
  9208. // Only calculate the skip ratio with the half width of longestRotateLabel if we got an actual rotation
  9209. // See #2584
  9210. if (isRotated) {
  9211. longestRotatedLabel /= 2;
  9212. }
  9213. if ((longestRotatedLabel + optionTicks.autoSkipPadding) * this.ticks.length > (this.width - (this.paddingLeft + this.paddingRight))) {
  9214. skipRatio = 1 + Math.floor(((longestRotatedLabel + optionTicks.autoSkipPadding) * this.ticks.length) / (this.width - (this.paddingLeft + this.paddingRight)));
  9215. }
  9216. // if they defined a max number of optionTicks,
  9217. // increase skipRatio until that number is met
  9218. if (maxTicks && this.ticks.length > maxTicks) {
  9219. while (!skipRatio || this.ticks.length / (skipRatio || 1) > maxTicks) {
  9220. if (!skipRatio) {
  9221. skipRatio = 1;
  9222. }
  9223. skipRatio += 1;
  9224. }
  9225. }
  9226. if (!useAutoskipper) {
  9227. skipRatio = false;
  9228. }
  9229. helpers.each(this.ticks, function (label, index) {
  9230. // Blank optionTicks
  9231. var isLastTick = this.ticks.length === index + 1;
  9232. // Since we always show the last tick,we need may need to hide the last shown one before
  9233. var shouldSkip = (skipRatio > 1 && index % skipRatio > 0) || (index % skipRatio === 0 && index + skipRatio >= this.ticks.length);
  9234. if (shouldSkip && !isLastTick || (label === undefined || label === null)) {
  9235. return;
  9236. }
  9237. var xLineValue = this.getPixelForTick(index); // xvalues for grid lines
  9238. var xLabelValue = this.getPixelForTick(index, gridLines.offsetGridLines); // x values for optionTicks (need to consider offsetLabel option)
  9239. if (gridLines.display) {
  9240. if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) {
  9241. // Draw the first index specially
  9242. context.lineWidth = gridLines.zeroLineWidth;
  9243. context.strokeStyle = gridLines.zeroLineColor;
  9244. setContextLineSettings = true; // reset next time
  9245. } else if (setContextLineSettings) {
  9246. context.lineWidth = gridLines.lineWidth;
  9247. context.strokeStyle = gridLines.color;
  9248. setContextLineSettings = false;
  9249. }
  9250. xLineValue += helpers.aliasPixel(context.lineWidth);
  9251. // Draw the label area
  9252. context.beginPath();
  9253. if (gridLines.drawTicks) {
  9254. context.moveTo(xLineValue, yTickStart);
  9255. context.lineTo(xLineValue, yTickEnd);
  9256. }
  9257. // Draw the chart area
  9258. if (gridLines.drawOnChartArea) {
  9259. context.moveTo(xLineValue, chartArea.top);
  9260. context.lineTo(xLineValue, chartArea.bottom);
  9261. }
  9262. // Need to stroke in the loop because we are potentially changing line widths & colours
  9263. context.stroke();
  9264. }
  9265. if (optionTicks.display) {
  9266. context.save();
  9267. context.translate(xLabelValue + optionTicks.labelOffset, (isRotated) ? this.top + 12 : options.position === "top" ? this.bottom - tl : this.top + tl);
  9268. context.rotate(labelRotationRadians * -1);
  9269. context.font = tickLabelFont;
  9270. context.textAlign = (isRotated) ? "right" : "center";
  9271. context.textBaseline = (isRotated) ? "middle" : options.position === "top" ? "bottom" : "top";
  9272. context.fillText(label, 0, 0);
  9273. context.restore();
  9274. }
  9275. }, this);
  9276. if (scaleLabel.display) {
  9277. // Draw the scale label
  9278. context.textAlign = "center";
  9279. context.textBaseline = 'middle';
  9280. context.fillStyle = scaleLabelFontColor; // render in correct colour
  9281. context.font = scaleLabelFont;
  9282. scaleLabelX = this.left + ((this.right - this.left) / 2); // midpoint of the width
  9283. scaleLabelY = options.position === 'bottom' ? this.bottom - (scaleLabelFontSize / 2) : this.top + (scaleLabelFontSize / 2);
  9284. context.fillText(scaleLabel.labelString, scaleLabelX, scaleLabelY);
  9285. }
  9286. } else {
  9287. setContextLineSettings = true;
  9288. var xTickStart = options.position === "right" ? this.left : this.right - 5;
  9289. var xTickEnd = options.position === "right" ? this.left + 5 : this.right;
  9290. helpers.each(this.ticks, function (label, index) {
  9291. // If the callback returned a null or undefined value, do not draw this line
  9292. if (label === undefined || label === null) {
  9293. return;
  9294. }
  9295. var yLineValue = this.getPixelForTick(index); // xvalues for grid lines
  9296. if (gridLines.display) {
  9297. if (index === (typeof this.zeroLineIndex !== 'undefined' ? this.zeroLineIndex : 0)) {
  9298. // Draw the first index specially
  9299. context.lineWidth = gridLines.zeroLineWidth;
  9300. context.strokeStyle = gridLines.zeroLineColor;
  9301. setContextLineSettings = true; // reset next time
  9302. } else if (setContextLineSettings) {
  9303. context.lineWidth = gridLines.lineWidth;
  9304. context.strokeStyle = gridLines.color;
  9305. setContextLineSettings = false;
  9306. }
  9307. yLineValue += helpers.aliasPixel(context.lineWidth);
  9308. // Draw the label area
  9309. context.beginPath();
  9310. if (gridLines.drawTicks) {
  9311. context.moveTo(xTickStart, yLineValue);
  9312. context.lineTo(xTickEnd, yLineValue);
  9313. }
  9314. // Draw the chart area
  9315. if (gridLines.drawOnChartArea) {
  9316. context.moveTo(chartArea.left, yLineValue);
  9317. context.lineTo(chartArea.right, yLineValue);
  9318. }
  9319. // Need to stroke in the loop because we are potentially changing line widths & colours
  9320. context.stroke();
  9321. }
  9322. if (optionTicks.display) {
  9323. var xLabelValue;
  9324. var yLabelValue = this.getPixelForTick(index, gridLines.offsetGridLines); // x values for optionTicks (need to consider offsetLabel option)
  9325. context.save();
  9326. if (options.position === "left") {
  9327. if (optionTicks.mirror) {
  9328. xLabelValue = this.right + optionTicks.padding;
  9329. context.textAlign = "left";
  9330. } else {
  9331. xLabelValue = this.right - optionTicks.padding;
  9332. context.textAlign = "right";
  9333. }
  9334. } else {
  9335. // right side
  9336. if (optionTicks.mirror) {
  9337. xLabelValue = this.left - optionTicks.padding;
  9338. context.textAlign = "right";
  9339. } else {
  9340. xLabelValue = this.left + optionTicks.padding;
  9341. context.textAlign = "left";
  9342. }
  9343. }
  9344. context.translate(xLabelValue, yLabelValue + optionTicks.labelOffset);
  9345. context.rotate(labelRotationRadians * -1);
  9346. context.font = tickLabelFont;
  9347. context.textBaseline = "middle";
  9348. context.fillText(label, 0, 0);
  9349. context.restore();
  9350. }
  9351. }, this);
  9352. if (scaleLabel.display) {
  9353. // Draw the scale label
  9354. scaleLabelX = options.position === 'left' ? this.left + (scaleLabelFontSize / 2) : this.right - (scaleLabelFontSize / 2);
  9355. scaleLabelY = this.top + ((this.bottom - this.top) / 2);
  9356. var rotation = options.position === 'left' ? -0.5 * Math.PI : 0.5 * Math.PI;
  9357. context.save();
  9358. context.translate(scaleLabelX, scaleLabelY);
  9359. context.rotate(rotation);
  9360. context.textAlign = "center";
  9361. context.fillStyle = scaleLabelFontColor; // render in correct colour
  9362. context.font = scaleLabelFont;
  9363. context.textBaseline = 'middle';
  9364. context.fillText(scaleLabel.labelString, 0, 0);
  9365. context.restore();
  9366. }
  9367. }
  9368. if (gridLines.drawBorder) {
  9369. // Draw the line at the edge of the axis
  9370. context.lineWidth = gridLines.lineWidth;
  9371. context.strokeStyle = gridLines.color;
  9372. var x1 = this.left,
  9373. x2 = this.right,
  9374. y1 = this.top,
  9375. y2 = this.bottom;
  9376. var aliasPixel = helpers.aliasPixel(context.lineWidth);
  9377. if (this.isHorizontal()) {
  9378. y1 = y2 = options.position === 'top' ? this.bottom : this.top;
  9379. y1 += aliasPixel;
  9380. y2 += aliasPixel;
  9381. } else {
  9382. x1 = x2 = options.position === 'left' ? this.right : this.left;
  9383. x1 += aliasPixel;
  9384. x2 += aliasPixel;
  9385. }
  9386. context.beginPath();
  9387. context.moveTo(x1, y1);
  9388. context.lineTo(x2, y2);
  9389. context.stroke();
  9390. }
  9391. }
  9392. });
  9393. };
  9394. },{}],31:[function(require,module,exports){
  9395. "use strict";
  9396. module.exports = function(Chart) {
  9397. var helpers = Chart.helpers;
  9398. Chart.scaleService = {
  9399. // Scale registration object. Extensions can register new scale types (such as log or DB scales) and then
  9400. // use the new chart options to grab the correct scale
  9401. constructors: {},
  9402. // Use a registration function so that we can move to an ES6 map when we no longer need to support
  9403. // old browsers
  9404. // Scale config defaults
  9405. defaults: {},
  9406. registerScaleType: function(type, scaleConstructor, defaults) {
  9407. this.constructors[type] = scaleConstructor;
  9408. this.defaults[type] = helpers.clone(defaults);
  9409. },
  9410. getScaleConstructor: function(type) {
  9411. return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;
  9412. },
  9413. getScaleDefaults: function(type) {
  9414. // Return the scale defaults merged with the global settings so that we always use the latest ones
  9415. return this.defaults.hasOwnProperty(type) ? helpers.scaleMerge(Chart.defaults.scale, this.defaults[type]) : {};
  9416. },
  9417. updateScaleDefaults: function(type, additions) {
  9418. var defaults = this.defaults;
  9419. if (defaults.hasOwnProperty(type)) {
  9420. defaults[type] = helpers.extend(defaults[type], additions);
  9421. }
  9422. },
  9423. addScalesToLayout: function(chartInstance) {
  9424. // Adds each scale to the chart.boxes array to be sized accordingly
  9425. helpers.each(chartInstance.scales, function(scale) {
  9426. Chart.layoutService.addBox(chartInstance, scale);
  9427. });
  9428. }
  9429. };
  9430. };
  9431. },{}],32:[function(require,module,exports){
  9432. "use strict";
  9433. module.exports = function(Chart) {
  9434. var helpers = Chart.helpers;
  9435. Chart.defaults.global.title = {
  9436. display: false,
  9437. position: 'top',
  9438. fullWidth: true, // marks that this box should take the full width of the canvas (pushing down other boxes)
  9439. fontStyle: 'bold',
  9440. padding: 10,
  9441. // actual title
  9442. text: ''
  9443. };
  9444. var noop = helpers.noop;
  9445. Chart.Title = Chart.Element.extend({
  9446. initialize: function(config) {
  9447. helpers.extend(this, config);
  9448. this.options = helpers.configMerge(Chart.defaults.global.title, config.options);
  9449. // Contains hit boxes for each dataset (in dataset order)
  9450. this.legendHitBoxes = [];
  9451. },
  9452. // These methods are ordered by lifecyle. Utilities then follow.
  9453. beforeUpdate: noop,
  9454. update: function(maxWidth, maxHeight, margins) {
  9455. // Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)
  9456. this.beforeUpdate();
  9457. // Absorb the master measurements
  9458. this.maxWidth = maxWidth;
  9459. this.maxHeight = maxHeight;
  9460. this.margins = margins;
  9461. // Dimensions
  9462. this.beforeSetDimensions();
  9463. this.setDimensions();
  9464. this.afterSetDimensions();
  9465. // Labels
  9466. this.beforeBuildLabels();
  9467. this.buildLabels();
  9468. this.afterBuildLabels();
  9469. // Fit
  9470. this.beforeFit();
  9471. this.fit();
  9472. this.afterFit();
  9473. //
  9474. this.afterUpdate();
  9475. return this.minSize;
  9476. },
  9477. afterUpdate: noop,
  9478. //
  9479. beforeSetDimensions: noop,
  9480. setDimensions: function() {
  9481. // Set the unconstrained dimension before label rotation
  9482. if (this.isHorizontal()) {
  9483. // Reset position before calculating rotation
  9484. this.width = this.maxWidth;
  9485. this.left = 0;
  9486. this.right = this.width;
  9487. } else {
  9488. this.height = this.maxHeight;
  9489. // Reset position before calculating rotation
  9490. this.top = 0;
  9491. this.bottom = this.height;
  9492. }
  9493. // Reset padding
  9494. this.paddingLeft = 0;
  9495. this.paddingTop = 0;
  9496. this.paddingRight = 0;
  9497. this.paddingBottom = 0;
  9498. // Reset minSize
  9499. this.minSize = {
  9500. width: 0,
  9501. height: 0
  9502. };
  9503. },
  9504. afterSetDimensions: noop,
  9505. //
  9506. beforeBuildLabels: noop,
  9507. buildLabels: noop,
  9508. afterBuildLabels: noop,
  9509. //
  9510. beforeFit: noop,
  9511. fit: function() {
  9512. var _this = this,
  9513. ctx = _this.ctx,
  9514. valueOrDefault = helpers.getValueOrDefault,
  9515. opts = _this.options,
  9516. globalDefaults = Chart.defaults.global,
  9517. display = opts.display,
  9518. fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
  9519. minSize = _this.minSize;
  9520. if (_this.isHorizontal()) {
  9521. minSize.width = _this.maxWidth; // fill all the width
  9522. minSize.height = display ? fontSize + (opts.padding * 2) : 0;
  9523. } else {
  9524. minSize.width = display ? fontSize + (opts.padding * 2) : 0;
  9525. minSize.height = _this.maxHeight; // fill all the height
  9526. }
  9527. _this.width = minSize.width;
  9528. _this.height = minSize.height;
  9529. },
  9530. afterFit: noop,
  9531. // Shared Methods
  9532. isHorizontal: function() {
  9533. var pos = this.options.position;
  9534. return pos === "top" || pos === "bottom";
  9535. },
  9536. // Actualy draw the title block on the canvas
  9537. draw: function() {
  9538. var _this = this,
  9539. ctx = _this.ctx,
  9540. valueOrDefault = helpers.getValueOrDefault,
  9541. opts = _this.options,
  9542. globalDefaults = Chart.defaults.global;
  9543. if (opts.display) {
  9544. var fontSize = valueOrDefault(opts.fontSize, globalDefaults.defaultFontSize),
  9545. fontStyle = valueOrDefault(opts.fontStyle, globalDefaults.defaultFontStyle),
  9546. fontFamily = valueOrDefault(opts.fontFamily, globalDefaults.defaultFontFamily),
  9547. titleFont = helpers.fontString(fontSize, fontStyle, fontFamily),
  9548. rotation = 0,
  9549. titleX,
  9550. titleY,
  9551. top = _this.top,
  9552. left = _this.left,
  9553. bottom = _this.bottom,
  9554. right = _this.right;
  9555. ctx.fillStyle = valueOrDefault(opts.fontColor, globalDefaults.defaultFontColor); // render in correct colour
  9556. ctx.font = titleFont;
  9557. // Horizontal
  9558. if (_this.isHorizontal()) {
  9559. titleX = left + ((right - left) / 2); // midpoint of the width
  9560. titleY = top + ((bottom - top) / 2); // midpoint of the height
  9561. } else {
  9562. titleX = opts.position === 'left' ? left + (fontSize / 2) : right - (fontSize / 2);
  9563. titleY = top + ((bottom - top) / 2);
  9564. rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);
  9565. }
  9566. ctx.save();
  9567. ctx.translate(titleX, titleY);
  9568. ctx.rotate(rotation);
  9569. ctx.textAlign = 'center';
  9570. ctx.textBaseline = 'middle';
  9571. ctx.fillText(opts.text, 0, 0);
  9572. ctx.restore();
  9573. }
  9574. }
  9575. });
  9576. };
  9577. },{}],33:[function(require,module,exports){
  9578. "use strict";
  9579. module.exports = function(Chart) {
  9580. var helpers = Chart.helpers;
  9581. Chart.defaults.global.tooltips = {
  9582. enabled: true,
  9583. custom: null,
  9584. mode: 'single',
  9585. backgroundColor: "rgba(0,0,0,0.8)",
  9586. titleFontStyle: "bold",
  9587. titleSpacing: 2,
  9588. titleMarginBottom: 6,
  9589. titleColor: "#fff",
  9590. titleAlign: "left",
  9591. bodySpacing: 2,
  9592. bodyColor: "#fff",
  9593. bodyAlign: "left",
  9594. footerFontStyle: "bold",
  9595. footerSpacing: 2,
  9596. footerMarginTop: 6,
  9597. footerColor: "#fff",
  9598. footerAlign: "left",
  9599. yPadding: 6,
  9600. xPadding: 6,
  9601. yAlign : 'center',
  9602. xAlign : 'center',
  9603. caretSize: 5,
  9604. cornerRadius: 6,
  9605. multiKeyBackground: '#fff',
  9606. callbacks: {
  9607. // Args are: (tooltipItems, data)
  9608. beforeTitle: helpers.noop,
  9609. title: function(tooltipItems, data) {
  9610. // Pick first xLabel for now
  9611. var title = '';
  9612. if (tooltipItems.length > 0) {
  9613. if (tooltipItems[0].xLabel) {
  9614. title = tooltipItems[0].xLabel;
  9615. } else if (data.labels.length > 0 && tooltipItems[0].index < data.labels.length) {
  9616. title = data.labels[tooltipItems[0].index];
  9617. }
  9618. }
  9619. return title;
  9620. },
  9621. afterTitle: helpers.noop,
  9622. // Args are: (tooltipItems, data)
  9623. beforeBody: helpers.noop,
  9624. // Args are: (tooltipItem, data)
  9625. beforeLabel: helpers.noop,
  9626. label: function(tooltipItem, data) {
  9627. var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || '';
  9628. return datasetLabel + ': ' + tooltipItem.yLabel;
  9629. },
  9630. afterLabel: helpers.noop,
  9631. // Args are: (tooltipItems, data)
  9632. afterBody: helpers.noop,
  9633. // Args are: (tooltipItems, data)
  9634. beforeFooter: helpers.noop,
  9635. footer: helpers.noop,
  9636. afterFooter: helpers.noop
  9637. }
  9638. };
  9639. // Helper to push or concat based on if the 2nd parameter is an array or not
  9640. function pushOrConcat(base, toPush) {
  9641. if (toPush) {
  9642. if (helpers.isArray(toPush)) {
  9643. base = base.concat(toPush);
  9644. } else {
  9645. base.push(toPush);
  9646. }
  9647. }
  9648. return base;
  9649. }
  9650. Chart.Tooltip = Chart.Element.extend({
  9651. initialize: function() {
  9652. var globalDefaults = Chart.defaults.global;
  9653. var options = this._options;
  9654. var tooltips = options.tooltips;
  9655. helpers.extend(this, {
  9656. _model: {
  9657. // Positioning
  9658. xPadding: tooltips.xPadding,
  9659. yPadding: tooltips.yPadding,
  9660. xAlign : tooltips.yAlign,
  9661. yAlign : tooltips.xAlign,
  9662. // Body
  9663. bodyColor: tooltips.bodyColor,
  9664. _bodyFontFamily: helpers.getValueOrDefault(tooltips.bodyFontFamily, globalDefaults.defaultFontFamily),
  9665. _bodyFontStyle: helpers.getValueOrDefault(tooltips.bodyFontStyle, globalDefaults.defaultFontStyle),
  9666. _bodyAlign: tooltips.bodyAlign,
  9667. bodyFontSize: helpers.getValueOrDefault(tooltips.bodyFontSize, globalDefaults.defaultFontSize),
  9668. bodySpacing: tooltips.bodySpacing,
  9669. // Title
  9670. titleColor: tooltips.titleColor,
  9671. _titleFontFamily: helpers.getValueOrDefault(tooltips.titleFontFamily, globalDefaults.defaultFontFamily),
  9672. _titleFontStyle: helpers.getValueOrDefault(tooltips.titleFontStyle, globalDefaults.defaultFontStyle),
  9673. titleFontSize: helpers.getValueOrDefault(tooltips.titleFontSize, globalDefaults.defaultFontSize),
  9674. _titleAlign: tooltips.titleAlign,
  9675. titleSpacing: tooltips.titleSpacing,
  9676. titleMarginBottom: tooltips.titleMarginBottom,
  9677. // Footer
  9678. footerColor: tooltips.footerColor,
  9679. _footerFontFamily: helpers.getValueOrDefault(tooltips.footerFontFamily, globalDefaults.defaultFontFamily),
  9680. _footerFontStyle: helpers.getValueOrDefault(tooltips.footerFontStyle, globalDefaults.defaultFontStyle),
  9681. footerFontSize: helpers.getValueOrDefault(tooltips.footerFontSize, globalDefaults.defaultFontSize),
  9682. _footerAlign: tooltips.footerAlign,
  9683. footerSpacing: tooltips.footerSpacing,
  9684. footerMarginTop: tooltips.footerMarginTop,
  9685. // Appearance
  9686. caretSize: tooltips.caretSize,
  9687. cornerRadius: tooltips.cornerRadius,
  9688. backgroundColor: tooltips.backgroundColor,
  9689. opacity: 0,
  9690. legendColorBackground: tooltips.multiKeyBackground
  9691. }
  9692. });
  9693. },
  9694. // Get the title
  9695. // Args are: (tooltipItem, data)
  9696. getTitle: function() {
  9697. var beforeTitle = this._options.tooltips.callbacks.beforeTitle.apply(this, arguments),
  9698. title = this._options.tooltips.callbacks.title.apply(this, arguments),
  9699. afterTitle = this._options.tooltips.callbacks.afterTitle.apply(this, arguments);
  9700. var lines = [];
  9701. lines = pushOrConcat(lines, beforeTitle);
  9702. lines = pushOrConcat(lines, title);
  9703. lines = pushOrConcat(lines, afterTitle);
  9704. return lines;
  9705. },
  9706. // Args are: (tooltipItem, data)
  9707. getBeforeBody: function() {
  9708. var lines = this._options.tooltips.callbacks.beforeBody.apply(this, arguments);
  9709. return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
  9710. },
  9711. // Args are: (tooltipItem, data)
  9712. getBody: function(tooltipItems, data) {
  9713. var lines = [];
  9714. helpers.each(tooltipItems, function(bodyItem) {
  9715. helpers.pushAllIfDefined(this._options.tooltips.callbacks.beforeLabel.call(this, bodyItem, data), lines);
  9716. helpers.pushAllIfDefined(this._options.tooltips.callbacks.label.call(this, bodyItem, data), lines);
  9717. helpers.pushAllIfDefined(this._options.tooltips.callbacks.afterLabel.call(this, bodyItem, data), lines);
  9718. }, this);
  9719. return lines;
  9720. },
  9721. // Args are: (tooltipItem, data)
  9722. getAfterBody: function() {
  9723. var lines = this._options.tooltips.callbacks.afterBody.apply(this, arguments);
  9724. return helpers.isArray(lines) ? lines : lines !== undefined ? [lines] : [];
  9725. },
  9726. // Get the footer and beforeFooter and afterFooter lines
  9727. // Args are: (tooltipItem, data)
  9728. getFooter: function() {
  9729. var beforeFooter = this._options.tooltips.callbacks.beforeFooter.apply(this, arguments);
  9730. var footer = this._options.tooltips.callbacks.footer.apply(this, arguments);
  9731. var afterFooter = this._options.tooltips.callbacks.afterFooter.apply(this, arguments);
  9732. var lines = [];
  9733. lines = pushOrConcat(lines, beforeFooter);
  9734. lines = pushOrConcat(lines, footer);
  9735. lines = pushOrConcat(lines, afterFooter);
  9736. return lines;
  9737. },
  9738. getAveragePosition: function(elements) {
  9739. if (!elements.length) {
  9740. return false;
  9741. }
  9742. var xPositions = [];
  9743. var yPositions = [];
  9744. helpers.each(elements, function(el) {
  9745. if (el && el.hasValue()){
  9746. var pos = el.tooltipPosition();
  9747. xPositions.push(pos.x);
  9748. yPositions.push(pos.y);
  9749. }
  9750. });
  9751. var x = 0,
  9752. y = 0;
  9753. for (var i = 0; i < xPositions.length; i++) {
  9754. x += xPositions[i];
  9755. y += yPositions[i];
  9756. }
  9757. return {
  9758. x: Math.round(x / xPositions.length),
  9759. y: Math.round(y / xPositions.length)
  9760. };
  9761. },
  9762. update: function(changed) {
  9763. if (this._active.length) {
  9764. this._model.opacity = 1;
  9765. var element = this._active[0],
  9766. labelColors = [],
  9767. tooltipPosition;
  9768. var tooltipItems = [];
  9769. if (this._options.tooltips.mode === 'single') {
  9770. var yScale = element._yScale || element._scale; // handle radar || polarArea charts
  9771. tooltipItems.push({
  9772. xLabel: element._xScale ? element._xScale.getLabelForIndex(element._index, element._datasetIndex) : '',
  9773. yLabel: yScale ? yScale.getLabelForIndex(element._index, element._datasetIndex) : '',
  9774. index: element._index,
  9775. datasetIndex: element._datasetIndex
  9776. });
  9777. tooltipPosition = this.getAveragePosition(this._active);
  9778. } else {
  9779. helpers.each(this._data.datasets, function(dataset, datasetIndex) {
  9780. if (!this._chartInstance.isDatasetVisible(datasetIndex)) {
  9781. return;
  9782. }
  9783. var meta = this._chartInstance.getDatasetMeta(datasetIndex);
  9784. var currentElement = meta.data[element._index];
  9785. if (currentElement) {
  9786. var yScale = element._yScale || element._scale; // handle radar || polarArea charts
  9787. tooltipItems.push({
  9788. xLabel: currentElement._xScale ? currentElement._xScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
  9789. yLabel: yScale ? yScale.getLabelForIndex(currentElement._index, currentElement._datasetIndex) : '',
  9790. index: element._index,
  9791. datasetIndex: datasetIndex
  9792. });
  9793. }
  9794. }, this);
  9795. helpers.each(this._active, function(active) {
  9796. if (active) {
  9797. labelColors.push({
  9798. borderColor: active._view.borderColor,
  9799. backgroundColor: active._view.backgroundColor
  9800. });
  9801. }
  9802. }, null);
  9803. tooltipPosition = this.getAveragePosition(this._active);
  9804. }
  9805. // Build the Text Lines
  9806. helpers.extend(this._model, {
  9807. title: this.getTitle(tooltipItems, this._data),
  9808. beforeBody: this.getBeforeBody(tooltipItems, this._data),
  9809. body: this.getBody(tooltipItems, this._data),
  9810. afterBody: this.getAfterBody(tooltipItems, this._data),
  9811. footer: this.getFooter(tooltipItems, this._data)
  9812. });
  9813. helpers.extend(this._model, {
  9814. x: Math.round(tooltipPosition.x),
  9815. y: Math.round(tooltipPosition.y),
  9816. caretPadding: helpers.getValueOrDefault(tooltipPosition.padding, 2),
  9817. labelColors: labelColors
  9818. });
  9819. // We need to determine alignment of
  9820. var tooltipSize = this.getTooltipSize(this._model);
  9821. this.determineAlignment(tooltipSize); // Smart Tooltip placement to stay on the canvas
  9822. helpers.extend(this._model, this.getBackgroundPoint(this._model, tooltipSize));
  9823. } else {
  9824. this._model.opacity = 0;
  9825. }
  9826. if (changed && this._options.tooltips.custom) {
  9827. this._options.tooltips.custom.call(this, this._model);
  9828. }
  9829. return this;
  9830. },
  9831. getTooltipSize: function getTooltipSize(vm) {
  9832. var ctx = this._chart.ctx;
  9833. var size = {
  9834. height: vm.yPadding * 2, // Tooltip Padding
  9835. width: 0
  9836. };
  9837. var combinedBodyLength = vm.body.length + vm.beforeBody.length + vm.afterBody.length;
  9838. size.height += vm.title.length * vm.titleFontSize; // Title Lines
  9839. size.height += (vm.title.length - 1) * vm.titleSpacing; // Title Line Spacing
  9840. size.height += vm.title.length ? vm.titleMarginBottom : 0; // Title's bottom Margin
  9841. size.height += combinedBodyLength * vm.bodyFontSize; // Body Lines
  9842. size.height += combinedBodyLength ? (combinedBodyLength - 1) * vm.bodySpacing : 0; // Body Line Spacing
  9843. size.height += vm.footer.length ? vm.footerMarginTop : 0; // Footer Margin
  9844. size.height += vm.footer.length * (vm.footerFontSize); // Footer Lines
  9845. size.height += vm.footer.length ? (vm.footer.length - 1) * vm.footerSpacing : 0; // Footer Line Spacing
  9846. // Width
  9847. ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
  9848. helpers.each(vm.title, function(line) {
  9849. size.width = Math.max(size.width, ctx.measureText(line).width);
  9850. });
  9851. ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
  9852. helpers.each(vm.beforeBody.concat(vm.afterBody), function(line) {
  9853. size.width = Math.max(size.width, ctx.measureText(line).width);
  9854. });
  9855. helpers.each(vm.body, function(line) {
  9856. size.width = Math.max(size.width, ctx.measureText(line).width + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0));
  9857. }, this);
  9858. ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
  9859. helpers.each(vm.footer, function(line) {
  9860. size.width = Math.max(size.width, ctx.measureText(line).width);
  9861. });
  9862. size.width += 2 * vm.xPadding;
  9863. return size;
  9864. },
  9865. determineAlignment: function determineAlignment(size) {
  9866. if (this._model.y < size.height) {
  9867. this._model.yAlign = 'top';
  9868. } else if (this._model.y > (this._chart.height - size.height)) {
  9869. this._model.yAlign = 'bottom';
  9870. }
  9871. var lf, rf; // functions to determine left, right alignment
  9872. var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart
  9873. var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges
  9874. var _this = this;
  9875. var midX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
  9876. var midY = (this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2;
  9877. if (this._model.yAlign === 'center') {
  9878. lf = function(x) {
  9879. return x <= midX;
  9880. };
  9881. rf = function(x) {
  9882. return x > midX;
  9883. };
  9884. } else {
  9885. lf = function(x) {
  9886. return x <= (size.width / 2);
  9887. };
  9888. rf = function(x) {
  9889. return x >= (_this._chart.width - (size.width / 2));
  9890. };
  9891. }
  9892. olf = function(x) {
  9893. return x + size.width > _this._chart.width;
  9894. };
  9895. orf = function(x) {
  9896. return x - size.width < 0;
  9897. };
  9898. yf = function(y) {
  9899. return y <= midY ? 'top' : 'bottom';
  9900. };
  9901. if (lf(this._model.x)) {
  9902. this._model.xAlign = 'left';
  9903. // Is tooltip too wide and goes over the right side of the chart.?
  9904. if (olf(this._model.x)) {
  9905. this._model.xAlign = 'center';
  9906. this._model.yAlign = yf(this._model.y);
  9907. }
  9908. } else if (rf(this._model.x)) {
  9909. this._model.xAlign = 'right';
  9910. // Is tooltip too wide and goes outside left edge of canvas?
  9911. if (orf(this._model.x)) {
  9912. this._model.xAlign = 'center';
  9913. this._model.yAlign = yf(this._model.y);
  9914. }
  9915. }
  9916. },
  9917. getBackgroundPoint: function getBackgroundPoint(vm, size) {
  9918. // Background Position
  9919. var pt = {
  9920. x: vm.x,
  9921. y: vm.y
  9922. };
  9923. if (vm.xAlign === 'right') {
  9924. pt.x -= size.width;
  9925. } else if (vm.xAlign === 'center') {
  9926. pt.x -= (size.width / 2);
  9927. }
  9928. if (vm.yAlign === 'top') {
  9929. pt.y += vm.caretPadding + vm.caretSize;
  9930. } else if (vm.yAlign === 'bottom') {
  9931. pt.y -= size.height + vm.caretPadding + vm.caretSize;
  9932. } else {
  9933. pt.y -= (size.height / 2);
  9934. }
  9935. if (vm.yAlign === 'center') {
  9936. if (vm.xAlign === 'left') {
  9937. pt.x += vm.caretPadding + vm.caretSize;
  9938. } else if (vm.xAlign === 'right') {
  9939. pt.x -= vm.caretPadding + vm.caretSize;
  9940. }
  9941. } else {
  9942. if (vm.xAlign === 'left') {
  9943. pt.x -= vm.cornerRadius + vm.caretPadding;
  9944. } else if (vm.xAlign === 'right') {
  9945. pt.x += vm.cornerRadius + vm.caretPadding;
  9946. }
  9947. }
  9948. return pt;
  9949. },
  9950. drawCaret: function drawCaret(tooltipPoint, size, opacity, caretPadding) {
  9951. var vm = this._view;
  9952. var ctx = this._chart.ctx;
  9953. var x1, x2, x3;
  9954. var y1, y2, y3;
  9955. if (vm.yAlign === 'center') {
  9956. // Left or right side
  9957. if (vm.xAlign === 'left') {
  9958. x1 = tooltipPoint.x;
  9959. x2 = x1 - vm.caretSize;
  9960. x3 = x1;
  9961. } else {
  9962. x1 = tooltipPoint.x + size.width;
  9963. x2 = x1 + vm.caretSize;
  9964. x3 = x1;
  9965. }
  9966. y2 = tooltipPoint.y + (size.height / 2);
  9967. y1 = y2 - vm.caretSize;
  9968. y3 = y2 + vm.caretSize;
  9969. } else {
  9970. if (vm.xAlign === 'left') {
  9971. x1 = tooltipPoint.x + vm.cornerRadius;
  9972. x2 = x1 + vm.caretSize;
  9973. x3 = x2 + vm.caretSize;
  9974. } else if (vm.xAlign === 'right') {
  9975. x1 = tooltipPoint.x + size.width - vm.cornerRadius;
  9976. x2 = x1 - vm.caretSize;
  9977. x3 = x2 - vm.caretSize;
  9978. } else {
  9979. x2 = tooltipPoint.x + (size.width / 2);
  9980. x1 = x2 - vm.caretSize;
  9981. x3 = x2 + vm.caretSize;
  9982. }
  9983. if (vm.yAlign === 'top') {
  9984. y1 = tooltipPoint.y;
  9985. y2 = y1 - vm.caretSize;
  9986. y3 = y1;
  9987. } else {
  9988. y1 = tooltipPoint.y + size.height;
  9989. y2 = y1 + vm.caretSize;
  9990. y3 = y1;
  9991. }
  9992. }
  9993. var bgColor = helpers.color(vm.backgroundColor);
  9994. ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
  9995. ctx.beginPath();
  9996. ctx.moveTo(x1, y1);
  9997. ctx.lineTo(x2, y2);
  9998. ctx.lineTo(x3, y3);
  9999. ctx.closePath();
  10000. ctx.fill();
  10001. },
  10002. drawTitle: function drawTitle(pt, vm, ctx, opacity) {
  10003. if (vm.title.length) {
  10004. ctx.textAlign = vm._titleAlign;
  10005. ctx.textBaseline = "top";
  10006. var titleColor = helpers.color(vm.titleColor);
  10007. ctx.fillStyle = titleColor.alpha(opacity * titleColor.alpha()).rgbString();
  10008. ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily);
  10009. helpers.each(vm.title, function(title, i) {
  10010. ctx.fillText(title, pt.x, pt.y);
  10011. pt.y += vm.titleFontSize + vm.titleSpacing; // Line Height and spacing
  10012. if (i + 1 === vm.title.length) {
  10013. pt.y += vm.titleMarginBottom - vm.titleSpacing; // If Last, add margin, remove spacing
  10014. }
  10015. });
  10016. }
  10017. },
  10018. drawBody: function drawBody(pt, vm, ctx, opacity) {
  10019. ctx.textAlign = vm._bodyAlign;
  10020. ctx.textBaseline = "top";
  10021. var bodyColor = helpers.color(vm.bodyColor);
  10022. ctx.fillStyle = bodyColor.alpha(opacity * bodyColor.alpha()).rgbString();
  10023. ctx.font = helpers.fontString(vm.bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);
  10024. // Before Body
  10025. helpers.each(vm.beforeBody, function(beforeBody) {
  10026. ctx.fillText(beforeBody, pt.x, pt.y);
  10027. pt.y += vm.bodyFontSize + vm.bodySpacing;
  10028. });
  10029. helpers.each(vm.body, function(body, i) {
  10030. // Draw Legend-like boxes if needed
  10031. if (this._options.tooltips.mode !== 'single') {
  10032. // Fill a white rect so that colours merge nicely if the opacity is < 1
  10033. ctx.fillStyle = helpers.color(vm.legendColorBackground).alpha(opacity).rgbaString();
  10034. ctx.fillRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
  10035. // Border
  10036. ctx.strokeStyle = helpers.color(vm.labelColors[i].borderColor).alpha(opacity).rgbaString();
  10037. ctx.strokeRect(pt.x, pt.y, vm.bodyFontSize, vm.bodyFontSize);
  10038. // Inner square
  10039. ctx.fillStyle = helpers.color(vm.labelColors[i].backgroundColor).alpha(opacity).rgbaString();
  10040. ctx.fillRect(pt.x + 1, pt.y + 1, vm.bodyFontSize - 2, vm.bodyFontSize - 2);
  10041. ctx.fillStyle = helpers.color(vm.bodyColor).alpha(opacity).rgbaString(); // Return fill style for text
  10042. }
  10043. // Body Line
  10044. ctx.fillText(body, pt.x + (this._options.tooltips.mode !== 'single' ? (vm.bodyFontSize + 2) : 0), pt.y);
  10045. pt.y += vm.bodyFontSize + vm.bodySpacing;
  10046. }, this);
  10047. // After Body
  10048. helpers.each(vm.afterBody, function(afterBody) {
  10049. ctx.fillText(afterBody, pt.x, pt.y);
  10050. pt.y += vm.bodyFontSize;
  10051. });
  10052. pt.y -= vm.bodySpacing; // Remove last body spacing
  10053. },
  10054. drawFooter: function drawFooter(pt, vm, ctx, opacity) {
  10055. if (vm.footer.length) {
  10056. pt.y += vm.footerMarginTop;
  10057. ctx.textAlign = vm._footerAlign;
  10058. ctx.textBaseline = "top";
  10059. var footerColor = helpers.color(vm.footerColor);
  10060. ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString();
  10061. ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily);
  10062. helpers.each(vm.footer, function(footer) {
  10063. ctx.fillText(footer, pt.x, pt.y);
  10064. pt.y += vm.footerFontSize + vm.footerSpacing;
  10065. });
  10066. }
  10067. },
  10068. draw: function draw() {
  10069. var ctx = this._chart.ctx;
  10070. var vm = this._view;
  10071. if (vm.opacity === 0) {
  10072. return;
  10073. }
  10074. var caretPadding = vm.caretPadding;
  10075. var tooltipSize = this.getTooltipSize(vm);
  10076. var pt = {
  10077. x: vm.x,
  10078. y: vm.y
  10079. };
  10080. // IE11/Edge does not like very small opacities, so snap to 0
  10081. var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
  10082. if (this._options.tooltips.enabled) {
  10083. // Draw Background
  10084. var bgColor = helpers.color(vm.backgroundColor);
  10085. ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
  10086. helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
  10087. ctx.fill();
  10088. // Draw Caret
  10089. this.drawCaret(pt, tooltipSize, opacity, caretPadding);
  10090. // Draw Title, Body, and Footer
  10091. pt.x += vm.xPadding;
  10092. pt.y += vm.yPadding;
  10093. // Titles
  10094. this.drawTitle(pt, vm, ctx, opacity);
  10095. // Body
  10096. this.drawBody(pt, vm, ctx, opacity);
  10097. // Footer
  10098. this.drawFooter(pt, vm, ctx, opacity);
  10099. }
  10100. }
  10101. });
  10102. };
  10103. },{}],34:[function(require,module,exports){
  10104. "use strict";
  10105. module.exports = function(Chart, moment) {
  10106. var helpers = Chart.helpers,
  10107. globalOpts = Chart.defaults.global;
  10108. globalOpts.elements.arc = {
  10109. backgroundColor: globalOpts.defaultColor,
  10110. borderColor: "#fff",
  10111. borderWidth: 2
  10112. };
  10113. Chart.elements.Arc = Chart.Element.extend({
  10114. inLabelRange: function(mouseX) {
  10115. var vm = this._view;
  10116. if (vm) {
  10117. return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
  10118. } else {
  10119. return false;
  10120. }
  10121. },
  10122. inRange: function(chartX, chartY) {
  10123. var vm = this._view;
  10124. if (vm) {
  10125. var pointRelativePosition = helpers.getAngleFromPoint(vm, {
  10126. x: chartX,
  10127. y: chartY
  10128. }),
  10129. angle = pointRelativePosition.angle,
  10130. distance = pointRelativePosition.distance;
  10131. //Sanitise angle range
  10132. var startAngle = vm.startAngle;
  10133. var endAngle = vm.endAngle;
  10134. while (endAngle < startAngle) {
  10135. endAngle += 2.0 * Math.PI;
  10136. }
  10137. while (angle > endAngle) {
  10138. angle -= 2.0 * Math.PI;
  10139. }
  10140. while (angle < startAngle) {
  10141. angle += 2.0 * Math.PI;
  10142. }
  10143. //Check if within the range of the open/close angle
  10144. var betweenAngles = (angle >= startAngle && angle <= endAngle),
  10145. withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
  10146. return (betweenAngles && withinRadius);
  10147. } else {
  10148. return false;
  10149. }
  10150. },
  10151. tooltipPosition: function() {
  10152. var vm = this._view;
  10153. var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2),
  10154. rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
  10155. return {
  10156. x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
  10157. y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
  10158. };
  10159. },
  10160. draw: function() {
  10161. var ctx = this._chart.ctx,
  10162. vm = this._view,
  10163. sA = vm.startAngle,
  10164. eA = vm.endAngle;
  10165. ctx.beginPath();
  10166. ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
  10167. ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
  10168. ctx.closePath();
  10169. ctx.strokeStyle = vm.borderColor;
  10170. ctx.lineWidth = vm.borderWidth;
  10171. ctx.fillStyle = vm.backgroundColor;
  10172. ctx.fill();
  10173. ctx.lineJoin = 'bevel';
  10174. if (vm.borderWidth) {
  10175. ctx.stroke();
  10176. }
  10177. }
  10178. });
  10179. };
  10180. },{}],35:[function(require,module,exports){
  10181. "use strict";
  10182. module.exports = function(Chart) {
  10183. var helpers = Chart.helpers;
  10184. var globalDefaults = Chart.defaults.global;
  10185. Chart.defaults.global.elements.line = {
  10186. tension: 0.4,
  10187. backgroundColor: globalDefaults.defaultColor,
  10188. borderWidth: 3,
  10189. borderColor: globalDefaults.defaultColor,
  10190. borderCapStyle: 'butt',
  10191. borderDash: [],
  10192. borderDashOffset: 0.0,
  10193. borderJoinStyle: 'miter',
  10194. fill: true // do we fill in the area between the line and its base axis
  10195. };
  10196. Chart.elements.Line = Chart.Element.extend({
  10197. lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
  10198. var ctx = this._chart.ctx;
  10199. if (point._view.skip) {
  10200. skipHandler.call(this, previousPoint, point, nextPoint);
  10201. } else if (previousPoint._view.skip) {
  10202. previousSkipHandler.call(this, previousPoint, point, nextPoint);
  10203. } else if (point._view.tension === 0) {
  10204. ctx.lineTo(point._view.x, point._view.y);
  10205. } else {
  10206. // Line between points
  10207. ctx.bezierCurveTo(
  10208. previousPoint._view.controlPointNextX,
  10209. previousPoint._view.controlPointNextY,
  10210. point._view.controlPointPreviousX,
  10211. point._view.controlPointPreviousY,
  10212. point._view.x,
  10213. point._view.y
  10214. );
  10215. }
  10216. },
  10217. draw: function() {
  10218. var _this = this;
  10219. var vm = this._view;
  10220. var ctx = this._chart.ctx;
  10221. var first = this._children[0];
  10222. var last = this._children[this._children.length - 1];
  10223. function loopBackToStart(drawLineToCenter) {
  10224. if (!first._view.skip && !last._view.skip) {
  10225. // Draw a bezier line from last to first
  10226. ctx.bezierCurveTo(
  10227. last._view.controlPointNextX,
  10228. last._view.controlPointNextY,
  10229. first._view.controlPointPreviousX,
  10230. first._view.controlPointPreviousY,
  10231. first._view.x,
  10232. first._view.y
  10233. );
  10234. } else if (drawLineToCenter) {
  10235. // Go to center
  10236. ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y);
  10237. }
  10238. }
  10239. ctx.save();
  10240. // If we had points and want to fill this line, do so.
  10241. if (this._children.length > 0 && vm.fill) {
  10242. // Draw the background first (so the border is always on top)
  10243. ctx.beginPath();
  10244. helpers.each(this._children, function(point, index) {
  10245. var previous = helpers.previousItem(this._children, index);
  10246. var next = helpers.nextItem(this._children, index);
  10247. // First point moves to it's starting position no matter what
  10248. if (index === 0) {
  10249. if (this._loop) {
  10250. ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
  10251. } else {
  10252. ctx.moveTo(point._view.x, vm.scaleZero);
  10253. }
  10254. if (point._view.skip) {
  10255. if (!this._loop) {
  10256. ctx.moveTo(next._view.x, this._view.scaleZero);
  10257. }
  10258. } else {
  10259. ctx.lineTo(point._view.x, point._view.y);
  10260. }
  10261. } else {
  10262. this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
  10263. if (this._loop) {
  10264. // Go to center
  10265. ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y);
  10266. } else {
  10267. ctx.lineTo(previousPoint._view.x, this._view.scaleZero);
  10268. ctx.moveTo(nextPoint._view.x, this._view.scaleZero);
  10269. }
  10270. }, function(previousPoint, point) {
  10271. // If we skipped the last point, draw a line to ourselves so that the fill is nice
  10272. ctx.lineTo(point._view.x, point._view.y);
  10273. });
  10274. }
  10275. }, this);
  10276. // For radial scales, loop back around to the first point
  10277. if (this._loop) {
  10278. loopBackToStart(true);
  10279. } else {
  10280. //Round off the line by going to the base of the chart, back to the start, then fill.
  10281. ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero);
  10282. ctx.lineTo(this._children[0]._view.x, vm.scaleZero);
  10283. }
  10284. ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
  10285. ctx.closePath();
  10286. ctx.fill();
  10287. }
  10288. var globalOptionLineElements = globalDefaults.elements.line;
  10289. // Now draw the line between all the points with any borders
  10290. ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
  10291. // IE 9 and 10 do not support line dash
  10292. if (ctx.setLineDash) {
  10293. ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);
  10294. }
  10295. ctx.lineDashOffset = vm.borderDashOffset || globalOptionLineElements.borderDashOffset;
  10296. ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
  10297. ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
  10298. ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
  10299. ctx.beginPath();
  10300. helpers.each(this._children, function(point, index) {
  10301. var previous = helpers.previousItem(this._children, index);
  10302. var next = helpers.nextItem(this._children, index);
  10303. if (index === 0) {
  10304. ctx.moveTo(point._view.x, point._view.y);
  10305. } else {
  10306. this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
  10307. ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
  10308. }, function(previousPoint, point) {
  10309. // If we skipped the last point, move up to our point preventing a line from being drawn
  10310. ctx.moveTo(point._view.x, point._view.y);
  10311. });
  10312. }
  10313. }, this);
  10314. if (this._loop && this._children.length > 0) {
  10315. loopBackToStart();
  10316. }
  10317. ctx.stroke();
  10318. ctx.restore();
  10319. }
  10320. });
  10321. };
  10322. },{}],36:[function(require,module,exports){
  10323. "use strict";
  10324. module.exports = function(Chart) {
  10325. var helpers = Chart.helpers,
  10326. globalOpts = Chart.defaults.global,
  10327. defaultColor = globalOpts.defaultColor;
  10328. globalOpts.elements.point = {
  10329. radius: 3,
  10330. pointStyle: 'circle',
  10331. backgroundColor: defaultColor,
  10332. borderWidth: 1,
  10333. borderColor: defaultColor,
  10334. // Hover
  10335. hitRadius: 1,
  10336. hoverRadius: 4,
  10337. hoverBorderWidth: 1
  10338. };
  10339. Chart.elements.Point = Chart.Element.extend({
  10340. inRange: function(mouseX, mouseY) {
  10341. var vm = this._view;
  10342. return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
  10343. },
  10344. inLabelRange: function(mouseX) {
  10345. var vm = this._view;
  10346. return vm ? (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hitRadius, 2)) : false;
  10347. },
  10348. tooltipPosition: function() {
  10349. var vm = this._view;
  10350. return {
  10351. x: vm.x,
  10352. y: vm.y,
  10353. padding: vm.radius + vm.borderWidth
  10354. };
  10355. },
  10356. draw: function() {
  10357. var vm = this._view;
  10358. var ctx = this._chart.ctx;
  10359. var pointStyle = vm.pointStyle;
  10360. var radius = vm.radius;
  10361. var x = vm.x;
  10362. var y = vm.y;
  10363. var type, edgeLength, xOffset, yOffset, height, size;
  10364. if (vm.skip) {
  10365. return;
  10366. }
  10367. if (typeof pointStyle === 'object') {
  10368. type = pointStyle.toString();
  10369. if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
  10370. ctx.drawImage(pointStyle, x - pointStyle.width / 2, y - pointStyle.height / 2);
  10371. return;
  10372. }
  10373. }
  10374. if (isNaN(radius) || radius <= 0) {
  10375. return;
  10376. }
  10377. ctx.strokeStyle = vm.borderColor || defaultColor;
  10378. ctx.lineWidth = helpers.getValueOrDefault(vm.borderWidth, globalOpts.elements.point.borderWidth);
  10379. ctx.fillStyle = vm.backgroundColor || defaultColor;
  10380. switch (pointStyle) {
  10381. // Default includes circle
  10382. default:
  10383. ctx.beginPath();
  10384. ctx.arc(x, y, radius, 0, Math.PI * 2);
  10385. ctx.closePath();
  10386. ctx.fill();
  10387. break;
  10388. case 'triangle':
  10389. ctx.beginPath();
  10390. edgeLength = 3 * radius / Math.sqrt(3);
  10391. height = edgeLength * Math.sqrt(3) / 2;
  10392. ctx.moveTo(x - edgeLength / 2, y + height / 3);
  10393. ctx.lineTo(x + edgeLength / 2, y + height / 3);
  10394. ctx.lineTo(x, y - 2 * height / 3);
  10395. ctx.closePath();
  10396. ctx.fill();
  10397. break;
  10398. case 'rect':
  10399. size = 1 / Math.SQRT2 * radius;
  10400. ctx.fillRect(x - size, y - size, 2 * size, 2 * size);
  10401. ctx.strokeRect(x - size, y - size, 2 * size, 2 * size);
  10402. break;
  10403. case 'rectRot':
  10404. ctx.translate(x, y);
  10405. ctx.rotate(Math.PI / 4);
  10406. size = 1 / Math.SQRT2 * radius;
  10407. ctx.fillRect(-size, -size, 2 * size, 2 * size);
  10408. ctx.strokeRect(-size, -size, 2 * size, 2 * size);
  10409. ctx.setTransform(1, 0, 0, 1, 0, 0);
  10410. break;
  10411. case 'cross':
  10412. ctx.beginPath();
  10413. ctx.moveTo(x, y + radius);
  10414. ctx.lineTo(x, y - radius);
  10415. ctx.moveTo(x - radius, y);
  10416. ctx.lineTo(x + radius, y);
  10417. ctx.closePath();
  10418. break;
  10419. case 'crossRot':
  10420. ctx.beginPath();
  10421. xOffset = Math.cos(Math.PI / 4) * radius;
  10422. yOffset = Math.sin(Math.PI / 4) * radius;
  10423. ctx.moveTo(x - xOffset, y - yOffset);
  10424. ctx.lineTo(x + xOffset, y + yOffset);
  10425. ctx.moveTo(x - xOffset, y + yOffset);
  10426. ctx.lineTo(x + xOffset, y - yOffset);
  10427. ctx.closePath();
  10428. break;
  10429. case 'star':
  10430. ctx.beginPath();
  10431. ctx.moveTo(x, y + radius);
  10432. ctx.lineTo(x, y - radius);
  10433. ctx.moveTo(x - radius, y);
  10434. ctx.lineTo(x + radius, y);
  10435. xOffset = Math.cos(Math.PI / 4) * radius;
  10436. yOffset = Math.sin(Math.PI / 4) * radius;
  10437. ctx.moveTo(x - xOffset, y - yOffset);
  10438. ctx.lineTo(x + xOffset, y + yOffset);
  10439. ctx.moveTo(x - xOffset, y + yOffset);
  10440. ctx.lineTo(x + xOffset, y - yOffset);
  10441. ctx.closePath();
  10442. break;
  10443. case 'line':
  10444. ctx.beginPath();
  10445. ctx.moveTo(x - radius, y);
  10446. ctx.lineTo(x + radius, y);
  10447. ctx.closePath();
  10448. break;
  10449. case 'dash':
  10450. ctx.beginPath();
  10451. ctx.moveTo(x, y);
  10452. ctx.lineTo(x + radius, y);
  10453. ctx.closePath();
  10454. break;
  10455. }
  10456. ctx.stroke();
  10457. }
  10458. });
  10459. };
  10460. },{}],37:[function(require,module,exports){
  10461. "use strict";
  10462. module.exports = function(Chart) {
  10463. var helpers = Chart.helpers,
  10464. globalOpts = Chart.defaults.global;
  10465. globalOpts.elements.rectangle = {
  10466. backgroundColor: globalOpts.defaultColor,
  10467. borderWidth: 0,
  10468. borderColor: globalOpts.defaultColor,
  10469. borderSkipped: 'bottom'
  10470. };
  10471. Chart.elements.Rectangle = Chart.Element.extend({
  10472. draw: function() {
  10473. var ctx = this._chart.ctx;
  10474. var vm = this._view;
  10475. var halfWidth = vm.width / 2,
  10476. leftX = vm.x - halfWidth,
  10477. rightX = vm.x + halfWidth,
  10478. top = vm.base - (vm.base - vm.y),
  10479. halfStroke = vm.borderWidth / 2;
  10480. // Canvas doesn't allow us to stroke inside the width so we can
  10481. // adjust the sizes to fit if we're setting a stroke on the line
  10482. if (vm.borderWidth) {
  10483. leftX += halfStroke;
  10484. rightX -= halfStroke;
  10485. top += halfStroke;
  10486. }
  10487. ctx.beginPath();
  10488. ctx.fillStyle = vm.backgroundColor;
  10489. ctx.strokeStyle = vm.borderColor;
  10490. ctx.lineWidth = vm.borderWidth;
  10491. // Corner points, from bottom-left to bottom-right clockwise
  10492. // | 1 2 |
  10493. // | 0 3 |
  10494. var corners = [
  10495. [leftX, vm.base],
  10496. [leftX, top],
  10497. [rightX, top],
  10498. [rightX, vm.base]
  10499. ];
  10500. // Find first (starting) corner with fallback to 'bottom'
  10501. var borders = ['bottom', 'left', 'top', 'right'];
  10502. var startCorner = borders.indexOf(vm.borderSkipped, 0);
  10503. if (startCorner === -1)
  10504. startCorner = 0;
  10505. function cornerAt(index) {
  10506. return corners[(startCorner + index) % 4];
  10507. }
  10508. // Draw rectangle from 'startCorner'
  10509. ctx.moveTo.apply(ctx, cornerAt(0));
  10510. for (var i = 1; i < 4; i++)
  10511. ctx.lineTo.apply(ctx, cornerAt(i));
  10512. ctx.fill();
  10513. if (vm.borderWidth) {
  10514. ctx.stroke();
  10515. }
  10516. },
  10517. height: function() {
  10518. var vm = this._view;
  10519. return vm.base - vm.y;
  10520. },
  10521. inRange: function(mouseX, mouseY) {
  10522. var vm = this._view;
  10523. return vm ?
  10524. (vm.y < vm.base ?
  10525. (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base) :
  10526. (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.base && mouseY <= vm.y)) :
  10527. false;
  10528. },
  10529. inLabelRange: function(mouseX) {
  10530. var vm = this._view;
  10531. return vm ? (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) : false;
  10532. },
  10533. tooltipPosition: function() {
  10534. var vm = this._view;
  10535. return {
  10536. x: vm.x,
  10537. y: vm.y
  10538. };
  10539. }
  10540. });
  10541. };
  10542. },{}],38:[function(require,module,exports){
  10543. "use strict";
  10544. module.exports = function(Chart) {
  10545. var helpers = Chart.helpers;
  10546. // Default config for a category scale
  10547. var defaultConfig = {
  10548. position: "bottom"
  10549. };
  10550. var DatasetScale = Chart.Scale.extend({
  10551. // Implement this so that
  10552. determineDataLimits: function() {
  10553. this.minIndex = 0;
  10554. this.maxIndex = this.chart.data.labels.length - 1;
  10555. var findIndex;
  10556. if (this.options.ticks.min !== undefined) {
  10557. // user specified min value
  10558. findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.min);
  10559. this.minIndex = findIndex !== -1 ? findIndex : this.minIndex;
  10560. }
  10561. if (this.options.ticks.max !== undefined) {
  10562. // user specified max value
  10563. findIndex = helpers.indexOf(this.chart.data.labels, this.options.ticks.max);
  10564. this.maxIndex = findIndex !== -1 ? findIndex : this.maxIndex;
  10565. }
  10566. this.min = this.chart.data.labels[this.minIndex];
  10567. this.max = this.chart.data.labels[this.maxIndex];
  10568. },
  10569. buildTicks: function(index) {
  10570. // If we are viewing some subset of labels, slice the original array
  10571. this.ticks = (this.minIndex === 0 && this.maxIndex === this.chart.data.labels.length - 1) ? this.chart.data.labels : this.chart.data.labels.slice(this.minIndex, this.maxIndex + 1);
  10572. },
  10573. getLabelForIndex: function(index, datasetIndex) {
  10574. return this.ticks[index];
  10575. },
  10576. // Used to get data value locations. Value can either be an index or a numerical value
  10577. getPixelForValue: function(value, index, datasetIndex, includeOffset) {
  10578. // 1 is added because we need the length but we have the indexes
  10579. var offsetAmt = Math.max((this.maxIndex + 1 - this.minIndex - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
  10580. if (this.isHorizontal()) {
  10581. var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
  10582. var valueWidth = innerWidth / offsetAmt;
  10583. var widthOffset = (valueWidth * (index - this.minIndex)) + this.paddingLeft;
  10584. if (this.options.gridLines.offsetGridLines && includeOffset) {
  10585. widthOffset += (valueWidth / 2);
  10586. }
  10587. return this.left + Math.round(widthOffset);
  10588. } else {
  10589. var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
  10590. var valueHeight = innerHeight / offsetAmt;
  10591. var heightOffset = (valueHeight * (index - this.minIndex)) + this.paddingTop;
  10592. if (this.options.gridLines.offsetGridLines && includeOffset) {
  10593. heightOffset += (valueHeight / 2);
  10594. }
  10595. return this.top + Math.round(heightOffset);
  10596. }
  10597. },
  10598. getPixelForTick: function(index, includeOffset) {
  10599. return this.getPixelForValue(this.ticks[index], index + this.minIndex, null, includeOffset);
  10600. },
  10601. getValueForPixel: function(pixel) {
  10602. var value
  10603. ; var offsetAmt = Math.max((this.ticks.length - ((this.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
  10604. var horz = this.isHorizontal();
  10605. var innerDimension = horz ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
  10606. var valueDimension = innerDimension / offsetAmt;
  10607. if (this.options.gridLines.offsetGridLines) {
  10608. pixel -= (valueDimension / 2);
  10609. }
  10610. pixel -= horz ? this.paddingLeft : this.paddingTop;
  10611. if (pixel <= 0) {
  10612. value = 0;
  10613. } else {
  10614. value = Math.round(pixel / valueDimension);
  10615. }
  10616. return value;
  10617. }
  10618. });
  10619. Chart.scaleService.registerScaleType("category", DatasetScale, defaultConfig);
  10620. };
  10621. },{}],39:[function(require,module,exports){
  10622. "use strict";
  10623. module.exports = function(Chart) {
  10624. var helpers = Chart.helpers;
  10625. var defaultConfig = {
  10626. position: "left",
  10627. ticks: {
  10628. callback: function(tickValue, index, ticks) {
  10629. // If we have lots of ticks, don't use the ones
  10630. var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];
  10631. // If we have a number like 2.5 as the delta, figure out how many decimal places we need
  10632. if (Math.abs(delta) > 1) {
  10633. if (tickValue !== Math.floor(tickValue)) {
  10634. // not an integer
  10635. delta = tickValue - Math.floor(tickValue);
  10636. }
  10637. }
  10638. var logDelta = helpers.log10(Math.abs(delta));
  10639. var tickString = '';
  10640. if (tickValue !== 0) {
  10641. var numDecimal = -1 * Math.floor(logDelta);
  10642. numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places
  10643. tickString = tickValue.toFixed(numDecimal);
  10644. } else {
  10645. tickString = '0'; // never show decimal places for 0
  10646. }
  10647. return tickString;
  10648. }
  10649. }
  10650. };
  10651. var LinearScale = Chart.Scale.extend({
  10652. determineDataLimits: function() {
  10653. var _this = this;
  10654. var opts = _this.options;
  10655. var tickOpts = opts.ticks;
  10656. var chart = _this.chart;
  10657. var data = chart.data;
  10658. var datasets = data.datasets;
  10659. var isHorizontal = _this.isHorizontal();
  10660. function IDMatches(meta) {
  10661. return isHorizontal ? meta.xAxisID === _this.id : meta.yAxisID === _this.id;
  10662. }
  10663. // First Calculate the range
  10664. _this.min = null;
  10665. _this.max = null;
  10666. if (opts.stacked) {
  10667. var valuesPerType = {};
  10668. var hasPositiveValues = false;
  10669. var hasNegativeValues = false;
  10670. helpers.each(datasets, function(dataset, datasetIndex) {
  10671. var meta = chart.getDatasetMeta(datasetIndex);
  10672. if (valuesPerType[meta.type] === undefined) {
  10673. valuesPerType[meta.type] = {
  10674. positiveValues: [],
  10675. negativeValues: []
  10676. };
  10677. }
  10678. // Store these per type
  10679. var positiveValues = valuesPerType[meta.type].positiveValues;
  10680. var negativeValues = valuesPerType[meta.type].negativeValues;
  10681. if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  10682. helpers.each(dataset.data, function(rawValue, index) {
  10683. var value = +_this.getRightValue(rawValue);
  10684. if (isNaN(value) || meta.data[index].hidden) {
  10685. return;
  10686. }
  10687. positiveValues[index] = positiveValues[index] || 0;
  10688. negativeValues[index] = negativeValues[index] || 0;
  10689. if (opts.relativePoints) {
  10690. positiveValues[index] = 100;
  10691. } else {
  10692. if (value < 0) {
  10693. hasNegativeValues = true;
  10694. negativeValues[index] += value;
  10695. } else {
  10696. hasPositiveValues = true;
  10697. positiveValues[index] += value;
  10698. }
  10699. }
  10700. });
  10701. }
  10702. });
  10703. helpers.each(valuesPerType, function(valuesForType) {
  10704. var values = valuesForType.positiveValues.concat(valuesForType.negativeValues);
  10705. var minVal = helpers.min(values);
  10706. var maxVal = helpers.max(values);
  10707. _this.min = _this.min === null ? minVal : Math.min(_this.min, minVal);
  10708. _this.max = _this.max === null ? maxVal : Math.max(_this.max, maxVal);
  10709. });
  10710. } else {
  10711. helpers.each(datasets, function(dataset, datasetIndex) {
  10712. var meta = chart.getDatasetMeta(datasetIndex);
  10713. if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  10714. helpers.each(dataset.data, function(rawValue, index) {
  10715. var value = +_this.getRightValue(rawValue);
  10716. if (isNaN(value) || meta.data[index].hidden) {
  10717. return;
  10718. }
  10719. if (_this.min === null) {
  10720. _this.min = value;
  10721. } else if (value < _this.min) {
  10722. _this.min = value;
  10723. }
  10724. if (_this.max === null) {
  10725. _this.max = value;
  10726. } else if (value > _this.max) {
  10727. _this.max = value;
  10728. }
  10729. });
  10730. }
  10731. });
  10732. }
  10733. // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
  10734. // do nothing since that would make the chart weird. If the user really wants a weird chart
  10735. // axis, they can manually override it
  10736. if (tickOpts.beginAtZero) {
  10737. var minSign = helpers.sign(_this.min);
  10738. var maxSign = helpers.sign(_this.max);
  10739. if (minSign < 0 && maxSign < 0) {
  10740. // move the top up to 0
  10741. _this.max = 0;
  10742. } else if (minSign > 0 && maxSign > 0) {
  10743. // move the botttom down to 0
  10744. _this.min = 0;
  10745. }
  10746. }
  10747. if (tickOpts.min !== undefined) {
  10748. _this.min = tickOpts.min;
  10749. } else if (tickOpts.suggestedMin !== undefined) {
  10750. _this.min = Math.min(_this.min, tickOpts.suggestedMin);
  10751. }
  10752. if (tickOpts.max !== undefined) {
  10753. _this.max = tickOpts.max;
  10754. } else if (tickOpts.suggestedMax !== undefined) {
  10755. _this.max = Math.max(_this.max, tickOpts.suggestedMax);
  10756. }
  10757. if (_this.min === _this.max) {
  10758. _this.max++;
  10759. if (!tickOpts.beginAtZero) {
  10760. _this.min--;
  10761. }
  10762. }
  10763. },
  10764. buildTicks: function() {
  10765. var _this = this;
  10766. var opts = _this.options;
  10767. var tickOpts = opts.ticks;
  10768. var getValueOrDefault = helpers.getValueOrDefault;
  10769. var isHorizontal = _this.isHorizontal();
  10770. var ticks = _this.ticks = [];
  10771. // Figure out what the max number of ticks we can support it is based on the size of
  10772. // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
  10773. // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
  10774. // the graph
  10775. var maxTicks;
  10776. if (isHorizontal) {
  10777. maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(_this.width / 50));
  10778. } else {
  10779. // The factor of 2 used to scale the font size has been experimentally determined.
  10780. var tickFontSize = getValueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize);
  10781. maxTicks = Math.min(tickOpts.maxTicksLimit ? tickOpts.maxTicksLimit : 11, Math.ceil(_this.height / (2 * tickFontSize)));
  10782. }
  10783. // Make sure we always have at least 2 ticks
  10784. maxTicks = Math.max(2, maxTicks);
  10785. // To get a "nice" value for the tick spacing, we will use the appropriately named
  10786. // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
  10787. // for details.
  10788. var spacing;
  10789. var fixedStepSizeSet = (tickOpts.fixedStepSize && tickOpts.fixedStepSize > 0) || (tickOpts.stepSize && tickOpts.stepSize > 0);
  10790. if (fixedStepSizeSet) {
  10791. spacing = getValueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize);
  10792. } else {
  10793. var niceRange = helpers.niceNum(_this.max - _this.min, false);
  10794. spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
  10795. }
  10796. var niceMin = Math.floor(_this.min / spacing) * spacing;
  10797. var niceMax = Math.ceil(_this.max / spacing) * spacing;
  10798. var numSpaces = (niceMax - niceMin) / spacing;
  10799. // If very close to our rounded value, use it.
  10800. if (helpers.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
  10801. numSpaces = Math.round(numSpaces);
  10802. } else {
  10803. numSpaces = Math.ceil(numSpaces);
  10804. }
  10805. // Put the values into the ticks array
  10806. ticks.push(tickOpts.min !== undefined ? tickOpts.min : niceMin);
  10807. for (var j = 1; j < numSpaces; ++j) {
  10808. ticks.push(niceMin + (j * spacing));
  10809. }
  10810. ticks.push(tickOpts.max !== undefined ? tickOpts.max : niceMax);
  10811. if (!isHorizontal) {
  10812. // We are in a vertical orientation. The top value is the highest. So reverse the array
  10813. ticks.reverse();
  10814. }
  10815. // At this point, we need to update our max and min given the tick values since we have expanded the
  10816. // range of the scale
  10817. _this.max = helpers.max(ticks);
  10818. _this.min = helpers.min(ticks);
  10819. if (tickOpts.reverse) {
  10820. ticks.reverse();
  10821. _this.start = _this.max;
  10822. _this.end = _this.min;
  10823. } else {
  10824. _this.start = _this.min;
  10825. _this.end = _this.max;
  10826. }
  10827. },
  10828. getLabelForIndex: function(index, datasetIndex) {
  10829. return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  10830. },
  10831. convertTicksToLabels: function() {
  10832. var _this = this;
  10833. _this.ticksAsNumbers = _this.ticks.slice();
  10834. _this.zeroLineIndex = _this.ticks.indexOf(0);
  10835. Chart.Scale.prototype.convertTicksToLabels.call(_this);
  10836. },
  10837. // Utils
  10838. getPixelForValue: function(value, index, datasetIndex, includeOffset) {
  10839. // This must be called after fit has been run so that
  10840. // this.left, this.top, this.right, and this.bottom have been defined
  10841. var _this = this;
  10842. var paddingLeft = _this.paddingLeft;
  10843. var paddingBottom = _this.paddingBottom;
  10844. var start = _this.start;
  10845. var rightValue = +_this.getRightValue(value);
  10846. var pixel;
  10847. var innerDimension;
  10848. var range = _this.end - start;
  10849. if (_this.isHorizontal()) {
  10850. innerDimension = _this.width - (paddingLeft + _this.paddingRight);
  10851. pixel = _this.left + (innerDimension / range * (rightValue - start));
  10852. return Math.round(pixel + paddingLeft);
  10853. } else {
  10854. innerDimension = _this.height - (_this.paddingTop + paddingBottom);
  10855. pixel = (_this.bottom - paddingBottom) - (innerDimension / range * (rightValue - start));
  10856. return Math.round(pixel);
  10857. }
  10858. },
  10859. getValueForPixel: function(pixel) {
  10860. var _this = this;
  10861. var isHorizontal = _this.isHorizontal();
  10862. var paddingLeft = _this.paddingLeft;
  10863. var paddingBottom = _this.paddingBottom;
  10864. var innerDimension = isHorizontal ? _this.width - (paddingLeft + _this.paddingRight) : _this.height - (_this.paddingTop + paddingBottom);
  10865. var offset = (isHorizontal ? pixel - _this.left - paddingLeft : _this.bottom - paddingBottom - pixel) / innerDimension;
  10866. return _this.start + ((_this.end - _this.start) * offset);
  10867. },
  10868. getPixelForTick: function(index, includeOffset) {
  10869. return this.getPixelForValue(this.ticksAsNumbers[index], null, null, includeOffset);
  10870. }
  10871. });
  10872. Chart.scaleService.registerScaleType("linear", LinearScale, defaultConfig);
  10873. };
  10874. },{}],40:[function(require,module,exports){
  10875. "use strict";
  10876. module.exports = function(Chart) {
  10877. var helpers = Chart.helpers;
  10878. var defaultConfig = {
  10879. position: "left",
  10880. // label settings
  10881. ticks: {
  10882. callback: function(value, index, arr) {
  10883. var remain = value / (Math.pow(10, Math.floor(helpers.log10(value))));
  10884. if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === arr.length - 1) {
  10885. return value.toExponential();
  10886. } else {
  10887. return '';
  10888. }
  10889. }
  10890. }
  10891. };
  10892. var LogarithmicScale = Chart.Scale.extend({
  10893. determineDataLimits: function() {
  10894. var _this = this;
  10895. var opts = _this.options;
  10896. var tickOpts = opts.ticks;
  10897. var chart = _this.chart;
  10898. var data = chart.data;
  10899. var datasets = data.datasets;
  10900. var getValueOrDefault = helpers.getValueOrDefault;
  10901. var isHorizontal = _this.isHorizontal();
  10902. function IDMatches(meta) {
  10903. return isHorizontal ? meta.xAxisID === _this.id : meta.yAxisID === _this.id;
  10904. }
  10905. // Calculate Range
  10906. _this.min = null;
  10907. _this.max = null;
  10908. if (opts.stacked) {
  10909. var valuesPerType = {};
  10910. helpers.each(datasets, function(dataset, datasetIndex) {
  10911. var meta = chart.getDatasetMeta(datasetIndex);
  10912. if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  10913. if (valuesPerType[meta.type] === undefined) {
  10914. valuesPerType[meta.type] = [];
  10915. }
  10916. helpers.each(dataset.data, function(rawValue, index) {
  10917. var values = valuesPerType[meta.type];
  10918. var value = +_this.getRightValue(rawValue);
  10919. if (isNaN(value) || meta.data[index].hidden) {
  10920. return;
  10921. }
  10922. values[index] = values[index] || 0;
  10923. if (opts.relativePoints) {
  10924. values[index] = 100;
  10925. } else {
  10926. // Don't need to split positive and negative since the log scale can't handle a 0 crossing
  10927. values[index] += value;
  10928. }
  10929. });
  10930. }
  10931. });
  10932. helpers.each(valuesPerType, function(valuesForType) {
  10933. var minVal = helpers.min(valuesForType);
  10934. var maxVal = helpers.max(valuesForType);
  10935. _this.min = _this.min === null ? minVal : Math.min(_this.min, minVal);
  10936. _this.max = _this.max === null ? maxVal : Math.max(_this.max, maxVal);
  10937. });
  10938. } else {
  10939. helpers.each(datasets, function(dataset, datasetIndex) {
  10940. var meta = chart.getDatasetMeta(datasetIndex);
  10941. if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {
  10942. helpers.each(dataset.data, function(rawValue, index) {
  10943. var value = +_this.getRightValue(rawValue);
  10944. if (isNaN(value) || meta.data[index].hidden) {
  10945. return;
  10946. }
  10947. if (_this.min === null) {
  10948. _this.min = value;
  10949. } else if (value < _this.min) {
  10950. _this.min = value;
  10951. }
  10952. if (_this.max === null) {
  10953. _this.max = value;
  10954. } else if (value > _this.max) {
  10955. _this.max = value;
  10956. }
  10957. });
  10958. }
  10959. });
  10960. }
  10961. _this.min = getValueOrDefault(tickOpts.min, _this.min);
  10962. _this.max = getValueOrDefault(tickOpts.max, _this.max);
  10963. if (_this.min === _this.max) {
  10964. if (_this.min !== 0 && _this.min !== null) {
  10965. _this.min = Math.pow(10, Math.floor(helpers.log10(_this.min)) - 1);
  10966. _this.max = Math.pow(10, Math.floor(helpers.log10(_this.max)) + 1);
  10967. } else {
  10968. _this.min = 1;
  10969. _this.max = 10;
  10970. }
  10971. }
  10972. },
  10973. buildTicks: function() {
  10974. var _this = this;
  10975. var opts = _this.options;
  10976. var tickOpts = opts.ticks;
  10977. var getValueOrDefault = helpers.getValueOrDefault;
  10978. // Reset the ticks array. Later on, we will draw a grid line at these positions
  10979. // The array simply contains the numerical value of the spots where ticks will be
  10980. var ticks = _this.ticks = [];
  10981. // Figure out what the max number of ticks we can support it is based on the size of
  10982. // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
  10983. // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
  10984. // the graph
  10985. var tickVal = getValueOrDefault(tickOpts.min, Math.pow(10, Math.floor(helpers.log10(_this.min))));
  10986. while (tickVal < _this.max) {
  10987. ticks.push(tickVal);
  10988. var exp = Math.floor(helpers.log10(tickVal));
  10989. var significand = Math.floor(tickVal / Math.pow(10, exp)) + 1;
  10990. if (significand === 10) {
  10991. significand = 1;
  10992. ++exp;
  10993. }
  10994. tickVal = significand * Math.pow(10, exp);
  10995. }
  10996. var lastTick = getValueOrDefault(tickOpts.max, tickVal);
  10997. ticks.push(lastTick);
  10998. if (!_this.isHorizontal()) {
  10999. // We are in a vertical orientation. The top value is the highest. So reverse the array
  11000. ticks.reverse();
  11001. }
  11002. // At this point, we need to update our max and min given the tick values since we have expanded the
  11003. // range of the scale
  11004. _this.max = helpers.max(ticks);
  11005. _this.min = helpers.min(ticks);
  11006. if (tickOpts.reverse) {
  11007. ticks.reverse();
  11008. _this.start = _this.max;
  11009. _this.end = _this.min;
  11010. } else {
  11011. _this.start = _this.min;
  11012. _this.end = _this.max;
  11013. }
  11014. },
  11015. convertTicksToLabels: function() {
  11016. this.tickValues = this.ticks.slice();
  11017. Chart.Scale.prototype.convertTicksToLabels.call(this);
  11018. },
  11019. // Get the correct tooltip label
  11020. getLabelForIndex: function(index, datasetIndex) {
  11021. return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  11022. },
  11023. getPixelForTick: function(index, includeOffset) {
  11024. return this.getPixelForValue(this.tickValues[index], null, null, includeOffset);
  11025. },
  11026. getPixelForValue: function(value, index, datasetIndex, includeOffset) {
  11027. var _this = this;
  11028. var innerDimension;
  11029. var pixel;
  11030. var start = _this.start;
  11031. var newVal = +_this.getRightValue(value);
  11032. var range = helpers.log10(_this.end) - helpers.log10(start);
  11033. var paddingTop = _this.paddingTop;
  11034. var paddingBottom = _this.paddingBottom;
  11035. var paddingLeft = _this.paddingLeft;
  11036. if (_this.isHorizontal()) {
  11037. if (newVal === 0) {
  11038. pixel = _this.left + paddingLeft;
  11039. } else {
  11040. innerDimension = _this.width - (paddingLeft + _this.paddingRight);
  11041. pixel = _this.left + (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
  11042. pixel += paddingLeft;
  11043. }
  11044. } else {
  11045. // Bottom - top since pixels increase downard on a screen
  11046. if (newVal === 0) {
  11047. pixel = _this.top + paddingTop;
  11048. } else {
  11049. innerDimension = _this.height - (paddingTop + paddingBottom);
  11050. pixel = (_this.bottom - paddingBottom) - (innerDimension / range * (helpers.log10(newVal) - helpers.log10(start)));
  11051. }
  11052. }
  11053. return pixel;
  11054. },
  11055. getValueForPixel: function(pixel) {
  11056. var _this = this;
  11057. var offset;
  11058. var range = helpers.log10(_this.end) - helpers.log10(_this.start);
  11059. var value;
  11060. var innerDimension;
  11061. if (_this.isHorizontal()) {
  11062. innerDimension = _this.width - (_this.paddingLeft + _this.paddingRight);
  11063. value = _this.start * Math.pow(10, (pixel - _this.left - _this.paddingLeft) * range / innerDimension);
  11064. } else {
  11065. innerDimension = _this.height - (_this.paddingTop + _this.paddingBottom);
  11066. value = Math.pow(10, (_this.bottom - _this.paddingBottom - pixel) * range / innerDimension) / _this.start;
  11067. }
  11068. return value;
  11069. }
  11070. });
  11071. Chart.scaleService.registerScaleType("logarithmic", LogarithmicScale, defaultConfig);
  11072. };
  11073. },{}],41:[function(require,module,exports){
  11074. "use strict";
  11075. module.exports = function(Chart) {
  11076. var helpers = Chart.helpers;
  11077. var globalDefaults = Chart.defaults.global;
  11078. var defaultConfig = {
  11079. display: true,
  11080. //Boolean - Whether to animate scaling the chart from the centre
  11081. animate: true,
  11082. lineArc: false,
  11083. position: "chartArea",
  11084. angleLines: {
  11085. display: true,
  11086. color: "rgba(0, 0, 0, 0.1)",
  11087. lineWidth: 1
  11088. },
  11089. // label settings
  11090. ticks: {
  11091. //Boolean - Show a backdrop to the scale label
  11092. showLabelBackdrop: true,
  11093. //String - The colour of the label backdrop
  11094. backdropColor: "rgba(255,255,255,0.75)",
  11095. //Number - The backdrop padding above & below the label in pixels
  11096. backdropPaddingY: 2,
  11097. //Number - The backdrop padding to the side of the label in pixels
  11098. backdropPaddingX: 2
  11099. },
  11100. pointLabels: {
  11101. //Number - Point label font size in pixels
  11102. fontSize: 10,
  11103. //Function - Used to convert point labels
  11104. callback: function(label) {
  11105. return label;
  11106. }
  11107. }
  11108. };
  11109. var LinearRadialScale = Chart.Scale.extend({
  11110. getValueCount: function() {
  11111. return this.chart.data.labels.length;
  11112. },
  11113. setDimensions: function() {
  11114. var options = this.options;
  11115. // Set the unconstrained dimension before label rotation
  11116. this.width = this.maxWidth;
  11117. this.height = this.maxHeight;
  11118. this.xCenter = Math.round(this.width / 2);
  11119. this.yCenter = Math.round(this.height / 2);
  11120. var minSize = helpers.min([this.height, this.width]);
  11121. var tickFontSize = helpers.getValueOrDefault(options.ticks.fontSize, globalDefaults.defaultFontSize);
  11122. this.drawingArea = (options.display) ? (minSize / 2) - (tickFontSize / 2 + options.ticks.backdropPaddingY) : (minSize / 2);
  11123. },
  11124. determineDataLimits: function() {
  11125. this.min = null;
  11126. this.max = null;
  11127. helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
  11128. if (this.chart.isDatasetVisible(datasetIndex)) {
  11129. var meta = this.chart.getDatasetMeta(datasetIndex);
  11130. helpers.each(dataset.data, function(rawValue, index) {
  11131. var value = +this.getRightValue(rawValue);
  11132. if (isNaN(value) || meta.data[index].hidden) {
  11133. return;
  11134. }
  11135. if (this.min === null) {
  11136. this.min = value;
  11137. } else if (value < this.min) {
  11138. this.min = value;
  11139. }
  11140. if (this.max === null) {
  11141. this.max = value;
  11142. } else if (value > this.max) {
  11143. this.max = value;
  11144. }
  11145. }, this);
  11146. }
  11147. }, this);
  11148. // If we are forcing it to begin at 0, but 0 will already be rendered on the chart,
  11149. // do nothing since that would make the chart weird. If the user really wants a weird chart
  11150. // axis, they can manually override it
  11151. if (this.options.ticks.beginAtZero) {
  11152. var minSign = helpers.sign(this.min);
  11153. var maxSign = helpers.sign(this.max);
  11154. if (minSign < 0 && maxSign < 0) {
  11155. // move the top up to 0
  11156. this.max = 0;
  11157. } else if (minSign > 0 && maxSign > 0) {
  11158. // move the botttom down to 0
  11159. this.min = 0;
  11160. }
  11161. }
  11162. if (this.options.ticks.min !== undefined) {
  11163. this.min = this.options.ticks.min;
  11164. } else if (this.options.ticks.suggestedMin !== undefined) {
  11165. this.min = Math.min(this.min, this.options.ticks.suggestedMin);
  11166. }
  11167. if (this.options.ticks.max !== undefined) {
  11168. this.max = this.options.ticks.max;
  11169. } else if (this.options.ticks.suggestedMax !== undefined) {
  11170. this.max = Math.max(this.max, this.options.ticks.suggestedMax);
  11171. }
  11172. if (this.min === this.max) {
  11173. this.min--;
  11174. this.max++;
  11175. }
  11176. },
  11177. buildTicks: function() {
  11178. this.ticks = [];
  11179. // Figure out what the max number of ticks we can support it is based on the size of
  11180. // the axis area. For now, we say that the minimum tick spacing in pixels must be 50
  11181. // We also limit the maximum number of ticks to 11 which gives a nice 10 squares on
  11182. // the graph
  11183. var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, globalDefaults.defaultFontSize);
  11184. var maxTicks = Math.min(this.options.ticks.maxTicksLimit ? this.options.ticks.maxTicksLimit : 11, Math.ceil(this.drawingArea / (1.5 * tickFontSize)));
  11185. maxTicks = Math.max(2, maxTicks); // Make sure we always have at least 2 ticks
  11186. // To get a "nice" value for the tick spacing, we will use the appropriately named
  11187. // "nice number" algorithm. See http://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks
  11188. // for details.
  11189. var niceRange = helpers.niceNum(this.max - this.min, false);
  11190. var spacing = helpers.niceNum(niceRange / (maxTicks - 1), true);
  11191. var niceMin = Math.floor(this.min / spacing) * spacing;
  11192. var niceMax = Math.ceil(this.max / spacing) * spacing;
  11193. var numSpaces = Math.ceil((niceMax - niceMin) / spacing);
  11194. // Put the values into the ticks array
  11195. this.ticks.push(this.options.ticks.min !== undefined ? this.options.ticks.min : niceMin);
  11196. for (var j = 1; j < numSpaces; ++j) {
  11197. this.ticks.push(niceMin + (j * spacing));
  11198. }
  11199. this.ticks.push(this.options.ticks.max !== undefined ? this.options.ticks.max : niceMax);
  11200. // At this point, we need to update our max and min given the tick values since we have expanded the
  11201. // range of the scale
  11202. this.max = helpers.max(this.ticks);
  11203. this.min = helpers.min(this.ticks);
  11204. if (this.options.ticks.reverse) {
  11205. this.ticks.reverse();
  11206. this.start = this.max;
  11207. this.end = this.min;
  11208. } else {
  11209. this.start = this.min;
  11210. this.end = this.max;
  11211. }
  11212. this.zeroLineIndex = this.ticks.indexOf(0);
  11213. },
  11214. convertTicksToLabels: function() {
  11215. Chart.Scale.prototype.convertTicksToLabels.call(this);
  11216. // Point labels
  11217. this.pointLabels = this.chart.data.labels.map(this.options.pointLabels.callback, this);
  11218. },
  11219. getLabelForIndex: function(index, datasetIndex) {
  11220. return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  11221. },
  11222. fit: function() {
  11223. /*
  11224. * Right, this is really confusing and there is a lot of maths going on here
  11225. * The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe9
  11226. *
  11227. * Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif
  11228. *
  11229. * Solution:
  11230. *
  11231. * We assume the radius of the polygon is half the size of the canvas at first
  11232. * at each index we check if the text overlaps.
  11233. *
  11234. * Where it does, we store that angle and that index.
  11235. *
  11236. * After finding the largest index and angle we calculate how much we need to remove
  11237. * from the shape radius to move the point inwards by that x.
  11238. *
  11239. * We average the left and right distances to get the maximum shape radius that can fit in the box
  11240. * along with labels.
  11241. *
  11242. * Once we have that, we can find the centre point for the chart, by taking the x text protrusion
  11243. * on each side, removing that from the size, halving it and adding the left x protrusion width.
  11244. *
  11245. * This will mean we have a shape fitted to the canvas, as large as it can be with the labels
  11246. * and position it in the most space efficient manner
  11247. *
  11248. * https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif
  11249. */
  11250. var pointLabels = this.options.pointLabels;
  11251. var pointLabelFontSize = helpers.getValueOrDefault(pointLabels.fontSize, globalDefaults.defaultFontSize);
  11252. var pointLabeFontStyle = helpers.getValueOrDefault(pointLabels.fontStyle, globalDefaults.defaultFontStyle);
  11253. var pointLabeFontFamily = helpers.getValueOrDefault(pointLabels.fontFamily, globalDefaults.defaultFontFamily);
  11254. var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
  11255. // Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.
  11256. // Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points
  11257. var largestPossibleRadius = helpers.min([(this.height / 2 - pointLabelFontSize - 5), this.width / 2]),
  11258. pointPosition,
  11259. i,
  11260. textWidth,
  11261. halfTextWidth,
  11262. furthestRight = this.width,
  11263. furthestRightIndex,
  11264. furthestRightAngle,
  11265. furthestLeft = 0,
  11266. furthestLeftIndex,
  11267. furthestLeftAngle,
  11268. xProtrusionLeft,
  11269. xProtrusionRight,
  11270. radiusReductionRight,
  11271. radiusReductionLeft,
  11272. maxWidthRadius;
  11273. this.ctx.font = pointLabeFont;
  11274. for (i = 0; i < this.getValueCount(); i++) {
  11275. // 5px to space the text slightly out - similar to what we do in the draw function.
  11276. pointPosition = this.getPointPosition(i, largestPossibleRadius);
  11277. textWidth = this.ctx.measureText(this.pointLabels[i] ? this.pointLabels[i] : '').width + 5;
  11278. if (i === 0 || i === this.getValueCount() / 2) {
  11279. // If we're at index zero, or exactly the middle, we're at exactly the top/bottom
  11280. // of the radar chart, so text will be aligned centrally, so we'll half it and compare
  11281. // w/left and right text sizes
  11282. halfTextWidth = textWidth / 2;
  11283. if (pointPosition.x + halfTextWidth > furthestRight) {
  11284. furthestRight = pointPosition.x + halfTextWidth;
  11285. furthestRightIndex = i;
  11286. }
  11287. if (pointPosition.x - halfTextWidth < furthestLeft) {
  11288. furthestLeft = pointPosition.x - halfTextWidth;
  11289. furthestLeftIndex = i;
  11290. }
  11291. } else if (i < this.getValueCount() / 2) {
  11292. // Less than half the values means we'll left align the text
  11293. if (pointPosition.x + textWidth > furthestRight) {
  11294. furthestRight = pointPosition.x + textWidth;
  11295. furthestRightIndex = i;
  11296. }
  11297. } else if (i > this.getValueCount() / 2) {
  11298. // More than half the values means we'll right align the text
  11299. if (pointPosition.x - textWidth < furthestLeft) {
  11300. furthestLeft = pointPosition.x - textWidth;
  11301. furthestLeftIndex = i;
  11302. }
  11303. }
  11304. }
  11305. xProtrusionLeft = furthestLeft;
  11306. xProtrusionRight = Math.ceil(furthestRight - this.width);
  11307. furthestRightAngle = this.getIndexAngle(furthestRightIndex);
  11308. furthestLeftAngle = this.getIndexAngle(furthestLeftIndex);
  11309. radiusReductionRight = xProtrusionRight / Math.sin(furthestRightAngle + Math.PI / 2);
  11310. radiusReductionLeft = xProtrusionLeft / Math.sin(furthestLeftAngle + Math.PI / 2);
  11311. // Ensure we actually need to reduce the size of the chart
  11312. radiusReductionRight = (helpers.isNumber(radiusReductionRight)) ? radiusReductionRight : 0;
  11313. radiusReductionLeft = (helpers.isNumber(radiusReductionLeft)) ? radiusReductionLeft : 0;
  11314. this.drawingArea = Math.round(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2);
  11315. this.setCenterPoint(radiusReductionLeft, radiusReductionRight);
  11316. },
  11317. setCenterPoint: function(leftMovement, rightMovement) {
  11318. var maxRight = this.width - rightMovement - this.drawingArea,
  11319. maxLeft = leftMovement + this.drawingArea;
  11320. this.xCenter = Math.round(((maxLeft + maxRight) / 2) + this.left);
  11321. // Always vertically in the centre as the text height doesn't change
  11322. this.yCenter = Math.round((this.height / 2) + this.top);
  11323. },
  11324. getIndexAngle: function(index) {
  11325. var angleMultiplier = (Math.PI * 2) / this.getValueCount();
  11326. // Start from the top instead of right, so remove a quarter of the circle
  11327. return index * angleMultiplier - (Math.PI / 2);
  11328. },
  11329. getDistanceFromCenterForValue: function(value) {
  11330. if (value === null) {
  11331. return 0; // null always in center
  11332. }
  11333. // Take into account half font size + the yPadding of the top value
  11334. var scalingFactor = this.drawingArea / (this.max - this.min);
  11335. if (this.options.reverse) {
  11336. return (this.max - value) * scalingFactor;
  11337. } else {
  11338. return (value - this.min) * scalingFactor;
  11339. }
  11340. },
  11341. getPointPosition: function(index, distanceFromCenter) {
  11342. var thisAngle = this.getIndexAngle(index);
  11343. return {
  11344. x: Math.round(Math.cos(thisAngle) * distanceFromCenter) + this.xCenter,
  11345. y: Math.round(Math.sin(thisAngle) * distanceFromCenter) + this.yCenter
  11346. };
  11347. },
  11348. getPointPositionForValue: function(index, value) {
  11349. return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
  11350. },
  11351. getBasePosition: function() {
  11352. var me = this;
  11353. var min = me.min;
  11354. var max = me.max;
  11355. return me.getPointPositionForValue(0,
  11356. me.beginAtZero? 0:
  11357. min < 0 && max < 0? max :
  11358. min > 0 && max > 0? min :
  11359. 0);
  11360. },
  11361. draw: function() {
  11362. if (this.options.display) {
  11363. var ctx = this.ctx;
  11364. helpers.each(this.ticks, function(label, index) {
  11365. // Don't draw a centre value (if it is minimum)
  11366. if (index > 0 || this.options.reverse) {
  11367. var yCenterOffset = this.getDistanceFromCenterForValue(this.ticks[index]);
  11368. var yHeight = this.yCenter - yCenterOffset;
  11369. // Draw circular lines around the scale
  11370. if (this.options.gridLines.display) {
  11371. ctx.strokeStyle = this.options.gridLines.color;
  11372. ctx.lineWidth = this.options.gridLines.lineWidth;
  11373. if (this.options.lineArc) {
  11374. // Draw circular arcs between the points
  11375. ctx.beginPath();
  11376. ctx.arc(this.xCenter, this.yCenter, yCenterOffset, 0, Math.PI * 2);
  11377. ctx.closePath();
  11378. ctx.stroke();
  11379. } else {
  11380. // Draw straight lines connecting each index
  11381. ctx.beginPath();
  11382. for (var i = 0; i < this.getValueCount(); i++) {
  11383. var pointPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.ticks[index]));
  11384. if (i === 0) {
  11385. ctx.moveTo(pointPosition.x, pointPosition.y);
  11386. } else {
  11387. ctx.lineTo(pointPosition.x, pointPosition.y);
  11388. }
  11389. }
  11390. ctx.closePath();
  11391. ctx.stroke();
  11392. }
  11393. }
  11394. if (this.options.ticks.display) {
  11395. var tickFontColor = helpers.getValueOrDefault(this.options.ticks.fontColor, globalDefaults.defaultFontColor);
  11396. var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, globalDefaults.defaultFontSize);
  11397. var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, globalDefaults.defaultFontStyle);
  11398. var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, globalDefaults.defaultFontFamily);
  11399. var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  11400. ctx.font = tickLabelFont;
  11401. if (this.options.ticks.showLabelBackdrop) {
  11402. var labelWidth = ctx.measureText(label).width;
  11403. ctx.fillStyle = this.options.ticks.backdropColor;
  11404. ctx.fillRect(
  11405. this.xCenter - labelWidth / 2 - this.options.ticks.backdropPaddingX,
  11406. yHeight - tickFontSize / 2 - this.options.ticks.backdropPaddingY,
  11407. labelWidth + this.options.ticks.backdropPaddingX * 2,
  11408. tickFontSize + this.options.ticks.backdropPaddingY * 2
  11409. );
  11410. }
  11411. ctx.textAlign = 'center';
  11412. ctx.textBaseline = "middle";
  11413. ctx.fillStyle = tickFontColor;
  11414. ctx.fillText(label, this.xCenter, yHeight);
  11415. }
  11416. }
  11417. }, this);
  11418. if (!this.options.lineArc) {
  11419. ctx.lineWidth = this.options.angleLines.lineWidth;
  11420. ctx.strokeStyle = this.options.angleLines.color;
  11421. for (var i = this.getValueCount() - 1; i >= 0; i--) {
  11422. if (this.options.angleLines.display) {
  11423. var outerPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max));
  11424. ctx.beginPath();
  11425. ctx.moveTo(this.xCenter, this.yCenter);
  11426. ctx.lineTo(outerPosition.x, outerPosition.y);
  11427. ctx.stroke();
  11428. ctx.closePath();
  11429. }
  11430. // Extra 3px out for some label spacing
  11431. var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);
  11432. var pointLabelFontColor = helpers.getValueOrDefault(this.options.pointLabels.fontColor, globalDefaults.defaultFontColor);
  11433. var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, globalDefaults.defaultFontSize);
  11434. var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, globalDefaults.defaultFontStyle);
  11435. var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, globalDefaults.defaultFontFamily);
  11436. var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
  11437. ctx.font = pointLabeFont;
  11438. ctx.fillStyle = pointLabelFontColor;
  11439. var labelsCount = this.pointLabels.length,
  11440. halfLabelsCount = this.pointLabels.length / 2,
  11441. quarterLabelsCount = halfLabelsCount / 2,
  11442. upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
  11443. exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
  11444. if (i === 0) {
  11445. ctx.textAlign = 'center';
  11446. } else if (i === halfLabelsCount) {
  11447. ctx.textAlign = 'center';
  11448. } else if (i < halfLabelsCount) {
  11449. ctx.textAlign = 'left';
  11450. } else {
  11451. ctx.textAlign = 'right';
  11452. }
  11453. // Set the correct text baseline based on outer positioning
  11454. if (exactQuarter) {
  11455. ctx.textBaseline = 'middle';
  11456. } else if (upperHalf) {
  11457. ctx.textBaseline = 'bottom';
  11458. } else {
  11459. ctx.textBaseline = 'top';
  11460. }
  11461. ctx.fillText(this.pointLabels[i] ? this.pointLabels[i] : '', pointLabelPosition.x, pointLabelPosition.y);
  11462. }
  11463. }
  11464. }
  11465. }
  11466. });
  11467. Chart.scaleService.registerScaleType("radialLinear", LinearRadialScale, defaultConfig);
  11468. };
  11469. },{}],42:[function(require,module,exports){
  11470. /*global window: false */
  11471. "use strict";
  11472. var moment = require('moment');
  11473. moment = typeof(moment) === 'function' ? moment : window.moment;
  11474. module.exports = function(Chart) {
  11475. var helpers = Chart.helpers;
  11476. var time = {
  11477. units: [{
  11478. name: 'millisecond',
  11479. steps: [1, 2, 5, 10, 20, 50, 100, 250, 500]
  11480. }, {
  11481. name: 'second',
  11482. steps: [1, 2, 5, 10, 30]
  11483. }, {
  11484. name: 'minute',
  11485. steps: [1, 2, 5, 10, 30]
  11486. }, {
  11487. name: 'hour',
  11488. steps: [1, 2, 3, 6, 12]
  11489. }, {
  11490. name: 'day',
  11491. steps: [1, 2, 5]
  11492. }, {
  11493. name: 'week',
  11494. maxStep: 4
  11495. }, {
  11496. name: 'month',
  11497. maxStep: 3
  11498. }, {
  11499. name: 'quarter',
  11500. maxStep: 4
  11501. }, {
  11502. name: 'year',
  11503. maxStep: false
  11504. }]
  11505. };
  11506. var defaultConfig = {
  11507. position: "bottom",
  11508. time: {
  11509. parser: false, // false == a pattern string from http://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment
  11510. format: false, // DEPRECATED false == date objects, moment object, callback or a pattern string from http://momentjs.com/docs/#/parsing/string-format/
  11511. unit: false, // false == automatic or override with week, month, year, etc.
  11512. round: false, // none, or override with week, month, year, etc.
  11513. displayFormat: false, // DEPRECATED
  11514. isoWeekday: false, // override week start day - see http://momentjs.com/docs/#/get-set/iso-weekday/
  11515. // defaults to unit's corresponding unitFormat below or override using pattern string from http://momentjs.com/docs/#/displaying/format/
  11516. displayFormats: {
  11517. 'millisecond': 'h:mm:ss.SSS a', // 11:20:01.123 AM,
  11518. 'second': 'h:mm:ss a', // 11:20:01 AM
  11519. 'minute': 'h:mm:ss a', // 11:20:01 AM
  11520. 'hour': 'MMM D, hA', // Sept 4, 5PM
  11521. 'day': 'll', // Sep 4 2015
  11522. 'week': 'll', // Week 46, or maybe "[W]WW - YYYY" ?
  11523. 'month': 'MMM YYYY', // Sept 2015
  11524. 'quarter': '[Q]Q - YYYY', // Q3
  11525. 'year': 'YYYY' // 2015
  11526. }
  11527. },
  11528. ticks: {
  11529. autoSkip: false
  11530. }
  11531. };
  11532. var TimeScale = Chart.Scale.extend({
  11533. initialize: function() {
  11534. if (!moment) {
  11535. throw new Error('Chart.js - Moment.js could not be found! You must include it before Chart.js to use the time scale. Download at https://momentjs.com');
  11536. }
  11537. Chart.Scale.prototype.initialize.call(this);
  11538. },
  11539. getLabelMoment: function(datasetIndex, index) {
  11540. return this.labelMoments[datasetIndex][index];
  11541. },
  11542. getMomentStartOf: function(tick) {
  11543. if (this.options.time.unit === 'week' && this.options.time.isoWeekday !== false) {
  11544. return tick.clone().startOf('isoWeek').isoWeekday(this.options.time.isoWeekday);
  11545. } else {
  11546. return tick.clone().startOf(this.tickUnit);
  11547. }
  11548. },
  11549. determineDataLimits: function() {
  11550. this.labelMoments = [];
  11551. // Only parse these once. If the dataset does not have data as x,y pairs, we will use
  11552. // these
  11553. var scaleLabelMoments = [];
  11554. if (this.chart.data.labels && this.chart.data.labels.length > 0) {
  11555. helpers.each(this.chart.data.labels, function(label, index) {
  11556. var labelMoment = this.parseTime(label);
  11557. if (labelMoment.isValid()) {
  11558. if (this.options.time.round) {
  11559. labelMoment.startOf(this.options.time.round);
  11560. }
  11561. scaleLabelMoments.push(labelMoment);
  11562. }
  11563. }, this);
  11564. this.firstTick = moment.min.call(this, scaleLabelMoments);
  11565. this.lastTick = moment.max.call(this, scaleLabelMoments);
  11566. } else {
  11567. this.firstTick = null;
  11568. this.lastTick = null;
  11569. }
  11570. helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
  11571. var momentsForDataset = [];
  11572. var datasetVisible = this.chart.isDatasetVisible(datasetIndex);
  11573. if (typeof dataset.data[0] === 'object' && dataset.data[0] !== null) {
  11574. helpers.each(dataset.data, function(value, index) {
  11575. var labelMoment = this.parseTime(this.getRightValue(value));
  11576. if (labelMoment.isValid()) {
  11577. if (this.options.time.round) {
  11578. labelMoment.startOf(this.options.time.round);
  11579. }
  11580. momentsForDataset.push(labelMoment);
  11581. if (datasetVisible) {
  11582. // May have gone outside the scale ranges, make sure we keep the first and last ticks updated
  11583. this.firstTick = this.firstTick !== null ? moment.min(this.firstTick, labelMoment) : labelMoment;
  11584. this.lastTick = this.lastTick !== null ? moment.max(this.lastTick, labelMoment) : labelMoment;
  11585. }
  11586. }
  11587. }, this);
  11588. } else {
  11589. // We have no labels. Use the ones from the scale
  11590. momentsForDataset = scaleLabelMoments;
  11591. }
  11592. this.labelMoments.push(momentsForDataset);
  11593. }, this);
  11594. // Set these after we've done all the data
  11595. if (this.options.time.min) {
  11596. this.firstTick = this.parseTime(this.options.time.min);
  11597. }
  11598. if (this.options.time.max) {
  11599. this.lastTick = this.parseTime(this.options.time.max);
  11600. }
  11601. // We will modify these, so clone for later
  11602. this.firstTick = (this.firstTick || moment()).clone();
  11603. this.lastTick = (this.lastTick || moment()).clone();
  11604. },
  11605. buildTicks: function(index) {
  11606. this.ctx.save();
  11607. var tickFontSize = helpers.getValueOrDefault(this.options.ticks.fontSize, Chart.defaults.global.defaultFontSize);
  11608. var tickFontStyle = helpers.getValueOrDefault(this.options.ticks.fontStyle, Chart.defaults.global.defaultFontStyle);
  11609. var tickFontFamily = helpers.getValueOrDefault(this.options.ticks.fontFamily, Chart.defaults.global.defaultFontFamily);
  11610. var tickLabelFont = helpers.fontString(tickFontSize, tickFontStyle, tickFontFamily);
  11611. this.ctx.font = tickLabelFont;
  11612. this.ticks = [];
  11613. this.unitScale = 1; // How much we scale the unit by, ie 2 means 2x unit per step
  11614. this.scaleSizeInUnits = 0; // How large the scale is in the base unit (seconds, minutes, etc)
  11615. // Set unit override if applicable
  11616. if (this.options.time.unit) {
  11617. this.tickUnit = this.options.time.unit || 'day';
  11618. this.displayFormat = this.options.time.displayFormats[this.tickUnit];
  11619. this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
  11620. this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, 1);
  11621. } else {
  11622. // Determine the smallest needed unit of the time
  11623. var innerWidth = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
  11624. // Crude approximation of what the label length might be
  11625. var tempFirstLabel = this.tickFormatFunction(this.firstTick, 0, []);
  11626. var tickLabelWidth = this.ctx.measureText(tempFirstLabel).width;
  11627. var cosRotation = Math.cos(helpers.toRadians(this.options.ticks.maxRotation));
  11628. var sinRotation = Math.sin(helpers.toRadians(this.options.ticks.maxRotation));
  11629. tickLabelWidth = (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation);
  11630. var labelCapacity = innerWidth / (tickLabelWidth);
  11631. // Start as small as possible
  11632. this.tickUnit = 'millisecond';
  11633. this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
  11634. this.displayFormat = this.options.time.displayFormats[this.tickUnit];
  11635. var unitDefinitionIndex = 0;
  11636. var unitDefinition = time.units[unitDefinitionIndex];
  11637. // While we aren't ideal and we don't have units left
  11638. while (unitDefinitionIndex < time.units.length) {
  11639. // Can we scale this unit. If `false` we can scale infinitely
  11640. this.unitScale = 1;
  11641. if (helpers.isArray(unitDefinition.steps) && Math.ceil(this.scaleSizeInUnits / labelCapacity) < helpers.max(unitDefinition.steps)) {
  11642. // Use one of the prefedined steps
  11643. for (var idx = 0; idx < unitDefinition.steps.length; ++idx) {
  11644. if (unitDefinition.steps[idx] >= Math.ceil(this.scaleSizeInUnits / labelCapacity)) {
  11645. this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, unitDefinition.steps[idx]);
  11646. break;
  11647. }
  11648. }
  11649. break;
  11650. } else if ((unitDefinition.maxStep === false) || (Math.ceil(this.scaleSizeInUnits / labelCapacity) < unitDefinition.maxStep)) {
  11651. // We have a max step. Scale this unit
  11652. this.unitScale = helpers.getValueOrDefault(this.options.time.unitStepSize, Math.ceil(this.scaleSizeInUnits / labelCapacity));
  11653. break;
  11654. } else {
  11655. // Move to the next unit up
  11656. ++unitDefinitionIndex;
  11657. unitDefinition = time.units[unitDefinitionIndex];
  11658. this.tickUnit = unitDefinition.name;
  11659. var leadingUnitBuffer = this.firstTick.diff(this.getMomentStartOf(this.firstTick), this.tickUnit, true);
  11660. var trailingUnitBuffer = this.getMomentStartOf(this.lastTick.clone().add(1, this.tickUnit)).diff(this.lastTick, this.tickUnit, true);
  11661. this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true) + leadingUnitBuffer + trailingUnitBuffer;
  11662. this.displayFormat = this.options.time.displayFormats[unitDefinition.name];
  11663. }
  11664. }
  11665. }
  11666. var roundedStart;
  11667. // Only round the first tick if we have no hard minimum
  11668. if (!this.options.time.min) {
  11669. this.firstTick = this.getMomentStartOf(this.firstTick);
  11670. roundedStart = this.firstTick;
  11671. } else {
  11672. roundedStart = this.getMomentStartOf(this.firstTick);
  11673. }
  11674. // Only round the last tick if we have no hard maximum
  11675. if (!this.options.time.max) {
  11676. var roundedEnd = this.getMomentStartOf(this.lastTick);
  11677. if (roundedEnd.diff(this.lastTick, this.tickUnit, true) !== 0) {
  11678. // Do not use end of because we need this to be in the next time unit
  11679. this.lastTick = this.getMomentStartOf(this.lastTick.add(1, this.tickUnit));
  11680. }
  11681. }
  11682. this.smallestLabelSeparation = this.width;
  11683. helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) {
  11684. for (var i = 1; i < this.labelMoments[datasetIndex].length; i++) {
  11685. this.smallestLabelSeparation = Math.min(this.smallestLabelSeparation, this.labelMoments[datasetIndex][i].diff(this.labelMoments[datasetIndex][i - 1], this.tickUnit, true));
  11686. }
  11687. }, this);
  11688. // Tick displayFormat override
  11689. if (this.options.time.displayFormat) {
  11690. this.displayFormat = this.options.time.displayFormat;
  11691. }
  11692. // first tick. will have been rounded correctly if options.time.min is not specified
  11693. this.ticks.push(this.firstTick.clone());
  11694. // For every unit in between the first and last moment, create a moment and add it to the ticks tick
  11695. for (var i = 1; i <= this.scaleSizeInUnits; ++i) {
  11696. var newTick = roundedStart.clone().add(i, this.tickUnit);
  11697. // Are we greater than the max time
  11698. if (this.options.time.max && newTick.diff(this.lastTick, this.tickUnit, true) >= 0) {
  11699. break;
  11700. }
  11701. if (i % this.unitScale === 0) {
  11702. this.ticks.push(newTick);
  11703. }
  11704. }
  11705. // Always show the right tick
  11706. var diff = this.ticks[this.ticks.length - 1].diff(this.lastTick, this.tickUnit);
  11707. if (diff !== 0 || this.scaleSizeInUnits === 0) {
  11708. // this is a weird case. If the <max> option is the same as the end option, we can't just diff the times because the tick was created from the roundedStart
  11709. // but the last tick was not rounded.
  11710. if (this.options.time.max) {
  11711. this.ticks.push(this.lastTick.clone());
  11712. this.scaleSizeInUnits = this.lastTick.diff(this.ticks[0], this.tickUnit, true);
  11713. } else {
  11714. this.ticks.push(this.lastTick.clone());
  11715. this.scaleSizeInUnits = this.lastTick.diff(this.firstTick, this.tickUnit, true);
  11716. }
  11717. }
  11718. this.ctx.restore();
  11719. },
  11720. // Get tooltip label
  11721. getLabelForIndex: function(index, datasetIndex) {
  11722. var label = this.chart.data.labels && index < this.chart.data.labels.length ? this.chart.data.labels[index] : '';
  11723. if (typeof this.chart.data.datasets[datasetIndex].data[0] === 'object') {
  11724. label = this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);
  11725. }
  11726. // Format nicely
  11727. if (this.options.time.tooltipFormat) {
  11728. label = this.parseTime(label).format(this.options.time.tooltipFormat);
  11729. }
  11730. return label;
  11731. },
  11732. // Function to format an individual tick mark
  11733. tickFormatFunction: function tickFormatFunction(tick, index, ticks) {
  11734. var formattedTick = tick.format(this.displayFormat);
  11735. var tickOpts = this.options.ticks;
  11736. var callback = helpers.getValueOrDefault(tickOpts.callback, tickOpts.userCallback);
  11737. if (callback) {
  11738. return callback(formattedTick, index, ticks);
  11739. } else {
  11740. return formattedTick;
  11741. }
  11742. },
  11743. convertTicksToLabels: function() {
  11744. this.tickMoments = this.ticks;
  11745. this.ticks = this.ticks.map(this.tickFormatFunction, this);
  11746. },
  11747. getPixelForValue: function(value, index, datasetIndex, includeOffset) {
  11748. var labelMoment = value && value.isValid && value.isValid() ? value : this.getLabelMoment(datasetIndex, index);
  11749. if (labelMoment) {
  11750. var offset = labelMoment.diff(this.firstTick, this.tickUnit, true);
  11751. var decimal = offset / this.scaleSizeInUnits;
  11752. if (this.isHorizontal()) {
  11753. var innerWidth = this.width - (this.paddingLeft + this.paddingRight);
  11754. var valueWidth = innerWidth / Math.max(this.ticks.length - 1, 1);
  11755. var valueOffset = (innerWidth * decimal) + this.paddingLeft;
  11756. return this.left + Math.round(valueOffset);
  11757. } else {
  11758. var innerHeight = this.height - (this.paddingTop + this.paddingBottom);
  11759. var valueHeight = innerHeight / Math.max(this.ticks.length - 1, 1);
  11760. var heightOffset = (innerHeight * decimal) + this.paddingTop;
  11761. return this.top + Math.round(heightOffset);
  11762. }
  11763. }
  11764. },
  11765. getPixelForTick: function(index, includeOffset) {
  11766. return this.getPixelForValue(this.tickMoments[index], null, null, includeOffset);
  11767. },
  11768. getValueForPixel: function(pixel) {
  11769. var innerDimension = this.isHorizontal() ? this.width - (this.paddingLeft + this.paddingRight) : this.height - (this.paddingTop + this.paddingBottom);
  11770. var offset = (pixel - (this.isHorizontal() ? this.left + this.paddingLeft : this.top + this.paddingTop)) / innerDimension;
  11771. offset *= this.scaleSizeInUnits;
  11772. return this.firstTick.clone().add(moment.duration(offset, this.tickUnit).asSeconds(), 'seconds');
  11773. },
  11774. parseTime: function(label) {
  11775. if (typeof this.options.time.parser === 'string') {
  11776. return moment(label, this.options.time.parser);
  11777. }
  11778. if (typeof this.options.time.parser === 'function') {
  11779. return this.options.time.parser(label);
  11780. }
  11781. // Date objects
  11782. if (typeof label.getMonth === 'function' || typeof label === 'number') {
  11783. return moment(label);
  11784. }
  11785. // Moment support
  11786. if (label.isValid && label.isValid()) {
  11787. return label;
  11788. }
  11789. // Custom parsing (return an instance of moment)
  11790. if (typeof this.options.time.format !== 'string' && this.options.time.format.call) {
  11791. console.warn("options.time.format is deprecated and replaced by options.time.parser. See http://nnnick.github.io/Chart.js/docs-v2/#scales-time-scale");
  11792. return this.options.time.format(label);
  11793. }
  11794. // Moment format parsing
  11795. return moment(label, this.options.time.format);
  11796. }
  11797. });
  11798. Chart.scaleService.registerScaleType("time", TimeScale, defaultConfig);
  11799. };
  11800. },{"moment":6}]},{},[7]);