123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974 |
- (function () {
- var UNDEFINED,
- doc = document,
- win = window,
- math = Math,
- mathRound = math.round,
- mathFloor = math.floor,
- mathCeil = math.ceil,
- mathMax = math.max,
- mathMin = math.min,
- mathAbs = math.abs,
- mathCos = math.cos,
- mathSin = math.sin,
- mathPI = math.PI,
- deg2rad = mathPI * 2 / 360,
-
- userAgent = navigator.userAgent,
- isOpera = win.opera,
- isIE = /msie/i.test(userAgent) && !isOpera,
- docMode8 = doc.documentMode === 8,
- isWebKit = /AppleWebKit/.test(userAgent),
- isFirefox = /Firefox/.test(userAgent),
- isTouchDevice = /(Mobile|Android|Windows Phone)/.test(userAgent),
- SVG_NS = 'http://www.w3.org/2000/svg',
- hasSVG = !!doc.createElementNS && !!doc.createElementNS(SVG_NS, 'svg').createSVGRect,
- hasBidiBug = isFirefox && parseInt(userAgent.split('Firefox/')[1], 10) < 4,
- useCanVG = !hasSVG && !isIE && !!doc.createElement('canvas').getContext,
- Renderer,
- hasTouch = doc.documentElement.ontouchstart !== UNDEFINED,
- symbolSizes = {},
- idCounter = 0,
- garbageBin,
- defaultOptions,
- dateFormat,
- globalAnimation,
- pathAnim,
- timeUnits,
- noop = function () {},
- charts = [],
- PRODUCT = 'Highcharts',
- VERSION = '3.0.6',
-
- DIV = 'div',
- ABSOLUTE = 'absolute',
- RELATIVE = 'relative',
- HIDDEN = 'hidden',
- PREFIX = 'highcharts-',
- VISIBLE = 'visible',
- PX = 'px',
- NONE = 'none',
- M = 'M',
- L = 'L',
-
- TRACKER_FILL = 'rgba(192,192,192,' + (hasSVG ? 0.0001 : 0.002) + ')',
-
- NORMAL_STATE = '',
- HOVER_STATE = 'hover',
- SELECT_STATE = 'select',
- MILLISECOND = 'millisecond',
- SECOND = 'second',
- MINUTE = 'minute',
- HOUR = 'hour',
- DAY = 'day',
- WEEK = 'week',
- MONTH = 'month',
- YEAR = 'year',
-
- LINEAR_GRADIENT = 'linearGradient',
- STOPS = 'stops',
- STROKE_WIDTH = 'stroke-width',
-
- makeTime,
- getMinutes,
- getHours,
- getDay,
- getDate,
- getMonth,
- getFullYear,
- setMinutes,
- setHours,
- setDate,
- setMonth,
- setFullYear,
-
- seriesTypes = {};
- win.Highcharts = win.Highcharts ? error(16, true) : {};
- function extend(a, b) {
- var n;
- if (!a) {
- a = {};
- }
- for (n in b) {
- a[n] = b[n];
- }
- return a;
- }
-
- function merge() {
- var i,
- len = arguments.length,
- ret = {},
- doCopy = function (copy, original) {
- var value, key;
-
- if (typeof copy !== 'object') {
- copy = {};
- }
- for (key in original) {
- if (original.hasOwnProperty(key)) {
- value = original[key];
-
- if (value && typeof value === 'object' && Object.prototype.toString.call(value) !== '[object Array]'
- && typeof value.nodeType !== 'number') {
- copy[key] = doCopy(copy[key] || {}, value);
-
-
- } else {
- copy[key] = original[key];
- }
- }
- }
- return copy;
- };
-
- for (i = 0; i < len; i++) {
- ret = doCopy(ret, arguments[i]);
- }
- return ret;
- }
- function hash() {
- var i = 0,
- args = arguments,
- length = args.length,
- obj = {};
- for (; i < length; i++) {
- obj[args[i++]] = args[i];
- }
- return obj;
- }
- function pInt(s, mag) {
- return parseInt(s, mag || 10);
- }
- function isString(s) {
- return typeof s === 'string';
- }
- function isObject(obj) {
- return typeof obj === 'object';
- }
- function isArray(obj) {
- return Object.prototype.toString.call(obj) === '[object Array]';
- }
- function isNumber(n) {
- return typeof n === 'number';
- }
- function log2lin(num) {
- return math.log(num) / math.LN10;
- }
- function lin2log(num) {
- return math.pow(10, num);
- }
- function erase(arr, item) {
- var i = arr.length;
- while (i--) {
- if (arr[i] === item) {
- arr.splice(i, 1);
- break;
- }
- }
-
- }
- function defined(obj) {
- return obj !== UNDEFINED && obj !== null;
- }
- function attr(elem, prop, value) {
- var key,
- setAttribute = 'setAttribute',
- ret;
-
- if (isString(prop)) {
-
- if (defined(value)) {
- elem[setAttribute](prop, value);
-
- } else if (elem && elem.getAttribute) {
- ret = elem.getAttribute(prop);
- }
-
- } else if (defined(prop) && isObject(prop)) {
- for (key in prop) {
- elem[setAttribute](key, prop[key]);
- }
- }
- return ret;
- }
- function splat(obj) {
- return isArray(obj) ? obj : [obj];
- }
- function pick() {
- var args = arguments,
- i,
- arg,
- length = args.length;
- for (i = 0; i < length; i++) {
- arg = args[i];
- if (typeof arg !== 'undefined' && arg !== null) {
- return arg;
- }
- }
- }
- function css(el, styles) {
- if (isIE) {
- if (styles && styles.opacity !== UNDEFINED) {
- styles.filter = 'alpha(opacity=' + (styles.opacity * 100) + ')';
- }
- }
- extend(el.style, styles);
- }
- function createElement(tag, attribs, styles, parent, nopad) {
- var el = doc.createElement(tag);
- if (attribs) {
- extend(el, attribs);
- }
- if (nopad) {
- css(el, {padding: 0, border: NONE, margin: 0});
- }
- if (styles) {
- css(el, styles);
- }
- if (parent) {
- parent.appendChild(el);
- }
- return el;
- }
- function extendClass(parent, members) {
- var object = function () {};
- object.prototype = new parent();
- extend(object.prototype, members);
- return object;
- }
- function numberFormat(number, decimals, decPoint, thousandsSep) {
- var lang = defaultOptions.lang,
-
- n = +number || 0,
- c = decimals === -1 ?
- (n.toString().split('.')[1] || '').length :
- (isNaN(decimals = mathAbs(decimals)) ? 2 : decimals),
- d = decPoint === undefined ? lang.decimalPoint : decPoint,
- t = thousandsSep === undefined ? lang.thousandsSep : thousandsSep,
- s = n < 0 ? "-" : "",
- i = String(pInt(n = mathAbs(n).toFixed(c))),
- j = i.length > 3 ? i.length % 3 : 0;
- return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) +
- (c ? d + mathAbs(n - i).toFixed(c).slice(2) : "");
- }
- function pad(number, length) {
-
- return new Array((length || 2) + 1 - String(number).length).join(0) + number;
- }
- function wrap(obj, method, func) {
- var proceed = obj[method];
- obj[method] = function () {
- var args = Array.prototype.slice.call(arguments);
- args.unshift(proceed);
- return func.apply(this, args);
- };
- }
- dateFormat = function (format, timestamp, capitalize) {
- if (!defined(timestamp) || isNaN(timestamp)) {
- return 'Invalid date';
- }
- format = pick(format, '%Y-%m-%d %H:%M:%S');
- var date = new Date(timestamp),
- key,
-
- hours = date[getHours](),
- day = date[getDay](),
- dayOfMonth = date[getDate](),
- month = date[getMonth](),
- fullYear = date[getFullYear](),
- lang = defaultOptions.lang,
- langWeekdays = lang.weekdays,
-
- replacements = extend({
-
- 'a': langWeekdays[day].substr(0, 3),
- 'A': langWeekdays[day],
- 'd': pad(dayOfMonth),
- 'e': dayOfMonth,
-
-
-
- 'b': lang.shortMonths[month],
- 'B': lang.months[month],
- 'm': pad(month + 1),
-
- 'y': fullYear.toString().substr(2, 2),
- 'Y': fullYear,
-
- 'H': pad(hours),
- 'I': pad((hours % 12) || 12),
- 'l': (hours % 12) || 12,
- 'M': pad(date[getMinutes]()),
- 'p': hours < 12 ? 'AM' : 'PM',
- 'P': hours < 12 ? 'am' : 'pm',
- 'S': pad(date.getSeconds()),
- 'L': pad(mathRound(timestamp % 1000), 3)
- }, Highcharts.dateFormats);
-
- for (key in replacements) {
- while (format.indexOf('%' + key) !== -1) {
- format = format.replace('%' + key, typeof replacements[key] === 'function' ? replacements[key](timestamp) : replacements[key]);
- }
- }
-
- return capitalize ? format.substr(0, 1).toUpperCase() + format.substr(1) : format;
- };
- function formatSingle(format, val) {
- var floatRegex = /f$/,
- decRegex = /\.([0-9])/,
- lang = defaultOptions.lang,
- decimals;
- if (floatRegex.test(format)) {
- decimals = format.match(decRegex);
- decimals = decimals ? decimals[1] : -1;
- val = numberFormat(
- val,
- decimals,
- lang.decimalPoint,
- format.indexOf(',') > -1 ? lang.thousandsSep : ''
- );
- } else {
- val = dateFormat(format, val);
- }
- return val;
- }
- function format(str, ctx) {
- var splitter = '{',
- isInside = false,
- segment,
- valueAndFormat,
- path,
- i,
- len,
- ret = [],
- val,
- index;
-
- while ((index = str.indexOf(splitter)) !== -1) {
-
- segment = str.slice(0, index);
- if (isInside) {
-
- valueAndFormat = segment.split(':');
- path = valueAndFormat.shift().split('.');
- len = path.length;
- val = ctx;
-
- for (i = 0; i < len; i++) {
- val = val[path[i]];
- }
-
- if (valueAndFormat.length) {
- val = formatSingle(valueAndFormat.join(':'), val);
- }
-
- ret.push(val);
-
- } else {
- ret.push(segment);
-
- }
- str = str.slice(index + 1);
- isInside = !isInside;
- splitter = isInside ? '}' : '{';
- }
- ret.push(str);
- return ret.join('');
- }
- function getMagnitude(num) {
- return math.pow(10, mathFloor(math.log(num) / math.LN10));
- }
- function normalizeTickInterval(interval, multiples, magnitude, options) {
- var normalized, i;
-
- magnitude = pick(magnitude, 1);
- normalized = interval / magnitude;
-
- if (!multiples) {
- multiples = [1, 2, 2.5, 5, 10];
-
- if (options && options.allowDecimals === false) {
- if (magnitude === 1) {
- multiples = [1, 2, 5, 10];
- } else if (magnitude <= 0.1) {
- multiples = [1 / magnitude];
- }
- }
- }
-
- for (i = 0; i < multiples.length; i++) {
- interval = multiples[i];
- if (normalized <= (multiples[i] + (multiples[i + 1] || multiples[i])) / 2) {
- break;
- }
- }
-
- interval *= magnitude;
- return interval;
- }
- function normalizeTimeTickInterval(tickInterval, unitsOption) {
- var units = unitsOption || [[
- MILLISECOND,
- [1, 2, 5, 10, 20, 25, 50, 100, 200, 500]
- ], [
- SECOND,
- [1, 2, 5, 10, 15, 30]
- ], [
- MINUTE,
- [1, 2, 5, 10, 15, 30]
- ], [
- HOUR,
- [1, 2, 3, 4, 6, 8, 12]
- ], [
- DAY,
- [1, 2]
- ], [
- WEEK,
- [1, 2]
- ], [
- MONTH,
- [1, 2, 3, 4, 6]
- ], [
- YEAR,
- null
- ]],
- unit = units[units.length - 1],
- interval = timeUnits[unit[0]],
- multiples = unit[1],
- count,
- i;
-
-
- for (i = 0; i < units.length; i++) {
- unit = units[i];
- interval = timeUnits[unit[0]];
- multiples = unit[1];
- if (units[i + 1]) {
-
- var lessThan = (interval * multiples[multiples.length - 1] +
- timeUnits[units[i + 1][0]]) / 2;
-
- if (tickInterval <= lessThan) {
- break;
- }
- }
- }
-
- if (interval === timeUnits[YEAR] && tickInterval < 5 * interval) {
- multiples = [1, 2, 5];
- }
-
- count = normalizeTickInterval(
- tickInterval / interval,
- multiples,
- unit[0] === YEAR ? getMagnitude(tickInterval / interval) : 1
- );
-
- return {
- unitRange: interval,
- count: count,
- unitName: unit[0]
- };
- }
- function getTimeTicks(normalizedInterval, min, max, startOfWeek) {
- var tickPositions = [],
- i,
- higherRanks = {},
- useUTC = defaultOptions.global.useUTC,
- minYear,
- minDate = new Date(min),
- interval = normalizedInterval.unitRange,
- count = normalizedInterval.count;
- if (defined(min)) {
- if (interval >= timeUnits[SECOND]) {
- minDate.setMilliseconds(0);
- minDate.setSeconds(interval >= timeUnits[MINUTE] ? 0 :
- count * mathFloor(minDate.getSeconds() / count));
- }
-
- if (interval >= timeUnits[MINUTE]) {
- minDate[setMinutes](interval >= timeUnits[HOUR] ? 0 :
- count * mathFloor(minDate[getMinutes]() / count));
- }
-
- if (interval >= timeUnits[HOUR]) {
- minDate[setHours](interval >= timeUnits[DAY] ? 0 :
- count * mathFloor(minDate[getHours]() / count));
- }
-
- if (interval >= timeUnits[DAY]) {
- minDate[setDate](interval >= timeUnits[MONTH] ? 1 :
- count * mathFloor(minDate[getDate]() / count));
- }
-
- if (interval >= timeUnits[MONTH]) {
- minDate[setMonth](interval >= timeUnits[YEAR] ? 0 :
- count * mathFloor(minDate[getMonth]() / count));
- minYear = minDate[getFullYear]();
- }
-
- if (interval >= timeUnits[YEAR]) {
- minYear -= minYear % count;
- minDate[setFullYear](minYear);
- }
-
-
- if (interval === timeUnits[WEEK]) {
-
- minDate[setDate](minDate[getDate]() - minDate[getDay]() +
- pick(startOfWeek, 1));
- }
-
-
-
- i = 1;
- minYear = minDate[getFullYear]();
- var time = minDate.getTime(),
- minMonth = minDate[getMonth](),
- minDateDate = minDate[getDate](),
- timezoneOffset = useUTC ?
- 0 :
- (24 * 3600 * 1000 + minDate.getTimezoneOffset() * 60 * 1000) % (24 * 3600 * 1000);
-
-
- while (time < max) {
- tickPositions.push(time);
-
-
- if (interval === timeUnits[YEAR]) {
- time = makeTime(minYear + i * count, 0);
-
-
- } else if (interval === timeUnits[MONTH]) {
- time = makeTime(minYear, minMonth + i * count);
-
-
-
- } else if (!useUTC && (interval === timeUnits[DAY] || interval === timeUnits[WEEK])) {
- time = makeTime(minYear, minMonth, minDateDate +
- i * count * (interval === timeUnits[DAY] ? 1 : 7));
-
-
- } else {
- time += interval * count;
- }
-
- i++;
- }
-
-
- tickPositions.push(time);
-
- each(grep(tickPositions, function (time) {
- return interval <= timeUnits[HOUR] && time % timeUnits[DAY] === timezoneOffset;
- }), function (time) {
- higherRanks[time] = DAY;
- });
- }
-
- tickPositions.info = extend(normalizedInterval, {
- higherRanks: higherRanks,
- totalRange: interval * count
- });
- return tickPositions;
- }
- function ChartCounters() {
- this.color = 0;
- this.symbol = 0;
- }
- ChartCounters.prototype = {
-
- wrapColor: function (length) {
- if (this.color >= length) {
- this.color = 0;
- }
- },
-
- wrapSymbol: function (length) {
- if (this.symbol >= length) {
- this.symbol = 0;
- }
- }
- };
- function stableSort(arr, sortFunction) {
- var length = arr.length,
- sortValue,
- i;
-
- for (i = 0; i < length; i++) {
- arr[i].ss_i = i;
- }
- arr.sort(function (a, b) {
- sortValue = sortFunction(a, b);
- return sortValue === 0 ? a.ss_i - b.ss_i : sortValue;
- });
-
- for (i = 0; i < length; i++) {
- delete arr[i].ss_i;
- }
- }
- function arrayMin(data) {
- var i = data.length,
- min = data[0];
- while (i--) {
- if (data[i] < min) {
- min = data[i];
- }
- }
- return min;
- }
- function arrayMax(data) {
- var i = data.length,
- max = data[0];
- while (i--) {
- if (data[i] > max) {
- max = data[i];
- }
- }
- return max;
- }
- function destroyObjectProperties(obj, except) {
- var n;
- for (n in obj) {
-
- if (obj[n] && obj[n] !== except && obj[n].destroy) {
-
- obj[n].destroy();
- }
-
- delete obj[n];
- }
- }
- function discardElement(element) {
-
- if (!garbageBin) {
- garbageBin = createElement(DIV);
- }
-
- if (element) {
- garbageBin.appendChild(element);
- }
- garbageBin.innerHTML = '';
- }
- function error(code, stop) {
- var msg = 'Highcharts error #' + code + ': www.highcharts.com/errors/' + code;
- if (stop) {
- throw msg;
- } else if (win.console) {
- console.log(msg);
- }
- }
- function correctFloat(num) {
- return parseFloat(
- num.toPrecision(14)
- );
- }
- function setAnimation(animation, chart) {
- globalAnimation = pick(animation, chart.animation);
- }
- timeUnits = hash(
- MILLISECOND, 1,
- SECOND, 1000,
- MINUTE, 60000,
- HOUR, 3600000,
- DAY, 24 * 3600000,
- WEEK, 7 * 24 * 3600000,
- MONTH, 31 * 24 * 3600000,
- YEAR, 31556952000
- );
- pathAnim = {
-
- init: function (elem, fromD, toD) {
- fromD = fromD || '';
- var shift = elem.shift,
- bezier = fromD.indexOf('C') > -1,
- numParams = bezier ? 7 : 3,
- endLength,
- slice,
- i,
- start = fromD.split(' '),
- end = [].concat(toD),
- startBaseLine,
- endBaseLine,
- sixify = function (arr) {
- i = arr.length;
- while (i--) {
- if (arr[i] === M) {
- arr.splice(i + 1, 0, arr[i + 1], arr[i + 2], arr[i + 1], arr[i + 2]);
- }
- }
- };
- if (bezier) {
- sixify(start);
- sixify(end);
- }
-
- if (elem.isArea) {
- startBaseLine = start.splice(start.length - 6, 6);
- endBaseLine = end.splice(end.length - 6, 6);
- }
-
- if (shift <= end.length / numParams && start.length === end.length) {
- while (shift--) {
- end = [].concat(end).splice(0, numParams).concat(end);
- }
- }
- elem.shift = 0;
-
- if (start.length) {
- endLength = end.length;
- while (start.length < endLength) {
-
- slice = [].concat(start).splice(start.length - numParams, numParams);
- if (bezier) {
- slice[numParams - 6] = slice[numParams - 2];
- slice[numParams - 5] = slice[numParams - 1];
- }
- start = start.concat(slice);
- }
- }
- if (startBaseLine) {
- start = start.concat(startBaseLine);
- end = end.concat(endBaseLine);
- }
- return [start, end];
- },
-
- step: function (start, end, pos, complete) {
- var ret = [],
- i = start.length,
- startVal;
- if (pos === 1) {
- ret = complete;
- } else if (i === end.length && pos < 1) {
- while (i--) {
- startVal = parseFloat(start[i]);
- ret[i] =
- isNaN(startVal) ?
- start[i] :
- pos * (parseFloat(end[i] - startVal)) + startVal;
- }
- } else {
- ret = end;
- }
- return ret;
- }
- };
- (function ($) {
-
- win.HighchartsAdapter = win.HighchartsAdapter || ($ && {
-
-
- init: function (pathAnim) {
-
-
- var Fx = $.fx,
- Step = Fx.step,
- dSetter,
- Tween = $.Tween,
- propHooks = Tween && Tween.propHooks,
- opacityHook = $.cssHooks.opacity;
-
-
- $.extend($.easing, {
- easeOutQuad: function (x, t, b, c, d) {
- return -c * (t /= d) * (t - 2) + b;
- }
- });
-
-
-
- $.each(['cur', '_default', 'width', 'height', 'opacity'], function (i, fn) {
- var obj = Step,
- base,
- elem;
-
-
- if (fn === 'cur') {
- obj = Fx.prototype;
-
- } else if (fn === '_default' && Tween) {
- obj = propHooks[fn];
- fn = 'set';
- }
-
-
- base = obj[fn];
- if (base) {
-
-
- obj[fn] = function (fx) {
-
-
- fx = i ? fx : this;
-
- if (fx.prop === 'align') {
- return;
- }
-
-
- elem = fx.elem;
-
-
-
- return elem.attr ?
- elem.attr(fx.prop, fn === 'cur' ? UNDEFINED : fx.now) :
- base.apply(this, arguments);
- };
- }
- });
-
- wrap(opacityHook, 'get', function (proceed, elem, computed) {
- return elem.attr ? (elem.opacity || 0) : proceed.call(this, elem, computed);
- });
-
-
-
- dSetter = function (fx) {
- var elem = fx.elem,
- ends;
-
-
-
-
- if (!fx.started) {
- ends = pathAnim.init(elem, elem.d, elem.toD);
- fx.start = ends[0];
- fx.end = ends[1];
- fx.started = true;
- }
-
-
-
- elem.attr('d', pathAnim.step(fx.start, fx.end, fx.pos, elem.toD));
- };
-
-
- if (Tween) {
- propHooks.d = {
- set: dSetter
- };
-
- } else {
-
- Step.d = dSetter;
- }
-
-
- this.each = Array.prototype.forEach ?
- function (arr, fn) {
- return Array.prototype.forEach.call(arr, fn);
-
- } :
- function (arr, fn) {
- var i = 0,
- len = arr.length;
- for (; i < len; i++) {
- if (fn.call(arr[i], arr[i], i, arr) === false) {
- return i;
- }
- }
- };
-
-
- $.fn.highcharts = function () {
- var constr = 'Chart',
- args = arguments,
- options,
- ret,
- chart;
- if (isString(args[0])) {
- constr = args[0];
- args = Array.prototype.slice.call(args, 1);
- }
- options = args[0];
-
- if (options !== UNDEFINED) {
-
- options.chart = options.chart || {};
- options.chart.renderTo = this[0];
- chart = new Highcharts[constr](options, args[1]);
- ret = this;
-
- }
-
- if (options === UNDEFINED) {
- ret = charts[attr(this[0], 'data-highcharts-chart')];
- }
- return ret;
- };
- },
-
-
- getScript: $.getScript,
-
-
- inArray: $.inArray,
-
-
- adapterRun: function (elem, method) {
- return $(elem)[method]();
- },
-
-
- grep: $.grep,
-
-
- map: function (arr, fn) {
-
- var results = [],
- i = 0,
- len = arr.length;
- for (; i < len; i++) {
- results[i] = fn.call(arr[i], arr[i], i, arr);
- }
- return results;
-
- },
-
-
- offset: function (el) {
- return $(el).offset();
- },
-
-
- addEvent: function (el, event, fn) {
- $(el).bind(event, fn);
- },
-
-
- removeEvent: function (el, eventType, handler) {
-
-
- var func = doc.removeEventListener ? 'removeEventListener' : 'detachEvent';
- if (doc[func] && el && !el[func]) {
- el[func] = function () {};
- }
-
- $(el).unbind(eventType, handler);
- },
-
-
- fireEvent: function (el, type, eventArguments, defaultFunction) {
- var event = $.Event(type),
- detachedType = 'detached' + type,
- defaultPrevented;
-
-
-
-
-
-
-
- if (!isIE && eventArguments) {
- delete eventArguments.layerX;
- delete eventArguments.layerY;
- }
-
- extend(event, eventArguments);
-
-
-
-
- if (el[type]) {
- el[detachedType] = el[type];
- el[type] = null;
- }
-
-
-
-
-
- $.each(['preventDefault', 'stopPropagation'], function (i, fn) {
- var base = event[fn];
- event[fn] = function () {
- try {
- base.call(event);
- } catch (e) {
- if (fn === 'preventDefault') {
- defaultPrevented = true;
- }
- }
- };
- });
-
-
-
- $(el).trigger(event);
-
-
- if (el[detachedType]) {
- el[type] = el[detachedType];
- el[detachedType] = null;
- }
-
- if (defaultFunction && !event.isDefaultPrevented() && !defaultPrevented) {
- defaultFunction(event);
- }
- },
-
-
- washMouseEvent: function (e) {
- var ret = e.originalEvent || e;
-
-
- if (ret.pageX === UNDEFINED) {
- ret.pageX = e.pageX;
- ret.pageY = e.pageY;
- }
-
- return ret;
- },
-
-
- animate: function (el, params, options) {
- var $el = $(el);
- if (!el.style) {
- el.style = {};
- }
- if (params.d) {
- el.toD = params.d;
- params.d = 1;
- }
-
- $el.stop();
- if (params.opacity !== UNDEFINED && el.attr) {
- params.opacity += 'px';
- }
- $el.animate(params, options);
-
- },
-
- stop: function (el) {
- $(el).stop();
- }
- });
- }(win.jQuery));
- var globalAdapter = win.HighchartsAdapter,
- adapter = globalAdapter || {};
-
- if (globalAdapter) {
- globalAdapter.init.call(globalAdapter, pathAnim);
- }
- var adapterRun = adapter.adapterRun,
- getScript = adapter.getScript,
- inArray = adapter.inArray,
- each = adapter.each,
- grep = adapter.grep,
- offset = adapter.offset,
- map = adapter.map,
- addEvent = adapter.addEvent,
- removeEvent = adapter.removeEvent,
- fireEvent = adapter.fireEvent,
- washMouseEvent = adapter.washMouseEvent,
- animate = adapter.animate,
- stop = adapter.stop;
- var
- defaultLabelOptions = {
- enabled: true,
-
-
- x: 0,
- y: 15,
-
- style: {
- color: '#666',
- cursor: 'default',
- fontSize: '11px',
- lineHeight: '14px'
- }
- };
- defaultOptions = {
- colors: ['#2f7ed8', '#0d233a', '#8bbc21', '#910000', '#1aadce', '#492970',
- '#f28f43', '#77a1e5', '#c42525', '#a6c96a'],
- symbols: ['circle', 'diamond', 'square', 'triangle', 'triangle-down'],
- lang: {
- loading: 'Loading...',
- months: ['January', 'February', 'March', 'April', 'May', 'June', 'July',
- 'August', 'September', 'October', 'November', 'December'],
- shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
- weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- decimalPoint: '.',
- numericSymbols: ['k', 'M', 'G', 'T', 'P', 'E'],
- resetZoom: 'Reset zoom',
- resetZoomTitle: 'Reset zoom level 1:1',
- thousandsSep: ','
- },
- global: {
- useUTC: true,
- canvasToolsURL: 'http://code.highcharts.com/3.0.6/modules/canvas-tools.js',
- VMLRadialGradientURL: 'http://code.highcharts.com/3.0.6/gfx/vml-radial-gradient.png'
- },
- chart: {
-
-
-
-
-
-
-
-
-
-
- borderColor: '#4572A7',
-
- borderRadius: 5,
- defaultSeriesType: 'line',
- ignoreHiddenSeries: true,
-
-
- spacing: [10, 10, 15, 10],
-
-
-
-
- style: {
- fontFamily: '"Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif',
- fontSize: '12px'
- },
- backgroundColor: '#FFFFFF',
-
- plotBorderColor: '#C0C0C0',
-
-
-
- resetZoomButton: {
- theme: {
- zIndex: 20
- },
- position: {
- align: 'right',
- x: -10,
-
- y: 10
- }
-
- }
- },
- title: {
- text: 'Chart title',
- align: 'center',
-
- margin: 15,
-
-
-
- style: {
- color: '#274b6d',
- fontSize: '16px'
- }
- },
- subtitle: {
- text: '',
- align: 'center',
-
-
-
-
- style: {
- color: '#4d759e'
- }
- },
- plotOptions: {
- line: {
- allowPointSelect: false,
- showCheckbox: false,
- animation: {
- duration: 1000
- },
-
-
-
-
-
- events: {},
-
- lineWidth: 2,
-
-
- marker: {
- enabled: true,
-
- lineWidth: 0,
- radius: 4,
- lineColor: '#FFFFFF',
-
- states: {
- hover: {
- enabled: true
-
- },
- select: {
- fillColor: '#FFFFFF',
- lineColor: '#000000',
- lineWidth: 2
- }
- }
- },
- point: {
- events: {}
- },
- dataLabels: merge(defaultLabelOptions, {
- align: 'center',
- enabled: false,
- formatter: function () {
- return this.y === null ? '' : numberFormat(this.y, -1);
- },
- verticalAlign: 'bottom',
- y: 0
-
-
-
-
-
-
- }),
- cropThreshold: 300,
- pointRange: 0,
-
-
- showInLegend: true,
- states: {
- hover: {
-
-
- marker: {
-
-
- }
- },
- select: {
- marker: {}
- }
- },
- stickyTracking: true
-
-
-
-
-
-
-
-
-
- }
- },
- labels: {
-
- style: {
-
- position: ABSOLUTE,
- color: '#3E576F'
- }
- },
- legend: {
- enabled: true,
- align: 'center',
-
- layout: 'horizontal',
- labelFormatter: function () {
- return this.name;
- },
- borderWidth: 1,
- borderColor: '#909090',
- borderRadius: 5,
- navigation: {
-
- activeColor: '#274b6d',
-
- inactiveColor: '#CCC'
-
- },
-
-
- shadow: false,
-
-
- itemStyle: {
- cursor: 'pointer',
- color: '#274b6d',
- fontSize: '12px'
- },
- itemHoverStyle: {
-
- color: '#000'
- },
- itemHiddenStyle: {
- color: '#CCC'
- },
- itemCheckboxStyle: {
- position: ABSOLUTE,
- width: '13px',
- height: '13px'
- },
-
- symbolWidth: 16,
- symbolPadding: 5,
- verticalAlign: 'bottom',
-
- x: 0,
- y: 0,
- title: {
-
- style: {
- fontWeight: 'bold'
- }
- }
- },
- loading: {
-
- labelStyle: {
- fontWeight: 'bold',
- position: RELATIVE,
- top: '1em'
- },
-
- style: {
- position: ABSOLUTE,
- backgroundColor: 'white',
- opacity: 0.5,
- textAlign: 'center'
- }
- },
- tooltip: {
- enabled: true,
- animation: hasSVG,
-
- backgroundColor: 'rgba(255, 255, 255, .85)',
- borderWidth: 1,
- borderRadius: 3,
- dateTimeLabelFormats: {
- millisecond: '%A, %b %e, %H:%M:%S.%L',
- second: '%A, %b %e, %H:%M:%S',
- minute: '%A, %b %e, %H:%M',
- hour: '%A, %b %e, %H:%M',
- day: '%A, %b %e, %Y',
- week: 'Week from %A, %b %e, %Y',
- month: '%B %Y',
- year: '%Y'
- },
-
- headerFormat: '<span style="font-size: 10px">{point.key}</span><br/>',
- pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b><br/>',
- shadow: true,
-
- snap: isTouchDevice ? 25 : 10,
- style: {
- color: '#333333',
- cursor: 'default',
- fontSize: '12px',
- padding: '8px',
- whiteSpace: 'nowrap'
- }
-
-
-
-
- },
- credits: {
- enabled: true,
- text: 'Highcharts.com',
- href: 'http://www.highcharts.com',
- position: {
- align: 'right',
- x: -10,
- verticalAlign: 'bottom',
- y: -5
- },
- style: {
- cursor: 'pointer',
- color: '#909090',
- fontSize: '9px'
- }
- }
- };
- var defaultPlotOptions = defaultOptions.plotOptions,
- defaultSeriesOptions = defaultPlotOptions.line;
- setTimeMethods();
- function setTimeMethods() {
- var useUTC = defaultOptions.global.useUTC,
- GET = useUTC ? 'getUTC' : 'get',
- SET = useUTC ? 'setUTC' : 'set';
- makeTime = useUTC ? Date.UTC : function (year, month, date, hours, minutes, seconds) {
- return new Date(
- year,
- month,
- pick(date, 1),
- pick(hours, 0),
- pick(minutes, 0),
- pick(seconds, 0)
- ).getTime();
- };
- getMinutes = GET + 'Minutes';
- getHours = GET + 'Hours';
- getDay = GET + 'Day';
- getDate = GET + 'Date';
- getMonth = GET + 'Month';
- getFullYear = GET + 'FullYear';
- setMinutes = SET + 'Minutes';
- setHours = SET + 'Hours';
- setDate = SET + 'Date';
- setMonth = SET + 'Month';
- setFullYear = SET + 'FullYear';
- }
- function setOptions(options) {
-
-
-
-
-
- defaultOptions = merge(defaultOptions, options);
-
-
- setTimeMethods();
- return defaultOptions;
- }
- function getOptions() {
- return defaultOptions;
- }
- var Color = function (input) {
-
- var rgba = [], result, stops;
-
- function init(input) {
-
- if (input && input.stops) {
- stops = map(input.stops, function (stop) {
- return Color(stop[1]);
- });
-
- } else {
-
- 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);
- if (result) {
- rgba = [pInt(result[1]), pInt(result[2]), pInt(result[3]), parseFloat(result[4], 10)];
- } else {
-
- result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(input);
- if (result) {
- rgba = [pInt(result[1], 16), pInt(result[2], 16), pInt(result[3], 16), 1];
- } else {
-
- result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(input);
- if (result) {
- rgba = [pInt(result[1]), pInt(result[2]), pInt(result[3]), 1];
- }
- }
- }
- }
- }
-
- function get(format) {
- var ret;
- if (stops) {
- ret = merge(input);
- ret.stops = [].concat(ret.stops);
- each(stops, function (stop, i) {
- ret.stops[i] = [ret.stops[i][0], stop.get(format)];
- });
-
- } else if (rgba && !isNaN(rgba[0])) {
- if (format === 'rgb') {
- ret = 'rgb(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ')';
- } else if (format === 'a') {
- ret = rgba[3];
- } else {
- ret = 'rgba(' + rgba.join(',') + ')';
- }
- } else {
- ret = input;
- }
- return ret;
- }
-
- function brighten(alpha) {
- if (stops) {
- each(stops, function (stop) {
- stop.brighten(alpha);
- });
-
- } else if (isNumber(alpha) && alpha !== 0) {
- var i;
- for (i = 0; i < 3; i++) {
- rgba[i] += pInt(alpha * 255);
- if (rgba[i] < 0) {
- rgba[i] = 0;
- }
- if (rgba[i] > 255) {
- rgba[i] = 255;
- }
- }
- }
- return this;
- }
-
- function setOpacity(alpha) {
- rgba[3] = alpha;
- return this;
- }
-
- init(input);
-
- return {
- get: get,
- brighten: brighten,
- rgba: rgba,
- setOpacity: setOpacity
- };
- };
- /**
- * A wrapper object for SVG elements
- */
- function SVGElement() {}
- SVGElement.prototype = {
-
- init: function (renderer, nodeName) {
- var wrapper = this;
- wrapper.element = nodeName === 'span' ?
- createElement(nodeName) :
- doc.createElementNS(SVG_NS, nodeName);
- wrapper.renderer = renderer;
-
- wrapper.attrSetters = {};
- },
-
- opacity: 1,
-
- animate: function (params, options, complete) {
- var animOptions = pick(options, globalAnimation, true);
- stop(this);
- if (animOptions) {
- animOptions = merge(animOptions);
- if (complete) {
- animOptions.complete = complete;
- }
- animate(this, params, animOptions);
- } else {
- this.attr(params);
- if (complete) {
- complete();
- }
- }
- },
-
- attr: function (hash, val) {
- var wrapper = this,
- key,
- value,
- result,
- i,
- child,
- element = wrapper.element,
- nodeName = element.nodeName.toLowerCase(),
- renderer = wrapper.renderer,
- skipAttr,
- titleNode,
- attrSetters = wrapper.attrSetters,
- shadows = wrapper.shadows,
- hasSetSymbolSize,
- doTransform,
- ret = wrapper;
-
- if (isString(hash) && defined(val)) {
- key = hash;
- hash = {};
- hash[key] = val;
- }
-
- if (isString(hash)) {
- key = hash;
- if (nodeName === 'circle') {
- key = { x: 'cx', y: 'cy' }[key] || key;
- } else if (key === 'strokeWidth') {
- key = 'stroke-width';
- }
- ret = attr(element, key) || wrapper[key] || 0;
- if (key !== 'd' && key !== 'visibility' && key !== 'fill') {
- ret = parseFloat(ret);
- }
-
- } else {
- for (key in hash) {
- skipAttr = false;
- value = hash[key];
-
- result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
- if (result !== false) {
- if (result !== UNDEFINED) {
- value = result;
- }
-
- if (key === 'd') {
- if (value && value.join) {
- value = value.join(' ');
- }
- if (/(NaN| {2}|^$)/.test(value)) {
- value = 'M 0 0';
- }
-
-
- } else if (key === 'x' && nodeName === 'text') {
- for (i = 0; i < element.childNodes.length; i++) {
- child = element.childNodes[i];
-
- if (attr(child, 'x') === attr(element, 'x')) {
-
- attr(child, 'x', value);
- }
- }
- } else if (wrapper.rotation && (key === 'x' || key === 'y')) {
- doTransform = true;
-
- } else if (key === 'fill') {
- value = renderer.color(value, element, key);
-
- } else if (nodeName === 'circle' && (key === 'x' || key === 'y')) {
- key = { x: 'cx', y: 'cy' }[key] || key;
-
- } else if (nodeName === 'rect' && key === 'r') {
- attr(element, {
- rx: value,
- ry: value
- });
- skipAttr = true;
-
- } else if (key === 'translateX' || key === 'translateY' || key === 'rotation' ||
- key === 'verticalAlign' || key === 'scaleX' || key === 'scaleY') {
- doTransform = true;
- skipAttr = true;
-
- } else if (key === 'stroke') {
- value = renderer.color(value, element, key);
-
- } else if (key === 'dashstyle') {
- key = 'stroke-dasharray';
- value = value && value.toLowerCase();
- if (value === 'solid') {
- value = NONE;
- } else if (value) {
- value = value
- .replace('shortdashdotdot', '3,1,1,1,1,1,')
- .replace('shortdashdot', '3,1,1,1')
- .replace('shortdot', '1,1,')
- .replace('shortdash', '3,1,')
- .replace('longdash', '8,3,')
- .replace(/dot/g, '1,3,')
- .replace('dash', '4,3,')
- .replace(/,$/, '')
- .split(',');
- i = value.length;
- while (i--) {
- value[i] = pInt(value[i]) * pick(hash['stroke-width'], wrapper['stroke-width']);
- }
- value = value.join(',');
- }
-
-
- } else if (key === 'width') {
- value = pInt(value);
-
- } else if (key === 'align') {
- key = 'text-anchor';
- value = { left: 'start', center: 'middle', right: 'end' }[value];
-
- } else if (key === 'title') {
- titleNode = element.getElementsByTagName('title')[0];
- if (!titleNode) {
- titleNode = doc.createElementNS(SVG_NS, 'title');
- element.appendChild(titleNode);
- }
- titleNode.textContent = value;
- }
-
- if (key === 'strokeWidth') {
- key = 'stroke-width';
- }
-
-
- if (key === 'stroke-width' || key === 'stroke') {
- wrapper[key] = value;
-
- if (wrapper.stroke && wrapper['stroke-width']) {
- attr(element, 'stroke', wrapper.stroke);
- attr(element, 'stroke-width', wrapper['stroke-width']);
- wrapper.hasStroke = true;
- } else if (key === 'stroke-width' && value === 0 && wrapper.hasStroke) {
- element.removeAttribute('stroke');
- wrapper.hasStroke = false;
- }
- skipAttr = true;
- }
-
- if (wrapper.symbolName && /^(x|y|width|height|r|start|end|innerR|anchorX|anchorY)/.test(key)) {
- if (!hasSetSymbolSize) {
- wrapper.symbolAttr(hash);
- hasSetSymbolSize = true;
- }
- skipAttr = true;
- }
-
- if (shadows && /^(width|height|visibility|x|y|d|transform|cx|cy|r)$/.test(key)) {
- i = shadows.length;
- while (i--) {
- attr(
- shadows[i],
- key,
- key === 'height' ?
- mathMax(value - (shadows[i].cutHeight || 0), 0) :
- value
- );
- }
- }
-
- if ((key === 'width' || key === 'height') && nodeName === 'rect' && value < 0) {
- value = 0;
- }
-
- wrapper[key] = value;
- if (key === 'text') {
-
- if (value !== wrapper.textStr) {
- delete wrapper.bBox;
- }
- wrapper.textStr = value;
- if (wrapper.added) {
- renderer.buildText(wrapper);
- }
- } else if (!skipAttr) {
- attr(element, key, value);
- }
- }
- }
-
-
- if (doTransform) {
- wrapper.updateTransform();
- }
- }
- return ret;
- },
-
- addClass: function (className) {
- var element = this.element,
- currentClassName = attr(element, 'class') || '';
- if (currentClassName.indexOf(className) === -1) {
- attr(element, 'class', currentClassName + ' ' + className);
- }
- return this;
- },
-
-
- symbolAttr: function (hash) {
- var wrapper = this;
- each(['x', 'y', 'r', 'start', 'end', 'width', 'height', 'innerR', 'anchorX', 'anchorY'], function (key) {
- wrapper[key] = pick(hash[key], wrapper[key]);
- });
- wrapper.attr({
- d: wrapper.renderer.symbols[wrapper.symbolName](
- wrapper.x,
- wrapper.y,
- wrapper.width,
- wrapper.height,
- wrapper
- )
- });
- },
-
- clip: function (clipRect) {
- return this.attr('clip-path', clipRect ? 'url(' + this.renderer.url + '#' + clipRect.id + ')' : NONE);
- },
-
- crisp: function (strokeWidth, x, y, width, height) {
- var wrapper = this,
- key,
- attribs = {},
- values = {},
- normalizer;
- strokeWidth = strokeWidth || wrapper.strokeWidth || (wrapper.attr && wrapper.attr('stroke-width')) || 0;
- normalizer = mathRound(strokeWidth) % 2 / 2;
-
- values.x = mathFloor(x || wrapper.x || 0) + normalizer;
- values.y = mathFloor(y || wrapper.y || 0) + normalizer;
- values.width = mathFloor((width || wrapper.width || 0) - 2 * normalizer);
- values.height = mathFloor((height || wrapper.height || 0) - 2 * normalizer);
- values.strokeWidth = strokeWidth;
- for (key in values) {
- if (wrapper[key] !== values[key]) {
- wrapper[key] = attribs[key] = values[key];
- }
- }
- return attribs;
- },
-
- css: function (styles) {
-
- var elemWrapper = this,
- elem = elemWrapper.element,
- textWidth = styles && styles.width && elem.nodeName.toLowerCase() === 'text',
- n,
- serializedCss = '',
- hyphenate = function (a, b) { return '-' + b.toLowerCase(); };
-
-
- if (styles && styles.color) {
- styles.fill = styles.color;
- }
-
- styles = extend(
- elemWrapper.styles,
- styles
- );
-
- elemWrapper.styles = styles;
-
- if (useCanVG && textWidth) {
- delete styles.width;
- }
-
- if (isIE && !hasSVG) {
- if (textWidth) {
- delete styles.width;
- }
- css(elemWrapper.element, styles);
- } else {
- for (n in styles) {
- serializedCss += n.replace(/([A-Z])/g, hyphenate) + ':' + styles[n] + ';';
- }
- attr(elem, 'style', serializedCss);
- }
-
- if (textWidth && elemWrapper.added) {
- elemWrapper.renderer.buildText(elemWrapper);
- }
- return elemWrapper;
- },
-
- on: function (eventType, handler) {
- var svgElement = this,
- element = svgElement.element;
-
-
- if (hasTouch && eventType === 'click') {
- element.ontouchstart = function (e) {
- svgElement.touchEventFired = Date.now();
- e.preventDefault();
- handler.call(element, e);
- };
- element.onclick = function (e) {
- if (userAgent.indexOf('Android') === -1 || Date.now() - (svgElement.touchEventFired || 0) > 1100) {
- handler.call(element, e);
- }
- };
- } else {
-
- element['on' + eventType] = handler;
- }
- return this;
- },
-
- setRadialReference: function (coordinates) {
- this.element.radialReference = coordinates;
- return this;
- },
-
- translate: function (x, y) {
- return this.attr({
- translateX: x,
- translateY: y
- });
- },
-
- invert: function () {
- var wrapper = this;
- wrapper.inverted = true;
- wrapper.updateTransform();
- return wrapper;
- },
-
- htmlCss: function (styles) {
- var wrapper = this,
- element = wrapper.element,
- textWidth = styles && element.tagName === 'SPAN' && styles.width;
- if (textWidth) {
- delete styles.width;
- wrapper.textWidth = textWidth;
- wrapper.updateTransform();
- }
- wrapper.styles = extend(wrapper.styles, styles);
- css(wrapper.element, styles);
- return wrapper;
- },
-
- htmlGetBBox: function () {
- var wrapper = this,
- element = wrapper.element,
- bBox = wrapper.bBox;
-
- if (!bBox) {
-
- if (element.nodeName === 'text') {
- element.style.position = ABSOLUTE;
- }
- bBox = wrapper.bBox = {
- x: element.offsetLeft,
- y: element.offsetTop,
- width: element.offsetWidth,
- height: element.offsetHeight
- };
- }
- return bBox;
- },
-
- htmlUpdateTransform: function () {
-
- if (!this.added) {
- this.alignOnAdd = true;
- return;
- }
- var wrapper = this,
- renderer = wrapper.renderer,
- elem = wrapper.element,
- translateX = wrapper.translateX || 0,
- translateY = wrapper.translateY || 0,
- x = wrapper.x || 0,
- y = wrapper.y || 0,
- align = wrapper.textAlign || 'left',
- alignCorrection = { left: 0, center: 0.5, right: 1 }[align],
- nonLeft = align && align !== 'left',
- shadows = wrapper.shadows;
-
- css(elem, {
- marginLeft: translateX,
- marginTop: translateY
- });
- if (shadows) {
- each(shadows, function (shadow) {
- css(shadow, {
- marginLeft: translateX + 1,
- marginTop: translateY + 1
- });
- });
- }
-
- if (wrapper.inverted) {
- each(elem.childNodes, function (child) {
- renderer.invertChild(child, elem);
- });
- }
- if (elem.tagName === 'SPAN') {
- var width, height,
- rotation = wrapper.rotation,
- baseline,
- radians = 0,
- costheta = 1,
- sintheta = 0,
- quad,
- textWidth = pInt(wrapper.textWidth),
- xCorr = wrapper.xCorr || 0,
- yCorr = wrapper.yCorr || 0,
- currentTextTransform = [rotation, align, elem.innerHTML, wrapper.textWidth].join(',');
- if (currentTextTransform !== wrapper.cTT) {
- if (defined(rotation)) {
- radians = rotation * deg2rad;
- costheta = mathCos(radians);
- sintheta = mathSin(radians);
- wrapper.setSpanRotation(rotation, sintheta, costheta);
- }
- width = pick(wrapper.elemWidth, elem.offsetWidth);
- height = pick(wrapper.elemHeight, elem.offsetHeight);
-
- if (width > textWidth && /[ \-]/.test(elem.textContent || elem.innerText)) {
- css(elem, {
- width: textWidth + PX,
- display: 'block',
- whiteSpace: 'normal'
- });
- width = textWidth;
- }
-
- baseline = renderer.fontMetrics(elem.style.fontSize).b;
- xCorr = costheta < 0 && -width;
- yCorr = sintheta < 0 && -height;
-
- quad = costheta * sintheta < 0;
- xCorr += sintheta * baseline * (quad ? 1 - alignCorrection : alignCorrection);
- yCorr -= costheta * baseline * (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1);
-
- if (nonLeft) {
- xCorr -= width * alignCorrection * (costheta < 0 ? -1 : 1);
- if (rotation) {
- yCorr -= height * alignCorrection * (sintheta < 0 ? -1 : 1);
- }
- css(elem, {
- textAlign: align
- });
- }
-
- wrapper.xCorr = xCorr;
- wrapper.yCorr = yCorr;
- }
-
- css(elem, {
- left: (x + xCorr) + PX,
- top: (y + yCorr) + PX
- });
-
- if (isWebKit) {
- height = elem.offsetHeight;
- }
-
- wrapper.cTT = currentTextTransform;
- }
- },
-
- setSpanRotation: function (rotation) {
- var rotationStyle = {},
- cssTransformKey = isIE ? '-ms-transform' : isWebKit ? '-webkit-transform' : isFirefox ? 'MozTransform' : isOpera ? '-o-transform' : '';
- rotationStyle[cssTransformKey] = rotationStyle.transform = 'rotate(' + rotation + 'deg)';
- css(this.element, rotationStyle);
- },
-
- updateTransform: function () {
- var wrapper = this,
- translateX = wrapper.translateX || 0,
- translateY = wrapper.translateY || 0,
- scaleX = wrapper.scaleX,
- scaleY = wrapper.scaleY,
- inverted = wrapper.inverted,
- rotation = wrapper.rotation,
- transform;
-
- if (inverted) {
- translateX += wrapper.attr('width');
- translateY += wrapper.attr('height');
- }
-
-
- transform = ['translate(' + translateX + ',' + translateY + ')'];
-
- if (inverted) {
- transform.push('rotate(90) scale(-1,1)');
- } else if (rotation) {
- transform.push('rotate(' + rotation + ' ' + (wrapper.x || 0) + ' ' + (wrapper.y || 0) + ')');
- }
-
- if (defined(scaleX) || defined(scaleY)) {
- transform.push('scale(' + pick(scaleX, 1) + ' ' + pick(scaleY, 1) + ')');
- }
- if (transform.length) {
- attr(wrapper.element, 'transform', transform.join(' '));
- }
- },
-
- toFront: function () {
- var element = this.element;
- element.parentNode.appendChild(element);
- return this;
- },
-
- align: function (alignOptions, alignByTranslate, box) {
- var align,
- vAlign,
- x,
- y,
- attribs = {},
- alignTo,
- renderer = this.renderer,
- alignedObjects = renderer.alignedObjects;
-
- if (alignOptions) {
- this.alignOptions = alignOptions;
- this.alignByTranslate = alignByTranslate;
- if (!box || isString(box)) {
- this.alignTo = alignTo = box || 'renderer';
- erase(alignedObjects, this);
- alignedObjects.push(this);
- box = null;
- }
-
- } else {
- alignOptions = this.alignOptions;
- alignByTranslate = this.alignByTranslate;
- alignTo = this.alignTo;
- }
- box = pick(box, renderer[alignTo], renderer);
-
- align = alignOptions.align;
- vAlign = alignOptions.verticalAlign;
- x = (box.x || 0) + (alignOptions.x || 0);
- y = (box.y || 0) + (alignOptions.y || 0);
-
- if (align === 'right' || align === 'center') {
- x += (box.width - (alignOptions.width || 0)) /
- { right: 1, center: 2 }[align];
- }
- attribs[alignByTranslate ? 'translateX' : 'x'] = mathRound(x);
-
- if (vAlign === 'bottom' || vAlign === 'middle') {
- y += (box.height - (alignOptions.height || 0)) /
- ({ bottom: 1, middle: 2 }[vAlign] || 1);
- }
- attribs[alignByTranslate ? 'translateY' : 'y'] = mathRound(y);
-
- this[this.placed ? 'animate' : 'attr'](attribs);
- this.placed = true;
- this.alignAttr = attribs;
- return this;
- },
-
- getBBox: function () {
- var wrapper = this,
- bBox = wrapper.bBox,
- renderer = wrapper.renderer,
- width,
- height,
- rotation = wrapper.rotation,
- element = wrapper.element,
- styles = wrapper.styles,
- rad = rotation * deg2rad;
- if (!bBox) {
-
- if (element.namespaceURI === SVG_NS || renderer.forExport) {
- try {
- bBox = element.getBBox ?
-
-
- extend({}, element.getBBox()) :
-
- {
- width: element.offsetWidth,
- height: element.offsetHeight
- };
- } catch (e) {}
-
-
- if (!bBox || bBox.width < 0) {
- bBox = { width: 0, height: 0 };
- }
-
- } else {
- bBox = wrapper.htmlGetBBox();
- }
-
-
- if (renderer.isSVG) {
- width = bBox.width;
- height = bBox.height;
-
- if (isIE && styles && styles.fontSize === '11px' && height.toPrecision(3) === '22.7') {
- bBox.height = height = 14;
- }
-
- if (rotation) {
- bBox.width = mathAbs(height * mathSin(rad)) + mathAbs(width * mathCos(rad));
- bBox.height = mathAbs(height * mathCos(rad)) + mathAbs(width * mathSin(rad));
- }
- }
- wrapper.bBox = bBox;
- }
- return bBox;
- },
-
- show: function () {
- return this.attr({ visibility: VISIBLE });
- },
-
- hide: function () {
- return this.attr({ visibility: HIDDEN });
- },
- fadeOut: function (duration) {
- var elemWrapper = this;
- elemWrapper.animate({
- opacity: 0
- }, {
- duration: duration || 150,
- complete: function () {
- elemWrapper.hide();
- }
- });
- },
-
- add: function (parent) {
- var renderer = this.renderer,
- parentWrapper = parent || renderer,
- parentNode = parentWrapper.element || renderer.box,
- childNodes = parentNode.childNodes,
- element = this.element,
- zIndex = attr(element, 'zIndex'),
- otherElement,
- otherZIndex,
- i,
- inserted;
- if (parent) {
- this.parentGroup = parent;
- }
-
- this.parentInverted = parent && parent.inverted;
-
- if (this.textStr !== undefined) {
- renderer.buildText(this);
- }
-
- if (zIndex) {
- parentWrapper.handleZ = true;
- zIndex = pInt(zIndex);
- }
-
- if (parentWrapper.handleZ) {
- for (i = 0; i < childNodes.length; i++) {
- otherElement = childNodes[i];
- otherZIndex = attr(otherElement, 'zIndex');
- if (otherElement !== element && (
-
- pInt(otherZIndex) > zIndex ||
-
- (!defined(zIndex) && defined(otherZIndex))
- )) {
- parentNode.insertBefore(element, otherElement);
- inserted = true;
- break;
- }
- }
- }
-
- if (!inserted) {
- parentNode.appendChild(element);
- }
-
- this.added = true;
-
- fireEvent(this, 'add');
- return this;
- },
-
- safeRemoveChild: function (element) {
- var parentNode = element.parentNode;
- if (parentNode) {
- parentNode.removeChild(element);
- }
- },
-
- destroy: function () {
- var wrapper = this,
- element = wrapper.element || {},
- shadows = wrapper.shadows,
- parentToClean = wrapper.renderer.isSVG && element.nodeName === 'SPAN' && element.parentNode,
- grandParent,
- key,
- i;
-
- element.onclick = element.onmouseout = element.onmouseover = element.onmousemove = element.point = null;
- stop(wrapper);
- if (wrapper.clipPath) {
- wrapper.clipPath = wrapper.clipPath.destroy();
- }
-
- if (wrapper.stops) {
- for (i = 0; i < wrapper.stops.length; i++) {
- wrapper.stops[i] = wrapper.stops[i].destroy();
- }
- wrapper.stops = null;
- }
-
- wrapper.safeRemoveChild(element);
-
- if (shadows) {
- each(shadows, function (shadow) {
- wrapper.safeRemoveChild(shadow);
- });
- }
-
- while (parentToClean && parentToClean.childNodes.length === 0) {
- grandParent = parentToClean.parentNode;
- wrapper.safeRemoveChild(parentToClean);
- parentToClean = grandParent;
- }
-
- if (wrapper.alignTo) {
- erase(wrapper.renderer.alignedObjects, wrapper);
- }
- for (key in wrapper) {
- delete wrapper[key];
- }
- return null;
- },
-
- shadow: function (shadowOptions, group, cutOff) {
- var shadows = [],
- i,
- shadow,
- element = this.element,
- strokeWidth,
- shadowWidth,
- shadowElementOpacity,
-
- transform;
- if (shadowOptions) {
- shadowWidth = pick(shadowOptions.width, 3);
- shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth;
- transform = this.parentInverted ?
- '(-1,-1)' :
- '(' + pick(shadowOptions.offsetX, 1) + ', ' + pick(shadowOptions.offsetY, 1) + ')';
- for (i = 1; i <= shadowWidth; i++) {
- shadow = element.cloneNode(0);
- strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
- attr(shadow, {
- 'isShadow': 'true',
- 'stroke': shadowOptions.color || 'black',
- 'stroke-opacity': shadowElementOpacity * i,
- 'stroke-width': strokeWidth,
- 'transform': 'translate' + transform,
- 'fill': NONE
- });
- if (cutOff) {
- attr(shadow, 'height', mathMax(attr(shadow, 'height') - strokeWidth, 0));
- shadow.cutHeight = strokeWidth;
- }
- if (group) {
- group.element.appendChild(shadow);
- } else {
- element.parentNode.insertBefore(shadow, element);
- }
- shadows.push(shadow);
- }
- this.shadows = shadows;
- }
- return this;
- }
- };
- var SVGRenderer = function () {
- this.init.apply(this, arguments);
- };
- SVGRenderer.prototype = {
- Element: SVGElement,
-
- init: function (container, width, height, forExport) {
- var renderer = this,
- loc = location,
- boxWrapper,
- element,
- desc;
- boxWrapper = renderer.createElement('svg')
- .attr({
- version: '1.1'
- });
- element = boxWrapper.element;
- container.appendChild(element);
-
- if (container.innerHTML.indexOf('xmlns') === -1) {
- attr(element, 'xmlns', SVG_NS);
- }
-
- renderer.isSVG = true;
- renderer.box = element;
- renderer.boxWrapper = boxWrapper;
- renderer.alignedObjects = [];
-
- renderer.url = (isFirefox || isWebKit) && doc.getElementsByTagName('base').length ?
- loc.href
- .replace(/#.*?$/, '')
- .replace(/([\('\)])/g, '\\$1')
- .replace(/ /g, '%20') :
- '';
-
- desc = this.createElement('desc').add();
- desc.element.appendChild(doc.createTextNode('Created with ' + PRODUCT + ' ' + VERSION));
- renderer.defs = this.createElement('defs').add();
- renderer.forExport = forExport;
- renderer.gradients = {};
- renderer.setSize(width, height, false);
-
-
-
-
-
-
- var subPixelFix, rect;
- if (isFirefox && container.getBoundingClientRect) {
- renderer.subPixelFix = subPixelFix = function () {
- css(container, { left: 0, top: 0 });
- rect = container.getBoundingClientRect();
- css(container, {
- left: (mathCeil(rect.left) - rect.left) + PX,
- top: (mathCeil(rect.top) - rect.top) + PX
- });
- };
-
- subPixelFix();
-
- addEvent(win, 'resize', subPixelFix);
- }
- },
-
- isHidden: function () {
- return !this.boxWrapper.getBBox().width;
- },
-
- destroy: function () {
- var renderer = this,
- rendererDefs = renderer.defs;
- renderer.box = null;
- renderer.boxWrapper = renderer.boxWrapper.destroy();
-
- destroyObjectProperties(renderer.gradients || {});
- renderer.gradients = null;
-
-
- if (rendererDefs) {
- renderer.defs = rendererDefs.destroy();
- }
-
-
-
- if (renderer.subPixelFix) {
- removeEvent(win, 'resize', renderer.subPixelFix);
- }
- renderer.alignedObjects = null;
- return null;
- },
-
- createElement: function (nodeName) {
- var wrapper = new this.Element();
- wrapper.init(this, nodeName);
- return wrapper;
- },
-
- draw: function () {},
-
- buildText: function (wrapper) {
- var textNode = wrapper.element,
- renderer = this,
- forExport = renderer.forExport,
- lines = pick(wrapper.textStr, '').toString()
- .replace(/<(b|strong)>/g, '<span style="font-weight:bold">')
- .replace(/<(i|em)>/g, '<span style="font-style:italic">')
- .replace(/<a/g, '<span')
- .replace(/<\/(b|strong|i|em|a)>/g, '</span>')
- .split(/<br.*?>/g),
- childNodes = textNode.childNodes,
- styleRegex = /style="([^"]+)"/,
- hrefRegex = /href="(http[^"]+)"/,
- parentX = attr(textNode, 'x'),
- textStyles = wrapper.styles,
- width = textStyles && textStyles.width && pInt(textStyles.width),
- textLineHeight = textStyles && textStyles.lineHeight,
- i = childNodes.length;
-
- while (i--) {
- textNode.removeChild(childNodes[i]);
- }
- if (width && !wrapper.added) {
- this.box.appendChild(textNode);
- }
-
- if (lines[lines.length - 1] === '') {
- lines.pop();
- }
-
- each(lines, function (line, lineNo) {
- var spans, spanNo = 0;
- line = line.replace(/<span/g, '|||<span').replace(/<\/span>/g, '</span>|||');
- spans = line.split('|||');
- each(spans, function (span) {
- if (span !== '' || spans.length === 1) {
- var attributes = {},
- tspan = doc.createElementNS(SVG_NS, 'tspan'),
- spanStyle;
- if (styleRegex.test(span)) {
- spanStyle = span.match(styleRegex)[1].replace(/(;| |^)color([ :])/, '$1fill$2');
- attr(tspan, 'style', spanStyle);
- }
- if (hrefRegex.test(span) && !forExport) {
- attr(tspan, 'onclick', 'location.href=\"' + span.match(hrefRegex)[1] + '\"');
- css(tspan, { cursor: 'pointer' });
- }
- span = (span.replace(/<(.|\n)*?>/g, '') || ' ')
- .replace(/</g, '<')
- .replace(/>/g, '>');
-
- if (span !== ' ') {
-
- tspan.appendChild(doc.createTextNode(span));
- if (!spanNo) {
- attributes.x = parentX;
- } else {
- attributes.dx = 0;
- }
-
- attr(tspan, attributes);
-
- if (!spanNo && lineNo) {
-
- if (!hasSVG && forExport) {
- css(tspan, { display: 'block' });
- }
-
-
- attr(
- tspan,
- 'dy',
- textLineHeight || renderer.fontMetrics(
- /px$/.test(tspan.style.fontSize) ?
- tspan.style.fontSize :
- textStyles.fontSize
- ).h,
-
-
- isWebKit && tspan.offsetHeight
- );
- }
-
- textNode.appendChild(tspan);
- spanNo++;
-
- if (width) {
- var words = span.replace(/([^\^])-/g, '$1- ').split(' '),
- tooLong,
- actualWidth,
- clipHeight = wrapper._clipHeight,
- rest = [],
- dy = pInt(textLineHeight || 16),
- softLineNo = 1,
- bBox;
- while (words.length || rest.length) {
- delete wrapper.bBox;
- bBox = wrapper.getBBox();
- actualWidth = bBox.width;
- tooLong = actualWidth > width;
- if (!tooLong || words.length === 1) {
- words = rest;
- rest = [];
- if (words.length) {
- softLineNo++;
- if (clipHeight && softLineNo * dy > clipHeight) {
- words = ['...'];
- wrapper.attr('title', wrapper.textStr);
- } else {
- tspan = doc.createElementNS(SVG_NS, 'tspan');
- attr(tspan, {
- dy: dy,
- x: parentX
- });
- if (spanStyle) {
- attr(tspan, 'style', spanStyle);
- }
- textNode.appendChild(tspan);
- if (actualWidth > width) {
- width = actualWidth;
- }
- }
- }
- } else {
- tspan.removeChild(tspan.firstChild);
- rest.unshift(words.pop());
- }
- if (words.length) {
- tspan.appendChild(doc.createTextNode(words.join(' ').replace(/- /g, '-')));
- }
- }
- }
- }
- }
- });
- });
- },
-
- button: function (text, x, y, callback, normalState, hoverState, pressedState, disabledState) {
- var label = this.label(text, x, y, null, null, null, null, null, 'button'),
- curState = 0,
- stateOptions,
- stateStyle,
- normalStyle,
- hoverStyle,
- pressedStyle,
- disabledStyle,
- STYLE = 'style',
- verticalGradient = { x1: 0, y1: 0, x2: 0, y2: 1 };
-
- normalState = merge({
- 'stroke-width': 1,
- stroke: '#CCCCCC',
- fill: {
- linearGradient: verticalGradient,
- stops: [
- [0, '#FEFEFE'],
- [1, '#F6F6F6']
- ]
- },
- r: 2,
- padding: 5,
- style: {
- color: 'black'
- }
- }, normalState);
- normalStyle = normalState[STYLE];
- delete normalState[STYLE];
-
- hoverState = merge(normalState, {
- stroke: '#68A',
- fill: {
- linearGradient: verticalGradient,
- stops: [
- [0, '#FFF'],
- [1, '#ACF']
- ]
- }
- }, hoverState);
- hoverStyle = hoverState[STYLE];
- delete hoverState[STYLE];
-
- pressedState = merge(normalState, {
- stroke: '#68A',
- fill: {
- linearGradient: verticalGradient,
- stops: [
- [0, '#9BD'],
- [1, '#CDF']
- ]
- }
- }, pressedState);
- pressedStyle = pressedState[STYLE];
- delete pressedState[STYLE];
-
- disabledState = merge(normalState, {
- style: {
- color: '#CCC'
- }
- }, disabledState);
- disabledStyle = disabledState[STYLE];
- delete disabledState[STYLE];
-
- addEvent(label.element, isIE ? 'mouseover' : 'mouseenter', function () {
- if (curState !== 3) {
- label.attr(hoverState)
- .css(hoverStyle);
- }
- });
- addEvent(label.element, isIE ? 'mouseout' : 'mouseleave', function () {
- if (curState !== 3) {
- stateOptions = [normalState, hoverState, pressedState][curState];
- stateStyle = [normalStyle, hoverStyle, pressedStyle][curState];
- label.attr(stateOptions)
- .css(stateStyle);
- }
- });
- label.setState = function (state) {
- label.state = curState = state;
- if (!state) {
- label.attr(normalState)
- .css(normalStyle);
- } else if (state === 2) {
- label.attr(pressedState)
- .css(pressedStyle);
- } else if (state === 3) {
- label.attr(disabledState)
- .css(disabledStyle);
- }
- };
- return label
- .on('click', function () {
- if (curState !== 3) {
- callback.call(label);
- }
- })
- .attr(normalState)
- .css(extend({ cursor: 'default' }, normalStyle));
- },
-
- crispLine: function (points, width) {
-
-
- if (points[1] === points[4]) {
-
- points[1] = points[4] = mathRound(points[1]) - (width % 2 / 2);
- }
- if (points[2] === points[5]) {
- points[2] = points[5] = mathRound(points[2]) + (width % 2 / 2);
- }
- return points;
- },
-
- path: function (path) {
- var attr = {
- fill: NONE
- };
- if (isArray(path)) {
- attr.d = path;
- } else if (isObject(path)) {
- extend(attr, path);
- }
- return this.createElement('path').attr(attr);
- },
-
- circle: function (x, y, r) {
- var attr = isObject(x) ?
- x :
- {
- x: x,
- y: y,
- r: r
- };
- return this.createElement('circle').attr(attr);
- },
-
- arc: function (x, y, r, innerR, start, end) {
- var arc;
- if (isObject(x)) {
- y = x.y;
- r = x.r;
- innerR = x.innerR;
- start = x.start;
- end = x.end;
- x = x.x;
- }
-
-
- arc = this.symbol('arc', x || 0, y || 0, r || 0, r || 0, {
- innerR: innerR || 0,
- start: start || 0,
- end: end || 0
- });
- arc.r = r;
- return arc;
- },
-
- rect: function (x, y, width, height, r, strokeWidth) {
- r = isObject(x) ? x.r : r;
- var wrapper = this.createElement('rect').attr({
- rx: r,
- ry: r,
- fill: NONE
- });
- return wrapper.attr(
- isObject(x) ?
- x :
-
- wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0))
- );
- },
-
- setSize: function (width, height, animate) {
- var renderer = this,
- alignedObjects = renderer.alignedObjects,
- i = alignedObjects.length;
- renderer.width = width;
- renderer.height = height;
- renderer.boxWrapper[pick(animate, true) ? 'animate' : 'attr']({
- width: width,
- height: height
- });
- while (i--) {
- alignedObjects[i].align();
- }
- },
-
- g: function (name) {
- var elem = this.createElement('g');
- return defined(name) ? elem.attr({ 'class': PREFIX + name }) : elem;
- },
-
- image: function (src, x, y, width, height) {
- var attribs = {
- preserveAspectRatio: NONE
- },
- elemWrapper;
-
- if (arguments.length > 1) {
- extend(attribs, {
- x: x,
- y: y,
- width: width,
- height: height
- });
- }
- elemWrapper = this.createElement('image').attr(attribs);
-
- if (elemWrapper.element.setAttributeNS) {
- elemWrapper.element.setAttributeNS('http://www.w3.org/1999/xlink',
- 'href', src);
- } else {
-
-
- elemWrapper.element.setAttribute('hc-svg-href', src);
- }
- return elemWrapper;
- },
-
- symbol: function (symbol, x, y, width, height, options) {
- var obj,
-
- symbolFn = this.symbols[symbol],
-
- path = symbolFn && symbolFn(
- mathRound(x),
- mathRound(y),
- width,
- height,
- options
- ),
- imageElement,
- imageRegex = /^url\((.*?)\)$/,
- imageSrc,
- imageSize,
- centerImage;
- if (path) {
- obj = this.path(path);
-
- extend(obj, {
- symbolName: symbol,
- x: x,
- y: y,
- width: width,
- height: height
- });
- if (options) {
- extend(obj, options);
- }
-
- } else if (imageRegex.test(symbol)) {
-
- centerImage = function (img, size) {
- if (img.element) {
- img.attr({
- width: size[0],
- height: size[1]
- });
- if (!img.alignByTranslate) {
- img.translate(
- mathRound((width - size[0]) / 2),
- mathRound((height - size[1]) / 2)
- );
- }
- }
- };
- imageSrc = symbol.match(imageRegex)[1];
- imageSize = symbolSizes[imageSrc];
-
- obj = this.image(imageSrc)
- .attr({
- x: x,
- y: y
- });
- obj.isImg = true;
- if (imageSize) {
- centerImage(obj, imageSize);
- } else {
-
-
- obj.attr({ width: 0, height: 0 });
-
-
- imageElement = createElement('img', {
- onload: function () {
- centerImage(obj, symbolSizes[imageSrc] = [this.width, this.height]);
- },
- src: imageSrc
- });
- }
- }
- return obj;
- },
-
- symbols: {
- 'circle': function (x, y, w, h) {
- var cpw = 0.166 * w;
- return [
- M, x + w / 2, y,
- 'C', x + w + cpw, y, x + w + cpw, y + h, x + w / 2, y + h,
- 'C', x - cpw, y + h, x - cpw, y, x + w / 2, y,
- 'Z'
- ];
- },
- 'square': function (x, y, w, h) {
- return [
- M, x, y,
- L, x + w, y,
- x + w, y + h,
- x, y + h,
- 'Z'
- ];
- },
- 'triangle': function (x, y, w, h) {
- return [
- M, x + w / 2, y,
- L, x + w, y + h,
- x, y + h,
- 'Z'
- ];
- },
- 'triangle-down': function (x, y, w, h) {
- return [
- M, x, y,
- L, x + w, y,
- x + w / 2, y + h,
- 'Z'
- ];
- },
- 'diamond': function (x, y, w, h) {
- return [
- M, x + w / 2, y,
- L, x + w, y + h / 2,
- x + w / 2, y + h,
- x, y + h / 2,
- 'Z'
- ];
- },
- 'arc': function (x, y, w, h, options) {
- var start = options.start,
- radius = options.r || w || h,
- end = options.end - 0.001,
- innerRadius = options.innerR,
- open = options.open,
- cosStart = mathCos(start),
- sinStart = mathSin(start),
- cosEnd = mathCos(end),
- sinEnd = mathSin(end),
- longArc = options.end - start < mathPI ? 0 : 1;
- return [
- M,
- x + radius * cosStart,
- y + radius * sinStart,
- 'A',
- radius,
- radius,
- 0,
- longArc,
- 1,
- x + radius * cosEnd,
- y + radius * sinEnd,
- open ? M : L,
- x + innerRadius * cosEnd,
- y + innerRadius * sinEnd,
- 'A',
- innerRadius,
- innerRadius,
- 0,
- longArc,
- 0,
- x + innerRadius * cosStart,
- y + innerRadius * sinStart,
- open ? '' : 'Z'
- ];
- }
- },
-
- clipRect: function (x, y, width, height) {
- var wrapper,
- id = PREFIX + idCounter++,
- clipPath = this.createElement('clipPath').attr({
- id: id
- }).add(this.defs);
- wrapper = this.rect(x, y, width, height, 0).add(clipPath);
- wrapper.id = id;
- wrapper.clipPath = clipPath;
- return wrapper;
- },
-
- color: function (color, elem, prop) {
- var renderer = this,
- colorObject,
- regexRgba = /^rgba/,
- gradName,
- gradAttr,
- gradients,
- gradientObject,
- stops,
- stopColor,
- stopOpacity,
- radialReference,
- n,
- id,
- key = [];
-
- if (color && color.linearGradient) {
- gradName = 'linearGradient';
- } else if (color && color.radialGradient) {
- gradName = 'radialGradient';
- }
- if (gradName) {
- gradAttr = color[gradName];
- gradients = renderer.gradients;
- stops = color.stops;
- radialReference = elem.radialReference;
-
- if (isArray(gradAttr)) {
- color[gradName] = gradAttr = {
- x1: gradAttr[0],
- y1: gradAttr[1],
- x2: gradAttr[2],
- y2: gradAttr[3],
- gradientUnits: 'userSpaceOnUse'
- };
- }
-
- if (gradName === 'radialGradient' && radialReference && !defined(gradAttr.gradientUnits)) {
- gradAttr = merge(gradAttr, {
- cx: (radialReference[0] - radialReference[2] / 2) + gradAttr.cx * radialReference[2],
- cy: (radialReference[1] - radialReference[2] / 2) + gradAttr.cy * radialReference[2],
- r: gradAttr.r * radialReference[2],
- gradientUnits: 'userSpaceOnUse'
- });
- }
-
- for (n in gradAttr) {
- if (n !== 'id') {
- key.push(n, gradAttr[n]);
- }
- }
- for (n in stops) {
- key.push(stops[n]);
- }
- key = key.join(',');
-
- if (gradients[key]) {
- id = gradients[key].id;
- } else {
-
- gradAttr.id = id = PREFIX + idCounter++;
- gradients[key] = gradientObject = renderer.createElement(gradName)
- .attr(gradAttr)
- .add(renderer.defs);
-
- gradientObject.stops = [];
- each(stops, function (stop) {
- var stopObject;
- if (regexRgba.test(stop[1])) {
- colorObject = Color(stop[1]);
- stopColor = colorObject.get('rgb');
- stopOpacity = colorObject.get('a');
- } else {
- stopColor = stop[1];
- stopOpacity = 1;
- }
- stopObject = renderer.createElement('stop').attr({
- offset: stop[0],
- 'stop-color': stopColor,
- 'stop-opacity': stopOpacity
- }).add(gradientObject);
-
- gradientObject.stops.push(stopObject);
- });
- }
-
- return 'url(' + renderer.url + '#' + id + ')';
-
- } else if (regexRgba.test(color)) {
- colorObject = Color(color);
- attr(elem, prop + '-opacity', colorObject.get('a'));
- return colorObject.get('rgb');
- } else {
-
- elem.removeAttribute(prop + '-opacity');
- return color;
- }
- },
-
- text: function (str, x, y, useHTML) {
-
- var renderer = this,
- defaultChartStyle = defaultOptions.chart.style,
- fakeSVG = useCanVG || (!hasSVG && renderer.forExport),
- wrapper;
- if (useHTML && !renderer.forExport) {
- return renderer.html(str, x, y);
- }
- x = mathRound(pick(x, 0));
- y = mathRound(pick(y, 0));
- wrapper = renderer.createElement('text')
- .attr({
- x: x,
- y: y,
- text: str
- })
- .css({
- fontFamily: defaultChartStyle.fontFamily,
- fontSize: defaultChartStyle.fontSize
- });
-
- if (fakeSVG) {
- wrapper.css({
- position: ABSOLUTE
- });
- }
- wrapper.x = x;
- wrapper.y = y;
- return wrapper;
- },
-
- html: function (str, x, y) {
- var defaultChartStyle = defaultOptions.chart.style,
- wrapper = this.createElement('span'),
- attrSetters = wrapper.attrSetters,
- element = wrapper.element,
- renderer = wrapper.renderer;
-
- attrSetters.text = function (value) {
- if (value !== element.innerHTML) {
- delete this.bBox;
- }
- element.innerHTML = value;
- return false;
- };
-
- attrSetters.x = attrSetters.y = attrSetters.align = function (value, key) {
- if (key === 'align') {
- key = 'textAlign';
- }
- wrapper[key] = value;
- wrapper.htmlUpdateTransform();
- return false;
- };
-
- wrapper.attr({
- text: str,
- x: mathRound(x),
- y: mathRound(y)
- })
- .css({
- position: ABSOLUTE,
- whiteSpace: 'nowrap',
- fontFamily: defaultChartStyle.fontFamily,
- fontSize: defaultChartStyle.fontSize
- });
-
- wrapper.css = wrapper.htmlCss;
-
- if (renderer.isSVG) {
- wrapper.add = function (svgGroupWrapper) {
- var htmlGroup,
- container = renderer.box.parentNode,
- parentGroup,
- parents = [];
-
- if (svgGroupWrapper) {
- htmlGroup = svgGroupWrapper.div;
- if (!htmlGroup) {
-
- parentGroup = svgGroupWrapper;
- while (parentGroup) {
- parents.push(parentGroup);
-
- parentGroup = parentGroup.parentGroup;
- }
-
- each(parents.reverse(), function (parentGroup) {
- var htmlGroupStyle;
-
-
- htmlGroup = parentGroup.div = parentGroup.div || createElement(DIV, {
- className: attr(parentGroup.element, 'class')
- }, {
- position: ABSOLUTE,
- left: (parentGroup.translateX || 0) + PX,
- top: (parentGroup.translateY || 0) + PX
- }, htmlGroup || container);
-
- htmlGroupStyle = htmlGroup.style;
-
-
- extend(parentGroup.attrSetters, {
- translateX: function (value) {
- htmlGroupStyle.left = value + PX;
- },
- translateY: function (value) {
- htmlGroupStyle.top = value + PX;
- },
- visibility: function (value, key) {
- htmlGroupStyle[key] = value;
- }
- });
- });
- }
- } else {
- htmlGroup = container;
- }
- htmlGroup.appendChild(element);
-
- wrapper.added = true;
- if (wrapper.alignOnAdd) {
- wrapper.htmlUpdateTransform();
- }
- return wrapper;
- };
- }
- return wrapper;
- },
-
- fontMetrics: function (fontSize) {
- fontSize = pInt(fontSize || 11);
-
-
- var lineHeight = fontSize < 24 ? fontSize + 4 : mathRound(fontSize * 1.2),
- baseline = mathRound(lineHeight * 0.8);
- return {
- h: lineHeight,
- b: baseline
- };
- },
-
- label: function (str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) {
- var renderer = this,
- wrapper = renderer.g(className),
- text = renderer.text('', 0, 0, useHTML)
- .attr({
- zIndex: 1
- }),
-
- box,
- bBox,
- alignFactor = 0,
- padding = 3,
- paddingLeft = 0,
- width,
- height,
- wrapperX,
- wrapperY,
- crispAdjust = 0,
- deferredAttr = {},
- baselineOffset,
- attrSetters = wrapper.attrSetters,
- needsBox;
-
- function updateBoxSize() {
- var boxX,
- boxY,
- style = text.element.style;
- bBox = (width === undefined || height === undefined || wrapper.styles.textAlign) &&
- text.getBBox();
- wrapper.width = (width || bBox.width || 0) + 2 * padding + paddingLeft;
- wrapper.height = (height || bBox.height || 0) + 2 * padding;
-
- baselineOffset = padding + renderer.fontMetrics(style && style.fontSize).b;
- if (needsBox) {
-
- if (!box) {
- boxX = mathRound(-alignFactor * padding);
- boxY = baseline ? -baselineOffset : 0;
- wrapper.box = box = shape ?
- renderer.symbol(shape, boxX, boxY, wrapper.width, wrapper.height) :
- renderer.rect(boxX, boxY, wrapper.width, wrapper.height, 0, deferredAttr[STROKE_WIDTH]);
- box.add(wrapper);
- }
-
- if (!box.isImg) {
- box.attr(merge({
- width: wrapper.width,
- height: wrapper.height
- }, deferredAttr));
- }
- deferredAttr = null;
- }
- }
-
- function updateTextPadding() {
- var styles = wrapper.styles,
- textAlign = styles && styles.textAlign,
- x = paddingLeft + padding * (1 - alignFactor),
- y;
-
- y = baseline ? 0 : baselineOffset;
-
- if (defined(width) && (textAlign === 'center' || textAlign === 'right')) {
- x += { center: 0.5, right: 1 }[textAlign] * (width - bBox.width);
- }
-
- if (x !== text.x || y !== text.y) {
- text.attr({
- x: x,
- y: y
- });
- }
-
- text.x = x;
- text.y = y;
- }
-
- function boxAttr(key, value) {
- if (box) {
- box.attr(key, value);
- } else {
- deferredAttr[key] = value;
- }
- }
- function getSizeAfterAdd() {
- text.add(wrapper);
- wrapper.attr({
- text: str,
- x: x,
- y: y
- });
- if (box && defined(anchorX)) {
- wrapper.attr({
- anchorX: anchorX,
- anchorY: anchorY
- });
- }
- }
-
- addEvent(wrapper, 'add', getSizeAfterAdd);
-
-
- attrSetters.width = function (value) {
- width = value;
- return false;
- };
- attrSetters.height = function (value) {
- height = value;
- return false;
- };
- attrSetters.padding = function (value) {
- if (defined(value) && value !== padding) {
- padding = value;
- updateTextPadding();
- }
- return false;
- };
- attrSetters.paddingLeft = function (value) {
- if (defined(value) && value !== paddingLeft) {
- paddingLeft = value;
- updateTextPadding();
- }
- return false;
- };
-
- attrSetters.align = function (value) {
- alignFactor = { left: 0, center: 0.5, right: 1 }[value];
- return false;
- };
-
- attrSetters.text = function (value, key) {
- text.attr(key, value);
- updateBoxSize();
- updateTextPadding();
- return false;
- };
-
- attrSetters[STROKE_WIDTH] = function (value, key) {
- needsBox = true;
- crispAdjust = value % 2 / 2;
- boxAttr(key, value);
- return false;
- };
- attrSetters.stroke = attrSetters.fill = attrSetters.r = function (value, key) {
- if (key === 'fill') {
- needsBox = true;
- }
- boxAttr(key, value);
- return false;
- };
- attrSetters.anchorX = function (value, key) {
- anchorX = value;
- boxAttr(key, value + crispAdjust - wrapperX);
- return false;
- };
- attrSetters.anchorY = function (value, key) {
- anchorY = value;
- boxAttr(key, value - wrapperY);
- return false;
- };
-
- attrSetters.x = function (value) {
- wrapper.x = value;
- value -= alignFactor * ((width || bBox.width) + padding);
- wrapperX = mathRound(value);
- wrapper.attr('translateX', wrapperX);
- return false;
- };
- attrSetters.y = function (value) {
- wrapperY = wrapper.y = mathRound(value);
- wrapper.attr('translateY', wrapperY);
- return false;
- };
-
- var baseCss = wrapper.css;
- return extend(wrapper, {
-
- css: function (styles) {
- if (styles) {
- var textStyles = {};
- styles = merge(styles);
- each(['fontSize', 'fontWeight', 'fontFamily', 'color', 'lineHeight', 'width', 'textDecoration', 'textShadow'], function (prop) {
- if (styles[prop] !== UNDEFINED) {
- textStyles[prop] = styles[prop];
- delete styles[prop];
- }
- });
- text.css(textStyles);
- }
- return baseCss.call(wrapper, styles);
- },
-
- getBBox: function () {
- return {
- width: bBox.width + 2 * padding,
- height: bBox.height + 2 * padding,
- x: bBox.x - padding,
- y: bBox.y - padding
- };
- },
-
- shadow: function (b) {
- if (box) {
- box.shadow(b);
- }
- return wrapper;
- },
-
- destroy: function () {
- removeEvent(wrapper, 'add', getSizeAfterAdd);
-
- removeEvent(wrapper.element, 'mouseenter');
- removeEvent(wrapper.element, 'mouseleave');
- if (text) {
- text = text.destroy();
- }
- if (box) {
- box = box.destroy();
- }
-
- SVGElement.prototype.destroy.call(wrapper);
-
- wrapper = renderer = updateBoxSize = updateTextPadding = boxAttr = getSizeAfterAdd = null;
- }
- });
- }
- };
- Renderer = SVGRenderer;
- var VMLRenderer, VMLElement;
- if (!hasSVG && !useCanVG) {
- Highcharts.VMLElement = VMLElement = {
-
- init: function (renderer, nodeName) {
- var wrapper = this,
- markup = ['<', nodeName, ' filled="f" stroked="f"'],
- style = ['position: ', ABSOLUTE, ';'],
- isDiv = nodeName === DIV;
-
- if (nodeName === 'shape' || isDiv) {
- style.push('left:0;top:0;width:1px;height:1px;');
- }
- style.push('visibility: ', isDiv ? HIDDEN : VISIBLE);
- markup.push(' style="', style.join(''), '"/>');
-
- if (nodeName) {
- markup = isDiv || nodeName === 'span' || nodeName === 'img' ?
- markup.join('')
- : renderer.prepVML(markup);
- wrapper.element = createElement(markup);
- }
- wrapper.renderer = renderer;
- wrapper.attrSetters = {};
- },
-
- add: function (parent) {
- var wrapper = this,
- renderer = wrapper.renderer,
- element = wrapper.element,
- box = renderer.box,
- inverted = parent && parent.inverted,
-
- parentNode = parent ?
- parent.element || parent :
- box;
-
- if (inverted) {
- renderer.invertChild(element, parentNode);
- }
-
- parentNode.appendChild(element);
-
- wrapper.added = true;
- if (wrapper.alignOnAdd && !wrapper.deferUpdateTransform) {
- wrapper.updateTransform();
- }
-
- fireEvent(wrapper, 'add');
- return wrapper;
- },
-
- updateTransform: SVGElement.prototype.htmlUpdateTransform,
-
- setSpanRotation: function (rotation, sintheta, costheta) {
-
-
-
-
-
- css(this.element, {
- filter: rotation ? ['progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
- ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
- ', sizingMethod=\'auto expand\')'].join('') : NONE
- });
- },
-
- pathToVML: function (value) {
-
- var i = value.length,
- path = [],
- clockwise;
- while (i--) {
-
-
-
- if (isNumber(value[i])) {
- path[i] = mathRound(value[i] * 10) - 5;
- } else if (value[i] === 'Z') {
- path[i] = 'x';
- } else {
- path[i] = value[i];
-
-
-
- if (value.isArc && (value[i] === 'wa' || value[i] === 'at')) {
- clockwise = value[i] === 'wa' ? 1 : -1;
- if (path[i + 5] === path[i + 7]) {
- path[i + 7] -= clockwise;
- }
-
- if (path[i + 6] === path[i + 8]) {
- path[i + 8] -= clockwise;
- }
- }
- }
- }
-
-
- return path.join(' ') || 'x';
- },
-
- attr: function (hash, val) {
- var wrapper = this,
- key,
- value,
- i,
- result,
- element = wrapper.element || {},
- elemStyle = element.style,
- nodeName = element.nodeName,
- renderer = wrapper.renderer,
- symbolName = wrapper.symbolName,
- hasSetSymbolSize,
- shadows = wrapper.shadows,
- skipAttr,
- attrSetters = wrapper.attrSetters,
- ret = wrapper;
-
- if (isString(hash) && defined(val)) {
- key = hash;
- hash = {};
- hash[key] = val;
- }
-
- if (isString(hash)) {
- key = hash;
- if (key === 'strokeWidth' || key === 'stroke-width') {
- ret = wrapper.strokeweight;
- } else {
- ret = wrapper[key];
- }
-
- } else {
- for (key in hash) {
- value = hash[key];
- skipAttr = false;
-
- result = attrSetters[key] && attrSetters[key].call(wrapper, value, key);
- if (result !== false && value !== null) {
- if (result !== UNDEFINED) {
- value = result;
- }
-
-
- if (symbolName && /^(x|y|r|start|end|width|height|innerR|anchorX|anchorY)/.test(key)) {
-
-
-
- if (!hasSetSymbolSize) {
- wrapper.symbolAttr(hash);
- hasSetSymbolSize = true;
- }
- skipAttr = true;
- } else if (key === 'd') {
- value = value || [];
- wrapper.d = value.join(' ');
- element.path = value = wrapper.pathToVML(value);
-
- if (shadows) {
- i = shadows.length;
- while (i--) {
- shadows[i].path = shadows[i].cutOff ? this.cutOffPath(value, shadows[i].cutOff) : value;
- }
- }
- skipAttr = true;
-
- } else if (key === 'visibility') {
-
- if (shadows) {
- i = shadows.length;
- while (i--) {
- shadows[i].style[key] = value;
- }
- }
-
-
- if (nodeName === 'DIV') {
- value = value === HIDDEN ? '-999em' : 0;
-
-
-
- if (!docMode8) {
- elemStyle[key] = value ? VISIBLE : HIDDEN;
- }
- key = 'top';
- }
- elemStyle[key] = value;
- skipAttr = true;
-
- } else if (key === 'zIndex') {
- if (value) {
- elemStyle[key] = value;
- }
- skipAttr = true;
-
- } else if (inArray(key, ['x', 'y', 'width', 'height']) !== -1) {
- wrapper[key] = value;
- if (key === 'x' || key === 'y') {
- key = { x: 'left', y: 'top' }[key];
- } else {
- value = mathMax(0, value);
- }
-
- if (wrapper.updateClipping) {
- wrapper[key] = value;
- wrapper.updateClipping();
- } else {
-
- elemStyle[key] = value;
- }
- skipAttr = true;
-
- } else if (key === 'class' && nodeName === 'DIV') {
-
- element.className = value;
-
- } else if (key === 'stroke') {
- value = renderer.color(value, element, key);
- key = 'strokecolor';
-
- } else if (key === 'stroke-width' || key === 'strokeWidth') {
- element.stroked = value ? true : false;
- key = 'strokeweight';
- wrapper[key] = value;
- if (isNumber(value)) {
- value += PX;
- }
-
- } else if (key === 'dashstyle') {
- var strokeElem = element.getElementsByTagName('stroke')[0] ||
- createElement(renderer.prepVML(['<stroke/>']), null, null, element);
- strokeElem[key] = value || 'solid';
- wrapper.dashstyle = value;
- skipAttr = true;
-
- } else if (key === 'fill') {
- if (nodeName === 'SPAN') {
- elemStyle.color = value;
- } else if (nodeName !== 'IMG') {
- element.filled = value !== NONE ? true : false;
- value = renderer.color(value, element, key, wrapper);
- key = 'fillcolor';
- }
-
- } else if (key === 'opacity') {
-
- skipAttr = true;
-
- } else if (nodeName === 'shape' && key === 'rotation') {
- wrapper[key] = element.style[key] = value;
-
- element.style.left = -mathRound(mathSin(value * deg2rad) + 1) + PX;
- element.style.top = mathRound(mathCos(value * deg2rad)) + PX;
-
- } else if (key === 'translateX' || key === 'translateY' || key === 'rotation') {
- wrapper[key] = value;
- wrapper.updateTransform();
- skipAttr = true;
-
- } else if (key === 'text') {
- this.bBox = null;
- element.innerHTML = value;
- skipAttr = true;
- }
- if (!skipAttr) {
- if (docMode8) {
- element[key] = value;
- } else {
- attr(element, key, value);
- }
- }
- }
- }
- }
- return ret;
- },
-
- clip: function (clipRect) {
- var wrapper = this,
- clipMembers,
- cssRet;
- if (clipRect) {
- clipMembers = clipRect.members;
- erase(clipMembers, wrapper);
- clipMembers.push(wrapper);
- wrapper.destroyClip = function () {
- erase(clipMembers, wrapper);
- };
- cssRet = clipRect.getCSS(wrapper);
- } else {
- if (wrapper.destroyClip) {
- wrapper.destroyClip();
- }
- cssRet = { clip: docMode8 ? 'inherit' : 'rect(auto)' };
- }
- return wrapper.css(cssRet);
- },
-
- css: SVGElement.prototype.htmlCss,
-
- safeRemoveChild: function (element) {
-
-
- if (element.parentNode) {
- discardElement(element);
- }
- },
-
- destroy: function () {
- if (this.destroyClip) {
- this.destroyClip();
- }
- return SVGElement.prototype.destroy.apply(this);
- },
-
- on: function (eventType, handler) {
-
- this.element['on' + eventType] = function () {
- var evt = win.event;
- evt.target = evt.srcElement;
- handler(evt);
- };
- return this;
- },
-
- cutOffPath: function (path, length) {
- var len;
- path = path.split(/[ ,]/);
- len = path.length;
- if (len === 9 || len === 11) {
- path[len - 4] = path[len - 2] = pInt(path[len - 2]) - 10 * length;
- }
- return path.join(' ');
- },
-
- shadow: function (shadowOptions, group, cutOff) {
- var shadows = [],
- i,
- element = this.element,
- renderer = this.renderer,
- shadow,
- elemStyle = element.style,
- markup,
- path = element.path,
- strokeWidth,
- modifiedPath,
- shadowWidth,
- shadowElementOpacity;
-
- if (path && typeof path.value !== 'string') {
- path = 'x';
- }
- modifiedPath = path;
- if (shadowOptions) {
- shadowWidth = pick(shadowOptions.width, 3);
- shadowElementOpacity = (shadowOptions.opacity || 0.15) / shadowWidth;
- for (i = 1; i <= 3; i++) {
- strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
-
- if (cutOff) {
- modifiedPath = this.cutOffPath(path.value, strokeWidth + 0.5);
- }
- markup = ['<shape isShadow="true" strokeweight="', strokeWidth,
- '" filled="false" path="', modifiedPath,
- '" coordsize="10 10" style="', element.style.cssText, '" />'];
- shadow = createElement(renderer.prepVML(markup),
- null, {
- left: pInt(elemStyle.left) + pick(shadowOptions.offsetX, 1),
- top: pInt(elemStyle.top) + pick(shadowOptions.offsetY, 1)
- }
- );
- if (cutOff) {
- shadow.cutOff = strokeWidth + 1;
- }
-
- markup = ['<stroke color="', shadowOptions.color || 'black', '" opacity="', shadowElementOpacity * i, '"/>'];
- createElement(renderer.prepVML(markup), null, null, shadow);
-
- if (group) {
- group.element.appendChild(shadow);
- } else {
- element.parentNode.insertBefore(shadow, element);
- }
-
- shadows.push(shadow);
- }
- this.shadows = shadows;
- }
- return this;
- }
- };
- VMLElement = extendClass(SVGElement, VMLElement);
- var VMLRendererExtension = {
- Element: VMLElement,
- isIE8: userAgent.indexOf('MSIE 8.0') > -1,
-
- init: function (container, width, height) {
- var renderer = this,
- boxWrapper,
- box;
- renderer.alignedObjects = [];
- boxWrapper = renderer.createElement(DIV);
- box = boxWrapper.element;
- box.style.position = RELATIVE;
- container.appendChild(boxWrapper.element);
-
- renderer.isVML = true;
- renderer.box = box;
- renderer.boxWrapper = boxWrapper;
- renderer.setSize(width, height, false);
-
-
-
- if (!doc.namespaces.hcv) {
- doc.namespaces.add('hcv', 'urn:schemas-microsoft-com:vml');
-
- (doc.styleSheets.length ? doc.styleSheets[0] : doc.createStyleSheet()).cssText +=
- 'hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke' +
- '{ behavior:url(#default#VML); display: inline-block; } ';
- }
- },
-
- isHidden: function () {
- return !this.box.offsetWidth;
- },
-
- clipRect: function (x, y, width, height) {
-
- var clipRect = this.createElement(),
- isObj = isObject(x);
-
- return extend(clipRect, {
- members: [],
- left: (isObj ? x.x : x) + 1,
- top: (isObj ? x.y : y) + 1,
- width: (isObj ? x.width : width) - 1,
- height: (isObj ? x.height : height) - 1,
- getCSS: function (wrapper) {
- var element = wrapper.element,
- nodeName = element.nodeName,
- isShape = nodeName === 'shape',
- inverted = wrapper.inverted,
- rect = this,
- top = rect.top - (isShape ? element.offsetTop : 0),
- left = rect.left,
- right = left + rect.width,
- bottom = top + rect.height,
- ret = {
- clip: 'rect(' +
- mathRound(inverted ? left : top) + 'px,' +
- mathRound(inverted ? bottom : right) + 'px,' +
- mathRound(inverted ? right : bottom) + 'px,' +
- mathRound(inverted ? top : left) + 'px)'
- };
-
- if (!inverted && docMode8 && nodeName === 'DIV') {
- extend(ret, {
- width: right + PX,
- height: bottom + PX
- });
- }
- return ret;
- },
-
- updateClipping: function () {
- each(clipRect.members, function (member) {
- member.css(clipRect.getCSS(member));
- });
- }
- });
- },
-
- color: function (color, elem, prop, wrapper) {
- var renderer = this,
- colorObject,
- regexRgba = /^rgba/,
- markup,
- fillType,
- ret = NONE;
-
- if (color && color.linearGradient) {
- fillType = 'gradient';
- } else if (color && color.radialGradient) {
- fillType = 'pattern';
- }
- if (fillType) {
- var stopColor,
- stopOpacity,
- gradient = color.linearGradient || color.radialGradient,
- x1,
- y1,
- x2,
- y2,
- opacity1,
- opacity2,
- color1,
- color2,
- fillAttr = '',
- stops = color.stops,
- firstStop,
- lastStop,
- colors = [],
- addFillNode = function () {
-
-
- markup = ['<fill colors="' + colors.join(',') + '" opacity="', opacity2, '" o:opacity2="', opacity1,
- '" type="', fillType, '" ', fillAttr, 'focus="100%" method="any" />'];
- createElement(renderer.prepVML(markup), null, null, elem);
- };
-
- firstStop = stops[0];
- lastStop = stops[stops.length - 1];
- if (firstStop[0] > 0) {
- stops.unshift([
- 0,
- firstStop[1]
- ]);
- }
- if (lastStop[0] < 1) {
- stops.push([
- 1,
- lastStop[1]
- ]);
- }
-
- each(stops, function (stop, i) {
- if (regexRgba.test(stop[1])) {
- colorObject = Color(stop[1]);
- stopColor = colorObject.get('rgb');
- stopOpacity = colorObject.get('a');
- } else {
- stopColor = stop[1];
- stopOpacity = 1;
- }
-
- colors.push((stop[0] * 100) + '% ' + stopColor);
-
- if (!i) {
- opacity1 = stopOpacity;
- color2 = stopColor;
- } else {
- opacity2 = stopOpacity;
- color1 = stopColor;
- }
- });
-
- if (prop === 'fill') {
-
- if (fillType === 'gradient') {
- x1 = gradient.x1 || gradient[0] || 0;
- y1 = gradient.y1 || gradient[1] || 0;
- x2 = gradient.x2 || gradient[2] || 0;
- y2 = gradient.y2 || gradient[3] || 0;
- fillAttr = 'angle="' + (90 - math.atan(
- (y2 - y1) /
- (x2 - x1)
- ) * 180 / mathPI) + '"';
- addFillNode();
-
- } else {
- var r = gradient.r,
- sizex = r * 2,
- sizey = r * 2,
- cx = gradient.cx,
- cy = gradient.cy,
- radialReference = elem.radialReference,
- bBox,
- applyRadialGradient = function () {
- if (radialReference) {
- bBox = wrapper.getBBox();
- cx += (radialReference[0] - bBox.x) / bBox.width - 0.5;
- cy += (radialReference[1] - bBox.y) / bBox.height - 0.5;
- sizex *= radialReference[2] / bBox.width;
- sizey *= radialReference[2] / bBox.height;
- }
- fillAttr = 'src="' + defaultOptions.global.VMLRadialGradientURL + '" ' +
- 'size="' + sizex + ',' + sizey + '" ' +
- 'origin="0.5,0.5" ' +
- 'position="' + cx + ',' + cy + '" ' +
- 'color2="' + color2 + '" ';
- addFillNode();
- };
-
- if (wrapper.added) {
- applyRadialGradient();
- } else {
-
- addEvent(wrapper, 'add', applyRadialGradient);
- }
-
-
- ret = color1;
- }
-
- } else {
- ret = stopColor;
- }
-
-
- } else if (regexRgba.test(color) && elem.tagName !== 'IMG') {
- colorObject = Color(color);
- markup = ['<', prop, ' opacity="', colorObject.get('a'), '"/>'];
- createElement(this.prepVML(markup), null, null, elem);
- ret = colorObject.get('rgb');
- } else {
- var propNodes = elem.getElementsByTagName(prop);
- if (propNodes.length) {
- propNodes[0].opacity = 1;
- propNodes[0].type = 'solid';
- }
- ret = color;
- }
- return ret;
- },
-
- prepVML: function (markup) {
- var vmlStyle = 'display:inline-block;behavior:url(#default#VML);',
- isIE8 = this.isIE8;
- markup = markup.join('');
- if (isIE8) {
- markup = markup.replace('/>', ' xmlns="urn:schemas-microsoft-com:vml" />');
- if (markup.indexOf('style="') === -1) {
- markup = markup.replace('/>', ' style="' + vmlStyle + '" />');
- } else {
- markup = markup.replace('style="', 'style="' + vmlStyle);
- }
- } else {
- markup = markup.replace('<', '<hcv:');
- }
- return markup;
- },
-
- text: SVGRenderer.prototype.html,
-
- path: function (path) {
- var attr = {
-
- coordsize: '10 10'
- };
- if (isArray(path)) {
- attr.d = path;
- } else if (isObject(path)) {
- extend(attr, path);
- }
-
- return this.createElement('shape').attr(attr);
- },
-
- circle: function (x, y, r) {
- var circle = this.symbol('circle');
- if (isObject(x)) {
- r = x.r;
- y = x.y;
- x = x.x;
- }
- circle.isCircle = true;
- circle.r = r;
- return circle.attr({ x: x, y: y });
- },
-
- g: function (name) {
- var wrapper,
- attribs;
-
- if (name) {
- attribs = { 'className': PREFIX + name, 'class': PREFIX + name };
- }
-
- wrapper = this.createElement(DIV).attr(attribs);
- return wrapper;
- },
-
- image: function (src, x, y, width, height) {
- var obj = this.createElement('img')
- .attr({ src: src });
- if (arguments.length > 1) {
- obj.attr({
- x: x,
- y: y,
- width: width,
- height: height
- });
- }
- return obj;
- },
-
- rect: function (x, y, width, height, r, strokeWidth) {
- var wrapper = this.symbol('rect');
- wrapper.r = isObject(x) ? x.r : r;
-
- return wrapper.attr(
- isObject(x) ?
- x :
-
- wrapper.crisp(strokeWidth, x, y, mathMax(width, 0), mathMax(height, 0))
- );
- },
-
- invertChild: function (element, parentNode) {
- var parentStyle = parentNode.style;
- css(element, {
- flip: 'x',
- left: pInt(parentStyle.width) - 1,
- top: pInt(parentStyle.height) - 1,
- rotation: -90
- });
- },
-
- symbols: {
-
- arc: function (x, y, w, h, options) {
- var start = options.start,
- end = options.end,
- radius = options.r || w || h,
- innerRadius = options.innerR,
- cosStart = mathCos(start),
- sinStart = mathSin(start),
- cosEnd = mathCos(end),
- sinEnd = mathSin(end),
- ret;
- if (end - start === 0) {
- return ['x'];
- }
- ret = [
- 'wa',
- x - radius,
- y - radius,
- x + radius,
- y + radius,
- x + radius * cosStart,
- y + radius * sinStart,
- x + radius * cosEnd,
- y + radius * sinEnd
- ];
- if (options.open && !innerRadius) {
- ret.push(
- 'e',
- M,
- x,
- y
- );
- }
- ret.push(
- 'at',
- x - innerRadius,
- y - innerRadius,
- x + innerRadius,
- y + innerRadius,
- x + innerRadius * cosEnd,
- y + innerRadius * sinEnd,
- x + innerRadius * cosStart,
- y + innerRadius * sinStart,
- 'x',
- 'e'
- );
- ret.isArc = true;
- return ret;
- },
-
- circle: function (x, y, w, h, wrapper) {
- if (wrapper) {
- w = h = 2 * wrapper.r;
- }
-
- if (wrapper && wrapper.isCircle) {
- x -= w / 2;
- y -= h / 2;
- }
-
- return [
- 'wa',
- x,
- y,
- x + w,
- y + h,
- x + w,
- y + h / 2,
- x + w,
- y + h / 2,
-
- 'e'
- ];
- },
-
- rect: function (left, top, width, height, options) {
- var right = left + width,
- bottom = top + height,
- ret,
- r;
-
- if (!defined(options) || !options.r) {
- ret = SVGRenderer.prototype.symbols.square.apply(0, arguments);
-
- } else {
- r = mathMin(options.r, width, height);
- ret = [
- M,
- left + r, top,
- L,
- right - r, top,
- 'wa',
- right - 2 * r, top,
- right, top + 2 * r,
- right - r, top,
- right, top + r,
- L,
- right, bottom - r,
- 'wa',
- right - 2 * r, bottom - 2 * r,
- right, bottom,
- right, bottom - r,
- right - r, bottom,
- L,
- left + r, bottom,
- 'wa',
- left, bottom - 2 * r,
- left + 2 * r, bottom,
- left + r, bottom,
- left, bottom - r,
- L,
- left, top + r,
- 'wa',
- left, top,
- left + 2 * r, top + 2 * r,
- left, top + r,
- left + r, top,
- 'x',
- 'e'
- ];
- }
- return ret;
- }
- }
- };
- Highcharts.VMLRenderer = VMLRenderer = function () {
- this.init.apply(this, arguments);
- };
- VMLRenderer.prototype = merge(SVGRenderer.prototype, VMLRendererExtension);
-
- Renderer = VMLRenderer;
- }
- var CanVGRenderer,
- CanVGController;
- if (useCanVG) {
-
- Highcharts.CanVGRenderer = CanVGRenderer = function () {
-
- SVG_NS = 'http://www.w3.org/1999/xhtml';
- };
-
- CanVGRenderer.prototype.symbols = {};
-
- CanVGController = (function () {
-
- var deferredRenderCalls = [];
-
- function drawDeferred() {
- var callLength = deferredRenderCalls.length,
- callIndex;
-
- for (callIndex = 0; callIndex < callLength; callIndex++) {
- deferredRenderCalls[callIndex]();
- }
-
- deferredRenderCalls = [];
- }
- return {
- push: function (func, scriptLocation) {
-
- if (deferredRenderCalls.length === 0) {
- getScript(scriptLocation, drawDeferred);
- }
-
- deferredRenderCalls.push(func);
- }
- };
- }());
- Renderer = CanVGRenderer;
- }
- function Tick(axis, pos, type, noLabel) {
- this.axis = axis;
- this.pos = pos;
- this.type = type || '';
- this.isNew = true;
- if (!type && !noLabel) {
- this.addLabel();
- }
- }
- Tick.prototype = {
-
- addLabel: function () {
- var tick = this,
- axis = tick.axis,
- options = axis.options,
- chart = axis.chart,
- horiz = axis.horiz,
- categories = axis.categories,
- names = axis.series[0] && axis.series[0].names,
- pos = tick.pos,
- labelOptions = options.labels,
- str,
- tickPositions = axis.tickPositions,
- width = (horiz && categories &&
- !labelOptions.step && !labelOptions.staggerLines &&
- !labelOptions.rotation &&
- chart.plotWidth / tickPositions.length) ||
- (!horiz && (chart.margin[3] || chart.chartWidth * 0.33)),
- isFirst = pos === tickPositions[0],
- isLast = pos === tickPositions[tickPositions.length - 1],
- css,
- attr,
- value = categories ?
- pick(categories[pos], names && names[pos], pos) :
- pos,
- label = tick.label,
- tickPositionInfo = tickPositions.info,
- dateTimeLabelFormat;
-
-
- if (axis.isDatetimeAxis && tickPositionInfo) {
- dateTimeLabelFormat = options.dateTimeLabelFormats[tickPositionInfo.higherRanks[pos] || tickPositionInfo.unitName];
- }
-
- tick.isFirst = isFirst;
- tick.isLast = isLast;
-
- str = axis.labelFormatter.call({
- axis: axis,
- chart: chart,
- isFirst: isFirst,
- isLast: isLast,
- dateTimeLabelFormat: dateTimeLabelFormat,
- value: axis.isLog ? correctFloat(lin2log(value)) : value
- });
-
- css = width && { width: mathMax(1, mathRound(width - 2 * (labelOptions.padding || 10))) + PX };
- css = extend(css, labelOptions.style);
-
- if (!defined(label)) {
- attr = {
- align: axis.labelAlign
- };
- if (isNumber(labelOptions.rotation)) {
- attr.rotation = labelOptions.rotation;
- }
- if (width && labelOptions.ellipsis) {
- attr._clipHeight = axis.len / tickPositions.length;
- }
- tick.label =
- defined(str) && labelOptions.enabled ?
- chart.renderer.text(
- str,
- 0,
- 0,
- labelOptions.useHTML
- )
- .attr(attr)
-
- .css(css)
- .add(axis.labelGroup) :
- null;
-
- } else if (label) {
- label.attr({
- text: str
- })
- .css(css);
- }
- },
-
- getLabelSize: function () {
- var label = this.label,
- axis = this.axis;
- return label ?
- ((this.labelBBox = label.getBBox()))[axis.horiz ? 'height' : 'width'] :
- 0;
- },
-
- getLabelSides: function () {
- var bBox = this.labelBBox,
- axis = this.axis,
- options = axis.options,
- labelOptions = options.labels,
- width = bBox.width,
- leftSide = width * { left: 0, center: 0.5, right: 1 }[axis.labelAlign] - labelOptions.x;
- return [-leftSide, width - leftSide];
- },
-
- handleOverflow: function (index, xy) {
- var show = true,
- axis = this.axis,
- chart = axis.chart,
- isFirst = this.isFirst,
- isLast = this.isLast,
- x = xy.x,
- reversed = axis.reversed,
- tickPositions = axis.tickPositions;
- if (isFirst || isLast) {
- var sides = this.getLabelSides(),
- leftSide = sides[0],
- rightSide = sides[1],
- plotLeft = chart.plotLeft,
- plotRight = plotLeft + axis.len,
- neighbour = axis.ticks[tickPositions[index + (isFirst ? 1 : -1)]],
- neighbourEdge = neighbour && neighbour.label.xy && neighbour.label.xy.x + neighbour.getLabelSides()[isFirst ? 0 : 1];
- if ((isFirst && !reversed) || (isLast && reversed)) {
-
- if (x + leftSide < plotLeft) {
-
- x = plotLeft - leftSide;
-
- if (neighbour && x + rightSide > neighbourEdge) {
- show = false;
- }
- }
- } else {
-
- if (x + rightSide > plotRight) {
-
- x = plotRight - rightSide;
-
- if (neighbour && x + leftSide < neighbourEdge) {
- show = false;
- }
- }
- }
-
- xy.x = x;
- }
- return show;
- },
-
- getPosition: function (horiz, pos, tickmarkOffset, old) {
- var axis = this.axis,
- chart = axis.chart,
- cHeight = (old && chart.oldChartHeight) || chart.chartHeight;
-
- return {
- x: horiz ?
- axis.translate(pos + tickmarkOffset, null, null, old) + axis.transB :
- axis.left + axis.offset + (axis.opposite ? ((old && chart.oldChartWidth) || chart.chartWidth) - axis.right - axis.left : 0),
- y: horiz ?
- cHeight - axis.bottom + axis.offset - (axis.opposite ? axis.height : 0) :
- cHeight - axis.translate(pos + tickmarkOffset, null, null, old) - axis.transB
- };
-
- },
-
-
- getLabelPosition: function (x, y, label, horiz, labelOptions, tickmarkOffset, index, step) {
- var axis = this.axis,
- transA = axis.transA,
- reversed = axis.reversed,
- staggerLines = axis.staggerLines,
- baseline = axis.chart.renderer.fontMetrics(labelOptions.style.fontSize).b,
- rotation = labelOptions.rotation;
-
- x = x + labelOptions.x - (tickmarkOffset && horiz ?
- tickmarkOffset * transA * (reversed ? -1 : 1) : 0);
- y = y + labelOptions.y - (tickmarkOffset && !horiz ?
- tickmarkOffset * transA * (reversed ? 1 : -1) : 0);
-
- if (rotation && axis.side === 2) {
- y -= baseline - baseline * mathCos(rotation * deg2rad);
- }
-
-
- if (!defined(labelOptions.y) && !rotation) {
- y += baseline - label.getBBox().height / 2;
- }
-
-
- if (staggerLines) {
- y += (index / (step || 1) % staggerLines) * (axis.labelOffset / staggerLines);
- }
-
- return {
- x: x,
- y: y
- };
- },
-
-
- getMarkPath: function (x, y, tickLength, tickWidth, horiz, renderer) {
- return renderer.crispLine([
- M,
- x,
- y,
- L,
- x + (horiz ? 0 : -tickLength),
- y + (horiz ? tickLength : 0)
- ], tickWidth);
- },
-
- render: function (index, old, opacity) {
- var tick = this,
- axis = tick.axis,
- options = axis.options,
- chart = axis.chart,
- renderer = chart.renderer,
- horiz = axis.horiz,
- type = tick.type,
- label = tick.label,
- pos = tick.pos,
- labelOptions = options.labels,
- gridLine = tick.gridLine,
- gridPrefix = type ? type + 'Grid' : 'grid',
- tickPrefix = type ? type + 'Tick' : 'tick',
- gridLineWidth = options[gridPrefix + 'LineWidth'],
- gridLineColor = options[gridPrefix + 'LineColor'],
- dashStyle = options[gridPrefix + 'LineDashStyle'],
- tickLength = options[tickPrefix + 'Length'],
- tickWidth = options[tickPrefix + 'Width'] || 0,
- tickColor = options[tickPrefix + 'Color'],
- tickPosition = options[tickPrefix + 'Position'],
- gridLinePath,
- mark = tick.mark,
- markPath,
- step = labelOptions.step,
- attribs,
- show = true,
- tickmarkOffset = axis.tickmarkOffset,
- xy = tick.getPosition(horiz, pos, tickmarkOffset, old),
- x = xy.x,
- y = xy.y,
- reverseCrisp = ((horiz && x === axis.pos + axis.len) || (!horiz && y === axis.pos)) ? -1 : 1,
- staggerLines = axis.staggerLines;
- this.isActive = true;
-
-
- if (gridLineWidth) {
- gridLinePath = axis.getPlotLinePath(pos + tickmarkOffset, gridLineWidth * reverseCrisp, old, true);
- if (gridLine === UNDEFINED) {
- attribs = {
- stroke: gridLineColor,
- 'stroke-width': gridLineWidth
- };
- if (dashStyle) {
- attribs.dashstyle = dashStyle;
- }
- if (!type) {
- attribs.zIndex = 1;
- }
- if (old) {
- attribs.opacity = 0;
- }
- tick.gridLine = gridLine =
- gridLineWidth ?
- renderer.path(gridLinePath)
- .attr(attribs).add(axis.gridGroup) :
- null;
- }
-
-
- if (!old && gridLine && gridLinePath) {
- gridLine[tick.isNew ? 'attr' : 'animate']({
- d: gridLinePath,
- opacity: opacity
- });
- }
- }
-
- if (tickWidth && tickLength) {
-
- if (tickPosition === 'inside') {
- tickLength = -tickLength;
- }
- if (axis.opposite) {
- tickLength = -tickLength;
- }
- markPath = tick.getMarkPath(x, y, tickLength, tickWidth * reverseCrisp, horiz, renderer);
- if (mark) {
- mark.animate({
- d: markPath,
- opacity: opacity
- });
- } else {
- tick.mark = renderer.path(
- markPath
- ).attr({
- stroke: tickColor,
- 'stroke-width': tickWidth,
- opacity: opacity
- }).add(axis.axisGroup);
- }
- }
-
- if (label && !isNaN(x)) {
- label.xy = xy = tick.getLabelPosition(x, y, label, horiz, labelOptions, tickmarkOffset, index, step);
-
-
- if ((tick.isFirst && !tick.isLast && !pick(options.showFirstLabel, 1)) ||
- (tick.isLast && !tick.isFirst && !pick(options.showLastLabel, 1))) {
- show = false;
-
- } else if (!staggerLines && horiz && labelOptions.overflow === 'justify' && !tick.handleOverflow(index, xy)) {
- show = false;
- }
-
- if (step && index % step) {
-
- show = false;
- }
-
- if (show && !isNaN(xy.y)) {
- xy.opacity = opacity;
- label[tick.isNew ? 'attr' : 'animate'](xy);
- tick.isNew = false;
- } else {
- label.attr('y', -9999);
- }
- }
- },
-
- destroy: function () {
- destroyObjectProperties(this, this.axis);
- }
- };
- function PlotLineOrBand(axis, options) {
- this.axis = axis;
- if (options) {
- this.options = options;
- this.id = options.id;
- }
- }
- PlotLineOrBand.prototype = {
-
-
- render: function () {
- var plotLine = this,
- axis = plotLine.axis,
- horiz = axis.horiz,
- halfPointRange = (axis.pointRange || 0) / 2,
- options = plotLine.options,
- optionsLabel = options.label,
- label = plotLine.label,
- width = options.width,
- to = options.to,
- from = options.from,
- isBand = defined(from) && defined(to),
- value = options.value,
- dashStyle = options.dashStyle,
- svgElem = plotLine.svgElem,
- path = [],
- addEvent,
- eventType,
- xs,
- ys,
- x,
- y,
- color = options.color,
- zIndex = options.zIndex,
- events = options.events,
- attribs,
- renderer = axis.chart.renderer;
-
- if (axis.isLog) {
- from = log2lin(from);
- to = log2lin(to);
- value = log2lin(value);
- }
-
- if (width) {
- path = axis.getPlotLinePath(value, width);
- attribs = {
- stroke: color,
- 'stroke-width': width
- };
- if (dashStyle) {
- attribs.dashstyle = dashStyle;
- }
- } else if (isBand) {
-
-
- from = mathMax(from, axis.min - halfPointRange);
- to = mathMin(to, axis.max + halfPointRange);
-
- path = axis.getPlotBandPath(from, to, options);
- attribs = {
- fill: color
- };
- if (options.borderWidth) {
- attribs.stroke = options.borderColor;
- attribs['stroke-width'] = options.borderWidth;
- }
- } else {
- return;
- }
-
- if (defined(zIndex)) {
- attribs.zIndex = zIndex;
- }
-
- if (svgElem) {
- if (path) {
- svgElem.animate({
- d: path
- }, null, svgElem.onGetPath);
- } else {
- svgElem.hide();
- svgElem.onGetPath = function () {
- svgElem.show();
- };
- }
- } else if (path && path.length) {
- plotLine.svgElem = svgElem = renderer.path(path)
- .attr(attribs).add();
-
- if (events) {
- addEvent = function (eventType) {
- svgElem.on(eventType, function (e) {
- events[eventType].apply(plotLine, [e]);
- });
- };
- for (eventType in events) {
- addEvent(eventType);
- }
- }
- }
-
- if (optionsLabel && defined(optionsLabel.text) && path && path.length && axis.width > 0 && axis.height > 0) {
-
- optionsLabel = merge({
- align: horiz && isBand && 'center',
- x: horiz ? !isBand && 4 : 10,
- verticalAlign : !horiz && isBand && 'middle',
- y: horiz ? isBand ? 16 : 10 : isBand ? 6 : -4,
- rotation: horiz && !isBand && 90
- }, optionsLabel);
-
- if (!label) {
- plotLine.label = label = renderer.text(
- optionsLabel.text,
- 0,
- 0,
- optionsLabel.useHTML
- )
- .attr({
- align: optionsLabel.textAlign || optionsLabel.align,
- rotation: optionsLabel.rotation,
- zIndex: zIndex
- })
- .css(optionsLabel.style)
- .add();
- }
-
- xs = [path[1], path[4], pick(path[6], path[1])];
- ys = [path[2], path[5], pick(path[7], path[2])];
- x = arrayMin(xs);
- y = arrayMin(ys);
- label.align(optionsLabel, false, {
- x: x,
- y: y,
- width: arrayMax(xs) - x,
- height: arrayMax(ys) - y
- });
- label.show();
- } else if (label) {
- label.hide();
- }
-
- return plotLine;
- },
-
- destroy: function () {
-
- erase(this.axis.plotLinesAndBands, this);
-
- delete this.axis;
- destroyObjectProperties(this);
- }
- };
- function StackItem(axis, options, isNegative, x, stackOption, stacking) {
-
- var inverted = axis.chart.inverted;
- this.axis = axis;
-
- this.isNegative = isNegative;
-
- this.options = options;
-
- this.x = x;
-
- this.total = null;
-
- this.points = {};
-
- this.stack = stackOption;
- this.percent = stacking === 'percent';
-
-
-
- this.alignOptions = {
- align: options.align || (inverted ? (isNegative ? 'left' : 'right') : 'center'),
- verticalAlign: options.verticalAlign || (inverted ? 'middle' : (isNegative ? 'bottom' : 'top')),
- y: pick(options.y, inverted ? 4 : (isNegative ? 14 : -6)),
- x: pick(options.x, inverted ? (isNegative ? -6 : 6) : 0)
- };
- this.textAlign = options.textAlign || (inverted ? (isNegative ? 'right' : 'left') : 'center');
- }
- StackItem.prototype = {
- destroy: function () {
- destroyObjectProperties(this, this.axis);
- },
-
- render: function (group) {
- var options = this.options,
- formatOption = options.format,
- str = formatOption ?
- format(formatOption, this) :
- options.formatter.call(this);
-
- if (this.label) {
- this.label.attr({text: str, visibility: HIDDEN});
-
- } else {
- this.label =
- this.axis.chart.renderer.text(str, 0, 0, options.useHTML)
- .css(options.style)
- .attr({
- align: this.textAlign,
- rotation: options.rotation,
- visibility: HIDDEN
- })
- .add(group);
- }
- },
-
- setOffset: function (xOffset, xWidth) {
- var stackItem = this,
- axis = stackItem.axis,
- chart = axis.chart,
- inverted = chart.inverted,
- neg = this.isNegative,
- y = axis.translate(this.percent ? 100 : this.total, 0, 0, 0, 1),
- yZero = axis.translate(0),
- h = mathAbs(y - yZero),
- x = chart.xAxis[0].translate(this.x) + xOffset,
- plotHeight = chart.plotHeight,
- stackBox = {
- x: inverted ? (neg ? y : y - h) : x,
- y: inverted ? plotHeight - x - xWidth : (neg ? (plotHeight - y - h) : plotHeight - y),
- width: inverted ? h : xWidth,
- height: inverted ? xWidth : h
- },
- label = this.label,
- alignAttr;
-
- if (label) {
- label.align(this.alignOptions, null, stackBox);
-
-
- alignAttr = label.alignAttr;
- label.attr({
- visibility: this.options.crop === false || chart.isInsidePlot(alignAttr.x, alignAttr.y) ?
- (hasSVG ? 'inherit' : VISIBLE) :
- HIDDEN
- });
- }
- }
- };
- function Axis() {
- this.init.apply(this, arguments);
- }
- Axis.prototype = {
-
-
- defaultOptions: {
-
-
-
- dateTimeLabelFormats: {
- millisecond: '%H:%M:%S.%L',
- second: '%H:%M:%S',
- minute: '%H:%M',
- hour: '%H:%M',
- day: '%e. %b',
- week: '%e. %b',
- month: '%b \'%y',
- year: '%Y'
- },
- endOnTick: false,
- gridLineColor: '#C0C0C0',
-
-
-
-
- labels: defaultLabelOptions,
-
- lineColor: '#C0D0E0',
- lineWidth: 1,
-
-
-
- minPadding: 0.01,
- maxPadding: 0.01,
-
- minorGridLineColor: '#E0E0E0',
-
- minorGridLineWidth: 1,
- minorTickColor: '#A0A0A0',
-
- minorTickLength: 2,
- minorTickPosition: 'outside',
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- startOfWeek: 1,
- startOnTick: false,
- tickColor: '#C0D0E0',
-
- tickLength: 5,
- tickmarkPlacement: 'between',
- tickPixelInterval: 100,
- tickPosition: 'outside',
- tickWidth: 1,
- title: {
-
- align: 'middle',
-
-
-
- style: {
- color: '#4d759e',
-
- fontWeight: 'bold'
- }
-
-
- },
- type: 'linear'
- },
-
-
- defaultYAxisOptions: {
- endOnTick: true,
- gridLineWidth: 1,
- tickPixelInterval: 72,
- showLastLabel: true,
- labels: {
- x: -8,
- y: 3
- },
- lineWidth: 0,
- maxPadding: 0.05,
- minPadding: 0.05,
- startOnTick: true,
- tickWidth: 0,
- title: {
- rotation: 270,
- text: 'Values'
- },
- stackLabels: {
- enabled: false,
-
-
-
-
-
-
- formatter: function () {
- return numberFormat(this.total, -1);
- },
- style: defaultLabelOptions.style
- }
- },
-
-
- defaultLeftAxisOptions: {
- labels: {
- x: -8,
- y: null
- },
- title: {
- rotation: 270
- }
- },
-
-
- defaultRightAxisOptions: {
- labels: {
- x: 8,
- y: null
- },
- title: {
- rotation: 90
- }
- },
-
-
- defaultBottomAxisOptions: {
- labels: {
- x: 0,
- y: 14
-
-
- },
- title: {
- rotation: 0
- }
- },
-
- defaultTopAxisOptions: {
- labels: {
- x: 0,
- y: -5
-
-
- },
- title: {
- rotation: 0
- }
- },
-
-
- init: function (chart, userOptions) {
-
-
- var isXAxis = userOptions.isX,
- axis = this;
-
-
- axis.horiz = chart.inverted ? !isXAxis : isXAxis;
-
-
- axis.isXAxis = isXAxis;
- axis.xOrY = isXAxis ? 'x' : 'y';
-
-
- axis.opposite = userOptions.opposite;
- axis.side = axis.horiz ?
- (axis.opposite ? 0 : 2) :
- (axis.opposite ? 1 : 3);
-
- axis.setOptions(userOptions);
-
-
- var options = this.options,
- type = options.type,
- isDatetimeAxis = type === 'datetime';
-
- axis.labelFormatter = options.labels.formatter || axis.defaultLabelFormatter;
-
-
-
- axis.userOptions = userOptions;
-
-
- axis.minPixelPadding = 0;
-
-
-
- axis.chart = chart;
- axis.reversed = options.reversed;
- axis.zoomEnabled = options.zoomEnabled !== false;
-
-
- axis.categories = options.categories || type === 'category';
-
-
-
-
-
-
-
-
- axis.isLog = type === 'logarithmic';
- axis.isDatetimeAxis = isDatetimeAxis;
-
-
- axis.isLinked = defined(options.linkedTo);
-
-
-
-
-
-
-
-
-
- axis.tickmarkOffset = (axis.categories && options.tickmarkPlacement === 'between') ? 0.5 : 0;
-
-
- axis.ticks = {};
-
- axis.minorTicks = {};
-
-
-
- axis.plotLinesAndBands = [];
-
-
- axis.alternateBands = {};
-
-
-
-
-
-
-
-
-
-
-
- axis.len = 0;
-
-
-
-
-
- axis.minRange = axis.userMinRange = options.minRange || options.maxZoom;
- axis.range = options.range;
- axis.offset = options.offset || 0;
-
-
-
- axis.stacks = {};
- axis.oldStacks = {};
-
- axis.stackExtremes = {};
-
-
-
-
-
- axis.max = null;
- axis.min = null;
-
-
-
-
-
-
- var eventType,
- events = axis.options.events;
-
- if (inArray(axis, chart.axes) === -1) {
- chart.axes.push(axis);
- chart[isXAxis ? 'xAxis' : 'yAxis'].push(axis);
- }
- axis.series = axis.series || [];
-
- if (chart.inverted && isXAxis && axis.reversed === UNDEFINED) {
- axis.reversed = true;
- }
- axis.removePlotBand = axis.removePlotBandOrLine;
- axis.removePlotLine = axis.removePlotBandOrLine;
-
- for (eventType in events) {
- addEvent(axis, eventType, events[eventType]);
- }
-
- if (axis.isLog) {
- axis.val2lin = log2lin;
- axis.lin2val = lin2log;
- }
- },
-
-
- setOptions: function (userOptions) {
- this.options = merge(
- this.defaultOptions,
- this.isXAxis ? {} : this.defaultYAxisOptions,
- [this.defaultTopAxisOptions, this.defaultRightAxisOptions,
- this.defaultBottomAxisOptions, this.defaultLeftAxisOptions][this.side],
- merge(
- defaultOptions[this.isXAxis ? 'xAxis' : 'yAxis'],
- userOptions
- )
- );
- },
-
- update: function (newOptions, redraw) {
- var chart = this.chart;
- newOptions = chart.options[this.xOrY + 'Axis'][this.options.index] = merge(this.userOptions, newOptions);
- this.destroy(true);
- this._addedPlotLB = this.userMin = this.userMax = UNDEFINED;
- this.init(chart, extend(newOptions, { events: UNDEFINED }));
- chart.isDirtyBox = true;
- if (pick(redraw, true)) {
- chart.redraw();
- }
- },
-
-
- remove: function (redraw) {
- var chart = this.chart,
- key = this.xOrY + 'Axis';
-
- each(this.series, function (series) {
- series.remove(false);
- });
-
- erase(chart.axes, this);
- erase(chart[key], this);
- chart.options[key].splice(this.options.index, 1);
- each(chart[key], function (axis, i) {
- axis.options.index = i;
- });
- this.destroy();
- chart.isDirtyBox = true;
- if (pick(redraw, true)) {
- chart.redraw();
- }
- },
-
-
- defaultLabelFormatter: function () {
- var axis = this.axis,
- value = this.value,
- categories = axis.categories,
- dateTimeLabelFormat = this.dateTimeLabelFormat,
- numericSymbols = defaultOptions.lang.numericSymbols,
- i = numericSymbols && numericSymbols.length,
- multi,
- ret,
- formatOption = axis.options.labels.format,
-
-
- numericSymbolDetector = axis.isLog ? value : axis.tickInterval;
- if (formatOption) {
- ret = format(formatOption, this);
-
- } else if (categories) {
- ret = value;
-
- } else if (dateTimeLabelFormat) {
- ret = dateFormat(dateTimeLabelFormat, value);
-
- } else if (i && numericSymbolDetector >= 1000) {
-
-
-
- while (i-- && ret === UNDEFINED) {
- multi = Math.pow(1000, i + 1);
- if (numericSymbolDetector >= multi && numericSymbols[i] !== null) {
- ret = numberFormat(value / multi, -1) + numericSymbols[i];
- }
- }
- }
-
- if (ret === UNDEFINED) {
- if (value >= 1000) {
- ret = numberFormat(value, 0);
- } else {
- ret = numberFormat(value, -1);
- }
- }
-
- return ret;
- },
-
- getSeriesExtremes: function () {
- var axis = this,
- chart = axis.chart;
- axis.hasVisibleSeries = false;
-
- axis.dataMin = axis.dataMax = null;
-
- axis.stackExtremes = {};
- axis.buildStacks();
-
- each(axis.series, function (series) {
- if (series.visible || !chart.options.chart.ignoreHiddenSeries) {
- var seriesOptions = series.options,
- xData,
- threshold = seriesOptions.threshold,
- seriesDataMin,
- seriesDataMax;
- axis.hasVisibleSeries = true;
-
- if (axis.isLog && threshold <= 0) {
- threshold = null;
- }
-
- if (axis.isXAxis) {
- xData = series.xData;
- if (xData.length) {
- axis.dataMin = mathMin(pick(axis.dataMin, xData[0]), arrayMin(xData));
- axis.dataMax = mathMax(pick(axis.dataMax, xData[0]), arrayMax(xData));
- }
-
- } else {
-
- series.getExtremes();
- seriesDataMax = series.dataMax;
- seriesDataMin = series.dataMin;
-
-
-
- if (defined(seriesDataMin) && defined(seriesDataMax)) {
- axis.dataMin = mathMin(pick(axis.dataMin, seriesDataMin), seriesDataMin);
- axis.dataMax = mathMax(pick(axis.dataMax, seriesDataMax), seriesDataMax);
- }
-
- if (defined(threshold)) {
- if (axis.dataMin >= threshold) {
- axis.dataMin = threshold;
- axis.ignoreMinPadding = true;
- } else if (axis.dataMax < threshold) {
- axis.dataMax = threshold;
- axis.ignoreMaxPadding = true;
- }
- }
- }
- }
- });
- },
-
- translate: function (val, backwards, cvsCoord, old, handleLog, pointPlacement) {
- var axis = this,
- axisLength = axis.len,
- sign = 1,
- cvsOffset = 0,
- localA = old ? axis.oldTransA : axis.transA,
- localMin = old ? axis.oldMin : axis.min,
- returnValue,
- minPixelPadding = axis.minPixelPadding,
- postTranslate = (axis.options.ordinal || (axis.isLog && handleLog)) && axis.lin2val;
- if (!localA) {
- localA = axis.transA;
- }
-
-
- if (cvsCoord) {
- sign *= -1;
- cvsOffset = axisLength;
- }
-
- if (axis.reversed) {
- sign *= -1;
- cvsOffset -= sign * axisLength;
- }
-
- if (backwards) {
-
- val = val * sign + cvsOffset;
- val -= minPixelPadding;
- returnValue = val / localA + localMin;
- if (postTranslate) {
- returnValue = axis.lin2val(returnValue);
- }
-
- } else {
- if (postTranslate) {
- val = axis.val2lin(val);
- }
- if (pointPlacement === 'between') {
- pointPlacement = 0.5;
- }
- returnValue = sign * (val - localMin) * localA + cvsOffset + (sign * minPixelPadding) +
- (isNumber(pointPlacement) ? localA * pointPlacement * axis.pointRange : 0);
- }
- return returnValue;
- },
-
- toPixels: function (value, paneCoordinates) {
- return this.translate(value, false, !this.horiz, null, true) + (paneCoordinates ? 0 : this.pos);
- },
-
- toValue: function (pixel, paneCoordinates) {
- return this.translate(pixel - (paneCoordinates ? 0 : this.pos), true, !this.horiz, null, true);
- },
-
- getPlotBandPath: function (from, to) {
- var toPath = this.getPlotLinePath(to),
- path = this.getPlotLinePath(from);
-
- if (path && toPath) {
- path.push(
- toPath[4],
- toPath[5],
- toPath[1],
- toPath[2]
- );
- } else {
- path = null;
- }
-
- return path;
- },
-
-
- getLinearTickPositions: function (tickInterval, min, max) {
- var pos,
- lastPos,
- roundedMin = correctFloat(mathFloor(min / tickInterval) * tickInterval),
- roundedMax = correctFloat(mathCeil(max / tickInterval) * tickInterval),
- tickPositions = [];
-
- pos = roundedMin;
- while (pos <= roundedMax) {
-
- tickPositions.push(pos);
-
- pos = correctFloat(pos + tickInterval);
-
-
- if (pos === lastPos) {
- break;
- }
-
- lastPos = pos;
- }
- return tickPositions;
- },
-
-
- getLogTickPositions: function (interval, min, max, minor) {
- var axis = this,
- options = axis.options,
- axisLength = axis.len,
-
-
- positions = [];
-
-
- if (!minor) {
- axis._minorAutoInterval = null;
- }
-
-
- if (interval >= 0.5) {
- interval = mathRound(interval);
- positions = axis.getLinearTickPositions(interval, min, max);
-
-
-
- } else if (interval >= 0.08) {
- var roundedMin = mathFloor(min),
- intermediate,
- i,
- j,
- len,
- pos,
- lastPos,
- break2;
-
- if (interval > 0.3) {
- intermediate = [1, 2, 4];
- } else if (interval > 0.15) {
- intermediate = [1, 2, 4, 6, 8];
- } else {
- intermediate = [1, 2, 3, 4, 5, 6, 7, 8, 9];
- }
-
- for (i = roundedMin; i < max + 1 && !break2; i++) {
- len = intermediate.length;
- for (j = 0; j < len && !break2; j++) {
- pos = log2lin(lin2log(i) * intermediate[j]);
-
- if (pos > min && (!minor || lastPos <= max)) {
- positions.push(lastPos);
- }
-
- if (lastPos > max) {
- break2 = true;
- }
- lastPos = pos;
- }
- }
-
-
-
-
- } else {
- var realMin = lin2log(min),
- realMax = lin2log(max),
- tickIntervalOption = options[minor ? 'minorTickInterval' : 'tickInterval'],
- filteredTickIntervalOption = tickIntervalOption === 'auto' ? null : tickIntervalOption,
- tickPixelIntervalOption = options.tickPixelInterval / (minor ? 5 : 1),
- totalPixelLength = minor ? axisLength / axis.tickPositions.length : axisLength;
-
- interval = pick(
- filteredTickIntervalOption,
- axis._minorAutoInterval,
- (realMax - realMin) * tickPixelIntervalOption / (totalPixelLength || 1)
- );
-
- interval = normalizeTickInterval(
- interval,
- null,
- getMagnitude(interval)
- );
-
- positions = map(axis.getLinearTickPositions(
- interval,
- realMin,
- realMax
- ), log2lin);
-
- if (!minor) {
- axis._minorAutoInterval = interval / 5;
- }
- }
-
-
- if (!minor) {
- axis.tickInterval = interval;
- }
- return positions;
- },
-
- getMinorTickPositions: function () {
- var axis = this,
- options = axis.options,
- tickPositions = axis.tickPositions,
- minorTickInterval = axis.minorTickInterval,
- minorTickPositions = [],
- pos,
- i,
- len;
-
- if (axis.isLog) {
- len = tickPositions.length;
- for (i = 1; i < len; i++) {
- minorTickPositions = minorTickPositions.concat(
- axis.getLogTickPositions(minorTickInterval, tickPositions[i - 1], tickPositions[i], true)
- );
- }
- } else if (axis.isDatetimeAxis && options.minorTickInterval === 'auto') {
- minorTickPositions = minorTickPositions.concat(
- getTimeTicks(
- normalizeTimeTickInterval(minorTickInterval),
- axis.min,
- axis.max,
- options.startOfWeek
- )
- );
- if (minorTickPositions[0] < axis.min) {
- minorTickPositions.shift();
- }
- } else {
- for (pos = axis.min + (tickPositions[0] - axis.min) % minorTickInterval; pos <= axis.max; pos += minorTickInterval) {
- minorTickPositions.push(pos);
- }
- }
- return minorTickPositions;
- },
-
- adjustForMinRange: function () {
- var axis = this,
- options = axis.options,
- min = axis.min,
- max = axis.max,
- zoomOffset,
- spaceAvailable = axis.dataMax - axis.dataMin >= axis.minRange,
- closestDataRange,
- i,
- distance,
- xData,
- loopLength,
- minArgs,
- maxArgs;
-
- if (axis.isXAxis && axis.minRange === UNDEFINED && !axis.isLog) {
- if (defined(options.min) || defined(options.max)) {
- axis.minRange = null;
- } else {
-
-
- each(axis.series, function (series) {
- xData = series.xData;
- loopLength = series.xIncrement ? 1 : xData.length - 1;
- for (i = loopLength; i > 0; i--) {
- distance = xData[i] - xData[i - 1];
- if (closestDataRange === UNDEFINED || distance < closestDataRange) {
- closestDataRange = distance;
- }
- }
- });
- axis.minRange = mathMin(closestDataRange * 5, axis.dataMax - axis.dataMin);
- }
- }
-
- if (max - min < axis.minRange) {
- var minRange = axis.minRange;
- zoomOffset = (minRange - max + min) / 2;
-
- minArgs = [min - zoomOffset, pick(options.min, min - zoomOffset)];
- if (spaceAvailable) {
- minArgs[2] = axis.dataMin;
- }
- min = arrayMax(minArgs);
- maxArgs = [min + minRange, pick(options.max, min + minRange)];
- if (spaceAvailable) {
- maxArgs[2] = axis.dataMax;
- }
- max = arrayMin(maxArgs);
-
- if (max - min < minRange) {
- minArgs[0] = max - minRange;
- minArgs[1] = pick(options.min, max - minRange);
- min = arrayMax(minArgs);
- }
- }
-
-
- axis.min = min;
- axis.max = max;
- },
-
- setAxisTranslation: function (saveOld) {
- var axis = this,
- range = axis.max - axis.min,
- pointRange = 0,
- closestPointRange,
- minPointOffset = 0,
- pointRangePadding = 0,
- linkedParent = axis.linkedParent,
- ordinalCorrection,
- transA = axis.transA;
-
- if (axis.isXAxis) {
- if (linkedParent) {
- minPointOffset = linkedParent.minPointOffset;
- pointRangePadding = linkedParent.pointRangePadding;
-
- } else {
- each(axis.series, function (series) {
- var seriesPointRange = series.pointRange,
- pointPlacement = series.options.pointPlacement,
- seriesClosestPointRange = series.closestPointRange;
- if (seriesPointRange > range) {
- seriesPointRange = 0;
- }
- pointRange = mathMax(pointRange, seriesPointRange);
-
-
-
-
- minPointOffset = mathMax(
- minPointOffset,
- isString(pointPlacement) ? 0 : seriesPointRange / 2
- );
-
-
-
- pointRangePadding = mathMax(
- pointRangePadding,
- pointPlacement === 'on' ? 0 : seriesPointRange
- );
-
- if (!series.noSharedTooltip && defined(seriesClosestPointRange)) {
- closestPointRange = defined(closestPointRange) ?
- mathMin(closestPointRange, seriesClosestPointRange) :
- seriesClosestPointRange;
- }
- });
- }
-
-
- ordinalCorrection = axis.ordinalSlope && closestPointRange ? axis.ordinalSlope / closestPointRange : 1;
- axis.minPointOffset = minPointOffset = minPointOffset * ordinalCorrection;
- axis.pointRangePadding = pointRangePadding = pointRangePadding * ordinalCorrection;
-
- axis.pointRange = mathMin(pointRange, range);
-
-
-
- axis.closestPointRange = closestPointRange;
- }
-
- if (saveOld) {
- axis.oldTransA = transA;
- }
- axis.translationSlope = axis.transA = transA = axis.len / ((range + pointRangePadding) || 1);
- axis.transB = axis.horiz ? axis.left : axis.bottom;
- axis.minPixelPadding = transA * minPointOffset;
- },
-
- setTickPositions: function (secondPass) {
- var axis = this,
- chart = axis.chart,
- options = axis.options,
- isLog = axis.isLog,
- isDatetimeAxis = axis.isDatetimeAxis,
- isXAxis = axis.isXAxis,
- isLinked = axis.isLinked,
- tickPositioner = axis.options.tickPositioner,
- maxPadding = options.maxPadding,
- minPadding = options.minPadding,
- length,
- linkedParentExtremes,
- tickIntervalOption = options.tickInterval,
- minTickIntervalOption = options.minTickInterval,
- tickPixelIntervalOption = options.tickPixelInterval,
- tickPositions,
- keepTwoTicksOnly,
- categories = axis.categories;
-
- if (isLinked) {
- axis.linkedParent = chart[isXAxis ? 'xAxis' : 'yAxis'][options.linkedTo];
- linkedParentExtremes = axis.linkedParent.getExtremes();
- axis.min = pick(linkedParentExtremes.min, linkedParentExtremes.dataMin);
- axis.max = pick(linkedParentExtremes.max, linkedParentExtremes.dataMax);
- if (options.type !== axis.linkedParent.options.type) {
- error(11, 1);
- }
- } else {
- axis.min = pick(axis.userMin, options.min, axis.dataMin);
- axis.max = pick(axis.userMax, options.max, axis.dataMax);
- }
- if (isLog) {
- if (!secondPass && mathMin(axis.min, pick(axis.dataMin, axis.min)) <= 0) {
- error(10, 1);
- }
- axis.min = correctFloat(log2lin(axis.min));
- axis.max = correctFloat(log2lin(axis.max));
- }
-
- if (axis.range) {
- axis.userMin = axis.min = mathMax(axis.min, axis.max - axis.range);
- axis.userMax = axis.max;
- if (secondPass) {
- axis.range = null;
- }
- }
-
-
- if (axis.beforePadding) {
- axis.beforePadding();
- }
-
- axis.adjustForMinRange();
-
-
-
- if (!categories && !axis.usePercentage && !isLinked && defined(axis.min) && defined(axis.max)) {
- length = axis.max - axis.min;
- if (length) {
- if (!defined(options.min) && !defined(axis.userMin) && minPadding && (axis.dataMin < 0 || !axis.ignoreMinPadding)) {
- axis.min -= length * minPadding;
- }
- if (!defined(options.max) && !defined(axis.userMax) && maxPadding && (axis.dataMax > 0 || !axis.ignoreMaxPadding)) {
- axis.max += length * maxPadding;
- }
- }
- }
-
- if (axis.min === axis.max || axis.min === undefined || axis.max === undefined) {
- axis.tickInterval = 1;
- } else if (isLinked && !tickIntervalOption &&
- tickPixelIntervalOption === axis.linkedParent.options.tickPixelInterval) {
- axis.tickInterval = axis.linkedParent.tickInterval;
- } else {
- axis.tickInterval = pick(
- tickIntervalOption,
- categories ?
- 1 :
-
- (axis.max - axis.min) * tickPixelIntervalOption / mathMax(axis.len, tickPixelIntervalOption)
- );
-
- if (!defined(tickIntervalOption) && axis.len < tickPixelIntervalOption && !this.isRadial) {
- keepTwoTicksOnly = true;
- axis.tickInterval /= 4;
- }
- }
-
-
- if (isXAxis && !secondPass) {
- each(axis.series, function (series) {
- series.processData(axis.min !== axis.oldMin || axis.max !== axis.oldMax);
- });
- }
-
- axis.setAxisTranslation(true);
-
- if (axis.beforeSetTickPositions) {
- axis.beforeSetTickPositions();
- }
-
-
- if (axis.postProcessTickInterval) {
- axis.tickInterval = axis.postProcessTickInterval(axis.tickInterval);
- }
-
- if (axis.pointRange) {
- axis.tickInterval = mathMax(axis.pointRange, axis.tickInterval);
- }
-
-
- if (!tickIntervalOption && axis.tickInterval < minTickIntervalOption) {
- axis.tickInterval = minTickIntervalOption;
- }
-
- if (!isDatetimeAxis && !isLog) {
- if (!tickIntervalOption) {
- axis.tickInterval = normalizeTickInterval(axis.tickInterval, null, getMagnitude(axis.tickInterval), options);
- }
- }
-
- axis.minorTickInterval = options.minorTickInterval === 'auto' && axis.tickInterval ?
- axis.tickInterval / 5 : options.minorTickInterval;
-
- axis.tickPositions = tickPositions = options.tickPositions ?
- [].concat(options.tickPositions) :
- (tickPositioner && tickPositioner.apply(axis, [axis.min, axis.max]));
- if (!tickPositions) {
-
-
- if (!axis.ordinalPositions && (axis.max - axis.min) / axis.tickInterval > mathMax(2 * axis.len, 200)) {
- error(19, true);
- }
-
- if (isDatetimeAxis) {
- tickPositions = (axis.getNonLinearTimeTicks || getTimeTicks)(
- normalizeTimeTickInterval(axis.tickInterval, options.units),
- axis.min,
- axis.max,
- options.startOfWeek,
- axis.ordinalPositions,
- axis.closestPointRange,
- true
- );
- } else if (isLog) {
- tickPositions = axis.getLogTickPositions(axis.tickInterval, axis.min, axis.max);
- } else {
- tickPositions = axis.getLinearTickPositions(axis.tickInterval, axis.min, axis.max);
- }
- if (keepTwoTicksOnly) {
- tickPositions.splice(1, tickPositions.length - 2);
- }
- axis.tickPositions = tickPositions;
- }
- if (!isLinked) {
-
- var roundedMin = tickPositions[0],
- roundedMax = tickPositions[tickPositions.length - 1],
- minPointOffset = axis.minPointOffset || 0,
- singlePad;
- if (options.startOnTick) {
- axis.min = roundedMin;
- } else if (axis.min - minPointOffset > roundedMin) {
- tickPositions.shift();
- }
- if (options.endOnTick) {
- axis.max = roundedMax;
- } else if (axis.max + minPointOffset < roundedMax) {
- tickPositions.pop();
- }
-
-
-
-
- if (tickPositions.length === 1) {
- singlePad = 0.001;
- axis.min -= singlePad;
- axis.max += singlePad;
- }
- }
- },
-
-
- setMaxTicks: function () {
-
- var chart = this.chart,
- maxTicks = chart.maxTicks || {},
- tickPositions = this.tickPositions,
- key = this._maxTicksKey = [this.xOrY, this.pos, this.len].join('-');
-
- if (!this.isLinked && !this.isDatetimeAxis && tickPositions && tickPositions.length > (maxTicks[key] || 0) && this.options.alignTicks !== false) {
- maxTicks[key] = tickPositions.length;
- }
- chart.maxTicks = maxTicks;
- },
-
- adjustTickAmount: function () {
- var axis = this,
- chart = axis.chart,
- key = axis._maxTicksKey,
- tickPositions = axis.tickPositions,
- maxTicks = chart.maxTicks;
- if (maxTicks && maxTicks[key] && !axis.isDatetimeAxis && !axis.categories && !axis.isLinked && axis.options.alignTicks !== false) {
- var oldTickAmount = axis.tickAmount,
- calculatedTickAmount = tickPositions.length,
- tickAmount;
-
- axis.tickAmount = tickAmount = maxTicks[key];
- if (calculatedTickAmount < tickAmount) {
- while (tickPositions.length < tickAmount) {
- tickPositions.push(correctFloat(
- tickPositions[tickPositions.length - 1] + axis.tickInterval
- ));
- }
- axis.transA *= (calculatedTickAmount - 1) / (tickAmount - 1);
- axis.max = tickPositions[tickPositions.length - 1];
- }
- if (defined(oldTickAmount) && tickAmount !== oldTickAmount) {
- axis.isDirty = true;
- }
- }
- },
-
- setScale: function () {
- var axis = this,
- stacks = axis.stacks,
- type,
- i,
- isDirtyData,
- isDirtyAxisLength;
- axis.oldMin = axis.min;
- axis.oldMax = axis.max;
- axis.oldAxisLength = axis.len;
-
- axis.setAxisSize();
-
- isDirtyAxisLength = axis.len !== axis.oldAxisLength;
-
- each(axis.series, function (series) {
- if (series.isDirtyData || series.isDirty ||
- series.xAxis.isDirty) {
- isDirtyData = true;
- }
- });
-
- if (isDirtyAxisLength || isDirtyData || axis.isLinked || axis.forceRedraw ||
- axis.userMin !== axis.oldUserMin || axis.userMax !== axis.oldUserMax) {
-
-
- if (!axis.isXAxis) {
- for (type in stacks) {
- delete stacks[type];
- }
- }
- axis.forceRedraw = false;
-
- axis.getSeriesExtremes();
-
- axis.setTickPositions();
-
- axis.oldUserMin = axis.userMin;
- axis.oldUserMax = axis.userMax;
-
- if (!axis.isDirty) {
- axis.isDirty = isDirtyAxisLength || axis.min !== axis.oldMin || axis.max !== axis.oldMax;
- }
- } else if (!axis.isXAxis) {
- if (axis.oldStacks) {
- stacks = axis.stacks = axis.oldStacks;
- }
-
- for (type in stacks) {
- for (i in stacks[type]) {
- stacks[type][i].cum = stacks[type][i].total;
- }
- }
- }
-
-
- axis.setMaxTicks();
- },
-
- setExtremes: function (newMin, newMax, redraw, animation, eventArguments) {
- var axis = this,
- chart = axis.chart;
- redraw = pick(redraw, true);
-
- eventArguments = extend(eventArguments, {
- min: newMin,
- max: newMax
- });
-
- fireEvent(axis, 'setExtremes', eventArguments, function () {
- axis.userMin = newMin;
- axis.userMax = newMax;
- axis.eventArgs = eventArguments;
-
- axis.isDirtyExtremes = true;
-
- if (redraw) {
- chart.redraw(animation);
- }
- });
- },
-
-
- zoom: function (newMin, newMax) {
-
- if (!this.allowZoomOutside) {
- if (defined(this.dataMin) && newMin <= this.dataMin) {
- newMin = UNDEFINED;
- }
- if (defined(this.dataMax) && newMax >= this.dataMax) {
- newMax = UNDEFINED;
- }
- }
-
- this.displayBtn = newMin !== UNDEFINED || newMax !== UNDEFINED;
-
-
- this.setExtremes(
- newMin,
- newMax,
- false,
- UNDEFINED,
- { trigger: 'zoom' }
- );
- return true;
- },
-
-
- setAxisSize: function () {
- var chart = this.chart,
- options = this.options,
- offsetLeft = options.offsetLeft || 0,
- offsetRight = options.offsetRight || 0,
- horiz = this.horiz,
- width,
- height,
- top,
- left;
-
- this.left = left = pick(options.left, chart.plotLeft + offsetLeft);
- this.top = top = pick(options.top, chart.plotTop);
- this.width = width = pick(options.width, chart.plotWidth - offsetLeft + offsetRight);
- this.height = height = pick(options.height, chart.plotHeight);
- this.bottom = chart.chartHeight - height - top;
- this.right = chart.chartWidth - width - left;
-
- this.len = mathMax(horiz ? width : height, 0);
- this.pos = horiz ? left : top;
- },
-
- getExtremes: function () {
- var axis = this,
- isLog = axis.isLog;
- return {
- min: isLog ? correctFloat(lin2log(axis.min)) : axis.min,
- max: isLog ? correctFloat(lin2log(axis.max)) : axis.max,
- dataMin: axis.dataMin,
- dataMax: axis.dataMax,
- userMin: axis.userMin,
- userMax: axis.userMax
- };
- },
-
- getThreshold: function (threshold) {
- var axis = this,
- isLog = axis.isLog;
- var realMin = isLog ? lin2log(axis.min) : axis.min,
- realMax = isLog ? lin2log(axis.max) : axis.max;
-
- if (realMin > threshold || threshold === null) {
- threshold = realMin;
- } else if (realMax < threshold) {
- threshold = realMax;
- }
- return axis.translate(threshold, 0, 1, 0, 1);
- },
- addPlotBand: function (options) {
- this.addPlotBandOrLine(options, 'plotBands');
- },
-
- addPlotLine: function (options) {
- this.addPlotBandOrLine(options, 'plotLines');
- },
-
- addPlotBandOrLine: function (options, coll) {
- var obj = new PlotLineOrBand(this, options).render(),
- userOptions = this.userOptions;
- if (obj) {
-
- if (coll) {
- userOptions[coll] = userOptions[coll] || [];
- userOptions[coll].push(options);
- }
- this.plotLinesAndBands.push(obj);
- }
-
- return obj;
- },
-
- autoLabelAlign: function (rotation) {
- var ret,
- angle = (pick(rotation, 0) - (this.side * 90) + 720) % 360;
- if (angle > 15 && angle < 165) {
- ret = 'right';
- } else if (angle > 195 && angle < 345) {
- ret = 'left';
- } else {
- ret = 'center';
- }
- return ret;
- },
-
- getOffset: function () {
- var axis = this,
- chart = axis.chart,
- renderer = chart.renderer,
- options = axis.options,
- tickPositions = axis.tickPositions,
- ticks = axis.ticks,
- horiz = axis.horiz,
- side = axis.side,
- invertedSide = chart.inverted ? [1, 0, 3, 2][side] : side,
- hasData,
- showAxis,
- titleOffset = 0,
- titleOffsetOption,
- titleMargin = 0,
- axisTitleOptions = options.title,
- labelOptions = options.labels,
- labelOffset = 0,
- axisOffset = chart.axisOffset,
- clipOffset = chart.clipOffset,
- directionFactor = [-1, 1, 1, -1][side],
- n,
- i,
- autoStaggerLines = 1,
- maxStaggerLines = pick(labelOptions.maxStaggerLines, 5),
- sortedPositions,
- lastRight,
- overlap,
- pos,
- bBox,
- x,
- w,
- lineNo;
-
-
- axis.hasData = hasData = (axis.hasVisibleSeries || (defined(axis.min) && defined(axis.max) && !!tickPositions));
- axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
-
- axis.staggerLines = axis.horiz && labelOptions.staggerLines;
-
-
- if (!axis.axisGroup) {
- axis.gridGroup = renderer.g('grid')
- .attr({ zIndex: options.gridZIndex || 1 })
- .add();
- axis.axisGroup = renderer.g('axis')
- .attr({ zIndex: options.zIndex || 2 })
- .add();
- axis.labelGroup = renderer.g('axis-labels')
- .attr({ zIndex: labelOptions.zIndex || 7 })
- .add();
- }
- if (hasData || axis.isLinked) {
-
-
- axis.labelAlign = pick(labelOptions.align || axis.autoLabelAlign(labelOptions.rotation));
- each(tickPositions, function (pos) {
- if (!ticks[pos]) {
- ticks[pos] = new Tick(axis, pos);
- } else {
- ticks[pos].addLabel();
- }
- });
-
- if (axis.horiz && !axis.staggerLines && maxStaggerLines && !labelOptions.rotation) {
- sortedPositions = axis.reversed ? [].concat(tickPositions).reverse() : tickPositions;
- while (autoStaggerLines < maxStaggerLines) {
- lastRight = [];
- overlap = false;
-
- for (i = 0; i < sortedPositions.length; i++) {
- pos = sortedPositions[i];
- bBox = ticks[pos].label && ticks[pos].label.getBBox();
- w = bBox ? bBox.width : 0;
- lineNo = i % autoStaggerLines;
-
- if (w) {
- x = axis.translate(pos);
- if (lastRight[lineNo] !== UNDEFINED && x < lastRight[lineNo]) {
- overlap = true;
- }
- lastRight[lineNo] = x + w;
- }
- }
- if (overlap) {
- autoStaggerLines++;
- } else {
- break;
- }
- }
- if (autoStaggerLines > 1) {
- axis.staggerLines = autoStaggerLines;
- }
- }
- each(tickPositions, function (pos) {
-
- if (side === 0 || side === 2 || { 1: 'left', 3: 'right' }[side] === axis.labelAlign) {
-
- labelOffset = mathMax(
- ticks[pos].getLabelSize(),
- labelOffset
- );
- }
- });
- if (axis.staggerLines) {
- labelOffset *= axis.staggerLines;
- axis.labelOffset = labelOffset;
- }
-
- } else {
- for (n in ticks) {
- ticks[n].destroy();
- delete ticks[n];
- }
- }
- if (axisTitleOptions && axisTitleOptions.text && axisTitleOptions.enabled !== false) {
- if (!axis.axisTitle) {
- axis.axisTitle = renderer.text(
- axisTitleOptions.text,
- 0,
- 0,
- axisTitleOptions.useHTML
- )
- .attr({
- zIndex: 7,
- rotation: axisTitleOptions.rotation || 0,
- align:
- axisTitleOptions.textAlign ||
- { low: 'left', middle: 'center', high: 'right' }[axisTitleOptions.align]
- })
- .css(axisTitleOptions.style)
- .add(axis.axisGroup);
- axis.axisTitle.isNew = true;
- }
- if (showAxis) {
- titleOffset = axis.axisTitle.getBBox()[horiz ? 'height' : 'width'];
- titleMargin = pick(axisTitleOptions.margin, horiz ? 5 : 10);
- titleOffsetOption = axisTitleOptions.offset;
- }
-
- axis.axisTitle[showAxis ? 'show' : 'hide']();
- }
-
-
- axis.offset = directionFactor * pick(options.offset, axisOffset[side]);
-
- axis.axisTitleMargin =
- pick(titleOffsetOption,
- labelOffset + titleMargin +
- (side !== 2 && labelOffset && directionFactor * options.labels[horiz ? 'y' : 'x'])
- );
- axisOffset[side] = mathMax(
- axisOffset[side],
- axis.axisTitleMargin + titleOffset + directionFactor * axis.offset
- );
- clipOffset[invertedSide] = mathMax(clipOffset[invertedSide], mathFloor(options.lineWidth / 2) * 2);
- },
-
-
- getLinePath: function (lineWidth) {
- var chart = this.chart,
- opposite = this.opposite,
- offset = this.offset,
- horiz = this.horiz,
- lineLeft = this.left + (opposite ? this.width : 0) + offset,
- lineTop = chart.chartHeight - this.bottom - (opposite ? this.height : 0) + offset;
-
- if (opposite) {
- lineWidth *= -1;
- }
- return chart.renderer.crispLine([
- M,
- horiz ?
- this.left :
- lineLeft,
- horiz ?
- lineTop :
- this.top,
- L,
- horiz ?
- chart.chartWidth - this.right :
- lineLeft,
- horiz ?
- lineTop :
- chart.chartHeight - this.bottom
- ], lineWidth);
- },
-
-
- getTitlePosition: function () {
-
- var horiz = this.horiz,
- axisLeft = this.left,
- axisTop = this.top,
- axisLength = this.len,
- axisTitleOptions = this.options.title,
- margin = horiz ? axisLeft : axisTop,
- opposite = this.opposite,
- offset = this.offset,
- fontSize = pInt(axisTitleOptions.style.fontSize || 12),
-
-
- alongAxis = {
- low: margin + (horiz ? 0 : axisLength),
- middle: margin + axisLength / 2,
- high: margin + (horiz ? axisLength : 0)
- }[axisTitleOptions.align],
-
-
- offAxis = (horiz ? axisTop + this.height : axisLeft) +
- (horiz ? 1 : -1) *
- (opposite ? -1 : 1) *
- this.axisTitleMargin +
- (this.side === 2 ? fontSize : 0);
- return {
- x: horiz ?
- alongAxis :
- offAxis + (opposite ? this.width : 0) + offset +
- (axisTitleOptions.x || 0),
- y: horiz ?
- offAxis - (opposite ? this.height : 0) + offset :
- alongAxis + (axisTitleOptions.y || 0)
- };
- },
-
-
- render: function () {
- var axis = this,
- chart = axis.chart,
- renderer = chart.renderer,
- options = axis.options,
- isLog = axis.isLog,
- isLinked = axis.isLinked,
- tickPositions = axis.tickPositions,
- axisTitle = axis.axisTitle,
- stacks = axis.stacks,
- ticks = axis.ticks,
- minorTicks = axis.minorTicks,
- alternateBands = axis.alternateBands,
- stackLabelOptions = options.stackLabels,
- alternateGridColor = options.alternateGridColor,
- tickmarkOffset = axis.tickmarkOffset,
- lineWidth = options.lineWidth,
- linePath,
- hasRendered = chart.hasRendered,
- slideInTicks = hasRendered && defined(axis.oldMin) && !isNaN(axis.oldMin),
- hasData = axis.hasData,
- showAxis = axis.showAxis,
- from,
- to;
-
- each([ticks, minorTicks, alternateBands], function (coll) {
- var pos;
- for (pos in coll) {
- coll[pos].isActive = false;
- }
- });
-
- if (hasData || isLinked) {
-
- if (axis.minorTickInterval && !axis.categories) {
- each(axis.getMinorTickPositions(), function (pos) {
- if (!minorTicks[pos]) {
- minorTicks[pos] = new Tick(axis, pos, 'minor');
- }
-
- if (slideInTicks && minorTicks[pos].isNew) {
- minorTicks[pos].render(null, true);
- }
- minorTicks[pos].render(null, false, 1);
- });
- }
-
-
- if (tickPositions.length) {
- each(tickPositions.slice(1).concat([tickPositions[0]]), function (pos, i) {
-
-
- i = (i === tickPositions.length - 1) ? 0 : i + 1;
-
-
- if (!isLinked || (pos >= axis.min && pos <= axis.max)) {
-
- if (!ticks[pos]) {
- ticks[pos] = new Tick(axis, pos);
- }
-
-
- if (slideInTicks && ticks[pos].isNew) {
- ticks[pos].render(i, true);
- }
-
- ticks[pos].render(i, false, 1);
- }
-
- });
-
-
- if (tickmarkOffset && axis.min === 0) {
- if (!ticks[-1]) {
- ticks[-1] = new Tick(axis, -1, null, true);
- }
- ticks[-1].render(-1);
- }
-
- }
-
- if (alternateGridColor) {
- each(tickPositions, function (pos, i) {
- if (i % 2 === 0 && pos < axis.max) {
- if (!alternateBands[pos]) {
- alternateBands[pos] = new PlotLineOrBand(axis);
- }
- from = pos + tickmarkOffset;
- to = tickPositions[i + 1] !== UNDEFINED ? tickPositions[i + 1] + tickmarkOffset : axis.max;
- alternateBands[pos].options = {
- from: isLog ? lin2log(from) : from,
- to: isLog ? lin2log(to) : to,
- color: alternateGridColor
- };
- alternateBands[pos].render();
- alternateBands[pos].isActive = true;
- }
- });
- }
-
- if (!axis._addedPlotLB) {
- each((options.plotLines || []).concat(options.plotBands || []), function (plotLineOptions) {
- axis.addPlotBandOrLine(plotLineOptions);
- });
- axis._addedPlotLB = true;
- }
- }
-
- each([ticks, minorTicks, alternateBands], function (coll) {
- var pos,
- i,
- forDestruction = [],
- delay = globalAnimation ? globalAnimation.duration || 500 : 0,
- destroyInactiveItems = function () {
- i = forDestruction.length;
- while (i--) {
-
-
- if (coll[forDestruction[i]] && !coll[forDestruction[i]].isActive) {
- coll[forDestruction[i]].destroy();
- delete coll[forDestruction[i]];
- }
- }
-
- };
- for (pos in coll) {
- if (!coll[pos].isActive) {
-
- coll[pos].render(pos, false, 0);
- coll[pos].isActive = false;
- forDestruction.push(pos);
- }
- }
-
- if (coll === alternateBands || !chart.hasRendered || !delay) {
- destroyInactiveItems();
- } else if (delay) {
- setTimeout(destroyInactiveItems, delay);
- }
- });
-
-
-
- if (lineWidth) {
- linePath = axis.getLinePath(lineWidth);
- if (!axis.axisLine) {
- axis.axisLine = renderer.path(linePath)
- .attr({
- stroke: options.lineColor,
- 'stroke-width': lineWidth,
- zIndex: 7
- })
- .add(axis.axisGroup);
- } else {
- axis.axisLine.animate({ d: linePath });
- }
-
- axis.axisLine[showAxis ? 'show' : 'hide']();
- }
- if (axisTitle && showAxis) {
-
- axisTitle[axisTitle.isNew ? 'attr' : 'animate'](
- axis.getTitlePosition()
- );
- axisTitle.isNew = false;
- }
-
- if (stackLabelOptions && stackLabelOptions.enabled) {
- var stackKey, oneStack, stackCategory,
- stackTotalGroup = axis.stackTotalGroup;
-
- if (!stackTotalGroup) {
- axis.stackTotalGroup = stackTotalGroup =
- renderer.g('stack-labels')
- .attr({
- visibility: VISIBLE,
- zIndex: 6
- })
- .add();
- }
-
-
- stackTotalGroup.translate(chart.plotLeft, chart.plotTop);
-
- for (stackKey in stacks) {
- oneStack = stacks[stackKey];
- for (stackCategory in oneStack) {
- oneStack[stackCategory].render(stackTotalGroup);
- }
- }
- }
-
- axis.isDirty = false;
- },
-
- removePlotBandOrLine: function (id) {
- var plotLinesAndBands = this.plotLinesAndBands,
- options = this.options,
- userOptions = this.userOptions,
- i = plotLinesAndBands.length;
- while (i--) {
- if (plotLinesAndBands[i].id === id) {
- plotLinesAndBands[i].destroy();
- }
- }
- each([options.plotLines || [], userOptions.plotLines || [], options.plotBands || [], userOptions.plotBands || []], function (arr) {
- i = arr.length;
- while (i--) {
- if (arr[i].id === id) {
- erase(arr, arr[i]);
- }
- }
- });
- },
-
- setTitle: function (newTitleOptions, redraw) {
- this.update({ title: newTitleOptions }, redraw);
- },
-
- redraw: function () {
- var axis = this,
- chart = axis.chart,
- pointer = chart.pointer;
-
- if (pointer.reset) {
- pointer.reset(true);
- }
-
- axis.render();
-
- each(axis.plotLinesAndBands, function (plotLine) {
- plotLine.render();
- });
-
- each(axis.series, function (series) {
- series.isDirty = true;
- });
- },
-
- buildStacks: function () {
- var series = this.series,
- i = series.length;
- if (!this.isXAxis) {
- while (i--) {
- series[i].setStackedPoints();
- }
-
- if (this.usePercentage) {
- for (i = 0; i < series.length; i++) {
- series[i].setPercentStacks();
- }
- }
- }
- },
-
- setCategories: function (categories, redraw) {
- this.update({ categories: categories }, redraw);
- },
-
- destroy: function (keepEvents) {
- var axis = this,
- stacks = axis.stacks,
- stackKey,
- plotLinesAndBands = axis.plotLinesAndBands,
- i;
-
- if (!keepEvents) {
- removeEvent(axis);
- }
-
- for (stackKey in stacks) {
- destroyObjectProperties(stacks[stackKey]);
- stacks[stackKey] = null;
- }
-
- each([axis.ticks, axis.minorTicks, axis.alternateBands], function (coll) {
- destroyObjectProperties(coll);
- });
- i = plotLinesAndBands.length;
- while (i--) {
- plotLinesAndBands[i].destroy();
- }
-
- each(['stackTotalGroup', 'axisLine', 'axisGroup', 'gridGroup', 'labelGroup', 'axisTitle'], function (prop) {
- if (axis[prop]) {
- axis[prop] = axis[prop].destroy();
- }
- });
- }
-
- };
- function Tooltip() {
- this.init.apply(this, arguments);
- }
- Tooltip.prototype = {
- init: function (chart, options) {
- var borderWidth = options.borderWidth,
- style = options.style,
- padding = pInt(style.padding);
-
- this.chart = chart;
- this.options = options;
-
-
-
- this.crosshairs = [];
-
- this.now = { x: 0, y: 0 };
-
- this.isHidden = true;
-
- this.label = chart.renderer.label('', 0, 0, options.shape, null, null, options.useHTML, null, 'tooltip')
- .attr({
- padding: padding,
- fill: options.backgroundColor,
- 'stroke-width': borderWidth,
- r: options.borderRadius,
- zIndex: 8
- })
- .css(style)
- .css({ padding: 0 })
- .add()
- .attr({ y: -999 });
-
-
- if (!useCanVG) {
- this.label.shadow(options.shadow);
- }
-
- this.shared = options.shared;
- },
-
- destroy: function () {
- each(this.crosshairs, function (crosshair) {
- if (crosshair) {
- crosshair.destroy();
- }
- });
-
- if (this.label) {
- this.label = this.label.destroy();
- }
- clearTimeout(this.hideTimer);
- clearTimeout(this.tooltipTimeout);
- },
-
- move: function (x, y, anchorX, anchorY) {
- var tooltip = this,
- now = tooltip.now,
- animate = tooltip.options.animation !== false && !tooltip.isHidden;
-
- extend(now, {
- x: animate ? (2 * now.x + x) / 3 : x,
- y: animate ? (now.y + y) / 2 : y,
- anchorX: animate ? (2 * now.anchorX + anchorX) / 3 : anchorX,
- anchorY: animate ? (now.anchorY + anchorY) / 2 : anchorY
- });
-
- tooltip.label.attr(now);
-
-
- if (animate && (mathAbs(x - now.x) > 1 || mathAbs(y - now.y) > 1)) {
-
-
- clearTimeout(this.tooltipTimeout);
-
-
- this.tooltipTimeout = setTimeout(function () {
-
- if (tooltip) {
- tooltip.move(x, y, anchorX, anchorY);
- }
- }, 32);
-
- }
- },
-
- hide: function () {
- var tooltip = this,
- hoverPoints;
-
- clearTimeout(this.hideTimer);
- if (!this.isHidden) {
- hoverPoints = this.chart.hoverPoints;
- this.hideTimer = setTimeout(function () {
- tooltip.label.fadeOut();
- tooltip.isHidden = true;
- }, pick(this.options.hideDelay, 500));
-
- if (hoverPoints) {
- each(hoverPoints, function (point) {
- point.setState();
- });
- }
- this.chart.hoverPoints = null;
- }
- },
-
- hideCrosshairs: function () {
- each(this.crosshairs, function (crosshair) {
- if (crosshair) {
- crosshair.hide();
- }
- });
- },
-
-
- getAnchor: function (points, mouseEvent) {
- var ret,
- chart = this.chart,
- inverted = chart.inverted,
- plotTop = chart.plotTop,
- plotX = 0,
- plotY = 0,
- yAxis;
-
- points = splat(points);
-
-
- ret = points[0].tooltipPos;
-
-
- if (this.followPointer && mouseEvent) {
- if (mouseEvent.chartX === UNDEFINED) {
- mouseEvent = chart.pointer.normalize(mouseEvent);
- }
- ret = [
- mouseEvent.chartX - chart.plotLeft,
- mouseEvent.chartY - plotTop
- ];
- }
-
- if (!ret) {
- each(points, function (point) {
- yAxis = point.series.yAxis;
- plotX += point.plotX;
- plotY += (point.plotLow ? (point.plotLow + point.plotHigh) / 2 : point.plotY) +
- (!inverted && yAxis ? yAxis.top - plotTop : 0);
- });
-
- plotX /= points.length;
- plotY /= points.length;
-
- ret = [
- inverted ? chart.plotWidth - plotY : plotX,
- this.shared && !inverted && points.length > 1 && mouseEvent ?
- mouseEvent.chartY - plotTop :
- inverted ? chart.plotHeight - plotX : plotY
- ];
- }
- return map(ret, mathRound);
- },
-
-
- getPosition: function (boxWidth, boxHeight, point) {
-
-
- var chart = this.chart,
- plotLeft = chart.plotLeft,
- plotTop = chart.plotTop,
- plotWidth = chart.plotWidth,
- plotHeight = chart.plotHeight,
- distance = pick(this.options.distance, 12),
- pointX = point.plotX,
- pointY = point.plotY,
- x = pointX + plotLeft + (chart.inverted ? distance : -boxWidth - distance),
- y = pointY - boxHeight + plotTop + 15,
- alignedRight;
-
-
- if (x < 7) {
- x = plotLeft + mathMax(pointX, 0) + distance;
- }
-
-
-
- if ((x + boxWidth) > (plotLeft + plotWidth)) {
- x -= (x + boxWidth) - (plotLeft + plotWidth);
- y = pointY - boxHeight + plotTop - distance;
- alignedRight = true;
- }
-
-
- if (y < plotTop + 5) {
- y = plotTop + 5;
-
-
- if (alignedRight && pointY >= y && pointY <= (y + boxHeight)) {
- y = pointY + plotTop + distance;
- }
- }
-
-
-
- if (y + boxHeight > plotTop + plotHeight) {
- y = mathMax(plotTop, plotTop + plotHeight - boxHeight - distance);
- }
-
- return {x: x, y: y};
- },
-
- defaultFormatter: function (tooltip) {
- var items = this.points || splat(this),
- series = items[0].series,
- s;
-
- s = [series.tooltipHeaderFormatter(items[0])];
-
- each(items, function (item) {
- series = item.series;
- s.push((series.tooltipFormatter && series.tooltipFormatter(item)) ||
- item.point.tooltipFormatter(series.tooltipOptions.pointFormat));
- });
-
- s.push(tooltip.options.footerFormat || '');
- return s.join('');
- },
-
- refresh: function (point, mouseEvent) {
- var tooltip = this,
- chart = tooltip.chart,
- label = tooltip.label,
- options = tooltip.options,
- x,
- y,
- anchor,
- textConfig = {},
- text,
- pointConfig = [],
- formatter = options.formatter || tooltip.defaultFormatter,
- hoverPoints = chart.hoverPoints,
- borderColor,
- crosshairsOptions = options.crosshairs,
- shared = tooltip.shared,
- currentSeries;
-
- clearTimeout(this.hideTimer);
-
-
- tooltip.followPointer = splat(point)[0].series.tooltipOptions.followPointer;
- anchor = tooltip.getAnchor(point, mouseEvent);
- x = anchor[0];
- y = anchor[1];
-
- if (shared && !(point.series && point.series.noSharedTooltip)) {
-
-
-
- chart.hoverPoints = point;
- if (hoverPoints) {
- each(hoverPoints, function (point) {
- point.setState();
- });
- }
- each(point, function (item) {
- item.setState(HOVER_STATE);
- pointConfig.push(item.getLabelConfig());
- });
- textConfig = {
- x: point[0].category,
- y: point[0].y
- };
- textConfig.points = pointConfig;
- point = point[0];
-
- } else {
- textConfig = point.getLabelConfig();
- }
- text = formatter.call(textConfig, tooltip);
-
- currentSeries = point.series;
-
- if (text === false) {
- this.hide();
- } else {
-
- if (tooltip.isHidden) {
- stop(label);
- label.attr('opacity', 1).show();
- }
-
- label.attr({
- text: text
- });
-
- borderColor = options.borderColor || point.color || currentSeries.color || '#606060';
- label.attr({
- stroke: borderColor
- });
-
- tooltip.updatePosition({ plotX: x, plotY: y });
-
- this.isHidden = false;
- }
-
- if (crosshairsOptions) {
- crosshairsOptions = splat(crosshairsOptions);
- var path,
- i = crosshairsOptions.length,
- attribs,
- axis,
- val,
- series;
- while (i--) {
- series = point.series;
- axis = series[i ? 'yAxis' : 'xAxis'];
- if (crosshairsOptions[i] && axis) {
- val = i ? pick(point.stackY, point.y) : point.x;
- if (axis.isLog) {
- val = log2lin(val);
- }
- if (i === 1 && series.modifyValue) {
- val = series.modifyValue(val);
- }
- path = axis.getPlotLinePath(
- val,
- 1
- );
- if (tooltip.crosshairs[i]) {
- tooltip.crosshairs[i].attr({ d: path, visibility: VISIBLE });
- } else {
- attribs = {
- 'stroke-width': crosshairsOptions[i].width || 1,
- stroke: crosshairsOptions[i].color || '#C0C0C0',
- zIndex: crosshairsOptions[i].zIndex || 2
- };
- if (crosshairsOptions[i].dashStyle) {
- attribs.dashstyle = crosshairsOptions[i].dashStyle;
- }
- tooltip.crosshairs[i] = chart.renderer.path(path)
- .attr(attribs)
- .add();
- }
- }
- }
- }
- fireEvent(chart, 'tooltipRefresh', {
- text: text,
- x: x + chart.plotLeft,
- y: y + chart.plotTop,
- borderColor: borderColor
- });
- },
-
-
- updatePosition: function (point) {
- var chart = this.chart,
- label = this.label,
- pos = (this.options.positioner || this.getPosition).call(
- this,
- label.width,
- label.height,
- point
- );
-
- this.move(
- mathRound(pos.x),
- mathRound(pos.y),
- point.plotX + chart.plotLeft,
- point.plotY + chart.plotTop
- );
- }
- };
- function Pointer(chart, options) {
- this.init(chart, options);
- }
- Pointer.prototype = {
-
- init: function (chart, options) {
-
- var chartOptions = options.chart,
- chartEvents = chartOptions.events,
- zoomType = useCanVG ? '' : chartOptions.zoomType,
- inverted = chart.inverted,
- zoomX,
- zoomY;
-
- this.options = options;
- this.chart = chart;
-
-
- this.zoomX = zoomX = /x/.test(zoomType);
- this.zoomY = zoomY = /y/.test(zoomType);
- this.zoomHor = (zoomX && !inverted) || (zoomY && inverted);
- this.zoomVert = (zoomY && !inverted) || (zoomX && inverted);
-
- this.runChartClick = chartEvents && !!chartEvents.click;
- this.pinchDown = [];
- this.lastValidTouch = {};
- if (options.tooltip.enabled) {
- chart.tooltip = new Tooltip(chart, options.tooltip);
- }
- this.setDOMEvents();
- },
-
- normalize: function (e, chartPosition) {
- var chartX,
- chartY,
- ePos;
-
- e = e || win.event;
- if (!e.target) {
- e.target = e.srcElement;
- }
-
- e = washMouseEvent(e);
-
-
- ePos = e.touches ? e.touches.item(0) : e;
-
- if (!chartPosition) {
- this.chartPosition = chartPosition = offset(this.chart.container);
- }
-
- if (ePos.pageX === UNDEFINED) {
- chartX = mathMax(e.x, e.clientX - chartPosition.left);
-
- chartY = e.y;
- } else {
- chartX = ePos.pageX - chartPosition.left;
- chartY = ePos.pageY - chartPosition.top;
- }
- return extend(e, {
- chartX: mathRound(chartX),
- chartY: mathRound(chartY)
- });
- },
-
- getCoordinates: function (e) {
- var coordinates = {
- xAxis: [],
- yAxis: []
- };
- each(this.chart.axes, function (axis) {
- coordinates[axis.isXAxis ? 'xAxis' : 'yAxis'].push({
- axis: axis,
- value: axis.toValue(e[axis.horiz ? 'chartX' : 'chartY'])
- });
- });
- return coordinates;
- },
-
-
- getIndex: function (e) {
- var chart = this.chart;
- return chart.inverted ?
- chart.plotHeight + chart.plotTop - e.chartY :
- e.chartX - chart.plotLeft;
- },
-
- runPointActions: function (e) {
- var pointer = this,
- chart = pointer.chart,
- series = chart.series,
- tooltip = chart.tooltip,
- point,
- points,
- hoverPoint = chart.hoverPoint,
- hoverSeries = chart.hoverSeries,
- i,
- j,
- distance = chart.chartWidth,
- index = pointer.getIndex(e),
- anchor;
-
- if (tooltip && pointer.options.tooltip.shared && !(hoverSeries && hoverSeries.noSharedTooltip)) {
- points = [];
-
- i = series.length;
- for (j = 0; j < i; j++) {
- if (series[j].visible &&
- series[j].options.enableMouseTracking !== false &&
- !series[j].noSharedTooltip && series[j].tooltipPoints.length) {
- point = series[j].tooltipPoints[index];
- if (point && point.series) {
- point._dist = mathAbs(index - point.clientX);
- distance = mathMin(distance, point._dist);
- points.push(point);
- }
- }
- }
-
- i = points.length;
- while (i--) {
- if (points[i]._dist > distance) {
- points.splice(i, 1);
- }
- }
-
- if (points.length && (points[0].clientX !== pointer.hoverX)) {
- tooltip.refresh(points, e);
- pointer.hoverX = points[0].clientX;
- }
- }
-
- if (hoverSeries && hoverSeries.tracker) {
-
- point = hoverSeries.tooltipPoints[index];
-
- if (point && point !== hoverPoint) {
-
- point.onMouseOver(e);
- }
-
- } else if (tooltip && tooltip.followPointer && !tooltip.isHidden) {
- anchor = tooltip.getAnchor([{}], e);
- tooltip.updatePosition({ plotX: anchor[0], plotY: anchor[1] });
- }
- },
-
- reset: function (allowMove) {
- var pointer = this,
- chart = pointer.chart,
- hoverSeries = chart.hoverSeries,
- hoverPoint = chart.hoverPoint,
- tooltip = chart.tooltip,
- tooltipPoints = tooltip && tooltip.shared ? chart.hoverPoints : hoverPoint;
-
-
- allowMove = allowMove && tooltip && tooltipPoints;
-
-
- if (allowMove && splat(tooltipPoints)[0].plotX === UNDEFINED) {
- allowMove = false;
- }
-
- if (allowMove) {
- tooltip.refresh(tooltipPoints);
-
- } else {
- if (hoverPoint) {
- hoverPoint.onMouseOut();
- }
- if (hoverSeries) {
- hoverSeries.onMouseOut();
- }
- if (tooltip) {
- tooltip.hide();
- tooltip.hideCrosshairs();
- }
- pointer.hoverX = null;
- }
- },
-
- scaleGroups: function (attribs, clip) {
- var chart = this.chart,
- seriesAttribs;
-
- each(chart.series, function (series) {
- seriesAttribs = attribs || series.getPlotBox();
- if (series.xAxis && series.xAxis.zoomEnabled) {
- series.group.attr(seriesAttribs);
- if (series.markerGroup) {
- series.markerGroup.attr(seriesAttribs);
- series.markerGroup.clip(clip ? chart.clipRect : null);
- }
- if (series.dataLabelsGroup) {
- series.dataLabelsGroup.attr(seriesAttribs);
- }
- }
- });
-
-
- chart.clipRect.attr(clip || chart.clipBox);
- },
-
- pinchTranslateDirection: function (horiz, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch) {
- var chart = this.chart,
- xy = horiz ? 'x' : 'y',
- XY = horiz ? 'X' : 'Y',
- sChartXY = 'chart' + XY,
- wh = horiz ? 'width' : 'height',
- plotLeftTop = chart['plot' + (horiz ? 'Left' : 'Top')],
- selectionWH,
- selectionXY,
- clipXY,
- scale = 1,
- inverted = chart.inverted,
- bounds = chart.bounds[horiz ? 'h' : 'v'],
- singleTouch = pinchDown.length === 1,
- touch0Start = pinchDown[0][sChartXY],
- touch0Now = touches[0][sChartXY],
- touch1Start = !singleTouch && pinchDown[1][sChartXY],
- touch1Now = !singleTouch && touches[1][sChartXY],
- outOfBounds,
- transformScale,
- scaleKey,
- setScale = function () {
- if (!singleTouch && mathAbs(touch0Start - touch1Start) > 20) {
- scale = mathAbs(touch0Now - touch1Now) / mathAbs(touch0Start - touch1Start);
- }
-
- clipXY = ((plotLeftTop - touch0Now) / scale) + touch0Start;
- selectionWH = chart['plot' + (horiz ? 'Width' : 'Height')] / scale;
- };
-
- setScale();
- selectionXY = clipXY;
-
- if (selectionXY < bounds.min) {
- selectionXY = bounds.min;
- outOfBounds = true;
- } else if (selectionXY + selectionWH > bounds.max) {
- selectionXY = bounds.max - selectionWH;
- outOfBounds = true;
- }
-
-
- if (outOfBounds) {
-
-
- touch0Now -= 0.8 * (touch0Now - lastValidTouch[xy][0]);
- if (!singleTouch) {
- touch1Now -= 0.8 * (touch1Now - lastValidTouch[xy][1]);
- }
-
- setScale();
- } else {
- lastValidTouch[xy] = [touch0Now, touch1Now];
- }
-
-
- if (!inverted) {
- clip[xy] = clipXY - plotLeftTop;
- clip[wh] = selectionWH;
- }
- scaleKey = inverted ? (horiz ? 'scaleY' : 'scaleX') : 'scale' + XY;
- transformScale = inverted ? 1 / scale : scale;
- selectionMarker[wh] = selectionWH;
- selectionMarker[xy] = selectionXY;
- transform[scaleKey] = scale;
- transform['translate' + XY] = (transformScale * plotLeftTop) + (touch0Now - (transformScale * touch0Start));
- },
-
-
- pinch: function (e) {
- var self = this,
- chart = self.chart,
- pinchDown = self.pinchDown,
- followTouchMove = chart.tooltip && chart.tooltip.options.followTouchMove,
- touches = e.touches,
- touchesLength = touches.length,
- lastValidTouch = self.lastValidTouch,
- zoomHor = self.zoomHor || self.pinchHor,
- zoomVert = self.zoomVert || self.pinchVert,
- hasZoom = zoomHor || zoomVert,
- selectionMarker = self.selectionMarker,
- transform = {},
- fireClickEvent = touchesLength === 1 && ((self.inClass(e.target, PREFIX + 'tracker') &&
- chart.runTrackerClick) || chart.runChartClick),
- clip = {};
-
- if ((hasZoom || followTouchMove) && !fireClickEvent) {
- e.preventDefault();
- }
-
-
- map(touches, function (e) {
- return self.normalize(e);
- });
-
-
- if (e.type === 'touchstart') {
- each(touches, function (e, i) {
- pinchDown[i] = { chartX: e.chartX, chartY: e.chartY };
- });
- lastValidTouch.x = [pinchDown[0].chartX, pinchDown[1] && pinchDown[1].chartX];
- lastValidTouch.y = [pinchDown[0].chartY, pinchDown[1] && pinchDown[1].chartY];
-
- each(chart.axes, function (axis) {
- if (axis.zoomEnabled) {
- var bounds = chart.bounds[axis.horiz ? 'h' : 'v'],
- minPixelPadding = axis.minPixelPadding,
- min = axis.toPixels(axis.dataMin),
- max = axis.toPixels(axis.dataMax),
- absMin = mathMin(min, max),
- absMax = mathMax(min, max);
-
- bounds.min = mathMin(axis.pos, absMin - minPixelPadding);
- bounds.max = mathMax(axis.pos + axis.len, absMax + minPixelPadding);
- }
- });
-
-
- } else if (pinchDown.length) {
-
-
- if (!selectionMarker) {
- self.selectionMarker = selectionMarker = extend({
- destroy: noop
- }, chart.plotBox);
- }
-
- if (zoomHor) {
- self.pinchTranslateDirection(true, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
- }
- if (zoomVert) {
- self.pinchTranslateDirection(false, pinchDown, touches, transform, selectionMarker, clip, lastValidTouch);
- }
- self.hasPinched = hasZoom;
-
- self.scaleGroups(transform, clip);
-
-
- if (!hasZoom && followTouchMove && touchesLength === 1) {
- this.runPointActions(self.normalize(e));
- }
- }
- },
-
- dragStart: function (e) {
- var chart = this.chart;
-
- chart.mouseIsDown = e.type;
- chart.cancelClick = false;
- chart.mouseDownX = this.mouseDownX = e.chartX;
- chart.mouseDownY = this.mouseDownY = e.chartY;
- },
-
- drag: function (e) {
- var chart = this.chart,
- chartOptions = chart.options.chart,
- chartX = e.chartX,
- chartY = e.chartY,
- zoomHor = this.zoomHor,
- zoomVert = this.zoomVert,
- plotLeft = chart.plotLeft,
- plotTop = chart.plotTop,
- plotWidth = chart.plotWidth,
- plotHeight = chart.plotHeight,
- clickedInside,
- size,
- mouseDownX = this.mouseDownX,
- mouseDownY = this.mouseDownY;
-
-
- if (chartX < plotLeft) {
- chartX = plotLeft;
- } else if (chartX > plotLeft + plotWidth) {
- chartX = plotLeft + plotWidth;
- }
- if (chartY < plotTop) {
- chartY = plotTop;
- } else if (chartY > plotTop + plotHeight) {
- chartY = plotTop + plotHeight;
- }
-
-
- this.hasDragged = Math.sqrt(
- Math.pow(mouseDownX - chartX, 2) +
- Math.pow(mouseDownY - chartY, 2)
- );
- if (this.hasDragged > 10) {
- clickedInside = chart.isInsidePlot(mouseDownX - plotLeft, mouseDownY - plotTop);
-
- if (chart.hasCartesianSeries && (this.zoomX || this.zoomY) && clickedInside) {
- if (!this.selectionMarker) {
- this.selectionMarker = chart.renderer.rect(
- plotLeft,
- plotTop,
- zoomHor ? 1 : plotWidth,
- zoomVert ? 1 : plotHeight,
- 0
- )
- .attr({
- fill: chartOptions.selectionMarkerFill || 'rgba(69,114,167,0.25)',
- zIndex: 7
- })
- .add();
- }
- }
-
- if (this.selectionMarker && zoomHor) {
- size = chartX - mouseDownX;
- this.selectionMarker.attr({
- width: mathAbs(size),
- x: (size > 0 ? 0 : size) + mouseDownX
- });
- }
-
- if (this.selectionMarker && zoomVert) {
- size = chartY - mouseDownY;
- this.selectionMarker.attr({
- height: mathAbs(size),
- y: (size > 0 ? 0 : size) + mouseDownY
- });
- }
-
- if (clickedInside && !this.selectionMarker && chartOptions.panning) {
- chart.pan(e, chartOptions.panning);
- }
- }
- },
-
- drop: function (e) {
- var chart = this.chart,
- hasPinched = this.hasPinched;
- if (this.selectionMarker) {
- var selectionData = {
- xAxis: [],
- yAxis: [],
- originalEvent: e.originalEvent || e
- },
- selectionBox = this.selectionMarker,
- selectionLeft = selectionBox.x,
- selectionTop = selectionBox.y,
- runZoom;
-
- if (this.hasDragged || hasPinched) {
-
- each(chart.axes, function (axis) {
- if (axis.zoomEnabled) {
- var horiz = axis.horiz,
- selectionMin = axis.toValue((horiz ? selectionLeft : selectionTop)),
- selectionMax = axis.toValue((horiz ? selectionLeft + selectionBox.width : selectionTop + selectionBox.height));
- if (!isNaN(selectionMin) && !isNaN(selectionMax)) {
- selectionData[axis.xOrY + 'Axis'].push({
- axis: axis,
- min: mathMin(selectionMin, selectionMax),
- max: mathMax(selectionMin, selectionMax)
- });
- runZoom = true;
- }
- }
- });
- if (runZoom) {
- fireEvent(chart, 'selection', selectionData, function (args) {
- chart.zoom(extend(args, hasPinched ? { animation: false } : null));
- });
- }
- }
- this.selectionMarker = this.selectionMarker.destroy();
-
- if (hasPinched) {
- this.scaleGroups();
- }
- }
-
- if (chart) {
- css(chart.container, { cursor: chart._cursor });
- chart.cancelClick = this.hasDragged > 10;
- chart.mouseIsDown = this.hasDragged = this.hasPinched = false;
- this.pinchDown = [];
- }
- },
- onContainerMouseDown: function (e) {
- e = this.normalize(e);
-
- if (e.preventDefault) {
- e.preventDefault();
- }
-
- this.dragStart(e);
- },
-
- onDocumentMouseUp: function (e) {
- this.drop(e);
- },
-
- onDocumentMouseMove: function (e) {
- var chart = this.chart,
- chartPosition = this.chartPosition,
- hoverSeries = chart.hoverSeries;
- e = this.normalize(e, chartPosition);
-
- if (chartPosition && hoverSeries && !this.inClass(e.target, 'highcharts-tracker') &&
- !chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
- this.reset();
- }
- },
-
- onContainerMouseLeave: function () {
- this.reset();
- this.chartPosition = null;
- },
-
- onContainerMouseMove: function (e) {
- var chart = this.chart;
-
- e = this.normalize(e);
-
- e.returnValue = false;
-
-
- if (chart.mouseIsDown === 'mousedown') {
- this.drag(e);
- }
-
-
- if ((this.inClass(e.target, 'highcharts-tracker') ||
- chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) && !chart.openMenu) {
- this.runPointActions(e);
- }
- },
-
- inClass: function (element, className) {
- var elemClassName;
- while (element) {
- elemClassName = attr(element, 'class');
- if (elemClassName) {
- if (elemClassName.indexOf(className) !== -1) {
- return true;
- } else if (elemClassName.indexOf(PREFIX + 'container') !== -1) {
- return false;
- }
- }
- element = element.parentNode;
- }
- },
- onTrackerMouseOut: function (e) {
- var series = this.chart.hoverSeries;
- if (series && !series.options.stickyTracking && !this.inClass(e.toElement || e.relatedTarget, PREFIX + 'tooltip')) {
- series.onMouseOut();
- }
- },
- onContainerClick: function (e) {
- var chart = this.chart,
- hoverPoint = chart.hoverPoint,
- plotLeft = chart.plotLeft,
- plotTop = chart.plotTop,
- inverted = chart.inverted,
- chartPosition,
- plotX,
- plotY;
-
- e = this.normalize(e);
- e.cancelBubble = true;
- if (!chart.cancelClick) {
-
-
- if (hoverPoint && this.inClass(e.target, PREFIX + 'tracker')) {
- chartPosition = this.chartPosition;
- plotX = hoverPoint.plotX;
- plotY = hoverPoint.plotY;
-
- extend(hoverPoint, {
- pageX: chartPosition.left + plotLeft +
- (inverted ? chart.plotWidth - plotY : plotX),
- pageY: chartPosition.top + plotTop +
- (inverted ? chart.plotHeight - plotX : plotY)
- });
-
-
- fireEvent(hoverPoint.series, 'click', extend(e, {
- point: hoverPoint
- }));
-
- if (chart.hoverPoint) {
- hoverPoint.firePointEvent('click', e);
- }
-
- } else {
- extend(e, this.getCoordinates(e));
-
- if (chart.isInsidePlot(e.chartX - plotLeft, e.chartY - plotTop)) {
- fireEvent(chart, 'click', e);
- }
- }
- }
- },
- onContainerTouchStart: function (e) {
- var chart = this.chart;
- if (e.touches.length === 1) {
- e = this.normalize(e);
- if (chart.isInsidePlot(e.chartX - chart.plotLeft, e.chartY - chart.plotTop)) {
-
-
-
-
- this.runPointActions(e);
- this.pinch(e);
- } else {
-
- this.reset();
- }
- } else if (e.touches.length === 2) {
- this.pinch(e);
- }
- },
- onContainerTouchMove: function (e) {
- if (e.touches.length === 1 || e.touches.length === 2) {
- this.pinch(e);
- }
- },
- onDocumentTouchEnd: function (e) {
- this.drop(e);
- },
-
- setDOMEvents: function () {
- var pointer = this,
- container = pointer.chart.container,
- events;
- this._events = events = [
- [container, 'onmousedown', 'onContainerMouseDown'],
- [container, 'onmousemove', 'onContainerMouseMove'],
- [container, 'onclick', 'onContainerClick'],
- [container, 'mouseleave', 'onContainerMouseLeave'],
- [doc, 'mousemove', 'onDocumentMouseMove'],
- [doc, 'mouseup', 'onDocumentMouseUp']
- ];
- if (hasTouch) {
- events.push(
- [container, 'ontouchstart', 'onContainerTouchStart'],
- [container, 'ontouchmove', 'onContainerTouchMove'],
- [doc, 'touchend', 'onDocumentTouchEnd']
- );
- }
- each(events, function (eventConfig) {
-
- pointer['_' + eventConfig[2]] = function (e) {
- pointer[eventConfig[2]](e);
- };
-
- if (eventConfig[1].indexOf('on') === 0) {
- eventConfig[0][eventConfig[1]] = pointer['_' + eventConfig[2]];
- } else {
- addEvent(eventConfig[0], eventConfig[1], pointer['_' + eventConfig[2]]);
- }
- });
-
- },
-
- destroy: function () {
- var pointer = this;
-
- each(pointer._events, function (eventConfig) {
- if (eventConfig[1].indexOf('on') === 0) {
- eventConfig[0][eventConfig[1]] = null;
- } else {
- removeEvent(eventConfig[0], eventConfig[1], pointer['_' + eventConfig[2]]);
- }
- });
- delete pointer._events;
-
- clearInterval(pointer.tooltipTimeout);
- }
- };
- function Legend(chart, options) {
- this.init(chart, options);
- }
- Legend.prototype = {
-
-
- init: function (chart, options) {
-
- var legend = this,
- itemStyle = options.itemStyle,
- padding = pick(options.padding, 8),
- itemMarginTop = options.itemMarginTop || 0;
-
- this.options = options;
- if (!options.enabled) {
- return;
- }
-
- legend.baseline = pInt(itemStyle.fontSize) + 3 + itemMarginTop;
- legend.itemStyle = itemStyle;
- legend.itemHiddenStyle = merge(itemStyle, options.itemHiddenStyle);
- legend.itemMarginTop = itemMarginTop;
- legend.padding = padding;
- legend.initialItemX = padding;
- legend.initialItemY = padding - 5;
- legend.maxItemWidth = 0;
- legend.chart = chart;
- legend.itemHeight = 0;
- legend.lastLineHeight = 0;
-
- legend.render();
-
- addEvent(legend.chart, 'endResize', function () {
- legend.positionCheckboxes();
- });
- },
-
- colorizeItem: function (item, visible) {
- var legend = this,
- options = legend.options,
- legendItem = item.legendItem,
- legendLine = item.legendLine,
- legendSymbol = item.legendSymbol,
- hiddenColor = legend.itemHiddenStyle.color,
- textColor = visible ? options.itemStyle.color : hiddenColor,
- symbolColor = visible ? item.color : hiddenColor,
- markerOptions = item.options && item.options.marker,
- symbolAttr = {
- stroke: symbolColor,
- fill: symbolColor
- },
- key,
- val;
-
- if (legendItem) {
- legendItem.css({ fill: textColor, color: textColor });
- }
- if (legendLine) {
- legendLine.attr({ stroke: symbolColor });
- }
-
- if (legendSymbol) {
-
-
- if (markerOptions && legendSymbol.isMarker) {
- markerOptions = item.convertAttribs(markerOptions);
- for (key in markerOptions) {
- val = markerOptions[key];
- if (val !== UNDEFINED) {
- symbolAttr[key] = val;
- }
- }
- }
- legendSymbol.attr(symbolAttr);
- }
- },
-
- positionItem: function (item) {
- var legend = this,
- options = legend.options,
- symbolPadding = options.symbolPadding,
- ltr = !options.rtl,
- legendItemPos = item._legendItemPos,
- itemX = legendItemPos[0],
- itemY = legendItemPos[1],
- checkbox = item.checkbox;
- if (item.legendGroup) {
- item.legendGroup.translate(
- ltr ? itemX : legend.legendWidth - itemX - 2 * symbolPadding - 4,
- itemY
- );
- }
- if (checkbox) {
- checkbox.x = itemX;
- checkbox.y = itemY;
- }
- },
-
- destroyItem: function (item) {
- var checkbox = item.checkbox;
-
- each(['legendItem', 'legendLine', 'legendSymbol', 'legendGroup'], function (key) {
- if (item[key]) {
- item[key] = item[key].destroy();
- }
- });
- if (checkbox) {
- discardElement(item.checkbox);
- }
- },
-
- destroy: function () {
- var legend = this,
- legendGroup = legend.group,
- box = legend.box;
- if (box) {
- legend.box = box.destroy();
- }
- if (legendGroup) {
- legend.group = legendGroup.destroy();
- }
- },
-
- positionCheckboxes: function (scrollOffset) {
- var alignAttr = this.group.alignAttr,
- translateY,
- clipHeight = this.clipHeight || this.legendHeight;
- if (alignAttr) {
- translateY = alignAttr.translateY;
- each(this.allItems, function (item) {
- var checkbox = item.checkbox,
- top;
-
- if (checkbox) {
- top = (translateY + checkbox.y + (scrollOffset || 0) + 3);
- css(checkbox, {
- left: (alignAttr.translateX + item.legendItemWidth + checkbox.x - 20) + PX,
- top: top + PX,
- display: top > translateY - 6 && top < translateY + clipHeight - 6 ? '' : NONE
- });
- }
- });
- }
- },
-
-
- renderTitle: function () {
- var options = this.options,
- padding = this.padding,
- titleOptions = options.title,
- titleHeight = 0,
- bBox;
-
- if (titleOptions.text) {
- if (!this.title) {
- this.title = this.chart.renderer.label(titleOptions.text, padding - 3, padding - 4, null, null, null, null, null, 'legend-title')
- .attr({ zIndex: 1 })
- .css(titleOptions.style)
- .add(this.group);
- }
- bBox = this.title.getBBox();
- titleHeight = bBox.height;
- this.offsetWidth = bBox.width;
- this.contentGroup.attr({ translateY: titleHeight });
- }
- this.titleHeight = titleHeight;
- },
-
- renderItem: function (item) {
- var legend = this,
- chart = legend.chart,
- renderer = chart.renderer,
- options = legend.options,
- horizontal = options.layout === 'horizontal',
- symbolWidth = options.symbolWidth,
- symbolPadding = options.symbolPadding,
- itemStyle = legend.itemStyle,
- itemHiddenStyle = legend.itemHiddenStyle,
- padding = legend.padding,
- itemDistance = horizontal ? pick(options.itemDistance, 8) : 0,
- ltr = !options.rtl,
- itemHeight,
- widthOption = options.width,
- itemMarginBottom = options.itemMarginBottom || 0,
- itemMarginTop = legend.itemMarginTop,
- initialItemX = legend.initialItemX,
- bBox,
- itemWidth,
- li = item.legendItem,
- series = item.series || item,
- itemOptions = series.options,
- showCheckbox = itemOptions.showCheckbox,
- useHTML = options.useHTML;
- if (!li) {
-
-
- item.legendGroup = renderer.g('legend-item')
- .attr({ zIndex: 1 })
- .add(legend.scrollGroup);
-
- series.drawLegendSymbol(legend, item);
-
- item.legendItem = li = renderer.text(
- options.labelFormat ? format(options.labelFormat, item) : options.labelFormatter.call(item),
- ltr ? symbolWidth + symbolPadding : -symbolPadding,
- legend.baseline,
- useHTML
- )
- .css(merge(item.visible ? itemStyle : itemHiddenStyle))
- .attr({
- align: ltr ? 'left' : 'right',
- zIndex: 2
- })
- .add(item.legendGroup);
-
- (useHTML ? li : item.legendGroup).on('mouseover', function () {
- item.setState(HOVER_STATE);
- li.css(legend.options.itemHoverStyle);
- })
- .on('mouseout', function () {
- li.css(item.visible ? itemStyle : itemHiddenStyle);
- item.setState();
- })
- .on('click', function (event) {
- var strLegendItemClick = 'legendItemClick',
- fnLegendItemClick = function () {
- item.setVisible();
- };
-
-
- event = {
- browserEvent: event
- };
-
- if (item.firePointEvent) {
- item.firePointEvent(strLegendItemClick, event, fnLegendItemClick);
- } else {
- fireEvent(item, strLegendItemClick, event, fnLegendItemClick);
- }
- });
-
- legend.colorizeItem(item, item.visible);
-
- if (itemOptions && showCheckbox) {
- item.checkbox = createElement('input', {
- type: 'checkbox',
- checked: item.selected,
- defaultChecked: item.selected
- }, options.itemCheckboxStyle, chart.container);
- addEvent(item.checkbox, 'click', function (event) {
- var target = event.target;
- fireEvent(item, 'checkboxClick', {
- checked: target.checked
- },
- function () {
- item.select();
- }
- );
- });
- }
- }
-
- bBox = li.getBBox();
- itemWidth = item.legendItemWidth =
- options.itemWidth || symbolWidth + symbolPadding + bBox.width + itemDistance +
- (showCheckbox ? 20 : 0);
- legend.itemHeight = itemHeight = bBox.height;
-
- if (horizontal && legend.itemX - initialItemX + itemWidth >
- (widthOption || (chart.chartWidth - 2 * padding - initialItemX))) {
- legend.itemX = initialItemX;
- legend.itemY += itemMarginTop + legend.lastLineHeight + itemMarginBottom;
- legend.lastLineHeight = 0;
- }
-
-
-
- legend.maxItemWidth = mathMax(legend.maxItemWidth, itemWidth);
- legend.lastItemY = itemMarginTop + legend.itemY + itemMarginBottom;
- legend.lastLineHeight = mathMax(itemHeight, legend.lastLineHeight);
-
- item._legendItemPos = [legend.itemX, legend.itemY];
-
- if (horizontal) {
- legend.itemX += itemWidth;
- } else {
- legend.itemY += itemMarginTop + itemHeight + itemMarginBottom;
- legend.lastLineHeight = itemHeight;
- }
-
- legend.offsetWidth = widthOption || mathMax(
- (horizontal ? legend.itemX - initialItemX - itemDistance : itemWidth) + padding,
- legend.offsetWidth
- );
- },
-
- render: function () {
- var legend = this,
- chart = legend.chart,
- renderer = chart.renderer,
- legendGroup = legend.group,
- allItems,
- display,
- legendWidth,
- legendHeight,
- box = legend.box,
- options = legend.options,
- padding = legend.padding,
- legendBorderWidth = options.borderWidth,
- legendBackgroundColor = options.backgroundColor;
- legend.itemX = legend.initialItemX;
- legend.itemY = legend.initialItemY;
- legend.offsetWidth = 0;
- legend.lastItemY = 0;
- if (!legendGroup) {
- legend.group = legendGroup = renderer.g('legend')
- .attr({ zIndex: 7 })
- .add();
- legend.contentGroup = renderer.g()
- .attr({ zIndex: 1 })
- .add(legendGroup);
- legend.scrollGroup = renderer.g()
- .add(legend.contentGroup);
- }
-
- legend.renderTitle();
-
- allItems = [];
- each(chart.series, function (serie) {
- var seriesOptions = serie.options;
- if (!seriesOptions.showInLegend || defined(seriesOptions.linkedTo)) {
- return;
- }
-
- allItems = allItems.concat(
- serie.legendItems ||
- (seriesOptions.legendType === 'point' ?
- serie.data :
- serie)
- );
- });
-
- stableSort(allItems, function (a, b) {
- return ((a.options && a.options.legendIndex) || 0) - ((b.options && b.options.legendIndex) || 0);
- });
-
- if (options.reversed) {
- allItems.reverse();
- }
- legend.allItems = allItems;
- legend.display = display = !!allItems.length;
-
- each(allItems, function (item) {
- legend.renderItem(item);
- });
-
- legendWidth = options.width || legend.offsetWidth;
- legendHeight = legend.lastItemY + legend.lastLineHeight + legend.titleHeight;
-
-
- legendHeight = legend.handleOverflow(legendHeight);
- if (legendBorderWidth || legendBackgroundColor) {
- legendWidth += padding;
- legendHeight += padding;
- if (!box) {
- legend.box = box = renderer.rect(
- 0,
- 0,
- legendWidth,
- legendHeight,
- options.borderRadius,
- legendBorderWidth || 0
- ).attr({
- stroke: options.borderColor,
- 'stroke-width': legendBorderWidth || 0,
- fill: legendBackgroundColor || NONE
- })
- .add(legendGroup)
- .shadow(options.shadow);
- box.isNew = true;
- } else if (legendWidth > 0 && legendHeight > 0) {
- box[box.isNew ? 'attr' : 'animate'](
- box.crisp(null, null, null, legendWidth, legendHeight)
- );
- box.isNew = false;
- }
-
- box[display ? 'show' : 'hide']();
- }
-
- legend.legendWidth = legendWidth;
- legend.legendHeight = legendHeight;
-
-
- each(allItems, function (item) {
- legend.positionItem(item);
- });
-
-
- if (display) {
- legendGroup.align(extend({
- width: legendWidth,
- height: legendHeight
- }, options), true, 'spacingBox');
- }
- if (!chart.isResizing) {
- this.positionCheckboxes();
- }
- },
-
-
- handleOverflow: function (legendHeight) {
- var legend = this,
- chart = this.chart,
- renderer = chart.renderer,
- pageCount,
- options = this.options,
- optionsY = options.y,
- alignTop = options.verticalAlign === 'top',
- spaceHeight = chart.spacingBox.height + (alignTop ? -optionsY : optionsY) - this.padding,
- maxHeight = options.maxHeight,
- clipHeight,
- clipRect = this.clipRect,
- navOptions = options.navigation,
- animation = pick(navOptions.animation, true),
- arrowSize = navOptions.arrowSize || 12,
- nav = this.nav;
-
-
- if (options.layout === 'horizontal') {
- spaceHeight /= 2;
- }
- if (maxHeight) {
- spaceHeight = mathMin(spaceHeight, maxHeight);
- }
-
-
- if (legendHeight > spaceHeight && !options.useHTML) {
- this.clipHeight = clipHeight = spaceHeight - 20 - this.titleHeight;
- this.pageCount = pageCount = mathCeil(legendHeight / clipHeight);
- this.currentPage = pick(this.currentPage, 1);
- this.fullHeight = legendHeight;
-
-
- if (!clipRect) {
- clipRect = legend.clipRect = renderer.clipRect(0, 0, 9999, 0);
- legend.contentGroup.clip(clipRect);
- }
- clipRect.attr({
- height: clipHeight
- });
-
-
- if (!nav) {
- this.nav = nav = renderer.g().attr({ zIndex: 1 }).add(this.group);
- this.up = renderer.symbol('triangle', 0, 0, arrowSize, arrowSize)
- .on('click', function () {
- legend.scroll(-1, animation);
- })
- .add(nav);
- this.pager = renderer.text('', 15, 10)
- .css(navOptions.style)
- .add(nav);
- this.down = renderer.symbol('triangle-down', 0, 0, arrowSize, arrowSize)
- .on('click', function () {
- legend.scroll(1, animation);
- })
- .add(nav);
- }
-
-
- legend.scroll(0);
-
- legendHeight = spaceHeight;
-
- } else if (nav) {
- clipRect.attr({
- height: chart.chartHeight
- });
- nav.hide();
- this.scrollGroup.attr({
- translateY: 1
- });
- this.clipHeight = 0;
- }
-
- return legendHeight;
- },
-
-
- scroll: function (scrollBy, animation) {
- var pageCount = this.pageCount,
- currentPage = this.currentPage + scrollBy,
- clipHeight = this.clipHeight,
- navOptions = this.options.navigation,
- activeColor = navOptions.activeColor,
- inactiveColor = navOptions.inactiveColor,
- pager = this.pager,
- padding = this.padding,
- scrollOffset;
-
-
- if (currentPage > pageCount) {
- currentPage = pageCount;
- }
-
- if (currentPage > 0) {
-
- if (animation !== UNDEFINED) {
- setAnimation(animation, this.chart);
- }
-
- this.nav.attr({
- translateX: padding,
- translateY: clipHeight + 7 + this.titleHeight,
- visibility: VISIBLE
- });
- this.up.attr({
- fill: currentPage === 1 ? inactiveColor : activeColor
- })
- .css({
- cursor: currentPage === 1 ? 'default' : 'pointer'
- });
- pager.attr({
- text: currentPage + '/' + this.pageCount
- });
- this.down.attr({
- x: 18 + this.pager.getBBox().width,
- fill: currentPage === pageCount ? inactiveColor : activeColor
- })
- .css({
- cursor: currentPage === pageCount ? 'default' : 'pointer'
- });
-
- scrollOffset = -mathMin(clipHeight * (currentPage - 1), this.fullHeight - clipHeight + padding) + 1;
- this.scrollGroup.animate({
- translateY: scrollOffset
- });
- pager.attr({
- text: currentPage + '/' + pageCount
- });
-
-
- this.currentPage = currentPage;
- this.positionCheckboxes(scrollOffset);
- }
-
- }
-
- };
- if (/Trident.*?11\.0/.test(userAgent)) {
- wrap(Legend.prototype, 'positionItem', function (proceed, item) {
- var legend = this;
- setTimeout(function () {
- proceed.call(legend, item);
- });
- });
- }
- function Chart() {
- this.init.apply(this, arguments);
- }
- Chart.prototype = {
-
- init: function (userOptions, callback) {
-
- var options,
- seriesOptions = userOptions.series;
- userOptions.series = null;
- options = merge(defaultOptions, userOptions);
- options.series = userOptions.series = seriesOptions;
- var optionsChart = options.chart;
-
-
- this.margin = this.splashArray('margin', optionsChart);
- this.spacing = this.splashArray('spacing', optionsChart);
- var chartEvents = optionsChart.events;
-
- this.bounds = { h: {}, v: {} };
- this.callback = callback;
- this.isResizing = 0;
- this.options = options;
-
-
- this.axes = [];
- this.series = [];
- this.hasCartesianSeries = optionsChart.showAxes;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- var chart = this,
- eventType;
-
- chart.index = charts.length;
- charts.push(chart);
-
- if (optionsChart.reflow !== false) {
- addEvent(chart, 'load', function () {
- chart.initReflow();
- });
- }
-
- if (chartEvents) {
- for (eventType in chartEvents) {
- addEvent(chart, eventType, chartEvents[eventType]);
- }
- }
- chart.xAxis = [];
- chart.yAxis = [];
-
- chart.animation = useCanVG ? false : pick(optionsChart.animation, true);
- chart.pointCount = 0;
- chart.counters = new ChartCounters();
- chart.firstRender();
- },
-
- initSeries: function (options) {
- var chart = this,
- optionsChart = chart.options.chart,
- type = options.type || optionsChart.type || optionsChart.defaultSeriesType,
- series,
- constr = seriesTypes[type];
-
- if (!constr) {
- error(17, true);
- }
- series = new constr();
- series.init(this, options);
- return series;
- },
-
- addSeries: function (options, redraw, animation) {
- var series,
- chart = this;
- if (options) {
- redraw = pick(redraw, true);
- fireEvent(chart, 'addSeries', { options: options }, function () {
- series = chart.initSeries(options);
-
- chart.isDirtyLegend = true;
- chart.linkSeries();
- if (redraw) {
- chart.redraw(animation);
- }
- });
- }
- return series;
- },
-
- addAxis: function (options, isX, redraw, animation) {
- var key = isX ? 'xAxis' : 'yAxis',
- chartOptions = this.options,
- axis;
-
- axis = new Axis(this, merge(options, {
- index: this[key].length,
- isX: isX
- }));
-
-
- chartOptions[key] = splat(chartOptions[key] || {});
- chartOptions[key].push(options);
- if (pick(redraw, true)) {
- this.redraw(animation);
- }
- },
-
- isInsidePlot: function (plotX, plotY, inverted) {
- var x = inverted ? plotY : plotX,
- y = inverted ? plotX : plotY;
-
- return x >= 0 &&
- x <= this.plotWidth &&
- y >= 0 &&
- y <= this.plotHeight;
- },
-
- adjustTickAmounts: function () {
- if (this.options.chart.alignTicks !== false) {
- each(this.axes, function (axis) {
- axis.adjustTickAmount();
- });
- }
- this.maxTicks = null;
- },
-
- redraw: function (animation) {
- var chart = this,
- axes = chart.axes,
- series = chart.series,
- pointer = chart.pointer,
- legend = chart.legend,
- redrawLegend = chart.isDirtyLegend,
- hasStackedSeries,
- hasDirtyStacks,
- isDirtyBox = chart.isDirtyBox,
- seriesLength = series.length,
- i = seriesLength,
- serie,
- renderer = chart.renderer,
- isHiddenChart = renderer.isHidden(),
- afterRedraw = [];
-
- setAnimation(animation, chart);
-
- if (isHiddenChart) {
- chart.cloneRenderTo();
- }
-
- chart.layOutTitles();
-
- while (i--) {
- serie = series[i];
- if (serie.options.stacking) {
- hasStackedSeries = true;
-
- if (serie.isDirty) {
- hasDirtyStacks = true;
- break;
- }
- }
- }
- if (hasDirtyStacks) {
- i = seriesLength;
- while (i--) {
- serie = series[i];
- if (serie.options.stacking) {
- serie.isDirty = true;
- }
- }
- }
-
- each(series, function (serie) {
- if (serie.isDirty) {
- if (serie.options.legendType === 'point') {
- redrawLegend = true;
- }
- }
- });
-
- if (redrawLegend && legend.options.enabled) {
-
- legend.render();
- chart.isDirtyLegend = false;
- }
-
- if (hasStackedSeries) {
- chart.getStacks();
- }
- if (chart.hasCartesianSeries) {
- if (!chart.isResizing) {
-
- chart.maxTicks = null;
-
- each(axes, function (axis) {
- axis.setScale();
- });
- }
- chart.adjustTickAmounts();
- chart.getMargins();
-
- each(axes, function (axis) {
- if (axis.isDirty) {
- isDirtyBox = true;
- }
- });
-
- each(axes, function (axis) {
-
-
- if (axis.isDirtyExtremes) {
- axis.isDirtyExtremes = false;
- afterRedraw.push(function () {
- fireEvent(axis, 'afterSetExtremes', extend(axis.eventArgs, axis.getExtremes()));
- delete axis.eventArgs;
- });
- }
-
- if (isDirtyBox || hasStackedSeries) {
- axis.redraw();
- }
- });
- }
-
- if (isDirtyBox) {
- chart.drawChartBox();
- }
-
- each(series, function (serie) {
- if (serie.isDirty && serie.visible &&
- (!serie.isCartesian || serie.xAxis)) {
- serie.redraw();
- }
- });
-
- if (pointer && pointer.reset) {
- pointer.reset(true);
- }
-
- renderer.draw();
-
- fireEvent(chart, 'redraw');
-
- if (isHiddenChart) {
- chart.cloneRenderTo(true);
- }
-
-
- each(afterRedraw, function (callback) {
- callback.call();
- });
- },
-
- showLoading: function (str) {
- var chart = this,
- options = chart.options,
- loadingDiv = chart.loadingDiv;
- var loadingOptions = options.loading;
-
- if (!loadingDiv) {
- chart.loadingDiv = loadingDiv = createElement(DIV, {
- className: PREFIX + 'loading'
- }, extend(loadingOptions.style, {
- zIndex: 10,
- display: NONE
- }), chart.container);
- chart.loadingSpan = createElement(
- 'span',
- null,
- loadingOptions.labelStyle,
- loadingDiv
- );
- }
-
- chart.loadingSpan.innerHTML = str || options.lang.loading;
-
- if (!chart.loadingShown) {
- css(loadingDiv, {
- opacity: 0,
- display: '',
- left: chart.plotLeft + PX,
- top: chart.plotTop + PX,
- width: chart.plotWidth + PX,
- height: chart.plotHeight + PX
- });
- animate(loadingDiv, {
- opacity: loadingOptions.style.opacity
- }, {
- duration: loadingOptions.showDuration || 0
- });
- chart.loadingShown = true;
- }
- },
-
- hideLoading: function () {
- var options = this.options,
- loadingDiv = this.loadingDiv;
- if (loadingDiv) {
- animate(loadingDiv, {
- opacity: 0
- }, {
- duration: options.loading.hideDuration || 100,
- complete: function () {
- css(loadingDiv, { display: NONE });
- }
- });
- }
- this.loadingShown = false;
- },
-
- get: function (id) {
- var chart = this,
- axes = chart.axes,
- series = chart.series;
- var i,
- j,
- points;
-
- for (i = 0; i < axes.length; i++) {
- if (axes[i].options.id === id) {
- return axes[i];
- }
- }
-
- for (i = 0; i < series.length; i++) {
- if (series[i].options.id === id) {
- return series[i];
- }
- }
-
- for (i = 0; i < series.length; i++) {
- points = series[i].points || [];
- for (j = 0; j < points.length; j++) {
- if (points[j].id === id) {
- return points[j];
- }
- }
- }
- return null;
- },
-
- getAxes: function () {
- var chart = this,
- options = this.options,
- xAxisOptions = options.xAxis = splat(options.xAxis || {}),
- yAxisOptions = options.yAxis = splat(options.yAxis || {}),
- optionsArray,
- axis;
-
- each(xAxisOptions, function (axis, i) {
- axis.index = i;
- axis.isX = true;
- });
- each(yAxisOptions, function (axis, i) {
- axis.index = i;
- });
-
- optionsArray = xAxisOptions.concat(yAxisOptions);
- each(optionsArray, function (axisOptions) {
- axis = new Axis(chart, axisOptions);
- });
- chart.adjustTickAmounts();
- },
-
- getSelectedPoints: function () {
- var points = [];
- each(this.series, function (serie) {
- points = points.concat(grep(serie.points || [], function (point) {
- return point.selected;
- }));
- });
- return points;
- },
-
- getSelectedSeries: function () {
- return grep(this.series, function (serie) {
- return serie.selected;
- });
- },
-
- getStacks: function () {
- var chart = this;
-
- each(chart.yAxis, function (axis) {
- if (axis.stacks && axis.hasVisibleSeries) {
- axis.oldStacks = axis.stacks;
- }
- });
- each(chart.series, function (series) {
- if (series.options.stacking && (series.visible === true || chart.options.chart.ignoreHiddenSeries === false)) {
- series.stackKey = series.type + pick(series.options.stack, '');
- }
- });
- },
-
- showResetZoom: function () {
- var chart = this,
- lang = defaultOptions.lang,
- btnOptions = chart.options.chart.resetZoomButton,
- theme = btnOptions.theme,
- states = theme.states,
- alignTo = btnOptions.relativeTo === 'chart' ? null : 'plotBox';
-
- this.resetZoomButton = chart.renderer.button(lang.resetZoom, null, null, function () { chart.zoomOut(); }, theme, states && states.hover)
- .attr({
- align: btnOptions.position.align,
- title: lang.resetZoomTitle
- })
- .add()
- .align(btnOptions.position, false, alignTo);
-
- },
-
- zoomOut: function () {
- var chart = this;
- fireEvent(chart, 'selection', { resetSelection: true }, function () {
- chart.zoom();
- });
- },
-
- zoom: function (event) {
- var chart = this,
- hasZoomed,
- pointer = chart.pointer,
- displayButton = false,
- resetZoomButton;
-
- if (!event || event.resetSelection) {
- each(chart.axes, function (axis) {
- hasZoomed = axis.zoom();
- });
- } else {
- each(event.xAxis.concat(event.yAxis), function (axisData) {
- var axis = axisData.axis,
- isXAxis = axis.isXAxis;
-
- if (pointer[isXAxis ? 'zoomX' : 'zoomY'] || pointer[isXAxis ? 'pinchX' : 'pinchY']) {
- hasZoomed = axis.zoom(axisData.min, axisData.max);
- if (axis.displayBtn) {
- displayButton = true;
- }
- }
- });
- }
-
-
- resetZoomButton = chart.resetZoomButton;
- if (displayButton && !resetZoomButton) {
- chart.showResetZoom();
- } else if (!displayButton && isObject(resetZoomButton)) {
- chart.resetZoomButton = resetZoomButton.destroy();
- }
-
-
- if (hasZoomed) {
- chart.redraw(
- pick(chart.options.chart.animation, event && event.animation, chart.pointCount < 100)
- );
- }
- },
-
- pan: function (e, panning) {
- var chart = this,
- hoverPoints = chart.hoverPoints,
- doRedraw;
-
- if (hoverPoints) {
- each(hoverPoints, function (point) {
- point.setState();
- });
- }
- each(panning === 'xy' ? [1, 0] : [1], function (isX) {
- var mousePos = e[isX ? 'chartX' : 'chartY'],
- axis = chart[isX ? 'xAxis' : 'yAxis'][0],
- startPos = chart[isX ? 'mouseDownX' : 'mouseDownY'],
- halfPointRange = (axis.pointRange || 0) / 2,
- extremes = axis.getExtremes(),
- newMin = axis.toValue(startPos - mousePos, true) + halfPointRange,
- newMax = axis.toValue(startPos + chart[isX ? 'plotWidth' : 'plotHeight'] - mousePos, true) - halfPointRange;
- if (axis.series.length && newMin > mathMin(extremes.dataMin, extremes.min) && newMax < mathMax(extremes.dataMax, extremes.max)) {
- axis.setExtremes(newMin, newMax, false, false, { trigger: 'pan' });
- doRedraw = true;
- }
- chart[isX ? 'mouseDownX' : 'mouseDownY'] = mousePos;
- });
- if (doRedraw) {
- chart.redraw(false);
- }
- css(chart.container, { cursor: 'move' });
- },
-
- setTitle: function (titleOptions, subtitleOptions) {
- var chart = this,
- options = chart.options,
- chartTitleOptions,
- chartSubtitleOptions;
- chartTitleOptions = options.title = merge(options.title, titleOptions);
- chartSubtitleOptions = options.subtitle = merge(options.subtitle, subtitleOptions);
-
- each([
- ['title', titleOptions, chartTitleOptions],
- ['subtitle', subtitleOptions, chartSubtitleOptions]
- ], function (arr) {
- var name = arr[0],
- title = chart[name],
- titleOptions = arr[1],
- chartTitleOptions = arr[2];
- if (title && titleOptions) {
- chart[name] = title = title.destroy();
- }
-
- if (chartTitleOptions && chartTitleOptions.text && !title) {
- chart[name] = chart.renderer.text(
- chartTitleOptions.text,
- 0,
- 0,
- chartTitleOptions.useHTML
- )
- .attr({
- align: chartTitleOptions.align,
- 'class': PREFIX + name,
- zIndex: chartTitleOptions.zIndex || 4
- })
- .css(chartTitleOptions.style)
- .add();
- }
- });
- chart.layOutTitles();
- },
-
- layOutTitles: function () {
- var titleOffset = 0,
- title = this.title,
- subtitle = this.subtitle,
- options = this.options,
- titleOptions = options.title,
- subtitleOptions = options.subtitle,
- autoWidth = this.spacingBox.width - 44;
- if (title) {
- title
- .css({ width: (titleOptions.width || autoWidth) + PX })
- .align(extend({ y: 15 }, titleOptions), false, 'spacingBox');
-
- if (!titleOptions.floating && !titleOptions.verticalAlign) {
- titleOffset = title.getBBox().height;
-
- if (titleOffset >= 18 && titleOffset <= 25) {
- titleOffset = 15;
- }
- }
- }
- if (subtitle) {
- subtitle
- .css({ width: (subtitleOptions.width || autoWidth) + PX })
- .align(extend({ y: titleOffset + titleOptions.margin }, subtitleOptions), false, 'spacingBox');
-
- if (!subtitleOptions.floating && !subtitleOptions.verticalAlign) {
- titleOffset = mathCeil(titleOffset + subtitle.getBBox().height);
- }
- }
- this.titleOffset = titleOffset;
- },
-
- getChartSize: function () {
- var chart = this,
- optionsChart = chart.options.chart,
- renderTo = chart.renderToClone || chart.renderTo;
-
- chart.containerWidth = adapterRun(renderTo, 'width');
- chart.containerHeight = adapterRun(renderTo, 'height');
-
- chart.chartWidth = mathMax(0, optionsChart.width || chart.containerWidth || 600);
- chart.chartHeight = mathMax(0, pick(optionsChart.height,
-
- chart.containerHeight > 19 ? chart.containerHeight : 400));
- },
-
- cloneRenderTo: function (revert) {
- var clone = this.renderToClone,
- container = this.container;
-
-
- if (revert) {
- if (clone) {
- this.renderTo.appendChild(container);
- discardElement(clone);
- delete this.renderToClone;
- }
-
-
- } else {
- if (container && container.parentNode === this.renderTo) {
- this.renderTo.removeChild(container);
- }
- this.renderToClone = clone = this.renderTo.cloneNode(0);
- css(clone, {
- position: ABSOLUTE,
- top: '-9999px',
- display: 'block'
- });
- doc.body.appendChild(clone);
- if (container) {
- clone.appendChild(container);
- }
- }
- },
-
- getContainer: function () {
- var chart = this,
- container,
- optionsChart = chart.options.chart,
- chartWidth,
- chartHeight,
- renderTo,
- indexAttrName = 'data-highcharts-chart',
- oldChartIndex,
- containerId;
- chart.renderTo = renderTo = optionsChart.renderTo;
- containerId = PREFIX + idCounter++;
- if (isString(renderTo)) {
- chart.renderTo = renderTo = doc.getElementById(renderTo);
- }
-
-
- if (!renderTo) {
- error(13, true);
- }
-
-
- oldChartIndex = pInt(attr(renderTo, indexAttrName));
- if (!isNaN(oldChartIndex) && charts[oldChartIndex]) {
- charts[oldChartIndex].destroy();
- }
-
-
- attr(renderTo, indexAttrName, chart.index);
-
- renderTo.innerHTML = '';
-
-
-
-
- if (!renderTo.offsetWidth) {
- chart.cloneRenderTo();
- }
-
- chart.getChartSize();
- chartWidth = chart.chartWidth;
- chartHeight = chart.chartHeight;
-
- chart.container = container = createElement(DIV, {
- className: PREFIX + 'container' +
- (optionsChart.className ? ' ' + optionsChart.className : ''),
- id: containerId
- }, extend({
- position: RELATIVE,
- overflow: HIDDEN,
-
- width: chartWidth + PX,
- height: chartHeight + PX,
- textAlign: 'left',
- lineHeight: 'normal',
- zIndex: 0,
- '-webkit-tap-highlight-color': 'rgba(0,0,0,0)'
- }, optionsChart.style),
- chart.renderToClone || renderTo
- );
-
- chart._cursor = container.style.cursor;
- chart.renderer =
- optionsChart.forExport ?
- new SVGRenderer(container, chartWidth, chartHeight, true) :
- new Renderer(container, chartWidth, chartHeight);
- if (useCanVG) {
-
-
- chart.renderer.create(chart, container, chartWidth, chartHeight);
- }
- },
-
- getMargins: function () {
- var chart = this,
- spacing = chart.spacing,
- axisOffset,
- legend = chart.legend,
- margin = chart.margin,
- legendOptions = chart.options.legend,
- legendMargin = pick(legendOptions.margin, 10),
- legendX = legendOptions.x,
- legendY = legendOptions.y,
- align = legendOptions.align,
- verticalAlign = legendOptions.verticalAlign,
- titleOffset = chart.titleOffset;
- chart.resetMargins();
- axisOffset = chart.axisOffset;
-
- if (titleOffset && !defined(margin[0])) {
- chart.plotTop = mathMax(chart.plotTop, titleOffset + chart.options.title.margin + spacing[0]);
- }
-
-
- if (legend.display && !legendOptions.floating) {
- if (align === 'right') {
- if (!defined(margin[1])) {
- chart.marginRight = mathMax(
- chart.marginRight,
- legend.legendWidth - legendX + legendMargin + spacing[1]
- );
- }
- } else if (align === 'left') {
- if (!defined(margin[3])) {
- chart.plotLeft = mathMax(
- chart.plotLeft,
- legend.legendWidth + legendX + legendMargin + spacing[3]
- );
- }
- } else if (verticalAlign === 'top') {
- if (!defined(margin[0])) {
- chart.plotTop = mathMax(
- chart.plotTop,
- legend.legendHeight + legendY + legendMargin + spacing[0]
- );
- }
- } else if (verticalAlign === 'bottom') {
- if (!defined(margin[2])) {
- chart.marginBottom = mathMax(
- chart.marginBottom,
- legend.legendHeight - legendY + legendMargin + spacing[2]
- );
- }
- }
- }
-
- if (chart.extraBottomMargin) {
- chart.marginBottom += chart.extraBottomMargin;
- }
- if (chart.extraTopMargin) {
- chart.plotTop += chart.extraTopMargin;
- }
-
- if (chart.hasCartesianSeries) {
- each(chart.axes, function (axis) {
- axis.getOffset();
- });
- }
-
- if (!defined(margin[3])) {
- chart.plotLeft += axisOffset[3];
- }
- if (!defined(margin[0])) {
- chart.plotTop += axisOffset[0];
- }
- if (!defined(margin[2])) {
- chart.marginBottom += axisOffset[2];
- }
- if (!defined(margin[1])) {
- chart.marginRight += axisOffset[1];
- }
- chart.setChartSize();
- },
-
- initReflow: function () {
- var chart = this,
- optionsChart = chart.options.chart,
- renderTo = chart.renderTo,
- reflowTimeout;
-
- function reflow(e) {
- var width = optionsChart.width || adapterRun(renderTo, 'width'),
- height = optionsChart.height || adapterRun(renderTo, 'height'),
- target = e ? e.target : win;
-
-
-
- if (!chart.hasUserSize && width && height && (target === win || target === doc)) {
-
- if (width !== chart.containerWidth || height !== chart.containerHeight) {
- clearTimeout(reflowTimeout);
- chart.reflowTimeout = reflowTimeout = setTimeout(function () {
- if (chart.container) {
- chart.setSize(width, height, false);
- chart.hasUserSize = null;
- }
- }, 100);
- }
- chart.containerWidth = width;
- chart.containerHeight = height;
- }
- }
- chart.reflow = reflow;
- addEvent(win, 'resize', reflow);
- addEvent(chart, 'destroy', function () {
- removeEvent(win, 'resize', reflow);
- });
- },
-
- setSize: function (width, height, animation) {
- var chart = this,
- chartWidth,
- chartHeight,
- fireEndResize;
-
- chart.isResizing += 1;
- fireEndResize = function () {
- if (chart) {
- fireEvent(chart, 'endResize', null, function () {
- chart.isResizing -= 1;
- });
- }
- };
-
- setAnimation(animation, chart);
- chart.oldChartHeight = chart.chartHeight;
- chart.oldChartWidth = chart.chartWidth;
- if (defined(width)) {
- chart.chartWidth = chartWidth = mathMax(0, mathRound(width));
- chart.hasUserSize = !!chartWidth;
- }
- if (defined(height)) {
- chart.chartHeight = chartHeight = mathMax(0, mathRound(height));
- }
- css(chart.container, {
- width: chartWidth + PX,
- height: chartHeight + PX
- });
- chart.setChartSize(true);
- chart.renderer.setSize(chartWidth, chartHeight, animation);
-
- chart.maxTicks = null;
- each(chart.axes, function (axis) {
- axis.isDirty = true;
- axis.setScale();
- });
-
- each(chart.series, function (serie) {
- serie.isDirty = true;
- });
- chart.isDirtyLegend = true;
- chart.isDirtyBox = true;
- chart.getMargins();
- chart.redraw(animation);
- chart.oldChartHeight = null;
- fireEvent(chart, 'resize');
-
-
- if (globalAnimation === false) {
- fireEndResize();
- } else {
- setTimeout(fireEndResize, (globalAnimation && globalAnimation.duration) || 500);
- }
- },
-
- setChartSize: function (skipAxes) {
- var chart = this,
- inverted = chart.inverted,
- renderer = chart.renderer,
- chartWidth = chart.chartWidth,
- chartHeight = chart.chartHeight,
- optionsChart = chart.options.chart,
- spacing = chart.spacing,
- clipOffset = chart.clipOffset,
- clipX,
- clipY,
- plotLeft,
- plotTop,
- plotWidth,
- plotHeight,
- plotBorderWidth;
- chart.plotLeft = plotLeft = mathRound(chart.plotLeft);
- chart.plotTop = plotTop = mathRound(chart.plotTop);
- chart.plotWidth = plotWidth = mathMax(0, mathRound(chartWidth - plotLeft - chart.marginRight));
- chart.plotHeight = plotHeight = mathMax(0, mathRound(chartHeight - plotTop - chart.marginBottom));
- chart.plotSizeX = inverted ? plotHeight : plotWidth;
- chart.plotSizeY = inverted ? plotWidth : plotHeight;
-
- chart.plotBorderWidth = optionsChart.plotBorderWidth || 0;
-
- chart.spacingBox = renderer.spacingBox = {
- x: spacing[3],
- y: spacing[0],
- width: chartWidth - spacing[3] - spacing[1],
- height: chartHeight - spacing[0] - spacing[2]
- };
- chart.plotBox = renderer.plotBox = {
- x: plotLeft,
- y: plotTop,
- width: plotWidth,
- height: plotHeight
- };
- plotBorderWidth = 2 * mathFloor(chart.plotBorderWidth / 2);
- clipX = mathCeil(mathMax(plotBorderWidth, clipOffset[3]) / 2);
- clipY = mathCeil(mathMax(plotBorderWidth, clipOffset[0]) / 2);
- chart.clipBox = {
- x: clipX,
- y: clipY,
- width: mathFloor(chart.plotSizeX - mathMax(plotBorderWidth, clipOffset[1]) / 2 - clipX),
- height: mathFloor(chart.plotSizeY - mathMax(plotBorderWidth, clipOffset[2]) / 2 - clipY)
- };
- if (!skipAxes) {
- each(chart.axes, function (axis) {
- axis.setAxisSize();
- axis.setAxisTranslation();
- });
- }
- },
-
- resetMargins: function () {
- var chart = this,
- spacing = chart.spacing,
- margin = chart.margin;
- chart.plotTop = pick(margin[0], spacing[0]);
- chart.marginRight = pick(margin[1], spacing[1]);
- chart.marginBottom = pick(margin[2], spacing[2]);
- chart.plotLeft = pick(margin[3], spacing[3]);
- chart.axisOffset = [0, 0, 0, 0];
- chart.clipOffset = [0, 0, 0, 0];
- },
-
- drawChartBox: function () {
- var chart = this,
- optionsChart = chart.options.chart,
- renderer = chart.renderer,
- chartWidth = chart.chartWidth,
- chartHeight = chart.chartHeight,
- chartBackground = chart.chartBackground,
- plotBackground = chart.plotBackground,
- plotBorder = chart.plotBorder,
- plotBGImage = chart.plotBGImage,
- chartBorderWidth = optionsChart.borderWidth || 0,
- chartBackgroundColor = optionsChart.backgroundColor,
- plotBackgroundColor = optionsChart.plotBackgroundColor,
- plotBackgroundImage = optionsChart.plotBackgroundImage,
- plotBorderWidth = optionsChart.plotBorderWidth || 0,
- mgn,
- bgAttr,
- plotLeft = chart.plotLeft,
- plotTop = chart.plotTop,
- plotWidth = chart.plotWidth,
- plotHeight = chart.plotHeight,
- plotBox = chart.plotBox,
- clipRect = chart.clipRect,
- clipBox = chart.clipBox;
-
- mgn = chartBorderWidth + (optionsChart.shadow ? 8 : 0);
- if (chartBorderWidth || chartBackgroundColor) {
- if (!chartBackground) {
-
- bgAttr = {
- fill: chartBackgroundColor || NONE
- };
- if (chartBorderWidth) {
- bgAttr.stroke = optionsChart.borderColor;
- bgAttr['stroke-width'] = chartBorderWidth;
- }
- chart.chartBackground = renderer.rect(mgn / 2, mgn / 2, chartWidth - mgn, chartHeight - mgn,
- optionsChart.borderRadius, chartBorderWidth)
- .attr(bgAttr)
- .add()
- .shadow(optionsChart.shadow);
- } else {
- chartBackground.animate(
- chartBackground.crisp(null, null, null, chartWidth - mgn, chartHeight - mgn)
- );
- }
- }
-
- if (plotBackgroundColor) {
- if (!plotBackground) {
- chart.plotBackground = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0)
- .attr({
- fill: plotBackgroundColor
- })
- .add()
- .shadow(optionsChart.plotShadow);
- } else {
- plotBackground.animate(plotBox);
- }
- }
- if (plotBackgroundImage) {
- if (!plotBGImage) {
- chart.plotBGImage = renderer.image(plotBackgroundImage, plotLeft, plotTop, plotWidth, plotHeight)
- .add();
- } else {
- plotBGImage.animate(plotBox);
- }
- }
-
-
- if (!clipRect) {
- chart.clipRect = renderer.clipRect(clipBox);
- } else {
- clipRect.animate({
- width: clipBox.width,
- height: clipBox.height
- });
- }
-
- if (plotBorderWidth) {
- if (!plotBorder) {
- chart.plotBorder = renderer.rect(plotLeft, plotTop, plotWidth, plotHeight, 0, -plotBorderWidth)
- .attr({
- stroke: optionsChart.plotBorderColor,
- 'stroke-width': plotBorderWidth,
- zIndex: 1
- })
- .add();
- } else {
- plotBorder.animate(
- plotBorder.crisp(null, plotLeft, plotTop, plotWidth, plotHeight)
- );
- }
- }
-
- chart.isDirtyBox = false;
- },
-
- propFromSeries: function () {
- var chart = this,
- optionsChart = chart.options.chart,
- klass,
- seriesOptions = chart.options.series,
- i,
- value;
-
-
- each(['inverted', 'angular', 'polar'], function (key) {
-
-
- klass = seriesTypes[optionsChart.type || optionsChart.defaultSeriesType];
-
-
- value = (
- chart[key] ||
- optionsChart[key] ||
- (klass && klass.prototype[key])
- );
-
-
- i = seriesOptions && seriesOptions.length;
- while (!value && i--) {
- klass = seriesTypes[seriesOptions[i].type];
- if (klass && klass.prototype[key]) {
- value = true;
- }
- }
-
-
- chart[key] = value;
- });
-
- },
-
- linkSeries: function () {
- var chart = this,
- chartSeries = chart.series;
-
- each(chartSeries, function (series) {
- series.linkedSeries.length = 0;
- });
-
- each(chartSeries, function (series) {
- var linkedTo = series.options.linkedTo;
- if (isString(linkedTo)) {
- if (linkedTo === ':previous') {
- linkedTo = chart.series[series.index - 1];
- } else {
- linkedTo = chart.get(linkedTo);
- }
- if (linkedTo) {
- linkedTo.linkedSeries.push(series);
- series.linkedParent = linkedTo;
- }
- }
- });
- },
-
- render: function () {
- var chart = this,
- axes = chart.axes,
- renderer = chart.renderer,
- options = chart.options;
- var labels = options.labels,
- credits = options.credits,
- creditsHref;
-
- chart.setTitle();
-
- chart.legend = new Legend(chart, options.legend);
- chart.getStacks();
-
-
- each(axes, function (axis) {
- axis.setScale();
- });
- chart.getMargins();
- chart.maxTicks = null;
- each(axes, function (axis) {
- axis.setTickPositions(true);
- axis.setMaxTicks();
- });
- chart.adjustTickAmounts();
- chart.getMargins();
-
- chart.drawChartBox();
-
- if (chart.hasCartesianSeries) {
- each(axes, function (axis) {
- axis.render();
- });
- }
-
- if (!chart.seriesGroup) {
- chart.seriesGroup = renderer.g('series-group')
- .attr({ zIndex: 3 })
- .add();
- }
- each(chart.series, function (serie) {
- serie.translate();
- serie.setTooltipPoints();
- serie.render();
- });
-
- if (labels.items) {
- each(labels.items, function (label) {
- var style = extend(labels.style, label.style),
- x = pInt(style.left) + chart.plotLeft,
- y = pInt(style.top) + chart.plotTop + 12;
-
- delete style.left;
- delete style.top;
- renderer.text(
- label.html,
- x,
- y
- )
- .attr({ zIndex: 2 })
- .css(style)
- .add();
- });
- }
-
- if (credits.enabled && !chart.credits) {
- creditsHref = credits.href;
- chart.credits = renderer.text(
- credits.text,
- 0,
- 0
- )
- .on('click', function () {
- if (creditsHref) {
- location.href = creditsHref;
- }
- })
- .attr({
- align: credits.position.align,
- zIndex: 8
- })
- .css(credits.style)
- .add()
- .align(credits.position);
- }
-
- chart.hasRendered = true;
- },
-
- destroy: function () {
- var chart = this,
- axes = chart.axes,
- series = chart.series,
- container = chart.container,
- i,
- parentNode = container && container.parentNode;
-
-
- fireEvent(chart, 'destroy');
-
-
- charts[chart.index] = UNDEFINED;
- chart.renderTo.removeAttribute('data-highcharts-chart');
-
- removeEvent(chart);
-
-
- i = axes.length;
- while (i--) {
- axes[i] = axes[i].destroy();
- }
-
- i = series.length;
- while (i--) {
- series[i] = series[i].destroy();
- }
-
- each(['title', 'subtitle', 'chartBackground', 'plotBackground', 'plotBGImage',
- 'plotBorder', 'seriesGroup', 'clipRect', 'credits', 'pointer', 'scroller',
- 'rangeSelector', 'legend', 'resetZoomButton', 'tooltip', 'renderer'], function (name) {
- var prop = chart[name];
- if (prop && prop.destroy) {
- chart[name] = prop.destroy();
- }
- });
-
- if (container) {
- container.innerHTML = '';
- removeEvent(container);
- if (parentNode) {
- discardElement(container);
- }
- }
-
- for (i in chart) {
- delete chart[i];
- }
- },
-
- isReadyToRender: function () {
- var chart = this;
-
-
- if ((!hasSVG && (win == win.top && doc.readyState !== 'complete')) || (useCanVG && !win.canvg)) {
-
- if (useCanVG) {
-
- CanVGController.push(function () { chart.firstRender(); }, chart.options.global.canvasToolsURL);
- } else {
- doc.attachEvent('onreadystatechange', function () {
- doc.detachEvent('onreadystatechange', chart.firstRender);
- if (doc.readyState === 'complete') {
- chart.firstRender();
- }
- });
- }
- return false;
- }
- return true;
- },
-
- firstRender: function () {
- var chart = this,
- options = chart.options,
- callback = chart.callback;
-
- if (!chart.isReadyToRender()) {
- return;
- }
-
- chart.getContainer();
-
- fireEvent(chart, 'init');
-
- chart.resetMargins();
- chart.setChartSize();
-
- chart.propFromSeries();
-
- chart.getAxes();
-
- each(options.series || [], function (serieOptions) {
- chart.initSeries(serieOptions);
- });
- chart.linkSeries();
-
-
-
- fireEvent(chart, 'beforeRender');
-
- chart.pointer = new Pointer(chart, options);
- chart.render();
-
- chart.renderer.draw();
-
- if (callback) {
- callback.apply(chart, [chart]);
- }
- each(chart.callbacks, function (fn) {
- fn.apply(chart, [chart]);
- });
-
-
-
- chart.cloneRenderTo(true);
- fireEvent(chart, 'load');
- },
-
- splashArray: function (target, options) {
- var oVar = options[target],
- tArray = isObject(oVar) ? oVar : [oVar, oVar, oVar, oVar];
- return [pick(options[target + 'Top'], tArray[0]),
- pick(options[target + 'Right'], tArray[1]),
- pick(options[target + 'Bottom'], tArray[2]),
- pick(options[target + 'Left'], tArray[3])];
- }
- };
- Chart.prototype.callbacks = [];
- var Point = function () {};
- Point.prototype = {
-
- init: function (series, options, x) {
- var point = this,
- colors;
- point.series = series;
- point.applyOptions(options, x);
- point.pointAttr = {};
- if (series.options.colorByPoint) {
- colors = series.options.colors || series.chart.options.colors;
- point.color = point.color || colors[series.colorCounter++];
-
- if (series.colorCounter === colors.length) {
- series.colorCounter = 0;
- }
- }
- series.chart.pointCount++;
- return point;
- },
-
- applyOptions: function (options, x) {
- var point = this,
- series = point.series,
- pointValKey = series.pointValKey;
- options = Point.prototype.optionsToObject.call(this, options);
-
- extend(point, options);
- point.options = point.options ? extend(point.options, options) : options;
-
-
- if (pointValKey) {
- point.y = point[pointValKey];
- }
-
-
-
- if (point.x === UNDEFINED && series) {
- point.x = x === UNDEFINED ? series.autoIncrement() : x;
- }
-
- return point;
- },
-
- optionsToObject: function (options) {
- var ret,
- series = this.series,
- pointArrayMap = series.pointArrayMap || ['y'],
- valueCount = pointArrayMap.length,
- firstItemType,
- i = 0,
- j = 0;
- if (typeof options === 'number' || options === null) {
- ret = { y: options };
- } else if (isArray(options)) {
- ret = {};
-
- if (options.length > valueCount) {
- firstItemType = typeof options[0];
- if (firstItemType === 'string') {
- ret.name = options[0];
- } else if (firstItemType === 'number') {
- ret.x = options[0];
- }
- i++;
- }
- while (j < valueCount) {
- ret[pointArrayMap[j++]] = options[i++];
- }
- } else if (typeof options === 'object') {
- ret = options;
-
-
- if (options.dataLabels) {
- series._hasPointLabels = true;
- }
-
- if (options.marker) {
- series._hasPointMarkers = true;
- }
- }
- return ret;
- },
-
- destroy: function () {
- var point = this,
- series = point.series,
- chart = series.chart,
- hoverPoints = chart.hoverPoints,
- prop;
- chart.pointCount--;
- if (hoverPoints) {
- point.setState();
- erase(hoverPoints, point);
- if (!hoverPoints.length) {
- chart.hoverPoints = null;
- }
- }
- if (point === chart.hoverPoint) {
- point.onMouseOut();
- }
-
-
- if (point.graphic || point.dataLabel) {
- removeEvent(point);
- point.destroyElements();
- }
- if (point.legendItem) {
- chart.legend.destroyItem(point);
- }
- for (prop in point) {
- point[prop] = null;
- }
- },
-
- destroyElements: function () {
- var point = this,
- props = ['graphic', 'dataLabel', 'dataLabelUpper', 'group', 'connector', 'shadowGroup'],
- prop,
- i = 6;
- while (i--) {
- prop = props[i];
- if (point[prop]) {
- point[prop] = point[prop].destroy();
- }
- }
- },
-
- getLabelConfig: function () {
- var point = this;
- return {
- x: point.category,
- y: point.y,
- key: point.name || point.category,
- series: point.series,
- point: point,
- percentage: point.percentage,
- total: point.total || point.stackTotal
- };
- },
-
- select: function (selected, accumulate) {
- var point = this,
- series = point.series,
- chart = series.chart;
- selected = pick(selected, !point.selected);
-
- point.firePointEvent(selected ? 'select' : 'unselect', { accumulate: accumulate }, function () {
- point.selected = point.options.selected = selected;
- series.options.data[inArray(point, series.data)] = point.options;
-
- point.setState(selected && SELECT_STATE);
-
- if (!accumulate) {
- each(chart.getSelectedPoints(), function (loopPoint) {
- if (loopPoint.selected && loopPoint !== point) {
- loopPoint.selected = loopPoint.options.selected = false;
- series.options.data[inArray(loopPoint, series.data)] = loopPoint.options;
- loopPoint.setState(NORMAL_STATE);
- loopPoint.firePointEvent('unselect');
- }
- });
- }
- });
- },
-
- onMouseOver: function (e) {
- var point = this,
- series = point.series,
- chart = series.chart,
- tooltip = chart.tooltip,
- hoverPoint = chart.hoverPoint;
-
- if (hoverPoint && hoverPoint !== point) {
- hoverPoint.onMouseOut();
- }
-
- point.firePointEvent('mouseOver');
-
- if (tooltip && (!tooltip.shared || series.noSharedTooltip)) {
- tooltip.refresh(point, e);
- }
-
- point.setState(HOVER_STATE);
- chart.hoverPoint = point;
- },
-
-
- onMouseOut: function () {
- var chart = this.series.chart,
- hoverPoints = chart.hoverPoints;
-
- if (!hoverPoints || inArray(this, hoverPoints) === -1) {
- this.firePointEvent('mouseOut');
-
- this.setState();
- chart.hoverPoint = null;
- }
- },
-
- tooltipFormatter: function (pointFormat) {
-
-
- var series = this.series,
- seriesTooltipOptions = series.tooltipOptions,
- valueDecimals = pick(seriesTooltipOptions.valueDecimals, ''),
- valuePrefix = seriesTooltipOptions.valuePrefix || '',
- valueSuffix = seriesTooltipOptions.valueSuffix || '';
-
-
- each(series.pointArrayMap || ['y'], function (key) {
- key = '{point.' + key;
- if (valuePrefix || valueSuffix) {
- pointFormat = pointFormat.replace(key + '}', valuePrefix + key + '}' + valueSuffix);
- }
- pointFormat = pointFormat.replace(key + '}', key + ':,.' + valueDecimals + 'f}');
- });
-
- return format(pointFormat, {
- point: this,
- series: this.series
- });
- },
-
- update: function (options, redraw, animation) {
- var point = this,
- series = point.series,
- graphic = point.graphic,
- i,
- data = series.data,
- chart = series.chart,
- seriesOptions = series.options;
- redraw = pick(redraw, true);
-
- point.firePointEvent('update', { options: options }, function () {
- point.applyOptions(options);
-
- if (isObject(options)) {
- series.getAttribs();
- if (graphic) {
- if (options.marker && options.marker.symbol) {
- point.graphic = graphic.destroy();
- } else {
- graphic.attr(point.pointAttr[point.state || '']);
- }
- }
- }
-
- i = inArray(point, data);
- series.xData[i] = point.x;
- series.yData[i] = series.toYData ? series.toYData(point) : point.y;
- series.zData[i] = point.z;
- seriesOptions.data[i] = point.options;
-
- series.isDirty = series.isDirtyData = true;
- if (!series.fixedBox && series.hasCartesianSeries) {
- chart.isDirtyBox = true;
- }
-
- if (seriesOptions.legendType === 'point') {
- chart.legend.destroyItem(point);
- }
- if (redraw) {
- chart.redraw(animation);
- }
- });
- },
-
- remove: function (redraw, animation) {
- var point = this,
- series = point.series,
- points = series.points,
- chart = series.chart,
- i,
- data = series.data;
- setAnimation(animation, chart);
- redraw = pick(redraw, true);
-
- point.firePointEvent('remove', null, function () {
-
- i = inArray(point, data);
- if (data.length === points.length) {
- points.splice(i, 1);
- }
- data.splice(i, 1);
- series.options.data.splice(i, 1);
- series.xData.splice(i, 1);
- series.yData.splice(i, 1);
- series.zData.splice(i, 1);
- point.destroy();
-
- series.isDirty = true;
- series.isDirtyData = true;
- if (redraw) {
- chart.redraw();
- }
- });
- },
-
- firePointEvent: function (eventType, eventArgs, defaultFunction) {
- var point = this,
- series = this.series,
- seriesOptions = series.options;
-
- if (seriesOptions.point.events[eventType] || (point.options && point.options.events && point.options.events[eventType])) {
- this.importEvents();
- }
-
- if (eventType === 'click' && seriesOptions.allowPointSelect) {
- defaultFunction = function (event) {
-
- point.select(null, event.ctrlKey || event.metaKey || event.shiftKey);
- };
- }
- fireEvent(this, eventType, eventArgs, defaultFunction);
- },
-
- importEvents: function () {
- if (!this.hasImportedEvents) {
- var point = this,
- options = merge(point.series.options.point, point.options),
- events = options.events,
- eventType;
- point.events = events;
- for (eventType in events) {
- addEvent(point, eventType, events[eventType]);
- }
- this.hasImportedEvents = true;
- }
- },
-
- setState: function (state) {
- var point = this,
- plotX = point.plotX,
- plotY = point.plotY,
- series = point.series,
- stateOptions = series.options.states,
- markerOptions = defaultPlotOptions[series.type].marker && series.options.marker,
- normalDisabled = markerOptions && !markerOptions.enabled,
- markerStateOptions = markerOptions && markerOptions.states[state],
- stateDisabled = markerStateOptions && markerStateOptions.enabled === false,
- stateMarkerGraphic = series.stateMarkerGraphic,
- pointMarker = point.marker || {},
- chart = series.chart,
- radius,
- newSymbol,
- pointAttr = point.pointAttr;
- state = state || NORMAL_STATE;
- if (
-
- state === point.state ||
-
- (point.selected && state !== SELECT_STATE) ||
-
- (stateOptions[state] && stateOptions[state].enabled === false) ||
-
- (state && (stateDisabled || (normalDisabled && !markerStateOptions.enabled)))
- ) {
- return;
- }
-
- if (point.graphic) {
- radius = markerOptions && point.graphic.symbolName && pointAttr[state].r;
- point.graphic.attr(merge(
- pointAttr[state],
- radius ? {
- x: plotX - radius,
- y: plotY - radius,
- width: 2 * radius,
- height: 2 * radius
- } : {}
- ));
- } else {
-
-
- if (state && markerStateOptions) {
- radius = markerStateOptions.radius;
- newSymbol = pointMarker.symbol || series.symbol;
-
-
- if (stateMarkerGraphic && stateMarkerGraphic.currentSymbol !== newSymbol) {
- stateMarkerGraphic = stateMarkerGraphic.destroy();
- }
-
- if (!stateMarkerGraphic) {
- series.stateMarkerGraphic = stateMarkerGraphic = chart.renderer.symbol(
- newSymbol,
- plotX - radius,
- plotY - radius,
- 2 * radius,
- 2 * radius
- )
- .attr(pointAttr[state])
- .add(series.markerGroup);
- stateMarkerGraphic.currentSymbol = newSymbol;
-
-
- } else {
- stateMarkerGraphic.attr({
- x: plotX - radius,
- y: plotY - radius
- });
- }
- }
- if (stateMarkerGraphic) {
- stateMarkerGraphic[state && chart.isInsidePlot(plotX, plotY) ? 'show' : 'hide']();
- }
- }
- point.state = state;
- }
- };
- var Series = function () {};
- Series.prototype = {
- isCartesian: true,
- type: 'line',
- pointClass: Point,
- sorted: true,
- requireSorting: true,
- pointAttrToOptions: {
- stroke: 'lineColor',
- 'stroke-width': 'lineWidth',
- fill: 'fillColor',
- r: 'radius'
- },
- colorCounter: 0,
- init: function (chart, options) {
- var series = this,
- eventType,
- events,
- chartSeries = chart.series;
- series.chart = chart;
- series.options = options = series.setOptions(options);
- series.linkedSeries = [];
-
- series.bindAxes();
-
- extend(series, {
- name: options.name,
- state: NORMAL_STATE,
- pointAttr: {},
- visible: options.visible !== false,
- selected: options.selected === true
- });
-
-
- if (useCanVG) {
- options.animation = false;
- }
-
- events = options.events;
- for (eventType in events) {
- addEvent(series, eventType, events[eventType]);
- }
- if (
- (events && events.click) ||
- (options.point && options.point.events && options.point.events.click) ||
- options.allowPointSelect
- ) {
- chart.runTrackerClick = true;
- }
- series.getColor();
- series.getSymbol();
-
- series.setData(options.data, false);
-
-
- if (series.isCartesian) {
- chart.hasCartesianSeries = true;
- }
-
- chartSeries.push(series);
- series._i = chartSeries.length - 1;
-
-
- stableSort(chartSeries, function (a, b) {
- return pick(a.options.index, a._i) - pick(b.options.index, a._i);
- });
- each(chartSeries, function (series, i) {
- series.index = i;
- series.name = series.name || 'Series ' + (i + 1);
- });
- },
-
-
- bindAxes: function () {
- var series = this,
- seriesOptions = series.options,
- chart = series.chart,
- axisOptions;
-
- if (series.isCartesian) {
-
- each(['xAxis', 'yAxis'], function (AXIS) {
-
- each(chart[AXIS], function (axis) {
-
- axisOptions = axis.options;
-
-
-
- if ((seriesOptions[AXIS] === axisOptions.index) ||
- (seriesOptions[AXIS] !== UNDEFINED && seriesOptions[AXIS] === axisOptions.id) ||
- (seriesOptions[AXIS] === UNDEFINED && axisOptions.index === 0)) {
-
-
- axis.series.push(series);
-
-
- series[AXIS] = axis;
-
-
- axis.isDirty = true;
- }
- });
-
- if (!series[AXIS]) {
- error(18, true);
- }
- });
- }
- },
-
- autoIncrement: function () {
- var series = this,
- options = series.options,
- xIncrement = series.xIncrement;
- xIncrement = pick(xIncrement, options.pointStart, 0);
- series.pointInterval = pick(series.pointInterval, options.pointInterval, 1);
- series.xIncrement = xIncrement + series.pointInterval;
- return xIncrement;
- },
-
- getSegments: function () {
- var series = this,
- lastNull = -1,
- segments = [],
- i,
- points = series.points,
- pointsLength = points.length;
- if (pointsLength) {
-
-
- if (series.options.connectNulls) {
- i = pointsLength;
- while (i--) {
- if (points[i].y === null) {
- points.splice(i, 1);
- }
- }
- if (points.length) {
- segments = [points];
- }
-
-
- } else {
- each(points, function (point, i) {
- if (point.y === null) {
- if (i > lastNull + 1) {
- segments.push(points.slice(lastNull + 1, i));
- }
- lastNull = i;
- } else if (i === pointsLength - 1) {
- segments.push(points.slice(lastNull + 1, i + 1));
- }
- });
- }
- }
-
-
- series.segments = segments;
- },
-
-
- setOptions: function (itemOptions) {
- var chart = this.chart,
- chartOptions = chart.options,
- plotOptions = chartOptions.plotOptions,
- typeOptions = plotOptions[this.type],
- options;
- this.userOptions = itemOptions;
- options = merge(
- typeOptions,
- plotOptions.series,
- itemOptions
- );
-
-
- this.tooltipOptions = merge(chartOptions.tooltip, options.tooltip);
-
-
- if (typeOptions.marker === null) {
- delete options.marker;
- }
-
- return options;
- },
-
- getColor: function () {
- var options = this.options,
- userOptions = this.userOptions,
- defaultColors = this.chart.options.colors,
- counters = this.chart.counters,
- color,
- colorIndex;
- color = options.color || defaultPlotOptions[this.type].color;
- if (!color && !options.colorByPoint) {
- if (defined(userOptions._colorIndex)) {
- colorIndex = userOptions._colorIndex;
- } else {
- userOptions._colorIndex = counters.color;
- colorIndex = counters.color++;
- }
- color = defaultColors[colorIndex];
- }
-
- this.color = color;
- counters.wrapColor(defaultColors.length);
- },
-
- getSymbol: function () {
- var series = this,
- userOptions = series.userOptions,
- seriesMarkerOption = series.options.marker,
- chart = series.chart,
- defaultSymbols = chart.options.symbols,
- counters = chart.counters,
- symbolIndex;
- series.symbol = seriesMarkerOption.symbol;
- if (!series.symbol) {
- if (defined(userOptions._symbolIndex)) {
- symbolIndex = userOptions._symbolIndex;
- } else {
- userOptions._symbolIndex = counters.symbol;
- symbolIndex = counters.symbol++;
- }
- series.symbol = defaultSymbols[symbolIndex];
- }
-
- if (/^url/.test(series.symbol)) {
- seriesMarkerOption.radius = 0;
- }
- counters.wrapSymbol(defaultSymbols.length);
- },
-
- drawLegendSymbol: function (legend) {
-
- var options = this.options,
- markerOptions = options.marker,
- radius,
- legendOptions = legend.options,
- legendSymbol,
- symbolWidth = legendOptions.symbolWidth,
- renderer = this.chart.renderer,
- legendItemGroup = this.legendGroup,
- verticalCenter = legend.baseline - mathRound(renderer.fontMetrics(legendOptions.itemStyle.fontSize).b * 0.3),
- attr;
-
-
- if (options.lineWidth) {
- attr = {
- 'stroke-width': options.lineWidth
- };
- if (options.dashStyle) {
- attr.dashstyle = options.dashStyle;
- }
- this.legendLine = renderer.path([
- M,
- 0,
- verticalCenter,
- L,
- symbolWidth,
- verticalCenter
- ])
- .attr(attr)
- .add(legendItemGroup);
- }
-
-
- if (markerOptions && markerOptions.enabled) {
- radius = markerOptions.radius;
- this.legendSymbol = legendSymbol = renderer.symbol(
- this.symbol,
- (symbolWidth / 2) - radius,
- verticalCenter - radius,
- 2 * radius,
- 2 * radius
- )
- .add(legendItemGroup);
- legendSymbol.isMarker = true;
- }
- },
-
- addPoint: function (options, redraw, shift, animation) {
- var series = this,
- seriesOptions = series.options,
- data = series.data,
- graph = series.graph,
- area = series.area,
- chart = series.chart,
- xData = series.xData,
- yData = series.yData,
- zData = series.zData,
- names = series.names,
- currentShift = (graph && graph.shift) || 0,
- dataOptions = seriesOptions.data,
- point,
- isInTheMiddle,
- x,
- i;
- setAnimation(animation, chart);
-
- if (shift) {
- each([graph, area, series.graphNeg, series.areaNeg], function (shape) {
- if (shape) {
- shape.shift = currentShift + 1;
- }
- });
- }
- if (area) {
- area.isArea = true;
- }
-
-
- redraw = pick(redraw, true);
-
-
- point = { series: series };
- series.pointClass.prototype.applyOptions.apply(point, [options]);
- x = point.x;
-
- i = xData.length;
- if (series.requireSorting && x < xData[i - 1]) {
- isInTheMiddle = true;
- while (i && xData[i - 1] > x) {
- i--;
- }
- }
-
- xData.splice(i, 0, x);
- yData.splice(i, 0, series.toYData ? series.toYData(point) : point.y);
- zData.splice(i, 0, point.z);
- if (names) {
- names[x] = point.name;
- }
- dataOptions.splice(i, 0, options);
- if (isInTheMiddle) {
- series.data.splice(i, 0, null);
- series.processData();
- }
-
-
- if (seriesOptions.legendType === 'point') {
- series.generatePoints();
- }
-
-
- if (shift) {
- if (data[0] && data[0].remove) {
- data[0].remove(false);
- } else {
- data.shift();
- xData.shift();
- yData.shift();
- zData.shift();
- dataOptions.shift();
- }
- }
-
- series.isDirty = true;
- series.isDirtyData = true;
- if (redraw) {
- series.getAttribs();
- chart.redraw();
- }
- },
-
- setData: function (data, redraw) {
- var series = this,
- oldData = series.points,
- options = series.options,
- chart = series.chart,
- firstPoint = null,
- xAxis = series.xAxis,
- names = xAxis && xAxis.categories && !xAxis.categories.length ? [] : null,
- i;
-
- series.xIncrement = null;
- series.pointRange = xAxis && xAxis.categories ? 1 : options.pointRange;
- series.colorCounter = 0;
-
-
- var xData = [],
- yData = [],
- zData = [],
- dataLength = data ? data.length : [],
- turboThreshold = pick(options.turboThreshold, 1000),
- pt,
- pointArrayMap = series.pointArrayMap,
- valueCount = pointArrayMap && pointArrayMap.length,
- hasToYData = !!series.toYData;
-
-
-
-
- if (turboThreshold && dataLength > turboThreshold) {
-
-
- i = 0;
- while (firstPoint === null && i < dataLength) {
- firstPoint = data[i];
- i++;
- }
-
-
- if (isNumber(firstPoint)) {
- var x = pick(options.pointStart, 0),
- pointInterval = pick(options.pointInterval, 1);
- for (i = 0; i < dataLength; i++) {
- xData[i] = x;
- yData[i] = data[i];
- x += pointInterval;
- }
- series.xIncrement = x;
- } else if (isArray(firstPoint)) {
- if (valueCount) {
- for (i = 0; i < dataLength; i++) {
- pt = data[i];
- xData[i] = pt[0];
- yData[i] = pt.slice(1, valueCount + 1);
- }
- } else {
- for (i = 0; i < dataLength; i++) {
- pt = data[i];
- xData[i] = pt[0];
- yData[i] = pt[1];
- }
- }
- } else {
- error(12);
- }
- } else {
- for (i = 0; i < dataLength; i++) {
- if (data[i] !== UNDEFINED) {
- pt = { series: series };
- series.pointClass.prototype.applyOptions.apply(pt, [data[i]]);
- xData[i] = pt.x;
- yData[i] = hasToYData ? series.toYData(pt) : pt.y;
- zData[i] = pt.z;
- if (names && pt.name) {
- names[pt.x] = pt.name;
- }
- }
- }
- }
-
-
- if (isString(yData[0])) {
- error(14, true);
- }
- series.data = [];
- series.options.data = data;
- series.xData = xData;
- series.yData = yData;
- series.zData = zData;
- series.names = names;
-
- i = (oldData && oldData.length) || 0;
- while (i--) {
- if (oldData[i] && oldData[i].destroy) {
- oldData[i].destroy();
- }
- }
-
- if (xAxis) {
- xAxis.minRange = xAxis.userMinRange;
- }
-
- series.isDirty = series.isDirtyData = chart.isDirtyBox = true;
- if (pick(redraw, true)) {
- chart.redraw(false);
- }
- },
-
- remove: function (redraw, animation) {
- var series = this,
- chart = series.chart;
- redraw = pick(redraw, true);
- if (!series.isRemoving) {
- series.isRemoving = true;
-
- fireEvent(series, 'remove', null, function () {
-
- series.destroy();
-
- chart.isDirtyLegend = chart.isDirtyBox = true;
- chart.linkSeries();
-
- if (redraw) {
- chart.redraw(animation);
- }
- });
- }
- series.isRemoving = false;
- },
-
- processData: function (force) {
- var series = this,
- processedXData = series.xData,
- processedYData = series.yData,
- dataLength = processedXData.length,
- croppedData,
- cropStart = 0,
- cropped,
- distance,
- closestPointRange,
- xAxis = series.xAxis,
- i,
- options = series.options,
- cropThreshold = options.cropThreshold,
- isCartesian = series.isCartesian;
-
-
- if (isCartesian && !series.isDirty && !xAxis.isDirty && !series.yAxis.isDirty && !force) {
- return false;
- }
-
-
- if (isCartesian && series.sorted && (!cropThreshold || dataLength > cropThreshold || series.forceCrop)) {
- var min = xAxis.min,
- max = xAxis.max;
-
- if (processedXData[dataLength - 1] < min || processedXData[0] > max) {
- processedXData = [];
- processedYData = [];
-
-
- } else if (processedXData[0] < min || processedXData[dataLength - 1] > max) {
- croppedData = this.cropData(series.xData, series.yData, min, max);
- processedXData = croppedData.xData;
- processedYData = croppedData.yData;
- cropStart = croppedData.start;
- cropped = true;
- }
- }
-
-
-
- for (i = processedXData.length - 1; i >= 0; i--) {
- distance = processedXData[i] - processedXData[i - 1];
- if (distance > 0 && (closestPointRange === UNDEFINED || distance < closestPointRange)) {
- closestPointRange = distance;
-
-
- } else if (distance < 0 && series.requireSorting) {
- error(15);
- }
- }
-
- series.cropped = cropped;
- series.cropStart = cropStart;
- series.processedXData = processedXData;
- series.processedYData = processedYData;
- if (options.pointRange === null) {
- series.pointRange = closestPointRange || 1;
- }
- series.closestPointRange = closestPointRange;
-
- },
-
- cropData: function (xData, yData, min, max) {
- var dataLength = xData.length,
- cropStart = 0,
- cropEnd = dataLength,
- cropShoulder = pick(this.cropShoulder, 1),
- i;
-
- for (i = 0; i < dataLength; i++) {
- if (xData[i] >= min) {
- cropStart = mathMax(0, i - cropShoulder);
- break;
- }
- }
-
- for (; i < dataLength; i++) {
- if (xData[i] > max) {
- cropEnd = i + cropShoulder;
- break;
- }
- }
- return {
- xData: xData.slice(cropStart, cropEnd),
- yData: yData.slice(cropStart, cropEnd),
- start: cropStart,
- end: cropEnd
- };
- },
-
- generatePoints: function () {
- var series = this,
- options = series.options,
- dataOptions = options.data,
- data = series.data,
- dataLength,
- processedXData = series.processedXData,
- processedYData = series.processedYData,
- pointClass = series.pointClass,
- processedDataLength = processedXData.length,
- cropStart = series.cropStart || 0,
- cursor,
- hasGroupedData = series.hasGroupedData,
- point,
- points = [],
- i;
- if (!data && !hasGroupedData) {
- var arr = [];
- arr.length = dataOptions.length;
- data = series.data = arr;
- }
- for (i = 0; i < processedDataLength; i++) {
- cursor = cropStart + i;
- if (!hasGroupedData) {
- if (data[cursor]) {
- point = data[cursor];
- } else if (dataOptions[cursor] !== UNDEFINED) {
- data[cursor] = point = (new pointClass()).init(series, dataOptions[cursor], processedXData[i]);
- }
- points[i] = point;
- } else {
-
- points[i] = (new pointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
- }
- }
-
-
- if (data && (processedDataLength !== (dataLength = data.length) || hasGroupedData)) {
- for (i = 0; i < dataLength; i++) {
- if (i === cropStart && !hasGroupedData) {
- i += processedDataLength;
- }
- if (data[i]) {
- data[i].destroyElements();
- data[i].plotX = UNDEFINED;
- }
- }
- }
- series.data = data;
- series.points = points;
- },
-
- setStackedPoints: function () {
- if (!this.options.stacking || (this.visible !== true && this.chart.options.chart.ignoreHiddenSeries !== false)) {
- return;
- }
- var series = this,
- xData = series.processedXData,
- yData = series.processedYData,
- stackedYData = [],
- yDataLength = yData.length,
- seriesOptions = series.options,
- threshold = seriesOptions.threshold,
- stackOption = seriesOptions.stack,
- stacking = seriesOptions.stacking,
- stackKey = series.stackKey,
- negKey = '-' + stackKey,
- negStacks = series.negStacks,
- yAxis = series.yAxis,
- stacks = yAxis.stacks,
- oldStacks = yAxis.oldStacks,
- isNegative,
- stack,
- other,
- key,
- i,
- x,
- y;
-
- for (i = 0; i < yDataLength; i++) {
- x = xData[i];
- y = yData[i];
-
-
- isNegative = negStacks && y < threshold;
- key = isNegative ? negKey : stackKey;
-
- if (!stacks[key]) {
- stacks[key] = {};
- }
-
- if (!stacks[key][x]) {
- if (oldStacks[key] && oldStacks[key][x]) {
- stacks[key][x] = oldStacks[key][x];
- stacks[key][x].total = null;
- } else {
- stacks[key][x] = new StackItem(yAxis, yAxis.options.stackLabels, isNegative, x, stackOption, stacking);
- }
- }
-
- stack = stacks[key][x];
- stack.points[series.index] = [stack.cum || 0];
-
- if (stacking === 'percent') {
-
-
- other = isNegative ? stackKey : negKey;
- if (negStacks && stacks[other] && stacks[other][x]) {
- other = stacks[other][x];
- stack.total = other.total = mathMax(other.total, stack.total) + mathAbs(y) || 0;
-
- } else {
- stack.total += mathAbs(y) || 0;
- }
- } else {
- stack.total += y || 0;
- }
- stack.cum = (stack.cum || 0) + (y || 0);
- stack.points[series.index].push(stack.cum);
- stackedYData[i] = stack.cum;
- }
- if (stacking === 'percent') {
- yAxis.usePercentage = true;
- }
- this.stackedYData = stackedYData;
-
-
- yAxis.oldStacks = {};
- },
-
- setPercentStacks: function () {
- var series = this,
- stackKey = series.stackKey,
- stacks = series.yAxis.stacks;
-
- each([stackKey, '-' + stackKey], function (key) {
- var i = series.xData.length,
- x,
- stack,
- pointExtremes,
- totalFactor;
- while (i--) {
- x = series.xData[i];
- stack = stacks[key] && stacks[key][x];
- pointExtremes = stack && stack.points[series.index];
- if (pointExtremes) {
- totalFactor = stack.total ? 100 / stack.total : 0;
- pointExtremes[0] = correctFloat(pointExtremes[0] * totalFactor);
- pointExtremes[1] = correctFloat(pointExtremes[1] * totalFactor);
- series.stackedYData[i] = pointExtremes[1];
- }
- }
- });
- },
-
- getExtremes: function () {
- var xAxis = this.xAxis,
- yAxis = this.yAxis,
- xData = this.processedXData,
- yData = this.stackedYData || this.processedYData,
- yDataLength = yData.length,
- activeYData = [],
- activeCounter = 0,
- xExtremes = xAxis.getExtremes(),
- xMin = xExtremes.min,
- xMax = xExtremes.max,
- validValue,
- withinRange,
- dataMin,
- dataMax,
- x,
- y,
- i,
- j;
- for (i = 0; i < yDataLength; i++) {
-
- x = xData[i];
- y = yData[i];
-
-
- validValue = y !== null && y !== UNDEFINED && (!yAxis.isLog || (y.length || y > 0));
- withinRange = this.getExtremesFromAll || this.cropped || ((xData[i + 1] || x) >= xMin &&
- (xData[i - 1] || x) <= xMax);
- if (validValue && withinRange) {
- j = y.length;
- if (j) {
- while (j--) {
- if (y[j] !== null) {
- activeYData[activeCounter++] = y[j];
- }
- }
- } else {
- activeYData[activeCounter++] = y;
- }
- }
- }
- this.dataMin = pick(dataMin, arrayMin(activeYData));
- this.dataMax = pick(dataMax, arrayMax(activeYData));
- },
-
- translate: function () {
- if (!this.processedXData) {
- this.processData();
- }
- this.generatePoints();
- var series = this,
- options = series.options,
- stacking = options.stacking,
- xAxis = series.xAxis,
- categories = xAxis.categories,
- yAxis = series.yAxis,
- points = series.points,
- dataLength = points.length,
- hasModifyValue = !!series.modifyValue,
- i,
- pointPlacement = options.pointPlacement,
- dynamicallyPlaced = pointPlacement === 'between' || isNumber(pointPlacement),
- threshold = options.threshold;
-
-
- for (i = 0; i < dataLength; i++) {
- var point = points[i],
- xValue = point.x,
- yValue = point.y,
- yBottom = point.low,
- stack = yAxis.stacks[(series.negStacks && yValue < threshold ? '-' : '') + series.stackKey],
- pointStack,
- stackValues;
-
- if (yAxis.isLog && yValue <= 0) {
- point.y = yValue = null;
- }
-
-
- point.plotX = xAxis.translate(xValue, 0, 0, 0, 1, pointPlacement, this.type === 'flags');
-
-
- if (stacking && series.visible && stack && stack[xValue]) {
- pointStack = stack[xValue];
- stackValues = pointStack.points[series.index];
- yBottom = stackValues[0];
- yValue = stackValues[1];
- if (yBottom === 0) {
- yBottom = pick(threshold, yAxis.min);
- }
- if (yAxis.isLog && yBottom <= 0) {
- yBottom = null;
- }
- point.percentage = stacking === 'percent' && yValue;
- point.total = point.stackTotal = pointStack.total;
- point.stackY = yValue;
-
- pointStack.setOffset(series.pointXOffset || 0, series.barW || 0);
-
- }
-
- point.yBottom = defined(yBottom) ?
- yAxis.translate(yBottom, 0, 1, 0, 1) :
- null;
-
-
- if (hasModifyValue) {
- yValue = series.modifyValue(yValue, point);
- }
-
- point.plotY = (typeof yValue === 'number' && yValue !== Infinity) ?
-
- yAxis.translate(yValue, 0, 1, 0, 1) :
- UNDEFINED;
-
-
- point.clientX = dynamicallyPlaced ? xAxis.translate(xValue, 0, 0, 0, 1) : point.plotX;
-
- point.negative = point.y < (threshold || 0);
-
- point.category = categories && categories[point.x] !== UNDEFINED ?
- categories[point.x] : point.x;
- }
-
- series.getSegments();
- },
-
- setTooltipPoints: function (renew) {
- var series = this,
- points = [],
- pointsLength,
- low,
- high,
- xAxis = series.xAxis,
- xExtremes = xAxis && xAxis.getExtremes(),
- axisLength = xAxis ? (xAxis.tooltipLen || xAxis.len) : series.chart.plotSizeX,
- point,
- pointX,
- nextPoint,
- i,
- tooltipPoints = [];
-
- if (series.options.enableMouseTracking === false) {
- return;
- }
-
- if (renew) {
- series.tooltipPoints = null;
- }
-
- each(series.segments || series.points, function (segment) {
- points = points.concat(segment);
- });
-
- if (xAxis && xAxis.reversed) {
- points = points.reverse();
- }
-
- if (series.orderTooltipPoints) {
- series.orderTooltipPoints(points);
- }
-
- pointsLength = points.length;
- for (i = 0; i < pointsLength; i++) {
- point = points[i];
- pointX = point.x;
- if (pointX >= xExtremes.min && pointX <= xExtremes.max) {
- nextPoint = points[i + 1];
-
-
- low = high === UNDEFINED ? 0 : high + 1;
-
- high = points[i + 1] ?
- mathMin(mathMax(0, mathFloor(
- (point.clientX + (nextPoint ? (nextPoint.wrappedClientX || nextPoint.clientX) : axisLength)) / 2
- )), axisLength) :
- axisLength;
- while (low >= 0 && low <= high) {
- tooltipPoints[low++] = point;
- }
- }
- }
- series.tooltipPoints = tooltipPoints;
- },
-
- tooltipHeaderFormatter: function (point) {
- var series = this,
- tooltipOptions = series.tooltipOptions,
- xDateFormat = tooltipOptions.xDateFormat,
- dateTimeLabelFormats = tooltipOptions.dateTimeLabelFormats,
- xAxis = series.xAxis,
- isDateTime = xAxis && xAxis.options.type === 'datetime',
- headerFormat = tooltipOptions.headerFormat,
- closestPointRange = xAxis && xAxis.closestPointRange,
- n;
-
-
- if (isDateTime && !xDateFormat) {
- if (closestPointRange) {
- for (n in timeUnits) {
- if (timeUnits[n] >= closestPointRange) {
- xDateFormat = dateTimeLabelFormats[n];
- break;
- }
- }
- } else {
- xDateFormat = dateTimeLabelFormats.day;
- }
- }
-
-
- if (isDateTime && xDateFormat && isNumber(point.key)) {
- headerFormat = headerFormat.replace('{point.key}', '{point.key:' + xDateFormat + '}');
- }
-
- return format(headerFormat, {
- point: point,
- series: series
- });
- },
-
- onMouseOver: function () {
- var series = this,
- chart = series.chart,
- hoverSeries = chart.hoverSeries;
-
- if (hoverSeries && hoverSeries !== series) {
- hoverSeries.onMouseOut();
- }
-
-
- if (series.options.events.mouseOver) {
- fireEvent(series, 'mouseOver');
- }
-
- series.setState(HOVER_STATE);
- chart.hoverSeries = series;
- },
-
- onMouseOut: function () {
-
- var series = this,
- options = series.options,
- chart = series.chart,
- tooltip = chart.tooltip,
- hoverPoint = chart.hoverPoint;
-
- if (hoverPoint) {
- hoverPoint.onMouseOut();
- }
-
- if (series && options.events.mouseOut) {
- fireEvent(series, 'mouseOut');
- }
-
- if (tooltip && !options.stickyTracking && (!tooltip.shared || series.noSharedTooltip)) {
- tooltip.hide();
- }
-
- series.setState();
- chart.hoverSeries = null;
- },
-
- animate: function (init) {
- var series = this,
- chart = series.chart,
- renderer = chart.renderer,
- clipRect,
- markerClipRect,
- animation = series.options.animation,
- clipBox = chart.clipBox,
- inverted = chart.inverted,
- sharedClipKey;
-
- if (animation && !isObject(animation)) {
- animation = defaultPlotOptions[series.type].animation;
- }
- sharedClipKey = '_sharedClip' + animation.duration + animation.easing;
-
- if (init) {
-
-
- clipRect = chart[sharedClipKey];
- markerClipRect = chart[sharedClipKey + 'm'];
- if (!clipRect) {
- chart[sharedClipKey] = clipRect = renderer.clipRect(
- extend(clipBox, { width: 0 })
- );
-
- chart[sharedClipKey + 'm'] = markerClipRect = renderer.clipRect(
- -99,
- inverted ? -chart.plotLeft : -chart.plotTop,
- 99,
- inverted ? chart.chartWidth : chart.chartHeight
- );
- }
- series.group.clip(clipRect);
- series.markerGroup.clip(markerClipRect);
- series.sharedClipKey = sharedClipKey;
-
- } else {
- clipRect = chart[sharedClipKey];
- if (clipRect) {
- clipRect.animate({
- width: chart.plotSizeX
- }, animation);
- chart[sharedClipKey + 'm'].animate({
- width: chart.plotSizeX + 99
- }, animation);
- }
-
- series.animate = null;
-
-
-
- series.animationTimeout = setTimeout(function () {
- series.afterAnimate();
- }, animation.duration);
- }
- },
-
-
- afterAnimate: function () {
- var chart = this.chart,
- sharedClipKey = this.sharedClipKey,
- group = this.group;
-
- if (group && this.options.clip !== false) {
- group.clip(chart.clipRect);
- this.markerGroup.clip();
- }
-
-
- setTimeout(function () {
- if (sharedClipKey && chart[sharedClipKey]) {
- chart[sharedClipKey] = chart[sharedClipKey].destroy();
- chart[sharedClipKey + 'm'] = chart[sharedClipKey + 'm'].destroy();
- }
- }, 100);
- },
-
- drawPoints: function () {
- var series = this,
- pointAttr,
- points = series.points,
- chart = series.chart,
- plotX,
- plotY,
- i,
- point,
- radius,
- symbol,
- isImage,
- graphic,
- options = series.options,
- seriesMarkerOptions = options.marker,
- pointMarkerOptions,
- enabled,
- isInside,
- markerGroup = series.markerGroup;
- if (seriesMarkerOptions.enabled || series._hasPointMarkers) {
-
- i = points.length;
- while (i--) {
- point = points[i];
- plotX = mathFloor(point.plotX);
- plotY = point.plotY;
- graphic = point.graphic;
- pointMarkerOptions = point.marker || {};
- enabled = (seriesMarkerOptions.enabled && pointMarkerOptions.enabled === UNDEFINED) || pointMarkerOptions.enabled;
- isInside = chart.isInsidePlot(mathRound(plotX), plotY, chart.inverted);
-
-
- if (enabled && plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
-
- pointAttr = point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE];
- radius = pointAttr.r;
- symbol = pick(pointMarkerOptions.symbol, series.symbol);
- isImage = symbol.indexOf('url') === 0;
- if (graphic) {
- graphic
- .attr({
- visibility: isInside ? (hasSVG ? 'inherit' : VISIBLE) : HIDDEN
- })
- .animate(extend({
- x: plotX - radius,
- y: plotY - radius
- }, graphic.symbolName ? {
- width: 2 * radius,
- height: 2 * radius
- } : {}));
- } else if (isInside && (radius > 0 || isImage)) {
- point.graphic = graphic = chart.renderer.symbol(
- symbol,
- plotX - radius,
- plotY - radius,
- 2 * radius,
- 2 * radius
- )
- .attr(pointAttr)
- .add(markerGroup);
- }
-
- } else if (graphic) {
- point.graphic = graphic.destroy();
- }
- }
- }
- },
-
- convertAttribs: function (options, base1, base2, base3) {
- var conversion = this.pointAttrToOptions,
- attr,
- option,
- obj = {};
- options = options || {};
- base1 = base1 || {};
- base2 = base2 || {};
- base3 = base3 || {};
- for (attr in conversion) {
- option = conversion[attr];
- obj[attr] = pick(options[option], base1[attr], base2[attr], base3[attr]);
- }
- return obj;
- },
-
- getAttribs: function () {
- var series = this,
- seriesOptions = series.options,
- normalOptions = defaultPlotOptions[series.type].marker ? seriesOptions.marker : seriesOptions,
- stateOptions = normalOptions.states,
- stateOptionsHover = stateOptions[HOVER_STATE],
- pointStateOptionsHover,
- seriesColor = series.color,
- normalDefaults = {
- stroke: seriesColor,
- fill: seriesColor
- },
- points = series.points || [],
- i,
- point,
- seriesPointAttr = [],
- pointAttr,
- pointAttrToOptions = series.pointAttrToOptions,
- hasPointSpecificOptions,
- negativeColor = seriesOptions.negativeColor,
- defaultLineColor = normalOptions.lineColor,
- key;
-
- if (seriesOptions.marker) {
-
- stateOptionsHover.radius = stateOptionsHover.radius || normalOptions.radius + 2;
- stateOptionsHover.lineWidth = stateOptionsHover.lineWidth || normalOptions.lineWidth + 1;
-
- } else {
-
- stateOptionsHover.color = stateOptionsHover.color ||
- Color(stateOptionsHover.color || seriesColor)
- .brighten(stateOptionsHover.brightness).get();
- }
-
- seriesPointAttr[NORMAL_STATE] = series.convertAttribs(normalOptions, normalDefaults);
-
- each([HOVER_STATE, SELECT_STATE], function (state) {
- seriesPointAttr[state] =
- series.convertAttribs(stateOptions[state], seriesPointAttr[NORMAL_STATE]);
- });
-
- series.pointAttr = seriesPointAttr;
-
-
-
- i = points.length;
- while (i--) {
- point = points[i];
- normalOptions = (point.options && point.options.marker) || point.options;
- if (normalOptions && normalOptions.enabled === false) {
- normalOptions.radius = 0;
- }
-
- if (point.negative && negativeColor) {
- point.color = point.fillColor = negativeColor;
- }
-
- hasPointSpecificOptions = seriesOptions.colorByPoint || point.color;
-
- if (point.options) {
- for (key in pointAttrToOptions) {
- if (defined(normalOptions[pointAttrToOptions[key]])) {
- hasPointSpecificOptions = true;
- }
- }
- }
-
-
- if (hasPointSpecificOptions) {
- normalOptions = normalOptions || {};
- pointAttr = [];
- stateOptions = normalOptions.states || {};
- pointStateOptionsHover = stateOptions[HOVER_STATE] = stateOptions[HOVER_STATE] || {};
-
- if (!seriesOptions.marker) {
-
- pointStateOptionsHover.color =
- Color(pointStateOptionsHover.color || point.color)
- .brighten(pointStateOptionsHover.brightness ||
- stateOptionsHover.brightness).get();
- }
-
- pointAttr[NORMAL_STATE] = series.convertAttribs(extend({
- color: point.color,
- fillColor: point.color,
- lineColor: defaultLineColor === null ? point.color : UNDEFINED
- }, normalOptions), seriesPointAttr[NORMAL_STATE]);
-
- pointAttr[HOVER_STATE] = series.convertAttribs(
- stateOptions[HOVER_STATE],
- seriesPointAttr[HOVER_STATE],
- pointAttr[NORMAL_STATE]
- );
-
-
- pointAttr[SELECT_STATE] = series.convertAttribs(
- stateOptions[SELECT_STATE],
- seriesPointAttr[SELECT_STATE],
- pointAttr[NORMAL_STATE]
- );
-
-
- } else {
- pointAttr = seriesPointAttr;
- }
- point.pointAttr = pointAttr;
- }
- },
-
- update: function (newOptions, redraw) {
- var chart = this.chart,
-
-
- oldOptions = this.userOptions,
- oldType = this.type,
- proto = seriesTypes[oldType].prototype,
- n;
-
- newOptions = merge(oldOptions, {
- animation: false,
- index: this.index,
- pointStart: this.xData[0]
- }, { data: this.options.data }, newOptions);
-
- this.remove(false);
- for (n in proto) {
- if (proto.hasOwnProperty(n)) {
- this[n] = UNDEFINED;
- }
- }
- extend(this, seriesTypes[newOptions.type || oldType].prototype);
-
- this.init(chart, newOptions);
- if (pick(redraw, true)) {
- chart.redraw(false);
- }
- },
-
- destroy: function () {
- var series = this,
- chart = series.chart,
- issue134 = /AppleWebKit\/533/.test(userAgent),
- destroy,
- i,
- data = series.data || [],
- point,
- prop,
- axis;
-
- fireEvent(series, 'destroy');
-
- removeEvent(series);
-
-
- each(['xAxis', 'yAxis'], function (AXIS) {
- axis = series[AXIS];
- if (axis) {
- erase(axis.series, series);
- axis.isDirty = axis.forceRedraw = true;
- axis.stacks = {};
- }
- });
-
- if (series.legendItem) {
- series.chart.legend.destroyItem(series);
- }
-
- i = data.length;
- while (i--) {
- point = data[i];
- if (point && point.destroy) {
- point.destroy();
- }
- }
- series.points = null;
-
- clearTimeout(series.animationTimeout);
-
- each(['area', 'graph', 'dataLabelsGroup', 'group', 'markerGroup', 'tracker',
- 'graphNeg', 'areaNeg', 'posClip', 'negClip'], function (prop) {
- if (series[prop]) {
-
- destroy = issue134 && prop === 'group' ?
- 'hide' :
- 'destroy';
- series[prop][destroy]();
- }
- });
-
- if (chart.hoverSeries === series) {
- chart.hoverSeries = null;
- }
- erase(chart.series, series);
-
- for (prop in series) {
- delete series[prop];
- }
- },
-
- drawDataLabels: function () {
-
- var series = this,
- seriesOptions = series.options,
- options = seriesOptions.dataLabels,
- points = series.points,
- pointOptions,
- generalOptions,
- str,
- dataLabelsGroup;
-
- if (options.enabled || series._hasPointLabels) {
-
-
- if (series.dlProcessOptions) {
- series.dlProcessOptions(options);
- }
-
- dataLabelsGroup = series.plotGroup(
- 'dataLabelsGroup',
- 'data-labels',
- series.visible ? VISIBLE : HIDDEN,
- options.zIndex || 6
- );
-
-
- generalOptions = options;
- each(points, function (point) {
-
- var enabled,
- dataLabel = point.dataLabel,
- labelConfig,
- attr,
- name,
- rotation,
- connector = point.connector,
- isNew = true;
-
-
- pointOptions = point.options && point.options.dataLabels;
- enabled = pick(pointOptions && pointOptions.enabled, generalOptions.enabled);
-
-
-
- if (dataLabel && !enabled) {
- point.dataLabel = dataLabel.destroy();
-
-
-
- } else if (enabled) {
-
-
-
- options = merge(generalOptions, pointOptions);
- rotation = options.rotation;
-
-
- labelConfig = point.getLabelConfig();
- str = options.format ?
- format(options.format, labelConfig) :
- options.formatter.call(labelConfig, options);
-
-
- options.style.color = pick(options.color, options.style.color, series.color, 'black');
-
-
-
- if (dataLabel) {
-
- if (defined(str)) {
- dataLabel
- .attr({
- text: str
- });
- isNew = false;
-
- } else {
- point.dataLabel = dataLabel = dataLabel.destroy();
- if (connector) {
- point.connector = connector.destroy();
- }
- }
-
-
- } else if (defined(str)) {
- attr = {
-
- fill: options.backgroundColor,
- stroke: options.borderColor,
- 'stroke-width': options.borderWidth,
- r: options.borderRadius || 0,
- rotation: rotation,
- padding: options.padding,
- zIndex: 1
- };
-
- for (name in attr) {
- if (attr[name] === UNDEFINED) {
- delete attr[name];
- }
- }
-
- dataLabel = point.dataLabel = series.chart.renderer[rotation ? 'text' : 'label'](
- str,
- 0,
- -999,
- null,
- null,
- null,
- options.useHTML
- )
- .attr(attr)
- .css(options.style)
- .add(dataLabelsGroup)
- .shadow(options.shadow);
-
- }
-
- if (dataLabel) {
-
- series.alignDataLabel(point, dataLabel, options, null, isNew);
- }
- }
- });
- }
- },
-
-
- alignDataLabel: function (point, dataLabel, options, alignTo, isNew) {
- var chart = this.chart,
- inverted = chart.inverted,
- plotX = pick(point.plotX, -999),
- plotY = pick(point.plotY, -999),
- bBox = dataLabel.getBBox(),
- visible = this.visible && chart.isInsidePlot(point.plotX, point.plotY, inverted),
- alignAttr;
-
- if (visible) {
-
- alignTo = extend({
- x: inverted ? chart.plotWidth - plotY : plotX,
- y: mathRound(inverted ? chart.plotHeight - plotX : plotY),
- width: 0,
- height: 0
- }, alignTo);
-
-
- extend(options, {
- width: bBox.width,
- height: bBox.height
- });
-
- if (options.rotation) {
- alignAttr = {
- align: options.align,
- x: alignTo.x + options.x + alignTo.width / 2,
- y: alignTo.y + options.y + alignTo.height / 2
- };
- dataLabel[isNew ? 'attr' : 'animate'](alignAttr);
- } else {
- dataLabel.align(options, null, alignTo);
- alignAttr = dataLabel.alignAttr;
-
- if (pick(options.overflow, 'justify') === 'justify') {
- this.justifyDataLabel(dataLabel, options, alignAttr, bBox, alignTo, isNew);
-
- } else if (pick(options.crop, true)) {
-
- visible = chart.isInsidePlot(alignAttr.x, alignAttr.y) && chart.isInsidePlot(alignAttr.x + bBox.width, alignAttr.y + bBox.height);
-
- }
- }
- }
-
- if (!visible) {
- dataLabel.attr({ y: -999 });
- }
-
- },
-
-
- justifyDataLabel: function (dataLabel, options, alignAttr, bBox, alignTo, isNew) {
- var chart = this.chart,
- align = options.align,
- verticalAlign = options.verticalAlign,
- off,
- justified;
-
- off = alignAttr.x;
- if (off < 0) {
- if (align === 'right') {
- options.align = 'left';
- } else {
- options.x = -off;
- }
- justified = true;
- }
-
- off = alignAttr.x + bBox.width;
- if (off > chart.plotWidth) {
- if (align === 'left') {
- options.align = 'right';
- } else {
- options.x = chart.plotWidth - off;
- }
- justified = true;
- }
-
- off = alignAttr.y;
- if (off < 0) {
- if (verticalAlign === 'bottom') {
- options.verticalAlign = 'top';
- } else {
- options.y = -off;
- }
- justified = true;
- }
-
- off = alignAttr.y + bBox.height;
- if (off > chart.plotHeight) {
- if (verticalAlign === 'top') {
- options.verticalAlign = 'bottom';
- } else {
- options.y = chart.plotHeight - off;
- }
- justified = true;
- }
-
- if (justified) {
- dataLabel.placed = !isNew;
- dataLabel.align(options, null, alignTo);
- }
- },
-
-
- getSegmentPath: function (segment) {
- var series = this,
- segmentPath = [],
- step = series.options.step;
-
-
- each(segment, function (point, i) {
-
- var plotX = point.plotX,
- plotY = point.plotY,
- lastPoint;
- if (series.getPointSpline) {
- segmentPath.push.apply(segmentPath, series.getPointSpline(segment, point, i));
- } else {
-
- segmentPath.push(i ? L : M);
-
- if (step && i) {
- lastPoint = segment[i - 1];
- if (step === 'right') {
- segmentPath.push(
- lastPoint.plotX,
- plotY
- );
-
- } else if (step === 'center') {
- segmentPath.push(
- (lastPoint.plotX + plotX) / 2,
- lastPoint.plotY,
- (lastPoint.plotX + plotX) / 2,
- plotY
- );
-
- } else {
- segmentPath.push(
- plotX,
- lastPoint.plotY
- );
- }
- }
-
- segmentPath.push(
- point.plotX,
- point.plotY
- );
- }
- });
-
- return segmentPath;
- },
-
- getGraphPath: function () {
- var series = this,
- graphPath = [],
- segmentPath,
- singlePoints = [];
-
- each(series.segments, function (segment) {
-
- segmentPath = series.getSegmentPath(segment);
-
-
- if (segment.length > 1) {
- graphPath = graphPath.concat(segmentPath);
- } else {
- singlePoints.push(segment[0]);
- }
- });
-
- series.singlePoints = singlePoints;
- series.graphPath = graphPath;
-
- return graphPath;
-
- },
-
-
- drawGraph: function () {
- var series = this,
- options = this.options,
- props = [['graph', options.lineColor || this.color]],
- lineWidth = options.lineWidth,
- dashStyle = options.dashStyle,
- graphPath = this.getGraphPath(),
- negativeColor = options.negativeColor;
-
- if (negativeColor) {
- props.push(['graphNeg', negativeColor]);
- }
-
-
- each(props, function (prop, i) {
- var graphKey = prop[0],
- graph = series[graphKey],
- attribs;
-
- if (graph) {
- stop(graph);
- graph.animate({ d: graphPath });
-
- } else if (lineWidth && graphPath.length) {
- attribs = {
- stroke: prop[1],
- 'stroke-width': lineWidth,
- zIndex: 1
- };
- if (dashStyle) {
- attribs.dashstyle = dashStyle;
- } else {
- attribs['stroke-linecap'] = attribs['stroke-linejoin'] = 'round';
- }
- series[graphKey] = series.chart.renderer.path(graphPath)
- .attr(attribs)
- .add(series.group)
- .shadow(!i && options.shadow);
- }
- });
- },
-
-
- clipNeg: function () {
- var options = this.options,
- chart = this.chart,
- renderer = chart.renderer,
- negativeColor = options.negativeColor || options.negativeFillColor,
- translatedThreshold,
- posAttr,
- negAttr,
- graph = this.graph,
- area = this.area,
- posClip = this.posClip,
- negClip = this.negClip,
- chartWidth = chart.chartWidth,
- chartHeight = chart.chartHeight,
- chartSizeMax = mathMax(chartWidth, chartHeight),
- yAxis = this.yAxis,
- above,
- below;
-
- if (negativeColor && (graph || area)) {
- translatedThreshold = mathRound(yAxis.toPixels(options.threshold || 0, true));
- above = {
- x: 0,
- y: 0,
- width: chartSizeMax,
- height: translatedThreshold
- };
- below = {
- x: 0,
- y: translatedThreshold,
- width: chartSizeMax,
- height: chartSizeMax
- };
-
- if (chart.inverted) {
- above.height = below.y = chart.plotWidth - translatedThreshold;
- if (renderer.isVML) {
- above = {
- x: chart.plotWidth - translatedThreshold - chart.plotLeft,
- y: 0,
- width: chartWidth,
- height: chartHeight
- };
- below = {
- x: translatedThreshold + chart.plotLeft - chartWidth,
- y: 0,
- width: chart.plotLeft + translatedThreshold,
- height: chartWidth
- };
- }
- }
-
- if (yAxis.reversed) {
- posAttr = below;
- negAttr = above;
- } else {
- posAttr = above;
- negAttr = below;
- }
-
- if (posClip) {
- posClip.animate(posAttr);
- negClip.animate(negAttr);
- } else {
-
- this.posClip = posClip = renderer.clipRect(posAttr);
- this.negClip = negClip = renderer.clipRect(negAttr);
-
- if (graph && this.graphNeg) {
- graph.clip(posClip);
- this.graphNeg.clip(negClip);
- }
-
- if (area) {
- area.clip(posClip);
- this.areaNeg.clip(negClip);
- }
- }
- }
- },
-
- invertGroups: function () {
- var series = this,
- chart = series.chart;
-
- if (!series.xAxis) {
- return;
- }
-
-
- function setInvert() {
- var size = {
- width: series.yAxis.len,
- height: series.xAxis.len
- };
-
- each(['group', 'markerGroup'], function (groupName) {
- if (series[groupName]) {
- series[groupName].attr(size).invert();
- }
- });
- }
- addEvent(chart, 'resize', setInvert);
- addEvent(series, 'destroy', function () {
- removeEvent(chart, 'resize', setInvert);
- });
-
- setInvert();
-
-
- series.invertGroups = setInvert;
- },
-
-
- plotGroup: function (prop, name, visibility, zIndex, parent) {
- var group = this[prop],
- isNew = !group;
-
-
- if (isNew) {
- this[prop] = group = this.chart.renderer.g(name)
- .attr({
- visibility: visibility,
- zIndex: zIndex || 0.1
- })
- .add(parent);
- }
-
- group[isNew ? 'attr' : 'animate'](this.getPlotBox());
- return group;
- },
-
- getPlotBox: function () {
- return {
- translateX: this.xAxis ? this.xAxis.left : this.chart.plotLeft,
- translateY: this.yAxis ? this.yAxis.top : this.chart.plotTop,
- scaleX: 1,
- scaleY: 1
- };
- },
-
-
- render: function () {
- var series = this,
- chart = series.chart,
- group,
- options = series.options,
- animation = options.animation,
- doAnimation = animation && !!series.animate &&
- chart.renderer.isSVG,
-
- visibility = series.visible ? VISIBLE : HIDDEN,
- zIndex = options.zIndex,
- hasRendered = series.hasRendered,
- chartSeriesGroup = chart.seriesGroup;
-
-
- group = series.plotGroup(
- 'group',
- 'series',
- visibility,
- zIndex,
- chartSeriesGroup
- );
-
- series.markerGroup = series.plotGroup(
- 'markerGroup',
- 'markers',
- visibility,
- zIndex,
- chartSeriesGroup
- );
-
-
- if (doAnimation) {
- series.animate(true);
- }
-
- series.getAttribs();
-
- group.inverted = series.isCartesian ? chart.inverted : false;
-
-
- if (series.drawGraph) {
- series.drawGraph();
- series.clipNeg();
- }
-
- series.drawDataLabels();
-
-
- series.drawPoints();
-
- if (series.options.enableMouseTracking !== false) {
- series.drawTracker();
- }
-
-
- if (chart.inverted) {
- series.invertGroups();
- }
-
-
- if (options.clip !== false && !series.sharedClipKey && !hasRendered) {
- group.clip(chart.clipRect);
- }
-
- if (doAnimation) {
- series.animate();
- } else if (!hasRendered) {
- series.afterAnimate();
- }
- series.isDirty = series.isDirtyData = false;
-
- series.hasRendered = true;
- },
-
-
- redraw: function () {
- var series = this,
- chart = series.chart,
- wasDirtyData = series.isDirtyData,
- group = series.group,
- xAxis = series.xAxis,
- yAxis = series.yAxis;
-
- if (group) {
- if (chart.inverted) {
- group.attr({
- width: chart.plotWidth,
- height: chart.plotHeight
- });
- }
- group.animate({
- translateX: pick(xAxis && xAxis.left, chart.plotLeft),
- translateY: pick(yAxis && yAxis.top, chart.plotTop)
- });
- }
- series.translate();
- series.setTooltipPoints(true);
- series.render();
- if (wasDirtyData) {
- fireEvent(series, 'updatedData');
- }
- },
-
- setState: function (state) {
- var series = this,
- options = series.options,
- graph = series.graph,
- graphNeg = series.graphNeg,
- stateOptions = options.states,
- lineWidth = options.lineWidth,
- attribs;
- state = state || NORMAL_STATE;
- if (series.state !== state) {
- series.state = state;
- if (stateOptions[state] && stateOptions[state].enabled === false) {
- return;
- }
- if (state) {
- lineWidth = stateOptions[state].lineWidth || lineWidth + 1;
- }
- if (graph && !graph.dashstyle) {
- attribs = {
- 'stroke-width': lineWidth
- };
-
- graph.attr(attribs);
- if (graphNeg) {
- graphNeg.attr(attribs);
- }
- }
- }
- },
-
- setVisible: function (vis, redraw) {
- var series = this,
- chart = series.chart,
- legendItem = series.legendItem,
- showOrHide,
- ignoreHiddenSeries = chart.options.chart.ignoreHiddenSeries,
- oldVisibility = series.visible;
-
- series.visible = vis = series.userOptions.visible = vis === UNDEFINED ? !oldVisibility : vis;
- showOrHide = vis ? 'show' : 'hide';
-
- each(['group', 'dataLabelsGroup', 'markerGroup', 'tracker'], function (key) {
- if (series[key]) {
- series[key][showOrHide]();
- }
- });
-
-
- if (chart.hoverSeries === series) {
- series.onMouseOut();
- }
- if (legendItem) {
- chart.legend.colorizeItem(series, vis);
- }
-
- series.isDirty = true;
-
- if (series.options.stacking) {
- each(chart.series, function (otherSeries) {
- if (otherSeries.options.stacking && otherSeries.visible) {
- otherSeries.isDirty = true;
- }
- });
- }
-
- each(series.linkedSeries, function (otherSeries) {
- otherSeries.setVisible(vis, false);
- });
- if (ignoreHiddenSeries) {
- chart.isDirtyBox = true;
- }
- if (redraw !== false) {
- chart.redraw();
- }
- fireEvent(series, showOrHide);
- },
-
- show: function () {
- this.setVisible(true);
- },
-
- hide: function () {
- this.setVisible(false);
- },
-
- select: function (selected) {
- var series = this;
-
- series.selected = selected = (selected === UNDEFINED) ? !series.selected : selected;
- if (series.checkbox) {
- series.checkbox.checked = selected;
- }
- fireEvent(series, selected ? 'select' : 'unselect');
- },
-
- drawTracker: function () {
- var series = this,
- options = series.options,
- trackByArea = options.trackByArea,
- trackerPath = [].concat(trackByArea ? series.areaPath : series.graphPath),
- trackerPathLength = trackerPath.length,
- chart = series.chart,
- pointer = chart.pointer,
- renderer = chart.renderer,
- snap = chart.options.tooltip.snap,
- tracker = series.tracker,
- cursor = options.cursor,
- css = cursor && { cursor: cursor },
- singlePoints = series.singlePoints,
- singlePoint,
- i,
- onMouseOver = function () {
- if (chart.hoverSeries !== series) {
- series.onMouseOver();
- }
- };
-
-
- if (trackerPathLength && !trackByArea) {
- i = trackerPathLength + 1;
- while (i--) {
- if (trackerPath[i] === M) {
- trackerPath.splice(i + 1, 0, trackerPath[i + 1] - snap, trackerPath[i + 2], L);
- }
- if ((i && trackerPath[i] === M) || i === trackerPathLength) {
- trackerPath.splice(i, 0, L, trackerPath[i - 2] + snap, trackerPath[i - 1]);
- }
- }
- }
-
- for (i = 0; i < singlePoints.length; i++) {
- singlePoint = singlePoints[i];
- trackerPath.push(M, singlePoint.plotX - snap, singlePoint.plotY,
- L, singlePoint.plotX + snap, singlePoint.plotY);
- }
-
-
-
- if (tracker) {
- tracker.attr({ d: trackerPath });
- } else {
-
- series.tracker = renderer.path(trackerPath)
- .attr({
- 'stroke-linejoin': 'round',
- visibility: series.visible ? VISIBLE : HIDDEN,
- stroke: TRACKER_FILL,
- fill: trackByArea ? TRACKER_FILL : NONE,
- 'stroke-width' : options.lineWidth + (trackByArea ? 0 : 2 * snap),
- zIndex: 2
- })
- .add(series.group);
-
-
-
- each([series.tracker, series.markerGroup], function (tracker) {
- tracker.addClass(PREFIX + 'tracker')
- .on('mouseover', onMouseOver)
- .on('mouseout', function (e) { pointer.onTrackerMouseOut(e); })
- .css(css);
- if (hasTouch) {
- tracker.on('touchstart', onMouseOver);
- }
- });
- }
- }
- };
- var LineSeries = extendClass(Series);
- seriesTypes.line = LineSeries;
- defaultPlotOptions.area = merge(defaultSeriesOptions, {
- threshold: 0
-
-
-
-
- });
- var AreaSeries = extendClass(Series, {
- type: 'area',
-
-
-
- getSegments: function () {
- var segments = [],
- segment = [],
- keys = [],
- xAxis = this.xAxis,
- yAxis = this.yAxis,
- stack = yAxis.stacks[this.stackKey],
- pointMap = {},
- plotX,
- plotY,
- points = this.points,
- connectNulls = this.options.connectNulls,
- val,
- i,
- x;
- if (this.options.stacking && !this.cropped) {
-
- for (i = 0; i < points.length; i++) {
- pointMap[points[i].x] = points[i];
- }
-
- for (x in stack) {
- keys.push(+x);
- }
- keys.sort(function (a, b) {
- return a - b;
- });
- each(keys, function (x) {
- if (connectNulls && (!pointMap[x] || pointMap[x].y === null)) {
- return;
-
- } else if (pointMap[x]) {
- segment.push(pointMap[x]);
-
-
-
- } else {
- plotX = xAxis.translate(x);
- val = stack[x].percent ? (stack[x].total ? stack[x].cum * 100 / stack[x].total : 0) : stack[x].cum;
- plotY = yAxis.toPixels(val, true);
- segment.push({
- y: null,
- plotX: plotX,
- clientX: plotX,
- plotY: plotY,
- yBottom: plotY,
- onMouseOver: noop
- });
- }
- });
- if (segment.length) {
- segments.push(segment);
- }
- } else {
- Series.prototype.getSegments.call(this);
- segments = this.segments;
- }
- this.segments = segments;
- },
-
-
- getSegmentPath: function (segment) {
-
- var segmentPath = Series.prototype.getSegmentPath.call(this, segment),
- areaSegmentPath = [].concat(segmentPath),
- i,
- options = this.options,
- segLength = segmentPath.length,
- translatedThreshold = this.yAxis.getThreshold(options.threshold),
- yBottom;
-
- if (segLength === 3) {
- areaSegmentPath.push(L, segmentPath[1], segmentPath[2]);
- }
- if (options.stacking && !this.closedStacks) {
-
-
-
-
- for (i = segment.length - 1; i >= 0; i--) {
- yBottom = pick(segment[i].yBottom, translatedThreshold);
-
-
- if (i < segment.length - 1 && options.step) {
- areaSegmentPath.push(segment[i + 1].plotX, yBottom);
- }
-
- areaSegmentPath.push(segment[i].plotX, yBottom);
- }
- } else {
- this.closeSegment(areaSegmentPath, segment, translatedThreshold);
- }
- this.areaPath = this.areaPath.concat(areaSegmentPath);
- return segmentPath;
- },
-
-
- closeSegment: function (path, segment, translatedThreshold) {
- path.push(
- L,
- segment[segment.length - 1].plotX,
- translatedThreshold,
- L,
- segment[0].plotX,
- translatedThreshold
- );
- },
-
-
- drawGraph: function () {
-
-
- this.areaPath = [];
-
-
- Series.prototype.drawGraph.apply(this);
-
-
- var series = this,
- areaPath = this.areaPath,
- options = this.options,
- negativeColor = options.negativeColor,
- negativeFillColor = options.negativeFillColor,
- props = [['area', this.color, options.fillColor]];
-
- if (negativeColor || negativeFillColor) {
- props.push(['areaNeg', negativeColor, negativeFillColor]);
- }
-
- each(props, function (prop) {
- var areaKey = prop[0],
- area = series[areaKey];
-
-
- if (area) {
- area.animate({ d: areaPath });
-
- } else {
- series[areaKey] = series.chart.renderer.path(areaPath)
- .attr({
- fill: pick(
- prop[2],
- Color(prop[1]).setOpacity(pick(options.fillOpacity, 0.75)).get()
- ),
- zIndex: 0
- }).add(series.group);
- }
- });
- },
-
-
- drawLegendSymbol: function (legend, item) {
-
- item.legendSymbol = this.chart.renderer.rect(
- 0,
- legend.baseline - 11,
- legend.options.symbolWidth,
- 12,
- 2
- ).attr({
- zIndex: 3
- }).add(item.legendGroup);
-
- }
- });
- seriesTypes.area = AreaSeries;
- defaultPlotOptions.spline = merge(defaultSeriesOptions);
- var SplineSeries = extendClass(Series, {
- type: 'spline',
-
- getPointSpline: function (segment, point, i) {
- var smoothing = 1.5,
- denom = smoothing + 1,
- plotX = point.plotX,
- plotY = point.plotY,
- lastPoint = segment[i - 1],
- nextPoint = segment[i + 1],
- leftContX,
- leftContY,
- rightContX,
- rightContY,
- ret;
-
- if (lastPoint && nextPoint) {
-
- var lastX = lastPoint.plotX,
- lastY = lastPoint.plotY,
- nextX = nextPoint.plotX,
- nextY = nextPoint.plotY,
- correction;
- leftContX = (smoothing * plotX + lastX) / denom;
- leftContY = (smoothing * plotY + lastY) / denom;
- rightContX = (smoothing * plotX + nextX) / denom;
- rightContY = (smoothing * plotY + nextY) / denom;
-
- correction = ((rightContY - leftContY) * (rightContX - plotX)) /
- (rightContX - leftContX) + plotY - rightContY;
- leftContY += correction;
- rightContY += correction;
-
-
- if (leftContY > lastY && leftContY > plotY) {
- leftContY = mathMax(lastY, plotY);
- rightContY = 2 * plotY - leftContY;
- } else if (leftContY < lastY && leftContY < plotY) {
- leftContY = mathMin(lastY, plotY);
- rightContY = 2 * plotY - leftContY;
- }
- if (rightContY > nextY && rightContY > plotY) {
- rightContY = mathMax(nextY, plotY);
- leftContY = 2 * plotY - rightContY;
- } else if (rightContY < nextY && rightContY < plotY) {
- rightContY = mathMin(nextY, plotY);
- leftContY = 2 * plotY - rightContY;
- }
-
- point.rightContX = rightContX;
- point.rightContY = rightContY;
- }
-
-
-
-
- if (!i) {
- ret = [M, plotX, plotY];
- } else {
- ret = [
- 'C',
- lastPoint.rightContX || lastPoint.plotX,
- lastPoint.rightContY || lastPoint.plotY,
- leftContX || plotX,
- leftContY || plotY,
- plotX,
- plotY
- ];
- lastPoint.rightContX = lastPoint.rightContY = null;
- }
- return ret;
- }
- });
- seriesTypes.spline = SplineSeries;
- defaultPlotOptions.areaspline = merge(defaultPlotOptions.area);
- var areaProto = AreaSeries.prototype,
- AreaSplineSeries = extendClass(SplineSeries, {
- type: 'areaspline',
- closedStacks: true,
-
-
- getSegmentPath: areaProto.getSegmentPath,
- closeSegment: areaProto.closeSegment,
- drawGraph: areaProto.drawGraph,
- drawLegendSymbol: areaProto.drawLegendSymbol
- });
- seriesTypes.areaspline = AreaSplineSeries;
- defaultPlotOptions.column = merge(defaultSeriesOptions, {
- borderColor: '#FFFFFF',
- borderWidth: 1,
- borderRadius: 0,
-
- groupPadding: 0.2,
-
- marker: null,
- pointPadding: 0.1,
-
- minPointLength: 0,
- cropThreshold: 50,
- pointRange: null,
- states: {
- hover: {
- brightness: 0.1,
- shadow: false
- },
- select: {
- color: '#C0C0C0',
- borderColor: '#000000',
- shadow: false
- }
- },
- dataLabels: {
- align: null,
- verticalAlign: null,
- y: null
- },
- stickyTracking: false,
- threshold: 0
- });
- var ColumnSeries = extendClass(Series, {
- type: 'column',
- pointAttrToOptions: {
- stroke: 'borderColor',
- 'stroke-width': 'borderWidth',
- fill: 'color',
- r: 'borderRadius'
- },
- cropShoulder: 0,
- trackerGroups: ['group', 'dataLabelsGroup'],
- negStacks: true,
-
-
-
- init: function () {
- Series.prototype.init.apply(this, arguments);
- var series = this,
- chart = series.chart;
-
-
- if (chart.hasRendered) {
- each(chart.series, function (otherSeries) {
- if (otherSeries.type === series.type) {
- otherSeries.isDirty = true;
- }
- });
- }
- },
-
- getColumnMetrics: function () {
- var series = this,
- options = series.options,
- xAxis = series.xAxis,
- yAxis = series.yAxis,
- reversedXAxis = xAxis.reversed,
- stackKey,
- stackGroups = {},
- columnIndex,
- columnCount = 0;
-
-
-
- if (options.grouping === false) {
- columnCount = 1;
- } else {
- each(series.chart.series, function (otherSeries) {
- var otherOptions = otherSeries.options,
- otherYAxis = otherSeries.yAxis;
- if (otherSeries.type === series.type && otherSeries.visible &&
- yAxis.len === otherYAxis.len && yAxis.pos === otherYAxis.pos) {
- if (otherOptions.stacking) {
- stackKey = otherSeries.stackKey;
- if (stackGroups[stackKey] === UNDEFINED) {
- stackGroups[stackKey] = columnCount++;
- }
- columnIndex = stackGroups[stackKey];
- } else if (otherOptions.grouping !== false) {
- columnIndex = columnCount++;
- }
- otherSeries.columnIndex = columnIndex;
- }
- });
- }
- var categoryWidth = mathMin(
- mathAbs(xAxis.transA) * (xAxis.ordinalSlope || options.pointRange || xAxis.closestPointRange || 1),
- xAxis.len
- ),
- groupPadding = categoryWidth * options.groupPadding,
- groupWidth = categoryWidth - 2 * groupPadding,
- pointOffsetWidth = groupWidth / columnCount,
- optionPointWidth = options.pointWidth,
- pointPadding = defined(optionPointWidth) ? (pointOffsetWidth - optionPointWidth) / 2 :
- pointOffsetWidth * options.pointPadding,
- pointWidth = pick(optionPointWidth, pointOffsetWidth - 2 * pointPadding),
- colIndex = (reversedXAxis ?
- columnCount - (series.columnIndex || 0) :
- series.columnIndex) || 0,
- pointXOffset = pointPadding + (groupPadding + colIndex *
- pointOffsetWidth - (categoryWidth / 2)) *
- (reversedXAxis ? -1 : 1);
-
- return (series.columnMetrics = {
- width: pointWidth,
- offset: pointXOffset
- });
-
- },
-
- translate: function () {
- var series = this,
- chart = series.chart,
- options = series.options,
- borderWidth = options.borderWidth,
- yAxis = series.yAxis,
- threshold = options.threshold,
- translatedThreshold = series.translatedThreshold = yAxis.getThreshold(threshold),
- minPointLength = pick(options.minPointLength, 5),
- metrics = series.getColumnMetrics(),
- pointWidth = metrics.width,
- seriesBarW = series.barW = mathCeil(mathMax(pointWidth, 1 + 2 * borderWidth)),
- pointXOffset = series.pointXOffset = metrics.offset,
- xCrisp = -(borderWidth % 2 ? 0.5 : 0),
- yCrisp = borderWidth % 2 ? 0.5 : 1;
- if (chart.renderer.isVML && chart.inverted) {
- yCrisp += 1;
- }
- Series.prototype.translate.apply(series);
-
- each(series.points, function (point) {
- var yBottom = pick(point.yBottom, translatedThreshold),
- plotY = mathMin(mathMax(-999 - yBottom, point.plotY), yAxis.len + 999 + yBottom),
- barX = point.plotX + pointXOffset,
- barW = seriesBarW,
- barY = mathMin(plotY, yBottom),
- right,
- bottom,
- fromTop,
- fromLeft,
- barH = mathMax(plotY, yBottom) - barY;
-
- if (mathAbs(barH) < minPointLength) {
- if (minPointLength) {
- barH = minPointLength;
- barY =
- mathRound(mathAbs(barY - translatedThreshold) > minPointLength ?
- yBottom - minPointLength :
- translatedThreshold - (yAxis.translate(point.y, 0, 1, 0, 1) <= translatedThreshold ? minPointLength : 0));
- }
- }
-
- point.barX = barX;
- point.pointWidth = pointWidth;
-
- fromLeft = mathAbs(barX) < 0.5;
- right = mathRound(barX + barW) + xCrisp;
- barX = mathRound(barX) + xCrisp;
- barW = right - barX;
- fromTop = mathAbs(barY) < 0.5;
- bottom = mathRound(barY + barH) + yCrisp;
- barY = mathRound(barY) + yCrisp;
- barH = bottom - barY;
-
- if (fromLeft) {
- barX += 1;
- barW -= 1;
- }
- if (fromTop) {
- barY -= 1;
- barH += 1;
- }
-
- point.shapeType = 'rect';
- point.shapeArgs = {
- x: barX,
- y: barY,
- width: barW,
- height: barH
- };
- });
- },
- getSymbol: noop,
-
-
- drawLegendSymbol: AreaSeries.prototype.drawLegendSymbol,
-
-
-
- drawGraph: noop,
-
- drawPoints: function () {
- var series = this,
- options = series.options,
- renderer = series.chart.renderer,
- shapeArgs;
-
- each(series.points, function (point) {
- var plotY = point.plotY,
- graphic = point.graphic;
- if (plotY !== UNDEFINED && !isNaN(plotY) && point.y !== null) {
- shapeArgs = point.shapeArgs;
-
- if (graphic) {
- stop(graphic);
- graphic.animate(merge(shapeArgs));
- } else {
- point.graphic = graphic = renderer[point.shapeType](shapeArgs)
- .attr(point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE])
- .add(series.group)
- .shadow(options.shadow, null, options.stacking && !options.borderRadius);
- }
- } else if (graphic) {
- point.graphic = graphic.destroy();
- }
- });
- },
-
- drawTracker: function () {
- var series = this,
- chart = series.chart,
- pointer = chart.pointer,
- cursor = series.options.cursor,
- css = cursor && { cursor: cursor },
- onMouseOver = function (e) {
- var target = e.target,
- point;
- if (chart.hoverSeries !== series) {
- series.onMouseOver();
- }
- while (target && !point) {
- point = target.point;
- target = target.parentNode;
- }
- if (point !== UNDEFINED && point !== chart.hoverPoint) {
- point.onMouseOver(e);
- }
- };
-
- each(series.points, function (point) {
- if (point.graphic) {
- point.graphic.element.point = point;
- }
- if (point.dataLabel) {
- point.dataLabel.element.point = point;
- }
- });
-
- if (!series._hasTracking) {
- each(series.trackerGroups, function (key) {
- if (series[key]) {
- series[key]
- .addClass(PREFIX + 'tracker')
- .on('mouseover', onMouseOver)
- .on('mouseout', function (e) { pointer.onTrackerMouseOut(e); })
- .css(css);
- if (hasTouch) {
- series[key].on('touchstart', onMouseOver);
- }
- }
- });
- series._hasTracking = true;
- }
- },
-
-
- alignDataLabel: function (point, dataLabel, options, alignTo, isNew) {
- var chart = this.chart,
- inverted = chart.inverted,
- dlBox = point.dlBox || point.shapeArgs,
- below = point.below || (point.plotY > pick(this.translatedThreshold, chart.plotSizeY)),
- inside = pick(options.inside, !!this.options.stacking);
-
-
- if (dlBox) {
- alignTo = merge(dlBox);
- if (inverted) {
- alignTo = {
- x: chart.plotWidth - alignTo.y - alignTo.height,
- y: chart.plotHeight - alignTo.x - alignTo.width,
- width: alignTo.height,
- height: alignTo.width
- };
- }
-
-
- if (!inside) {
- if (inverted) {
- alignTo.x += below ? 0 : alignTo.width;
- alignTo.width = 0;
- } else {
- alignTo.y += below ? alignTo.height : 0;
- alignTo.height = 0;
- }
- }
- }
-
-
-
- options.align = pick(
- options.align,
- !inverted || inside ? 'center' : below ? 'right' : 'left'
- );
- options.verticalAlign = pick(
- options.verticalAlign,
- inverted || inside ? 'middle' : below ? 'top' : 'bottom'
- );
-
-
- Series.prototype.alignDataLabel.call(this, point, dataLabel, options, alignTo, isNew);
- },
-
- animate: function (init) {
- var series = this,
- yAxis = this.yAxis,
- options = series.options,
- inverted = this.chart.inverted,
- attr = {},
- translatedThreshold;
- if (hasSVG) {
- if (init) {
- attr.scaleY = 0.001;
- translatedThreshold = mathMin(yAxis.pos + yAxis.len, mathMax(yAxis.pos, yAxis.toPixels(options.threshold)));
- if (inverted) {
- attr.translateX = translatedThreshold - yAxis.len;
- } else {
- attr.translateY = translatedThreshold;
- }
- series.group.attr(attr);
- } else {
-
- attr.scaleY = 1;
- attr[inverted ? 'translateX' : 'translateY'] = yAxis.pos;
- series.group.animate(attr, series.options.animation);
-
- series.animate = null;
- }
- }
- },
-
-
- remove: function () {
- var series = this,
- chart = series.chart;
-
-
- if (chart.hasRendered) {
- each(chart.series, function (otherSeries) {
- if (otherSeries.type === series.type) {
- otherSeries.isDirty = true;
- }
- });
- }
- Series.prototype.remove.apply(series, arguments);
- }
- });
- seriesTypes.column = ColumnSeries;
- defaultPlotOptions.bar = merge(defaultPlotOptions.column);
- var BarSeries = extendClass(ColumnSeries, {
- type: 'bar',
- inverted: true
- });
- seriesTypes.bar = BarSeries;
- defaultPlotOptions.scatter = merge(defaultSeriesOptions, {
- lineWidth: 0,
- tooltip: {
- headerFormat: '<span style="font-size: 10px; color:{series.color}">{series.name}</span><br/>',
- pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>',
- followPointer: true
- },
- stickyTracking: false
- });
- var ScatterSeries = extendClass(Series, {
- type: 'scatter',
- sorted: false,
- requireSorting: false,
- noSharedTooltip: true,
- trackerGroups: ['markerGroup'],
- drawTracker: ColumnSeries.prototype.drawTracker,
-
- setTooltipPoints: noop
- });
- seriesTypes.scatter = ScatterSeries;
- defaultPlotOptions.pie = merge(defaultSeriesOptions, {
- borderColor: '#FFFFFF',
- borderWidth: 1,
- center: [null, null],
- clip: false,
- colorByPoint: true,
- dataLabels: {
-
-
-
-
- distance: 30,
- enabled: true,
- formatter: function () {
- return this.point.name;
- }
-
-
- },
- ignoreHiddenPoint: true,
-
- legendType: 'point',
- marker: null,
- size: null,
- showInLegend: false,
- slicedOffset: 10,
- states: {
- hover: {
- brightness: 0.1,
- shadow: false
- }
- },
- stickyTracking: false,
- tooltip: {
- followPointer: true
- }
- });
- var PiePoint = extendClass(Point, {
-
- init: function () {
- Point.prototype.init.apply(this, arguments);
- var point = this,
- toggleSlice;
-
- if (point.y < 0) {
- point.y = null;
- }
-
- extend(point, {
- visible: point.visible !== false,
- name: pick(point.name, 'Slice')
- });
-
- toggleSlice = function (e) {
- point.slice(e.type === 'select');
- };
- addEvent(point, 'select', toggleSlice);
- addEvent(point, 'unselect', toggleSlice);
- return point;
- },
-
- setVisible: function (vis) {
- var point = this,
- series = point.series,
- chart = series.chart,
- method;
-
- point.visible = point.options.visible = vis = vis === UNDEFINED ? !point.visible : vis;
- series.options.data[inArray(point, series.data)] = point.options;
-
- method = vis ? 'show' : 'hide';
-
- each(['graphic', 'dataLabel', 'connector', 'shadowGroup'], function (key) {
- if (point[key]) {
- point[key][method]();
- }
- });
- if (point.legendItem) {
- chart.legend.colorizeItem(point, vis);
- }
-
-
- if (!series.isDirty && series.options.ignoreHiddenPoint) {
- series.isDirty = true;
- chart.redraw();
- }
- },
-
- slice: function (sliced, redraw, animation) {
- var point = this,
- series = point.series,
- chart = series.chart,
- translation;
- setAnimation(animation, chart);
-
- redraw = pick(redraw, true);
-
- point.sliced = point.options.sliced = sliced = defined(sliced) ? sliced : !point.sliced;
- series.options.data[inArray(point, series.data)] = point.options;
- translation = sliced ? point.slicedTranslation : {
- translateX: 0,
- translateY: 0
- };
- point.graphic.animate(translation);
-
- if (point.shadowGroup) {
- point.shadowGroup.animate(translation);
- }
- }
- });
- var PieSeries = {
- type: 'pie',
- isCartesian: false,
- pointClass: PiePoint,
- requireSorting: false,
- noSharedTooltip: true,
- trackerGroups: ['group', 'dataLabelsGroup'],
- pointAttrToOptions: {
- stroke: 'borderColor',
- 'stroke-width': 'borderWidth',
- fill: 'color'
- },
-
- getColor: noop,
-
- animate: function (init) {
- var series = this,
- points = series.points,
- startAngleRad = series.startAngleRad;
- if (!init) {
- each(points, function (point) {
- var graphic = point.graphic,
- args = point.shapeArgs;
- if (graphic) {
-
- graphic.attr({
- r: series.center[3] / 2,
- start: startAngleRad,
- end: startAngleRad
- });
-
- graphic.animate({
- r: args.r,
- start: args.start,
- end: args.end
- }, series.options.animation);
- }
- });
-
- series.animate = null;
- }
- },
-
- setData: function (data, redraw) {
- Series.prototype.setData.call(this, data, false);
- this.processData();
- this.generatePoints();
- if (pick(redraw, true)) {
- this.chart.redraw();
- }
- },
-
- generatePoints: function () {
- var i,
- total = 0,
- points,
- len,
- point,
- ignoreHiddenPoint = this.options.ignoreHiddenPoint;
- Series.prototype.generatePoints.call(this);
-
- points = this.points;
- len = points.length;
-
-
- for (i = 0; i < len; i++) {
- point = points[i];
- total += (ignoreHiddenPoint && !point.visible) ? 0 : point.y;
- }
- this.total = total;
-
- for (i = 0; i < len; i++) {
- point = points[i];
- point.percentage = total > 0 ? (point.y / total) * 100 : 0;
- point.total = total;
- }
-
- },
-
-
- getCenter: function () {
-
- var options = this.options,
- chart = this.chart,
- slicingRoom = 2 * (options.slicedOffset || 0),
- handleSlicingRoom,
- plotWidth = chart.plotWidth - 2 * slicingRoom,
- plotHeight = chart.plotHeight - 2 * slicingRoom,
- centerOption = options.center,
- positions = [pick(centerOption[0], '50%'), pick(centerOption[1], '50%'), options.size || '100%', options.innerSize || 0],
- smallestSize = mathMin(plotWidth, plotHeight),
- isPercent;
-
- return map(positions, function (length, i) {
- isPercent = /%$/.test(length);
- handleSlicingRoom = i < 2 || (i === 2 && isPercent);
- return (isPercent ?
-
-
-
-
- [plotWidth, plotHeight, smallestSize, smallestSize][i] *
- pInt(length) / 100 :
- length) + (handleSlicingRoom ? slicingRoom : 0);
- });
- },
-
-
- translate: function (positions) {
- this.generatePoints();
-
- var series = this,
- cumulative = 0,
- precision = 1000,
- options = series.options,
- slicedOffset = options.slicedOffset,
- connectorOffset = slicedOffset + options.borderWidth,
- start,
- end,
- angle,
- startAngle = options.startAngle || 0,
- startAngleRad = series.startAngleRad = mathPI / 180 * (startAngle - 90),
- endAngleRad = series.endAngleRad = mathPI / 180 * ((options.endAngle || (startAngle + 360)) - 90),
- circ = endAngleRad - startAngleRad,
- points = series.points,
- radiusX,
- radiusY,
- labelDistance = options.dataLabels.distance,
- ignoreHiddenPoint = options.ignoreHiddenPoint,
- i,
- len = points.length,
- point;
-
-
-
- if (!positions) {
- series.center = positions = series.getCenter();
- }
-
- series.getX = function (y, left) {
- angle = math.asin((y - positions[1]) / (positions[2] / 2 + labelDistance));
- return positions[0] +
- (left ? -1 : 1) *
- (mathCos(angle) * (positions[2] / 2 + labelDistance));
- };
-
- for (i = 0; i < len; i++) {
-
- point = points[i];
-
-
- start = startAngleRad + (cumulative * circ);
- if (!ignoreHiddenPoint || point.visible) {
- cumulative += point.percentage / 100;
- }
- end = startAngleRad + (cumulative * circ);
-
- point.shapeType = 'arc';
- point.shapeArgs = {
- x: positions[0],
- y: positions[1],
- r: positions[2] / 2,
- innerR: positions[3] / 2,
- start: mathRound(start * precision) / precision,
- end: mathRound(end * precision) / precision
- };
-
- angle = (end + start) / 2;
- if (angle > 0.75 * circ) {
- angle -= 2 * mathPI;
- }
- point.slicedTranslation = {
- translateX: mathRound(mathCos(angle) * slicedOffset),
- translateY: mathRound(mathSin(angle) * slicedOffset)
- };
-
- radiusX = mathCos(angle) * positions[2] / 2;
- radiusY = mathSin(angle) * positions[2] / 2;
- point.tooltipPos = [
- positions[0] + radiusX * 0.7,
- positions[1] + radiusY * 0.7
- ];
-
- point.half = angle < -mathPI / 2 || angle > mathPI / 2 ? 1 : 0;
- point.angle = angle;
-
- connectorOffset = mathMin(connectorOffset, labelDistance / 2);
- point.labelPos = [
- positions[0] + radiusX + mathCos(angle) * labelDistance,
- positions[1] + radiusY + mathSin(angle) * labelDistance,
- positions[0] + radiusX + mathCos(angle) * connectorOffset,
- positions[1] + radiusY + mathSin(angle) * connectorOffset,
- positions[0] + radiusX,
- positions[1] + radiusY,
- labelDistance < 0 ?
- 'center' :
- point.half ? 'right' : 'left',
- angle
- ];
- }
- },
- setTooltipPoints: noop,
- drawGraph: null,
-
- drawPoints: function () {
- var series = this,
- chart = series.chart,
- renderer = chart.renderer,
- groupTranslation,
-
- graphic,
-
- shadow = series.options.shadow,
- shadowGroup,
- shapeArgs;
- if (shadow && !series.shadowGroup) {
- series.shadowGroup = renderer.g('shadow')
- .add(series.group);
- }
-
- each(series.points, function (point) {
- graphic = point.graphic;
- shapeArgs = point.shapeArgs;
- shadowGroup = point.shadowGroup;
-
- if (shadow && !shadowGroup) {
- shadowGroup = point.shadowGroup = renderer.g('shadow')
- .add(series.shadowGroup);
- }
-
- groupTranslation = point.sliced ? point.slicedTranslation : {
- translateX: 0,
- translateY: 0
- };
-
- if (shadowGroup) {
- shadowGroup.attr(groupTranslation);
- }
-
- if (graphic) {
- graphic.animate(extend(shapeArgs, groupTranslation));
- } else {
- point.graphic = graphic = renderer.arc(shapeArgs)
- .setRadialReference(series.center)
- .attr(
- point.pointAttr[point.selected ? SELECT_STATE : NORMAL_STATE]
- )
- .attr({ 'stroke-linejoin': 'round' })
- .attr(groupTranslation)
- .add(series.group)
- .shadow(shadow, shadowGroup);
- }
-
- if (point.visible === false) {
- point.setVisible(false);
- }
- });
- },
-
- sortByAngle: function (points, sign) {
- points.sort(function (a, b) {
- return a.angle !== undefined && (b.angle - a.angle) * sign;
- });
- },
-
- drawDataLabels: function () {
- var series = this,
- data = series.data,
- point,
- chart = series.chart,
- options = series.options.dataLabels,
- connectorPadding = pick(options.connectorPadding, 10),
- connectorWidth = pick(options.connectorWidth, 1),
- plotWidth = chart.plotWidth,
- plotHeight = chart.plotHeight,
- connector,
- connectorPath,
- softConnector = pick(options.softConnector, true),
- distanceOption = options.distance,
- seriesCenter = series.center,
- radius = seriesCenter[2] / 2,
- centerY = seriesCenter[1],
- outside = distanceOption > 0,
- dataLabel,
- dataLabelWidth,
- labelPos,
- labelHeight,
- halves = [
- [],
- []
- ],
- x,
- y,
- visibility,
- rankArr,
- i,
- j,
- overflow = [0, 0, 0, 0],
- sort = function (a, b) {
- return b.y - a.y;
- };
-
- if (!series.visible || (!options.enabled && !series._hasPointLabels)) {
- return;
- }
-
- Series.prototype.drawDataLabels.apply(series);
-
- each(data, function (point) {
- if (point.dataLabel) {
- halves[point.half].push(point);
- }
- });
-
- i = 0;
- while (!labelHeight && data[i]) {
- labelHeight = data[i] && data[i].dataLabel && (data[i].dataLabel.getBBox().height || 21);
- i++;
- }
-
- i = 2;
- while (i--) {
- var slots = [],
- slotsLength,
- usedSlots = [],
- points = halves[i],
- pos,
- length = points.length,
- slotIndex;
-
-
- series.sortByAngle(points, i - 0.5);
-
- if (distanceOption > 0) {
-
-
- for (pos = centerY - radius - distanceOption; pos <= centerY + radius + distanceOption; pos += labelHeight) {
- slots.push(pos);
-
-
-
- }
- slotsLength = slots.length;
-
-
- if (length > slotsLength) {
-
- rankArr = [].concat(points);
- rankArr.sort(sort);
- j = length;
- while (j--) {
- rankArr[j].rank = j;
- }
- j = length;
- while (j--) {
- if (points[j].rank >= slotsLength) {
- points.splice(j, 1);
- }
- }
- length = points.length;
- }
-
-
-
- for (j = 0; j < length; j++) {
-
- point = points[j];
- labelPos = point.labelPos;
-
- var closest = 9999,
- distance,
- slotI;
-
-
- for (slotI = 0; slotI < slotsLength; slotI++) {
- distance = mathAbs(slots[slotI] - labelPos[1]);
- if (distance < closest) {
- closest = distance;
- slotIndex = slotI;
- }
- }
-
-
-
- if (slotIndex < j && slots[j] !== null) {
- slotIndex = j;
- } else if (slotsLength < length - j + slotIndex && slots[j] !== null) {
- slotIndex = slotsLength - length + j;
- while (slots[slotIndex] === null) {
- slotIndex++;
- }
- } else {
-
-
- while (slots[slotIndex] === null) {
- slotIndex++;
- }
- }
-
- usedSlots.push({ i: slotIndex, y: slots[slotIndex] });
- slots[slotIndex] = null;
- }
-
- usedSlots.sort(sort);
- }
-
- for (j = 0; j < length; j++) {
-
- var slot, naturalY;
- point = points[j];
- labelPos = point.labelPos;
- dataLabel = point.dataLabel;
- visibility = point.visible === false ? HIDDEN : VISIBLE;
- naturalY = labelPos[1];
-
- if (distanceOption > 0) {
- slot = usedSlots.pop();
- slotIndex = slot.i;
-
-
- y = slot.y;
- if ((naturalY > y && slots[slotIndex + 1] !== null) ||
- (naturalY < y && slots[slotIndex - 1] !== null)) {
- y = naturalY;
- }
-
- } else {
- y = naturalY;
- }
-
-
- x = options.justify ?
- seriesCenter[0] + (i ? -1 : 1) * (radius + distanceOption) :
- series.getX(slotIndex === 0 || slotIndex === slots.length - 1 ? naturalY : y, i);
-
-
-
- dataLabel._attr = {
- visibility: visibility,
- align: labelPos[6]
- };
- dataLabel._pos = {
- x: x + options.x +
- ({ left: connectorPadding, right: -connectorPadding }[labelPos[6]] || 0),
- y: y + options.y - 10
- };
- dataLabel.connX = x;
- dataLabel.connY = y;
-
-
-
- if (this.options.size === null) {
- dataLabelWidth = dataLabel.width;
-
- if (x - dataLabelWidth < connectorPadding) {
- overflow[3] = mathMax(mathRound(dataLabelWidth - x + connectorPadding), overflow[3]);
-
-
- } else if (x + dataLabelWidth > plotWidth - connectorPadding) {
- overflow[1] = mathMax(mathRound(x + dataLabelWidth - plotWidth + connectorPadding), overflow[1]);
- }
-
-
- if (y - labelHeight / 2 < 0) {
- overflow[0] = mathMax(mathRound(-y + labelHeight / 2), overflow[0]);
-
-
- } else if (y + labelHeight / 2 > plotHeight) {
- overflow[2] = mathMax(mathRound(y + labelHeight / 2 - plotHeight), overflow[2]);
- }
- }
- }
- }
-
-
-
- if (arrayMax(overflow) === 0 || this.verifyDataLabelOverflow(overflow)) {
-
-
- this.placeDataLabels();
-
-
- if (outside && connectorWidth) {
- each(this.points, function (point) {
- connector = point.connector;
- labelPos = point.labelPos;
- dataLabel = point.dataLabel;
-
- if (dataLabel && dataLabel._pos) {
- visibility = dataLabel._attr.visibility;
- x = dataLabel.connX;
- y = dataLabel.connY;
- connectorPath = softConnector ? [
- M,
- x + (labelPos[6] === 'left' ? 5 : -5), y,
- 'C',
- x, y,
- 2 * labelPos[2] - labelPos[4], 2 * labelPos[3] - labelPos[5],
- labelPos[2], labelPos[3],
- L,
- labelPos[4], labelPos[5]
- ] : [
- M,
- x + (labelPos[6] === 'left' ? 5 : -5), y,
- L,
- labelPos[2], labelPos[3],
- L,
- labelPos[4], labelPos[5]
- ];
-
- if (connector) {
- connector.animate({ d: connectorPath });
- connector.attr('visibility', visibility);
-
- } else {
- point.connector = connector = series.chart.renderer.path(connectorPath).attr({
- 'stroke-width': connectorWidth,
- stroke: options.connectorColor || point.color || '#606060',
- visibility: visibility
- })
- .add(series.group);
- }
- } else if (connector) {
- point.connector = connector.destroy();
- }
- });
- }
- }
- },
-
-
- verifyDataLabelOverflow: function (overflow) {
-
- var center = this.center,
- options = this.options,
- centerOption = options.center,
- minSize = options.minSize || 80,
- newSize = minSize,
- ret;
-
-
- if (centerOption[0] !== null) {
- newSize = mathMax(center[2] - mathMax(overflow[1], overflow[3]), minSize);
-
- } else {
- newSize = mathMax(
- center[2] - overflow[1] - overflow[3],
- minSize
- );
- center[0] += (overflow[3] - overflow[1]) / 2;
- }
-
-
- if (centerOption[1] !== null) {
- newSize = mathMax(mathMin(newSize, center[2] - mathMax(overflow[0], overflow[2])), minSize);
-
- } else {
- newSize = mathMax(
- mathMin(
- newSize,
- center[2] - overflow[0] - overflow[2]
- ),
- minSize
- );
- center[1] += (overflow[0] - overflow[2]) / 2;
- }
-
-
- if (newSize < center[2]) {
- center[2] = newSize;
- this.translate(center);
- each(this.points, function (point) {
- if (point.dataLabel) {
- point.dataLabel._pos = null;
- }
- });
- this.drawDataLabels();
-
-
- } else {
- ret = true;
- }
- return ret;
- },
-
-
- placeDataLabels: function () {
- each(this.points, function (point) {
- var dataLabel = point.dataLabel,
- _pos;
-
- if (dataLabel) {
- _pos = dataLabel._pos;
- if (_pos) {
- dataLabel.attr(dataLabel._attr);
- dataLabel[dataLabel.moved ? 'animate' : 'attr'](_pos);
- dataLabel.moved = true;
- } else if (dataLabel) {
- dataLabel.attr({ y: -999 });
- }
- }
- });
- },
-
- alignDataLabel: noop,
-
- drawTracker: ColumnSeries.prototype.drawTracker,
-
- drawLegendSymbol: AreaSeries.prototype.drawLegendSymbol,
-
- getSymbol: noop
- };
- PieSeries = extendClass(Series, PieSeries);
- seriesTypes.pie = PieSeries;
- extend(Highcharts, {
-
-
- Axis: Axis,
- Chart: Chart,
- Color: Color,
- Legend: Legend,
- Pointer: Pointer,
- Point: Point,
- Tick: Tick,
- Tooltip: Tooltip,
- Renderer: Renderer,
- Series: Series,
- SVGElement: SVGElement,
- SVGRenderer: SVGRenderer,
-
-
- arrayMin: arrayMin,
- arrayMax: arrayMax,
- charts: charts,
- dateFormat: dateFormat,
- format: format,
- pathAnim: pathAnim,
- getOptions: getOptions,
- hasBidiBug: hasBidiBug,
- isTouchDevice: isTouchDevice,
- numberFormat: numberFormat,
- seriesTypes: seriesTypes,
- setOptions: setOptions,
- addEvent: addEvent,
- removeEvent: removeEvent,
- createElement: createElement,
- discardElement: discardElement,
- css: css,
- each: each,
- extend: extend,
- map: map,
- merge: merge,
- pick: pick,
- splat: splat,
- extendClass: extendClass,
- pInt: pInt,
- wrap: wrap,
- svg: hasSVG,
- canvas: useCanVG,
- vml: !hasSVG && !useCanVG,
- product: PRODUCT,
- version: VERSION
- });
- }());
|