highcharts.src.js.soonsu 185 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661
  1. (function() {
  2. var doc = document,
  3. win = window,
  4. math = Math,
  5. mathRound = math.round,
  6. mathFloor = math.floor,
  7. mathCeil = math.ceil,
  8. mathMax = math.max,
  9. mathMin = math.min,
  10. mathAbs = math.abs,
  11. mathCos = math.cos,
  12. mathSin = math.sin,
  13. mathPI = math.PI,
  14. deg2rad = mathPI * 2 / 360,
  15. userAgent = navigator.userAgent,
  16. isIE = /msie/i.test(userAgent) && !win.opera,
  17. docMode8 = doc.documentMode == 8,
  18. isWebKit = /AppleWebKit/.test(userAgent),
  19. isFirefox = /Firefox/.test(userAgent),
  20. hasSVG = !!doc.createElementNS && !!doc.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect,
  21. SVG_NS = 'http://www.w3.org/2000/svg',
  22. hasTouch = 'ontouchstart' in doc.documentElement,
  23. colorCounter,
  24. symbolCounter,
  25. symbolSizes = {},
  26. idCounter = 0,
  27. timeFactor = 1,
  28. garbageBin,
  29. defaultOptions,
  30. dateFormat,
  31. globalAnimation,
  32. pathAnim,
  33. UNDEFINED,
  34. DIV = 'div',
  35. ABSOLUTE = 'absolute',
  36. RELATIVE = 'relative',
  37. HIDDEN = 'hidden',
  38. PREFIX = 'highcharts-',
  39. VISIBLE = 'visible',
  40. PX = 'px',
  41. NONE = 'none',
  42. M = 'M',
  43. L = 'L',
  44. TRACKER_FILL = 'rgba(192,192,192,'+ (hasSVG ? 0.000001 : 0.002) +')',
  45. NORMAL_STATE = '',
  46. HOVER_STATE = 'hover',
  47. SELECT_STATE = 'select',
  48. makeTime,
  49. getMinutes,
  50. getHours,
  51. getDay,
  52. getDate,
  53. getMonth,
  54. getFullYear,
  55. setMinutes,
  56. setHours,
  57. setDate,
  58. setMonth,
  59. setFullYear,
  60. globalAdapter = win.HighchartsAdapter,
  61. adapter = globalAdapter || {},
  62. each = adapter.each,
  63. grep = adapter.grep,
  64. map = adapter.map,
  65. merge = adapter.merge,
  66. hyphenate = adapter.hyphenate,
  67. addEvent = adapter.addEvent,
  68. removeEvent = adapter.removeEvent,
  69. fireEvent = adapter.fireEvent,
  70. animate = adapter.animate,
  71. stop = adapter.stop,
  72. seriesTypes = {},
  73. hoverChart;
  74. function extend(a, b) {
  75. if (!a) {
  76. a = {};
  77. }
  78. for (var n in b) {
  79. a[n] = b[n];
  80. }
  81. return a;
  82. }
  83. function pInt(s, mag) {
  84. return parseInt(s, mag || 10);
  85. }
  86. function isString(s) {
  87. return typeof s == 'string';
  88. }
  89. function isObject(obj) {
  90. return typeof obj == 'object';
  91. }
  92. function isNumber(n) {
  93. return typeof n == 'number';
  94. }
  95. function erase(arr, item) {
  96. var i = arr.length;
  97. while (i--) {
  98. if (arr[i] == item) {
  99. arr.splice(i, 1);
  100. break;
  101. }
  102. }
  103. }
  104. function defined (obj) {
  105. return obj !== UNDEFINED && obj !== null;
  106. }
  107. function attr(elem, prop, value) {
  108. var key,
  109. setAttribute = 'setAttribute',
  110. ret;
  111. if (isString(prop)) {
  112. if (defined(value)) {
  113. elem[setAttribute](prop, value);
  114. } else if (elem && elem.getAttribute) {
  115. ret = elem.getAttribute(prop);
  116. }
  117. } else if (defined(prop) && isObject(prop)) {
  118. for (key in prop) {
  119. elem[setAttribute](key, prop[key]);
  120. }
  121. }
  122. return ret;
  123. }
  124. function splat(obj) {
  125. if (!obj || obj.constructor != Array) {
  126. obj = [obj];
  127. }
  128. return obj;
  129. }
  130. function pick() {
  131. var args = arguments,
  132. i,
  133. arg,
  134. length = args.length;
  135. for (i = 0; i < length; i++) {
  136. arg = args[i];
  137. if (typeof arg !== 'undefined' && arg !== null) {
  138. return arg;
  139. }
  140. }
  141. }
  142. function serializeCSS(style) {
  143. var s = '',
  144. key;
  145. for (key in style) {
  146. s += hyphenate(key) +':'+ style[key] + ';';
  147. }
  148. return s;
  149. }
  150. function css (el, styles) {
  151. if (isIE) {
  152. if (styles && styles.opacity !== UNDEFINED) {
  153. styles.filter = 'alpha(opacity='+ (styles.opacity * 100) +')';
  154. }
  155. }
  156. extend(el.style, styles);
  157. }
  158. function createElement (tag, attribs, styles, parent, nopad) {
  159. var el = doc.createElement(tag);
  160. if (attribs) {
  161. extend(el, attribs);
  162. }
  163. if (nopad) {
  164. css(el, {padding: 0, border: NONE, margin: 0});
  165. }
  166. if (styles) {
  167. css(el, styles);
  168. }
  169. if (parent) {
  170. parent.appendChild(el);
  171. }
  172. return el;
  173. }
  174. function setAnimation(animation, chart) {
  175. globalAnimation = pick(animation, chart.animation);
  176. }
  177. if (globalAdapter && globalAdapter.init) {
  178. globalAdapter.init();
  179. }
  180. if (!globalAdapter && win.jQuery) {
  181. var jQ = jQuery;
  182. each = function(arr, fn) {
  183. for (var i = 0, len = arr.length; i < len; i++) {
  184. if (fn.call(arr[i], arr[i], i, arr) === false) {
  185. return i;
  186. }
  187. }
  188. };
  189. grep = jQ.grep;
  190. map = function(arr, fn){
  191. var results = [];
  192. for (var i = 0, len = arr.length; i < len; i++) {
  193. results[i] = fn.call(arr[i], arr[i], i, arr);
  194. }
  195. return results;
  196. };
  197. merge = function(){
  198. var args = arguments;
  199. return jQ.extend(true, null, args[0], args[1], args[2], args[3]);
  200. };
  201. hyphenate = function (str) {
  202. return str.replace(/([A-Z])/g, function(a, b){ return '-'+ b.toLowerCase(); });
  203. };
  204. addEvent = function (el, event, fn){
  205. jQ(el).bind(event, fn);
  206. };
  207. removeEvent = function(el, eventType, handler) {
  208. var func = doc.removeEventListener ? 'removeEventListener' : 'detachEvent';
  209. if (doc[func] && !el[func]) {
  210. el[func] = function() {};
  211. }
  212. jQ(el).unbind(eventType, handler);
  213. };
  214. fireEvent = function(el, type, eventArguments, defaultFunction) {
  215. var m_event = jQ.Event(type),
  216. detachedType = 'detached'+ type;
  217. extend(event, eventArguments);
  218. if (el[type]) {
  219. el[detachedType] = el[type];
  220. el[type] = null;
  221. }
  222. jQ(el).trigger(m_event);
  223. if (el[detachedType]) {
  224. el[type] = el[detachedType];
  225. el[detachedType] = null;
  226. }
  227. if (defaultFunction && !m_event.isDefaultPrevented()) {
  228. defaultFunction(m_event);
  229. }
  230. };
  231. animate = function (el, params, options) {
  232. var $el = jQ(el);
  233. if (params.d) {
  234. el.toD = params.d;
  235. params.d = 1;
  236. }
  237. $el.stop();
  238. $el.animate(params, options);
  239. };
  240. stop = function (el) {
  241. jQ(el).stop();
  242. };
  243. jQ.extend( jQ.easing, {
  244. easeOutQuad: function (x, t, b, c, d) {
  245. return -c *(t/=d)*(t-2) + b;
  246. }
  247. });
  248. var oldStepDefault = jQuery.fx.step._default,
  249. oldCur = jQuery.fx.prototype.cur;
  250. jQ.fx.step._default = function(fx){
  251. var elem = fx.elem;
  252. if (elem.attr) {
  253. elem.attr(fx.prop, fx.now);
  254. } else {
  255. oldStepDefault.apply(this, arguments);
  256. }
  257. };
  258. jQ.fx.step.d = function(fx) {
  259. var elem = fx.elem;
  260. if (!fx.started) {
  261. var ends = pathAnim.init(elem, elem.d, elem.toD);
  262. fx.start = ends[0];
  263. fx.end = ends[1];
  264. fx.started = true;
  265. }
  266. elem.attr('d', pathAnim.step(fx.start, fx.end, fx.pos, elem.toD));
  267. };
  268. jQ.fx.prototype.cur = function() {
  269. var elem = this.elem,
  270. r;
  271. if (elem.attr) {
  272. r = elem.attr(this.prop);
  273. } else {
  274. r = oldCur.apply(this, arguments);
  275. }
  276. return r;
  277. };
  278. }
  279. pathAnim = {
  280. init: function(elem, fromD, toD) {
  281. fromD = fromD || '';
  282. var shift = elem.shift,
  283. bezier = fromD.indexOf('C') > -1,
  284. numParams = bezier ? 7 : 3,
  285. endLength,
  286. slice,
  287. i,
  288. start = fromD.split(' '),
  289. end = [].concat(toD),
  290. startBaseLine,
  291. endBaseLine,
  292. sixify = function(arr) {
  293. i = arr.length;
  294. while (i--) {
  295. if (arr[i] == M) {
  296. arr.splice(i + 1, 0, arr[i+1], arr[i+2], arr[i+1], arr[i+2]);
  297. }
  298. }
  299. };
  300. if (bezier) {
  301. sixify(start);
  302. sixify(end);
  303. }
  304. if (elem.isArea) {
  305. startBaseLine = start.splice(start.length - 6, 6);
  306. endBaseLine = end.splice(end.length - 6, 6);
  307. }
  308. if (shift) {
  309. end = [].concat(end).splice(0, numParams).concat(end);
  310. elem.shift = false;
  311. }
  312. if (start.length) {
  313. endLength = end.length;
  314. while (start.length < endLength) {
  315. slice = [].concat(start).splice(start.length - numParams, numParams);
  316. if (bezier) {
  317. slice[numParams - 6] = slice[numParams - 2];
  318. slice[numParams - 5] = slice[numParams - 1];
  319. }
  320. start = start.concat(slice);
  321. }
  322. }
  323. if (startBaseLine) {
  324. start = start.concat(startBaseLine);
  325. end = end.concat(endBaseLine);
  326. }
  327. return [start, end];
  328. },
  329. step: function(start, end, pos, complete) {
  330. var ret = [],
  331. i = start.length,
  332. startVal;
  333. if (pos == 1) {
  334. ret = complete;
  335. } else if (i == end.length && pos < 1) {
  336. while (i--) {
  337. startVal = parseFloat(start[i]);
  338. ret[i] =
  339. isNaN(startVal) ?
  340. start[i] :
  341. pos * (parseFloat(end[i] - startVal)) + startVal;
  342. }
  343. } else {
  344. ret = end;
  345. }
  346. return ret;
  347. }
  348. };
  349. function setTimeMethods() {
  350. var useUTC = defaultOptions.global.useUTC;
  351. makeTime = useUTC ? Date.UTC : function(year, month, date, hours, minutes, seconds) {
  352. return new Date(
  353. year,
  354. month,
  355. pick(date, 1),
  356. pick(hours, 0),
  357. pick(minutes, 0),
  358. pick(seconds, 0)
  359. ).getTime();
  360. };
  361. getMinutes = useUTC ? 'getUTCMinutes' : 'getMinutes';
  362. getHours = useUTC ? 'getUTCHours' : 'getHours';
  363. getDay = useUTC ? 'getUTCDay' : 'getDay';
  364. getDate = useUTC ? 'getUTCDate' : 'getDate';
  365. getMonth = useUTC ? 'getUTCMonth' : 'getMonth';
  366. getFullYear = useUTC ? 'getUTCFullYear' : 'getFullYear';
  367. setMinutes = useUTC ? 'setUTCMinutes' : 'setMinutes';
  368. setHours = useUTC ? 'setUTCHours' : 'setHours';
  369. setDate = useUTC ? 'setUTCDate' : 'setDate';
  370. setMonth = useUTC ? 'setUTCMonth' : 'setMonth';
  371. setFullYear = useUTC ? 'setUTCFullYear' : 'setFullYear';
  372. }
  373. function setOptions(options) {
  374. defaultOptions = merge(defaultOptions, options);
  375. setTimeMethods();
  376. return defaultOptions;
  377. }
  378. function getOptions() {
  379. return defaultOptions;
  380. }
  381. function discardElement(element) {
  382. if (!garbageBin) {
  383. garbageBin = createElement(DIV);
  384. }
  385. if (element) {
  386. garbageBin.appendChild(element);
  387. }
  388. garbageBin.innerHTML = '';
  389. }
  390. var
  391. defaultLabelOptions = {
  392. enabled: true,
  393. align: 'center',
  394. x: 0,
  395. y: 15,
  396. style: {
  397. color: '#666',
  398. fontSize: '11px',
  399. lineHeight: '14px'
  400. }
  401. };
  402. defaultOptions = {
  403. colors: ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE',
  404. '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92'],
  405. symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'],
  406. lang: {
  407. loading: 'Loading...',
  408. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July',
  409. 'August', 'September', 'October', 'November', 'December'],
  410. weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  411. decimalPoint: '.',
  412. resetZoom: 'Reset zoom',
  413. resetZoomTitle: 'Reset zoom level 1:1',
  414. thousandsSep: ','
  415. },
  416. global: {
  417. useUTC: true
  418. },
  419. chart: {
  420. borderColor: '#4572A7',
  421. borderRadius: 5,
  422. defaultSeriesType: 'line',
  423. ignoreHiddenSeries: true,
  424. spacingTop: 10,
  425. spacingRight: 10,
  426. spacingBottom: 15,
  427. spacingLeft: 10,
  428. style: {
  429. fontFamily: '"Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif',
  430. fontSize: '12px'
  431. },
  432. backgroundColor: '#FFFFFF',
  433. plotBorderColor: '#C0C0C0'
  434. },
  435. title: {
  436. text: 'Chart title',
  437. align: 'center',
  438. y: 15,
  439. style: {
  440. color: '#3E576F',
  441. fontSize: '16px'
  442. }
  443. },
  444. subtitle: {
  445. text: '',
  446. align: 'center',
  447. y: 30,
  448. style: {
  449. color: '#6D869F'
  450. }
  451. },
  452. plotOptions: {
  453. line: {
  454. allowPointSelect: false,
  455. showCheckbox: false,
  456. animation: {
  457. duration: 1000
  458. },
  459. events: {},
  460. lineWidth: 2,
  461. shadow: true,
  462. marker: {
  463. enabled: true,
  464. lineWidth: 0,
  465. radius: 4,
  466. lineColor: '#FFFFFF',
  467. states: {
  468. hover: {
  469. },
  470. select: {
  471. fillColor: '#FFFFFF',
  472. lineColor: '#000000',
  473. lineWidth: 2
  474. }
  475. }
  476. },
  477. point: {
  478. events: {}
  479. },
  480. dataLabels: merge(defaultLabelOptions, {
  481. enabled: false,
  482. y: -6,
  483. formatter: function() {
  484. return this.y;
  485. }
  486. }),
  487. showInLegend: true,
  488. states: {
  489. hover: {
  490. marker: {
  491. }
  492. },
  493. select: {
  494. marker: {}
  495. }
  496. },
  497. stickyTracking: true
  498. }
  499. },
  500. labels: {
  501. style: {
  502. position: ABSOLUTE,
  503. color: '#3E576F'
  504. }
  505. },
  506. legend: {
  507. enabled: true,
  508. align: 'center',
  509. layout: 'horizontal',
  510. labelFormatter: function() {
  511. return this.name;
  512. },
  513. borderWidth: 1,
  514. borderColor: '#909090',
  515. borderRadius: 5,
  516. shadow: false,
  517. style: {
  518. padding: '5px'
  519. },
  520. itemStyle: {
  521. cursor: 'pointer',
  522. color: '#3E576F'
  523. },
  524. itemHoverStyle: {
  525. cursor: 'pointer',
  526. color: '#000000'
  527. },
  528. itemHiddenStyle: {
  529. color: '#C0C0C0'
  530. },
  531. itemCheckboxStyle: {
  532. position: ABSOLUTE,
  533. width: '13px',
  534. height: '13px'
  535. },
  536. symbolWidth: 16,
  537. symbolPadding: 5,
  538. verticalAlign: 'bottom',
  539. x: 0,
  540. y: 0
  541. },
  542. loading: {
  543. hideDuration: 100,
  544. labelStyle: {
  545. fontWeight: 'bold',
  546. position: RELATIVE,
  547. top: '1em'
  548. },
  549. showDuration: 100,
  550. style: {
  551. position: ABSOLUTE,
  552. backgroundColor: 'white',
  553. opacity: 0.5,
  554. textAlign: 'center'
  555. }
  556. },
  557. tooltip: {
  558. enabled: true,
  559. backgroundColor: 'rgba(255, 255, 255, .85)',
  560. borderWidth: 2,
  561. borderRadius: 5,
  562. shadow: true,
  563. snap: hasTouch ? 25 : 10,
  564. style: {
  565. color: '#333333',
  566. fontSize: '12px',
  567. padding: '5px',
  568. whiteSpace: 'nowrap'
  569. }
  570. },
  571. toolbar: {
  572. itemStyle: {
  573. color: '#4572A7',
  574. cursor: 'pointer'
  575. }
  576. },
  577. credits: {
  578. enabled: true,
  579. text: 'Highcharts.com',
  580. href: 'http://www.highcharts.com',
  581. position: {
  582. align: 'right',
  583. x: -10,
  584. verticalAlign: 'bottom',
  585. y: -5
  586. },
  587. style: {
  588. cursor: 'pointer',
  589. color: '#909090',
  590. fontSize: '10px'
  591. }
  592. }
  593. };
  594. var defaultXAxisOptions = {
  595. dateTimeLabelFormats: {
  596. second: '%H:%M:%S',
  597. minute: '%H:%M',
  598. hour: '%H:%M',
  599. day: '%e. %b',
  600. week: '%e. %b',
  601. month: '%b \'%y',
  602. year: '%Y'
  603. },
  604. endOnTick: false,
  605. gridLineColor: '#C0C0C0',
  606. labels: defaultLabelOptions,
  607. lineColor: '#C0D0E0',
  608. lineWidth: 1,
  609. max: null,
  610. min: null,
  611. minPadding: 0.01,
  612. maxPadding: 0.01,
  613. minorGridLineColor: '#E0E0E0',
  614. minorGridLineWidth: 1,
  615. minorTickColor: '#A0A0A0',
  616. minorTickLength: 2,
  617. minorTickPosition: 'outside',
  618. startOfWeek: 1,
  619. startOnTick: false,
  620. tickColor: '#C0D0E0',
  621. tickLength: 5,
  622. tickmarkPlacement: 'between',
  623. tickPixelInterval: 100,
  624. tickPosition: 'outside',
  625. tickWidth: 1,
  626. title: {
  627. align: 'middle',
  628. style: {
  629. color: '#6D869F',
  630. fontWeight: 'bold'
  631. }
  632. },
  633. type: 'linear'
  634. },
  635. defaultYAxisOptions = merge(defaultXAxisOptions, {
  636. endOnTick: true,
  637. gridLineWidth: 1,
  638. tickPixelInterval: 72,
  639. showLastLabel: true,
  640. labels: {
  641. align: 'right',
  642. x: -8,
  643. y: 3
  644. },
  645. lineWidth: 0,
  646. maxPadding: 0.05,
  647. minPadding: 0.05,
  648. startOnTick: true,
  649. tickWidth: 0,
  650. title: {
  651. rotation: 270,
  652. text: 'Y-values'
  653. }
  654. }),
  655. defaultLeftAxisOptions = {
  656. labels: {
  657. align: 'right',
  658. x: -8,
  659. y: null
  660. },
  661. title: {
  662. rotation: 270
  663. }
  664. },
  665. defaultRightAxisOptions = {
  666. labels: {
  667. align: 'left',
  668. x: 8,
  669. y: null
  670. },
  671. title: {
  672. rotation: 90
  673. }
  674. },
  675. defaultBottomAxisOptions = {
  676. labels: {
  677. align: 'center',
  678. x: 0,
  679. y: 14
  680. },
  681. title: {
  682. rotation: 0
  683. }
  684. },
  685. defaultTopAxisOptions = merge(defaultBottomAxisOptions, {
  686. labels: {
  687. y: -5
  688. }
  689. });
  690. var defaultPlotOptions = defaultOptions.plotOptions,
  691. defaultSeriesOptions = defaultPlotOptions.line;
  692. defaultPlotOptions.spline = merge(defaultSeriesOptions);
  693. defaultPlotOptions.scatter = merge(defaultSeriesOptions, {
  694. lineWidth: 0,
  695. states: {
  696. hover: {
  697. lineWidth: 0
  698. }
  699. }
  700. });
  701. defaultPlotOptions.area = merge(defaultSeriesOptions, {
  702. });
  703. defaultPlotOptions.areaspline = merge(defaultPlotOptions.area);
  704. defaultPlotOptions.column = merge(defaultSeriesOptions, {
  705. borderColor: '#FFFFFF',
  706. borderWidth: 1,
  707. borderRadius: 0,
  708. groupPadding: 0.2,
  709. marker: null,
  710. pointPadding: 0.1,
  711. minPointLength: 0,
  712. states: {
  713. hover: {
  714. brightness: 0.1,
  715. shadow: false
  716. },
  717. select: {
  718. color: '#C0C0C0',
  719. borderColor: '#000000',
  720. shadow: false
  721. }
  722. }
  723. });
  724. defaultPlotOptions.bar = merge(defaultPlotOptions.column, {
  725. dataLabels: {
  726. align: 'left',
  727. x: 5,
  728. y: 0
  729. }
  730. });
  731. defaultPlotOptions.pie = merge(defaultSeriesOptions, {
  732. borderColor: '#FFFFFF',
  733. borderWidth: 1,
  734. center: ['50%', '50%'],
  735. colorByPoint: true,
  736. dataLabels: {
  737. distance: 30,
  738. enabled: true,
  739. formatter: function() {
  740. return this.point.name;
  741. },
  742. y: 5
  743. },
  744. legendType: 'point',
  745. marker: null,
  746. size: '75%',
  747. showInLegend: false,
  748. slicedOffset: 10,
  749. states: {
  750. hover: {
  751. brightness: 0.1,
  752. shadow: false
  753. }
  754. }
  755. });
  756. setTimeMethods();
  757. function extendClass(parent, members) {
  758. var object = function(){};
  759. object.prototype = new parent();
  760. extend(object.prototype, members);
  761. return object;
  762. }
  763. var Color = function(input) {
  764. var rgba = [], result;
  765. function init(input) {
  766. if((result = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]?(?:\.[0-9]+)?)\s*\)/.exec(input))) {
  767. rgba = [pInt(result[1]), pInt(result[2]), pInt(result[3]), parseFloat(result[4], 10)];
  768. }
  769. else if((result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(input))) {
  770. rgba = [pInt(result[1],16), pInt(result[2],16), pInt(result[3],16), 1];
  771. }
  772. }
  773. function get(format) {
  774. var ret;
  775. if (rgba && !isNaN(rgba[0])) {
  776. if (format == 'rgb') {
  777. ret = 'rgb('+ rgba[0] +','+ rgba[1] +','+ rgba[2] +')';
  778. } else if (format == 'a') {
  779. ret = rgba[3];
  780. } else {
  781. ret = 'rgba('+ rgba.join(',') +')';
  782. }
  783. } else {
  784. ret = input;
  785. }
  786. return ret;
  787. }
  788. function brighten(alpha) {
  789. if (isNumber(alpha) && alpha !== 0) {
  790. var i;
  791. for (i = 0; i < 3; i++) {
  792. rgba[i] += pInt(alpha * 255);
  793. if (rgba[i] < 0) {
  794. rgba[i] = 0;
  795. }
  796. if (rgba[i] > 255) {
  797. rgba[i] = 255;
  798. }
  799. }
  800. }
  801. return this;
  802. }
  803. function setOpacity(alpha) {
  804. rgba[3] = alpha;
  805. return this;
  806. }
  807. init(input);
  808. return {
  809. get: get,
  810. brighten: brighten,
  811. setOpacity: setOpacity
  812. };
  813. };
  814. function numberFormat (number, decimals, decPoint, thousandsSep) {
  815. var lang = defaultOptions.lang,
  816. n = number, c = isNaN(decimals = mathAbs(decimals)) ? 2 : decimals,
  817. d = decPoint === undefined ? lang.decimalPoint : decPoint,
  818. t = thousandsSep === undefined ? lang.thousandsSep : thousandsSep, s = n < 0 ? "-" : "",
  819. i = pInt(n = mathAbs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
  820. return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
  821. (c ? d + mathAbs(n - i).toFixed(c).slice(2) : "");
  822. }
  823. dateFormat = function (format, timestamp, capitalize) {
  824. function pad (number) {
  825. return number.toString().replace(/^([0-9])$/, '0$1');
  826. }
  827. if (!defined(timestamp) || isNaN(timestamp)) {
  828. return 'Invalid date';
  829. }
  830. format = pick(format, '%Y-%m-%d %H:%M:%S');
  831. var date = new Date(timestamp * timeFactor),
  832. hours = date[getHours](),
  833. day = date[getDay](),
  834. dayOfMonth = date[getDate](),
  835. month = date[getMonth](),
  836. fullYear = date[getFullYear](),
  837. lang = defaultOptions.lang,
  838. langWeekdays = lang.weekdays,
  839. langMonths = lang.months,
  840. replacements = {
  841. 'a': langWeekdays[day].substr(0, 3),
  842. 'A': langWeekdays[day],
  843. 'd': pad(dayOfMonth),
  844. 'e': dayOfMonth,
  845. 'b': langMonths[month].substr(0, 3),
  846. 'B': langMonths[month],
  847. 'm': pad(month + 1),
  848. 'y': fullYear.toString().substr(2, 2),
  849. 'Y': fullYear,
  850. 'H': pad(hours),
  851. 'I': pad((hours % 12) || 12),
  852. 'l': (hours % 12) || 12,
  853. 'M': pad(date[getMinutes]()),
  854. 'p': hours < 12 ? 'AM' : 'PM',
  855. 'P': hours < 12 ? 'am' : 'pm',
  856. 'S': pad(date.getSeconds())
  857. };
  858. for (var key in replacements) {
  859. format = format.replace('%'+ key, replacements[key]);
  860. }
  861. return capitalize ? format.substr(0, 1).toUpperCase() + format.substr(1) : format;
  862. };
  863. function getPosition (el) {
  864. var p = { left: el.offsetLeft, top: el.offsetTop };
  865. while ((el = el.offsetParent)) {
  866. p.left += el.offsetLeft;
  867. p.top += el.offsetTop;
  868. if (el != doc.body && el != doc.documentElement) {
  869. p.left -= el.scrollLeft;
  870. p.top -= el.scrollTop;
  871. }
  872. }
  873. return p;
  874. }
  875. function SVGElement () {}
  876. SVGElement.prototype = {
  877. init: function(renderer, nodeName) {
  878. this.element = doc.createElementNS(SVG_NS, nodeName);
  879. this.renderer = renderer;
  880. },
  881. animate: function(params, options, complete) {
  882. var animOptions = pick(options, globalAnimation, true);
  883. if (animOptions) {
  884. animOptions = merge(animOptions);
  885. if (complete) {
  886. animOptions.complete = complete;
  887. }
  888. animate(this, params, animOptions);
  889. } else {
  890. this.attr(params);
  891. if (complete) {
  892. complete();
  893. }
  894. }
  895. },
  896. attr: function(hash, val) {
  897. var key,
  898. value,
  899. i,
  900. child,
  901. element = this.element,
  902. nodeName = element.nodeName,
  903. renderer = this.renderer,
  904. skipAttr,
  905. shadows = this.shadows,
  906. hasSetSymbolSize,
  907. ret = this;
  908. if (isString(hash) && defined(val)) {
  909. key = hash;
  910. hash = {};
  911. hash[key] = val;
  912. }
  913. if (isString(hash)) {
  914. key = hash;
  915. if (nodeName == 'circle') {
  916. key = { x: 'cx', y: 'cy' }[key] || key;
  917. } else if (key == 'strokeWidth') {
  918. key = 'stroke-width';
  919. }
  920. ret = attr(element, key) || this[key] || 0;
  921. if (key != 'd' && key != 'visibility') {
  922. ret = parseFloat(ret);
  923. }
  924. } else {
  925. for (key in hash) {
  926. skipAttr = false;
  927. value = hash[key];
  928. if (key == 'd') {
  929. if (value && value.join) {
  930. value = value.join(' ');
  931. }
  932. if (/(NaN| {2}|^$)/.test(value)) {
  933. value = 'M 0 0';
  934. }
  935. this.d = value;
  936. } else if (key == 'x' && nodeName == 'text') {
  937. for (i = 0; i < element.childNodes.length; i++ ) {
  938. child = element.childNodes[i];
  939. if (attr(child, 'x') == attr(element, 'x')) {
  940. attr(child, 'x', value);
  941. }
  942. }
  943. if (this.rotation) {
  944. attr(element, 'transform', 'rotate('+ this.rotation +' '+ value +' '+
  945. pInt(hash.y || attr(element, 'y')) +')');
  946. }
  947. } else if (key == 'fill') {
  948. value = renderer.color(value, element, key);
  949. } else if (nodeName == 'circle' && (key == 'x' || key == 'y')) {
  950. key = { x: 'cx', y: 'cy' }[key] || key;
  951. } else if (key == 'translateX' || key == 'translateY' || key == 'rotation' || key == 'verticalAlign') {
  952. this[key] = value;
  953. this.updateTransform();
  954. skipAttr = true;
  955. } else if (key == 'stroke') {
  956. value = renderer.color(value, element, key);
  957. } else if (key == 'dashstyle') {
  958. key = 'stroke-dasharray';
  959. if (value) {
  960. value = value.toLowerCase()
  961. .replace('shortdashdotdot', '3,1,1,1,1,1,')
  962. .replace('shortdashdot', '3,1,1,1')
  963. .replace('shortdot', '1,1,')
  964. .replace('shortdash', '3,1,')
  965. .replace('longdash', '8,3,')
  966. .replace(/dot/g, '1,3,')
  967. .replace('dash', '4,3,')
  968. .replace(/,$/, '')
  969. .split(',');
  970. i = value.length;
  971. while (i--) {
  972. value[i] = pInt(value[i]) * hash['stroke-width'];
  973. }
  974. value = value.join(',');
  975. }
  976. } else if (key == 'isTracker') {
  977. this[key] = value;
  978. } else if (key == 'width') {
  979. value = pInt(value);
  980. } else if (key == 'align') {
  981. key = 'text-anchor';
  982. value = { left: 'start', center: 'middle', right: 'end' }[value];
  983. }
  984. if (key == 'strokeWidth') {
  985. key = 'stroke-width';
  986. }
  987. if (isWebKit && key == 'stroke-width' && value === 0) {
  988. value = 0.000001;
  989. }
  990. if (this.symbolName && /^(x|y|r|start|end|innerR)/.test(key)) {
  991. if (!hasSetSymbolSize) {
  992. this.symbolAttr(hash);
  993. hasSetSymbolSize = true;
  994. }
  995. skipAttr = true;
  996. }
  997. if (shadows && /^(width|height|visibility|x|y|d)$/.test(key)) {
  998. i = shadows.length;
  999. while (i--) {
  1000. attr(shadows[i], key, value);
  1001. }
  1002. }
  1003. if (key == 'text') {
  1004. this.textStr = value;
  1005. if (this.added) {
  1006. renderer.buildText(this);
  1007. }
  1008. } else if (!skipAttr) {
  1009. attr(element, key, value);
  1010. }
  1011. }
  1012. }
  1013. return ret;
  1014. },
  1015. symbolAttr: function(hash) {
  1016. var wrapper = this;
  1017. each (['x', 'y', 'r', 'start', 'end', 'width', 'height', 'innerR'], function(key) {
  1018. wrapper[key] = pick(hash[key], wrapper[key]);
  1019. });
  1020. wrapper.attr({
  1021. d: wrapper.renderer.symbols[wrapper.symbolName](wrapper.x, wrapper.y, wrapper.r, {
  1022. start: wrapper.start,
  1023. end: wrapper.end,
  1024. width: wrapper.width,
  1025. height: wrapper.height,
  1026. innerR: wrapper.innerR
  1027. })
  1028. });
  1029. },
  1030. clip: function(clipRect) {
  1031. return this.attr('clip-path', 'url('+ this.renderer.URL +'#'+ clipRect.id +')');
  1032. },
  1033. crisp: function(strokeWidth, x, y, width, height) {
  1034. var wrapper = this,
  1035. key,
  1036. attr = {},
  1037. values = {},
  1038. normalizer;
  1039. strokeWidth = strokeWidth || wrapper.strokeWidth || 0;
  1040. normalizer = strokeWidth % 2 / 2;
  1041. values.x = mathFloor(x || wrapper.x || 0) + normalizer;
  1042. values.y = mathFloor(y || wrapper.y || 0) + normalizer;
  1043. values.setWidth(mathFloor((width || wrapper.width || 0) - 2 * normalizer));
  1044. values.setHeight(mathFloor((height || wrapper.height || 0) - 2 * normalizer));
  1045. values.strokeWidth = strokeWidth;
  1046. for (key in values) {
  1047. if (wrapper[key] != values[key]) {
  1048. wrapper[key] = attr[key] = values[key];
  1049. }
  1050. }
  1051. return attr;
  1052. },
  1053. css: function(styles) {
  1054. var elemWrapper = this,
  1055. elem = elemWrapper.element,
  1056. textWidth = styles && styles.width && elem.nodeName == 'text';
  1057. if (styles && styles.color) {
  1058. styles.fill = styles.color;
  1059. }
  1060. styles = extend(
  1061. elemWrapper.styles,
  1062. styles
  1063. );
  1064. elemWrapper.styles = styles;
  1065. if (isIE && !hasSVG) {
  1066. if (textWidth) {
  1067. delete styles.width;
  1068. }
  1069. css(elemWrapper.element, styles);
  1070. } else {
  1071. elemWrapper.attr({
  1072. style: serializeCSS(styles)
  1073. });
  1074. }
  1075. if (textWidth && elemWrapper.added) {
  1076. elemWrapper.renderer.buildText(elemWrapper);
  1077. }
  1078. return elemWrapper;
  1079. },
  1080. on: function(eventType, handler) {
  1081. var fn = handler;
  1082. if (hasTouch && eventType == 'click') {
  1083. eventType = 'touchstart';
  1084. fn = function(e) {
  1085. e.preventDefault();
  1086. handler();
  1087. }
  1088. }
  1089. this.element['on'+ eventType] = fn;
  1090. return this;
  1091. },
  1092. translate: function(x, y) {
  1093. return this.attr({
  1094. translateX: x,
  1095. translateY: y
  1096. });
  1097. },
  1098. invert: function() {
  1099. var wrapper = this;
  1100. wrapper.inverted = true;
  1101. wrapper.updateTransform();
  1102. return wrapper;
  1103. },
  1104. updateTransform: function() {
  1105. var wrapper = this,
  1106. translateX = wrapper.translateX || 0,
  1107. translateY = wrapper.translateY || 0,
  1108. inverted = wrapper.inverted,
  1109. rotation = wrapper.rotation,
  1110. transform = [];
  1111. if (inverted) {
  1112. translateX += wrapper.attr('width');
  1113. translateY += wrapper.attr('height');
  1114. }
  1115. if (translateX || translateY) {
  1116. transform.push('translate('+ translateX +','+ translateY +')');
  1117. }
  1118. if (inverted) {
  1119. transform.push('rotate(90) scale(-1,1)');
  1120. } else if (rotation) {
  1121. transform.push('rotate('+ rotation +' '+ wrapper.x +' '+ wrapper.y +')');
  1122. }
  1123. if (transform.length) {
  1124. attr(wrapper.element, 'transform', transform.join(' '));
  1125. }
  1126. },
  1127. toFront: function() {
  1128. var element = this.element;
  1129. element.parentNode.appendChild(element);
  1130. return this;
  1131. },
  1132. align: function(alignOptions, alignByTranslate, box) {
  1133. if (!alignOptions) {
  1134. alignOptions = this.alignOptions;
  1135. alignByTranslate = this.alignByTranslate;
  1136. } else {
  1137. this.alignOptions = alignOptions;
  1138. this.alignByTranslate = alignByTranslate;
  1139. if (!box) {
  1140. this.renderer.alignedObjects.push(this);
  1141. }
  1142. }
  1143. box = pick(box, this.renderer);
  1144. var align = alignOptions.align,
  1145. vAlign = alignOptions.verticalAlign,
  1146. x = (box.x || 0) + (alignOptions.x || 0),
  1147. y = (box.y || 0) + (alignOptions.y || 0),
  1148. attribs = {};
  1149. if (/^(right|center)$/.test(align)) {
  1150. x += (box.width - (alignOptions.width || 0) ) /
  1151. { right: 1, center: 2 }[align];
  1152. }
  1153. attribs[alignByTranslate ? 'translateX' : 'x'] = mathRound(x);
  1154. if (/^(bottom|middle)$/.test(vAlign)) {
  1155. y += (box.height - (alignOptions.height || 0)) /
  1156. ({ bottom: 1, middle: 2 }[vAlign] || 1);
  1157. }
  1158. attribs[alignByTranslate ? 'translateY' : 'y'] = mathRound(y);
  1159. this[this.placed ? 'animate' : 'attr'](attribs);
  1160. this.placed = true;
  1161. return this;
  1162. },
  1163. getBBox: function() {
  1164. var bBox,
  1165. width,
  1166. height,
  1167. rotation = this.rotation,
  1168. rad = rotation * deg2rad;
  1169. try {
  1170. bBox = extend({}, this.element.getBBox());
  1171. } catch(e) {
  1172. bBox = { width: 0, height: 0 };
  1173. }
  1174. width = bBox.width;
  1175. height = bBox.height;
  1176. if (rotation) {
  1177. bBox.setWidth(mathAbs(height * mathSin(rad)) + mathAbs(width * mathCos(rad)));
  1178. bBox.setHeight(mathAbs(height * mathCos(rad)) + mathAbs(width * mathSin(rad)));
  1179. }
  1180. return bBox;
  1181. },
  1182. show: function() {
  1183. return this.attr({ visibility: VISIBLE });
  1184. },
  1185. hide: function() {
  1186. return this.attr({ visibility: HIDDEN });
  1187. },
  1188. add: function(parent) {
  1189. var renderer = this.renderer,
  1190. parentWrapper = parent || renderer,
  1191. parentNode = parentWrapper.element || renderer.box,
  1192. childNodes = parentNode.childNodes,
  1193. element = this.element,
  1194. zIndex = attr(element, 'zIndex'),
  1195. otherElement,
  1196. otherZIndex,
  1197. i;
  1198. this.parentInverted = parent && parent.inverted;
  1199. if (this.textStr !== undefined) {
  1200. renderer.buildText(this);
  1201. }
  1202. if (zIndex) {
  1203. parentWrapper.handleZ = true;
  1204. zIndex = pInt(zIndex);
  1205. }
  1206. if (parentWrapper.handleZ) {
  1207. for (i = 0; i < childNodes.length; i++) {
  1208. otherElement = childNodes[i];
  1209. otherZIndex = attr(otherElement, 'zIndex');
  1210. if (otherElement != element && (
  1211. pInt(otherZIndex) > zIndex ||
  1212. (!defined(zIndex) && defined(otherZIndex))
  1213. )) {
  1214. parentNode.insertBefore(element, otherElement);
  1215. return this;
  1216. }
  1217. }
  1218. }
  1219. parentNode.appendChild(element);
  1220. this.added = true;
  1221. return this;
  1222. },
  1223. destroy: function() {
  1224. var wrapper = this,
  1225. element = wrapper.element || {},
  1226. shadows = wrapper.shadows,
  1227. parentNode = element.parentNode,
  1228. key;
  1229. element.onclick = element.onmouseout = element.onmouseover = element.onmousemove = null;
  1230. stop(wrapper);
  1231. if (parentNode) {
  1232. parentNode.removeChild(element);
  1233. }
  1234. if (shadows) {
  1235. each(shadows, function(shadow) {
  1236. parentNode = shadow.parentNode;
  1237. if (parentNode) {
  1238. parentNode.removeChild(shadow);
  1239. }
  1240. });
  1241. }
  1242. erase(wrapper.renderer.alignedObjects, wrapper);
  1243. for (key in wrapper) {
  1244. delete wrapper[key];
  1245. }
  1246. return null;
  1247. },
  1248. empty: function() {
  1249. var element = this.element,
  1250. childNodes = element.childNodes,
  1251. i = childNodes.length;
  1252. while (i--) {
  1253. element.removeChild(childNodes[i]);
  1254. }
  1255. },
  1256. shadow: function(apply) {
  1257. var shadows = [],
  1258. i,
  1259. shadow,
  1260. element = this.element,
  1261. transform = this.parentInverted ? '(-1,-1)' : '(1,1)';
  1262. if (apply) {
  1263. for (i = 1; i <= 3; i++) {
  1264. shadow = element.cloneNode(0);
  1265. attr(shadow, {
  1266. 'isShadow': 'true',
  1267. 'stroke': 'rgb(0, 0, 0)',
  1268. 'stroke-opacity': 0.05 * i,
  1269. 'stroke-width': 7 - 2 * i,
  1270. 'transform': 'translate'+ transform,
  1271. 'fill': NONE
  1272. });
  1273. element.parentNode.insertBefore(shadow, element);
  1274. shadows.push(shadow);
  1275. }
  1276. this.shadows = shadows;
  1277. }
  1278. return this;
  1279. }
  1280. };
  1281. var SVGRenderer = function() {
  1282. this.init.apply(this, arguments);
  1283. };
  1284. SVGRenderer.prototype = {
  1285. init: function(container, width, height, forExport) {
  1286. var renderer = this,
  1287. loc = location,
  1288. boxWrapper;
  1289. renderer.Element = SVGElement;
  1290. boxWrapper = renderer.createElement('svg')
  1291. .attr({
  1292. xmlns: SVG_NS,
  1293. version: '1.1'
  1294. });
  1295. container.appendChild(boxWrapper.element);
  1296. renderer.box = boxWrapper.element;
  1297. renderer.boxWrapper = boxWrapper;
  1298. renderer.alignedObjects = [];
  1299. renderer.URL = isIE ? '' : loc.href.replace(/#.*?$/, '');
  1300. renderer.defs = this.createElement('defs').add();
  1301. renderer.forExport = forExport;
  1302. renderer.setSize(width, height, false);
  1303. },
  1304. createElement: function(nodeName) {
  1305. var wrapper = new this.Element();
  1306. wrapper.init(this, nodeName);
  1307. return wrapper;
  1308. },
  1309. buildText: function(wrapper) {
  1310. var textNode = wrapper.element,
  1311. lines = pick(wrapper.textStr, '').toString()
  1312. .replace(/<(b|strong)>/g, '<span style="font-weight:bold">')
  1313. .replace(/<(i|em)>/g, '<span style="font-style:italic">')
  1314. .replace(/<a/g, '<span')
  1315. .replace(/<\/(b|strong|i|em|a)>/g, '</span>')
  1316. .split(/<br[^>]?>/g),
  1317. childNodes = textNode.childNodes,
  1318. styleRegex = /style="([^"]+)"/,
  1319. hrefRegex = /href="([^"]+)"/,
  1320. parentX = attr(textNode, 'x'),
  1321. textStyles = wrapper.styles,
  1322. reverse = isFirefox && textStyles && textStyles.HcDirection == 'rtl' && !this.forExport,
  1323. arr,
  1324. width = textStyles && pInt(textStyles.width),
  1325. textLineHeight = textStyles && textStyles.lineHeight,
  1326. lastLine,
  1327. i = childNodes.length;
  1328. while (i--) {
  1329. textNode.removeChild(childNodes[i]);
  1330. }
  1331. if (width && !wrapper.added) {
  1332. this.box.appendChild(textNode);
  1333. }
  1334. each(lines, function(line, lineNo) {
  1335. var spans, spanNo = 0, lineHeight;
  1336. line = line.replace(/<span/g, '|||<span').replace(/<\/span>/g, '</span>|||');
  1337. spans = line.split('|||');
  1338. each(spans, function (span) {
  1339. if (span !== '' || spans.length == 1) {
  1340. var attributes = {},
  1341. tspan = doc.createElementNS(SVG_NS, 'tspan');
  1342. if (styleRegex.test(span)) {
  1343. attr(
  1344. tspan,
  1345. 'style',
  1346. span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2')
  1347. );
  1348. }
  1349. if (hrefRegex.test(span)) {
  1350. attr(tspan, 'onclick', 'location.href=\"'+ span.match(hrefRegex)[1] +'\"');
  1351. css(tspan, { cursor: 'pointer' });
  1352. }
  1353. span = span.replace(/<(.|\n)*?>/g, '') || ' ';
  1354. if (reverse) {
  1355. arr = [];
  1356. i = span.length;
  1357. while (i--) {
  1358. arr.push(span.charAt(i))
  1359. }
  1360. span = arr.join('');
  1361. }
  1362. tspan.appendChild(doc.createTextNode(span));
  1363. if (!spanNo) {
  1364. attributes.x = parentX;
  1365. } else {
  1366. attributes.dx = 3;
  1367. }
  1368. if (!spanNo) {
  1369. if (lineNo) {
  1370. lineHeight = pInt(window.getComputedStyle(lastLine, null).getPropertyValue('line-height'));
  1371. if (isNaN(lineHeight)) {
  1372. lineHeight = textLineHeight || lastLine.offsetHeight || 18;
  1373. }
  1374. attr(tspan, 'dy', lineHeight);
  1375. }
  1376. lastLine = tspan;
  1377. }
  1378. attr(tspan, attributes);
  1379. textNode.appendChild(tspan);
  1380. spanNo++;
  1381. if (width) {
  1382. var words = span.replace(/-/g, '- ').split(' '),
  1383. tooLong,
  1384. actualWidth,
  1385. rest = [];
  1386. while (words.length || rest.length) {
  1387. actualWidth = textNode.getBBox().width;
  1388. tooLong = actualWidth > width;
  1389. if (!tooLong || words.length == 1) {
  1390. words = rest;
  1391. rest = [];
  1392. if (words.length) {
  1393. tspan = doc.createElementNS(SVG_NS, 'tspan');
  1394. attr(tspan, {
  1395. x: parentX,
  1396. dy: textLineHeight || 16
  1397. });
  1398. textNode.appendChild(tspan);
  1399. if (actualWidth > width) {
  1400. width = actualWidth;
  1401. }
  1402. }
  1403. } else {
  1404. tspan.removeChild(tspan.firstChild);
  1405. rest.unshift(words.pop());
  1406. }
  1407. tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
  1408. }
  1409. }
  1410. }
  1411. });
  1412. });
  1413. },
  1414. crispLine: function(points, width) {
  1415. if (points[1] == points[4]) {
  1416. points[1] = points[4] = mathRound(points[1]) + (width % 2 / 2);
  1417. }
  1418. if (points[2] == points[5]) {
  1419. points[2] = points[5] = mathRound(points[2]) + (width % 2 / 2);
  1420. }
  1421. return points;
  1422. },
  1423. path: function (path) {
  1424. return this.createElement('path').attr({
  1425. d: path,
  1426. fill: NONE
  1427. });
  1428. },
  1429. circle: function (x, y, r) {
  1430. var attr = isObject(x) ?
  1431. x :
  1432. {
  1433. x: x,
  1434. y: y,
  1435. r: r
  1436. };
  1437. return this.createElement('circle').attr(attr);
  1438. },
  1439. arc: function (x, y, r, innerR, start, end) {
  1440. if (isObject(x)) {
  1441. y = x.y;
  1442. r = x.r;
  1443. innerR = x.innerR;
  1444. start = x.start;
  1445. end = x.end;
  1446. x = x.x;
  1447. }
  1448. return this.symbol('arc', x || 0, y || 0, r || 0, {
  1449. innerR: innerR || 0,
  1450. start: start || 0,
  1451. end: end || 0
  1452. });
  1453. },
  1454. rect: function (x, y, width, height, r, strokeWidth) {
  1455. if (isObject(x)) {
  1456. y = x.y;
  1457. width = x.width;
  1458. height = x.height;
  1459. r = x.r;
  1460. x = x.x;
  1461. }
  1462. var wrapper = this.createElement('rect').attr({
  1463. rx: r,
  1464. ry: r,
  1465. fill: NONE
  1466. });
  1467. return wrapper.attr(wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0)));
  1468. },
  1469. setSize: function(width, height, animate) {
  1470. var renderer = this,
  1471. alignedObjects = renderer.alignedObjects,
  1472. i = alignedObjects.length;
  1473. renderer.setWidth(width);
  1474. renderer.setHeight(height);
  1475. renderer.boxWrapper[pick(animate, true) ? 'animate' : 'attr']({
  1476. width: width,
  1477. height: height
  1478. });
  1479. while (i--) {
  1480. alignedObjects[i].align();
  1481. }
  1482. },
  1483. g: function(name) {
  1484. return this.createElement('g').attr(
  1485. defined(name) && { 'class': PREFIX + name }
  1486. );
  1487. },
  1488. image: function(src, x, y, width, height) {
  1489. var attribs = {
  1490. preserveAspectRatio: NONE
  1491. },
  1492. elemWrapper;
  1493. if (arguments.length > 1) {
  1494. extend(attribs, {
  1495. x: x,
  1496. y: y,
  1497. width: width,
  1498. height: height
  1499. });
  1500. }
  1501. elemWrapper = this.createElement('image').attr(attribs);
  1502. elemWrapper.element.setAttributeNS('http://www.w3.org/1999/xlink',
  1503. 'href', src);
  1504. return elemWrapper;
  1505. },
  1506. symbol: function(symbol, x, y, radius, options) {
  1507. var obj,
  1508. symbolFn = this.symbols[symbol],
  1509. path = symbolFn && symbolFn(
  1510. x,
  1511. y,
  1512. radius,
  1513. options
  1514. ),
  1515. imageRegex = /^url\((.*?)\)$/,
  1516. imageSrc;
  1517. if (path) {
  1518. obj = this.path(path);
  1519. extend(obj, {
  1520. symbolName: symbol,
  1521. x: x,
  1522. y: y,
  1523. r: radius
  1524. });
  1525. if (options) {
  1526. extend(obj, options);
  1527. }
  1528. } else if (imageRegex.test(symbol)) {
  1529. imageSrc = symbol.match(imageRegex)[1];
  1530. obj = this.image(imageSrc)
  1531. .attr({
  1532. x: x,
  1533. y: y
  1534. });
  1535. createElement('img', {
  1536. onload: function() {
  1537. var img = this,
  1538. size = symbolSizes[img.src] || [img.width, img.height];
  1539. obj.attr({
  1540. width: size[0],
  1541. height: size[1]
  1542. }).translate(
  1543. -mathRound(size[0] / 2),
  1544. -mathRound(size[1] / 2)
  1545. );
  1546. },
  1547. src: imageSrc
  1548. });
  1549. } else {
  1550. obj = this.circle(x, y, radius);
  1551. }
  1552. return obj;
  1553. },
  1554. symbols: {
  1555. 'square': function (x, y, radius) {
  1556. var len = 0.707 * radius;
  1557. return [
  1558. M, x-len, y-len,
  1559. L, x+len, y-len,
  1560. x+len, y+len,
  1561. x-len, y+len,
  1562. 'Z'
  1563. ];
  1564. },
  1565. 'triangle': function (x, y, radius) {
  1566. return [
  1567. M, x, y-1.33 * radius,
  1568. L, x+radius, y + 0.67 * radius,
  1569. x-radius, y + 0.67 * radius,
  1570. 'Z'
  1571. ];
  1572. },
  1573. 'triangle-down': function (x, y, radius) {
  1574. return [
  1575. M, x, y + 1.33 * radius,
  1576. L, x-radius, y-0.67 * radius,
  1577. x+radius, y-0.67 * radius,
  1578. 'Z'
  1579. ];
  1580. },
  1581. 'diamond': function (x, y, radius) {
  1582. return [
  1583. M, x, y-radius,
  1584. L, x+radius, y,
  1585. x, y+radius,
  1586. x-radius, y,
  1587. 'Z'
  1588. ];
  1589. },
  1590. 'arc': function (x, y, radius, options) {
  1591. var start = options.start,
  1592. end = options.end - 0.000001,
  1593. innerRadius = options.innerR,
  1594. cosStart = mathCos(start),
  1595. sinStart = mathSin(start),
  1596. cosEnd = mathCos(end),
  1597. sinEnd = mathSin(end),
  1598. longArc = options.end - start < mathPI ? 0 : 1;
  1599. return [
  1600. M,
  1601. x + radius * cosStart,
  1602. y + radius * sinStart,
  1603. 'A',
  1604. radius,
  1605. radius,
  1606. 0,
  1607. longArc,
  1608. 1,
  1609. x + radius * cosEnd,
  1610. y + radius * sinEnd,
  1611. L,
  1612. x + innerRadius * cosEnd,
  1613. y + innerRadius * sinEnd,
  1614. 'A',
  1615. innerRadius,
  1616. innerRadius,
  1617. 0,
  1618. longArc,
  1619. 0,
  1620. x + innerRadius * cosStart,
  1621. y + innerRadius * sinStart,
  1622. 'Z'
  1623. ];
  1624. }
  1625. },
  1626. clipRect: function (x, y, width, height) {
  1627. var wrapper,
  1628. id = PREFIX + idCounter++,
  1629. clipPath = this.createElement('clipPath').attr({
  1630. id: id
  1631. }).add(this.defs);
  1632. wrapper = this.rect(x, y, width, height, 0).add(clipPath);
  1633. wrapper.id = id;
  1634. return wrapper;
  1635. },
  1636. color: function(color, elem, prop) {
  1637. var colorObject,
  1638. regexRgba = /^rgba/;
  1639. if (color && color.linearGradient) {
  1640. var renderer = this,
  1641. strLinearGradient = 'linearGradient',
  1642. linearGradient = color[strLinearGradient],
  1643. id = PREFIX + idCounter++,
  1644. gradientObject,
  1645. stopColor,
  1646. stopOpacity;
  1647. gradientObject = renderer.createElement(strLinearGradient).attr({
  1648. id: id,
  1649. gradientUnits: 'userSpaceOnUse',
  1650. x1: linearGradient[0],
  1651. y1: linearGradient[1],
  1652. x2: linearGradient[2],
  1653. y2: linearGradient[3]
  1654. }).add(renderer.defs);
  1655. each(color.stops, function(stop) {
  1656. if (regexRgba.test(stop[1])) {
  1657. colorObject = Color(stop[1]);
  1658. stopColor = colorObject.get('rgb');
  1659. stopOpacity = colorObject.get('a');
  1660. } else {
  1661. stopColor = stop[1];
  1662. stopOpacity = 1;
  1663. }
  1664. renderer.createElement('stop').attr({
  1665. offset: stop[0],
  1666. 'stop-color': stopColor,
  1667. 'stop-opacity': stopOpacity
  1668. }).add(gradientObject);
  1669. });
  1670. return 'url('+ this.URL +'#'+ id +')';
  1671. } else if (regexRgba.test(color)) {
  1672. colorObject = Color(color);
  1673. attr(elem, prop +'-opacity', colorObject.get('a'));
  1674. return colorObject.get('rgb');
  1675. } else {
  1676. return color;
  1677. }
  1678. },
  1679. text: function(str, x, y) {
  1680. var defaultChartStyle = defaultOptions.chart.style,
  1681. wrapper;
  1682. x = mathRound(pick(x, 0));
  1683. y = mathRound(pick(y, 0));
  1684. wrapper = this.createElement('text')
  1685. .attr({
  1686. x: x,
  1687. y: y,
  1688. text: str
  1689. })
  1690. .css({
  1691. 'font-family': defaultChartStyle.fontFamily,
  1692. 'font-size': defaultChartStyle.fontSize
  1693. });
  1694. wrapper.x = x;
  1695. wrapper.y = y;
  1696. return wrapper;
  1697. }
  1698. };
  1699. var VMLRenderer;
  1700. if (!hasSVG) {
  1701. var VMLElement = extendClass( SVGElement, {
  1702. init: function(renderer, nodeName) {
  1703. var markup = ['<', nodeName, ' filled="f" stroked="f"'],
  1704. style = ['position: ', ABSOLUTE, ';'];
  1705. if (nodeName == 'shape' || nodeName == DIV) {
  1706. style.push('left:0;top:0;width:10px;height:10px;');
  1707. }
  1708. if (docMode8) {
  1709. style.push('visibility: ', nodeName == DIV ? HIDDEN : VISIBLE);
  1710. }
  1711. markup.push(' style="', style.join(''), '"/>');
  1712. if (nodeName) {
  1713. markup = nodeName == DIV || nodeName == 'span' || nodeName == 'img' ?
  1714. markup.join('')
  1715. : renderer.prepVML(markup);
  1716. this.element = createElement(markup);
  1717. }
  1718. this.renderer = renderer;
  1719. },
  1720. add: function(parent) {
  1721. var wrapper = this,
  1722. renderer = wrapper.renderer,
  1723. element = wrapper.element,
  1724. box = renderer.box,
  1725. inverted = parent && parent.inverted,
  1726. parentNode = parent ?
  1727. parent.element || parent :
  1728. box;
  1729. if (inverted) {
  1730. renderer.invertChild(element, parentNode);
  1731. }
  1732. if (docMode8 && parentNode.gVis == HIDDEN) {
  1733. css(element, { visibility: HIDDEN });
  1734. }
  1735. parentNode.appendChild(element);
  1736. wrapper.added = true;
  1737. if (wrapper.alignOnAdd) {
  1738. wrapper.updateTransform();
  1739. }
  1740. return wrapper;
  1741. },
  1742. attr: function(hash, val) {
  1743. var key,
  1744. value,
  1745. i,
  1746. element = this.element || {},
  1747. elemStyle = element.style,
  1748. nodeName = element.nodeName,
  1749. renderer = this.renderer,
  1750. symbolName = this.symbolName,
  1751. childNodes,
  1752. hasSetSymbolSize,
  1753. shadows = this.shadows,
  1754. skipAttr,
  1755. ret = this;
  1756. if (isString(hash) && defined(val)) {
  1757. key = hash;
  1758. hash = {};
  1759. hash[key] = val;
  1760. }
  1761. if (isString(hash)) {
  1762. key = hash;
  1763. if (key == 'strokeWidth' || key == 'stroke-width') {
  1764. ret = this.strokeweight;
  1765. } else {
  1766. ret = this[key];
  1767. }
  1768. } else {
  1769. for (key in hash) {
  1770. value = hash[key];
  1771. skipAttr = false;
  1772. if (symbolName && /^(x|y|r|start|end|width|height|innerR)/.test(key)) {
  1773. if (!hasSetSymbolSize) {
  1774. this.symbolAttr(hash);
  1775. hasSetSymbolSize = true;
  1776. }
  1777. skipAttr = true;
  1778. } else if (key == 'd') {
  1779. value = value || [];
  1780. this.d = value.join(' ');
  1781. i = value.length;
  1782. var convertedPath = [];
  1783. while (i--) {
  1784. if (isNumber(value[i])) {
  1785. convertedPath[i] = mathRound(value[i] * 10) - 5;
  1786. }
  1787. else if (value[i] == 'Z') {
  1788. convertedPath[i] = 'x';
  1789. }
  1790. else {
  1791. convertedPath[i] = value[i];
  1792. }
  1793. }
  1794. value = convertedPath.join(' ') || 'x';
  1795. element.path = value;
  1796. if (shadows) {
  1797. i = shadows.length;
  1798. while (i--) {
  1799. shadows[i].path = value;
  1800. }
  1801. }
  1802. skipAttr = true;
  1803. } else if (key == 'zIndex' || key == 'visibility') {
  1804. if (docMode8 && key == 'visibility' && nodeName == 'DIV') {
  1805. element.gVis = value;
  1806. childNodes = element.childNodes;
  1807. i = childNodes.length;
  1808. while (i--) {
  1809. css(childNodes[i], { visibility: value });
  1810. }
  1811. if (value == VISIBLE) {
  1812. value = null;
  1813. }
  1814. }
  1815. if (value) {
  1816. elemStyle[key] = value;
  1817. }
  1818. skipAttr = true;
  1819. } else if (/^(width|height)$/.test(key)) {
  1820. if (this.updateClipping) {
  1821. this[key] = value;
  1822. this.updateClipping();
  1823. } else {
  1824. elemStyle[key] = value;
  1825. }
  1826. skipAttr = true;
  1827. } else if (/^(x|y)$/.test(key)) {
  1828. this[key] = value;
  1829. if (element.tagName == 'SPAN') {
  1830. this.updateTransform();
  1831. } else {
  1832. elemStyle[{ x: 'left', y: 'top' }[key]] = value;
  1833. }
  1834. } else if (key == 'class') {
  1835. element.className = value;
  1836. } else if (key == 'stroke') {
  1837. value = renderer.color(value, element, key);
  1838. key = 'strokecolor';
  1839. } else if (key == 'stroke-width' || key == 'strokeWidth') {
  1840. element.stroked = value ? true : false;
  1841. key = 'strokeweight';
  1842. this[key] = value;
  1843. if (isNumber(value)) {
  1844. value += PX;
  1845. }
  1846. } else if (key == 'dashstyle') {
  1847. var strokeElem = element.getElementsByTagName('stroke')[0] ||
  1848. createElement(renderer.prepVML(['<stroke/>']), null, null, element);
  1849. strokeElem[key] = value || 'solid';
  1850. this.dashstyle = value;
  1851. skipAttr = true;
  1852. } else if (key == 'fill') {
  1853. if (nodeName == 'SPAN') {
  1854. elemStyle.color = value;
  1855. } else {
  1856. element.filled = value != NONE ? true : false;
  1857. value = renderer.color(value, element, key);
  1858. key = 'fillcolor';
  1859. }
  1860. } else if (key == 'translateX' || key == 'translateY' || key == 'rotation' || key == 'align') {
  1861. if (key == 'align') {
  1862. key = 'textAlign';
  1863. }
  1864. this[key] = value;
  1865. this.updateTransform();
  1866. skipAttr = true;
  1867. }
  1868. else if (key == 'text') {
  1869. element.innerHTML = value;
  1870. skipAttr = true;
  1871. }
  1872. if (shadows && key == 'visibility') {
  1873. i = shadows.length;
  1874. while (i--) {
  1875. shadows[i].style[key] = value;
  1876. }
  1877. }
  1878. if (!skipAttr) {
  1879. if (docMode8) {
  1880. element[key] = value;
  1881. } else {
  1882. attr(element, key, value);
  1883. }
  1884. }
  1885. }
  1886. }
  1887. return ret;
  1888. },
  1889. clip: function(clipRect) {
  1890. var wrapper = this,
  1891. clipMembers = clipRect.members;
  1892. clipMembers.push(wrapper);
  1893. wrapper.destroyClip = function() {
  1894. erase(clipMembers, wrapper);
  1895. };
  1896. return wrapper.css(clipRect.getCSS(wrapper.inverted));
  1897. },
  1898. css: function(styles) {
  1899. var wrapper = this,
  1900. element = wrapper.element,
  1901. textWidth = styles && element.tagName == 'SPAN' && styles.width;
  1902. if (textWidth) {
  1903. delete styles.width;
  1904. wrapper.textWidth = textWidth;
  1905. wrapper.updateTransform();
  1906. }
  1907. wrapper.styles = extend(wrapper.styles, styles);
  1908. css(wrapper.element, styles);
  1909. return wrapper;
  1910. },
  1911. destroy: function() {
  1912. var wrapper = this;
  1913. if (wrapper.destroyClip) {
  1914. wrapper.destroyClip();
  1915. }
  1916. SVGElement.prototype.destroy.apply(wrapper);
  1917. },
  1918. empty: function() {
  1919. var element = this.element,
  1920. childNodes = element.childNodes,
  1921. i = childNodes.length,
  1922. node;
  1923. while (i--) {
  1924. node = childNodes[i];
  1925. node.parentNode.removeChild(node);
  1926. }
  1927. },
  1928. getBBox: function() {
  1929. var element = this.element;
  1930. if (element.nodeName == 'text') {
  1931. element.style.position = ABSOLUTE;
  1932. }
  1933. return {
  1934. x: element.offsetLeft,
  1935. y: element.offsetTop,
  1936. width: element.offsetWidth,
  1937. height: element.offsetHeight
  1938. };
  1939. },
  1940. on: function(eventType, handler) {
  1941. this.element['on'+ eventType] = function() {
  1942. var evt = win.m_event;
  1943. evt.target = evt.srcElement;
  1944. handler(evt);
  1945. };
  1946. return this;
  1947. },
  1948. updateTransform: function(hash) {
  1949. if (!this.added) {
  1950. this.alignOnAdd = true;
  1951. return;
  1952. }
  1953. var wrapper = this,
  1954. elem = wrapper.element,
  1955. translateX = wrapper.translateX || 0,
  1956. translateY = wrapper.translateY || 0,
  1957. x = wrapper.x || 0,
  1958. y = wrapper.y || 0,
  1959. align = wrapper.textAlign || 'left',
  1960. alignCorrection = { left: 0, center: 0.5, right: 1 }[align],
  1961. nonLeft = align && align != 'left';
  1962. if (translateX || translateY) {
  1963. wrapper.css({
  1964. marginLeft: translateX,
  1965. marginTop: translateY
  1966. });
  1967. }
  1968. if (wrapper.inverted) {
  1969. each(elem.childNodes, function(child) {
  1970. wrapper.renderer.invertChild(child, elem);
  1971. });
  1972. }
  1973. if (elem.tagName == 'SPAN') {
  1974. var width, height,
  1975. rotation = wrapper.rotation,
  1976. lineHeight,
  1977. radians = 0,
  1978. costheta = 1,
  1979. sintheta = 0,
  1980. quad,
  1981. textWidth = pInt(wrapper.textWidth),
  1982. xCorr = wrapper.xCorr || 0,
  1983. yCorr = wrapper.yCorr || 0,
  1984. currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
  1985. if (currentTextTransform != wrapper.cTT) {
  1986. if (defined(rotation)) {
  1987. radians = rotation * deg2rad;
  1988. costheta = mathCos(radians);
  1989. sintheta = mathSin(radians);
  1990. css(elem, {
  1991. filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
  1992. ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
  1993. ', sizingMethod=\'auto expand\')'].join('') : NONE
  1994. });
  1995. }
  1996. width = elem.offsetWidth;
  1997. height = elem.offsetHeight;
  1998. if (width > textWidth) {
  1999. css(elem, {
  2000. width: textWidth +PX,
  2001. display: 'block',
  2002. whiteSpace: 'normal'
  2003. });
  2004. width = textWidth;
  2005. }
  2006. lineHeight = mathRound(pInt(elem.style.fontSize || 12) * 1.2);
  2007. xCorr = costheta < 0 && -width;
  2008. yCorr = sintheta < 0 && -height;
  2009. quad = costheta * sintheta < 0;
  2010. xCorr += sintheta * lineHeight * (quad ? 1 - alignCorrection : alignCorrection);
  2011. yCorr -= costheta * lineHeight * (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1);
  2012. if (nonLeft) {
  2013. xCorr -= width * alignCorrection * (costheta < 0 ? -1 : 1);
  2014. if (rotation) {
  2015. yCorr -= height * alignCorrection * (sintheta < 0 ? -1 : 1);
  2016. }
  2017. css(elem, {
  2018. textAlign: align
  2019. });
  2020. }
  2021. wrapper.xCorr = xCorr;
  2022. wrapper.yCorr = yCorr;
  2023. }
  2024. css(elem, {
  2025. left: x + xCorr,
  2026. top: y + yCorr
  2027. });
  2028. wrapper.cTT = currentTextTransform;
  2029. }
  2030. },
  2031. shadow: function(apply) {
  2032. var shadows = [],
  2033. i,
  2034. element = this.element,
  2035. renderer = this.renderer,
  2036. shadow,
  2037. elemStyle = element.style,
  2038. markup,
  2039. path = element.path;
  2040. if (''+ element.path === '') {
  2041. path = 'x';
  2042. }
  2043. if (apply) {
  2044. for (i = 1; i <= 3; i++) {
  2045. markup = ['<shape isShadow="true" strokeweight="', ( 7 - 2 * i ) ,
  2046. '" filled="false" path="', path,
  2047. '" coordsize="100,100" style="', element.style.cssText, '" />'];
  2048. shadow = createElement(renderer.prepVML(markup),
  2049. null, {
  2050. left: pInt(elemStyle.left) + 1,
  2051. top: pInt(elemStyle.top) + 1
  2052. }
  2053. );
  2054. markup = ['<stroke color="black" opacity="', (0.05 * i), '"/>'];
  2055. createElement(renderer.prepVML(markup), null, null, shadow);
  2056. element.parentNode.insertBefore(shadow, element);
  2057. shadows.push(shadow);
  2058. }
  2059. this.shadows = shadows;
  2060. }
  2061. return this;
  2062. }
  2063. });
  2064. VMLRenderer = function() {
  2065. this.init.apply(this, arguments);
  2066. };
  2067. VMLRenderer.prototype = merge( SVGRenderer.prototype, {
  2068. isIE8: userAgent.indexOf('MSIE 8.0') > -1,
  2069. init: function(container, width, height) {
  2070. var renderer = this,
  2071. boxWrapper;
  2072. renderer.Element = VMLElement;
  2073. renderer.alignedObjects = [];
  2074. boxWrapper = renderer.createElement(DIV);
  2075. container.appendChild(boxWrapper.element);
  2076. renderer.box = boxWrapper.element;
  2077. renderer.boxWrapper = boxWrapper;
  2078. renderer.setSize(width, height, false);
  2079. if (!doc.namespaces.hcv) {
  2080. doc.namespaces.add('hcv', 'urn:schemas-microsoft-com:vml');
  2081. doc.createStyleSheet().cssText =
  2082. 'hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke'+
  2083. '{ behavior:url(#default#VML); display: inline-block; } ';
  2084. }
  2085. },
  2086. clipRect: function (x, y, width, height) {
  2087. var clipRect = this.createElement();
  2088. return extend(clipRect, {
  2089. members: [],
  2090. left: x,
  2091. top: y,
  2092. width: width,
  2093. height: height,
  2094. getCSS: function(inverted) {
  2095. var rect = this,
  2096. top = rect.top,
  2097. left = rect.left,
  2098. right = left + rect.width,
  2099. bottom = top + rect.height,
  2100. ret = {
  2101. clip: 'rect('+
  2102. mathRound(inverted ? left : top) + 'px,'+
  2103. mathRound(inverted ? bottom : right) + 'px,'+
  2104. mathRound(inverted ? right : bottom) + 'px,'+
  2105. mathRound(inverted ? top : left) +'px)'
  2106. };
  2107. if (!inverted && docMode8) {
  2108. extend(ret, {
  2109. width: right +PX,
  2110. height: bottom +PX
  2111. });
  2112. }
  2113. return ret;
  2114. },
  2115. updateClipping: function() {
  2116. each(clipRect.members, function(member) {
  2117. member.css(clipRect.getCSS(member.inverted));
  2118. });
  2119. }
  2120. });
  2121. },
  2122. color: function(color, elem, prop) {
  2123. var colorObject,
  2124. regexRgba = /^rgba/,
  2125. markup;
  2126. if (color && color.linearGradient) {
  2127. var stopColor,
  2128. stopOpacity,
  2129. linearGradient = color.linearGradient,
  2130. angle,
  2131. color1,
  2132. opacity1,
  2133. color2,
  2134. opacity2;
  2135. each(color.stops, function(stop, i) {
  2136. if (regexRgba.test(stop[1])) {
  2137. colorObject = Color(stop[1]);
  2138. stopColor = colorObject.get('rgb');
  2139. stopOpacity = colorObject.get('a');
  2140. } else {
  2141. stopColor = stop[1];
  2142. stopOpacity = 1;
  2143. }
  2144. if (!i) {
  2145. color1 = stopColor;
  2146. opacity1 = stopOpacity;
  2147. } else {
  2148. color2 = stopColor;
  2149. opacity2 = stopOpacity;
  2150. }
  2151. });
  2152. angle = 90 - math.atan(
  2153. (linearGradient[3] - linearGradient[1]) /
  2154. (linearGradient[2] - linearGradient[0])
  2155. ) * 180 / mathPI;
  2156. markup = ['<', prop, ' colors="0% ', color1, ',100% ', color2, '" angle="', angle,
  2157. '" opacity="', opacity2, '" o:opacity2="', opacity1,
  2158. '" type="gradient" focus="100%" />'];
  2159. createElement(this.prepVML(markup), null, null, elem);
  2160. } else if (regexRgba.test(color) && elem.tagName != 'IMG') {
  2161. colorObject = Color(color);
  2162. markup = ['<', prop, ' opacity="', colorObject.get('a'), '"/>'];
  2163. createElement(this.prepVML(markup), null, null, elem);
  2164. return colorObject.get('rgb');
  2165. } else {
  2166. return color;
  2167. }
  2168. },
  2169. prepVML: function(markup) {
  2170. var vmlStyle = 'display:inline-block;behavior:url(#default#VML);',
  2171. isIE8 = this.isIE8;
  2172. markup = markup.join('');
  2173. if (isIE8) {
  2174. markup = markup.replace('/>', ' xmlns="urn:schemas-microsoft-com:vml" />');
  2175. if (markup.indexOf('style="') == -1) {
  2176. markup = markup.replace('/>', ' style="'+ vmlStyle +'" />');
  2177. } else {
  2178. markup = markup.replace('style="', 'style="'+ vmlStyle);
  2179. }
  2180. } else {
  2181. markup = markup.replace('<', '<hcv:');
  2182. }
  2183. return markup;
  2184. },
  2185. text: function(str, x, y) {
  2186. var defaultChartStyle = defaultOptions.chart.style;
  2187. return this.createElement('span')
  2188. .attr({
  2189. text: str,
  2190. x: mathRound(x),
  2191. y: mathRound(y)
  2192. })
  2193. .css({
  2194. whiteSpace: 'nowrap',
  2195. fontFamily: defaultChartStyle.fontFamily,
  2196. fontSize: defaultChartStyle.fontSize
  2197. });
  2198. },
  2199. path: function (path) {
  2200. return this.createElement('shape').attr({
  2201. coordsize: '100 100',
  2202. d: path
  2203. });
  2204. },
  2205. circle: function(x, y, r) {
  2206. return this.path(this.symbols.circle(x, y, r));
  2207. },
  2208. g: function(name) {
  2209. var wrapper,
  2210. attribs;
  2211. if (name) {
  2212. attribs = { 'className': PREFIX + name, 'class': PREFIX + name };
  2213. }
  2214. wrapper = this.createElement(DIV).attr(attribs);
  2215. return wrapper;
  2216. },
  2217. image: function(src, x, y, width, height) {
  2218. var obj = this.createElement('img')
  2219. .attr({ src: src });
  2220. if (arguments.length > 1) {
  2221. obj.css({
  2222. left: x,
  2223. top: y,
  2224. width: width,
  2225. height: height
  2226. });
  2227. }
  2228. return obj;
  2229. },
  2230. rect: function(x, y, width, height, r, strokeWidth) {
  2231. if (isObject(x)) {
  2232. y = x.y;
  2233. width = x.width;
  2234. height = x.height;
  2235. r = x.r;
  2236. x = x.x;
  2237. }
  2238. var wrapper = this.symbol('rect');
  2239. wrapper.r = r;
  2240. return wrapper.attr(wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0)));
  2241. },
  2242. invertChild: function(element, parentNode) {
  2243. var parentStyle = parentNode.style;
  2244. css(element, {
  2245. flip: 'x',
  2246. left: pInt(parentStyle.width) - 10,
  2247. top: pInt(parentStyle.height) - 10,
  2248. rotation: -90
  2249. });
  2250. },
  2251. symbols: {
  2252. arc: function (x, y, radius, options) {
  2253. var start = options.start,
  2254. end = options.end,
  2255. cosStart = mathCos(start),
  2256. sinStart = mathSin(start),
  2257. cosEnd = mathCos(end),
  2258. sinEnd = mathSin(end),
  2259. innerRadius = options.innerR,
  2260. circleCorrection = 0.07 / radius,
  2261. innerCorrection = innerRadius && 0.1 / innerRadius || 0;
  2262. if (end - start === 0) {
  2263. return ['x'];
  2264. } else if (2 * mathPI - end + start < circleCorrection) {
  2265. cosEnd = - circleCorrection;
  2266. } else if (end - start < innerCorrection) {
  2267. cosEnd = mathCos(start + innerCorrection);
  2268. }
  2269. return [
  2270. 'wa',
  2271. x - radius,
  2272. y - radius,
  2273. x + radius,
  2274. y + radius,
  2275. x + radius * cosStart,
  2276. y + radius * sinStart,
  2277. x + radius * cosEnd,
  2278. y + radius * sinEnd,
  2279. 'at',
  2280. x - innerRadius,
  2281. y - innerRadius,
  2282. x + innerRadius,
  2283. y + innerRadius,
  2284. x + innerRadius * cosEnd,
  2285. y + innerRadius * sinEnd,
  2286. x + innerRadius * cosStart,
  2287. y + innerRadius * sinStart,
  2288. 'x',
  2289. 'e'
  2290. ];
  2291. },
  2292. circle: function (x, y, r) {
  2293. return [
  2294. 'wa',
  2295. x - r,
  2296. y - r,
  2297. x + r,
  2298. y + r,
  2299. x + r,
  2300. y,
  2301. x + r,
  2302. y,
  2303. 'e'
  2304. ];
  2305. },
  2306. rect: function (left, top, r, options) {
  2307. if (!defined(options)) {
  2308. return [];
  2309. }
  2310. var width = options.width,
  2311. height = options.height,
  2312. right = left + width,
  2313. bottom = top + height;
  2314. r = mathMin(r, width, height);
  2315. return [
  2316. M,
  2317. left + r, top,
  2318. L,
  2319. right - r, top,
  2320. 'wa',
  2321. right - 2 * r, top,
  2322. right, top + 2 * r,
  2323. right - r, top,
  2324. right, top + r,
  2325. L,
  2326. right, bottom - r,
  2327. 'wa',
  2328. right - 2 * r, bottom - 2 * r,
  2329. right, bottom,
  2330. right, bottom - r,
  2331. right - r, bottom,
  2332. L,
  2333. left + r, bottom,
  2334. 'wa',
  2335. left, bottom - 2 * r,
  2336. left + 2 * r, bottom,
  2337. left + r, bottom,
  2338. left, bottom - r,
  2339. L,
  2340. left, top + r,
  2341. 'wa',
  2342. left, top,
  2343. left + 2 * r, top + 2 * r,
  2344. left, top + r,
  2345. left + r, top,
  2346. 'x',
  2347. 'e'
  2348. ];
  2349. }
  2350. }
  2351. });
  2352. }
  2353. var Renderer = hasSVG ? SVGRenderer : VMLRenderer;
  2354. function Chart (options, callback) {
  2355. defaultXAxisOptions = merge(defaultXAxisOptions, defaultOptions.xAxis);
  2356. defaultYAxisOptions = merge(defaultYAxisOptions, defaultOptions.yAxis);
  2357. defaultOptions.xAxis = defaultOptions.yAxis = null;
  2358. options = merge(defaultOptions, options);
  2359. var optionsChart = options.chart,
  2360. optionsMargin = optionsChart.margin,
  2361. margin = isObject(optionsMargin) ?
  2362. optionsMargin :
  2363. [optionsMargin, optionsMargin, optionsMargin, optionsMargin],
  2364. optionsMarginTop = pick(optionsChart.marginTop, margin[0]),
  2365. optionsMarginRight = pick(optionsChart.marginRight, margin[1]),
  2366. optionsMarginBottom = pick(optionsChart.marginBottom, margin[2]),
  2367. optionsMarginLeft = pick(optionsChart.marginLeft, margin[3]),
  2368. spacingTop = optionsChart.spacingTop,
  2369. spacingRight = optionsChart.spacingRight,
  2370. spacingBottom = optionsChart.spacingBottom,
  2371. spacingLeft = optionsChart.spacingLeft,
  2372. spacingBox,
  2373. chartTitleOptions,
  2374. chartSubtitleOptions,
  2375. plotTop,
  2376. marginRight,
  2377. marginBottom,
  2378. plotLeft,
  2379. axisOffset,
  2380. renderTo,
  2381. renderToClone,
  2382. container,
  2383. containerId,
  2384. containerWidth,
  2385. containerHeight,
  2386. chartWidth,
  2387. chartHeight,
  2388. oldChartWidth,
  2389. oldChartHeight,
  2390. chartBackground,
  2391. plotBackground,
  2392. plotBGImage,
  2393. plotBorder,
  2394. chart = this,
  2395. chartEvents = optionsChart.events,
  2396. runChartClick = chartEvents && !!chartEvents.click,
  2397. eventType,
  2398. isInsidePlot,
  2399. tooltip,
  2400. mouseIsDown,
  2401. loadingDiv,
  2402. loadingSpan,
  2403. loadingShown,
  2404. plotHeight,
  2405. plotWidth,
  2406. tracker,
  2407. trackerGroup,
  2408. placeTrackerGroup,
  2409. legend,
  2410. legendWidth,
  2411. legendHeight,
  2412. chartPosition,
  2413. hasCartesianSeries = optionsChart.showAxes,
  2414. isResizing = 0,
  2415. axes = [],
  2416. maxTicks,
  2417. series = [],
  2418. inverted,
  2419. renderer,
  2420. tooltipTick,
  2421. tooltipInterval,
  2422. hoverX,
  2423. drawChartBox,
  2424. getMargins,
  2425. resetMargins,
  2426. setChartSize,
  2427. resize,
  2428. zoom,
  2429. zoomOut;
  2430. function Axis (chart, options) {
  2431. var isXAxis = options.isX,
  2432. opposite = options.opposite,
  2433. horiz = inverted ? !isXAxis : isXAxis,
  2434. side = horiz ?
  2435. (opposite ? 0 : 2 ) :
  2436. (opposite ? 1 : 3 ),
  2437. stacks = {};
  2438. options = merge(
  2439. isXAxis ? defaultXAxisOptions : defaultYAxisOptions,
  2440. [defaultTopAxisOptions, defaultRightAxisOptions,
  2441. defaultBottomAxisOptions, defaultLeftAxisOptions][side],
  2442. options
  2443. );
  2444. var axis = this,
  2445. isDatetimeAxis = options.type == 'datetime',
  2446. offset = options.offset || 0,
  2447. xOrY = isXAxis ? 'x' : 'y',
  2448. axisLength,
  2449. transA,
  2450. oldTransA,
  2451. transB = horiz ? plotLeft : marginBottom,
  2452. translate,
  2453. getPlotLinePath,
  2454. axisGroup,
  2455. gridGroup,
  2456. axisLine,
  2457. dataMin,
  2458. dataMax,
  2459. associatedSeries,
  2460. userSetMin,
  2461. userSetMax,
  2462. max = null,
  2463. min = null,
  2464. oldMin,
  2465. oldMax,
  2466. minPadding = options.minPadding,
  2467. maxPadding = options.maxPadding,
  2468. isLinked = defined(options.linkedTo),
  2469. ignoreMinPadding,
  2470. ignoreMaxPadding,
  2471. usePercentage,
  2472. events = options.events,
  2473. eventType,
  2474. plotLinesAndBands = [],
  2475. tickInterval,
  2476. minorTickInterval,
  2477. magnitude,
  2478. tickPositions,
  2479. ticks = {},
  2480. minorTicks = {},
  2481. alternateBands = {},
  2482. tickAmount,
  2483. labelOffset,
  2484. axisTitleMargin,
  2485. dateTimeLabelFormat,
  2486. categories = options.categories,
  2487. labelFormatter = options.labels.formatter ||
  2488. function() {
  2489. var value = this.value,
  2490. ret;
  2491. if (dateTimeLabelFormat) {
  2492. ret = dateFormat(dateTimeLabelFormat, value);
  2493. } else if (tickInterval % 1000000 === 0) {
  2494. ret = (value / 1000000) +'M';
  2495. } else if (tickInterval % 1000 === 0) {
  2496. ret = (value / 1000) +'k';
  2497. } else if (!categories && value >= 1000) {
  2498. ret = numberFormat(value, 0);
  2499. } else {
  2500. ret = value;
  2501. }
  2502. return ret;
  2503. },
  2504. staggerLines = horiz && options.labels.staggerLines,
  2505. reversed = options.reversed,
  2506. tickmarkOffset = (categories && options.tickmarkPlacement == 'between') ? 0.5 : 0;
  2507. function Tick(pos, minor) {
  2508. var tick = this;
  2509. tick.pos = pos;
  2510. tick.minor = minor;
  2511. tick.isNew = true;
  2512. if (!minor) {
  2513. tick.addLabel();
  2514. }
  2515. }
  2516. Tick.prototype = {
  2517. addLabel: function() {
  2518. var pos = this.pos,
  2519. labelOptions = options.labels,
  2520. str,
  2521. withLabel = !((pos == min && !pick(options.showFirstLabel, 1)) ||
  2522. (pos == max && !pick(options.showLastLabel, 0))),
  2523. width = categories && horiz && categories.length &&
  2524. !labelOptions.step && !labelOptions.staggerLines &&
  2525. !labelOptions.rotation &&
  2526. plotWidth / categories.length ||
  2527. !horiz && plotWidth / 2,
  2528. css,
  2529. label = this.label;
  2530. str = labelFormatter.call({
  2531. isFirst: pos == tickPositions[0],
  2532. isLast: pos == tickPositions[tickPositions.length - 1],
  2533. dateTimeLabelFormat: dateTimeLabelFormat,
  2534. value: (categories && categories[pos] ? categories[pos] : pos)
  2535. });
  2536. css = width && { width: (width - 2 * (labelOptions.padding || 10)) +PX };
  2537. css = extend(css, labelOptions.style);
  2538. if (label === UNDEFINED) {
  2539. this.label =
  2540. defined(str) && withLabel && labelOptions.enabled ?
  2541. renderer.text(
  2542. str,
  2543. 0,
  2544. 0
  2545. )
  2546. .attr({
  2547. align: labelOptions.align,
  2548. rotation: labelOptions.rotation
  2549. })
  2550. .css(css)
  2551. .add(axisGroup):
  2552. null;
  2553. } else if (label) {
  2554. label.attr({ text: str })
  2555. .css(css);
  2556. }
  2557. },
  2558. getLabelSize: function() {
  2559. var label = this.label;
  2560. return label ?
  2561. ((this.labelBBox = label.getBBox()))[horiz ? 'height' : 'width'] :
  2562. 0;
  2563. },
  2564. render: function(index, old) {
  2565. var tick = this,
  2566. major = !tick.minor,
  2567. label = tick.label,
  2568. pos = tick.pos,
  2569. labelOptions = options.labels,
  2570. gridLine = tick.gridLine,
  2571. gridLineWidth = major ? options.gridLineWidth : options.minorGridLineWidth,
  2572. gridLineColor = major ? options.gridLineColor : options.minorGridLineColor,
  2573. dashStyle = major ?
  2574. options.gridLineDashStyle :
  2575. options.minorGridLineDashStyle,
  2576. gridLinePath,
  2577. mark = tick.mark,
  2578. markPath,
  2579. tickLength = major ? options.tickLength : options.minorTickLength,
  2580. tickWidth = major ? options.tickWidth : (options.minorTickWidth || 0),
  2581. tickColor = major ? options.tickColor : options.minorTickColor,
  2582. tickPosition = major ? options.tickPosition : options.minorTickPosition,
  2583. step = labelOptions.step,
  2584. cHeight = old && oldChartHeight || chartHeight,
  2585. attribs,
  2586. x,
  2587. y;
  2588. x = horiz ?
  2589. translate(pos + tickmarkOffset, null, null, old) + transB :
  2590. plotLeft + offset + (opposite ? (old && oldChartWidth || chartWidth) - marginRight - plotLeft : 0);
  2591. y = horiz ?
  2592. cHeight - marginBottom + offset - (opposite ? plotHeight : 0) :
  2593. cHeight - translate(pos + tickmarkOffset, null, null, old) - transB;
  2594. if (gridLineWidth) {
  2595. gridLinePath = getPlotLinePath(pos + tickmarkOffset, gridLineWidth, old);
  2596. if (gridLine === UNDEFINED) {
  2597. attribs = {
  2598. stroke: gridLineColor,
  2599. 'stroke-width': gridLineWidth
  2600. };
  2601. if (dashStyle) {
  2602. attribs.dashstyle = dashStyle;
  2603. }
  2604. tick.gridLine = gridLine =
  2605. gridLineWidth ?
  2606. renderer.path(gridLinePath)
  2607. .attr(attribs).add(gridGroup) :
  2608. null;
  2609. }
  2610. if (gridLine && gridLinePath) {
  2611. gridLine.animate({
  2612. d: gridLinePath
  2613. });
  2614. }
  2615. }
  2616. if (tickWidth) {
  2617. if (tickPosition == 'inside') {
  2618. tickLength = -tickLength;
  2619. }
  2620. if (opposite) {
  2621. tickLength = -tickLength;
  2622. }
  2623. markPath = renderer.crispLine([
  2624. M,
  2625. x,
  2626. y,
  2627. L,
  2628. x + (horiz ? 0 : -tickLength),
  2629. y + (horiz ? tickLength : 0)
  2630. ], tickWidth);
  2631. if (mark) {
  2632. mark.animate({
  2633. d: markPath
  2634. });
  2635. } else {
  2636. tick.mark = renderer.path(
  2637. markPath
  2638. ).attr({
  2639. stroke: tickColor,
  2640. 'stroke-width': tickWidth
  2641. }).add(axisGroup);
  2642. }
  2643. }
  2644. if (label) {
  2645. x = x + labelOptions.x - (tickmarkOffset && horiz ?
  2646. tickmarkOffset * transA * (reversed ? -1 : 1) : 0);
  2647. y = y + labelOptions.y - (tickmarkOffset && !horiz ?
  2648. tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
  2649. if (!defined(labelOptions.y)) {
  2650. y += parseInt(label.styles.lineHeight) * 0.9 - label.getBBox().height / 2;
  2651. }
  2652. if (staggerLines) {
  2653. y += (index % staggerLines) * 16;
  2654. }
  2655. if (step) {
  2656. label[index % step ? 'hide' : 'show']();
  2657. }
  2658. label[tick.isNew ? 'attr' : 'animate']({
  2659. x: x,
  2660. y: y
  2661. });
  2662. }
  2663. tick.isNew = false;
  2664. },
  2665. destroy: function() {
  2666. var tick = this,
  2667. n;
  2668. for (n in tick) {
  2669. if (tick[n] && tick[n].destroy) {
  2670. tick[n].destroy();
  2671. }
  2672. }
  2673. }
  2674. };
  2675. function PlotLineOrBand(options) {
  2676. var plotLine = this;
  2677. if (options) {
  2678. plotLine.options = options;
  2679. plotLine.id = options.id;
  2680. }
  2681. return plotLine;
  2682. }
  2683. PlotLineOrBand.prototype = {
  2684. render: function () {
  2685. var plotLine = this,
  2686. options = plotLine.options,
  2687. optionsLabel = options.label,
  2688. label = plotLine.label,
  2689. width = options.width,
  2690. to = options.to,
  2691. toPath,
  2692. from = options.from,
  2693. dashStyle = options.dashStyle,
  2694. svgElem = plotLine.svgElem,
  2695. path = [],
  2696. addEvent,
  2697. eventType,
  2698. xs,
  2699. ys,
  2700. x,
  2701. y,
  2702. color = options.color,
  2703. zIndex = options.zIndex,
  2704. events = options.events,
  2705. attribs;
  2706. if (width) {
  2707. path = getPlotLinePath(options.value, width);
  2708. attribs = {
  2709. stroke: color,
  2710. 'stroke-width': width
  2711. };
  2712. if (dashStyle) {
  2713. attribs.dashstyle = dashStyle;
  2714. }
  2715. }
  2716. else if (defined(from) && defined(to)) {
  2717. from = mathMax(from, min);
  2718. to = mathMin(to, max);
  2719. toPath = getPlotLinePath(to);
  2720. path = getPlotLinePath(from);
  2721. if (path && toPath) {
  2722. path.push(
  2723. toPath[4],
  2724. toPath[5],
  2725. toPath[1],
  2726. toPath[2]
  2727. );
  2728. } else {
  2729. path = null;
  2730. }
  2731. attribs = {
  2732. fill: color
  2733. };
  2734. } else {
  2735. return;
  2736. }
  2737. if (defined(zIndex)) {
  2738. attribs.zIndex = zIndex;
  2739. }
  2740. if (svgElem) {
  2741. if (path) {
  2742. svgElem.animate({
  2743. d: path
  2744. }, null, svgElem.onGetPath);
  2745. } else {
  2746. svgElem.hide();
  2747. svgElem.onGetPath = function() {
  2748. svgElem.show();
  2749. }
  2750. }
  2751. } else if (path && path.length) {
  2752. plotLine.svgElem = svgElem = renderer.path(path)
  2753. .attr(attribs).add();
  2754. if (events) {
  2755. addEvent = function(eventType) {
  2756. svgElem.on(eventType, function(e) {
  2757. events[eventType].apply(plotLine, [e]);
  2758. });
  2759. };
  2760. for (eventType in events) {
  2761. addEvent(eventType);
  2762. }
  2763. }
  2764. }
  2765. if (optionsLabel && defined(optionsLabel.text) && path && path.length && plotWidth > 0 && plotHeight > 0) {
  2766. optionsLabel = merge({
  2767. align: horiz && toPath && 'center',
  2768. x: horiz ? !toPath && 4 : 10,
  2769. verticalAlign : !horiz && toPath && 'middle',
  2770. y: horiz ? toPath ? 16 : 10 : toPath ? 6 : -4,
  2771. rotation: horiz && !toPath && 90
  2772. }, optionsLabel);
  2773. if (!label) {
  2774. plotLine.label = label = renderer.text(
  2775. optionsLabel.text,
  2776. 0,
  2777. 0
  2778. )
  2779. .attr({
  2780. align: optionsLabel.textAlign || optionsLabel.align,
  2781. rotation: optionsLabel.rotation,
  2782. zIndex: zIndex
  2783. })
  2784. .css(optionsLabel.style)
  2785. .add();
  2786. }
  2787. xs = [path[1], path[4], path[6] || path[1]];
  2788. ys = [path[2], path[5], path[7] || path[2]];
  2789. x = mathMin.apply(math, xs);
  2790. y = mathMin.apply(math, ys);
  2791. label.align(optionsLabel, false, {
  2792. x: x,
  2793. y: y,
  2794. width: mathMax.apply(math, xs) - x,
  2795. height: mathMax.apply(math, ys) - y
  2796. });
  2797. label.show();
  2798. } else if (label) {
  2799. label.hide();
  2800. }
  2801. return plotLine;
  2802. },
  2803. destroy: function() {
  2804. var obj = this,
  2805. n;
  2806. for (n in obj) {
  2807. if (obj[n] && obj[n].destroy) {
  2808. obj[n].destroy();
  2809. }
  2810. delete obj[n];
  2811. }
  2812. erase(plotLinesAndBands, obj);
  2813. }
  2814. };
  2815. function getSeriesExtremes() {
  2816. var posStack = [],
  2817. negStack = [],
  2818. run;
  2819. dataMin = dataMax = null;
  2820. associatedSeries = [];
  2821. each(series, function(serie) {
  2822. run = false;
  2823. each(['xAxis', 'yAxis'], function(strAxis) {
  2824. if (
  2825. serie.isCartesian &&
  2826. (strAxis == 'xAxis' && isXAxis || strAxis == 'yAxis' && !isXAxis) && (
  2827. (serie.options[strAxis] == options.index) ||
  2828. (serie.options[strAxis] === UNDEFINED && options.index === 0)
  2829. )
  2830. ) {
  2831. serie[strAxis] = axis;
  2832. associatedSeries.push(serie);
  2833. run = true;
  2834. }
  2835. });
  2836. if (!serie.visible && optionsChart.ignoreHiddenSeries) {
  2837. run = false;
  2838. }
  2839. if (run) {
  2840. var stacking,
  2841. posPointStack,
  2842. negPointStack,
  2843. stackKey,
  2844. negKey;
  2845. if (!isXAxis) {
  2846. stacking = serie.options.stacking;
  2847. usePercentage = stacking == 'percent';
  2848. if (stacking) {
  2849. stackKey = serie.type + pick(serie.options.stack, '');
  2850. negKey = '-'+ stackKey;
  2851. serie.stackKey = stackKey;
  2852. posPointStack = posStack[stackKey] || [];
  2853. posStack[stackKey] = posPointStack;
  2854. negPointStack = negStack[negKey] || [];
  2855. negStack[negKey] = negPointStack;
  2856. }
  2857. if (usePercentage) {
  2858. dataMin = 0;
  2859. dataMax = 99;
  2860. }
  2861. }
  2862. if (serie.isCartesian) {
  2863. each(serie.data, function(point, i) {
  2864. var pointX = point.x,
  2865. pointY = point.y,
  2866. isNegative = pointY < 0,
  2867. pointStack = isNegative ? negPointStack : posPointStack,
  2868. key = isNegative ? negKey : stackKey,
  2869. totalPos,
  2870. pointLow;
  2871. if (dataMin === null) {
  2872. dataMin = dataMax = point[xOrY];
  2873. }
  2874. if (isXAxis) {
  2875. if (pointX > dataMax) {
  2876. dataMax = pointX;
  2877. } else if (pointX < dataMin) {
  2878. dataMin = pointX;
  2879. }
  2880. }
  2881. else if (defined(pointY)) {
  2882. if (stacking) {
  2883. pointStack[pointX] =
  2884. defined(pointStack[pointX]) ?
  2885. pointStack[pointX] + pointY : pointY;
  2886. }
  2887. totalPos = pointStack ? pointStack[pointX] : pointY;
  2888. pointLow = pick(point.low, totalPos);
  2889. if (!usePercentage) {
  2890. if (totalPos > dataMax) {
  2891. dataMax = totalPos;
  2892. } else if (pointLow < dataMin) {
  2893. dataMin = pointLow;
  2894. }
  2895. }
  2896. if (stacking) {
  2897. if (!stacks[key]) {
  2898. stacks[key] = {};
  2899. }
  2900. stacks[key][pointX] = {
  2901. total: totalPos,
  2902. cum: totalPos
  2903. };
  2904. }
  2905. }
  2906. });
  2907. if (/(area|column|bar)/.test(serie.type) && !isXAxis) {
  2908. if (dataMin >= 0) {
  2909. dataMin = 0;
  2910. ignoreMinPadding = true;
  2911. } else if (dataMax < 0) {
  2912. dataMax = 0;
  2913. ignoreMaxPadding = true;
  2914. }
  2915. }
  2916. }
  2917. }
  2918. });
  2919. }
  2920. translate = function(val, backwards, cvsCoord, old) {
  2921. var sign = 1,
  2922. cvsOffset = 0,
  2923. localA = old ? oldTransA : transA,
  2924. localMin = old ? oldMin : min,
  2925. returnValue;
  2926. if (!localA) {
  2927. localA = transA;
  2928. }
  2929. if (cvsCoord) {
  2930. sign *= -1;
  2931. cvsOffset = axisLength;
  2932. }
  2933. if (reversed) {
  2934. sign *= -1;
  2935. cvsOffset -= sign * axisLength;
  2936. }
  2937. if (backwards) {
  2938. if (reversed) {
  2939. val = axisLength - val;
  2940. }
  2941. returnValue = val / localA + localMin;
  2942. } else {
  2943. returnValue = sign * (val - localMin) * localA + cvsOffset;
  2944. }
  2945. return returnValue;
  2946. };
  2947. getPlotLinePath = function(value, lineWidth, old) {
  2948. var x1,
  2949. y1,
  2950. x2,
  2951. y2,
  2952. translatedValue = translate(value, null, null, old),
  2953. cHeight = old && oldChartHeight || chartHeight,
  2954. cWidth = old && oldChartWidth || chartWidth,
  2955. skip;
  2956. x1 = x2 = mathRound(translatedValue + transB);
  2957. y1 = y2 = mathRound(cHeight - translatedValue - transB);
  2958. if (isNaN(translatedValue)) {
  2959. skip = true;
  2960. } else if (horiz) {
  2961. y1 = plotTop;
  2962. y2 = cHeight - marginBottom;
  2963. if (x1 < plotLeft || x1 > plotLeft + plotWidth) {
  2964. skip = true;
  2965. }
  2966. } else {
  2967. x1 = plotLeft;
  2968. x2 = cWidth - marginRight;
  2969. if (y1 < plotTop || y1 > plotTop + plotHeight) {
  2970. skip = true;
  2971. }
  2972. }
  2973. return skip ?
  2974. null :
  2975. renderer.crispLine([M, x1, y1, L, x2, y2], lineWidth || 0);
  2976. };
  2977. function normalizeTickInterval(interval, multiples) {
  2978. var normalized;
  2979. magnitude = multiples ? 1 : math.pow(10, mathFloor(math.log(interval) / math.LN10));
  2980. normalized = interval / magnitude;
  2981. if (!multiples) {
  2982. multiples = [1, 2, 2.5, 5, 10];
  2983. if (options.allowDecimals === false) {
  2984. if (magnitude == 1) {
  2985. multiples = [1, 2, 5, 10];
  2986. } else if (magnitude <= 0.1) {
  2987. multiples = [1 / magnitude];
  2988. }
  2989. }
  2990. }
  2991. for (var i = 0; i < multiples.length; i++) {
  2992. interval = multiples[i];
  2993. if (normalized <= (multiples[i] + (multiples[i+1] || multiples[i])) / 2) {
  2994. break;
  2995. }
  2996. }
  2997. interval *= magnitude;
  2998. return interval;
  2999. }
  3000. function setDateTimeTickPositions() {
  3001. tickPositions = [];
  3002. var i,
  3003. useUTC = defaultOptions.global.useUTC,
  3004. oneSecond = 1000 / timeFactor,
  3005. oneMinute = 60000 / timeFactor,
  3006. oneHour = 3600000 / timeFactor,
  3007. oneDay = 24 * 3600000 / timeFactor,
  3008. oneWeek = 7 * 24 * 3600000 / timeFactor,
  3009. oneMonth = 30 * 24 * 3600000 / timeFactor,
  3010. oneYear = 31556952000 / timeFactor,
  3011. units = [[
  3012. 'second',
  3013. oneSecond,
  3014. [1, 2, 5, 10, 15, 30]
  3015. ], [
  3016. 'minute',
  3017. oneMinute,
  3018. [1, 2, 5, 10, 15, 30]
  3019. ], [
  3020. 'hour',
  3021. oneHour,
  3022. [1, 2, 3, 4, 6, 8, 12]
  3023. ], [
  3024. 'day',
  3025. oneDay,
  3026. [1, 2]
  3027. ], [
  3028. 'week',
  3029. oneWeek,
  3030. [1, 2]
  3031. ], [
  3032. 'month',
  3033. oneMonth,
  3034. [1, 2, 3, 4, 6]
  3035. ], [
  3036. 'year',
  3037. oneYear,
  3038. null
  3039. ]],
  3040. unit = units[6],
  3041. interval = unit[1],
  3042. multiples = unit[2];
  3043. for (i = 0; i < units.length; i++) {
  3044. unit = units[i];
  3045. interval = unit[1];
  3046. multiples = unit[2];
  3047. if (units[i+1]) {
  3048. var lessThan = (interval * multiples[multiples.length - 1] +
  3049. units[i + 1][1]) / 2;
  3050. if (tickInterval <= lessThan) {
  3051. break;
  3052. }
  3053. }
  3054. }
  3055. if (interval == oneYear && tickInterval < 5 * interval) {
  3056. multiples = [1, 2, 5];
  3057. }
  3058. var multitude = normalizeTickInterval(tickInterval / interval, multiples),
  3059. minYear,
  3060. minDate = new Date(min * timeFactor);
  3061. minDate.setMilliseconds(0);
  3062. if (interval >= oneSecond) {
  3063. minDate.setSeconds(interval >= oneMinute ? 0 :
  3064. multitude * mathFloor(minDate.getSeconds() / multitude));
  3065. }
  3066. if (interval >= oneMinute) {
  3067. minDate[setMinutes](interval >= oneHour ? 0 :
  3068. multitude * mathFloor(minDate[getMinutes]() / multitude));
  3069. }
  3070. if (interval >= oneHour) {
  3071. minDate[setHours](interval >= oneDay ? 0 :
  3072. multitude * mathFloor(minDate[getHours]() / multitude));
  3073. }
  3074. if (interval >= oneDay) {
  3075. minDate[setDate](interval >= oneMonth ? 1 :
  3076. multitude * mathFloor(minDate[getDate]() / multitude));
  3077. }
  3078. if (interval >= oneMonth) {
  3079. minDate[setMonth](interval >= oneYear ? 0 :
  3080. multitude * mathFloor(minDate[getMonth]() / multitude));
  3081. minYear = minDate[getFullYear]();
  3082. }
  3083. if (interval >= oneYear) {
  3084. minYear -= minYear % multitude;
  3085. minDate[setFullYear](minYear);
  3086. }
  3087. if (interval == oneWeek) {
  3088. minDate[setDate](minDate[getDate]() - minDate[getDay]() +
  3089. options.startOfWeek);
  3090. }
  3091. i = 1;
  3092. minYear = minDate[getFullYear]();
  3093. var time = minDate.getTime() / timeFactor,
  3094. minMonth = minDate[getMonth](),
  3095. minDateDate = minDate[getDate]();
  3096. while (time < max && i < plotWidth) {
  3097. tickPositions.push(time);
  3098. if (interval == oneYear) {
  3099. time = makeTime(minYear + i * multitude, 0) / timeFactor;
  3100. } else if (interval == oneMonth) {
  3101. time = makeTime(minYear, minMonth + i * multitude) / timeFactor;
  3102. } else if (!useUTC && (interval == oneDay || interval == oneWeek)) {
  3103. time = makeTime(minYear, minMonth, minDateDate +
  3104. i * multitude * (interval == oneDay ? 1 : 7));
  3105. } else {
  3106. time += interval * multitude;
  3107. }
  3108. i++;
  3109. }
  3110. tickPositions.push(time);
  3111. dateTimeLabelFormat = options.dateTimeLabelFormats[unit[0]];
  3112. }
  3113. function correctFloat(num) {
  3114. var invMag, ret = num;
  3115. if (defined(magnitude)) {
  3116. invMag = (magnitude < 1 ? mathRound(1 / magnitude) : 1) * 10;
  3117. ret = mathRound(num * invMag) / invMag;
  3118. }
  3119. return ret;
  3120. }
  3121. function setLinearTickPositions() {
  3122. var i,
  3123. roundedMin = mathFloor(min / tickInterval) * tickInterval,
  3124. roundedMax = mathCeil(max / tickInterval) * tickInterval;
  3125. tickPositions = [];
  3126. i = correctFloat(roundedMin);
  3127. while (i <= roundedMax) {
  3128. tickPositions.push(i);
  3129. i = correctFloat(i + tickInterval);
  3130. }
  3131. }
  3132. function setTickPositions(secondPass) {
  3133. var length,
  3134. catPad,
  3135. linkedParent,
  3136. linkedParentExtremes,
  3137. tickIntervalOption = options.tickInterval,
  3138. tickPixelIntervalOption = options.tickPixelInterval,
  3139. maxZoom = options.maxZoom || (
  3140. isXAxis ?
  3141. mathMin(chart.smallestInterval * 5, dataMax - dataMin) :
  3142. null
  3143. ),
  3144. zoomOffset;
  3145. axisLength = horiz ? plotWidth : plotHeight;
  3146. if (isLinked) {
  3147. linkedParent = chart[isXAxis ? 'xAxis' : 'yAxis'][options.linkedTo];
  3148. linkedParentExtremes = linkedParent.getExtremes();
  3149. min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin);
  3150. max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax);
  3151. }
  3152. else {
  3153. min = pick(userSetMin, options.min, dataMin);
  3154. max = pick(userSetMax, options.max, dataMax);
  3155. }
  3156. if (max - min < maxZoom) {
  3157. zoomOffset = (maxZoom - max + min) / 2;
  3158. min = mathMax(min - zoomOffset, pick(options.min, min - zoomOffset), dataMin);
  3159. max = mathMin(min + maxZoom, pick(options.max, min + maxZoom), dataMax);
  3160. }
  3161. if (!categories && !usePercentage && !isLinked && defined(min) && defined(max)) {
  3162. length = (max - min) || 1;
  3163. if (!defined(options.min) && !defined(userSetMin) && minPadding && (dataMin < 0 || !ignoreMinPadding)) {
  3164. min -= length * minPadding;
  3165. }
  3166. if (!defined(options.max) && !defined(userSetMax) && maxPadding && (dataMax > 0 || !ignoreMaxPadding)) {
  3167. max += length * maxPadding;
  3168. }
  3169. }
  3170. if (min == max) {
  3171. tickInterval = 1;
  3172. } else if (isLinked && !tickIntervalOption &&
  3173. tickPixelIntervalOption == linkedParent.options.tickPixelInterval) {
  3174. tickInterval = linkedParent.tickInterval;
  3175. } else {
  3176. tickInterval = pick(
  3177. tickIntervalOption,
  3178. categories ?
  3179. 1 :
  3180. (max - min) * tickPixelIntervalOption / axisLength
  3181. );
  3182. }
  3183. if (!isDatetimeAxis && !defined(options.tickInterval)) {
  3184. tickInterval = normalizeTickInterval(tickInterval);
  3185. }
  3186. axis.tickInterval = tickInterval;
  3187. minorTickInterval = options.minorTickInterval === 'auto' && tickInterval ?
  3188. tickInterval / 5 : options.minorTickInterval;
  3189. if (isDatetimeAxis) {
  3190. setDateTimeTickPositions();
  3191. } else {
  3192. setLinearTickPositions();
  3193. }
  3194. if (!isLinked) {
  3195. if (categories || (isXAxis && chart.hasColumn)) {
  3196. catPad = (categories ? 1 : tickInterval) * 0.5;
  3197. if (categories || !defined(pick(options.min, userSetMin))) {
  3198. min -= catPad;
  3199. }
  3200. if (categories || !defined(pick(options.max, userSetMax))) {
  3201. max += catPad;
  3202. }
  3203. }
  3204. var roundedMin = tickPositions[0],
  3205. roundedMax = tickPositions[tickPositions.length - 1];
  3206. if (options.startOnTick) {
  3207. min = roundedMin;
  3208. } else if (min > roundedMin) {
  3209. tickPositions.shift();
  3210. }
  3211. if (options.endOnTick) {
  3212. max = roundedMax;
  3213. } else if (max < roundedMax) {
  3214. tickPositions.pop();
  3215. }
  3216. if (!maxTicks) {
  3217. maxTicks = {
  3218. x: 0,
  3219. y: 0
  3220. };
  3221. }
  3222. if (!isDatetimeAxis && tickPositions.length > maxTicks[xOrY]) {
  3223. maxTicks[xOrY] = tickPositions.length;
  3224. }
  3225. }
  3226. }
  3227. function adjustTickAmount() {
  3228. if (maxTicks && !isDatetimeAxis && !categories && !isLinked) {
  3229. var oldTickAmount = tickAmount,
  3230. calculatedTickAmount = tickPositions.length;
  3231. tickAmount = maxTicks[xOrY];
  3232. if (calculatedTickAmount < tickAmount) {
  3233. while (tickPositions.length < tickAmount) {
  3234. tickPositions.push( correctFloat(
  3235. tickPositions[tickPositions.length - 1] + tickInterval
  3236. ));
  3237. }
  3238. transA *= (calculatedTickAmount - 1) / (tickAmount - 1);
  3239. max = tickPositions[tickPositions.length - 1];
  3240. }
  3241. if (defined(oldTickAmount) && tickAmount != oldTickAmount) {
  3242. axis.isDirty = true;
  3243. }
  3244. }
  3245. }
  3246. function setScale() {
  3247. var type,
  3248. i;
  3249. oldMin = min;
  3250. oldMax = max;
  3251. getSeriesExtremes();
  3252. setTickPositions();
  3253. oldTransA = transA;
  3254. transA = axisLength / ((max - min) || 1);
  3255. if (!isXAxis) {
  3256. for (type in stacks) {
  3257. for (i in stacks[type]) {
  3258. stacks[type][i].cum = stacks[type][i].total;
  3259. }
  3260. }
  3261. }
  3262. if (!axis.isDirty) {
  3263. axis.isDirty = (min != oldMin || max != oldMax);
  3264. }
  3265. }
  3266. function setExtremes(newMin, newMax, redraw, animation) {
  3267. redraw = pick(redraw, true);
  3268. fireEvent(axis, 'setExtremes', {
  3269. min: newMin,
  3270. max: newMax
  3271. }, function() {
  3272. userSetMin = newMin;
  3273. userSetMax = newMax;
  3274. if (redraw) {
  3275. chart.redraw(animation);
  3276. }
  3277. });
  3278. }
  3279. function getExtremes() {
  3280. return {
  3281. min: min,
  3282. max: max,
  3283. dataMin: dataMin,
  3284. dataMax: dataMax
  3285. };
  3286. }
  3287. function getThreshold(threshold) {
  3288. if (min > threshold) {
  3289. threshold = min;
  3290. } else if (max < threshold) {
  3291. threshold = max;
  3292. }
  3293. return translate(threshold, 0, 1);
  3294. }
  3295. function addPlotBandOrLine(options) {
  3296. var obj = new PlotLineOrBand(options).render();
  3297. plotLinesAndBands.push(obj);
  3298. return obj;
  3299. }
  3300. function getOffset() {
  3301. var hasData = associatedSeries.length && defined(min) && defined(max),
  3302. titleOffset = 0,
  3303. titleMargin = 0,
  3304. axisTitleOptions = options.title,
  3305. labelOptions = options.labels,
  3306. directionFactor = [-1, 1, 1, -1][side];
  3307. if (!axisGroup) {
  3308. axisGroup = renderer.g('axis')
  3309. .attr({ zIndex: 7 })
  3310. .add();
  3311. gridGroup = renderer.g('grid')
  3312. .attr({ zIndex: 1 })
  3313. .add();
  3314. }
  3315. labelOffset = 0;
  3316. if (hasData || isLinked) {
  3317. each(tickPositions, function(pos) {
  3318. if (!ticks[pos]) {
  3319. ticks[pos] = new Tick(pos);
  3320. } else {
  3321. ticks[pos].addLabel();
  3322. }
  3323. if (side === 0 || side == 2 || { 1: 'left', 3: 'right' }[side] == labelOptions.align) {
  3324. labelOffset = mathMax(
  3325. ticks[pos].getLabelSize(),
  3326. labelOffset
  3327. );
  3328. }
  3329. });
  3330. if (staggerLines) {
  3331. labelOffset += (staggerLines - 1) * 16;
  3332. }
  3333. } else {
  3334. for (var n in ticks) {
  3335. ticks[n].destroy();
  3336. delete ticks[n];
  3337. }
  3338. }
  3339. if (axisTitleOptions && axisTitleOptions.text) {
  3340. if (!axis.axisTitle) {
  3341. axis.axisTitle = renderer.text(
  3342. axisTitleOptions.text,
  3343. 0,
  3344. 0
  3345. )
  3346. .attr({
  3347. zIndex: 7,
  3348. rotation: axisTitleOptions.rotation || 0,
  3349. align:
  3350. axisTitleOptions.textAlign ||
  3351. { low: 'left', middle: 'center', high: 'right' }[axisTitleOptions.align]
  3352. })
  3353. .css(axisTitleOptions.style)
  3354. .add();
  3355. }
  3356. titleOffset = axis.axisTitle.getBBox()[horiz ? 'height' : 'width'];
  3357. titleMargin = pick(axisTitleOptions.margin, horiz ? 5 : 10);
  3358. }
  3359. offset = directionFactor * (options.offset || axisOffset[side]);
  3360. axisTitleMargin =
  3361. labelOffset +
  3362. (side != 2 && labelOffset && directionFactor * options.labels[horiz ? 'y' : 'x']) +
  3363. titleMargin;
  3364. axisOffset[side] = mathMax(
  3365. axisOffset[side],
  3366. axisTitleMargin + titleOffset + directionFactor * offset
  3367. );
  3368. }
  3369. function render() {
  3370. var axisTitleOptions = options.title,
  3371. alternateGridColor = options.alternateGridColor,
  3372. lineWidth = options.lineWidth,
  3373. lineLeft,
  3374. lineTop,
  3375. linePath,
  3376. hasRendered = chart.hasRendered,
  3377. slideInTicks = hasRendered && defined(oldMin) && !isNaN(oldMin),
  3378. hasData = associatedSeries.length && defined(min) && defined(max);
  3379. axisLength = horiz ? plotWidth : plotHeight;
  3380. transA = axisLength / ((max - min) || 1);
  3381. transB = horiz ? plotLeft : marginBottom;
  3382. if (hasData || isLinked) {
  3383. if (minorTickInterval && !categories) {
  3384. var pos = min + (tickPositions[0] - min) % minorTickInterval;
  3385. for (pos; pos <= max; pos += minorTickInterval) {
  3386. if (!minorTicks[pos]) {
  3387. minorTicks[pos] = new Tick(pos, true);
  3388. }
  3389. if (slideInTicks && minorTicks[pos].isNew) {
  3390. minorTicks[pos].render(null, true);
  3391. }
  3392. minorTicks[pos].isActive = true;
  3393. minorTicks[pos].render();
  3394. }
  3395. }
  3396. each(tickPositions, function(pos, i) {
  3397. if (!isLinked || (pos >= min && pos <= max)) {
  3398. if (slideInTicks && ticks[pos].isNew) {
  3399. ticks[pos].render(i, true);
  3400. }
  3401. ticks[pos].isActive = true;
  3402. ticks[pos].render(i);
  3403. }
  3404. });
  3405. if (alternateGridColor) {
  3406. each(tickPositions, function(pos, i) {
  3407. if (i % 2 === 0 && pos < max) {
  3408. if (!alternateBands[pos]) {
  3409. alternateBands[pos] = new PlotLineOrBand();
  3410. }
  3411. alternateBands[pos].options = {
  3412. from: pos,
  3413. to: tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] : max,
  3414. color: alternateGridColor
  3415. };
  3416. alternateBands[pos].render();
  3417. alternateBands[pos].isActive = true;
  3418. }
  3419. });
  3420. }
  3421. if (!hasRendered) {
  3422. each((options.plotLines || []).concat(options.plotBands || []), function(plotLineOptions) {
  3423. plotLinesAndBands.push(new PlotLineOrBand(plotLineOptions).render());
  3424. });
  3425. }
  3426. }
  3427. each([ticks, minorTicks, alternateBands], function(coll) {
  3428. for (var pos in coll) {
  3429. if (!coll[pos].isActive) {
  3430. coll[pos].destroy();
  3431. delete coll[pos];
  3432. } else {
  3433. coll[pos].isActive = false;
  3434. }
  3435. }
  3436. });
  3437. if (lineWidth) {
  3438. lineLeft = plotLeft + (opposite ? plotWidth : 0) + offset;
  3439. lineTop = chartHeight - marginBottom - (opposite ? plotHeight : 0) + offset;
  3440. linePath = renderer.crispLine([
  3441. M,
  3442. horiz ?
  3443. plotLeft:
  3444. lineLeft,
  3445. horiz ?
  3446. lineTop:
  3447. plotTop,
  3448. L,
  3449. horiz ?
  3450. chartWidth - marginRight :
  3451. lineLeft,
  3452. horiz ?
  3453. lineTop:
  3454. chartHeight - marginBottom
  3455. ], lineWidth);
  3456. if (!axisLine) {
  3457. axisLine = renderer.path(linePath)
  3458. .attr({
  3459. stroke: options.lineColor,
  3460. 'stroke-width': lineWidth,
  3461. zIndex: 7
  3462. })
  3463. .add();
  3464. } else {
  3465. axisLine.animate({ d: linePath });
  3466. }
  3467. }
  3468. if (axis.axisTitle) {
  3469. var margin = horiz ? plotLeft : plotTop,
  3470. fontSize = pInt(axisTitleOptions.style.fontSize || 12),
  3471. alongAxis = {
  3472. low: margin + (horiz ? 0 : axisLength),
  3473. middle: margin + axisLength / 2,
  3474. high: margin + (horiz ? axisLength : 0)
  3475. }[axisTitleOptions.align],
  3476. offAxis = (horiz ? plotTop + plotHeight : plotLeft) +
  3477. (horiz ? 1 : -1) *
  3478. (opposite ? -1 : 1) *
  3479. axisTitleMargin +
  3480. (side == 2 ? fontSize : 0);
  3481. axis.axisTitle[hasRendered ? 'animate' : 'attr']({
  3482. x: horiz ?
  3483. alongAxis:
  3484. offAxis + (opposite ? plotWidth : 0) + offset +
  3485. (axisTitleOptions.x || 0),
  3486. y: horiz ?
  3487. offAxis - (opposite ? plotHeight : 0) + offset:
  3488. alongAxis + (axisTitleOptions.y || 0)
  3489. });
  3490. }
  3491. axis.isDirty = false;
  3492. }
  3493. function removePlotBandOrLine(id) {
  3494. var i = plotLinesAndBands.length;
  3495. while (i--) {
  3496. if (plotLinesAndBands[i].id == id) {
  3497. plotLinesAndBands[i].destroy();
  3498. }
  3499. }
  3500. }
  3501. function redraw() {
  3502. if (tracker.resetTracker) {
  3503. tracker.resetTracker();
  3504. }
  3505. render();
  3506. each(plotLinesAndBands, function(plotLine) {
  3507. plotLine.render();
  3508. });
  3509. each(associatedSeries, function(series) {
  3510. series.isDirty = true;
  3511. });
  3512. }
  3513. function setCategories(newCategories, doRedraw) {
  3514. axis.categories = categories = newCategories;
  3515. each(associatedSeries, function(series) {
  3516. series.translate();
  3517. series.setTooltipPoints(true);
  3518. });
  3519. axis.isDirty = true;
  3520. if (pick(doRedraw, true)) {
  3521. chart.redraw();
  3522. }
  3523. }
  3524. if (inverted && isXAxis && reversed === UNDEFINED) {
  3525. reversed = true;
  3526. }
  3527. extend(axis, {
  3528. addPlotBand: addPlotBandOrLine,
  3529. addPlotLine: addPlotBandOrLine,
  3530. adjustTickAmount: adjustTickAmount,
  3531. categories: categories,
  3532. getExtremes: getExtremes,
  3533. getPlotLinePath: getPlotLinePath,
  3534. getThreshold: getThreshold,
  3535. isXAxis: isXAxis,
  3536. options: options,
  3537. plotLinesAndBands: plotLinesAndBands,
  3538. getOffset: getOffset,
  3539. render: render,
  3540. setCategories: setCategories,
  3541. setExtremes: setExtremes,
  3542. setScale: setScale,
  3543. setTickPositions: setTickPositions,
  3544. translate: translate,
  3545. redraw: redraw,
  3546. removePlotBand: removePlotBandOrLine,
  3547. removePlotLine: removePlotBandOrLine,
  3548. reversed: reversed,
  3549. stacks: stacks
  3550. });
  3551. for (eventType in events) {
  3552. addEvent(axis, eventType, events[eventType]);
  3553. }
  3554. setScale();
  3555. }
  3556. function Toolbar(chart) {
  3557. var buttons = {};
  3558. function add(id, text, title, fn) {
  3559. if (!buttons[id]) {
  3560. var button = renderer.text(
  3561. text,
  3562. 0,
  3563. 0
  3564. )
  3565. .css(options.toolbar.itemStyle)
  3566. .align({
  3567. align: 'right',
  3568. x: - marginRight - 20,
  3569. y: plotTop + 30
  3570. })
  3571. .on('click', fn)
  3572. .attr({
  3573. align: 'right',
  3574. zIndex: 20
  3575. })
  3576. .add();
  3577. buttons[id] = button;
  3578. }
  3579. }
  3580. function remove(id) {
  3581. discardElement(buttons[id].element);
  3582. buttons[id] = null;
  3583. }
  3584. return {
  3585. add: add,
  3586. remove: remove
  3587. };
  3588. }
  3589. function Tooltip (options) {
  3590. var currentSeries,
  3591. borderWidth = options.borderWidth,
  3592. crosshairsOptions = options.crosshairs,
  3593. crosshairs = [],
  3594. style = options.style,
  3595. shared = options.shared,
  3596. padding = pInt(style.padding),
  3597. boxOffLeft = borderWidth + padding,
  3598. tooltipIsHidden = true,
  3599. boxWidth,
  3600. boxHeight,
  3601. currentX = 0,
  3602. currentY = 0;
  3603. style.padding = 0;
  3604. var group = renderer.g('tooltip')
  3605. .attr({ zIndex: 8 })
  3606. .add(),
  3607. box = renderer.rect(boxOffLeft, boxOffLeft, 0, 0, options.borderRadius, borderWidth)
  3608. .attr({
  3609. fill: options.backgroundColor,
  3610. 'stroke-width': borderWidth
  3611. })
  3612. .add(group)
  3613. .shadow(options.shadow),
  3614. label = renderer.text('', padding + boxOffLeft, pInt(style.fontSize) + padding + boxOffLeft)
  3615. .attr({ zIndex: 1 })
  3616. .css(style)
  3617. .add(group);
  3618. group.hide();
  3619. function defaultFormatter() {
  3620. var pThis = this,
  3621. items = pThis.points || splat(pThis),
  3622. xAxis = items[0].series.xAxis,
  3623. x = pThis.x,
  3624. isDateTime = xAxis && xAxis.options.type == 'datetime',
  3625. useHeader = isString(x) || isDateTime,
  3626. series,
  3627. s;
  3628. s = useHeader ?
  3629. ['<span style="font-size: 10px">',
  3630. (isDateTime ? dateFormat('%A, %b %e, %Y', x) : x),
  3631. '</span><br/>'] : [];
  3632. each(items, function(item) {
  3633. s.push(item.point.tooltipFormatter(useHeader));
  3634. });
  3635. return s.join('');
  3636. }
  3637. function move(finalX, finalY) {
  3638. currentX = tooltipIsHidden ? finalX : (2 * currentX + finalX) / 3;
  3639. currentY = tooltipIsHidden ? finalY : (currentY + finalY) / 2;
  3640. group.translate(currentX, currentY);
  3641. if (mathAbs(finalX - currentX) > 1 || mathAbs(finalY - currentY) > 1) {
  3642. tooltipTick = function() {
  3643. move(finalX, finalY);
  3644. };
  3645. } else {
  3646. tooltipTick = null;
  3647. }
  3648. }
  3649. function hide() {
  3650. if (!tooltipIsHidden) {
  3651. var hoverPoints = chart.hoverPoints;
  3652. group.hide();
  3653. each(crosshairs, function(crosshair) {
  3654. if (crosshair) {
  3655. crosshair.hide();
  3656. }
  3657. });
  3658. if (hoverPoints) {
  3659. each (hoverPoints, function(point) {
  3660. point.setState();
  3661. });
  3662. }
  3663. chart.hoverPoints = null;
  3664. tooltipIsHidden = true;
  3665. }
  3666. }
  3667. function refresh(point) {
  3668. var x,
  3669. y,
  3670. boxX,
  3671. boxY,
  3672. show,
  3673. bBox,
  3674. plotX,
  3675. plotY = 0,
  3676. textConfig = {},
  3677. text,
  3678. pointConfig = [],
  3679. tooltipPos = point.tooltipPos,
  3680. formatter = options.formatter || defaultFormatter,
  3681. hoverPoints = chart.hoverPoints,
  3682. getConfig = function(point) {
  3683. return {
  3684. series: point.series,
  3685. point: point,
  3686. x: point.category,
  3687. y: point.y,
  3688. percentage: point.percentage,
  3689. total: point.total || point.stackTotal
  3690. };
  3691. };
  3692. if (shared) {
  3693. if (hoverPoints) {
  3694. each (hoverPoints, function(point) {
  3695. point.setState();
  3696. });
  3697. }
  3698. chart.hoverPoints = point;
  3699. each(point, function(item, i) {
  3700. item.setState(HOVER_STATE);
  3701. plotY += item.plotY;
  3702. pointConfig.push(getConfig(item));
  3703. });
  3704. plotX = point[0].plotX;
  3705. plotY = mathRound(plotY) / point.length;
  3706. textConfig = {
  3707. x: point[0].category
  3708. };
  3709. textConfig.points = pointConfig;
  3710. point = point[0];
  3711. } else {
  3712. textConfig = getConfig(point);
  3713. }
  3714. text = formatter.call(textConfig);
  3715. currentSeries = point.series;
  3716. plotX = shared ? plotX : point.plotX;
  3717. plotY = shared ? plotY : point.plotY;
  3718. x = mathRound(tooltipPos ? tooltipPos[0] : (inverted ? plotWidth - plotY : plotX));
  3719. y = mathRound(tooltipPos ? tooltipPos[1] : (inverted ? plotHeight - plotX : plotY));
  3720. show = shared || !point.series.isCartesian || isInsidePlot(x, y);
  3721. if (text === false || !show) {
  3722. hide();
  3723. } else {
  3724. if (tooltipIsHidden) {
  3725. group.show();
  3726. tooltipIsHidden = false;
  3727. }
  3728. label.attr({
  3729. text: text
  3730. });
  3731. bBox = label.getBBox();
  3732. boxWidth = bBox.width + 2 * padding;
  3733. boxHeight = bBox.height + 2 * padding;
  3734. box.attr({
  3735. width: boxWidth,
  3736. height: boxHeight,
  3737. stroke: options.borderColor || point.color || currentSeries.color || '#606060'
  3738. });
  3739. boxX = x - boxWidth + plotLeft - 25;
  3740. boxY = y - boxHeight + plotTop + 10;
  3741. if (boxX < 7) {
  3742. boxX = 7;
  3743. boxY -= 30;
  3744. }
  3745. if (boxY < 5) {
  3746. boxY = 5;
  3747. } else if (boxY + boxHeight > chartHeight) {
  3748. boxY = chartHeight - boxHeight - 5;
  3749. }
  3750. move(mathRound(boxX - boxOffLeft), mathRound(boxY - boxOffLeft));
  3751. }
  3752. if (crosshairsOptions) {
  3753. crosshairsOptions = splat(crosshairsOptions);
  3754. var path,
  3755. i = crosshairsOptions.length,
  3756. attribs,
  3757. axis;
  3758. while (i--) {
  3759. if (crosshairsOptions[i] && (axis = point.series[i ? 'yAxis' : 'xAxis'])) {
  3760. path = axis
  3761. .getPlotLinePath(point[i ? 'y' : 'x'], 1);
  3762. if (crosshairs[i]) {
  3763. crosshairs[i].attr({ d: path, visibility: VISIBLE });
  3764. } else {
  3765. attribs = {
  3766. 'stroke-width': crosshairsOptions[i].width || 1,
  3767. stroke: crosshairsOptions[i].color || '#C0C0C0',
  3768. zIndex: 2
  3769. };
  3770. if (crosshairsOptions[i].dashStyle) {
  3771. attribs.dashstyle = crosshairsOptions[i].dashStyle;
  3772. }
  3773. crosshairs[i] = renderer.path(path)
  3774. .attr(attribs)
  3775. .add();
  3776. }
  3777. }
  3778. }
  3779. }
  3780. }
  3781. return {
  3782. shared: shared,
  3783. refresh: refresh,
  3784. hide: hide
  3785. };
  3786. }
  3787. function MouseTracker (chart, options) {
  3788. var mouseDownX,
  3789. mouseDownY,
  3790. hasDragged,
  3791. selectionMarker,
  3792. zoomType = optionsChart.zoomType,
  3793. zoomX = /x/.test(zoomType),
  3794. zoomY = /y/.test(zoomType),
  3795. zoomHor = zoomX && !inverted || zoomY && inverted,
  3796. zoomVert = zoomY && !inverted || zoomX && inverted;
  3797. function normalizeMouseEvent(e) {
  3798. var ePos;
  3799. e = e || win.event;
  3800. if (!e.target) {
  3801. e.target = e.srcElement;
  3802. }
  3803. ePos = e.touches ? e.touches.item(0) : e;
  3804. if (e.type != 'mousemove' || win.opera) {
  3805. chartPosition = getPosition(container);
  3806. }
  3807. if (isIE) {
  3808. e.chartX = e.x;
  3809. e.chartY = e.y;
  3810. } else {
  3811. if (ePos.layerX === UNDEFINED) {
  3812. e.chartX = ePos.pageX - chartPosition.left;
  3813. e.chartY = ePos.pageY - chartPosition.top;
  3814. } else {
  3815. e.chartX = e.layerX;
  3816. e.chartY = e.layerY;
  3817. }
  3818. }
  3819. return e;
  3820. }
  3821. function getMouseCoordinates(e) {
  3822. var coordinates = {
  3823. xAxis: [],
  3824. yAxis: []
  3825. };
  3826. each(axes, function(axis, i) {
  3827. var translate = axis.translate,
  3828. isXAxis = axis.isXAxis,
  3829. isHorizontal = inverted ? !isXAxis : isXAxis;
  3830. coordinates[isXAxis ? 'xAxis' : 'yAxis'].push({
  3831. axis: axis,
  3832. value: translate(
  3833. isHorizontal ?
  3834. e.chartX - plotLeft :
  3835. plotHeight - e.chartY + plotTop,
  3836. true
  3837. )
  3838. });
  3839. });
  3840. return coordinates;
  3841. }
  3842. function onmousemove (e) {
  3843. var point,
  3844. points,
  3845. hoverPoint = chart.hoverPoint,
  3846. hoverSeries = chart.hoverSeries,
  3847. i,
  3848. j,
  3849. distance = chartWidth,
  3850. index = inverted ? e.chartY : e.chartX - plotLeft;
  3851. if (tooltip && options.shared) {
  3852. points = [];
  3853. i = series.length;
  3854. for (j = 0; j < i; j++) {
  3855. if (series[j].visible && series[j].tooltipPoints.length) {
  3856. point = series[j].tooltipPoints[index];
  3857. point._dist = mathAbs(index - point.plotX);
  3858. distance = mathMin(distance, point._dist);
  3859. points.push(point);
  3860. }
  3861. }
  3862. i = points.length;
  3863. while (i--) {
  3864. if (points[i]._dist > distance) {
  3865. points.splice(i, 1);
  3866. }
  3867. }
  3868. if (points.length && (points[0].plotX != hoverX)) {
  3869. tooltip.refresh(points);
  3870. hoverX = points[0].plotX;
  3871. }
  3872. }
  3873. if (hoverSeries && hoverSeries.tracker) {
  3874. point = hoverSeries.tooltipPoints[index];
  3875. if (point && point != hoverPoint) {
  3876. point.onMouseOver();
  3877. }
  3878. }
  3879. }
  3880. function resetTracker() {
  3881. var hoverSeries = chart.hoverSeries,
  3882. hoverPoint = chart.hoverPoint;
  3883. if (hoverPoint) {
  3884. hoverPoint.onMouseOut();
  3885. }
  3886. if (hoverSeries) {
  3887. hoverSeries.onMouseOut();
  3888. }
  3889. if (tooltip) {
  3890. tooltip.hide();
  3891. }
  3892. hoverX = null;
  3893. }
  3894. function drop() {
  3895. if (selectionMarker) {
  3896. var selectionData = {
  3897. xAxis: [],
  3898. yAxis: []
  3899. },
  3900. selectionBox = selectionMarker.getBBox(),
  3901. selectionLeft = selectionBox.x - plotLeft,
  3902. selectionTop = selectionBox.y - plotTop;
  3903. if (hasDragged) {
  3904. each(axes, function(axis, i) {
  3905. var translate = axis.translate,
  3906. isXAxis = axis.isXAxis,
  3907. isHorizontal = inverted ? !isXAxis : isXAxis,
  3908. selectionMin = translate(
  3909. isHorizontal ?
  3910. selectionLeft :
  3911. plotHeight - selectionTop - selectionBox.height,
  3912. true
  3913. ),
  3914. selectionMax = translate(
  3915. isHorizontal ?
  3916. selectionLeft + selectionBox.width :
  3917. plotHeight - selectionTop,
  3918. true
  3919. );
  3920. selectionData[isXAxis ? 'xAxis' : 'yAxis'].push({
  3921. axis: axis,
  3922. min: mathMin(selectionMin, selectionMax),
  3923. max: mathMax(selectionMin, selectionMax)
  3924. });
  3925. });
  3926. fireEvent(chart, 'selection', selectionData, zoom);
  3927. }
  3928. selectionMarker = selectionMarker.destroy();
  3929. }
  3930. chart.mouseIsDown = mouseIsDown = hasDragged = false;
  3931. removeEvent(doc, hasTouch ? 'touchend' : 'mouseup', drop);
  3932. }
  3933. function setDOMEvents () {
  3934. var lastWasOutsidePlot = true;
  3935. container.onmousedown = function(e) {
  3936. e = normalizeMouseEvent(e);
  3937. chart.mouseIsDown = mouseIsDown = true;
  3938. mouseDownX = e.chartX;
  3939. mouseDownY = e.chartY;
  3940. addEvent(doc, hasTouch ? 'touchend' : 'mouseup', drop);
  3941. };
  3942. var mouseMove = function(e) {
  3943. if (e && e.touches && e.touches.length > 1) {
  3944. return;
  3945. }
  3946. e = normalizeMouseEvent(e);
  3947. if (!hasTouch) {
  3948. e.returnValue = false;
  3949. }
  3950. var chartX = e.chartX,
  3951. chartY = e.chartY,
  3952. isOutsidePlot = !isInsidePlot(chartX - plotLeft, chartY - plotTop);
  3953. if (hasTouch && e.type == 'touchstart') {
  3954. if (attr(e.target, 'isTracker')) {
  3955. if (!chart.runTrackerClick) {
  3956. e.preventDefault();
  3957. }
  3958. } else if (!runChartClick && !isOutsidePlot) {
  3959. e.preventDefault();
  3960. }
  3961. }
  3962. if (isOutsidePlot) {
  3963. if (!lastWasOutsidePlot) {
  3964. resetTracker();
  3965. }
  3966. if (chartX < plotLeft) {
  3967. chartX = plotLeft;
  3968. } else if (chartX > plotLeft + plotWidth) {
  3969. chartX = plotLeft + plotWidth;
  3970. }
  3971. if (chartY < plotTop) {
  3972. chartY = plotTop;
  3973. } else if (chartY > plotTop + plotHeight) {
  3974. chartY = plotTop + plotHeight;
  3975. }
  3976. }
  3977. if (mouseIsDown && e.type != 'touchstart') {
  3978. if ((hasDragged = Math.sqrt(
  3979. Math.pow(mouseDownX - chartX, 2) +
  3980. Math.pow(mouseDownY - chartY, 2)
  3981. ) > 10)) {
  3982. if (hasCartesianSeries && (zoomX || zoomY) &&
  3983. isInsidePlot(mouseDownX - plotLeft, mouseDownY - plotTop)) {
  3984. if (!selectionMarker) {
  3985. selectionMarker = renderer.rect(
  3986. plotLeft,
  3987. plotTop,
  3988. zoomHor ? 1 : plotWidth,
  3989. zoomVert ? 1 : plotHeight,
  3990. 0
  3991. )
  3992. .attr({
  3993. fill: 'rgba(69,114,167,0.25)',
  3994. zIndex: 7
  3995. })
  3996. .add();
  3997. }
  3998. }
  3999. if (selectionMarker && zoomHor) {
  4000. var xSize = chartX - mouseDownX;
  4001. selectionMarker.attr({
  4002. width: mathAbs(xSize),
  4003. x: (xSize > 0 ? 0 : xSize) + mouseDownX
  4004. });
  4005. }
  4006. if (selectionMarker && zoomVert) {
  4007. var ySize = chartY - mouseDownY;
  4008. selectionMarker.attr({
  4009. height: mathAbs(ySize),
  4010. y: (ySize > 0 ? 0 : ySize) + mouseDownY
  4011. });
  4012. }
  4013. }
  4014. } else if (!isOutsidePlot) {
  4015. onmousemove(e);
  4016. }
  4017. lastWasOutsidePlot = isOutsidePlot;
  4018. return isOutsidePlot || !hasCartesianSeries;
  4019. };
  4020. container.onmousemove = mouseMove;
  4021. addEvent(container, 'mouseleave', resetTracker);
  4022. container.ontouchstart = function(e) {
  4023. if (zoomX || zoomY) {
  4024. container.onmousedown(e);
  4025. }
  4026. mouseMove(e);
  4027. };
  4028. container.ontouchmove = mouseMove;
  4029. container.ontouchend = function() {
  4030. if (hasDragged) {
  4031. resetTracker();
  4032. }
  4033. };
  4034. container.onclick = function(e) {
  4035. var hoverPoint = chart.hoverPoint;
  4036. e = normalizeMouseEvent(e);
  4037. e.cancelBubble = true;
  4038. if (!hasDragged) {
  4039. if (hoverPoint && attr(e.target, 'isTracker')) {
  4040. var plotX = hoverPoint.plotX,
  4041. plotY = hoverPoint.plotY;
  4042. extend(hoverPoint, {
  4043. pageX: chartPosition.left + plotLeft +
  4044. (inverted ? plotWidth - plotY : plotX),
  4045. pageY: chartPosition.top + plotTop +
  4046. (inverted ? plotHeight - plotX : plotY)
  4047. });
  4048. fireEvent(hoverPoint.series, 'click', extend(e, {
  4049. point: hoverPoint
  4050. }));
  4051. hoverPoint.firePointEvent('click', e);
  4052. } else {
  4053. extend(e, getMouseCoordinates(e));
  4054. if (isInsidePlot(e.chartX - plotLeft, e.chartY - plotTop)) {
  4055. fireEvent(chart, 'click', e);
  4056. }
  4057. }
  4058. }
  4059. hasDragged = false;
  4060. };
  4061. }
  4062. placeTrackerGroup = function() {
  4063. if (!trackerGroup) {
  4064. chart.trackerGroup = trackerGroup = renderer.g('tracker')
  4065. .attr({ zIndex: 9 })
  4066. .add();
  4067. } else {
  4068. trackerGroup.translate(plotLeft, plotTop);
  4069. if (inverted) {
  4070. trackerGroup.attr({
  4071. width: chart.plotWidth,
  4072. height: chart.plotHeight
  4073. }).invert();
  4074. }
  4075. }
  4076. };
  4077. placeTrackerGroup();
  4078. if (options.enabled) {
  4079. chart.tooltip = tooltip = Tooltip(options);
  4080. }
  4081. setDOMEvents();
  4082. tooltipInterval = setInterval(function() {
  4083. if (tooltipTick) {
  4084. tooltipTick();
  4085. }
  4086. }, 32);
  4087. extend(this, {
  4088. zoomX: zoomX,
  4089. zoomY: zoomY,
  4090. resetTracker: resetTracker
  4091. });
  4092. }
  4093. var Legend = function(chart) {
  4094. var options = chart.options.legend;
  4095. if (!options.enabled) {
  4096. return;
  4097. }
  4098. var horizontal = options.layout == 'horizontal',
  4099. symbolWidth = options.symbolWidth,
  4100. symbolPadding = options.symbolPadding,
  4101. allItems,
  4102. style = options.style,
  4103. itemStyle = options.itemStyle,
  4104. itemHoverStyle = options.itemHoverStyle,
  4105. itemHiddenStyle = options.itemHiddenStyle,
  4106. padding = pInt(style.padding),
  4107. rightPadding = 20,
  4108. y = 18,
  4109. initialItemX = 4 + padding + symbolWidth + symbolPadding,
  4110. itemX,
  4111. itemY,
  4112. lastItemY,
  4113. itemHeight = 0,
  4114. box,
  4115. legendBorderWidth = options.borderWidth,
  4116. legendBackgroundColor = options.backgroundColor,
  4117. legendGroup,
  4118. offsetWidth,
  4119. widthOption = options.width,
  4120. series = chart.series,
  4121. reversedLegend = options.reversed;
  4122. function colorizeItem(item, visible) {
  4123. var legendItem = item.legendItem,
  4124. legendLine = item.legendLine,
  4125. legendSymbol = item.legendSymbol,
  4126. hiddenColor = itemHiddenStyle.color,
  4127. textColor = visible ? options.itemStyle.color : hiddenColor,
  4128. symbolColor = visible ? item.color : hiddenColor;
  4129. if (legendItem) {
  4130. legendItem.css({ fill: textColor });
  4131. }
  4132. if (legendLine) {
  4133. legendLine.attr({ stroke: symbolColor });
  4134. }
  4135. if (legendSymbol) {
  4136. legendSymbol.attr({
  4137. stroke: symbolColor,
  4138. fill: symbolColor
  4139. });
  4140. }
  4141. }
  4142. function positionItem(item, itemX, itemY) {
  4143. var legendItem = item.legendItem,
  4144. legendLine = item.legendLine,
  4145. legendSymbol = item.legendSymbol,
  4146. checkbox = item.checkbox;
  4147. if (legendItem) {
  4148. legendItem.attr({
  4149. x: itemX,
  4150. y: itemY
  4151. });
  4152. }
  4153. if (legendLine) {
  4154. legendLine.translate(itemX, itemY - 4);
  4155. }
  4156. if (legendSymbol) {
  4157. legendSymbol.attr({
  4158. x: itemX + legendSymbol.xOff,
  4159. y: itemY + legendSymbol.yOff
  4160. });
  4161. }
  4162. if (checkbox) {
  4163. checkbox.x = itemX;
  4164. checkbox.y = itemY;
  4165. }
  4166. }
  4167. function destroyItem(item) {
  4168. var checkbox = item.checkbox;
  4169. each(['legendItem', 'legendLine', 'legendSymbol'], function(key) {
  4170. if (item[key]) {
  4171. item[key].destroy();
  4172. }
  4173. });
  4174. if (checkbox) {
  4175. discardElement(item.checkbox);
  4176. }
  4177. }
  4178. function positionCheckboxes() {
  4179. each(allItems, function(item) {
  4180. var checkbox = item.checkbox;
  4181. if (checkbox) {
  4182. css(checkbox, {
  4183. left: (legendGroup.attr('translateX') + item.legendItemWidth + checkbox.x - 40) +PX,
  4184. top: (legendGroup.attr('translateY') + checkbox.y - 11) + PX
  4185. });
  4186. }
  4187. });
  4188. }
  4189. function renderItem(item) {
  4190. var bBox,
  4191. itemWidth,
  4192. legendSymbol,
  4193. symbolX,
  4194. symbolY,
  4195. attribs,
  4196. simpleSymbol,
  4197. li = item.legendItem,
  4198. series = item.series || item,
  4199. i = allItems.length;
  4200. if (!li) {
  4201. simpleSymbol = /^(bar|pie|area|column)$/.test(series.type);
  4202. item.legendItem = li = renderer.text(
  4203. options.labelFormatter.call(item),
  4204. 0,
  4205. 0
  4206. )
  4207. .css(item.visible ? itemStyle : itemHiddenStyle)
  4208. .on('mouseover', function() {
  4209. item.setState(HOVER_STATE);
  4210. li.css(itemHoverStyle);
  4211. })
  4212. .on('mouseout', function() {
  4213. li.css(item.visible ? itemStyle : itemHiddenStyle);
  4214. item.setState();
  4215. })
  4216. .on('click', function(event) {
  4217. var strLegendItemClick = 'legendItemClick',
  4218. fnLegendItemClick = function() {
  4219. item.setVisible();
  4220. };
  4221. if (item.firePointEvent) {
  4222. item.firePointEvent(strLegendItemClick, null, fnLegendItemClick);
  4223. } else {
  4224. fireEvent(item, strLegendItemClick, null, fnLegendItemClick);
  4225. }
  4226. })
  4227. .attr({ zIndex: 2 })
  4228. .add(legendGroup);
  4229. if (!simpleSymbol && item.options && item.options.lineWidth) {
  4230. var itemOptions = item.options;
  4231. attribs = {
  4232. 'stroke-width': itemOptions.lineWidth,
  4233. zIndex: 2
  4234. };
  4235. if (itemOptions.dashStyle) {
  4236. attribs.dashstyle = itemOptions.dashStyle;
  4237. }
  4238. item.legendLine = renderer.path([
  4239. M,
  4240. -symbolWidth - symbolPadding,
  4241. 0,
  4242. L,
  4243. -symbolPadding,
  4244. 0
  4245. ])
  4246. .attr(attribs)
  4247. .add(legendGroup);
  4248. }
  4249. if (simpleSymbol) {
  4250. legendSymbol = renderer.rect(
  4251. (symbolX = -symbolWidth - symbolPadding),
  4252. (symbolY = -11),
  4253. symbolWidth,
  4254. 12,
  4255. 2
  4256. ).attr({
  4257. 'stroke-width': 0,
  4258. zIndex: 3
  4259. }).add(legendGroup);
  4260. }
  4261. else if (item.options && item.options.marker && item.options.marker.enabled) {
  4262. legendSymbol = renderer.symbol(
  4263. item.symbol,
  4264. (symbolX = -symbolWidth / 2 - symbolPadding),
  4265. (symbolY = -4),
  4266. item.options.marker.radius
  4267. )
  4268. .attr(item.pointAttr[NORMAL_STATE])
  4269. .attr({ zIndex: 3 })
  4270. .add(legendGroup);
  4271. }
  4272. if (legendSymbol) {
  4273. legendSymbol.xOff = symbolX;
  4274. legendSymbol.yOff = symbolY;
  4275. }
  4276. item.legendSymbol = legendSymbol;
  4277. colorizeItem(item, item.visible);
  4278. if (item.options && item.options.showCheckbox) {
  4279. item.checkbox = createElement('input', {
  4280. type: 'checkbox',
  4281. checked: item.selected,
  4282. defaultChecked: item.selected
  4283. }, options.itemCheckboxStyle, container);
  4284. addEvent(item.checkbox, 'click', function(event) {
  4285. var target = event.target;
  4286. fireEvent(item, 'checkboxClick', {
  4287. checked: target.checked
  4288. },
  4289. function() {
  4290. item.select();
  4291. }
  4292. );
  4293. });
  4294. }
  4295. }
  4296. bBox = li.getBBox();
  4297. itemWidth = item.legendItemWidth =
  4298. options.itemWidth || symbolWidth + symbolPadding + bBox.width + rightPadding;
  4299. itemHeight = bBox.height;
  4300. if (horizontal && itemX - initialItemX + itemWidth >
  4301. (widthOption || (chartWidth - 2 * padding - initialItemX))) {
  4302. itemX = initialItemX;
  4303. itemY += itemHeight;
  4304. }
  4305. lastItemY = itemY;
  4306. positionItem(item, itemX, itemY);
  4307. if (horizontal) {
  4308. itemX += itemWidth;
  4309. } else {
  4310. itemY += itemHeight;
  4311. }
  4312. offsetWidth = widthOption || mathMax(
  4313. horizontal ? itemX - initialItemX : itemWidth,
  4314. offsetWidth
  4315. );
  4316. allItems.push(item);
  4317. }
  4318. function renderLegend() {
  4319. itemX = initialItemX;
  4320. itemY = y;
  4321. offsetWidth = 0;
  4322. lastItemY = 0;
  4323. allItems = [];
  4324. if (!legendGroup) {
  4325. legendGroup = renderer.g('legend')
  4326. .attr({ zIndex: 7 })
  4327. .add();
  4328. }
  4329. if (reversedLegend) {
  4330. series.reverse();
  4331. }
  4332. each(series, function(serie) {
  4333. if (!serie.options.showInLegend) {
  4334. return;
  4335. }
  4336. var items = (serie.options.legendType == 'point') ?
  4337. serie.data : [serie];
  4338. each(items, renderItem);
  4339. });
  4340. if (reversedLegend) {
  4341. series.reverse();
  4342. }
  4343. legendWidth = widthOption || offsetWidth;
  4344. legendHeight = lastItemY - y + itemHeight;
  4345. if (legendBorderWidth || legendBackgroundColor) {
  4346. legendWidth += 2 * padding;
  4347. legendHeight += 2 * padding;
  4348. if (!box) {
  4349. box = renderer.rect(
  4350. 0,
  4351. 0,
  4352. legendWidth,
  4353. legendHeight,
  4354. options.borderRadius,
  4355. legendBorderWidth || 0
  4356. ).attr({
  4357. stroke: options.borderColor,
  4358. 'stroke-width': legendBorderWidth || 0,
  4359. fill: legendBackgroundColor || NONE
  4360. })
  4361. .add(legendGroup)
  4362. .shadow(options.shadow);
  4363. } else if (legendWidth > 0 && legendHeight > 0) {
  4364. box.animate(
  4365. box.crisp(null, null, null, legendWidth, legendHeight)
  4366. );
  4367. }
  4368. box[allItems.length ? 'show' : 'hide']();
  4369. }
  4370. var props = ['left', 'right', 'top', 'bottom'],
  4371. prop,
  4372. i = 4;
  4373. while(i--) {
  4374. prop = props[i];
  4375. if (style[prop] && style[prop] != 'auto') {
  4376. options[i < 2 ? 'align' : 'verticalAlign'] = prop;
  4377. options[i < 2 ? 'x' : 'y'] = pInt(style[prop]) * (i % 2 ? -1 : 1);
  4378. }
  4379. }
  4380. legendGroup.align(extend(options, {
  4381. width: legendWidth,
  4382. height: legendHeight
  4383. }), true, spacingBox);
  4384. if (!isResizing) {
  4385. positionCheckboxes();
  4386. }
  4387. }
  4388. renderLegend();
  4389. addEvent(chart, 'endResize', positionCheckboxes);
  4390. return {
  4391. colorizeItem: colorizeItem,
  4392. destroyItem: destroyItem,
  4393. renderLegend: renderLegend
  4394. };
  4395. };
  4396. function initSeries(options) {
  4397. var type = options.type || optionsChart.type || optionsChart.defaultSeriesType,
  4398. typeClass = seriesTypes[type],
  4399. serie,
  4400. hasRendered = chart.hasRendered;
  4401. if (hasRendered) {
  4402. if (inverted && type == 'column') {
  4403. typeClass = seriesTypes.bar;
  4404. } else if (!inverted && type == 'bar') {
  4405. typeClass = seriesTypes.column;
  4406. }
  4407. }
  4408. serie = new typeClass();
  4409. serie.init(chart, options);
  4410. if (!hasRendered && serie.inverted) {
  4411. inverted = true;
  4412. }
  4413. if (serie.isCartesian) {
  4414. hasCartesianSeries = serie.isCartesian;
  4415. }
  4416. series.push(serie);
  4417. return serie;
  4418. }
  4419. function addSeries(options, redraw, animation) {
  4420. var series;
  4421. if (options) {
  4422. setAnimation(animation, chart);
  4423. redraw = pick(redraw, true);
  4424. fireEvent(chart, 'addSeries', { options: options }, function() {
  4425. series = initSeries(options);
  4426. series.isDirty = true;
  4427. chart.isDirtyLegend = true;
  4428. if (redraw) {
  4429. chart.redraw();
  4430. }
  4431. });
  4432. }
  4433. return series;
  4434. }
  4435. isInsidePlot = function(x, y) {
  4436. return x >= 0 &&
  4437. x <= plotWidth &&
  4438. y >= 0 &&
  4439. y <= plotHeight;
  4440. };
  4441. function adjustTickAmounts() {
  4442. if (optionsChart.alignTicks !== false) {
  4443. each(axes, function(axis) {
  4444. axis.adjustTickAmount();
  4445. });
  4446. }
  4447. maxTicks = null;
  4448. }
  4449. function redraw(animation) {
  4450. var redrawLegend = chart.isDirtyLegend,
  4451. hasStackedSeries,
  4452. isDirtyBox = chart.isDirtyBox,
  4453. seriesLength = series.length,
  4454. i = seriesLength,
  4455. clipRect = chart.clipRect,
  4456. serie;
  4457. setAnimation(animation, chart);
  4458. while (i--) {
  4459. serie = series[i];
  4460. if (serie.isDirty && serie.options.stacking) {
  4461. hasStackedSeries = true;
  4462. break;
  4463. }
  4464. }
  4465. if (hasStackedSeries) {
  4466. i = seriesLength;
  4467. while (i--) {
  4468. serie = series[i];
  4469. if (serie.options.stacking) {
  4470. serie.isDirty = true;
  4471. }
  4472. }
  4473. }
  4474. each(series, function(serie) {
  4475. if (serie.isDirty) {
  4476. serie.cleanData();
  4477. serie.getSegments();
  4478. if (serie.options.legendType == 'point') {
  4479. redrawLegend = true;
  4480. }
  4481. }
  4482. });
  4483. if (redrawLegend && legend.renderLegend) {
  4484. legend.renderLegend();
  4485. chart.isDirtyLegend = false;
  4486. }
  4487. if (hasCartesianSeries) {
  4488. if (!isResizing) {
  4489. maxTicks = null;
  4490. each(axes, function(axis) {
  4491. axis.setScale();
  4492. });
  4493. }
  4494. adjustTickAmounts();
  4495. getMargins();
  4496. each(axes, function(axis) {
  4497. if (axis.isDirty || isDirtyBox) {
  4498. axis.redraw();
  4499. isDirtyBox = true;
  4500. }
  4501. });
  4502. }
  4503. if (isDirtyBox) {
  4504. drawChartBox();
  4505. placeTrackerGroup();
  4506. if (clipRect) {
  4507. stop(clipRect);
  4508. clipRect.animate({
  4509. width: chart.plotSizeX,
  4510. height: chart.plotSizeY
  4511. });
  4512. }
  4513. }
  4514. each(series, function(serie) {
  4515. if (serie.isDirty && serie.visible &&
  4516. (!serie.isCartesian || serie.xAxis)) {
  4517. serie.redraw();
  4518. }
  4519. });
  4520. if (tracker && tracker.resetTracker) {
  4521. tracker.resetTracker();
  4522. }
  4523. fireEvent(chart, 'redraw');
  4524. }
  4525. function showLoading(str) {
  4526. var loadingOptions = options.loading;
  4527. if (!loadingDiv) {
  4528. loadingDiv = createElement(DIV, {
  4529. className: 'highcharts-loading'
  4530. }, extend(loadingOptions.style, {
  4531. left: plotLeft + PX,
  4532. top: plotTop + PX,
  4533. width: plotWidth + PX,
  4534. height: plotHeight + PX,
  4535. zIndex: 10,
  4536. display: NONE
  4537. }), container);
  4538. loadingSpan = createElement(
  4539. 'span',
  4540. null,
  4541. loadingOptions.labelStyle,
  4542. loadingDiv
  4543. );
  4544. }
  4545. loadingSpan.innerHTML = str || options.lang.loading;
  4546. if (!loadingShown) {
  4547. css(loadingDiv, { opacity: 0, display: '' });
  4548. animate(loadingDiv, {
  4549. opacity: loadingOptions.style.opacity
  4550. }, {
  4551. duration: loadingOptions.showDuration
  4552. });
  4553. loadingShown = true;
  4554. }
  4555. }
  4556. function hideLoading() {
  4557. animate(loadingDiv, {
  4558. opacity: 0
  4559. }, {
  4560. duration: options.loading.hideDuration,
  4561. complete: function() {
  4562. css(loadingDiv, { display: NONE });
  4563. }
  4564. });
  4565. loadingShown = false;
  4566. }
  4567. function get(id) {
  4568. var i,
  4569. j,
  4570. data;
  4571. for (i = 0; i < axes.length; i++) {
  4572. if (axes[i].options.id == id) {
  4573. return axes[i];
  4574. }
  4575. }
  4576. for (i = 0; i < series.length; i++) {
  4577. if (series[i].options.id == id) {
  4578. return series[i];
  4579. }
  4580. }
  4581. for (i = 0; i < series.length; i++) {
  4582. data = series[i].data;
  4583. for (j = 0; j < data.length; j++) {
  4584. if (data[j].id == id) {
  4585. return data[j];
  4586. }
  4587. }
  4588. }
  4589. return null;
  4590. }
  4591. function getAxes() {
  4592. var xAxisOptions = options.xAxis || {},
  4593. yAxisOptions = options.yAxis || {},
  4594. axis;
  4595. xAxisOptions = splat(xAxisOptions);
  4596. each(xAxisOptions, function(axis, i) {
  4597. axis.index = i;
  4598. axis.isX = true;
  4599. });
  4600. yAxisOptions = splat(yAxisOptions);
  4601. each(yAxisOptions, function(axis, i) {
  4602. axis.index = i;
  4603. });
  4604. axes = xAxisOptions.concat(yAxisOptions);
  4605. chart.xAxis = [];
  4606. chart.yAxis = [];
  4607. axes = map(axes, function(axisOptions) {
  4608. axis = new Axis(chart, axisOptions);
  4609. chart[axis.isXAxis ? 'xAxis' : 'yAxis'].push(axis);
  4610. return axis;
  4611. });
  4612. adjustTickAmounts();
  4613. }
  4614. function getSelectedPoints() {
  4615. var points = [];
  4616. each(series, function(serie) {
  4617. points = points.concat( grep( serie.data, function(point) {
  4618. return point.selected;
  4619. }));
  4620. });
  4621. return points;
  4622. }
  4623. function getSelectedSeries() {
  4624. return grep(series, function (serie) {
  4625. return serie.selected;
  4626. });
  4627. }
  4628. zoomOut = function () {
  4629. fireEvent(chart, 'selection', { resetSelection: true }, zoom);
  4630. chart.toolbar.remove('zoom');
  4631. };
  4632. zoom = function (event) {
  4633. var lang = defaultOptions.lang,
  4634. animate = chart.pointCount < 100;
  4635. chart.toolbar.add('zoom', lang.resetZoom, lang.resetZoomTitle, zoomOut);
  4636. if (!event || event.resetSelection) {
  4637. each(axes, function(axis) {
  4638. axis.setExtremes(null, null, false, animate);
  4639. });
  4640. }
  4641. else {
  4642. each(event.xAxis.concat(event.yAxis), function(axisData) {
  4643. var axis = axisData.axis;
  4644. if (chart.tracker[axis.isXAxis ? 'zoomX' : 'zoomY']) {
  4645. axis.setExtremes(axisData.min, axisData.max, false, animate);
  4646. }
  4647. });
  4648. }
  4649. redraw();
  4650. };
  4651. function setTitle (titleOptions, subtitleOptions) {
  4652. chartTitleOptions = merge(options.title, titleOptions);
  4653. chartSubtitleOptions = merge(options.subtitle, subtitleOptions);
  4654. each([
  4655. ['title', titleOptions, chartTitleOptions],
  4656. ['subtitle', subtitleOptions, chartSubtitleOptions]
  4657. ], function(arr) {
  4658. var name = arr[0],
  4659. title = chart[name],
  4660. titleOptions = arr[1],
  4661. chartTitleOptions = arr[2];
  4662. if (title && titleOptions) {
  4663. title.destroy();
  4664. title = null;
  4665. }
  4666. if (chartTitleOptions && chartTitleOptions.text && !title) {
  4667. chart[name] = renderer.text(
  4668. chartTitleOptions.text,
  4669. 0,
  4670. 0
  4671. )
  4672. .attr({
  4673. align: chartTitleOptions.align,
  4674. 'class': 'highcharts-'+ name,
  4675. zIndex: 1
  4676. })
  4677. .css(chartTitleOptions.style)
  4678. .add()
  4679. .align(chartTitleOptions, false, spacingBox);
  4680. }
  4681. });
  4682. }
  4683. function getChartSize() {
  4684. containerWidth = (renderToClone || renderTo).offsetWidth;
  4685. containerHeight = (renderToClone || renderTo).offsetHeight;
  4686. chart.chartWidth = chartWidth = optionsChart.width || containerWidth || 600;
  4687. chart.chartHeight = chartHeight = optionsChart.height ||
  4688. (containerHeight > 19 ? containerHeight : 400);
  4689. }
  4690. function getContainer() {
  4691. renderTo = optionsChart.renderTo;
  4692. containerId = PREFIX + idCounter++;
  4693. if (isString(renderTo)) {
  4694. renderTo = doc.getElementById(renderTo);
  4695. }
  4696. renderTo.innerHTML = '';
  4697. if (!renderTo.offsetWidth) {
  4698. renderToClone = renderTo.cloneNode(0);
  4699. css(renderToClone, {
  4700. position: ABSOLUTE,
  4701. top: '-9999px',
  4702. display: ''
  4703. });
  4704. doc.body.appendChild(renderToClone);
  4705. }
  4706. getChartSize();
  4707. chart.container = container = createElement(DIV, {
  4708. className: 'highcharts-container' +
  4709. (optionsChart.className ? ' '+ optionsChart.className : ''),
  4710. id: containerId
  4711. }, extend({
  4712. position: RELATIVE,
  4713. overflow: HIDDEN,
  4714. width: chartWidth + PX,
  4715. height: chartHeight + PX,
  4716. textAlign: 'left'
  4717. }, optionsChart.style),
  4718. renderToClone || renderTo
  4719. );
  4720. chart.renderer = renderer =
  4721. optionsChart.forExport ?
  4722. new SVGRenderer(container, chartWidth, chartHeight, true) :
  4723. new Renderer(container, chartWidth, chartHeight);
  4724. var subPixelFix, rect;
  4725. if (isFirefox && container.getBoundingClientRect) {
  4726. subPixelFix = function() {
  4727. css(container, { left: 0, top: 0 });
  4728. rect = container.getBoundingClientRect();
  4729. css(container, {
  4730. left: (-rect.left % 1) + PX,
  4731. top: (-rect.top % 1) + PX
  4732. });
  4733. };
  4734. subPixelFix();
  4735. addEvent(win, 'resize', subPixelFix);
  4736. addEvent(chart, 'destroy', function() {
  4737. removeEvent(win, 'resize', subPixelFix);
  4738. });
  4739. }
  4740. }
  4741. getMargins = function() {
  4742. var legendOptions = options.legend,
  4743. legendMargin = pick(legendOptions.margin, 10),
  4744. legendX = legendOptions.x,
  4745. legendY = legendOptions.y,
  4746. align = legendOptions.align,
  4747. verticalAlign = legendOptions.verticalAlign,
  4748. titleOffset;
  4749. resetMargins();
  4750. if ((chart.title || chart.subtitle) && !defined(optionsMarginTop)) {
  4751. titleOffset = mathMax(
  4752. chart.title && !chartTitleOptions.floating && !chartTitleOptions.verticalAlign && chartTitleOptions.y || 0,
  4753. chart.subtitle && !chartSubtitleOptions.floating && !chartSubtitleOptions.verticalAlign && chartSubtitleOptions.y || 0
  4754. );
  4755. if (titleOffset) {
  4756. plotTop = mathMax(plotTop, titleOffset + pick(chartTitleOptions.margin, 15) + spacingTop);
  4757. }
  4758. }
  4759. if (legendOptions.enabled && !legendOptions.floating) {
  4760. if (align == 'right') {
  4761. if (!defined(optionsMarginRight)) {
  4762. marginRight = mathMax(
  4763. marginRight,
  4764. legendWidth - legendX + legendMargin + spacingRight
  4765. );
  4766. }
  4767. } else if (align == 'left') {
  4768. if (!defined(optionsMarginLeft)) {
  4769. plotLeft = mathMax(
  4770. plotLeft,
  4771. legendWidth + legendX + legendMargin + spacingLeft
  4772. );
  4773. }
  4774. } else if (verticalAlign == 'top') {
  4775. if (!defined(optionsMarginTop)) {
  4776. plotTop = mathMax(
  4777. plotTop,
  4778. legendHeight + legendY + legendMargin + spacingTop
  4779. );
  4780. }
  4781. } else if (verticalAlign == 'bottom') {
  4782. if (!defined(optionsMarginBottom)) {
  4783. marginBottom = mathMax(
  4784. marginBottom,
  4785. legendHeight - legendY + legendMargin + spacingBottom
  4786. );
  4787. }
  4788. }
  4789. }
  4790. if (hasCartesianSeries) {
  4791. each(axes, function(axis) {
  4792. axis.getOffset();
  4793. });
  4794. }
  4795. if (!defined(optionsMarginLeft)) {
  4796. plotLeft += axisOffset[3];
  4797. }
  4798. if (!defined(optionsMarginTop)) {
  4799. plotTop += axisOffset[0];
  4800. }
  4801. if (!defined(optionsMarginBottom)) {
  4802. marginBottom += axisOffset[2];
  4803. }
  4804. if (!defined(optionsMarginRight)) {
  4805. marginRight += axisOffset[1];
  4806. }
  4807. setChartSize();
  4808. };
  4809. function initReflow() {
  4810. var reflowTimeout;
  4811. function reflow() {
  4812. var width = optionsChart.width || renderTo.offsetWidth,
  4813. height = optionsChart.height || renderTo.offsetHeight;
  4814. if (width && height) {
  4815. if (width != containerWidth || height != containerHeight) {
  4816. clearTimeout(reflowTimeout);
  4817. reflowTimeout = setTimeout(function() {
  4818. resize(width, height, false);
  4819. }, 100);
  4820. }
  4821. containerWidth = width;
  4822. containerHeight = height;
  4823. }
  4824. }
  4825. addEvent(window, 'resize', reflow);
  4826. addEvent(chart, 'destroy', function() {
  4827. removeEvent(window, 'resize', reflow);
  4828. });
  4829. }
  4830. resize = function(width, height, animation) {
  4831. var chartTitle = chart.title,
  4832. chartSubtitle = chart.subtitle;
  4833. isResizing += 1;
  4834. setAnimation(animation, chart);
  4835. oldChartHeight = chartHeight;
  4836. oldChartWidth = chartWidth;
  4837. chartWidth = mathRound(width);
  4838. chartHeight = mathRound(height);
  4839. css(container, {
  4840. width: chartWidth + PX,
  4841. height: chartHeight + PX
  4842. });
  4843. renderer.setSize(chartWidth, chartHeight, animation);
  4844. plotWidth = chartWidth - plotLeft - marginRight;
  4845. plotHeight = chartHeight - plotTop - marginBottom;
  4846. maxTicks = null;
  4847. each(axes, function(axis) {
  4848. axis.isDirty = true;
  4849. axis.setScale();
  4850. });
  4851. each(series, function(serie) {
  4852. serie.isDirty = true;
  4853. });
  4854. chart.isDirtyLegend = true;
  4855. chart.isDirtyBox = true;
  4856. getMargins();
  4857. if (chartTitle) {
  4858. chartTitle.align(null, null, spacingBox);
  4859. }
  4860. if (chartSubtitle) {
  4861. chartSubtitle.align(null, null, spacingBox);
  4862. }
  4863. redraw(animation);
  4864. oldChartHeight = null;
  4865. fireEvent(chart, 'resize');
  4866. setTimeout(function() {
  4867. fireEvent(chart, 'endResize', null, function() {
  4868. isResizing -= 1;
  4869. });
  4870. }, globalAnimation && globalAnimation.duration || 500);
  4871. };
  4872. setChartSize = function() {
  4873. chart.plotLeft = plotLeft = mathRound(plotLeft);
  4874. chart.plotTop = plotTop = mathRound(plotTop);
  4875. chart.plotWidth = plotWidth = mathRound(chartWidth - plotLeft - marginRight);
  4876. chart.plotHeight = plotHeight = mathRound(chartHeight - plotTop - marginBottom);
  4877. chart.plotSizeX = inverted ? plotHeight : plotWidth;
  4878. chart.plotSizeY = inverted ? plotWidth : plotHeight;
  4879. spacingBox = {
  4880. x: spacingLeft,
  4881. y: spacingTop,
  4882. width: chartWidth - spacingLeft - spacingRight,
  4883. height: chartHeight - spacingTop - spacingBottom
  4884. };
  4885. };
  4886. resetMargins = function() {
  4887. plotTop = pick(optionsMarginTop, spacingTop);
  4888. marginRight = pick(optionsMarginRight, spacingRight);
  4889. marginBottom = pick(optionsMarginBottom, spacingBottom);
  4890. plotLeft = pick(optionsMarginLeft, spacingLeft);
  4891. axisOffset = [0, 0, 0, 0];
  4892. };
  4893. drawChartBox = function() {
  4894. var chartBorderWidth = optionsChart.borderWidth || 0,
  4895. chartBackgroundColor = optionsChart.backgroundColor,
  4896. plotBackgroundColor = optionsChart.plotBackgroundColor,
  4897. plotBackgroundImage = optionsChart.plotBackgroundImage,
  4898. mgn,
  4899. plotSize = {
  4900. x: plotLeft,
  4901. y: plotTop,
  4902. width: plotWidth,
  4903. height: plotHeight
  4904. };
  4905. mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
  4906. if (chartBorderWidth || chartBackgroundColor) {
  4907. if (!chartBackground) {
  4908. chartBackground = renderer.rect(mgn / 2, mgn / 2, chartWidth - mgn, chartHeight - mgn,
  4909. optionsChart.borderRadius, chartBorderWidth)
  4910. .attr({
  4911. stroke: optionsChart.borderColor,
  4912. 'stroke-width': chartBorderWidth,
  4913. fill: chartBackgroundColor || NONE
  4914. })
  4915. .add()
  4916. .shadow(optionsChart.shadow);
  4917. } else {
  4918. chartBackground.animate(
  4919. chartBackground.crisp(null, null, null, chartWidth - mgn, chartHeight - mgn)
  4920. );
  4921. }
  4922. }
  4923. if (plotBackgroundColor) {
  4924. if (!plotBackground) {
  4925. plotBackground = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0)
  4926. .attr({
  4927. fill: plotBackgroundColor
  4928. })
  4929. .add()
  4930. .shadow(optionsChart.plotShadow);
  4931. } else {
  4932. plotBackground.animate(plotSize);
  4933. }
  4934. }
  4935. if (plotBackgroundImage) {
  4936. if (!plotBGImage) {
  4937. plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight)
  4938. .add();
  4939. } else {
  4940. plotBGImage.animate(plotSize);
  4941. }
  4942. }
  4943. if (optionsChart.plotBorderWidth) {
  4944. if (!plotBorder) {
  4945. plotBorder = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0, optionsChart.plotBorderWidth)
  4946. .attr({
  4947. stroke: optionsChart.plotBorderColor,
  4948. 'stroke-width': optionsChart.plotBorderWidth,
  4949. zIndex: 4
  4950. })
  4951. .add();
  4952. } else {
  4953. plotBorder.animate(
  4954. plotBorder.crisp(null, plotLeft, plotTop, plotWidth, plotHeight)
  4955. );
  4956. }
  4957. }
  4958. chart.isDirtyBox = false;
  4959. };
  4960. function render () {
  4961. var labels = options.labels,
  4962. credits = options.credits,
  4963. creditsHref;
  4964. setTitle();
  4965. legend = chart.legend = new Legend(chart);
  4966. getMargins();
  4967. each(axes, function(axis) {
  4968. axis.setTickPositions(true);
  4969. });
  4970. adjustTickAmounts();
  4971. getMargins();
  4972. drawChartBox();
  4973. if (hasCartesianSeries) {
  4974. each(axes, function(axis) {
  4975. axis.render();
  4976. });
  4977. }
  4978. if (!chart.seriesGroup) {
  4979. chart.seriesGroup = renderer.g('series-group')
  4980. .attr({ zIndex: 3 })
  4981. .add();
  4982. }
  4983. each(series, function(serie) {
  4984. serie.translate();
  4985. serie.setTooltipPoints();
  4986. serie.render();
  4987. });
  4988. if (labels.items) {
  4989. each(labels.items, function() {
  4990. var style = extend(labels.style, this.style),
  4991. x = pInt(style.left) + plotLeft,
  4992. y = pInt(style.top) + plotTop + 12;
  4993. delete style.left;
  4994. delete style.top;
  4995. renderer.text(
  4996. this.html,
  4997. x,
  4998. y
  4999. )
  5000. .attr({ zIndex: 2 })
  5001. .css(style)
  5002. .add();
  5003. });
  5004. }
  5005. if (!chart.toolbar) {
  5006. chart.toolbar = Toolbar(chart);
  5007. }
  5008. if (credits.enabled && !chart.credits) {
  5009. creditsHref = credits.href;
  5010. renderer.text(
  5011. credits.text,
  5012. 0,
  5013. 0
  5014. )
  5015. .on('click', function() {
  5016. if (creditsHref) {
  5017. location.href = creditsHref;
  5018. }
  5019. })
  5020. .attr({
  5021. align: credits.position.align,
  5022. zIndex: 8
  5023. })
  5024. .css(credits.style)
  5025. .add()
  5026. .align(credits.position);
  5027. }
  5028. placeTrackerGroup();
  5029. chart.hasRendered = true;
  5030. if (renderToClone) {
  5031. renderTo.appendChild(container);
  5032. discardElement(renderToClone);
  5033. }
  5034. }
  5035. function destroy() {
  5036. var i = series.length,
  5037. parentNode = container && container.parentNode;
  5038. fireEvent(chart, 'destroy');
  5039. removeEvent(win, 'unload', destroy);
  5040. removeEvent(chart);
  5041. each(axes, function(axis) {
  5042. removeEvent(axis);
  5043. });
  5044. while (i--) {
  5045. series[i].destroy();
  5046. }
  5047. if (container) {
  5048. container.innerHTML = '';
  5049. removeEvent(container);
  5050. if (parentNode) {
  5051. parentNode.removeChild(container);
  5052. }
  5053. container = null;
  5054. }
  5055. if (renderer) {
  5056. renderer.alignedObjects = null;
  5057. }
  5058. clearInterval(tooltipInterval);
  5059. for (i in chart) {
  5060. delete chart[i];
  5061. }
  5062. }
  5063. function firstRender() {
  5064. var onreadystatechange = 'onreadystatechange';
  5065. if (!hasSVG && win == win.top && doc.readyState != 'complete') {
  5066. doc.attachEvent(onreadystatechange, function() {
  5067. doc.detachEvent(onreadystatechange, firstRender);
  5068. firstRender();
  5069. });
  5070. return;
  5071. }
  5072. getContainer();
  5073. resetMargins();
  5074. setChartSize();
  5075. each(options.series || [], function(serieOptions) {
  5076. initSeries(serieOptions);
  5077. });
  5078. chart.inverted = inverted = pick(inverted, options.chart.inverted);
  5079. getAxes();
  5080. chart.render = render;
  5081. chart.tracker = tracker = new MouseTracker(chart, options.tooltip);
  5082. render();
  5083. fireEvent(chart, 'load');
  5084. if (callback) {
  5085. callback.apply(chart, [chart]);
  5086. }
  5087. each(chart.callbacks, function(fn) {
  5088. fn.apply(chart, [chart]);
  5089. });
  5090. }
  5091. colorCounter = 0;
  5092. symbolCounter = 0;
  5093. addEvent(win, 'unload', destroy);
  5094. if (optionsChart.reflow !== false) {
  5095. addEvent(chart, 'load', initReflow);
  5096. }
  5097. if (chartEvents) {
  5098. for (eventType in chartEvents) {
  5099. addEvent(chart, eventType, chartEvents[eventType]);
  5100. }
  5101. }
  5102. chart.options = options;
  5103. chart.series = series;
  5104. chart.addSeries = addSeries;
  5105. chart.animation = pick(optionsChart.animation, true);
  5106. chart.destroy = destroy;
  5107. chart.get = get;
  5108. chart.getSelectedPoints = getSelectedPoints;
  5109. chart.getSelectedSeries = getSelectedSeries;
  5110. chart.hideLoading = hideLoading;
  5111. chart.isInsidePlot = isInsidePlot;
  5112. chart.redraw = redraw;
  5113. chart.setSize = resize;
  5114. chart.setTitle = setTitle;
  5115. chart.showLoading = showLoading;
  5116. chart.pointCount = 0;
  5117. firstRender();
  5118. }
  5119. Chart.prototype.callbacks = [];
  5120. var Point = function() {};
  5121. Point.prototype = {
  5122. init: function(series, options) {
  5123. var point = this,
  5124. defaultColors;
  5125. point.series = series;
  5126. point.applyOptions(options);
  5127. point.pointAttr = {};
  5128. if (series.options.colorByPoint) {
  5129. defaultColors = series.chart.options.colors;
  5130. if (!point.options) {
  5131. point.options = {};
  5132. }
  5133. point.color = point.options.color = point.color || defaultColors[colorCounter++];
  5134. if (colorCounter >= defaultColors.length) {
  5135. colorCounter = 0;
  5136. }
  5137. }
  5138. series.chart.pointCount++;
  5139. return point;
  5140. },
  5141. applyOptions: function(options) {
  5142. var point = this,
  5143. series = point.series;
  5144. point.config = options;
  5145. if (isNumber(options) || options === null) {
  5146. point.y = options;
  5147. }
  5148. else if (isObject(options) && !isNumber(options.length)) {
  5149. extend(point, options);
  5150. point.options = options;
  5151. }
  5152. else if (isString(options[0])) {
  5153. point.name = options[0];
  5154. point.y = options[1];
  5155. }
  5156. else if (isNumber(options[0])) {
  5157. point.x = options[0];
  5158. point.y = options[1];
  5159. }
  5160. if (point.x === UNDEFINED) {
  5161. point.x = series.autoIncrement();
  5162. }
  5163. },
  5164. destroy: function() {
  5165. var point = this,
  5166. series = point.series,
  5167. prop;
  5168. series.chart.pointCount--;
  5169. if (point == series.chart.hoverPoint) {
  5170. point.onMouseOut();
  5171. }
  5172. series.chart.hoverPoints = null;
  5173. removeEvent(point);
  5174. each(['graphic', 'tracker', 'group', 'dataLabel', 'connector'], function(prop) {
  5175. if (point[prop]) {
  5176. point[prop].destroy();
  5177. }
  5178. });
  5179. if (point.legendItem) {
  5180. point.series.chart.legend.destroyItem(point);
  5181. }
  5182. for (prop in point) {
  5183. point[prop] = null;
  5184. }
  5185. },
  5186. select: function(selected, accumulate) {
  5187. var point = this,
  5188. series = point.series,
  5189. chart = series.chart;
  5190. point.selected = selected = pick(selected, !point.selected);
  5191. point.firePointEvent(selected ? 'select' : 'unselect');
  5192. point.setState(selected && SELECT_STATE);
  5193. if (!accumulate) {
  5194. each(chart.getSelectedPoints(), function (loopPoint) {
  5195. if (loopPoint.selected && loopPoint != point) {
  5196. loopPoint.selected = false;
  5197. loopPoint.setState(NORMAL_STATE);
  5198. loopPoint.firePointEvent('unselect');
  5199. }
  5200. });
  5201. }
  5202. },
  5203. onMouseOver: function() {
  5204. var point = this,
  5205. chart = point.series.chart,
  5206. tooltip = chart.tooltip,
  5207. hoverPoint = chart.hoverPoint;
  5208. if (hoverPoint && hoverPoint != point) {
  5209. hoverPoint.onMouseOut();
  5210. }
  5211. point.firePointEvent('mouseOver');
  5212. if (tooltip && !tooltip.shared) {
  5213. tooltip.refresh(point);
  5214. }
  5215. point.setState(HOVER_STATE);
  5216. chart.hoverPoint = point;
  5217. },
  5218. onMouseOut: function() {
  5219. var point = this;
  5220. point.firePointEvent('mouseOut');
  5221. point.setState();
  5222. point.series.chart.hoverPoint = null;
  5223. },
  5224. tooltipFormatter: function(useHeader) {
  5225. var point = this,
  5226. series = point.series;
  5227. return ['<span style="color:'+ series.color +'">', (point.name || series.name), '</span>: ',
  5228. (!useHeader ? ('<b>x = '+ (point.name || point.x) + ',</b> ') : ''),
  5229. '<b>', (!useHeader ? 'y = ' : '' ), point.y, '</b><br/>'].join('');
  5230. },
  5231. getDataLabelText: function() {
  5232. var point = this;
  5233. return this.series.options.dataLabels.formatter.call({
  5234. x: point.x,
  5235. y: point.y,
  5236. series: point.series,
  5237. point: point,
  5238. percentage: point.percentage,
  5239. total: point.total || point.stackTotal
  5240. });
  5241. },
  5242. update: function(options, redraw, animation) {
  5243. var point = this,
  5244. series = point.series,
  5245. dataLabel = point.dataLabel,
  5246. graphic = point.graphic,
  5247. chart = series.chart;
  5248. redraw = pick(redraw, true);
  5249. point.firePointEvent('update', { options: options }, function() {
  5250. point.applyOptions(options);
  5251. if (dataLabel) {
  5252. dataLabel.attr({
  5253. text: point.getDataLabelText()
  5254. })
  5255. }
  5256. if (isObject(options)) {
  5257. series.getAttribs();
  5258. if (graphic) {
  5259. graphic.attr(point.pointAttr[series.state]);
  5260. }
  5261. }
  5262. series.isDirty = true;
  5263. if (redraw) {
  5264. chart.redraw(animation);
  5265. }
  5266. });
  5267. },
  5268. remove: function(redraw, animation) {
  5269. var point = this,
  5270. series = point.series,
  5271. chart = series.chart,
  5272. data = series.data;
  5273. setAnimation(animation, chart);
  5274. redraw = pick(redraw, true);
  5275. point.firePointEvent('remove', null, function() {
  5276. erase(data, point);
  5277. point.destroy();
  5278. series.isDirty = true;
  5279. if (redraw) {
  5280. chart.redraw();
  5281. }
  5282. });
  5283. },
  5284. firePointEvent: function(eventType, eventArgs, defaultFunction) {
  5285. var point = this,
  5286. series = this.series,
  5287. seriesOptions = series.options;
  5288. if (seriesOptions.point.events[eventType] || (
  5289. point.options && point.options.events && point.options.events[eventType])) {
  5290. this.importEvents();
  5291. }
  5292. if (eventType == 'click' && seriesOptions.allowPointSelect) {
  5293. defaultFunction = function (event) {
  5294. point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
  5295. };
  5296. }
  5297. fireEvent(this, eventType, eventArgs, defaultFunction);
  5298. },
  5299. importEvents: function() {
  5300. if (!this.hasImportedEvents) {
  5301. var point = this,
  5302. options = merge(point.series.options.point, point.options),
  5303. events = options.events,
  5304. eventType;
  5305. point.events = events;
  5306. for (eventType in events) {
  5307. addEvent(point, eventType, events[eventType]);
  5308. }
  5309. this.hasImportedEvents = true;
  5310. }
  5311. },
  5312. setState: function(state) {
  5313. var point = this,
  5314. series = point.series,
  5315. stateOptions = series.options.states,
  5316. markerOptions = defaultPlotOptions[series.type].marker && series.options.marker,
  5317. normalDisabled = markerOptions && !markerOptions.enabled,
  5318. markerStateOptions = markerOptions && markerOptions.states[state],
  5319. stateDisabled = markerStateOptions && markerStateOptions.enabled === false,
  5320. stateMarkerGraphic = series.stateMarkerGraphic,
  5321. chart = series.chart,
  5322. pointAttr = point.pointAttr;
  5323. if (!state) {
  5324. state = NORMAL_STATE;
  5325. }
  5326. if (
  5327. state == point.state ||
  5328. (point.selected && state != SELECT_STATE) ||
  5329. (stateOptions[state] && stateOptions[state].enabled === false) ||
  5330. (state && (stateDisabled || normalDisabled && !markerStateOptions.enabled))
  5331. ) {
  5332. return;
  5333. }
  5334. if (point.graphic) {
  5335. point.graphic.attr(pointAttr[state]);
  5336. }
  5337. else {
  5338. if (state) {
  5339. if (!stateMarkerGraphic) {
  5340. series.stateMarkerGraphic = stateMarkerGraphic = chart.renderer.circle(
  5341. 0, 0, pointAttr[state].r
  5342. )
  5343. .attr(pointAttr[state])
  5344. .add(series.group);
  5345. }
  5346. stateMarkerGraphic.translate(
  5347. point.plotX,
  5348. point.plotY
  5349. );
  5350. }
  5351. if (stateMarkerGraphic) {
  5352. stateMarkerGraphic[state ? 'show' : 'hide']();
  5353. }
  5354. }
  5355. point.state = state;
  5356. }
  5357. };
  5358. var Series = function() {};
  5359. Series.prototype = {
  5360. isCartesian: true,
  5361. type: 'line',
  5362. pointClass: Point,
  5363. pointAttrToOptions: {
  5364. stroke: 'lineColor',
  5365. 'stroke-width': 'lineWidth',
  5366. fill: 'fillColor',
  5367. r: 'radius'
  5368. },
  5369. init: function(chart, options) {
  5370. var series = this,
  5371. eventType,
  5372. events,
  5373. index = chart.series.length;
  5374. series.chart = chart;
  5375. options = series.setOptions(options);
  5376. extend(series, {
  5377. index: index,
  5378. options: options,
  5379. name: options.name || 'Series '+ (index + 1),
  5380. state: NORMAL_STATE,
  5381. pointAttr: {},
  5382. visible: options.visible !== false,
  5383. selected: options.selected === true
  5384. });
  5385. events = options.events;
  5386. for (eventType in events) {
  5387. addEvent(series, eventType, events[eventType]);
  5388. }
  5389. if (
  5390. (events && events.click) ||
  5391. (options.point && options.point.events && options.point.events.click) ||
  5392. options.allowPointSelect
  5393. ) {
  5394. chart.runTrackerClick = true;
  5395. }
  5396. series.getColor();
  5397. series.getSymbol();
  5398. series.setData(options.data, false);
  5399. },
  5400. autoIncrement: function() {
  5401. var series = this,
  5402. options = series.options,
  5403. xIncrement = series.xIncrement;
  5404. xIncrement = pick(xIncrement, options.pointStart, 0);
  5405. series.pointInterval = pick(series.pointInterval, options.pointInterval, 1);
  5406. series.xIncrement = xIncrement + series.pointInterval;
  5407. return xIncrement;
  5408. },
  5409. cleanData: function() {
  5410. var series = this,
  5411. chart = series.chart,
  5412. data = series.data,
  5413. closestPoints,
  5414. smallestInterval,
  5415. chartSmallestInterval = chart.smallestInterval,
  5416. interval,
  5417. i;
  5418. data.sort(function(a, b){
  5419. return (a.x - b.x);
  5420. });
  5421. for (i = data.length - 1; i >= 0; i--) {
  5422. if (data[i - 1]) {
  5423. if (data[i - 1].x == data[i].x) {
  5424. data.splice(i - 1, 1);
  5425. }
  5426. }
  5427. }
  5428. for (i = data.length - 1; i >= 0; i--) {
  5429. if (data[i - 1]) {
  5430. interval = data[i].x - data[i - 1].x;
  5431. if (smallestInterval === UNDEFINED || interval < smallestInterval) {
  5432. smallestInterval = interval;
  5433. closestPoints = i;
  5434. }
  5435. }
  5436. }
  5437. if (chartSmallestInterval === UNDEFINED || smallestInterval < chartSmallestInterval) {
  5438. chart.smallestInterval = smallestInterval;
  5439. }
  5440. series.closestPoints = closestPoints;
  5441. },
  5442. getSegments: function() {
  5443. var lastNull = -1,
  5444. segments = [],
  5445. data = this.data;
  5446. each(data, function(point, i) {
  5447. if (point.y === null) {
  5448. if (i > lastNull + 1) {
  5449. segments.push(data.slice(lastNull + 1, i));
  5450. }
  5451. lastNull = i;
  5452. } else if (i == data.length - 1) {
  5453. segments.push(data.slice(lastNull + 1, i + 1));
  5454. }
  5455. });
  5456. this.segments = segments;
  5457. },
  5458. setOptions: function(itemOptions) {
  5459. var plotOptions = this.chart.options.plotOptions,
  5460. options = merge(
  5461. plotOptions[this.type],
  5462. plotOptions.series,
  5463. itemOptions
  5464. );
  5465. return options;
  5466. },
  5467. getColor: function(){
  5468. var defaultColors = this.chart.options.colors;
  5469. this.color = this.options.color || defaultColors[colorCounter++] || '#0000ff';
  5470. if (colorCounter >= defaultColors.length) {
  5471. colorCounter = 0;
  5472. }
  5473. },
  5474. getSymbol: function(){
  5475. var defaultSymbols = this.chart.options.symbols,
  5476. symbol = this.options.marker.symbol || defaultSymbols[symbolCounter++];
  5477. this.symbol = symbol;
  5478. if (symbolCounter >= defaultSymbols.length) {
  5479. symbolCounter = 0;
  5480. }
  5481. },
  5482. addPoint: function(options, redraw, shift, animation) {
  5483. var series = this,
  5484. data = series.data,
  5485. graph = series.graph,
  5486. area = series.area,
  5487. chart = series.chart,
  5488. point = (new series.pointClass()).init(series, options);
  5489. setAnimation(animation, chart);
  5490. if (graph && shift) {
  5491. graph.shift = shift;
  5492. }
  5493. if (area) {
  5494. area.shift = shift;
  5495. area.isArea = true;
  5496. }
  5497. redraw = pick(redraw, true);
  5498. data.push(point);
  5499. if (shift) {
  5500. data[0].remove(false);
  5501. }
  5502. series.isDirty = true;
  5503. if (redraw) {
  5504. chart.redraw();
  5505. }
  5506. },
  5507. setData: function(data, redraw) {
  5508. var series = this,
  5509. oldData = series.data,
  5510. initialColor = series.initialColor,
  5511. chart = series.chart,
  5512. i = oldData && oldData.length || 0;
  5513. series.xIncrement = null;
  5514. if (defined(initialColor)) {
  5515. colorCounter = initialColor;
  5516. }
  5517. data = map(splat(data || []), function(pointOptions) {
  5518. return (new series.pointClass()).init(series, pointOptions);
  5519. });
  5520. while (i--) {
  5521. oldData[i].destroy();
  5522. }
  5523. series.data = data;
  5524. series.cleanData();
  5525. series.getSegments();
  5526. series.isDirty = true;
  5527. chart.isDirtyBox = true;
  5528. if (pick(redraw, true)) {
  5529. chart.redraw(false);
  5530. }
  5531. },
  5532. remove: function(redraw, animation) {
  5533. var series = this,
  5534. chart = series.chart;
  5535. redraw = pick(redraw, true);
  5536. if (!series.isRemoving) {
  5537. series.isRemoving = true;
  5538. fireEvent(series, 'remove', null, function() {
  5539. series.destroy();
  5540. chart.isDirtyLegend = chart.isDirtyBox = true;
  5541. if (redraw) {
  5542. chart.redraw(animation);
  5543. }
  5544. });
  5545. }
  5546. series.isRemoving = false;
  5547. },
  5548. translate: function() {
  5549. var series = this,
  5550. chart = series.chart,
  5551. stacking = series.options.stacking,
  5552. categories = series.xAxis.categories,
  5553. yAxis = series.yAxis,
  5554. data = series.data,
  5555. i = data.length;
  5556. while (i--) {
  5557. var point = data[i],
  5558. xValue = point.x,
  5559. yValue = point.y,
  5560. yBottom = point.low,
  5561. stack = yAxis.stacks[(yValue < 0 ? '-' : '') + series.stackKey],
  5562. pointStack,
  5563. pointStackTotal;
  5564. point.plotX = series.xAxis.translate(xValue);
  5565. if (stacking && series.visible && stack && stack[xValue]) {
  5566. pointStack = stack[xValue];
  5567. pointStackTotal = pointStack.total;
  5568. pointStack.cum = yBottom = pointStack.cum - yValue;
  5569. yValue = yBottom + yValue;
  5570. if (stacking == 'percent') {
  5571. yBottom = pointStackTotal ? yBottom * 100 / pointStackTotal : 0;
  5572. yValue = pointStackTotal ? yValue * 100 / pointStackTotal : 0;
  5573. }
  5574. point.percentage = pointStackTotal ? point.y * 100 / pointStackTotal : 0;
  5575. point.stackTotal = pointStackTotal;
  5576. }
  5577. if (defined(yBottom)) {
  5578. point.yBottom = yAxis.translate(yBottom, 0, 1);
  5579. }
  5580. if (yValue !== null) {
  5581. point.plotY = yAxis.translate(yValue, 0, 1);
  5582. }
  5583. point.clientX = chart.inverted ?
  5584. chart.plotHeight - point.plotX :
  5585. point.plotX;
  5586. point.category = categories && categories[point.x] !== UNDEFINED ?
  5587. categories[point.x] : point.x;
  5588. }
  5589. },
  5590. setTooltipPoints: function (renew) {
  5591. var series = this,
  5592. chart = series.chart,
  5593. inverted = chart.inverted,
  5594. data = [],
  5595. plotSize = mathRound((inverted ? chart.plotTop : chart.plotLeft) + chart.plotSizeX),
  5596. low,
  5597. high,
  5598. tooltipPoints = [];
  5599. if (renew) {
  5600. series.tooltipPoints = null;
  5601. }
  5602. each(series.segments, function(segment){
  5603. data = data.concat(segment);
  5604. });
  5605. if (series.xAxis && series.xAxis.reversed) {
  5606. data = data.reverse();
  5607. }
  5608. each(data, function(point, i) {
  5609. low = data[i - 1] ? data[i - 1].high + 1 : 0;
  5610. high = point.high = data[i + 1] ? (
  5611. mathFloor((point.plotX + (data[i + 1] ?
  5612. data[i + 1].plotX : plotSize)) / 2)) :
  5613. plotSize;
  5614. while (low <= high) {
  5615. tooltipPoints[inverted ? plotSize - low++ : low++] = point;
  5616. }
  5617. });
  5618. series.tooltipPoints = tooltipPoints;
  5619. },
  5620. onMouseOver: function() {
  5621. var series = this,
  5622. chart = series.chart,
  5623. hoverSeries = chart.hoverSeries;
  5624. if (!hasTouch && chart.mouseIsDown) {
  5625. return;
  5626. }
  5627. if (hoverSeries && hoverSeries != series) {
  5628. hoverSeries.onMouseOut();
  5629. }
  5630. if (series.options.events.mouseOver) {
  5631. fireEvent(series, 'mouseOver');
  5632. }
  5633. if (series.tracker) {
  5634. series.tracker.toFront();
  5635. }
  5636. series.setState(HOVER_STATE);
  5637. chart.hoverSeries = series;
  5638. },
  5639. onMouseOut: function() {
  5640. var series = this,
  5641. options = series.options,
  5642. chart = series.chart,
  5643. tooltip = chart.tooltip,
  5644. hoverPoint = chart.hoverPoint;
  5645. if (hoverPoint) {
  5646. hoverPoint.onMouseOut();
  5647. }
  5648. if (series && options.events.mouseOut) {
  5649. fireEvent(series, 'mouseOut');
  5650. }
  5651. if (tooltip && !options.stickyTracking) {
  5652. tooltip.hide();
  5653. }
  5654. series.setState();
  5655. chart.hoverSeries = null;
  5656. },
  5657. animate: function(init) {
  5658. var series = this,
  5659. chart = series.chart,
  5660. clipRect = series.clipRect,
  5661. animation = series.options.animation;
  5662. if (animation && !isObject(animation)) {
  5663. animation = {};
  5664. }
  5665. if (init) {
  5666. if (!clipRect.isAnimating) {
  5667. clipRect.attr( 'width', 0 );
  5668. clipRect.isAnimating = true;
  5669. }
  5670. } else {
  5671. clipRect.animate({
  5672. width: chart.plotSizeX
  5673. }, animation);
  5674. this.animate = null;
  5675. }
  5676. },
  5677. drawPoints: function(){
  5678. var series = this,
  5679. pointAttr,
  5680. data = series.data,
  5681. chart = series.chart,
  5682. plotX,
  5683. plotY,
  5684. i,
  5685. point,
  5686. radius,
  5687. graphic;
  5688. if (series.options.marker.enabled) {
  5689. i = data.length;
  5690. while (i--) {
  5691. point = data[i];
  5692. plotX = point.plotX;
  5693. plotY = point.plotY;
  5694. graphic = point.graphic;
  5695. if (plotY !== UNDEFINED && !isNaN(plotY)) {
  5696. pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE];
  5697. radius = pointAttr.r;
  5698. if (graphic) {
  5699. graphic.animate({
  5700. x: plotX,
  5701. y: plotY,
  5702. r: radius
  5703. });
  5704. } else {
  5705. point.graphic = chart.renderer.symbol(
  5706. pick(point.marker && point.marker.symbol, series.symbol),
  5707. plotX,
  5708. plotY,
  5709. radius
  5710. )
  5711. .attr(pointAttr)
  5712. .add(series.group);
  5713. }
  5714. }
  5715. }
  5716. }
  5717. },
  5718. convertAttribs: function(options, base1, base2, base3) {
  5719. var conversion = this.pointAttrToOptions,
  5720. attr,
  5721. option,
  5722. obj = {};
  5723. options = options || {};
  5724. base1 = base1 || {};
  5725. base2 = base2 || {};
  5726. base3 = base3 || {};
  5727. for (attr in conversion) {
  5728. option = conversion[attr];
  5729. obj[attr] = pick(options[option], base1[attr], base2[attr], base3[attr]);
  5730. }
  5731. return obj;
  5732. },
  5733. getAttribs: function() {
  5734. var series = this,
  5735. normalOptions = defaultPlotOptions[series.type].marker ? series.options.marker : series.options,
  5736. stateOptions = normalOptions.states,
  5737. stateOptionsHover = stateOptions[HOVER_STATE],
  5738. pointStateOptionsHover,
  5739. seriesColor = series.color,
  5740. normalDefaults = {
  5741. stroke: seriesColor,
  5742. fill: seriesColor
  5743. },
  5744. data = series.data,
  5745. i,
  5746. point,
  5747. seriesPointAttr = [],
  5748. pointAttr,
  5749. pointAttrToOptions = series.pointAttrToOptions,
  5750. hasPointSpecificOptions;
  5751. if (series.options.marker) {
  5752. stateOptionsHover.radius = stateOptionsHover.radius || normalOptions.radius + 2;
  5753. stateOptionsHover.lineWidth = stateOptionsHover.lineWidth || normalOptions.lineWidth + 1;
  5754. } else {
  5755. stateOptionsHover.color = stateOptionsHover.color ||
  5756. Color(stateOptionsHover.color || seriesColor)
  5757. .brighten(stateOptionsHover.brightness).get();
  5758. }
  5759. seriesPointAttr[NORMAL_STATE] = series.convertAttribs(normalOptions, normalDefaults);
  5760. each([HOVER_STATE, SELECT_STATE], function(state) {
  5761. seriesPointAttr[state] =
  5762. series.convertAttribs(stateOptions[state], seriesPointAttr[NORMAL_STATE]);
  5763. });
  5764. series.pointAttr = seriesPointAttr;
  5765. i = data.length;
  5766. while (i--) {
  5767. point = data[i];
  5768. normalOptions = (point.options && point.options.marker) || point.options;
  5769. if (normalOptions && normalOptions.enabled === false) {
  5770. normalOptions.radius = 0;
  5771. }
  5772. hasPointSpecificOptions = false;
  5773. if (point.options) {
  5774. for (var key in pointAttrToOptions) {
  5775. if (defined(normalOptions[pointAttrToOptions[key]])) {
  5776. hasPointSpecificOptions = true;
  5777. }
  5778. }
  5779. }
  5780. if (hasPointSpecificOptions) {
  5781. pointAttr = [];
  5782. stateOptions = normalOptions.states || {};
  5783. pointStateOptionsHover = stateOptions[HOVER_STATE] = stateOptions[HOVER_STATE] || {};
  5784. if (!series.options.marker) {
  5785. pointStateOptionsHover.color =
  5786. Color(pointStateOptionsHover.color || point.options.color)
  5787. .brighten(pointStateOptionsHover.brightness ||
  5788. stateOptionsHover.brightness).get();
  5789. }
  5790. pointAttr[NORMAL_STATE] = series.convertAttribs(normalOptions, seriesPointAttr[NORMAL_STATE]);
  5791. pointAttr[HOVER_STATE] = series.convertAttribs(
  5792. stateOptions[HOVER_STATE],
  5793. seriesPointAttr[HOVER_STATE],
  5794. pointAttr[NORMAL_STATE]
  5795. );
  5796. pointAttr[SELECT_STATE] = series.convertAttribs(
  5797. stateOptions[SELECT_STATE],
  5798. seriesPointAttr[SELECT_STATE],
  5799. pointAttr[NORMAL_STATE]
  5800. );
  5801. } else {
  5802. pointAttr = seriesPointAttr;
  5803. }
  5804. point.pointAttr = pointAttr;
  5805. }
  5806. },
  5807. destroy: function() {
  5808. var series = this,
  5809. chart = series.chart,
  5810. clipRect = series.clipRect,
  5811. issue134 = /\/5[0-9\.]+ (Safari|Mobile)\
  5812. destroy,
  5813. prop;
  5814. removeEvent(series);
  5815. if (series.legendItem) {
  5816. series.chart.legend.destroyItem(series);
  5817. }
  5818. each(series.data, function(point) {
  5819. point.destroy();
  5820. });
  5821. each(['area', 'graph', 'dataLabelsGroup', 'group', 'tracker'], function(prop) {
  5822. if (series[prop]) {
  5823. destroy = issue134 && prop == 'group' ?
  5824. 'hide' :
  5825. 'destroy';
  5826. series[prop][destroy]();
  5827. }
  5828. });
  5829. if (chart.hoverSeries == series) {
  5830. chart.hoverSeries = null;
  5831. }
  5832. erase(chart.series, series);
  5833. for (prop in series) {
  5834. delete series[prop];
  5835. }
  5836. },
  5837. drawDataLabels: function() {
  5838. if (this.options.dataLabels.enabled) {
  5839. var series = this,
  5840. x,
  5841. y,
  5842. data = series.data,
  5843. options = series.options.dataLabels,
  5844. str,
  5845. dataLabelsGroup = series.dataLabelsGroup,
  5846. chart = series.chart,
  5847. inverted = chart.inverted,
  5848. seriesType = series.type,
  5849. color;
  5850. if (!dataLabelsGroup) {
  5851. dataLabelsGroup = series.dataLabelsGroup =
  5852. chart.renderer.g(PREFIX +'data-labels')
  5853. .attr({
  5854. visibility: series.visible ? VISIBLE : HIDDEN,
  5855. zIndex: 5
  5856. })
  5857. .translate(chart.plotLeft, chart.plotTop)
  5858. .add();
  5859. }
  5860. color = options.color;
  5861. if (color == 'auto') {
  5862. color = null;
  5863. }
  5864. options.style.color = pick(color, series.color);
  5865. each(data, function(point, i){
  5866. var barX = point.barX,
  5867. plotX = barX && barX + point.barW / 2 || point.plotX || -999,
  5868. plotY = pick(point.plotY, -999),
  5869. dataLabel = point.dataLabel,
  5870. align = options.align;
  5871. str = point.getDataLabelText();
  5872. x = (inverted ? chart.plotWidth - plotY : plotX) + options.x;
  5873. y = (inverted ? chart.plotHeight - plotX : plotY) + options.y;
  5874. if (seriesType == 'column') {
  5875. x += { left: -1, right: 1 }[align] * point.barW / 2 || 0;
  5876. }
  5877. if (dataLabel) {
  5878. dataLabel.animate({
  5879. x: x,
  5880. y: y
  5881. });
  5882. } else if (defined(str)) {
  5883. dataLabel = point.dataLabel = chart.renderer.text(
  5884. str,
  5885. x,
  5886. y
  5887. )
  5888. .attr({
  5889. align: align,
  5890. rotation: options.rotation,
  5891. zIndex: 1
  5892. })
  5893. .css(options.style)
  5894. .add(dataLabelsGroup);
  5895. }
  5896. if (inverted && !options.y) {
  5897. dataLabel.attr({
  5898. y: y + parseInt(dataLabel.styles.lineHeight) * 0.9 - dataLabel.getBBox().height / 2
  5899. });
  5900. }
  5901. });
  5902. }
  5903. },
  5904. drawGraph: function(state) {
  5905. var series = this,
  5906. options = series.options,
  5907. chart = series.chart,
  5908. graph = series.graph,
  5909. graphPath = [],
  5910. fillColor,
  5911. area = series.area,
  5912. group = series.group,
  5913. color = options.lineColor || series.color,
  5914. lineWidth = options.lineWidth,
  5915. dashStyle = options.dashStyle,
  5916. segmentPath,
  5917. renderer = chart.renderer,
  5918. translatedThreshold = series.yAxis.getThreshold(options.threshold || 0),
  5919. useArea = /^area/.test(series.type),
  5920. singlePoints = [],
  5921. areaPath = [],
  5922. attribs;
  5923. each(series.segments, function(segment) {
  5924. segmentPath = [];
  5925. each(segment, function(point, i) {
  5926. if (series.getPointSpline) {
  5927. segmentPath.push.apply(segmentPath, series.getPointSpline(segment, point, i));
  5928. } else {
  5929. segmentPath.push(i ? L : M);
  5930. if (i && options.step) {
  5931. var lastPoint = segment[i - 1];
  5932. segmentPath.push(
  5933. point.plotX,
  5934. lastPoint.plotY
  5935. );
  5936. }
  5937. segmentPath.push(
  5938. point.plotX,
  5939. point.plotY
  5940. );
  5941. }
  5942. });
  5943. if (segment.length > 1) {
  5944. graphPath = graphPath.concat(segmentPath);
  5945. } else {
  5946. singlePoints.push(segment[0]);
  5947. }
  5948. if (useArea) {
  5949. var areaSegmentPath = [],
  5950. i,
  5951. segLength = segmentPath.length;
  5952. for (i = 0; i < segLength; i++) {
  5953. areaSegmentPath.push(segmentPath[i]);
  5954. }
  5955. if (segLength == 3) {
  5956. areaSegmentPath.push(L, segmentPath[1], segmentPath[2]);
  5957. }
  5958. if (options.stacking && series.type != 'areaspline') {
  5959. for (i = segment.length - 1; i >= 0; i--) {
  5960. areaSegmentPath.push(segment[i].plotX, segment[i].yBottom);
  5961. }
  5962. } else {
  5963. areaSegmentPath.push(
  5964. L,
  5965. segment[segment.length - 1].plotX,
  5966. translatedThreshold,
  5967. L,
  5968. segment[0].plotX,
  5969. translatedThreshold
  5970. );
  5971. }
  5972. areaPath = areaPath.concat(areaSegmentPath);
  5973. }
  5974. });
  5975. series.graphPath = graphPath;
  5976. series.singlePoints = singlePoints;
  5977. if (useArea) {
  5978. fillColor = pick(
  5979. options.fillColor,
  5980. Color(series.color).setOpacity(options.fillOpacity || 0.75).get()
  5981. );
  5982. if (area) {
  5983. area.animate({ d: areaPath });
  5984. } else {
  5985. series.area = series.chart.renderer.path(areaPath)
  5986. .attr({
  5987. fill: fillColor
  5988. }).add(group);
  5989. }
  5990. }
  5991. if (graph) {
  5992. graph.animate({ d: graphPath });
  5993. } else {
  5994. if (lineWidth) {
  5995. attribs = {
  5996. 'stroke': color,
  5997. 'stroke-width': lineWidth
  5998. };
  5999. if (dashStyle) {
  6000. attribs.dashstyle = dashStyle;
  6001. }
  6002. series.graph = renderer.path(graphPath)
  6003. .attr(attribs).add(group).shadow(options.shadow);
  6004. }
  6005. }
  6006. },
  6007. render: function() {
  6008. var series = this,
  6009. chart = series.chart,
  6010. group,
  6011. setInvert,
  6012. options = series.options,
  6013. animation = options.animation,
  6014. doAnimation = animation && series.animate,
  6015. duration = doAnimation ? animation && animation.duration || 500 : 0,
  6016. clipRect = series.clipRect,
  6017. renderer = chart.renderer;
  6018. if (!clipRect) {
  6019. clipRect = series.clipRect = !chart.hasRendered && chart.clipRect ?
  6020. chart.clipRect :
  6021. renderer.clipRect(0, 0, chart.plotSizeX, chart.plotSizeY);
  6022. if (!chart.clipRect) {
  6023. chart.clipRect = clipRect;
  6024. }
  6025. }
  6026. if (!series.group) {
  6027. group = series.group = renderer.g('series');
  6028. if (chart.inverted) {
  6029. setInvert = function() {
  6030. group.attr({
  6031. width: chart.plotWidth,
  6032. height: chart.plotHeight
  6033. }).invert();
  6034. };
  6035. setInvert();
  6036. addEvent(chart, 'resize', setInvert);
  6037. }
  6038. group.clip(series.clipRect)
  6039. .attr({
  6040. visibility: series.visible ? VISIBLE : HIDDEN,
  6041. zIndex: options.zIndex
  6042. })
  6043. .translate(chart.plotLeft, chart.plotTop)
  6044. .add(chart.seriesGroup);
  6045. }
  6046. series.drawDataLabels();
  6047. if (doAnimation) {
  6048. series.animate(true);
  6049. }
  6050. series.getAttribs();
  6051. if (series.drawGraph) {
  6052. series.drawGraph();
  6053. }
  6054. series.drawPoints();
  6055. if (series.options.enableMouseTracking !== false) {
  6056. series.drawTracker();
  6057. }
  6058. if (doAnimation) {
  6059. series.animate();
  6060. }
  6061. setTimeout(function() {
  6062. clipRect.isAnimating = false;
  6063. group = series.group;
  6064. if (group && clipRect != chart.clipRect && clipRect.renderer) {
  6065. group.clip((series.clipRect = chart.clipRect));
  6066. clipRect.destroy();
  6067. }
  6068. }, duration);
  6069. series.isDirty = false;
  6070. },
  6071. redraw: function() {
  6072. var series = this,
  6073. chart = series.chart,
  6074. clipRect = series.clipRect,
  6075. group = series.group;
  6076. if (group) {
  6077. if (chart.inverted) {
  6078. group.attr({
  6079. width: chart.plotWidth,
  6080. height: chart.plotHeight
  6081. });
  6082. }
  6083. group.animate({
  6084. translateX: chart.plotLeft,
  6085. translateY: chart.plotTop
  6086. });
  6087. }
  6088. series.translate();
  6089. series.setTooltipPoints(true);
  6090. series.render();
  6091. },
  6092. setState: function(state) {
  6093. var series = this,
  6094. options = series.options,
  6095. graph = series.graph,
  6096. stateOptions = options.states,
  6097. lineWidth = options.lineWidth;
  6098. state = state || NORMAL_STATE;
  6099. if (series.state != state) {
  6100. series.state = state;
  6101. if (stateOptions[state] && stateOptions[state].enabled === false) {
  6102. return;
  6103. }
  6104. if (state) {
  6105. lineWidth = stateOptions[state].lineWidth || lineWidth + 1;
  6106. }
  6107. if (graph && !graph.dashstyle) {
  6108. graph.attr({
  6109. 'stroke-width': lineWidth
  6110. }, state ? 0 : 500);
  6111. }
  6112. }
  6113. },
  6114. setVisible: function(vis, redraw) {
  6115. var series = this,
  6116. chart = series.chart,
  6117. legendItem = series.legendItem,
  6118. seriesGroup = series.group,
  6119. seriesTracker = series.tracker,
  6120. dataLabelsGroup = series.dataLabelsGroup,
  6121. showOrHide,
  6122. i,
  6123. data = series.data,
  6124. point,
  6125. ignoreHiddenSeries = chart.options.chart.ignoreHiddenSeries,
  6126. oldVisibility = series.visible;
  6127. series.visible = vis = vis === UNDEFINED ? !oldVisibility : vis;
  6128. showOrHide = vis ? 'show' : 'hide';
  6129. if (seriesGroup) {
  6130. seriesGroup[showOrHide]();
  6131. }
  6132. if (seriesTracker) {
  6133. seriesTracker[showOrHide]();
  6134. } else {
  6135. i = data.length;
  6136. while (i--) {
  6137. point = data[i];
  6138. if (point.tracker) {
  6139. point.tracker[showOrHide]();
  6140. }
  6141. }
  6142. }
  6143. if (dataLabelsGroup) {
  6144. dataLabelsGroup[showOrHide]();
  6145. }
  6146. if (legendItem) {
  6147. chart.legend.colorizeItem(series, vis);
  6148. }
  6149. series.isDirty = true;
  6150. if (series.options.stacking) {
  6151. each(chart.series, function(otherSeries) {
  6152. if (otherSeries.options.stacking && otherSeries.visible) {
  6153. otherSeries.isDirty = true;
  6154. }
  6155. });
  6156. }
  6157. if (ignoreHiddenSeries) {
  6158. chart.isDirtyBox = true;
  6159. }
  6160. if (redraw !== false) {
  6161. chart.redraw();
  6162. }
  6163. fireEvent(series, showOrHide);
  6164. },
  6165. show: function() {
  6166. this.setVisible(true);
  6167. },
  6168. hide: function() {
  6169. this.setVisible(false);
  6170. },
  6171. select: function(selected) {
  6172. var series = this;
  6173. series.selected = selected = (selected === UNDEFINED) ? !series.selected : selected;
  6174. if (series.checkbox) {
  6175. series.checkbox.checked = selected;
  6176. }
  6177. fireEvent(series, selected ? 'select' : 'unselect');
  6178. },
  6179. drawTracker: function() {
  6180. var series = this,
  6181. options = series.options,
  6182. trackerPath = [].concat(series.graphPath),
  6183. trackerPathLength = trackerPath.length,
  6184. chart = series.chart,
  6185. snap = chart.options.tooltip.snap,
  6186. tracker = series.tracker,
  6187. cursor = options.cursor,
  6188. css = cursor && { cursor: cursor },
  6189. singlePoints = series.singlePoints,
  6190. singlePoint,
  6191. i;
  6192. if (trackerPathLength) {
  6193. i = trackerPathLength + 1;
  6194. while (i--) {
  6195. if (trackerPath[i] == M) {
  6196. trackerPath.splice(i + 1, 0, trackerPath[i + 1] - snap, trackerPath[i + 2], L);
  6197. }
  6198. if ((i && trackerPath[i] == M) || i == trackerPathLength) {
  6199. trackerPath.splice(i, 0, L, trackerPath[i - 2] + snap, trackerPath[i - 1]);
  6200. }
  6201. }
  6202. }
  6203. for (i = 0; i < singlePoints.length; i++) {
  6204. singlePoint = singlePoints[i];
  6205. trackerPath.push(M, singlePoint.plotX - snap, singlePoint.plotY,
  6206. L, singlePoint.plotX + snap, singlePoint.plotY);
  6207. }
  6208. if (tracker) {
  6209. tracker.attr({ d: trackerPath });
  6210. } else {
  6211. series.tracker = chart.renderer.path(trackerPath)
  6212. .attr({
  6213. isTracker: true,
  6214. stroke: TRACKER_FILL,
  6215. fill: NONE,
  6216. 'stroke-width' : options.lineWidth + 2 * snap,
  6217. visibility: series.visible ? VISIBLE : HIDDEN,
  6218. zIndex: 1
  6219. })
  6220. .on(hasTouch ? 'touchstart' : 'mouseover', function() {
  6221. if (chart.hoverSeries != series) {
  6222. series.onMouseOver();
  6223. }
  6224. })
  6225. .on('mouseout', function() {
  6226. if (!options.stickyTracking) {
  6227. series.onMouseOut();
  6228. }
  6229. })
  6230. .css(css)
  6231. .add(chart.trackerGroup);
  6232. }
  6233. }
  6234. };
  6235. var LineSeries = extendClass(Series);
  6236. seriesTypes.line = LineSeries;
  6237. var AreaSeries = extendClass(Series, {
  6238. type: 'area'
  6239. });
  6240. seriesTypes.area = AreaSeries;
  6241. var SplineSeries = extendClass( Series, {
  6242. type: 'spline',
  6243. getPointSpline: function(segment, point, i) {
  6244. var smoothing = 1.5,
  6245. denom = smoothing + 1,
  6246. plotX = point.plotX,
  6247. plotY = point.plotY,
  6248. lastPoint = segment[i - 1],
  6249. nextPoint = segment[i + 1],
  6250. leftContX,
  6251. leftContY,
  6252. rightContX,
  6253. rightContY,
  6254. ret;
  6255. if (i && i < segment.length - 1) {
  6256. var lastX = lastPoint.plotX,
  6257. lastY = lastPoint.plotY,
  6258. nextX = nextPoint.plotX,
  6259. nextY = nextPoint.plotY,
  6260. correction;
  6261. leftContX = (smoothing * plotX + lastX) / denom;
  6262. leftContY = (smoothing * plotY + lastY) / denom;
  6263. rightContX = (smoothing * plotX + nextX) / denom;
  6264. rightContY = (smoothing * plotY + nextY) / denom;
  6265. correction = ((rightContY - leftContY) * (rightContX - plotX)) /
  6266. (rightContX - leftContX) + plotY - rightContY;
  6267. leftContY += correction;
  6268. rightContY += correction;
  6269. if (leftContY > lastY && leftContY > plotY) {
  6270. leftContY = mathMax(lastY, plotY);
  6271. rightContY = 2 * plotY - leftContY;
  6272. } else if (leftContY < lastY && leftContY < plotY) {
  6273. leftContY = mathMin(lastY, plotY);
  6274. rightContY = 2 * plotY - leftContY;
  6275. }
  6276. if (rightContY > nextY && rightContY > plotY) {
  6277. rightContY = mathMax(nextY, plotY);
  6278. leftContY = 2 * plotY - rightContY;
  6279. } else if (rightContY < nextY && rightContY < plotY) {
  6280. rightContY = mathMin(nextY, plotY);
  6281. leftContY = 2 * plotY - rightContY;
  6282. }
  6283. point.rightContX = rightContX;
  6284. point.rightContY = rightContY;
  6285. }
  6286. if (!i) {
  6287. ret = [M, plotX, plotY];
  6288. }
  6289. else {
  6290. ret = [
  6291. 'C',
  6292. lastPoint.rightContX || lastPoint.plotX,
  6293. lastPoint.rightContY || lastPoint.plotY,
  6294. leftContX || plotX,
  6295. leftContY || plotY,
  6296. plotX,
  6297. plotY
  6298. ];
  6299. lastPoint.rightContX = lastPoint.rightContY = null;
  6300. }
  6301. return ret;
  6302. }
  6303. });
  6304. seriesTypes.spline = SplineSeries;
  6305. var AreaSplineSeries = extendClass(SplineSeries, {
  6306. type: 'areaspline'
  6307. });
  6308. seriesTypes.areaspline = AreaSplineSeries;
  6309. var ColumnSeries = extendClass(Series, {
  6310. type: 'column',
  6311. pointAttrToOptions: {
  6312. stroke: 'borderColor',
  6313. 'stroke-width': 'borderWidth',
  6314. fill: 'color',
  6315. r: 'borderRadius'
  6316. },
  6317. init: function() {
  6318. Series.prototype.init.apply(this, arguments);
  6319. var series = this,
  6320. chart = series.chart;
  6321. chart.hasColumn = true;
  6322. if (chart.hasRendered) {
  6323. each(chart.series, function(otherSeries) {
  6324. if (otherSeries.type == series.type) {
  6325. otherSeries.isDirty = true;
  6326. }
  6327. });
  6328. }
  6329. },
  6330. translate: function() {
  6331. var series = this,
  6332. chart = series.chart,
  6333. columnCount = 0,
  6334. reversedXAxis = series.xAxis.reversed,
  6335. categories = series.xAxis.categories,
  6336. stackGroups = {},
  6337. stackKey,
  6338. columnIndex;
  6339. Series.prototype.translate.apply(series);
  6340. each(chart.series, function(otherSeries) {
  6341. if (otherSeries.type == series.type) {
  6342. if (otherSeries.options.stacking) {
  6343. stackKey = otherSeries.stackKey;
  6344. if (stackGroups[stackKey] === UNDEFINED) {
  6345. stackGroups[stackKey] = columnCount++;
  6346. }
  6347. columnIndex = stackGroups[stackKey];
  6348. } else if (otherSeries.visible){
  6349. columnIndex = columnCount++;
  6350. }
  6351. otherSeries.columnIndex = columnIndex;
  6352. }
  6353. });
  6354. var options = series.options,
  6355. data = series.data,
  6356. closestPoints = series.closestPoints,
  6357. categoryWidth = mathAbs(
  6358. data[1] ? data[closestPoints].plotX - data[closestPoints - 1].plotX :
  6359. chart.plotSizeX / (categories ? categories.length : 1)
  6360. ),
  6361. groupPadding = categoryWidth * options.groupPadding,
  6362. groupWidth = categoryWidth - 2 * groupPadding,
  6363. pointOffsetWidth = groupWidth / columnCount,
  6364. optionPointWidth = options.pointWidth,
  6365. pointPadding = defined(optionPointWidth) ? (pointOffsetWidth - optionPointWidth) / 2 :
  6366. pointOffsetWidth * options.pointPadding,
  6367. pointWidth = mathMax(pick(optionPointWidth, pointOffsetWidth - 2 * pointPadding), 1),
  6368. colIndex = (reversedXAxis ? columnCount -
  6369. series.columnIndex : series.columnIndex) || 0,
  6370. pointXOffset = pointPadding + (groupPadding + colIndex *
  6371. pointOffsetWidth -(categoryWidth / 2)) *
  6372. (reversedXAxis ? -1 : 1),
  6373. threshold = options.threshold || 0,
  6374. translatedThreshold = series.yAxis.getThreshold(threshold),
  6375. minPointLength = pick(options.minPointLength, 5);
  6376. each(data, function(point) {
  6377. var plotY = point.plotY,
  6378. yBottom = point.yBottom || translatedThreshold,
  6379. barX = point.plotX + pointXOffset,
  6380. barY = mathCeil(mathMin(plotY, yBottom)),
  6381. barH = mathCeil(mathMax(plotY, yBottom) - barY),
  6382. trackerY;
  6383. if (mathAbs(barH) < minPointLength) {
  6384. if (minPointLength) {
  6385. barH = minPointLength;
  6386. barY =
  6387. mathAbs(barY - translatedThreshold) > minPointLength ?
  6388. yBottom - minPointLength :
  6389. translatedThreshold - (plotY <= translatedThreshold ? minPointLength : 0);
  6390. }
  6391. trackerY = barY - 3;
  6392. }
  6393. extend(point, {
  6394. barX: barX,
  6395. barY: barY,
  6396. barW: pointWidth,
  6397. barH: barH
  6398. });
  6399. point.shapeType = 'rect';
  6400. point.shapeArgs = {
  6401. x: barX,
  6402. y: barY,
  6403. width: pointWidth,
  6404. height: barH,
  6405. r: options.borderRadius
  6406. };
  6407. point.trackerArgs = defined(trackerY) && merge(point.shapeArgs, {
  6408. height: mathMax(6, barH + 3),
  6409. y: trackerY
  6410. });
  6411. });
  6412. },
  6413. getSymbol: function(){
  6414. },
  6415. drawGraph: function() {},
  6416. drawPoints: function() {
  6417. var series = this,
  6418. options = series.options,
  6419. renderer = series.chart.renderer,
  6420. graphic,
  6421. shapeArgs;
  6422. each(series.data, function(point) {
  6423. var plotY = point.plotY;
  6424. if (plotY !== UNDEFINED && !isNaN(plotY)) {
  6425. graphic = point.graphic;
  6426. shapeArgs = point.shapeArgs;
  6427. if (graphic) {
  6428. stop(graphic);
  6429. graphic.animate(shapeArgs);
  6430. } else {
  6431. point.graphic = renderer[point.shapeType](shapeArgs)
  6432. .attr(point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE])
  6433. .add(series.group)
  6434. .shadow(options.shadow);
  6435. }
  6436. }
  6437. });
  6438. },
  6439. drawTracker: function() {
  6440. var series = this,
  6441. chart = series.chart,
  6442. renderer = chart.renderer,
  6443. shapeArgs,
  6444. tracker,
  6445. trackerLabel = +new Date(),
  6446. cursor = series.options.cursor,
  6447. css = cursor && { cursor: cursor },
  6448. rel;
  6449. each(series.data, function(point) {
  6450. tracker = point.tracker;
  6451. shapeArgs = point.trackerArgs || point.shapeArgs;
  6452. if (point.y !== null) {
  6453. if (tracker) {
  6454. tracker.attr(shapeArgs);
  6455. } else {
  6456. point.tracker =
  6457. renderer[point.shapeType](shapeArgs)
  6458. .attr({
  6459. isTracker: trackerLabel,
  6460. fill: TRACKER_FILL,
  6461. visibility: series.visible ? VISIBLE : HIDDEN,
  6462. zIndex: 1
  6463. })
  6464. .on(hasTouch ? 'touchstart' : 'mouseover', function(event) {
  6465. rel = event.relatedTarget || event.fromElement;
  6466. if (chart.hoverSeries != series && attr(rel, 'isTracker') != trackerLabel) {
  6467. series.onMouseOver();
  6468. }
  6469. point.onMouseOver();
  6470. })
  6471. .on('mouseout', function(event) {
  6472. if (!series.options.stickyTracking) {
  6473. rel = event.relatedTarget || event.toElement;
  6474. if (attr(rel, 'isTracker') != trackerLabel) {
  6475. series.onMouseOut();
  6476. }
  6477. }
  6478. })
  6479. .css(css)
  6480. .add(chart.trackerGroup);
  6481. }
  6482. }
  6483. });
  6484. },
  6485. animate: function(init) {
  6486. var series = this,
  6487. data = series.data;
  6488. if (!init) {
  6489. each(data, function(point) {
  6490. var graphic = point.graphic;
  6491. if (graphic) {
  6492. graphic.attr({
  6493. height: 0,
  6494. y: series.yAxis.translate(0, 0, 1)
  6495. });
  6496. graphic.animate({
  6497. height: point.barH,
  6498. y: point.barY
  6499. }, series.options.animation);
  6500. }
  6501. });
  6502. series.animate = null;
  6503. }
  6504. },
  6505. remove: function() {
  6506. var series = this,
  6507. chart = series.chart;
  6508. if (chart.hasRendered) {
  6509. each(chart.series, function(otherSeries) {
  6510. if (otherSeries.type == series.type) {
  6511. otherSeries.isDirty = true;
  6512. }
  6513. });
  6514. }
  6515. Series.prototype.remove.apply(series, arguments);
  6516. }
  6517. });
  6518. seriesTypes.column = ColumnSeries;
  6519. var BarSeries = extendClass(ColumnSeries, {
  6520. type: 'bar',
  6521. init: function(chart) {
  6522. chart.inverted = this.inverted = true;
  6523. ColumnSeries.prototype.init.apply(this, arguments);
  6524. }
  6525. });
  6526. seriesTypes.bar = BarSeries;
  6527. var ScatterSeries = extendClass(Series, {
  6528. type: 'scatter',
  6529. translate: function() {
  6530. var series = this;
  6531. Series.prototype.translate.apply(series);
  6532. each(series.data, function(point) {
  6533. point.shapeType = 'circle';
  6534. point.shapeArgs = {
  6535. x: point.plotX,
  6536. y: point.plotY,
  6537. r: series.chart.options.tooltip.snap
  6538. };
  6539. });
  6540. },
  6541. drawTracker: function() {
  6542. var series = this,
  6543. cursor = series.options.cursor,
  6544. css = cursor && { cursor: cursor },
  6545. graphic;
  6546. each(series.data, function(point) {
  6547. graphic = point.graphic;
  6548. if (graphic) {
  6549. graphic
  6550. .attr({ isTracker: true })
  6551. .on('mouseover', function(event) {
  6552. series.onMouseOver();
  6553. point.onMouseOver();
  6554. })
  6555. .on('mouseout', function(event) {
  6556. if (!series.options.stickyTracking) {
  6557. series.onMouseOut();
  6558. }
  6559. })
  6560. .css(css);
  6561. }
  6562. });
  6563. },
  6564. cleanData: function() {}
  6565. });
  6566. seriesTypes.scatter = ScatterSeries;
  6567. var PiePoint = extendClass(Point, {
  6568. init: function () {
  6569. Point.prototype.init.apply(this, arguments);
  6570. var point = this,
  6571. toggleSlice;
  6572. extend(point, {
  6573. visible: point.visible !== false,
  6574. name: pick(point.name, 'Slice')
  6575. });
  6576. toggleSlice = function() {
  6577. point.slice();
  6578. };
  6579. addEvent(point, 'select', toggleSlice);
  6580. addEvent(point, 'unselect', toggleSlice);
  6581. return point;
  6582. },
  6583. setVisible: function(vis) {
  6584. var point = this,
  6585. chart = point.series.chart,
  6586. tracker = point.tracker,
  6587. dataLabel = point.dataLabel,
  6588. connector = point.connector,
  6589. method;
  6590. point.visible = vis = vis === UNDEFINED ? !point.visible : vis;
  6591. method = vis ? 'show' : 'hide';
  6592. point.group[method]();
  6593. if (tracker) {
  6594. tracker[method]();
  6595. }
  6596. if (dataLabel) {
  6597. dataLabel[method]();
  6598. }
  6599. if (connector) {
  6600. connector[method]();
  6601. }
  6602. if (point.legendItem) {
  6603. chart.legend.colorizeItem(point, vis);
  6604. }
  6605. },
  6606. slice: function(sliced, redraw, animation) {
  6607. var point = this,
  6608. series = point.series,
  6609. chart = series.chart,
  6610. slicedTranslation = point.slicedTranslation;
  6611. setAnimation(animation, chart);
  6612. redraw = pick(redraw, true);
  6613. sliced = point.sliced = defined(sliced) ? sliced : !point.sliced;
  6614. point.group.animate({
  6615. translateX: (sliced ? slicedTranslation[0] : chart.plotLeft),
  6616. translateY: (sliced ? slicedTranslation[1] : chart.plotTop)
  6617. });
  6618. }
  6619. });
  6620. var PieSeries = extendClass(Series, {
  6621. type: 'pie',
  6622. isCartesian: false,
  6623. pointClass: PiePoint,
  6624. pointAttrToOptions: {
  6625. stroke: 'borderColor',
  6626. 'stroke-width': 'borderWidth',
  6627. fill: 'color'
  6628. },
  6629. getColor: function() {
  6630. this.initialColor = colorCounter;
  6631. },
  6632. animate: function(init) {
  6633. var series = this,
  6634. data = series.data;
  6635. each(data, function(point) {
  6636. var graphic = point.graphic,
  6637. args = point.shapeArgs,
  6638. up = -mathPI / 2;
  6639. if (graphic) {
  6640. graphic.attr({
  6641. r: 0,
  6642. start: up,
  6643. end: up
  6644. });
  6645. graphic.animate({
  6646. r: args.r,
  6647. start: args.start,
  6648. end: args.end
  6649. }, series.options.animation);
  6650. }
  6651. });
  6652. series.animate = null;
  6653. },
  6654. translate: function() {
  6655. var total = 0,
  6656. series = this,
  6657. cumulative = -0.25,
  6658. precision = 1000,
  6659. options = series.options,
  6660. slicedOffset = options.slicedOffset,
  6661. connectorOffset = slicedOffset + options.borderWidth,
  6662. positions = options.center,
  6663. chart = series.chart,
  6664. plotWidth = chart.plotWidth,
  6665. plotHeight = chart.plotHeight,
  6666. start,
  6667. end,
  6668. angle,
  6669. data = series.data,
  6670. circ = 2 * mathPI,
  6671. fraction,
  6672. smallestSize = mathMin(plotWidth, plotHeight),
  6673. isPercent,
  6674. radiusX,
  6675. radiusY,
  6676. labelDistance = options.dataLabels.distance;
  6677. positions.push(options.size, options.innerSize || 0);
  6678. positions = map(positions, function(length, i) {
  6679. isPercent = /%$/.test(length);
  6680. return isPercent ?
  6681. [plotWidth, plotHeight, smallestSize, smallestSize][i] *
  6682. pInt(length) / 100:
  6683. length;
  6684. });
  6685. series.getX = function(y, left) {
  6686. angle = math.asin((y - positions[1]) / (positions[2] / 2 + labelDistance));
  6687. return positions[0] +
  6688. (left ? -1 : 1) *
  6689. (mathCos(angle) * (positions[2] / 2 + labelDistance));
  6690. };
  6691. series.center = positions;
  6692. each(data, function(point) {
  6693. total += point.y;
  6694. });
  6695. each(data, function(point) {
  6696. fraction = total ? point.y / total : 0;
  6697. start = mathRound(cumulative * circ * precision) / precision;
  6698. cumulative += fraction;
  6699. end = mathRound(cumulative * circ * precision) / precision;
  6700. point.shapeType = 'arc';
  6701. point.shapeArgs = {
  6702. x: positions[0],
  6703. y: positions[1],
  6704. r: positions[2] / 2,
  6705. innerR: positions[3] / 2,
  6706. start: start,
  6707. end: end
  6708. };
  6709. angle = (end + start) / 2;
  6710. point.slicedTranslation = map([
  6711. mathCos(angle) * slicedOffset + chart.plotLeft,
  6712. mathSin(angle) * slicedOffset + chart.plotTop
  6713. ], mathRound);
  6714. radiusX = mathCos(angle) * positions[2] / 2;
  6715. radiusY = mathSin(angle) * positions[2] / 2;
  6716. point.tooltipPos = [
  6717. positions[0] + radiusX * 0.7,
  6718. positions[1] + radiusY * 0.7
  6719. ];
  6720. point.labelPos = [
  6721. positions[0] + radiusX + mathCos(angle) * labelDistance,
  6722. positions[1] + radiusY + mathSin(angle) * labelDistance,
  6723. positions[0] + radiusX + mathCos(angle) * connectorOffset,
  6724. positions[1] + radiusY + mathSin(angle) * connectorOffset,
  6725. positions[0] + radiusX,
  6726. positions[1] + radiusY,
  6727. labelDistance < 0 ?
  6728. 'center' :
  6729. angle < circ / 4 ? 'left' : 'right',
  6730. angle
  6731. ];
  6732. point.percentage = fraction * 100;
  6733. point.total = total;
  6734. });
  6735. this.setTooltipPoints();
  6736. },
  6737. render: function() {
  6738. var series = this;
  6739. series.getAttribs();
  6740. this.drawPoints();
  6741. if (series.options.enableMouseTracking !== false) {
  6742. series.drawTracker();
  6743. }
  6744. this.drawDataLabels();
  6745. if (series.options.animation && series.animate) {
  6746. series.animate();
  6747. }
  6748. series.isDirty = false;
  6749. },
  6750. drawPoints: function() {
  6751. var series = this,
  6752. chart = series.chart,
  6753. renderer = chart.renderer,
  6754. groupTranslation,
  6755. graphic,
  6756. group,
  6757. shapeArgs;
  6758. each(series.data, function(point) {
  6759. graphic = point.graphic;
  6760. shapeArgs = point.shapeArgs;
  6761. group = point.group;
  6762. if (!group) {
  6763. group = point.group = renderer.g('point')
  6764. .attr({ zIndex: 5 })
  6765. .add();
  6766. }
  6767. groupTranslation = point.sliced ? point.slicedTranslation : [chart.plotLeft, chart.plotTop];
  6768. group.translate(groupTranslation[0], groupTranslation[1])
  6769. if (graphic) {
  6770. graphic.animate(shapeArgs);
  6771. } else {
  6772. point.graphic =
  6773. renderer.arc(shapeArgs)
  6774. .attr(extend(
  6775. point.pointAttr[NORMAL_STATE],
  6776. { 'stroke-linejoin': 'round' }
  6777. ))
  6778. .add(point.group);
  6779. }
  6780. if (point.visible === false) {
  6781. point.setVisible(false);
  6782. }
  6783. });
  6784. },
  6785. drawDataLabels: function() {
  6786. var series = this,
  6787. data = series.data,
  6788. point,
  6789. chart = series.chart,
  6790. options = series.options.dataLabels,
  6791. connectorPadding = pick(options.connectorPadding, 10),
  6792. connectorWidth = pick(options.connectorWidth, 1),
  6793. connector,
  6794. connectorPath,
  6795. outside = options.distance > 0,
  6796. dataLabel,
  6797. labelPos,
  6798. labelHeight,
  6799. lastY,
  6800. centerY = series.center[1],
  6801. quarters = [
  6802. [],
  6803. [],
  6804. [],
  6805. []
  6806. ],
  6807. x,
  6808. y,
  6809. visibility,
  6810. overlapping,
  6811. rankArr,
  6812. secondPass,
  6813. sign,
  6814. lowerHalf,
  6815. sort,
  6816. i = 4,
  6817. j;
  6818. Series.prototype.drawDataLabels.apply(series);
  6819. each(data, function(point) {
  6820. var angle = point.labelPos[7],
  6821. quarter;
  6822. if (angle < 0) {
  6823. quarter = 0;
  6824. } else if (angle < mathPI / 2) {
  6825. quarter = 1;
  6826. } else if (angle < mathPI) {
  6827. quarter = 2;
  6828. } else {
  6829. quarter = 3;
  6830. }
  6831. quarters[quarter].push(point);
  6832. });
  6833. quarters[1].reverse();
  6834. quarters[3].reverse();
  6835. sort = function(a,b) {
  6836. return a.y > b.y;
  6837. };
  6838. while (i--) {
  6839. overlapping = 0;
  6840. rankArr = [].concat(quarters[i]);
  6841. rankArr.sort(sort);
  6842. j = rankArr.length;
  6843. while (j--) {
  6844. rankArr[j].rank = j;
  6845. }
  6846. for (secondPass = 0; secondPass < 2; secondPass++) {
  6847. lowerHalf = i % 3;
  6848. lastY = lowerHalf ? 9999 : -9999;
  6849. sign = lowerHalf ? -1 : 1;
  6850. for (j = 0; j < quarters[i].length; j++) {
  6851. point = quarters[i][j];
  6852. if ((dataLabel = point.dataLabel)) {
  6853. labelPos = point.labelPos;
  6854. visibility = VISIBLE;
  6855. x = labelPos[0];
  6856. y = labelPos[1];
  6857. if (!labelHeight) {
  6858. labelHeight = dataLabel && dataLabel.getBBox().height;
  6859. }
  6860. if (outside) {
  6861. if (secondPass && point.rank < overlapping) {
  6862. visibility = HIDDEN;
  6863. } else if ((!lowerHalf && y < lastY + labelHeight) ||
  6864. (lowerHalf && y > lastY - labelHeight)) {
  6865. y = lastY + sign * labelHeight;
  6866. x = series.getX(y, i > 1);
  6867. if ((!lowerHalf && y + labelHeight > centerY) ||
  6868. (lowerHalf && y -labelHeight < centerY)) {
  6869. if (secondPass) {
  6870. visibility = HIDDEN;
  6871. } else {
  6872. overlapping++;
  6873. }
  6874. }
  6875. }
  6876. }
  6877. if (point.visible === false) {
  6878. visibility = HIDDEN;
  6879. }
  6880. if (visibility == VISIBLE) {
  6881. lastY = y;
  6882. }
  6883. if (secondPass) {
  6884. dataLabel
  6885. .attr({
  6886. visibility: visibility,
  6887. align: labelPos[6]
  6888. })
  6889. [dataLabel.moved ? 'animate' : 'attr']({
  6890. x: x + options.x +
  6891. ({ left: connectorPadding, right: -connectorPadding }[labelPos[6]] || 0),
  6892. y: y + options.y
  6893. });
  6894. dataLabel.moved = true;
  6895. if (outside && connectorWidth) {
  6896. connector = point.connector;
  6897. connectorPath = [
  6898. M,
  6899. x + (labelPos[6] == 'left' ? 5 : -5), y,
  6900. L,
  6901. x, y,
  6902. L,
  6903. labelPos[2], labelPos[3],
  6904. L,
  6905. labelPos[4], labelPos[5]
  6906. ];
  6907. if (connector) {
  6908. connector.animate({ d: connectorPath });
  6909. connector.attr('visibility', visibility);
  6910. } else {
  6911. point.connector = connector = series.chart.renderer.path(connectorPath).attr({
  6912. 'stroke-width': connectorWidth,
  6913. stroke: options.connectorColor || '#606060',
  6914. visibility: visibility,
  6915. zIndex: 3
  6916. })
  6917. .translate(chart.plotLeft, chart.plotTop)
  6918. .add();
  6919. }
  6920. }
  6921. }
  6922. }
  6923. }
  6924. }
  6925. }
  6926. },
  6927. drawTracker: ColumnSeries.prototype.drawTracker,
  6928. getSymbol: function() {}
  6929. });
  6930. seriesTypes.pie = PieSeries;
  6931. win.Highcharts = {
  6932. Chart: Chart,
  6933. dateFormat: dateFormat,
  6934. pathAnim: pathAnim,
  6935. getOptions: getOptions,
  6936. numberFormat: numberFormat,
  6937. Point: Point,
  6938. Color: Color,
  6939. Renderer: Renderer,
  6940. seriesTypes: seriesTypes,
  6941. setOptions: setOptions,
  6942. Series: Series,
  6943. addEvent: addEvent,
  6944. createElement: createElement,
  6945. discardElement: discardElement,
  6946. css: css,
  6947. each: each,
  6948. extend: extend,
  6949. map: map,
  6950. merge: merge,
  6951. pick: pick,
  6952. extendClass: extendClass,
  6953. version: '2.1.4'
  6954. };
  6955. })();